1 硬件布局

每个网卡(MAC)都有自己的专用DMA Engine,如上图的 TSEC 和 e1000 网卡intel82546。

上图中的红色线就是以太网数据流,DMA与DDR打交道需要其他模块的协助,如TSEC,PCI controller

以太网数据在 TSEC<-->DDR PCI_Controller<-->DDR 之间的流动,CPU的core是不需要介入的

只有在数据流动结束时(接收完、发送完),DMA Engine才会以外部中断的方式告诉CPU的core

2 DMA Engine

上面是DMA Engine的框图,以接收为例:

1.在System memory中为DMA开辟一端连续空间,用来BD数组 (一致性dma内存)

BD是给DMA Engine使用的,所以不同的设备,BD结构不同,但是大致都有状态、长度、指针3个成员。

2.初始化BD数组,status为E,length为0

在System memory中再开辟一块一块的内存,可以不连续,用来存放以太网包

将这些内存块的总线地址赋给buf(dma映射)

3.当MAC接收以太网数据流,放在了Rx FIFO中

4.当一个以太网包接收完全后,DMA engine依次做以下事情

fetch bd:开始一个个的遍历BD数组,直到当前BD状态为Empty为止

update bd:更新BD状态为Ready

move data:把数据从Rx FIFO中搬移到System Memory中dma映射的部分

generate interrupt:数据搬移完了,产生外部中断给cpu core

5.cpu core处理外部中断,此时以太网数据已经在System memory中dma映射的部分了

解除dma映射,更新bd状态为Empty

再开辟一端内存,将这块内存的总线地址赋给bd的指针字段

3 内核中DMA相关API

void *dma_alloc_cohrent(struct device *dev, size_t size, dma_addr_t *dma_handle, int flag);

功能:分配一致性dma内存,返回这块内存的虚拟地址EA, 这块内存的物理地址保存在 dma_handle

dev: NULL也行

size: 分配空间的大小

dma_handle: 用来保存内存的总线地址(物理地址)

注意:一致性DMA映射,BD所占内存就是靠dma_alloc_cohrent来分配的。

dma_addr_t *dma_map_single(struct device *dev, void *buffer, size_t size, enum dma_data_direction);

功能:将一块连续的内存 buffer 映射为DMA内存来使用。映射后,CPU不能再操作这块 buffer

返回:这块buffer的总线地址(物理地址)

dev: NULL也行

buffer: 一块连续内存的虚拟地址EA

size: 连续内存的大小

dma_data_direction: dma数据流的方向

注意:流式DMA映射,以太网包所占内存先通过kmalloc来分配,然后通过dma_map_single来映射给bd的

4 e1000驱动中的DMA

网卡驱动中使用DMA的套路差不多都一样,以e1000驱动为例讲一下

4.1 加载e1000网卡驱动

e1000_probe(){                        //主要是初始化钩子函数netdev = alloc_etherdev(sizeof(struct e1000_adapter));netdev->open = &e1000_open;       //重要netdev->stop = &e1000_close;netdev->hard_start_xmit = &e1000_xmit_frame;netdev->get_stats = &e1000_get_stats;netdev->set_multicast_list = &e1000_set_multi;netdev->set_mac_address = &e1000_set_mac;netdev->change_mtu = &e1000_change_mtu;netdev->do_ioctl = &e1000_ioctl;e1000_set_ethtool_ops(netdev);netdev->tx_timeout = &e1000_tx_timeout;netdev->watchdog_timeo = 5 * HZ;
#ifdef CONFIG_E1000_NAPInetif_napi_add(netdev, &adapter->napi, e1000_clean, 64); //重要
#endif
}

4.2 启动e1000网卡

   e1000_open() //当用户敲ifconfig up命令时,最终调用网卡驱动的open函数-->e1000_setup_all_rx_resources(adapter)-->e1000_setup_rx_resources(adapter, &adapter->rx_ring[i])//给rx bd分配一致性dma内存rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);-->e1000_configure(adapter)-->e1000_configure_rx(adapter)adapter->clean_rx = e1000_clean_rx_irq;adapter->alloc_rx_buf = e1000_alloc_rx_buffers;-->调用 adapter->alloc_rx_buf钩子函数,即 e1000_alloc_rx_buffers--> skb = netdev_alloc_skb(netdev, bufsz); //调用kmalloc新建一个skbbuffer_info->dma = pci_map_single(pdev,skb->data,adapter->rx_buffer_len,PCI_DMA_FROMDEVICE);               //给skb->data建立DMA映射rx_desc->buffer_addr = cpu_to_le64(buffer_info->dma);//初始化bd的buf指针-->e1000_request_irq(adapter);//挂rx 中断ISR函数为 e1000_intr()

最终bd数据结构应该是下面这个样子

4.3 e1000的中断

注意:e1000产生rx中断时,以太网数据包已经在系统内存中,即在skb->data里面

下面的中断处理过程就简略了,

do_IRQ()

{

中断上半部

调用e1000网卡的rx中断函数 e1000_intr()

触发软中断 (使用NAPI的话)

中断下半部

依次调用软中断的所有handler

在net_rx_action中最终调用e1000的napi_struct.poll()钩子函数,即e1000_clean

e1000_clean()最终调用 e1000_clean_rx_irq()

}

e1000_clean_rx_irq()
{rx_desc = E1000_RX_DESC(*rx_ring, i); //获取rx bdstatus = rx_desc->status;skb = buffer_info->skb;buffer_info->skb = NULL;pci_unmap_single(pdev,                //解除skb->data的DMA映射buffer_info->dma,buffer_info->length,PCI_DMA_FROMDEVICE);length = le16_to_cpu(rx_desc->length);length -= 4;                          //以太网包的FCS校验就不要了skb_put(skb, length);skb->protocol = eth_type_trans(skb, netdev);netif_receive_skb(skb);               //skb进入协议栈
}

e1000网卡和DMA相关推荐

  1. 网络数据包收发流程(三):e1000网卡和DMA

    早就想整理网络数据包收发流程了,一直太懒没动笔.今天下决心写了 一.硬件环境 intel82546:PHY与MAC集成在一起的PCI网卡芯片,很强大 bcm5461:   PHY芯片,与之对应的MAC ...

  2. e1000网卡驱动小结

    1.网卡的初始化 e1000网卡的初始化调用函数e1000_probe(),网卡作为一种PCI设备就要初始化PCI设备的一些属性,设置DMA,初始化驱动的操作函数(收包函数.发包函数).设置循环队列缓 ...

  3. intel e1000 网卡 napi分析

    内核如何从网卡接收数据,传统的过程: 1.数据到达网卡: 2.网卡产生一个中断给内核: 3.内核使用I/O指令,从网卡I/O区域中去读取数据: 我们在许多网卡驱动中(很老那些),都可以在网卡的中断函数 ...

  4. 6.S081 lab: networking e1000 网卡驱动 附 Linux 网卡驱动编写分析

    本文是 6.S081 操作系统课程学习最后一个 lab,编写一个 intel 的 e1000 网卡的驱动在 xv6 下.需要复习知识有:操作系统知识,计算机组成原理 DMA 相关,循环缓冲区的概念,e ...

  5. Intel e1000 网卡

    参考资料: 1.Intel 82547 网卡 开发 手册.其他Intel网卡的手册应该也可以从网上下载到. http://linux.chinaunix.net/bbs/thread-1142051- ...

  6. e1000网卡驱动初感受

    在网络上搜索到一片Linux-千兆网卡驱动实现机制浅析,自己大概浏览了一下,觉得写得很好,可是自己没有看明白的时候还是白扯.想起来一句话,文档时写给已经懂了的人的.这句话在我做一个小东西的时候领悟的特 ...

  7. linux网卡e1000下载,Linux E1000网卡驱动分析

    本分析主要针对e1000网卡,驱动源码为7.3.20-k2.本文的目的不是为了讲述如何编写驱动程序,主要是分析网卡驱动内部的实现机制. Linux-千兆网卡驱动实现机制浅析 作者: Minit, 出处 ...

  8. mandrake安装INTEL e1000网卡驱动

    使用U盘 #mkdir /usb #mount /dev/sda1 /usb 或 #mount /dev/scsi/host1/bus0/target0/lun0/disc /usb 如果你的电脑上还 ...

  9. Centos6.5更新e1000网卡驱动

    在工作过程中经常遇到linux的操作系统网络不正常的情况,以前没有注意到,今天查看系统日志发现原来是网络驱动的问题.索性直接更新系统,更新网卡 问题:linux系统经常出现断网的情况,重启之后系统恢复 ...

最新文章

  1. windows下检测网站是否正常运行并自动重启服务
  2. 爬虫工具篇 - 必会用的 6 款 Chrome 插件
  3. 信息安全与网络安全,你分清了吗?
  4. linux下安装使用libuuid(uuid-generate)
  5. go WaitGroup 简单示例
  6. Adroid学习之 从源码角度分析-禁止使用回退按钮方案
  7. java数组 0912
  8. 华为鸿蒙理性,华为的理性,鸿蒙的节奏
  9. MDK、keil复制中文注释乱码
  10. ue4账号注册不了_英雄联盟手游拳头账号注册
  11. Win32 SDK - 打开文件对话框
  12. Node JS和MongoDB的集成简单示例
  13. vue和js点击下载pdf,word,png,jpg等格式的文件,解决点击下载pdf却是打开预览的问题
  14. 龙芯源码编译mysql_使用源码包在龙芯2F上安装mysql
  15. TFN频谱仪为什么好用以150为例
  16. 雷军内部信:米家有品拆分 做独立电商
  17. Navicat绘制数据库物理模型
  18. 最佳化三维建模与重构中的神经网络先验
  19. [ROC-RK3568-PC] 手把手教你编译Linux_SDK并打包Buildroot系统固件
  20. 2019湖南对口升学计算机c语言试卷,2019年湖南省中等职业学校对口升学考试:计算机文化基础+计算机应用基础模拟试卷...

热门文章

  1. CentOS 7安装 MySQL5.7之后,登录提示ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using passw
  2. 亮灯泡科技php,记科学小实验《灯泡亮了》
  3. Cadence OrCAD Capture 检索和定位功能的介绍图文视频教程
  4. 《微型计算机原理与接口技术》复习笔记(三)
  5. 思科交换机如何配置Trunk?
  6. SCI论文写作的学习与总结
  7. 站内通知 java组件,spring-aop组件详解——Advice通知
  8. Enhanced ShockBurst (ESB)原文翻译
  9. 北斗时钟服务器(GPS卫星同步时钟)应用电子政务系统
  10. Python 3.x 学习笔记