您的当前位置:首页正文

Linux设备驱动—网卡驱动程序

2020-11-11 来源:个人技术集锦
Linux设备驱动工程师之路——DM9000网卡驱动程序分析

Linux设备驱动工程师之路——DM9000网卡驱动程序分析

K-Style

转载请注明来自于衡阳师范学院08电

2 K-Style http://blog.csdn.net/ayangke,QQ:843308498 邮箱:yangkeemail@qq.com DM9000是开发板经采用的网络芯片,是一种高度集成而且功耗很低的高速网络控制器,可以和CPU直连,支持10/100M以太网连接,芯片内部自带16K SARM(3KB用来发送,13KB用来接收). 1.模块初始化

[html] view plaincopy

1. static struct platform_driver dm9000_driver = { 2. .driver = {

3. .name = \"dm9000\", 4. .owner = THIS_MODULE, 5. },

6. .probe = dm9000_probe,

7. .remove = __devexit_p(dm9000_drv_remove), 8. .suspend = dm9000_drv_suspend, 9. .resume = dm9000_drv_resume, 10. }; 11.

12. static int __init 13. dm9000_init(void) 14. {

15. printk(KERN_INFO \"%s Ethernet Driver, V%s\\n\ 16.

17. return platform_driver_register(&dm9000_driver); 18. }

模块初始化完成了基于platfrom平台的DM9000网卡驱动的注册,当DM9000网卡找到其对应的能处理的platform设备后调用probe函数。

2.DM9000网卡初始化

在probe函数中完成了对DM9000网卡的初始化

DM9000的特性:DM9000地址信号和数据信号复用使用CMD引脚区分它们(CMD为低是读写DM900地址寄存器,CMD为高时读写DM9000数据寄存器),访问DM9000内部寄存器时,先将CMD置低,写DM900地址寄存器,然后将CMD置高,读写DM9000数据寄存器。

[html] view plaincopy

1. static int __devinit

2. dm9000_probe(struct platform_device *pdev) 3. {

4. struct dm9000_plat_data *pdata = pdev->dev.platform_data;

5. struct board_info *db; /* Point a board information structure */ 6. struct net_device *ndev; 7. const unsigned char *mac_src; 8. int ret = 0; 9. int iosize; 10. int i; 11. u32 id_val; 12.

13. /* Init network device */ 14. //申请net_device结构

15. ndev = alloc_etherdev(sizeof(struct board_info)); 16. if (!ndev) {

17. dev_err(&pdev->dev, \"could not allocate device.\\n\"); 18. return -ENOMEM; 19. } 20. 21.

22. //将net_device的parent指针指向platform_device对象,表示该设备挂载platform设备

上。

23. SET_NETDEV_DEV(ndev, &pdev->dev); 24.

25. dev_dbg(&pdev->dev, \"dm9000_probe()\\n\"); 26.

27. /* setup board info structure */ 28. //获取net_device私有数据结构指针 29. db = netdev_priv(ndev); 30. memset(db, 0, sizeof(*db)); 31.

32. //设置相关设备

33. db->dev = &pdev->dev; 34. db->ndev = ndev; 35.

36. spin_lock_init(&db->lock); 37. mutex_init(&db->addr_lock);

38.

39. INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work); 40.

41. //获取平台设备资源。包括DM9000地址寄存器地址,DM9000数据寄存器地址,和DM900

所占用的中断号 42.

43. db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 44. db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 45. db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 46.

47. if (db->addr_res == NULL || db->data_res == NULL || 48. db->irq_res == NULL) {

49. dev_err(db->dev, \"insufficient resources\\n\"); 50. ret = -ENOENT; 51. goto out; 52. } 53.

54. //申请地址寄存器IO内存区域并映射 55. iosize = res_size(db->addr_res);

56. db->addr_req = request_mem_region(db->addr_res->start, iosize, 57. pdev->name); 58.

59. if (db->addr_req == NULL) {

60. dev_err(db->dev, \"cannot claim address reg area\\n\"); 61. ret = -EIO; 62. goto out; 63. } 64.

65. db->io_addr = ioremap(db->addr_res->start, iosize); 66.

67. if (db->io_addr == NULL) {

68. dev_err(db->dev, \"failed to ioremap address reg\\n\"); 69. ret = -EINVAL; 70. goto out; 71. } 72.

73. //申请数据寄存器IO内存区域并映射 74. iosize = res_size(db->data_res);

75. db->data_req = request_mem_region(db->data_res->start, iosize, 76. pdev->name); 77.

78. if (db->data_req == NULL) {

79. dev_err(db->dev, \"cannot claim data reg area\\n\"); 80. ret = -EIO;

81. goto out; 82. } 83.

84. db->io_data = ioremap(db->data_res->start, iosize); 85.

86. if (db->io_data == NULL) {

87. dev_err(db->dev, \"failed to ioremap data reg\\n\"); 88. ret = -EINVAL; 89. goto out; 90. } 91.

92. /* fill in parameters for net-dev structure */ 93. ndev->base_addr = (unsigned long)db->io_addr; 94. ndev->irq = db->irq_res->start; 95.

96. //设置数据位宽

97. /* ensure at least we have a default set of IO routines */ 98. dm9000_set_io(db, iosize); 99.

100. /* check to see if anything is being over-ridden */ 101. if (pdata != NULL) {

102. /* check to see if the driver wants to over-ride the 103. * default IO width */ 104.

105. if (pdata->flags & DM9000_PLATF_8BITONLY) 106. dm9000_set_io(db, 1); 107.

108. if (pdata->flags & DM9000_PLATF_16BITONLY) 109. dm9000_set_io(db, 2); 110.

111. if (pdata->flags & DM9000_PLATF_32BITONLY) 112. dm9000_set_io(db, 4); 113.

114. /* check to see if there are any IO routine 115. * over-rides */ 116.

117. if (pdata->inblk != NULL) 118. db->inblk = pdata->inblk; 119.

120. if (pdata->outblk != NULL) 121. db->outblk = pdata->outblk; 122.

123. if (pdata->dumpblk != NULL) 124. db->dumpblk = pdata->dumpblk;

125.

126. db->flags = pdata->flags; 127. } 128.

129. #ifdef CONFIG_DM9000_FORCE_SIMPLE_PHY_POLL 130. db->flags |= DM9000_PLATF_SIMPLE_PHY; 131. #endif 132.

133. //复位网卡芯片 134. dm9000_reset(db); 135.

136. //读取设备ID,判断是否是驱动能够处理的网卡芯片

137. /* try multiple times, DM9000 sometimes gets the read wrong */ 138. for (i = 0; i < 8; i++) {

139. id_val = ior(db, DM9000_VIDL);

140. id_val |= (u32)ior(db, DM9000_VIDH) << 8; 141. id_val |= (u32)ior(db, DM9000_PIDL) << 16; 142. id_val |= (u32)ior(db, DM9000_PIDH) << 24; 143.

144. if (id_val == DM9000_ID) 145. break;

146. dev_err(db->dev, \"read wrong id 0x%08x\\n\ 147. } 148.

149. if (id_val != DM9000_ID) {

150. dev_err(db->dev, \"wrong id: 0x%08x\\n\ 151. ret = -ENODEV; 152. goto out; 153. } 154.

155. /* Identify what type of DM9000 we are working on */ 156.

157. id_val = ior(db, DM9000_CHIPR);

158. dev_dbg(db->dev, \"dm9000 revision 0x%02x\\n\ 159.

160. switch (id_val) { 161. case CHIPR_DM9000A:

162. db->type = TYPE_DM9000A; 163. break;

164. case CHIPR_DM9000B:

165. db->type = TYPE_DM9000B; 166. break; 167. default:

168. dev_dbg(db->dev, \"ID %02x => defaulting to DM9000E\\n\

169. db->type = TYPE_DM9000E; 170. } 171.

172. /* from this point we assume that we have found a DM9000 */ 173.

174. /* driver system function */ 175. ether_setup(ndev); 176.

177. //设置网卡芯片的接口函数

178. ndev->open = &dm9000_open;

179. ndev->hard_start_xmit = &dm9000_start_xmit; 180. ndev->tx_timeout = &dm9000_timeout; 181. ndev->watchdog_timeo = msecs_to_jiffies(watchdog); 182. ndev->stop = &dm9000_stop;

183. ndev->set_multicast_list = &dm9000_hash_table; 184. ndev->ethtool_ops = &dm9000_ethtool_ops; 185. ndev->do_ioctl = &dm9000_ioctl; 186.

187. #ifdef CONFIG_NET_POLL_CONTROLLER

188. ndev->poll_controller = &dm9000_poll_controller; 189. #endif 190.

191. db->msg_enable = NETIF_MSG_LINK; 192. db->mii.phy_id_mask = 0x1f; 193. db->mii.reg_num_mask = 0x1f; 194. db->mii.force_media = 0; 195. db->mii.full_duplex = 0; 196. db->mii.dev = ndev;

197. db->mii.mdio_read = dm9000_phy_read; 198. db->mii.mdio_write = dm9000_phy_write; 199.

200. mac_src = \"eeprom\"; 201.

202. //从EEPROM中读取MAC地址填充dev_addr

203. /* try reading the node address from the attached EEPROM */ 204. for (i = 0; i < 6; i += 2)

205. dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i); 206.

207. if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) { 208. mac_src = \"platform data\";

209. memcpy(ndev->dev_addr, pdata->dev_addr, 6); 210. } 211.

212. if (!is_valid_ether_addr(ndev->dev_addr)) {

213. /* try reading from mac */ 214.

215. mac_src = \"chip\"; 216. for (i = 0; i < 6; i++)

217. ndev->dev_addr[i] = ior(db, i+DM9000_PAR); 218. } 219.

220. if (!is_valid_ether_addr(ndev->dev_addr))

221. dev_warn(db->dev, \"%s: Invalid ethernet MAC address. Please \" 222. \"set using ifconfig\\n\>name); 223.

224. //设置平台设备驱动的dev成员为ndev。 225. platform_set_drvdata(pdev, ndev); 226.

227. //注册网络设备驱动

228. ret = register_netdev(ndev); 229.

230. if (ret == 0)

231. printk(KERN_INFO \"%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\\n\ 232. ndev->name, dm9000_type_to_char(db->type), 233. db->io_addr, db->io_data, ndev->irq, 234. ndev->dev_addr, mac_src); 235. return 0; 236. 237. out:

238. dev_err(db->dev, \"not found (%d).\\n\ 239.

240. dm9000_release_board(pdev, db); 241. free_netdev(ndev); 242.

243. return ret; 244. }

我们在来看看读写网卡寄存器所用的ior和iow

[html] view plaincopy

1. static u8

2. ior(board_info_t * db, int reg) 3. {

4. writeb(reg, db->io_addr); 5. return readb(db->io_data); 6. }

7.

8. static void

9. iow(board_info_t * db, int reg, int value) 10. {

11. writeb(reg, db->io_addr); 12. writeb(value, db->io_data); 13. }

可以看得出是先将要访问的寄存器地址写入到地址寄存器,然后在将数据写入到数据寄存器。地址。 3.打开网卡

在linux终端下使用ifconfig命令时调用net_device的open函数打开网卡设备

[html] view plaincopy

1. static int

2. dm9000_open(struct net_device *dev) 3. {

4. board_info_t *db = netdev_priv(dev);

5. unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; 6.

7. if (netif_msg_ifup(db))

8. dev_dbg(db->dev, \"enabling %s\\n\>name); 9.

10. /* If there is no IRQ type specified, default to something that 11. * may work, and tell the user that this is a problem */ 12.

13. if (irqflags == IRQF_TRIGGER_NONE)

14. dev_warn(db->dev, \"WARNING: no IRQ resource flags set.\\n\"); 15.

16. irqflags |= IRQF_SHARED; 17.

18. //申请中断

19. if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))

20. return -EAGAIN; 21.

22. /* Initialize DM9000 board */ 23. //复位网卡芯片 24. dm9000_reset(db);

25.

26. //初始化网卡(相关寄存器设置) 27. dm9000_init_dm9000(dev); 28.

29. /* Init driver variable */ 30. db->dbug_cnt = 0; 31.

32. mii_check_media(&db->mii, netif_msg_link(db), 1); 33.

34. //打开发送队列

35. netif_start_queue(dev); 36.

37. //调度发送队列开始工作 38. dm9000_schedule_poll(db); 39.

40. return 0; 41. }

4.数据发送

下面说一下DM9000A中的存储部分,DM9000A内部有一个4K Dword SRAM,其中3KB是作为发送,16KB作为接收,如下图所示。其中0x0000~0x0BFF是传说中的TX buffer(TX buffer中只能存放两个包),0x0C00~0x3FFF是RX buffer。因此在写内存操作时,当IMR的第7位被设置,如果到达了地址的结尾比如到了3KB,则回卷到0。相似的方式,在读操作中,当IMR的第7位被设置如果到达了地址的结尾比如16K,则回卷到0x0C00。

DM9000的TX RAM可以同时放两个包,可以第9行代码中看出如果大于TXRAM中的包大于2则返回,DM9000会先发送第一个包,然后再发第二个包。

[html] view plaincopy

1.

[html] view plaincopy

1. static int

2. dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) 3. {

4. unsigned long flags;

5. board_info_t *db = netdev_priv(dev); 6.

7. dm9000_dbg(db, 3, \"%s:\\n\ 8.

9. //如果TX RAM中的包大于2个包则返回

10. if (db->tx_pkt_cnt > 1) 11. return 1; 12.

13. spin_lock_irqsave(&db->lock, flags); 14.

15. *MWCMD是

Memory data write command with address increment Register(F8H) 16. *将要访问的TXRAM地址写入地址寄存器。 17.

18. /* Move data to DM9000 TX RAM */ 19. writeb(DM9000_MWCMD, db->io_addr); 20.

21. //拷贝数据到TXRAM

22. (db->outblk)(db->io_data, skb->data, skb->len); 23. dev->stats.tx_bytes += skb->len; 24.

25. db->tx_pkt_cnt++;//增加数据包计数,这个值会在发送完成中断时进行自减 26.

27. 如果是第一个包则直接发送

28. /* TX control: First packet immediately send, second packet queue */ 29. if (db->tx_pkt_cnt == 1) { 30.

31. /* Set TX length to DM9000 */

32. /*把数据的长度填到TXPLL(发送包长度低字节)和TXPLH(发送包长度高字节)中*/ 33. iow(db, DM9000_TXPLL, skb->len); 34. iow(db, DM9000_TXPLH, skb->len >> 8); 35. /*置发送控制寄存器(TX Control Register)的发送请求位

TXREQ(Auto clears after sending completely),这样就可以发送出去了*/ 36. 37. /*

38. *记下此时的时间,这里起一个时间戳的作用,之后的超时会用到。如果当前的系统时

间超过设备的trans_start时间

39. *至少一个超时周期,网络层将最终调用驱动程序的tx_timeout。那个这个\"一个超

时周期\"又是什么呢?这个是我们在 40. *probe函数中设置

的,ndev->watchdog_timeo = msecs_to_jiffies(watchdog); 41. */

42. dev->trans_start = jiffies; /* save the time stamp */ 43. } else {

44. //如果是第二个包,则暂时不发送,等待第一个包发送完成时tx_pkt_cnt减为1的时候再发

送。

45. /* Second packet */

46. db->queue_pkt_len = skb->len; 47. netif_stop_queue(dev);//停止发送队列

48. } 49.

50. spin_unlock_irqrestore(&db->lock, flags); 51.

52. /* free this SKB */ 53. dev_kfree_skb(skb); 54.

55. return 0; 56. }

4.中断

[html] view plaincopy

1. static irqreturn_t dm9000_interrupt(intirq, void *dev_id) 2. {

3. structnet_device *dev = dev_id; 4. board_info_t*db = netdev_priv(dev); 5. intint_status; 6. unsignedlong flags; 7. u8reg_save; 8.

9. dm9000_dbg(db,3, \"entering %s\\n\ 10.

11. /*A real interrupt coming */ 12.

13. //禁止所用中断

14. /*holders of db->lock must always block IRQs */ 15. spin_lock_irqsave(&db->lock,flags); 16.

17. //保存寄存器地址

18. /*Save previous register address */ 19. reg_save= readb(db->io_addr); 20.

21. //禁止DM9000的所有中断 22. /*Disable all interrupts */ 23. iow(db,DM9000_IMR, IMR_PAR); 24.

25. /*Got DM9000 interrupt status */ 26. //获取中断状态寄存器的值

27. int_status= ior(db, DM9000_ISR); /* Got ISR */ 28. iow(db,DM9000_ISR, int_status); /* Clear ISRstatus */

29.

30. if(netif_msg_intr(db))

31. dev_dbg(db->dev,\"interrupt status %02x\\n\ 32.

33. /*Received the coming packet */ 34. //如果是读取中断,则开始读取 35. if(int_status & ISR_PRS) 36. dm9000_rx(dev); 37.

38. /*Trnasmit Interrupt check */ 39. //是发送完成中断则处理发送完成后的事情 40. if(int_status & ISR_PTS)

41. dm9000_tx_done(dev,db); 42.

43. if(db->type != TYPE_DM9000E) {

44. if(int_status & ISR_LNKCHNG) {

45. /*fire a link-change request */

46. schedule_delayed_work(&db->phy_poll,1); 47. } 48. } 49.

50. /*Re-enable interrupt mask */ 51. //重新打开DM9000的内部中断 52. iow(db,DM9000_IMR, db->imr_all); 53.

54. /*Restore previous register address */ 55. //恢复寄存器的值

56. writeb(reg_save,db->io_addr); 57.

58. //重新允许所有中断

59. spin_unlock_irqrestore(&db->lock,flags); 60.

61. returnIRQ_HANDLED; 62. }

5.接收数据

[html] view plaincopy

1.

[html] view plaincopy

1. static void

2. dm9000_rx(struct net_device *dev) 3. {

4. board_info_t *db = netdev_priv(dev); 5. struct dm9000_rxhdr rxhdr; 6. struct sk_buff *skb; 7. u8 rxbyte, *rdptr; 8. bool GoodPacket; 9. int RxLen; 10.

11. /* Check packet ready or not */ 12. do {

13. ior(db, DM9000_MRCMDX); /* Dummy read */ 14.

15. //获取接收数据的长度

16. /* Get most updated data */ 17. rxbyte = readb(db->io_data); 18.

19. //检查设备接收状态

20. /* Status check: this byte must be 0 or 1 */ 21. if (rxbyte > DM9000_PKT_RDY) {

22. dev_warn(db->dev, \"status check fail: %d\\n\ 23. iow(db, DM9000_RCR, 0x00); /* Stop Device */

24. iow(db, DM9000_ISR, IMR_PAR); /* Stop INT request */ 25. return; 26. } 27.

28. if (rxbyte != DM9000_PKT_RDY) 29. return; 30.

31.

32. /* A packet ready now & Get status/length */ 33. GoodPacket = true;

34. writeb(DM9000_MRCMD, db->io_addr); 35.

36. (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); 37.

38. RxLen = le16_to_cpu(rxhdr.RxLen); 39.

40. if (netif_msg_rx_status(db))

41. dev_dbg(db->dev, \"RX: status %02x, length %04x\\n\ 42. rxhdr.RxStatus, RxLen); 43.

44. /* Packet Status check */ 45. if (RxLen < 0x40) {

46. GoodPacket = false; 47. if (netif_msg_rx_err(db))

48. dev_dbg(db->dev, \"RX: Bad Packet (runt)\\n\"); 49. } 50.

51. if (RxLen > DM9000_PKT_MAX) {

52. dev_dbg(db->dev, \"RST: RX Len:%x\\n\ 53. } 54.

55. /* rxhdr.RxStatus is identical to RSR register. */ 56. if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE | 57. RSR_PLE | RSR_RWTO | 58. RSR_LCS | RSR_RF)) { 59. GoodPacket = false;

60. if (rxhdr.RxStatus & RSR_FOE) { 61. if (netif_msg_rx_err(db))

62. dev_dbg(db->dev, \"fifo error\\n\"); 63. dev->stats.rx_fifo_errors++; 64. }

65. if (rxhdr.RxStatus & RSR_CE) { 66. if (netif_msg_rx_err(db))

67. dev_dbg(db->dev, \"crc error\\n\"); 68. dev->stats.rx_crc_errors++; 69. }

70. if (rxhdr.RxStatus & RSR_RF) { 71. if (netif_msg_rx_err(db))

72. dev_dbg(db->dev, \"length error\\n\"); 73. dev->stats.rx_length_errors++; 74. } 75. } 76.

77. /* Move data from DM9000 */ 78. //如果接收正确,开始接收 79. if (GoodPacket

80. && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) { 81. skb_reserve(skb, 2);

82. rdptr = (u8 *) skb_put(skb, RxLen - 4);//获取skb的数据指针 83.

84. /* Read received packet from RX SRAM */ 85.

86. (db->inblk)(db->io_data, rdptr, RxLen);//读取数据 87. dev->stats.rx_bytes += RxLen; 88.

89. /* Pass to upper layer */

90. skb->protocol = eth_type_trans(skb, dev); 91. netif_rx(skb);//将接收到的skb交给协议层 92. dev->stats.rx_packets++; 93.

94. } else {

95. /* need to dump the packet's data */ 96.

97. (db->dumpblk)(db->io_data, RxLen); 98. }

99. } while (rxbyte == DM9000_PKT_RDY); 100. }

6.发送完成

[html] view plaincopy

1.

[html] view plaincopy

1. static void dm9000_tx_done(struct net_device *dev, board_info_t *db) 2. {

3. int tx_status = ior(db, DM9000_NSR); /* Got TX status */ 4.

5. if (tx_status & (NSR_TX2END | NSR_TX1END)) { 6. /* One packet sent complete */ 7.

8. //将数据包计数减1 9. db->tx_pkt_cnt--; 10. dev->stats.tx_packets++; 11.

12. if (netif_msg_tx_done(db))

13. dev_dbg(db->dev, \"tx done, NSR %02x\\n\ 14.

15. /* Queue packet check & send */

16. //如果数据包数量依然大于0,说明是TX RAM中的第二个包,再次启动发送,将TX RAM

中第二个包发送出去

17. if (db->tx_pkt_cnt > 0) {

18. /*把数据的长度填到TXPLL(发送包长度低字节)和TXPLH(发送包长度高字节)中

*/

19. iow(db, DM9000_TXPLL, skb->len); 20. iow(db, DM9000_TXPLH, skb->len >> 8); 21. /*置发送控制寄存器(TX Control Register)的发送请求位

TXREQ(Auto clears after sending completely),这样就可以发送出去了*/ 22. dev->trans_start = jiffies; 23. }

24. netif_wake_queue(dev);//唤醒发送队列 25. } 26. }

7.超时处理

[html] view plaincopy

1. static void dm9000_timeout(struct net_device *dev) 2. {

3. board_info_t *db = netdev_priv(dev); 4. u8 reg_save;

5. unsigned long flags; 6.

7. /* Save previous register address */ 8. reg_save = readb(db->io_addr); 9. spin_lock_irqsave(&db->lock, flags); 10.

11. //停止发送队列并复位DM9000网卡 12. netif_stop_queue(dev); 13. dm9000_reset(db); 14. dm9000_init_dm9000(dev);

15. /* We can accept TX packets again */ 16.

17. //重新发送

18. dev->trans_start = jiffies; 19. netif_wake_queue(dev); 20.

21. /* Restore previous register address */ 22. writeb(reg_save, db->io_addr);

23. spin_unlock_irqrestore(&db->lock, flags); 24. }

因篇幅问题不能全部显示,请点此查看更多更全内容