栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

r8169驱动源码阅读记录

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

r8169驱动源码阅读记录

源码地址:linux-4.19.90driversnetethernetrealtekr8169.c
源码阅读环境:Windows 搭建 opengrok|极客教程

阅读网卡驱动源码第一步,简要看一下发送描述符,接收描述符,发送缓存区,接收缓冲区定义与初始化
RTL8169数据手册
第九节介绍发送描述符与接收描述符
发送描述符

接收描述符

// 发送描述符
596  struct TxDesc {
597  	__le32 opts1;
598  	__le32 opts2;
599  	__le64 addr;		// 小端地址
600  };
// 接收描述符
602  struct RxDesc {
603  	__le32 opts1;
604  	__le32 opts2;
605  	__le64 addr;       // 小端地址
606  };
// 缓冲区相关定义
650  struct rtl8169_private {
657  	u32 cur_rx; 
658  	u32 cur_tx; 
659  	u32 dirty_tx;
660  	struct rtl8169_stats rx_stats;
661  	struct rtl8169_stats tx_stats;
662  	struct TxDesc *TxDescArray;	
663  	struct RxDesc *RxDescArray;	
664  	dma_addr_t TxPhyAddr;
665  	dma_addr_t RxPhyAddr;
666  	void *Rx_databuff[NUM_RX_DESC];	
667  	struct ring_info tx_skb[NUM_TX_DESC];	
715  };
// 缓冲区初始化
6860  	
6864  	tp->TxDescArray = dma_alloc_coherent(&pdev->dev, R8169_TX_RING_BYTES,
6865  					     &tp->TxPhyAddr, GFP_KERNEL);
6869  	tp->RxDescArray = dma_alloc_coherent(&pdev->dev, R8169_RX_RING_BYTES,
6870  					     &tp->RxPhyAddr, GFP_KERNEL);

手册中写明了描述符的大小与字节对齐要求

Each descriptor consists of 4 consecutive double words. The start address of each descriptor group should be 256-byte alignment.

然后看网络设备的操作函数,简要分析发包过程

7193  static const struct net_device_ops rtl_netdev_ops = {
7194  	.ndo_open		= rtl_open,
7195  	.ndo_stop		= rtl8169_close,
7197  	.ndo_start_xmit		= rtl8169_start_xmit,
7198  	.ndo_tx_timeout		= rtl8169_tx_timeout,
7210  };

1、网卡驱动创建tx descriptor ring(一致性DMA内存),将tx descriptor ring的总线地址写入网卡寄存器TDBA
2、协议栈通过dev_queue_xmit()将sk_buff下送网卡驱动
3、网卡驱动将sk_buff放入tx descriptor ring,更新TDT
4、DMA感知到TDT的改变后,找到tx descriptor ring中下一个将要使用的descriptor
5、DMA通过PCI总线将descriptor的数据缓存区复制到Tx FIFO
6、复制完后,通过MAC芯片将数据包发送出去
7、发送完后,网卡更新TDH,启动硬中断通知CPU释放数据缓存区中的数据包

6279  static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
6280  				      struct net_device *dev)
6281  {
6282  	struct rtl8169_private *tp = netdev_priv(dev);
6283  	unsigned int entry = tp->cur_tx % NUM_TX_DESC;
6284  	struct TxDesc *txd = tp->TxDescArray + entry;
6285  	struct device *d = tp_to_dev(tp);
6286  	dma_addr_t mapping;
6287  	u32 status, len;
6288  	u32 opts[2];
6289  	int frags;
6290  
6291  	if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
6292  		netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!n");
6293  		goto err_stop_0;
6294  	}
6295  
6296  	if (unlikely(le32_to_cpu(txd->opts1) & DescOwn))
6297  		goto err_stop_0;
6298  
6299  	opts[1] = cpu_to_le32(rtl8169_tx_vlan_tag(skb));
6300  	opts[0] = DescOwn;
6301  
6302  	if (!tp->tso_csum(tp, skb, opts)) {
6303  		r8169_csum_workaround(tp, skb);
6304  		return NETDEV_TX_OK;
6305  	}
6306  
6307  	len = skb_headlen(skb);
6308  	mapping = dma_map_single(d, skb->data, len, DMA_TO_DEVICE);
6309  	if (unlikely(dma_mapping_error(d, mapping))) {
6310  		if (net_ratelimit())
6311  			netif_err(tp, drv, dev, "Failed to map TX DMA!n");
6312  		goto err_dma_0;
6313  	}
6314  
6315  	tp->tx_skb[entry].len = len;
6316  	txd->addr = cpu_to_le64(mapping);
6317  
6318  	frags = rtl8169_xmit_frags(tp, skb, opts);
6319  	if (frags < 0)
6320  		goto err_dma_1;
6321  	else if (frags)
6322  		opts[0] |= FirstFrag;
6323  	else {
6324  		opts[0] |= FirstFrag | LastFrag;
6325  		tp->tx_skb[entry].skb = skb;
6326  	}
6327  
6328  	txd->opts2 = cpu_to_le32(opts[1]);
6329  
6330  	skb_tx_timestamp(skb);
6331  
6332  	
6333  	dma_wmb();
6334  
6335  	
6336  	status = opts[0] | len | (RingEnd * !((entry + 1) % NUM_TX_DESC));
6337  	txd->opts1 = cpu_to_le32(status);
6338  
6339  	
6340  	wmb();
6341  
6342  	tp->cur_tx += frags + 1;
6343  
6344  	RTL_W8(tp, TxPoll, NPQ);
6345  
6346  	mmiowb();
6347  
6348  	if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
6349  		
6352  		smp_wmb();
6353  		netif_stop_queue(dev);
6354  		
6361  		smp_mb();
6362  		if (TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS))
6363  			netif_wake_queue(dev);
6364  	}
6365  
6366  	return NETDEV_TX_OK;
6367  
6368  err_dma_1:
6369  	rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd);
6370  err_dma_0:
6371  	dev_kfree_skb_any(skb);
6372  	dev->stats.tx_dropped++;
6373  	return NETDEV_TX_OK;
6374  
6375  err_stop_0:
6376  	netif_stop_queue(dev);
6377  	dev->stats.tx_dropped++;
6378  	return NETDEV_TX_BUSY;
6379  }

TxDesc结构体即为发送描述符,其定义如下:

596  struct TxDesc {
597  	__le32 opts1;
598  	__le32 opts2;
599  	__le64 addr;
600  };

tp->TxDescArray为发送缓冲区

参考博客:
Linux 网络子系统
网卡驱动的收发包流程

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/940789.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号