Linux协议栈IP层的路由处理
时间:2010-03-11 来源:cao5170
二:从网卡驱动说起。 以intel 100M 网卡驱动为例简要概述数据包的接收与发送流程。代码见(drivers/net/e100.c) 网卡是属于PCI设备,它的注册跟一般的PCI设备注册没什么两样。 static int __init e100_init_module(void) { if(((1 << debug) - 1) & NETIF_MSG_DRV) { printk(KERN_INFO PFX "%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); printk(KERN_INFO PFX "%s\n", DRV_COPYRIGHT); } //注册PCI return pci_module_init(&e100_driver); } 其中e100_driver对应为网卡的pci_driver. static struct pci_driver e100_driver = { //驱动对应的名字 .name = DRV_NAME, //匹配类型 .id_table = e100_id_table, //侦测函数 .probe = e100_probe, //移除函数,设备移除时将调用此函数 .remove = __devexit_p(e100_remove), #ifdef CONFIG_PM .suspend = e100_suspend, .resume = e100_resume, #endif } 当总数探测到PCI设备符合e100_id_table中的参数时,将会调用e100_probe,开始设备的初始化 在e100_probe中: static int __devinit e100_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct nic *nic; int err; //分配net_device并为其赋值 //alloc_etherdev为以太网接口的net_device分配函数。它是alloc_netdev的封装函数 if(!(netdev = alloc_etherdev(sizeof(struct nic)))) { if(((1 << debug) - 1) & NETIF_MSG_PROBE) printk(KERN_ERR PFX "Etherdev alloc failed, abort.\n"); return -ENOMEM; } //对netdev中的函数指针赋初值 netdev->open = e100_open; netdev->stop = e100_close; netdev->hard_start_xmit = e100_xmit_frame; netdev->get_stats = e100_get_stats; netdev->set_multicast_list = e100_set_multicast_list; netdev->set_mac_address = e100_set_mac_address; netdev->change_mtu = e100_change_mtu; netdev->do_ioctl = e100_do_ioctl; //支持ethtool工具时有效 SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); netdev->tx_timeout = e100_tx_timeout; netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; //轮询函数 netdev->poll = e100_poll; netdev->weight = E100_NAPI_WEIGHT; #ifdef CONFIG_NET_POLL_CONTROLLER netdev->poll_controller = e100_netpoll; #endif //获得net_device私有数据区,并对其赋值 //私有数据大小是由alloc_etherdev()参数中指定的 nic = netdev_priv(netdev); nic->netdev = netdev; nic->pdev = pdev; nic->msg_enable = (1 << debug) - 1; pci_set_drvdata(pdev, netdev); //启动网卡.为之后DMA,I/O内存映射做准备 //它实际上是对PCI的控制寄存器赋值来实现的 if((err = pci_enable_device(pdev))) { DPRINTK(PROBE, ERR, "Cannot enable PCI device, aborting.\n"); goto err_out_free_dev; } //获取该资源相关联的标志 //如果该设备存在I/O内存,则置IORESOURCE_MEM if(!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { DPRINTK(PROBE, ERR, "Cannot find proper PCI device " "base address, aborting.\n"); err = -ENODEV; goto err_out_disable_pdev; } //对PCI的6个寄存器都会调用资源分配函数进行申请 if((err = pci_request_regions(pdev, DRV_NAME))) { DPRINTK(PROBE, ERR, "Cannot obtain PCI resources, aborting.\n"); goto err_out_disable_pdev; } //探制设备的DMA能力。如果设备支持DMA。pci_set_dma_mask返回0 pci_set_master(pdev); if((err = pci_set_dma_mask(pdev, 0xFFFFFFFFULL))) { DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n"); goto err_out_free_res; } SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &pdev->dev); //映射设备对应的I/O。以后对设备寄存器的操作可以直接转换为对内存的操作 nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr)); if(!nic->csr) { DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n"); err = -ENOMEM; goto err_out_free_res; } if(ent->driver_data) nic->flags |= ich; else nic->flags &= ~ich; spin_lock_init(&nic->cb_lock); spin_lock_init(&nic->cmd_lock); //设置定时器。 init_timer(&nic->watchdog); nic->watchdog.function = e100_watchdog; nic->watchdog.data = (unsigned long)nic; init_timer(&nic->blink_timer); nic->blink_timer.function = e100_blink_led; nic->blink_timer.data = (unsigned long)nic; //为nic->mem建立线性DMA。只是在支持ethtool的时候才有用 if((err = e100_alloc(nic))) { DPRINTK(PROBE, ERR, "Cannot alloc driver memory, aborting.\n"); goto err_out_iounmap; } //对nic成员赋初值 e100_get_defaults(nic); e100_hw_reset(nic); e100_phy_init(nic); //读取网卡的EEPROM。其中存放着网卡的MAC地址。 //对EEPROM是通过对I/O映射内存的操作实现的,即nic->csr if((err = e100_eeprom_load(nic))) goto err_out_free; //设置netdev->dev_addr memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN); if(!is_valid_ether_addr(netdev->dev_addr)) { DPRINTK(PROBE, ERR, "Invalid MAC address from " "EEPROM, aborting.\n"); err = -EAGAIN; goto err_out_free; } /* Wol magic packet can be enabled from eeprom */ if((nic->mac >= mac_82558_D101_A4) && (nic->eeprom[eeprom_id] & eeprom_id_wol)) nic->flags |= wol_magic; pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic))); //注册网络设备 if((err = register_netdev(netdev))) { DPRINTK(PROBE, ERR, "Cannot register net device, aborting.\n"); goto err_out_free; } DPRINTK(PROBE, INFO, "addr 0x%lx, irq %d, " "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n", pci_resource_start(pdev, 0), pdev->irq, netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); return 0; err_out_free: e100_free(nic); err_out_iounmap: iounmap(nic->csr); err_out_free_res: pci_release_regions(pdev); err_out_disable_pdev: pci_disable_device(pdev); err_out_free_dev: pci_set_drvdata(pdev, NULL); free_netdev(netdev); return err; } 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/luoye144200720102030/archive/2009/06/04/4243344.aspx
相关阅读 更多 +