分类:
2016-08-03 10:28:33
8139 有一个接收缓冲寄存器,用于存放接收缓存的首地址,网卡一边把网线上的发出
的数据放到内部FIFO,一边从FIFO 中把数据通过DMA 传送到由接收寄存器指定的内存
地址中,接收到的数据依次排放,当长度超过默认的缓冲区长度时,会回过头来放到开
始的地方,所以接收缓冲区被称为环形缓冲区。
8139 有四个发送地址寄存器,CPU 将要发送的数据在内存中的地址写入这四个寄存器
中的任何一个,网卡就会通过DMA 操作把数据发送出去。
当发送或者接送完成后,网卡会发出中断,中断处理程序通过读取网卡的中断状态寄存
器来识别出是发送完成发出的中断,接收到数据包的中断,还是错误中断。
当运行ifconfig ethx up 的时候,rtl8139_open 得到调用。该函数的任务就是分配和初始
化接收及发送缓冲区,分配中断号,挂接中断处理程序等。
当网卡发生中断(如数据到达)时,中断控制器8259A 把中断号发给CPU, CPU 根据这个
中断号找到处理程序,这里就是rtl8139_interrupt,然后执行。rtl8139_interrupt 也是在我们
的程序中定义 好了的,这是驱动程序的一个重要的义务,也是一个基本的功能。request_irq
的代码在arch/i386/kernel/irq.c 中。
① 注册这个设备的中断处理函数。当网卡发送数据完成或者接收到数据时,是用中断
的形式来告知的,比如有数据从网线传来,中断也通知了我们,那么必须要有一个
处理这个中断的函数来完成数据的接收。就是中断号的分配,和内存地址映射一样,
中断号也是BIOS 在初始化阶段分配并写入设备的配置空间的,然后Linux 在建立
pci_dev 时从配置空间读 出这个中断号然后写入pci_dev 的irq 成员中,所以我们注
册中断程序需要中断号就是直接从pci_dev 里取就可以了。
request_irq 的代码在arch/i386/kernel/irq.c 中
② 分配发送和接收的缓存空间
根据官方文档,发送一个数据包的过程是这样的:先从应用程序中把数据包拷贝到
一段连续的内存中(这段内存就是我们这里要分配的缓存),然后把这段内存的地
址写进网卡的数据发送地址寄存器(TSAD)中,这个寄存器的偏移量是TxAddr0 =
0x20。在把这个数据包的长度写进另一个寄存器(TSD)中,它的偏移量是TxStatus0
= 0x10。然后就把这段内存的数据发送到网卡内部的发送缓冲中(FIFO),最后由这个
发送缓冲区把数据发送到网线上。
tx_bufs 是发送缓冲内存的首地址,rx_ring 是接收缓存内存的首地址,他们都是虚
拟地址,而最后 一个参数tx_bufs_dma 和rx_ring_dma 均是这一段内存的物理地址。
为什么同一个事物,既用虚拟地址来表示它还要用物理地址呢,是这样 的,CPU
执行程序用到这个地址时,用虚拟地址,而网卡设备向这些内存中存取数据时用的
是物理地址( 因为网卡相对CPU 属于头脑比较简单型的)。
pci_alloc_consistent 的代码在Linux/arch/i386/kernel/pci‐dma.c
中。
③发送和接收缓冲区初始化和网卡开始工作的操作
RTL8139 有4 个发送描述符(包括4 个发送缓冲区的基地址寄存器(TSAD0‐TSAD3)
和4 个发送状态寄存器(TSD0‐TSD3)。也就是说我们分配的缓冲区要分成四个等分
并把这四个空间的地址都写到相关寄存器里去,下面这段代码完成了这个操作。
for (i = 0; i < NUM_TX_DESC; i++)
((struct rtl8139_private*)dev‐>priv)‐>tx_buf[i] =
&((struct rtl8139_private*)dev‐>priv)‐>tx_bufs[i * TX_BUF_SIZE];
上面这段代码负责把发送缓冲区虚拟空间进行了分割。
for (i = 0; i < NUM_TX_DESC; i++)
{
writel(tp‐>tx_bufs_dma+(tp‐>tx_buf[i]tp‐>tx_bufs),ioaddr+TxAddr0+(i*4));
readl(ioaddr+TxAddr0+(i * 4));
}
上面这段代码负责把发送缓冲区物理空间进行了分割,并把它写到了相关寄存器
中,这样在网卡开始工作后就能够迅速定位和找到这些内存并存取他们的数据。
writel(tp‐>rx_ring_dma,ioaddr+RxBuf);
上面这行代码是把接收缓冲区的物理地址写到了相关寄存器中,这样网卡接收到
数据后就能准确的把数据从网卡中搬运到这些内存空间中,等待CPU 来领走他们。
|
|
rtl8139_hw_start 主要是对网卡芯片进行初始化,主要就是根据网卡的硬件手册,
Programming guide 向一些寄存器写入某些值。接下来我们将看到大量类似的操作。
|
以上都是向某个地址写入一些值,基地址是PCI 总线驱动程序配置的,某个偏移位置的地址
代表什么意思,该写入什么值是功能设备的芯片逻辑规定的。以接收配置寄存器为例:
接收模式参数寄存器编号为RxConfig = 0x44, 即该寄存器地址偏移是0x44
AcceptAllPhys 被定义为0x01, AcceptMyPhys 被定义为0x02,
就是说该寄存器的最低位为1 时,网卡会进入混杂模式接收所有的帧,
第1 位为0,第2 位为1 时,只接收目的MAC 地址为自己的帧。
彻底的搞清楚每一个寄存器的每个BIT 代表什么实在是没有必要,不同的网卡芯片都是不一
样的。
|
|
|
|
|