1. dma buffer及zero-copy

在打开网卡时,stmmac_init_rx_buffers()函数负责分配dma buffer。

static int stmmac_init_rx_buffers(struct stmmac_priv *priv, struct dma_desc *p,int i, gfp_t flags, u32 queue)
{struct stmmac_rx_queue *rx_q = &priv->rx_queue[queue];struct sk_buff *skb;skb = __netdev_alloc_skb_ip_align(priv->dev, priv->dma_buf_sz, flags);if (!skb) {netdev_err(priv->dev,"%s: Rx init fails; skb is NULL\n", __func__);return -ENOMEM;}rx_q->rx_skbuff[i] = skb;rx_q->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,priv->dma_buf_sz,DMA_FROM_DEVICE);if (dma_mapping_error(priv->device, rx_q->rx_skbuff_dma[i])) {netdev_err(priv->dev, "%s: DMA mapping error\n", __func__);dev_kfree_skb_any(skb);return -EINVAL;}if (priv->synopsys_id >= DWMAC_CORE_4_00)p->des0 = cpu_to_le32(rx_q->rx_skbuff_dma[i]);elsep->des2 = cpu_to_le32(rx_q->rx_skbuff_dma[i]);if ((priv->hw->mode->init_desc3) &&(priv->dma_buf_sz == BUF_SIZE_16KiB))priv->hw->mode->init_desc3(p);return 0;
}

1)skb = __netdev_alloc_skb_ip_align(priv->dev, priv->dma_buf_sz, flags); 分配skb

2)rx_q->rx_skbuff[i] = skb; 用于zero-copy,以后再接收软中断中直接使用rx_q->rx_skbuff[i],并交给上层协议处理

3)rx_q->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data, priv->dma_buf_sz, DMA_FROM_DEVICE); 进行dma映射,得到rx_q->rx_skbuff_dma[i] 源地址(即物理地址)

4)p->des0 = cpu_to_le32(rx_q->rx_skbuff_dma[i]); 在des0设置源地址(即填充buffer地址)

2. 接收数据流程:

2.1. DMA产生中断,调用 stmmac_interrupt服务程序

2.2. stmmac_interrupt 通过调用 stmmac_dma_interrupt 处理DMA相关中断(包括发送和接收)。在stmmac_dma_interrupt中,通过NAPI机制触发软中断,调用stmmac_poll接收数据包。

2.3. 在stmmac_poll中调用如下代码收数据包

   work_done = stmmac_rx(priv, budget, rx_q->queue_index);if (work_done < budget) {napi_complete_done(napi, work_done);stmmac_enable_dma_irq(priv, chan);}return work_done;

1)调用stmmac_rx接收,budget为循环读取dma descriptor(通过处理descriptor来获取数据包,每个descriptor对应一个数据包)的最大次数,work_done为实际循环的次数。

2)if (work_done < budget) 代表实际循环读取dma descriptor的次数小于最大次数budget,代表已经处理完所有需要被处理的descriptor,取完所有的数据包。这时,调用stmmac_enable_dma_irq()开启中断,再次接收数据。如果work_done = budget,代表可能还有数据包需要处理,那么这些数据包留到net_rx_action再次调用stmmac_poll时处理。

3)return work_done; 该返回值会被net_rx_action使用。

2.4. 在stmmac_rx中,循环收包,循环次数while (count < limit)。每次循环以DMA descriptor为处理单位,即每次循环时从一个descriptor指定的buffer读取一个数据包,再通过 napi_gro_receive 送给协议层,处理完后count++。这里limit = budget。

2.5. 调用 stmmac_rx_refill重新填充descriptor。

在触发DMA中断前,DMA已经将网卡收到的数据包搬到descriptor指定的buffer,而这个buffer又采用了zero-copy机制,所以直接将该buffer的地址copy给一个skb,再将此skb送到协议层处理,最后再调用 stmmac_rx_refill重新填充descriptor并设置buffer。之前descriptor指定的buffer地址已经被赋值给skb,由协议层负责该skb(buffer)的管理(释放内存等)。

2.6. 总结:

这里有三种“一次获取多个数据包”的情况

1)一次软中断可能会多次调用net_rx_action

2)net_rx_action可能会多次调用stmmac_poll

3)stmmac_poll处理多个descriptor

网卡驱动:stmmac DMA接收流程相关推荐

  1. udp数据报从网卡驱动到用户空间流程总结

    附有相关介绍资料 NAPI驱动流程:     中断发生     -->确定中断原因是数据接收完毕(中断原因也可能是发送完毕,DMA完毕,甚至是中断通道上的其他设备中断)     -->通过 ...

  2. 网卡驱动:stmmac DMA发送流程

    1. 设置DAM buffer&descriptor,并启动DMA发送 在stmmac_xmit设置buffe r& descriptor,如下片段: if (likely(!is_j ...

  3. linux接收网络数据并存存储,Linux网络设备驱动之数据接收流程(六)

    网络设备接收数据的主要方法是由中断引发设备的中断处理函数,中断处理函数判断中断类型,如果为接收中断,则读取接收到的数据,分配 sk_buffer 数据结构和数据缓冲区,将接收到的数据复制到数据缓冲区, ...

  4. linux 串口 dma,STM32 USART串口DMA 接收和发送流程详解

    1.dma发送流程 1.配置DMA发送中断 - NVIC_Init 2.配置串口中断 - NVIC_Init 3.GPIO配置 - GPIO_Init 4.DMA发送配置 -DMA_Init  DMA ...

  5. Linux 网卡驱动相关——03

    紧接上一篇,这里简要介绍net_device 结构和网卡驱动框架. struct net_device  是一个比sk_buff 更复杂的结构,里面包含了与TCP/IP协议栈通信的接口函数,但是自从2 ...

  6. 【Linux高级驱动】如何分析并移植网卡驱动

    dm9000的驱动分析 m9000_init  platform_driver_register(&dm9000_driver); dm9000_probe  /*获取平台数据*/  stru ...

  7. linux内核网络协议栈--数据包的接收流程(二十三)

    网卡在接受数据包时会产生中断,即当 有一个以太网帧到来时,网卡向内核产生一次中断: CPU收到中断信号后,执行中断处理程序,中断处理程序会设置 缓冲区地址.DMA 地址等信息: 网卡通过DMA 方式将 ...

  8. arm平台linux的ethtool配置,ARM-Linux驱动--DM9000网卡驱动分析(四)

    原标题:ARM-Linux驱动--DM9000网卡驱动分析(四) 硬件平台:FL2440 (S3C2440) 内核版本:2.6.35 主机平台:Ubuntu 11.04 内核版本:2.6.39 交叉编 ...

  9. 网卡驱动(hisi3536网卡驱动,以及stmmac层)

    一:基本概念 应用程序最终以套接字的形式完成网络设备的接口.,对网络设备定义四个层次:网络协议接口层(数据包的发送接收,向网络层协议提供统一的数据包收发接口,舍得上层协议独立于具体的设备,(ip,ar ...

最新文章

  1. docker 启动sqlserver_在Docker上安装MSSQL(SQL Server)
  2. Windows Live Writer连接sharePoint博客时,有一个权限相关的BUG
  3. 如何订阅Form的自定义事件
  4. golang mysql proxy_mixer: 一个用go实现的mysql proxy
  5. 如何用Linux写c程序并编译运行
  6. 浅析人工智能的数学基础(文末送书!)
  7. flask使用tablib导出excel数据表
  8. 最长回文Manacher
  9. python pandas教程百家号_Pandas 常见的基本方法
  10. 【250期门诊集锦】痛并快乐着的正则表达式
  11. PBRT 学习:安装编译
  12. 经典机器学习系列(十三)【结构化学习】
  13. 使用JS完成一个简单的计算器功能
  14. windows mac谷歌浏览器跨域
  15. php过滤只匹配中英文字符串
  16. vue 管理系统顶部tags浏览历史实现
  17. 进入中国内地第31年的麦当劳 ,为什么还能不断吸引新消费人群?
  18. 官网下载QT不成功解决方案
  19. C++课程实训——银行系统
  20. 使用标准的接口和API导入料号

热门文章

  1. 是否应该立即将网站升级到Drupal 8?
  2. maven远程发布jar
  3. 【独家:震惊!——西城区所有学区优质度透解与大排名,泄密了!】
  4. Exchange 2013学习(六),脱机通讯簿
  5. puppet系列之nginx+php日志切割与salt结合使用
  6. 基于ASP.NET 3.5 Web Service 的JSON扩展应用
  7. 分享我做的博客园Skin(目前12个,最后更新时间2006-5-10 PM)
  8. 数据库中主键和外键的设计原则
  9. ajax headers 参数有什么用_动态爬虫(ajax)-爬取bilibili热门视频信息
  10. 成绩查询系统c语言,学生成绩查询系统C语言代码(分服务器端和客户端).doc