Linux内核里的ixgb目录为linux/drivers/net/ethernet/intel/ixgb/
目录下内容有
# ls
ixgb_ee.c ixgb_ee.h ixgb_ethtool.c ixgb.h ixgb_hw.c ixgb_hw.h ixgb_ids.h ixgb_main.c ixgb_osdep.h ixgb_param.c Makefile
ixgb_main.c为ixgb驱动主要实现;
ixgb_hw.c实现了直接操作硬件的接口,主要是对硬件寄存器操作的一层封装,比如phy的读写,led的控制等;
ixgb_ethtool.c主要实现了netdev->ethtool_ops = &ixgb_ethtool_ops;即,网卡的ethtool系列操作;
ixgb_ee.c主要实现了针对网卡设备上的eeprom操作。
ixgb驱动的入口函数为ixgb_init_module,当驱动被加载是调用
static int __init
ixgb_init_module(void)
{pr_info("%s\n", ixgb_driver_string);pr_info("%s\n", ixgb_copyright);return pci_register_driver(&ixgb_driver);
}module_init(ixgb_init_module);
/* ixgb_main.c */
pci_register_driver(&ixgb_driver); 将ixgb_driver注册上去,ixgb_driver的实例为
static struct pci_driver ixgb_driver = {.name = ixgb_driver_name,.id_table = ixgb_pci_tbl,.probe = ixgb_probe,.remove = ixgb_remove,.err_handler = &ixgb_err_handler
};
/* ixgb_main.c */
当pci bus上匹配到device和driver时,会调用probe函数,probe函数的具体实现如下:
static int ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{/* PCI设备的初始化 */err = pci_enable_device(pdev);err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));err = pci_request_regions(pdev, ixgb_driver_name);pci_set_master(pdev);netdev = alloc_etherdev(sizeof(struct ixgb_adapter));SET_NETDEV_DEV(netdev, &pdev->dev);pci_set_drvdata(pdev, netdev);/* adapter结构体的初始化 */adapter = netdev_priv(netdev);adapter->netdev = netdev;adapter->pdev = pdev;adapter->hw.back = adapter;adapter->msg_enable = netif_msg_init(debug, DEFAULT_MSG_ENABLE);adapter->hw.hw_addr = pci_ioremap_bar(pdev, BAR_0);adapter->hw.io_base = pci_resource_start(pdev, i);adapter->bd_number = cards_found;adapter->link_speed = 0;adapter->link_duplex = 0;/* ixgb_netdev_ops是网卡设备操作的重点结构体 */netdev->netdev_ops = &ixgb_netdev_ops;ixgb_set_ethtool_ops(netdev);netdev->watchdog_timeo = 5 * HZ;/* NAPI的poll函数为ixgb_clean,将其挂上结构体 */netif_napi_add(netdev, &adapter->napi, ixgb_clean);/* 设置网卡设备的四有结构体 *//* ixgb_sw_init函数里主要将PCI设备信息和网路设置如MTU信息初始化到adapter->hw */err = ixgb_sw_init(adapter);netdev->hw_features = NETIF_F_SG |NETIF_F_TSO |NETIF_F_HW_CSUM |NETIF_F_HW_VLAN_CTAG_TX |NETIF_F_HW_VLAN_CTAG_RX;netdev->features = netdev->hw_features |NETIF_F_HW_VLAN_CTAG_FILTER;netdev->hw_features |= NETIF_F_RXCSUM;netdev->features |= NETIF_F_HIGHDMA;netdev->vlan_features |= NETIF_F_HIGHDMA;/* MTU range: 68 - 16114 */netdev->min_mtu = ETH_MIN_MTU;netdev->max_mtu = IXGB_MAX_JUMBO_FRAME_SIZE - ETH_HLEN;/* 初始化定时器 */timer_setup(&adapter->watchdog_timer, ixgb_watchdog, 0);INIT_WORK(&adapter->tx_timeout_task, ixgb_tx_timeout_task);/* 注册设备 */err = register_netdev(netdev);/* carrier off reporting is important to ethtool even BEFORE open */netif_carrier_off(netdev);ixgb_check_options(adapter);/* 用新的配置重新硬件, ixgb_reset内的重点函数是ixgb_init_hw */ixgb_reset(adapter);cards_found++;return 0;
}
/* ixgb_main.c */
ixgb_probe函数里涉及到的初始化结构体ixgb_netdev_ops实现如下:
static const struct net_device_ops ixgb_netdev_ops = {.ndo_open = ixgb_open,.ndo_stop = ixgb_close,.ndo_start_xmit = ixgb_xmit_frame,.ndo_set_rx_mode = ixgb_set_multi,.ndo_validate_addr = eth_validate_addr,.ndo_set_mac_address = ixgb_set_mac,.ndo_change_mtu = ixgb_change_mtu,.ndo_tx_timeout = ixgb_tx_timeout,.ndo_vlan_rx_add_vid = ixgb_vlan_rx_add_vid,.ndo_vlan_rx_kill_vid = ixgb_vlan_rx_kill_vid,.ndo_fix_features = ixgb_fix_features,.ndo_set_features = ixgb_set_features,
};
/* ixgb_main.c */
每当网络接口被UP激活的时候,ixgb_open函数都会被调用,ixgb_open的具体实现如下:
static int ixgb_open(struct net_device *netdev)
{struct ixgb_adapter *adapter = netdev_priv(netdev);/* 分配发送数据包的描述体资源,使用dma_alloc_coherent初始化TX Descriptor Ring */err = ixgb_setup_tx_resources(adapter);netif_carrier_off(netdev);/* 分配接收数据包的描述体资源,使用dma_alloc_coherent初始化RX Descriptor Ring */err = ixgb_setup_rx_resources(adapter);/* 将网卡接口UP起来的一系列操作 */err = ixgb_up(adapter);/* 允许上层协议栈调用网卡设备的hard_start_xmit功能 */netif_start_queue(netdev);return 0;err_up:ixgb_free_rx_resources(adapter);
err_setup_rx:ixgb_free_tx_resources(adapter);
err_setup_tx:ixgb_reset(adapter);return err;
}
/* ixgb_main.c */
当网络接口被link down的时候,ixgb_close函数被调用,ixgb_close的具体实现如下:
static int
ixgb_close(struct net_device *netdev)
{struct ixgb_adapter *adapter = netdev_priv(netdev);ixgb_down(adapter, true);ixgb_free_tx_resources(adapter);ixgb_free_rx_resources(adapter);return 0;
}
/* ixgb_main.c */
当协议栈要发送数据包时,会调用ixgb_xmit_frame,ixgb_xmit_frame的具体实现如下:
static netdev_tx_t ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{struct ixgb_adapter *adapter = netdev_priv(netdev);unsigned int first;unsigned int tx_flags = 0;int vlan_id = 0;int count = 0;int tso;first = adapter->tx_ring.next_to_use;/* 是否做TCP Segment Offload,即TCP字段硬件卸载 */tso = ixgb_tso(adapter, skb);if (likely(tso))tx_flags |= IXGB_TX_FLAGS_TSO;else if (ixgb_tx_csum(adapter, skb)) /* 是否做校验和的硬件卸载 */tx_flags |= IXGB_TX_FLAGS_CSUM;/* ixgb_tx_map为网卡具体发送数据包的函数* 实际操作是使用buffer_info->dma = dma_map_single(&pdev->dev, skb->data + offset,size, DMA_TO_DEVICE);* 将发送数据包skb->data映射到host与NIC交互的TX Ring的DMA空间上。*/count = ixgb_tx_map(adapter, skb, first); if (count) {/* 根据count,遍历填充tx_desc,把数据包交给网卡设备发出去* tx_desc->buff_addr = cpu_to_le64(buffer_info->dma);*/ixgb_tx_queue(adapter, count, vlan_id, tx_flags);/* Make sure there is space in the ring for the next send. */ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, DESC_NEEDED);} else {dev_kfree_skb_any(skb);adapter->tx_ring.buffer_info[first].time_stamp = 0;adapter->tx_ring.next_to_use = first;}return NETDEV_TX_OK;
}
/* ixgb_main.c */
网卡的收数据包部分,采用NAPI机制,即在ixgb_probe函数里有
netif_napi_add(netdev, &adapter->napi, ixgb_clean);执行语句,其中ixgb_clean为NAPI Polling函数,让我们来看看ixgb_clean的具体实现:
static int ixgb_clean(struct napi_struct *napi, int budget)
{struct ixgb_adapter *adapter = container_of(napi, struct ixgb_adapter, napi);int work_done = 0;ixgb_clean_tx_irq(adapter);ixgb_clean_rx_irq(adapter, &work_done, budget);/* If budget not fully consumed, exit the polling mode */if (work_done < budget) {napi_complete_done(napi, work_done);if (!test_bit(__IXGB_DOWN, &adapter->flags))ixgb_irq_enable(adapter);}return work_done;
}
设置网卡的features,网络协议栈会查询这些feature了解网卡的能力做对数据包做不同的处理,比如网卡是否支持tso的硬件卸载,是否支持checksum的硬件卸载都在features里有所体现
static int ixgb_set_features(struct net_device *netdev, netdev_features_t features)
{struct ixgb_adapter *adapter = netdev_priv(netdev);netdev_features_t changed = features ^ netdev->features;if (!(changed & (NETIF_F_RXCSUM|NETIF_F_HW_VLAN_CTAG_RX)))return 0;adapter->rx_csum = !!(features & NETIF_F_RXCSUM);if (netif_running(netdev)) {ixgb_down(adapter, true);ixgb_up(adapter);ixgb_set_speed_duplex(netdev);} elseixgb_reset(adapter);return 0;
}
/* ixgb_main.c */