一、dm9000_porbe函数分析
不同于u-boot代码,tq2440中的DM9000更加复杂,需要分析的点也很多:
- /*
- * Search DM9000 board, allocate space and register it
- */
- static int __devinit
- dm9000_probe(struct platform_device *pdev)
- {
- struct dm9000_plat_data *pdata = pdev->dev.platform_data;
- struct board_info *db; /* Point a board information structure */
- struct net_device *ndev;
- const unsigned char *mac_src;
- int ret = 0;
- int iosize;
- int i;
- u32 id_val;
- #if defined(CONFIG_ARCH_S3C2410)
- unsigned int oldval_bwscon = *(volatile unsigned int *)S3C2410_BWSCON;
- unsigned int oldval_bankcon4 = *(volatile unsigned int *)S3C2410_BANKCON4;
- #endif
- /* Init network device */
- ndev = alloc_etherdev(sizeof(struct board_info)); //分配netdev结构
- if (!ndev) {
- dev_err(&pdev->dev, "could not allocate device.\n");
- return -ENOMEM;
- }
- SET_NETDEV_DEV(ndev, &pdev->dev);
- dev_dbg(&pdev->dev, "dm9000_probe()\n"); //不管
- #if defined(CONFIG_ARCH_S3C2410) //2410可以不管
- // *((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
- *((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 ;
- *((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;
- #endif
- /* setup board info structure */
- db = netdev_priv(ndev);
- memset(db, 0, sizeof(*db));
- db->dev = &pdev->dev;
- db->ndev = ndev;
- spin_lock_init(&db->lock);
- mutex_init(&db->addr_lock);
- INIT_DELAYED_WORK(&db->phy_poll, dm9000_poll_work);
- db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取平台资源,对应的platform_driver
- db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- ..................
- }
从这里可以引出之前的知识点:平台设备和平台驱动的相关知识。在dm9000.c中有:
- static struct platform_driver dm9000_driver = {
- .driver = {
- .name = "dm9000", //这个平台驱动通过name和tq2440中的dm9000的驱动设备结构对接
- .owner = THIS_MODULE,
- },
- .probe = dm9000_probe,
- .remove = __devexit_p(dm9000_drv_remove),
- .suspend = dm9000_drv_suspend,
- .resume = dm9000_drv_resume,
- };
在arch/arm/mach-tq2440.c:
- struct platform_device s3c_device_dm9000 = {
- .name = "dm9000", //这里有同样的name来实现
- .id = 0,
- .num_resources = ARRAY_SIZE(s3c_dm9k_resource),
- .resource = s3c_dm9k_resource, //这里保存着dm9000硬件的资源
- .dev = {
- .platform_data = &s3c_dm9k_platdata,
- }
- };
同样在此文件中:
- static struct resource s3c_dm9k_resource[] = {
- [0] = { //用的片选4
- .start = S3C2410_CS4, //这里的起始地址是0x20000000和网上一些0x20000300不一样。wu'suo
- .end = S3C2410_CS4 + 3, //.end为什么尾地址是+3?因为一个地址需要四个字节。这是根据网卡来定义的
- .flags = IORESOURCE_MEM,
- },
- [1] = { //0x20000004~0x20000007?
- .start = S3C2410_CS4 + 4, //这里的4意味着地址线2等于1,设置了cmd为高位,是数据内容
- .end = S3C2410_CS4 + 4 + 3,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = IRQ_EINT7, //对应的中断信息
- .end = IRQ_EINT7,
- .flags = IORESOURCE_IRQ | IRQF_TRIGGER_RISING,
- }
- };
回来继续看dm9000.c中的probe函数:
- db->addr_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- db->data_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- db->irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (db->addr_res == NULL || db->data_res == NULL ||
- db->irq_res == NULL) {
- dev_err(db->dev, "insufficient resources\n");
- ret = -ENOENT;
- goto out;
- }
- iosize = res_size(db->addr_res);
- db->addr_req = request_mem_region(db->addr_res->start, iosize,
- pdev->name);
- if (db->addr_req == NULL) {
- dev_err(db->dev, "cannot claim address reg area\n");
- ret = -EIO;
- goto out;
- }
- db->io_addr = ioremap(db->addr_res->start, iosize); //将地址信息重映射
- if (db->io_addr == NULL) {
- dev_err(db->dev, "failed to ioremap address reg\n");
- ret = -EINVAL;
- goto out;
- }
- iosize = res_size(db->data_res);
- db->data_req = request_mem_region(db->data_res->start, iosize,
- pdev->name);
- if (db->data_req == NULL) {
- dev_err(db->dev, "cannot claim data reg area\n");
- ret = -EIO;
- goto out;
- }
- db->io_data = ioremap(db->data_res->start, iosize); //将数据信息重映射
- if (db->io_data == NULL) {
- dev_err(db->dev, "failed to ioremap data reg\n");
- ret = -EINVAL;
- goto out;
- }
- .........................
- id_val = ior(db, DM9000_CHIPR); //读取芯片信息
- // dev_dbg(db->dev, "dm9000 revision 0x%02x io_mode %02x \n", id_val, db->io_mode);
- printk(KERN_INFO "dm9000 revision 0x%02x io_mode %02x \n", id_val, db->io_mode);
- switch (id_val) {
- case CHIPR_DM9000A:
- db->type = TYPE_DM9000A;
- break;
- case CHIPR_DM9000B:
- db->type = TYPE_DM9000B;
- break;
- case CHIPR_DM9000C:
- db->type = TYPE_DM9000C;
- break;
- default:
- dev_dbg(db->dev, "ID %02x => defaulting to DM9000E\n", id_val);
- db->type = TYPE_DM9000E;
- }
- /* from this point we assume that we have found a DM9000 */
- /* driver system function */ //下面在设置dm9000的操作函数集了
- ether_setup(ndev);
- ndev->open = &dm9000_open;
- ndev->hard_start_xmit = &dm9000_start_xmit;
- ndev->tx_timeout = &dm9000_timeout;
- ndev->watchdog_timeo = msecs_to_jiffies(watchdog);
- ndev->stop = &dm9000_stop;
- ndev->set_multicast_list = &dm9000_hash_table;
- ndev->ethtool_ops = &dm9000_ethtool_ops;
- ndev->do_ioctl = &dm9000_ioctl;
- #ifdef CONFIG_NET_POLL_CONTROLLER
- ndev->poll_controller = &dm9000_poll_controller;
- #endif
- db->msg_enable = NETIF_MSG_LINK;
- db->mii.phy_id_mask = 0x1f;
- db->mii.reg_num_mask = 0x1f;
- db->mii.force_media = 0;
- db->mii.full_duplex = 0;
- db->mii.dev = ndev;
- db->mii.mdio_read = dm9000_phy_read;
- db->mii.mdio_write = dm9000_phy_write;
- #if defined(CONFIG_ARCH_S3C2410)
- printk("Now use the default MAC address: 10:23:45:67:89:ab\n");
- mac_src = "EmbedSky";
- ndev->dev_addr[0] = 0x10;
- ndev->dev_addr[1] = 0x23;
- ndev->dev_addr[2] = 0x45;
- ndev->dev_addr[3] = 0x67;
- ndev->dev_addr[4] = 0x89;
- ndev->dev_addr[5] = 0xab;
- #else
- mac_src = "eeprom";
- /* try reading the node address from the attached EEPROM */ //读取MAC地址,从EEPROM中
- for (i = 0; i < 6; i += 2)
- dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);
- if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
- mac_src = "platform data";
- memcpy(ndev->dev_addr, pdata->dev_addr, 6);
- }
- if (!is_valid_ether_addr(ndev->dev_addr)) {
- /* try reading from mac */
- mac_src = "chip";
- for (i = 0; i < 6; i++)
- ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
- }
- if (!is_valid_ether_addr(ndev->dev_addr))
- dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please "
- "set using ifconfig\n", ndev->name);
- #endif
- platform_set_drvdata(pdev, ndev);
- ret = register_netdev(ndev); //注册网卡驱动
- if (ret == 0)
- printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",
- ndev->name, dm9000_type_to_char(db->type),
- db->io_addr, db->io_data, ndev->irq,
- ndev->dev_addr, mac_src);
- return 0;
- out:
- #if defined(CONFIG_ARCH_S3C2410)
- *(volatile unsigned int *)S3C2410_BWSCON = oldval_bwscon;
- *(volatile unsigned int *)S3C2410_BANKCON4 = oldval_bankcon4;
- #endif
- dev_err(db->dev, "not found (%d).\n", ret);
- dm9000_release_board(pdev, db);
- free_netdev(ndev);
- return ret;
- }
二、DM9000_OPEN函数分析
在probe中没有太多的dm9000的初始化代码,都写在了open中(这个open函数在ifconfig eth0 192.168.1.1时调用):
- /*
- * Open the interface.
- * The interface is opened whenever "ifconfig" actives it.
- */
- static int
- dm9000_open(struct net_device *dev)
- {
- board_info_t *db = netdev_priv(dev);
- unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;
- if (netif_msg_ifup(db))
- dev_dbg(db->dev, "enabling %s\n", dev->name);
- /* If there is no IRQ type specified, default to something that
- * may work, and tell the user that this is a problem */
- if (irqflags == IRQF_TRIGGER_NONE)
- dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
- irqflags |= IRQF_SHARED;
- if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev)) //注册网卡驱动的中断处理函数
- return -EAGAIN;
- /* Initialize DM9000 board */
- // dm9000_reset(db);
- dm9000_init_dm9000(dev); //网卡初始化在这里
- /* Init driver variable */
- db->dbug_cnt = 0;
- mii_check_media(&db->mii, netif_msg_link(db), 1);
- netif_start_queue(dev); //启动发送队列
- dm9000_schedule_poll(db);
- return 0;
- }
DM9000初始化:
①分配net_device结构
②从platform_device中获取地址,中断号
③把获取到的地址映射为虚拟地址
④读取芯片类型
⑤设置操作函数集
⑥注册网卡驱动
三、dm9000_start_xmit发送函数分析
dm9000_start_xmit:
- /*
- * Hardware start transmission.
- * Send a packet to media from the upper layer.
- */
- static int
- dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
- {
- unsigned long flags;
- board_info_t *db = netdev_priv(dev);
- int save_mwr, check_mwr, calc_mwr;
- dm9000_dbg(db, 3, "%s:\n", __func__);
- if ((db->tx_pkt_cnt > 0) || !netif_carrier_ok(dev))
- return 1;
- spin_lock_irqsave(&db->lock, flags);
- netif_stop_queue(dev); //通知协议栈,暂停向驱动传送数据
- db->tx_pkt_cnt++;
- dev->stats.tx_bytes += skb->len;
- dev->stats.tx_packets++;
- save_mwr = (ior(db, 0xfb) << 8) | ior(db, 0xfa);
- calc_mwr = save_mwr + skb->len;
- if(skb->len & 0x01) calc_mwr++;
- if(calc_mwr > 0x0bff ) calc_mwr -= 0x0c00;
- /* Set TX length to DM9000 */ //获取发送长度
- iow(db, DM9000_TXPLL, skb->len);
- iow(db, DM9000_TXPLH, skb->len >> 8);
- /* Move data to DM9000 TX RAM */ //将要发送的数据发送入缓存
- writeb(DM9000_MWCMD, db->io_addr);
- (db->outblk)(db->io_data, skb->data, skb->len); //skb->data,skb->len分别指向结构体数据的头和尾
- /* Issue TX polling command */
- iow(db, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ //清除发送位
- dev->trans_start = jiffies; /* save the time stamp */
- check_mwr = (ior(db, 0xfb) << 8) | ior(db, 0xfa);
- if(calc_mwr != check_mwr)
- {
- printk(KERN_INFO "TX: fifo error %04x %04x %04x %04x\n", save_mwr, skb->len, calc_mwr, check_mwr);
- iow(db, 0xfb, (calc_mwr >> 8) & 0xff);
- iow(db, 0xfa, calc_mwr & 0xff);
- }
- spin_unlock_irqrestore(&db->lock, flags);
- /* free this SKB */
- dev_kfree_skb(skb); //释放SKB结构
- return 0;
- }
发送完成产生中断(dm9000_interrupt):
- static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
- {
- struct net_device *dev = dev_id;
- board_info_t *db = netdev_priv(dev);
- int int_status;
- unsigned long flags;
- u8 reg_save;
- dm9000_dbg(db, 3, "entering %s\n", __func__);
- /* A real interrupt coming */
- /* holders of db->lock must always block IRQs */
- spin_lock_irqsave(&db->lock, flags);
- /* Save previous register address */
- reg_save = readb(db->io_addr);
- /* Disable all interrupts */
- iow(db, DM9000_IMR, IMR_PAR);
- /* Got DM9000 interrupt status */
- int_status = ior(db, DM9000_ISR); /* Got ISR */
- iow(db, DM9000_ISR, int_status); /* Clear ISR status */
- if (netif_msg_intr(db))
- dev_dbg(db->dev, "interrupt status %02x\n", int_status);
- /* Received the coming packet */
- if (int_status & ISR_PRS)
- dm9000_rx(dev); //接收中断
- int_status |= ior(db, DM9000_ISR); /* Got ISR */
- /* Trnasmit Interrupt check */
- if (int_status & ISR_PTS)
- {
- iow(db, DM9000_ISR, ISR_PTS);
- dm9000_tx_done(dev, db); //发送中断
- }
- if (db->type != TYPE_DM9000E) {
- if (int_status & ISR_LNKCHNG) {
- /* fire a link-change request */
- schedule_delayed_work(&db->phy_poll, 1);
- }
- }
- /* Re-enable interrupt mask */
- iow(db, DM9000_IMR, db->imr_all);
- /* Restore previous register address */
- writeb(reg_save, db->io_addr);
- spin_unlock_irqrestore(&db->lock, flags);
- return IRQ_HANDLED;
- }
发送函数完成后进入中断dm9000_tx_done:
- /*
- * DM9000 interrupt handler
- * receive the packet to upper layer, free the transmitted packet
- */
- static void dm9000_tx_done(struct net_device *dev, board_info_t *db)
- {
- int tx_status = ior(db, DM9000_TCR); /* Got TX status */ //获取中断状态
- if(tx_status & TCR_TXREQ) //查看发送是否出错
- {
- dev->stats.rx_fifo_errors++; //错误计数加1
- }
- else
- {
- db->tx_pkt_cnt = 0;
- dev->trans_start = 0;
- netif_wake_queue(dev); //调用netif_wake_queue(),通知协议栈发送数据
- }
- }
dm9000_rx():
- /*
- * Received a packet and pass to upper layer
- */
- static void
- dm9000_rx(struct net_device *dev)
- {
- board_info_t *db = netdev_priv(dev);
- struct dm9000_rxhdr rxhdr;
- struct sk_buff *skb;
- u8 rxbyte, *rdptr;
- bool GoodPacket;
- int RxLen;
- int save_mrr, check_mrr, calc_mrr;
- /* Check packet ready or not */
- do {
- ior(db, DM9000_MRCMDX); /* Dummy read */ //空读
- save_mrr = (ior(db, 0xf5) << 8) | ior(db, 0xf4);
- /* Get most updated data */
- rxbyte = ior(db, DM9000_MRCMDX); //查看接收状态
- if(DM9000_PKT_RDY != rxbyte) //是否已经ready
- {
- /* Status check: this byte must be 0 or 1 */
- if (rxbyte) {
- // dev_warn(db->dev, "status check fail: %d\n", rxbyte);
- printk(KERN_INFO "status check fail: %d\n", rxbyte);
- iow(db, DM9000_RCR, 0x00); /* Stop Device */
- iow(db, DM9000_IMR, IMR_PAR); /* Stop INT request */
- dm9000_init_dm9000(dev);
- }
- return;
- }
- /* A packet ready now & Get status/length */
- GoodPacket = true;
- writeb(DM9000_MRCMD, db->io_addr); //
- (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr)); //dm9000_rxhdr结构中有rx_len,接收长度
- calc_mrr = save_mrr + 4;
- if(calc_mrr > 0x3fff) calc_mrr -= 0x3400;
- check_mrr = (ior(db, 0xf5) << 8) | ior(db, 0xf4);
- if(calc_mrr != check_mrr)
- {
- printk(KERN_INFO "RX: 4 byte error %04x %04x %04x \n", save_mrr, calc_mrr, check_mrr);
- iow(db, 0xf5, (save_mrr >> 8) & 0xff);
- iow(db, 0xf4, save_mrr & 0xff);
- continue;
- }
- writeb(DM9000_MRCMD, db->io_addr);
- RxLen = le16_to_cpu(rxhdr.RxLen);
- calc_mrr = save_mrr + 4 + RxLen;
- if(RxLen & 0x01) calc_mrr++;
- if(calc_mrr > 0x3fff) calc_mrr -= 0x3400;
- if (netif_msg_rx_status(db))
- dev_dbg(db->dev, "RX: status %02x, length %04x\n",
- rxhdr.RxStatus, RxLen);
- /* Packet Status check */ //判断长度
- if (RxLen < 0x40) {
- GoodPacket = false;
- if (netif_msg_rx_err(db))
- dev_dbg(db->dev, "RX: Bad Packet (runt)\n");
- }
- if (RxLen > DM9000_PKT_MAX) {
- dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);
- }
- /* rxhdr.RxStatus is identical to RSR register. */ //读取状态看有没有出错
- if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
- RSR_PLE | RSR_RWTO |
- RSR_LCS | RSR_RF)) {
- GoodPacket = false;
- if (rxhdr.RxStatus & RSR_FOE) {
- if (netif_msg_rx_err(db))
- dev_dbg(db->dev, "fifo error\n");
- dev->stats.rx_fifo_errors++;
- }
- if (rxhdr.RxStatus & RSR_CE) {
- if (netif_msg_rx_err(db))
- dev_dbg(db->dev, "crc error\n");
- dev->stats.rx_crc_errors++;
- }
- if (rxhdr.RxStatus & RSR_RF) {
- if (netif_msg_rx_err(db))
- dev_dbg(db->dev, "length error\n");
- dev->stats.rx_length_errors++;
- }
- }
- /* Move data from DM9000 */
- if (GoodPacket
- && ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) { //分配skb=接收到的数据长度+4
- skb_reserve(skb, 2); //skb中的ip包需要4字节对齐,所以skb要保留多2个字节。(以太网包格式)
- rdptr = (u8 *) skb_put(skb, RxLen - 4); //skb的tail指针,数据包长度减4
- /* Read received packet from RX SRAM */
- (db->inblk)(db->io_data, rdptr, RxLen); //读取io_data地址到rdptr中
- dev->stats.rx_bytes += RxLen;
- /* Pass to upper layer */
- skb->protocol = eth_type_trans(skb, dev);
- netif_rx(skb); //把准备好的skb提交给上层协议
- dev->stats.rx_packets++;
- check_mrr = (ior(db, 0xf5) << 8) | ior(db, 0xf4);
- if(calc_mrr != check_mrr)
- {
- // dev_dbg(db->dev, "RX: fifo error %04x %04x %04x %04x\n", save_mrr, RxLen, calc_mrr, check_mrr);
- printk(KERN_INFO "RX: fifo error %04x %04x %04x %04x\n", save_mrr, RxLen, calc_mrr, check_mrr);
- iow(db, 0xf5, (calc_mrr >> 8) & 0xff);
- iow(db, 0xf4, calc_mrr & 0xff);
- }
- } else {
- /* need to dump the packet's data */
- iow(db, 0xf5, (calc_mrr >> 8) & 0xff);
- iow(db, 0xf4, calc_mrr & 0xff);
- }
- } while (rxbyte == DM9000_PKT_RDY);
- }