首页 » 互联网 » 网卡DM9000裸机驱动开拓详解_存放器_网卡

网卡DM9000裸机驱动开拓详解_存放器_网卡

神尊大人 2025-01-18 02:45:23 0

扫一扫用手机浏览

文章目录 [+]

每一个网卡都有一个被称为MAC地址的独一无二的48位串行号,它被写在卡上的一块ROM中。
在网络上的每一个打算机都必须拥有一个独一无二的MAC地址。
没有任何两块被生产出来的网卡拥有同样的地址。
这是由于电气电子工程师协会(IEEE)卖力为网络接口掌握器(网卡)发卖商分配唯一的MAC地址。

网卡上面装有处理器和存储器(包括RAM和ROM)。
网卡和局域网之间的通信是通过电缆或双绞线以串行传输办法进行的。
而网卡和打算机之间的通信则是通过打算机主板上的I/O总线以并行传输办法进行。

网卡DM9000裸机驱动开拓详解_存放器_网卡 网卡DM9000裸机驱动开拓详解_存放器_网卡 互联网

因此,网卡的一个主要功能便是要进行串行/并行转换。
由于网络上的数据率和打算机总线上的数据率并不相同,因此在网卡中必须装有对数据进行缓存的存储芯片

网卡DM9000裸机驱动开拓详解_存放器_网卡 网卡DM9000裸机驱动开拓详解_存放器_网卡 互联网
(图片来自网络侵删)

网卡以前是作为扩展卡插到打算机总线上的,但是由于其价格低廉而且以太网标准普遍存在,大部分新的打算机都在主板上集成了网络接口。

这些主板或是在主板芯片中集成了以太网的功能,或是利用一块通过PCI (或者更新的PCI-Express总线)连接到主板上的廉价网卡。

除非须要多接口或者利用其它种类的网络,否则不再须要一块独立的网卡。
乃至更新的主板可能含有内置的双网络(以太网)接口。

2. 紧张功能

1、数据的封装与解封 发送时将上一层通报来的数据加上首部和尾部,成为以太网的帧。
吸收时将以太网的帧剥去首部和尾部,然后送交上一层

2、链路管理 紧张是通过CSMA/CD(Carrier Sense Multiple Access with Collision Detection ,带冲突检测的载波监听多路访问)协议来实现

3、数据编码与译码 即曼彻斯特编码与译码。
个中曼彻斯特码,又称数字双向码、分相码或相位编码(PE),是一种常用的二元码线路编码办法之一,被物理层利用来编码一个同步位流的时钟和数据。
在通信技能中,用来表示所要发送比特 流中的数据与定时旗子暗记所结合起来的代码。
常用在以太网通信,列车总线掌握,工业总线等领域。

3. 分类按总线接口类型分 按网卡的总线接口类型来分一样平常可分bai为ISA接口网卡、PCI接口网卡以及在做事器上利用的PCI-X总线接口类型的网卡,条记本电脑所利用的网卡是PCMCIA接口类型的。
(1)ISA总线网卡(2)PCI总线网卡(3)PCI-X总线网卡(4)PCMCIA总线网卡(5)USB总线接口网卡按网络接口划分 除了可以按网卡的总线接口类型划分外,我们还可以按网卡的网络接口类型来划分。
网卡终极是要与网络进行连接,以是也就必须有一个接口使网线通过它与其它打算机网络设备连接起来。
不同的网络接话柄用于不同的网络类型,目前常见的接口紧张有以太网的RJ-45接口、细同轴电缆的BNC接口和粗同轴电AUI接口、FDDI接口、ATM接口等。
而且有的网卡为了适用于更广泛的运用环境,供应了两种或多种类型的接口,如有的网卡会同时供应RJ-45、BNC接口或AUI接口。
(1)RJ-45接口网卡(2)BNC接口网卡(3)AUI接口网卡(4)FDDI接口网卡(5)ATM接口网卡按带宽划分 随着网络技能的发展,网络带宽也在不断提高,但是不同带宽的网卡所运用的环境也有所不同,目前主流的网卡紧张有10Mbps网卡、100Mbps以太网卡、10Mbps/100Mbps自适应网卡、1000Mbps千兆以太网卡四种。
(1)10Mbps网卡(2)100Mbps网卡(3)10Mbps/100Mbps网卡(4)1000Mbps以太网卡二、DM9000A

DM9000芯片是DAVICOM公司生产,DM9000A 是一款完备集成的、性价比高、引脚数少、带有通用途理器接口的单芯片快速以太网掌握器。

一个 10/100M PHY 和 4K 双字的 SRAM 。
它是出于低功耗和高性能目的设计的,其 IO 端口支持 3.3V 与 5V 容限值。

DM9000A 为适应各种处理器,供应了 8 位、16 位数据接口访问内部存储器。

DM9000A物理协议层接口完备支持利用 10MBps 下 3 类、4 类、5 类非屏蔽双绞线和 100MBps 下 5类非屏蔽双绞线。
这是完备遵照 IEEE 802.3u 标准。

它的自动协商功能将自动完成 DM9000AE配置以使其发挥出最佳性能。

它还支持 IEEE 802.3x 全双工流量掌握。

1. 模块图

图1 DM9000内部构造框架

EEPROM Interface接口用于存放mac地址,Internal SRAM用于存放收发数据,MII部分把MAC部分与PHY部分连接起来通信,AUTO-MDIX用于自适应10/100M网络,在物理层上,MAC在PHY之下。

2. 引脚剖析

(#:表示低电平有效)

开拓板FS4412的网卡DM9000A连接到了SROM掌握器,下面我们剖析数据线、地址线和旗子暗记线连接

1) SD0~15

SD0~15: 16位数据线连接到引脚BUF_B_Xm0DATA[0:15],由CMD引脚决定访问类型。

可见数据和地址线都连接到了SOC的XM0上。

数据线和旗子暗记线对应的SROMC的引脚如上图。

2) CMD dm9000 外围电路 转换电路 soc CMD--------BUF_B_Xm0ADDR2--------Xm0ADDR2-----Xm0ADDR2

如下图所示: CMD: 命令线,当CMD为高,表示SD 传输的是数据,CMD为低表示传输的是地址,接在exynos4412的BUF_B_Xm0ADDR2上,可见CMD复用了地址线Xm0ADDR2引脚。

3) IOR#、IOW# dm9000 外围电路 转换电路 soc IOR--------BUF_Xm0OEn--------Xm0OEn-----Xm0OEn IOW--------BUF_Xm0WEn--------Xm0WEn-----Xm0WEn

4) CS# dm9000 外围电路 转换电路 soc CS--------BUF_Xm0cs1--------Xm0cs1-----Xm0CSn1

CS#:片选,放在exynos4412的Bank1的片选上面,内存基地址是0x05000000。

我们的DM9000A是放在exynos4412的Bank1(0X05000000)的片选上面。

而DM9000的CMD引脚接在Bank1的LADDR2上面

读写DM9000A的地址 CMD拉低, 此时向0X05000000地址上读写的数据便是DM9000A的内部寄存器地址

读写DM9000A的数据 CMD拉高,此时向0X05000000+4地址上读写的数据便是DM9000A的数据

设置exynos4412的bank1的硬件位宽,时序,由于不同的硬件,涉及的数据收发都不同。

5) INT#

中断线DM9000_IRQ通过U8转接到引脚XEINT6

由上图可知中断引脚INT,接在exynos4412的GPX0_6脚上。
uboot中的DM9000A的驱动没有用到中断。

3. 复用GPIO引脚

XM0引脚复用了GPIO引脚,以是须要初始化对应的GPIO引脚来使能SROMC。

1) GPY0CON

2) GPY1CON

3)GPY3CON

4) GPY5CON

5) GPY6CON

三、SROM 掌握器1. 观点

SROM是高速存储器,Cache技能便是通过在DROM和CPU之间插入一小块SROM来减小CPU和存储之间的速率差异的。

EXYNOS 4412包含了SROM掌握器,特性如下:

外部 8/16位 NOR Flash/PROM/ SRAM memory.4组内存,每块内存最多16 MB

首先我们要初始化 exynos4412的 SROM 掌握器,设置总线宽度和干系时序。

针对 SROM 掌握器的每一个 bank 只有2 个寄存器: SROM_BW 和 SROM_BC。

2. SROM_BW

在 SROM_BW 寄存器中,我们只关心与 bank1 干系的域。

上面剖析过, DM9000A 的 16 根数据线全部接在 exynos 4412的数据线上,以是 DataWidth1 设置为 1; DM9000A 的地址是按字节存取的,以是 AddrMode1 设置为 1; 通过查看事理图,没有利用 Xm0WAITn和 Xm0BEn 引脚; 以是 WaitEnable1 和 ByteEnable1 均设置为 0。

SROM_BW[7:4]=0x33. SROM_BC1

SROM 掌握器读时序和 DM9000A 的读时序紧张通过SROM_BCn掌握寄存器设置。

设置这些时序之前,首先来看DM9000A芯片手册时序图和exynos4412的时序图

详尽时序剖析:,内存掌握器利用HCLK作为时钟,在HCLK为100MHz时,1个clock大约为10ns。
旗子暗记值的设定如下:

旗子暗记 含义 最低韶光(ns) Tacs 地址发出后等多永劫光发片选, DM9000AE 中 CS 和 CMD(地址)同时发出,以是 Tacs最低为0ns 0 Tcos 发出片选旗子暗记后等多永劫光发出读使能旗子暗记(nOW、 IOR),在 DM9000A 的时序图上对应 T1,最小为 0 0 Tacc 读使能旗子暗记持续韶光,access cycle ,读写使能后,多久才能访问数据,在 DM9000A 的时序图上对应 T2 10 Tcoh 当DM9000A的写旗子暗记取消后,数据线上的数据还须要至少3ns才消逝(nOE读写取消后,片选须要坚持多永劫光)在 DM9000A 的时序图中对应 T4 3 Tcah 片选结束后,地址保存韶光, DM9000A 中CS和cmd同时结束,以是 Tcah=0 0 Tacp 页模式,不管 0 PMC 页模式,不管 0

从DM9000A的读写时序图中可以看出,T2+T6实际上构成了DM9000A的一个访问周期,因此还须要知足:Tacs + Tcos + Tacc + Tcoh + Tcah>= T2+T6,终极利用下面的表达式来表达: (Tacs >= 0 && Tacs <= 4) && (Tcos >= 0 && Tcos <= 4) && (Tacc >= 1 && Tacc <= 14 ) && (Tcoh >=1 && Tcoh <= 4 )

寄存器SROM_BCn (n = 0 to 3)定义如下:

故设置参考值为:

#defineDM9000_Tacs(0x1)//addressset-up#defineDM9000_Tcos(0x1)//chipselectionset-up#defineDM9000_Tacc(0x5)//accesscycle#defineDM9000_Tcoh(0x1)//chipselectionhold#defineDM9000_Tah(0xC)//addressholdingtime#defineDM9000_Tacp(0x9)//pagemodeaccesscycle#defineDM9000_PMC(0x1)//normal(1data)pagemodeconfiguration4. SROM初始化

u-boot 已经自带了 DM9000系列网卡的驱动,在 u-boot 源码中的 driver/net/dm9000x.c 的有一段解释:

06/03/2008RemyBohmer<linux@bohmer.net>-FixedthedrivertoworkwithDM9000A.(checkonISRreceivestatusbitbeforereadingtheFIFOasdescribedinDM9000programmingguideandapplicationnotes)-Addedautodetectofdatabuswidth.-Madedebugcodecompileagain.-Adapteth_sendsuchthatitmatchestheDM9000applicationnotes.NeededtomakeitworkproperlyforDM9000A.-AdaptedresetproceduretomatchDM9000applicationnotes(i.e.doublereset)-someminorcodecleanupsThesechangesaretestedwithDM9000{A,EP,E}togetherwitha200MHzAtmelAT91SAM9261core

可见,2008年Remy Bohmer已经为 DM9000A 添加了驱动,但是我们仍旧须要针对板子做一些修正。

前一章我们针对参考的fs4412开拓板移植了DM9000A的驱动,下面我们来详细剖析DM9000A驱动程序。

剖析驱动涉及到以下几个文件:

arch/arm/lib/board.cboard/samsung/origen/origen.cdrivers/net/Dm9000x.cdrivers/net/Dm9000x.hinclude/config_cmd_default.hinclude/configs/origen.hinclude/net.hnet/eth.c5. 宏定义

在include/configs/origen.h中须要定义DM9000A基地址和编译的宏。
个中最主要的几个宏如下:

名称 解释 值 CONFIG_DM9000_BASE DM9000A 的基地址 0x05000000 DM9000_IO DM9000A 的 INDEX 端口地址 CONFIG_DM9000_BASE DM9000_DATA DM9000A 的 DATA 端口地址 (CONFIG_DM9000_BASE + 4) CONFIG_DRIVER_DM9000 Makefile中用于掌握dm9000驱动是否编译 1 CONFIG_DM9000_USE_16BIT DM9000A数据宽度 CONFIG_DM9000_NO_SROM 表示没有利用SROM 1

个中DM9000_DATA 定义为基地址+0x4,刚好把 Xm0ADDR2 拉高,即把 CMD 拉高。

查看文件drivers/net/Makefile:

从 Makefile 得知,要把 DM9000A 的驱动编译进 u-boot中,须要定义 CONFIG_DRIVER_DM9000 这个宏。

宏定义如下:

#ifdefCONFIG_CMD_NET#defineCONFIG_NET_MULTI#defineCONFIG_DRIVER_DM90001#defineCONFIG_DM9000_BASE0x05000000#defineDM9000_IOCONFIG_DM9000_BASE#defineDM9000_DATA(CONFIG_DM9000_BASE+4)#defineCONFIG_DM9000_USE_16BIT#defineCONFIG_DM9000_NO_SROM1#defineCONFIG_ETHADDR11:22:33:44:55:66#defineCONFIG_IPADDR192.168.6.187#defineCONFIG_SERVERIP192.168.6.186#defineCONFIG_GATEWAYIP192.168.6.1#defineCONFIG_NETMASK255.255.255.0#endif

除此以外我们还须要添加一些 u-boot 的命令,比如 ping 命令用来检讨网络是否通畅,tftp用来下载文件。

uboot通过宏来掌握是否编译这些命令,include/configs/origen.h定义了一些宏,但是有的是undefine,我们要打开它们。

/Commanddefinition/#include<config_cmd_default.h>#defineCONFIG_CMD_PING#defineCONFIG_CMD_ELF#defineCONFIG_CMD_DHCP#defineCONFIG_CMD_MMC#defineCONFIG_CMD_FAT#defineCONFIG_CMD_NET#undefCONFIG_CMD_NFS#defineCONFIG_CMD_HELLO#defineCONFIG_CMD_LEDA

除此之外头文件: u-boot-2013.01/include/config_cmd_all.h 也列出了一些可用的命令。

#defineCONFIG_CMD_BDI/bdinfo/#defineCONFIG_CMD_BOOTD/bootd/#defineCONFIG_CMD_CONSOLE/coninfo/#defineCONFIG_CMD_ECHO/echoarguments/#defineCONFIG_CMD_EDITENV/editenv/#defineCONFIG_CMD_FPGA/FPGAconfigurationSupport/#defineCONFIG_CMD_IMI/iminfo/#defineCONFIG_CMD_ITEST/Integer(andstring)test/#ifndefCONFIG_SYS_NO_FLASH#defineCONFIG_CMD_FLASH/flinfo,erase,protect/#defineCONFIG_CMD_IMLS/Listallfoundimages/#endif#defineCONFIG_CMD_LOADB/loadb/#defineCONFIG_CMD_LOADS/loads/#defineCONFIG_CMD_MEMORY/mdmmnmmwcpcmpcrcbaseloopmtest/#defineCONFIG_CMD_MISC/Miscfunctionslikesleepetc/#defineCONFIG_CMD_NET/bootp,tftpboot,rarpboot/#defineCONFIG_CMD_NFS/NFSsupport/#defineCONFIG_CMD_RUN/runcommandinenvvariable/#defineCONFIG_CMD_SAVEENV/saveenv/#defineCONFIG_CMD_SETGETDCR/DCRsupporton4xx/#defineCONFIG_CMD_SOURCE/"source"commandsupport/#defineCONFIG_CMD_XIMG/LoadpartofMultiImage/6. 初始化srom

在arch/arm/lib/board.c的函数board_init_r中有如下代码:

voidboard_init_r(gd_tid,ulongdest_addr){……board_init();/Setupchipselects/……}

函数board_init()定义在board/samsung/origen/origen.c中,我们在该函数中添加了初始化srom代码:

intboard_init(void){gpio1=(structexynos4_gpio_part1)EXYNOS4_GPIO_PART1_BASE;gpio2=(structexynos4_gpio_part2)EXYNOS4_GPIO_PART2_BASE;gd->bd->bi_boot_params=(PHYS_SDRAM_1+0x100UL);#ifdefCONFIG_DRIVER_DM9000dm9000aep_pre_init();#endifreturn0;}

函数dm9000aep_pre_init用来设置 SROM 掌握器。

staticvoiddm9000aep_pre_init(void){unsignedinttmp;unsignedcharsmc_bank_num=1;unsignedintsmc_bw_conf=0;unsignedintsmc_bc_conf=0;/gpioconfiguration/writel(0x00220020,0x11000000+0x120);//GPY0CONwritel(0x00002222,0x11000000+0x140);//GPY1CON/16Bitbuswidth/writel(0x22222222,0x11000000+0x180);//GPY3CONwritel(0x0000FFFF,0x11000000+0x188);//GPY3PUDwritel(0x22222222,0x11000000+0x1C0);//GPY5CONwritel(0x0000FFFF,0x11000000+0x1C8);//GPY5PUDwritel(0x22222222,0x11000000+0x1E0);//GPY6CONwritel(0x0000FFFF,0x11000000+0x1E8);//GPY6PUDsmc_bw_conf&=~(0xf<<4);smc_bw_conf|=(1<<7)|(1<<6)|(1<<5)|(1<<4);smc_bc_conf=((DM9000_Tacs<<28)|(DM9000_Tcos<<24)|(DM9000_Tacc<<16)|(DM9000_Tcoh<<12)|(DM9000_Tah<<8)|(DM9000_Tacp<<4)|(DM9000_PMC));exynos_config_sromc(smc_bank_num,smc_bw_conf,smc_bc_conf);}/exynos_config_sromc()-selecttheproperSROMCBankandconfigurethebandwidthcontrolandbankcontrolregisterssrom_bank-SROMsrom_bw_conf-SMCBandwitdhregconfigurationvaluesrom_bc_conf-SMCBankControlregconfigurationvalue/voidexynos_config_sromc(u32srom_bank,u32srom_bw_conf,u32srom_bc_conf){unsignedinttmp;structexynos_sromcsrom=(structexynos_sromc)(EXYNOS4412_SROMC_BASE);/ConfigureSMC_BWregistertohandleproperSROMCbank/tmp=srom->bw;tmp&=~(0xF<<(srom_bank4));tmp|=srom_bw_conf;srom->bw=tmp;/ConfigureSMC_BCregister/srom->bc[srom_bank]=srom_bc_conf;}四、DM9000A驱动剖析

DM9000A所能支持的功能非常的多,驱动的实现相比拟较繁芜,搞清楚裸机的网卡驱动,我们再去学习Linux内核的DM9000驱动就相对随意马虎一些。
本节将详细讲解DM9000A网卡的数据的收发操作的流程。

1. 干系构造体

struct board_info

/Structure/enumdeclaration-------------------------------/typedefstructboard_info{u32runt_length_counter;/counter:RXlength<64byte/u32long_length_counter;/counter:RXlength>1514byte/u32reset_counter;/counter:RESET/u32reset_tx_timeout;/RESETcausedbyTXTimeout/u32reset_rx_status;/RESETcausedbyRXStatsuswrong/u16tx_pkt_cnt;u16queue_start_addr;u16dbug_cnt;u8phy_addr;u8device_wait_reset;/devicestate/unsignedcharsrom[128];void(outblk)(volatilevoiddata_ptr,intcount);void(inblk)(voiddata_ptr,intcount);void(rx_status)(u16RxStatus,u16RxLen);structeth_devicenetdev;}board_info_t;staticboard_info_tdm9000_info;

该构造体是用来掩护DM9000系列网卡的构造体,所有和网卡DM9000A信息都保存到该构造体中。
struct eth_device struct board_info中有一个主要的成员 netdev,该成员是uboot供应的标准的统一的网卡设备接口。

structeth_device{charname[16];unsignedcharenetaddr[6];intiobase;intstate;int(init)(structeth_device,bd_t);int(send)(structeth_device,voidpacket,intlength);int(recv)(structeth_device);void(halt)(structeth_device);#ifdefCONFIG_MCAST_TFTPint(mcast)(structeth_device,u32ip,u8set);#endifint(write_hwaddr)(structeth_device);structeth_devicenext;intindex;voidpriv;};

该构造体掩护了操作网卡的回调函数等信息,我们只须要把网口的收发数据操作封装到对应的回调函数中,然后注册到系统即可。

2. 网卡注册/注销

进入到arch/arm/lib/board.c 中的 board_init_r 函数:

665#ifdefined(CONFIG_CMD_NET)666puts("Net:");667eth_initialize(gd->bd);668#ifdefined(CONFIG_RESET_PHY_R)669debug("ResetEthernetPHY\n");670reset_phy();671#endif

如果定义了 CONFIG_CMD_NET,就调用 eth_initialize(gd->bd)进行网卡初始化。

这个宏在include/config_cmd_default.h 中定义,这个头文件又被单板配置文件 include/configs/origen.h 所包含。

eth_initialize 函数在 net/eth.c 中定义,下面是该函数部分代码:

308/309Ifboard-specificinitializationexists,callit.310Ifnot,callaCPU-specificone311/312if(board_eth_init!=__def_eth_init){313if(board_eth_init(bis)<0)314printf("BoardNetInitializationFailed\n");315}elseif(cpu_eth_init!=__def_eth_init){316if(cpu_eth_init(bis)<0)317printf("CPUNetInitializationFailed\n");318}else319printf("NetInitializationSkipped\n");

这段代码功能是:如果定义了单板干系的初始化函数就调用它,否则调用 CPU 干系的初始化函数。

个中__def_eth_init 函数,同样在net/eth.c 中定义

105CPUandboard-specificEthernetinitializations.Aliasedfunction106signalscallertomoveon107/108staticint__def_eth_init(bd_tbis)109{110return-1;111}112intcpu_eth_init(bd_tbis)__attribute__((weak,alias("__def_eth_init")));113intboard_eth_init(bd_tbis)__attribute__((weak,alias("__def_eth_init")));

这里用到了 gcc 的弱符号和别名属性。
如果我们没有定义自己的 board_eth_init 函数,则 board_eth_init 就和__def_eth_init 相同,调用 board_eth_init 就相称于调用__def_eth_init,现在就能明白上面的 if 判断语句了。

board_eth_init 在board/samsung/origen/origen.c 中定义

264#ifdefCONFIG_CMD_NET265intboard_eth_init(bd_tbis)266{267268intrc=0;269#ifdefCONFIG_DRIVER_DM9000270rc=dm9000_initialize(bis);271#endif272returnrc;273}274#endif

这里通过配置宏来决定调用哪个网卡初始化函数。

我们利用的是 DM9000A,我们先查看下 DM9000A 的驱动源文件drivers/net/DM9000x.c,初始化函数如下:

626intdm9000_initialize(bd_tbis)627{628structeth_devicedev=&(dm9000_info.netdev);629630/LoadMACaddressfromEEPROM/631dm9000_get_enetaddr(dev);632633dev->init=dm9000_init;634dev->halt=dm9000_halt;635dev->send=dm9000_send;636dev->recv=dm9000_rx;637sprintf(dev->name,"dm9000");638639eth_register(dev);640641return0;642}

该函数便是 DM9000A 的初始化函数。
631行dm9000_get_enetaddr 从 EEPROM 加载MAC地址,

staticvoiddm9000_get_enetaddr(structeth_devicedev){#if!defined(CONFIG_DM9000_NO_SROM)inti;for(i=0;i<3;i++)dm9000_read_srom_word(i,dev->enetaddr+(2i));#endif}

该函数根据宏CONFIG_DM9000_NO_SROM 来决定是否从EEPROM 加载MAC地址, 参考的板子上的 DM9000A 没有接 EEPROM,我们在 origen.h 中定义了这个宏,表示不从 EEPROM 加载 MAC地址。

633~636行是将网卡的初始化和收发数据的函数添补到dev中,用于注册到系统中:

639行,函数eth_register()的参数是dev,该变量地址实在是dm9000_info.netdev的地址。
dm9000_info定义在同一文件下:

108staticboard_info_tdm9000_info;

函数eth_register()位于net/eth.c中;

功能:用于注册网卡到系统中,如果之前网卡设备链表为空,则直接复制给全局指针变量eth_devices和eth_current ,如果不为空,则把当前网卡插入到链表eth_devices中。

inteth_register(structeth_devicedev){structeth_deviced;staticintindex;assert(strlen(dev->name)<sizeof(dev->name));if(!eth_devices){//网卡设备链表为空eth_current=eth_devices=dev;eth_current_changed();}else{//找到表尾for(d=eth_devices;d->next!=eth_devices;d=d->next);d->next=dev;//插入表尾}dev->state=ETH_STATE_INIT;dev->next=eth_devices;//新的设备指向网卡设备表头dev->index=index++;return0;}

个中

eth_devices:网卡设备的链表 eth_current: 用于保存当前利用的网卡

网卡注销 网卡注销函数eth_unregister() 该函数会将网卡节点dev从链表eth_devices中删除,并重新设置变量eth_current。

inteth_unregister(structeth_devicedev){structeth_devicecur;/Nodevice/if(!eth_devices)return-1;for(cur=eth_devices;cur->next!=eth_devices&&cur->next!=dev;cur=cur->next);/Devicenotfound/if(cur->next!=dev)return-1;cur->next=dev->next;if(eth_devices==dev)eth_devices=dev->next==eth_devices?NULL:dev->next;if(eth_current==dev){eth_current=eth_devices;eth_current_changed();}return0;}3. 寄存器

DM9000A 拥有一系列的掌握和状态寄存器,这些寄存器可以被处理器所访问,这些寄存器是按字节对齐的。

所有的 CSRs 在软件或者硬件复位后都将被置为默认值,除非他们被其余标识。

编号 寄存器 描述 偏移地址 复位后默认值 1 NCR 网络掌握寄存器 00H 00H 2 NSR 网络状态寄存器 01H 00H 3 TCR 发送掌握寄存器 02H 00H 4 TSR I 发送状态寄存器 1 03H 00H 5 TSR II 发送状态寄存器 2 04H 00H 6 RCR 吸收掌握寄存器 05H 00H 7 RSR 吸收状态寄存器 06H 00H 8 ROCR 吸收溢出计数寄存器 07H 00H 9 BPTR 背压阈值寄存器 08H 37H 10 FCTR 流掌握阈值寄存器 09H 38H 11 FCR TX/RX 流掌握寄存器 0AH 00H 12 EPCR EEPROM&PHY 掌握寄存器 0BH 00H 13 EPAR EEPROM&PHY 地址寄存器 0CH 40H 14 EPDRL EEPROM&PHY 低字节数据寄存器 0DH XXH 15 EPDRH EEPROM&PHY 高字节数据寄存器 0EH XXH 16 WCR 唤醒掌握寄存器 0FH 00H 17 PAR 物理地址寄存器 10H~15H 由 EEPROM决定 18 MAR 广播地址寄存器 16H~1DH XXH 19 GPCR 通用目的掌握寄存器(8bit 模式) 1EH 01H 20 GPR 通用目的寄存器 1FH XXH 21 TRPAL TX SRAM 读指针地址低字节 22H 00H 22 TRPAH TX SRAM 读指针地址高字节 23H 00H 23 RWPAL RX SRAM 写指针地址低字节 24H 00H 24 RWPAH RX SRAM 写指针地址高字节 25H 0CH 25 VID 厂家 ID 28H~29H 0A46H 26 PID 产品 ID 2AH~2BH 9000H 27 CHIPR 芯片版本 2CH 18H 28 TCR2 发送掌握寄存器 2 2DH 00H 29 OCR 操作掌握寄存器 2EH 00H 30 SMCR 分外模式掌握寄存器 2FH 00H 31 ETXCSR 即将发送掌握/状态寄存器 30H 00H 32 TCSCR 发送校验和掌握寄存器 31H 00H 33 RCSCSR 吸收校验和掌握状态寄存器 32H 00H 34 MRCMDX 内存数据预取读命令寄存器(地址不加 1) F0H XXH 35 MRCMDX1 内存数据读命令寄存器(地址不加 1) F1H XXH 36 MRCMD 内存数据读命令寄存器(地址加 1) F2H XXH 37 MRRL 内存数据读地址寄存器低字节 F4H 00H 38 MRRH 内存数据读地址寄存器高字节 F5H 00H 39 MWCMDX 内存数据写命令寄存器(地址不加 1) F6H XXH 40 MWCMD 内存数据写命令寄存器(地址加 1) F8H XXH 41 MWRL 内存数据写地址寄存器低字节 FAH 00H 42 MWRH 内存数据写地址寄存器高字节 FBH 00H 43 TXPLL TX 数据包长度低字节寄存器 FCH XXH 44 TXPLH TX 数据包长度高字节寄存器 FDH XXH 45 ISR 中断状态寄存器 FEH 00H 46 IMR 中断屏蔽寄存器 FFH 00H

关于默认值的要点(Key to Default) 不才面寄存器描述中,默认栏采取如下形式:

<ResetValue>,<AccessType>

个中

1该位设为逻辑10该位设为逻辑0X没有默认值P电源复位规复默认值H硬件复位规复默认值S软件复位规复默认值E从EEPROM得到默认值T从捆绑引脚(strappin)得到默认值

:

RO=只读RW=可读可写R/C=可读/擦除RW/C1=可读可写/通过写1擦除WO=只写

保留位被隐蔽且应写 0,在读访问时保留位没有定义。

如何读取 DM9000A 的寄存器 RSR? 假设要读取 DM9000A 的寄存器 RSR(RX Status Register),须要分 2 步:

向 INDEX 端口写入 RSR 寄存器的地址(0x06) 条件: nGCS1 旗子暗记拉低、 Xm0WEn 旗子暗记拉低、 Xm0ADDR2 拉低, 或者说向下面的地址写数据 0x06从 DATA 端口读取 RSR 寄存器的值 条件: nGCS1 旗子暗记拉低、 Xm0OEn 旗子暗记拉低、 Xm0ADDR2 拉高, 或者说从下面的地址读数据

DM9000A的寄存器很多,但是我们并须要都节制,我们只须要节制个中几个最主要的寄存器的利用即可。

网络掌握寄存器(NCR)网络状态寄存器(NSR)

在这里插入图片描述

ISR

DAVICOM 指定配置和状态寄存器(DSCSR)

4. 网卡的初始化

网卡的初始化函数入口位于文件net/eth.c下的函数eth_init():

404inteth_init(bd_tbis)405{406structeth_deviceold_current,dev;……425old_current=eth_current;426do{427debug("Trying%s\n",eth_current->name);428429if(eth_current->init(eth_current,bis)>=0){430eth_current->state=ETH_STATE_ACTIVE;431432return0;433}434debug("FAIL\n");……440}

429行即调用我们注册的dm9000A初始化函数,从这也可以看出,全体架构是把网卡的驱动独立分别隔,与硬件操作干系的代码由用户自己添补并注册到系统中即可,便于扩展。
进入dm9000_init():

290staticintdm9000_init(structeth_devicedev,bd_tbd)291{292inti,oft,lnk;293u8io_mode;294structboard_infodb=&dm9000_info;295296DM9000_DBG("%s\n",__func__);297298/RESETdevice/299dm9000_reset();300301if(dm9000_probe()<0)302return-1;303304/Auto-detect8/16/32bitmode,ISRBit6+7indicatebuswidth/305io_mode=DM9000_ior(DM9000_ISR)>>6;306307switch(io_mode){308case0x0:/16-bitmode/309printf("DM9000:runningin16bitmode\n");310db->outblk=dm9000_outblk_16bit;311db->inblk=dm9000_inblk_16bit;312db->rx_status=dm9000_rx_status_16bit;313break;314case0x01:/32-bitmode/315printf("DM9000:runningin32bitmode\n");316db->outblk=dm9000_outblk_32bit;317db->inblk=dm9000_inblk_32bit;318db->rx_status=dm9000_rx_status_32bit;319break;320case0x02:/8bitmode/321printf("DM9000:runningin8bitmode\n");322db->outblk=dm9000_outblk_8bit;323db->inblk=dm9000_inblk_8bit;324db->rx_status=dm9000_rx_status_8bit;325break;326default:327/Assume8bitmode,willprobablynotworkanyway/328printf("DM9000:UndefinedIO-mode:0x%x\n",io_mode);329db->outblk=dm9000_outblk_8bit;330db->inblk=dm9000_inblk_8bit;331db->rx_status=dm9000_rx_status_8bit;332break;333}334335/Programoperatingregister,onlyinternalphysupported/336DM9000_iow(DM9000_NCR,0x0);337/TXPollingclear/338DM9000_iow(DM9000_TCR,0);339/Less3Kb,200us/340DM9000_iow(DM9000_BPTR,BPTR_BPHW(3)|BPTR_JPT_600US);341/FlowControl:High/LowWater/342DM9000_iow(DM9000_FCTR,FCTR_HWOT(3)|FCTR_LWOT(8));343/SHFIXME:Thislooksstrange!FlowControl/344DM9000_iow(DM9000_FCR,0x0);345/SpecialMode/346DM9000_iow(DM9000_SMCR,0);347/clearTXstatus/348DM9000_iow(DM9000_NSR,NSR_WAKEST|NSR_TX2END|NSR_TX1END);349/Clearinterruptstatus/350DM9000_iow(DM9000_ISR,ISR_ROOS|ISR_ROS|ISR_PTS|ISR_PRS);351352printf("MAC:%pM\n",dev->enetaddr);353354/filldeviceMACaddressregisters/355for(i=0,oft=DM9000_PAR;i<6;i++,oft++)356DM9000_iow(oft,dev->enetaddr[i]);357for(i=0,oft=0x16;i<8;i++,oft++)358DM9000_iow(oft,0xff);359360/readbackmac,justtobesure/361for(i=0,oft=0x10;i<6;i++,oft++)362DM9000_DBG("%02x:",DM9000_ior(oft));363DM9000_DBG("\n");364365/ActivateDM9000/366/RXenable/367DM9000_iow(DM9000_RCR,RCR_DIS_LONG|RCR_DIS_CRC|RCR_RXEN);368/EnableTX/RXinterruptmask/369DM9000_iow(DM9000_IMR,IMR_PAR);370371i=0;372while(!(dm9000_phy_read(1)&0x20)){/autonegationcompletebit/373udelay(1000);374i++;375if(i==10000){376printf("couldnotestablishlink\n");377return0;378}379}380381/seewhatwe'vegot/382lnk=dm9000_phy_read(17)>>12;383printf("operatingat");384switch(lnk){385case1:386printf("10Mhalfduplex");387break;388case2:389printf("10Mfullduplex");390break;391case4:392printf("100Mhalfduplex");393break;394case8:395printf("100Mfullduplex");396break;397default:398printf("unknown:%d",lnk);399break;400}401printf("mode\n");402return0;403}

299行 函数DM9000_reset()是对dm9000A重置 301行 函数dm9000_probe()分别从寄存器VID、PID读取厂家ID、产品ID 305行 读取DM9000A的 ISR寄存器,根据bite[6:7]的值来决定终极从DM9000A中读取数位数,并将对应的函数设置到db->outblk和db->inblk这两个变量,终极上层做事想收发数据就通过这两个函数,对付16位模式,就分别赋值dm9000_outblk_16bit、dm9000_inblk_16bit; db->rx_status该函数用于从DM9000A中读取网卡的状态信息和数据包的长度,对付16位模式会赋值为dm9000_rx_status_16bit 336~350行 对DM9000A进行初始化配置 355~358行 将mac地址写入到DM9000A的PAR寄存器 367行 使能数据吸收 369行 使能SRAM的读/写指针在指针地址超过SRAM的大小时自动跳回起始位置 382行 读取phy寄存器DSCSR,打印当前网口的带宽

通过读 bit[15:12]来看经由自动协商后选择的是哪一种模式。
网卡自动协商完成后,结果将被写到该位。
若该位为 1,意味着操作 1 模式是 100M 全双工模式。

5. 数据的发送

发送流程

清中断,ISR寄存器bit[1] = 1发送写操作,操作MWCMD通过DM9000_DATA写入数据设置数据帧的长度 TXPLL、TXPLH发送发送要求,TCR等待数据发送完毕,轮训检讨NSR清中断,ISR寄存器bit[1] = 1

网卡数据的发送函数是dm9000_send()

405/406Hardwarestarttransmission.407Sendapackettomediafromtheupperlayer.408/409staticintdm9000_send(structeth_devicenetdev,voidpacket,intlength)410{411inttmo;412structboard_infodb=&dm9000_info;413414DM9000_DMP_PACKET(__func__,packet,length);415416DM9000_iow(DM9000_ISR,IMR_PTM);/ClearTxbitinISR/417418/MovedatatoDM9000TXRAM/419DM9000_outb(DM9000_MWCMD,DM9000_IO);/PrepareforTX-data/420421/pushthedatatotheTX-fifo/422(db->outblk)(packet,length);423424/SetTXlengthtoDM9000/425DM9000_iow(DM9000_TXPLL,length&0xff);426DM9000_iow(DM9000_TXPLH,(length>>8)&0xff);427428/IssueTXpollingcommand/429DM9000_iow(DM9000_TCR,TCR_TXREQ);/ClearedafterTXcomplete/430431/waitforendoftransmission/432tmo=get_timer(0)+5CONFIG_SYS_HZ;433while(!(DM9000_ior(DM9000_NSR)&(NSR_TX1END|NSR_TX2END))||434!(DM9000_ior(DM9000_ISR)&IMR_PTM)){435if(get_timer(0)>=tmo){436printf("transmissiontimeout\n");437break;438}439}440DM9000_iow(DM9000_ISR,IMR_PTM);/ClearTxbitinISR/441442DM9000_DBG("transmitdone\n\n");443return0;444}

该函数的参数

structeth_devicenetdev:设备voidpacket:发送数据包存放的内存的首地址intlength:发送的数据包长度

414行 打开debug开关,该行会打印发送的数据包 416行 使能数据包发送,将寄存器ISR的bit[1]设置为1 419行 通过寄存器MWCMD写入一个地址,并向该地址对应的 SRAM 中写数据。
实行写该指令之后,写指针会根据操作模式(8 位或 16 位)自动增加 1 或 2。
422行 调用上一节db->outblk所赋值的函数将数据包发送的DM9000A的发送fifo中 425~426行 将发送数据包长度写入到寄存器TXPLL/TXPLH中,这两个寄存器分别对应低字节和高字节 429行 向寄存器TCR的bit[0]写入1,来要求发送数据,发送完毕该位自动清0 432~440行 通过向寄存器ISR的bit[1]写入1,来清楚发送标记位

个中发送函数dm9000_outblk_16bit() 定义如下:

159staticvoiddm9000_outblk_16bit(volatilevoiddata_ptr,intcount)160{161inti;162u32tmplen=(count+1)/2;163164for(i=0;i<tmplen;i++)165DM9000_outw(((u16)data_ptr)[i],DM9000_DATA);166}

164~165行 便是循环从地址DM9000_DATA读取数据并存储到data_ptr实行的内存中 此处我们看到每次都是从相同的地址读取数据,为什么不须要做地址偏移呢? 答:寄存器MWCMD已经和我们说的很清楚了,写该指令之后,指写指针根据操作模式(8 位或 16 位)增 加 1 或 2。

6. 数据的吸收

DM9000A的数据吸收

464staticintdm9000_rx(structeth_devicenetdev)465{466u8rxbyte,rdptr=(u8)NetRxPackets[0];467u16RxStatus,RxLen=0;468structboard_infodb=&dm9000_info;469470/Checkpacketreadyornot,wemustcheck471theISRstatusfirstforDM9000A/472if(!(DM9000_ior(DM9000_ISR)&0x01))/Rx-ISRbitmustbeset./473return0;474475DM9000_iow(DM9000_ISR,0x01);/clearPRstatuslatchedinbit0/476477/Thereis_atleast_1packageinthefifo,readthemall/478for(;;){479DM9000_ior(DM9000_MRCMDX);/Dummyread/480481/Getmostupdateddata,482onlylookatbits0:1,SeeapplicationnotesDM9000/483rxbyte=DM9000_inb(DM9000_DATA)&0x03;484485/Statuscheck:thisbytemustbe0or1/486if(rxbyte>DM9000_PKT_RDY){487DM9000_iow(DM9000_RCR,0x00);/StopDevice/488DM9000_iow(DM9000_ISR,0x80);/StopINTrequest/489printf("DM9000error:statuscheckfail:0x%x\n",490rxbyte);491return0;492}493494if(rxbyte!=DM9000_PKT_RDY)495return0;/Nopacketreceived,ignore/496497DM9000_DBG("receivingpacket\n");498499/Apacketreadynow&Getstatus/length/500(db->rx_status)(&RxStatus,&RxLen);501502DM9000_DBG("rxstatus:0x%04xrxlen:%d\n",RxStatus,RxLen);503504/MovedatafromDM9000/505/ReadreceivedpacketfromRXSRAM/506(db->inblk)(rdptr,RxLen);507508if((RxStatus&0xbf00)||(RxLen<0x40)509||(RxLen>DM9000_PKT_MAX)){510if(RxStatus&0x100){511printf("rxfifoerror\n");512}513if(RxStatus&0x200){514printf("rxcrcerror\n");515}516if(RxStatus&0x8000){517printf("rxlengtherror\n");518}519if(RxLen>DM9000_PKT_MAX){520printf("rxlengthtoobig\n");521dm9000_reset();522}523}else{524DM9000_DMP_PACKET(__func__,rdptr,RxLen);525526DM9000_DBG("passingpackettoupperlayer\n");527NetReceive(NetRxPackets[0],RxLen);528}529}530return0;531}

472行 DM9000A的寄存器ISR的bit[0]必须设置为1,否则无法吸收数据 475行 将ISR的bit[0]设置为1 479行 读取寄存器MRCMDX, 以从吸收 SRAM 中读数据;实行读取该指令之后,指向内部 SRAM的读指针不变。
DM9000A 开始预取 SRAM 中数据到内部数据缓冲中 483~494行 从地址DM9000_DATA中读取数据,从SRAM中读取的第一个数据的bit[0]必须是1,否则出错 500行 通过函数指针db->rx_status读取网卡的状态和吸收到的数据包的长度 506行 通过函数指针db->inblk从网卡中读取数据 527行 通过函数NetReceive()提交给上层协议栈

真正读取数据的函数是dm9000_inblk_16bit(); 定义如下:

staticvoiddm9000_inblk_16bit(voiddata_ptr,intcount){inti;u32tmplen=(count+1)/2;for(i=0;i<tmplen;i++)((u16)data_ptr)[i]=DM9000_inw(DM9000_DATA);}

事理类似于函数dm9000_outblk_16bit,不再重复。

由此可见,要剖析DM9000A的数据收发的事理和流程,就要剖析我们注册网卡的以下几个函数:

635dev->send=dm9000_send;636dev->recv=dm9000_rx;310db->outblk=dm9000_outblk_16bit;311db->inblk=dm9000_inblk_16bit;

标签:

相关文章

贴片电容以及电容测试座_电容_贴片

陶瓷贴片电容陶瓷贴片电容是市场上最常见的一种贴片电容。它具有极高的稳定性和可靠性,利用寿命长,适用于各种频率的电路中。钽贴片电容钽...

互联网 2025-01-19 阅读0 评论0