Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1307810
  • 博文数量: 548
  • 博客积分: 7597
  • 博客等级: 少将
  • 技术积分: 4224
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-15 13:21
个人简介

嵌入式软件工程师&&太极拳

文章分类

全部博文(548)

文章存档

2014年(10)

2013年(76)

2012年(175)

2011年(287)

分类: 嵌入式

2012-05-09 13:44:31


点击(此处)折叠或打开

  1. /*
  2.  * 驱动内接收数据包过程
  3.  * at91rm9200 - dm9161 - 2.6.20
  4.  */

  5. 当MAC有数据包接收到,并且顺利的通过DMA拷贝到了驱动里设置的接收缓冲区之后,
  6. 会触发一个RCOM(接收完成)的中断,驱动在中断处理例程中调用at91ether_rx(dev)
  7. 进行处理。

  8. 首先,这里说明一下AT91rm9200的MAC硬件部分是怎么做接收缓冲的。


  9. #define MAX_RBUFF_SZ 0x600 /* 1518 rounded up */
  10. #define MAX_RX_DESCR 9 /* max number of receive buffers */

  11. /* zhs: used in buflist entry's word0 */
  12. #define EMAC_DESC_DONE 0x00000001 /* bit for if DMA is done */
  13. #define EMAC_DESC_WRAP 0x00000002 /* bit for wrap */

  14. #define EMAC_BROADCAST 0x80000000 /* broadcast address */
  15. #define EMAC_MULTICAST 0x40000000 /* multicast address */
  16. #define EMAC_UNICAST 0x20000000 /* unicast address */

  17. struct rbf_t
  18. {
  19.  unsigned int addr; //descriptor's word0
  20.  unsigned long size; //descriptor's word1
  21. };

  22. struct recv_desc_bufs
  23. {
  24.  struct rbf_t descriptors[MAX_RX_DESCR]; /* must be on sizeof (rbf_t) boundary */
  25.  char recv_buf[MAX_RX_DESCR][MAX_RBUFF_SZ]; /* must be on long boundary */
  26. };

  27. struct at91_private
  28. {
  29.  struct net_device_stats stats;
  30.  struct mii_if_info mii; /* ethtool support */
  31.  struct at91_eth_data board_data; /* board-specific configuration */
  32.  struct clk *ether_clk; /* clock */

  33.  /* PHY */
  34.  unsigned long phy_type; /* type of PHY (PHY_ID) */
  35.  spinlock_t lock; /* lock for MDI interface */
  36.  short phy_media; /* media interface type */
  37.  unsigned short phy_address; /* 5-bit MDI address of PHY (0..31) */
  38.  struct timer_list check_timer; /* Poll link status zhs: 用于轮询(没有中断) */

  39.  /* Transmit */
  40.  struct sk_buff *skb; /* holds skb until xmit interrupt completes. zhs: just for tx */
  41.  dma_addr_t skb_physaddr; /* phys addr from pci_map_single */
  42.  int skb_length; /* saved skb length for pci_unmap_single */

  43.  /* Receive */
  44.  int rxBuffIndex; /* index into receive descriptor list */
  45.  struct recv_desc_bufs *dlist; /* descriptor list address. */
  46.  struct recv_desc_bufs *dlist_phys; /* descriptor list physical address */
  47. }


  48. 以上的宏和结构体定义提供了对于at91rm9200的MAC硬件接收和发送的支持。这里说
  49. 明下接收的情况。

  50. 如果一个包接收后,经过地址验证后没问题的话,该包被DMA存储到接收缓冲中去。

  51. 接收缓冲区是为MAX_RBUFF_SZ大小的一个内存空间,这里定义了MAX_RX_DESCR个接收
  52. 缓冲区。其实以太网内最大的包大小为1522.

  53. 驱动需要提供给MAC硬件的缓冲区的格式是MAC硬件要求的规定格式.多个的接收缓冲
  54. 区被组织成一个list。这个list被叫作descriptor list(描述符列表)。每个list的
  55. 节点为一个叫作descriptor(dp)或者一个list entry,每个dp有两个word组成,分别
  56. 为word0和word1,结构体 struct rbf_t就为这个list entry,结构体内的addr就为
  57. word0, size为word1。因为 int 和 long 类型都是4字节的,所以这个结构体是字对
  58. 齐的,不用担心hole问题。

  59. 而list这个结构则有结构体 struct recv-desc_bufs来维护,里面有两个成员变量.
  60. 一个是dp的数组,为实际的list,即这个数组就是list的实体。 另一个为缓冲区的
  61. 数组,每个缓冲区大小为MAX_RBUFF_SZ,有MAX_RX_DESCR个缓冲区。

  62. 在 struct at91_private结构体中的 Receive段有三个成员变量来维护接收缓冲区.
  63. int rxBuffIndex表示当前软件中处理的list的入口标号,即是对那个缓冲区进行处
  64. 理。struct recv_desc_bufs *dlist指向descriptor list的虚拟内存地址,在驱动
  65. 中调用并操作list。struct recv_desc_bufs *dlist_phys用来保存描述符列表的物
  66. 理地址,便于MAC硬件和DMA处理。而对于dlist_phys的初始化在at91ether_setup中
  67. 进行。

  68. 至于MAC对接收缓冲列表的具体处理过程和list entry每个word代表的含义可以参考
  69. at91rm9200的datasheet。

  70. void at91ether_rx(struct net_device *dev) 这个函数在MAC的中断处理例程中被
  71. 调用,在中断上下文中对接收到的包进行处理,并提交给内核上层。

  72. at91ether_rx(dev)
  73.  |
  74.  取得private和dlist数据
  75.  |
  76.  循环检查list的每个entry
  77.  |
  78.  -----------------------------
  79.  | |
  80.  如果缓冲区中有新包数据 如果没有新包数据
  81.  | |
  82.  取出实际数据包头地址和长度 |
  83.  这个时候的包地址已经是虚拟 |
  84.  内存地址了 |
  85.  | |
  86.  分配skb套接字缓冲区 |
  87.  | |
  88.  拷贝包数据到skb中 |
  89.  | |
  90.  设置skb其他成员变量 |
  91.  | |
  92.  netif_rx(skb) |
  93.  传输给内核上层 |
  94.  | |
  95.  标记该缓冲区已处理 |
  96.  | |
  97.  对index处理 |
  98.  | |
  99.  -------------------------------------
  100.  |
  101. |


  102. /*
  103.  * 驱动内发送数据包过程
  104.  * at91rm9200 - dm9161 - 2.6.20
  105.  */

  106. dev_queue_xmit --> dev_hard_start_xmit --> hard_start_xmit(指向驱动函数)

  107. 以上为发送数据包的大致流程。来自IP层的的一个套接字结构体struct sk_buff存
  108. 放在内核维护的发送队列中。在发送队列能够发送一个套接字缓冲区时,调用这个
  109. 函数:dev_queue_xmit(). 该函数的参数为 struct sk_buff *skb, 通过skb->dev
  110. 可以取得这个套接字缓冲区所要发送到的设备, struct net_device dev = skb->dev;
  111. 获得dev之后,就可以获得操作该网络设备的能力了。检测网络设备硬件状况,如果
  112. 符合要求能够发送数据包,则调用dev_hard_start_xmit(skb, dev)发送包。

  113. 在int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
  114. 通过dev->hard_start_xmit(skb, dev)来执行实际的发送动作.这里dev的成员函数
  115. hard_start_xmit()是一个函数指针,在dev的驱动初始化过程中应该应该初始化好
  116. 了的。对于at91rm9200-dm9161,该函数为at91_ether.c中的at91ether_tx()函数.

  117. int at91ether_tx(struct sk_buff *skb, struct net_device *dev)函数中,执行
  118. 的流程如下:

  119. at91ether_tx(skb, dev);
  120.  |
  121.  取得private数据
  122.  |
  123.  检查EMAC寄存器,硬件是否可以发送数据包
  124.  |
  125.  ------------------------------------------
  126.  | |
  127.  如果可以发送 如果不能发送
  128.  | |
  129.  netif_stop_queue(dev) 打印一条设备忙信息
  130.  暂停发送队列,即不启动其他包发送 |
  131.  可以在硬件发送完成的中断中唤醒队列 返回1
  132.  | |
  133.  将skb相关信息配置到private的发送相 |
  134.  关的成员变量中,并配置发送的DMA. |
  135.  | |
  136.  配置好之后,写EMAC,包括数据包的物 |
  137.  理地址和发送长度,即开始一次硬件发 |
  138.  送 |
  139.  | |
  140.  返回0 |
  141.  | |
  142. |<------------------------------------------------

  143. 这里对于虚拟内存中的套接字缓冲区skb,调用了以下的函数:
  144.  lp->skb_physaddr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE);
  145. 这个函数应该是将虚拟内存的地址转化为物理地址,并存放在private中的成员变量
  146. skb_physaddr中,再调用at91_emac_write(AT91_EMAC_TAR, lp->skb_physaddr);
  147. 要发送的套接字缓冲区物理地址写到EMAC的Transmit Address Register中,这样就
  148. 可以在发送这个物理硬件过程和DMA中直接处理物理地址。

  149. 这个发送函数的返回值不同,则处理有不同。如果返回的是1,即不能发送,则调用
  150. 驱动函数的dev_queue_xmit函数会在调用这个驱动函数之后释放掉skb套接字缓冲区
  151. 占用的内存空间;而如果返回的是0,即交由了硬件发送,则在发送完成(包括发送
  152. 失败的情况)的中断处理例程中,会释放掉由private中成员变量所指向的套接字缓

阅读(623) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~