Linux内核里的ixgb驱动代码走读
创始人
2024-05-29 15:42:36
0

代码结构介绍

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_init_module

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 */

ixgb_probe

当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 */

ixgb_open

每当网络接口被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 */

ixgb_close

当网络接口被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,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 */

ixgb_clean

网卡的收数据包部分,采用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 */

相关内容

热门资讯

小仓鼠在笼子里一动不动的是怎么... 小仓鼠在笼子里一动不动的是怎么回事?小仓鼠应该是生病了,建议尽快处理,找兽医看看,他们最专业。目前应...
扬州何园的寻访感受 扬州何园的寻访感受 你好,请参考: 初见何园,似乎有种似曾相识的感觉,或许意识到这种想...
童年傻事作文---速来 童年傻事作文---速来童年傻事 童年是多么美好,童年的生活令人向往,童年的天空总是那么蓝,而童...
家庭幽默大赛老韩头一家幽默服装... 家庭幽默大赛老韩头一家幽默服装秀家庭幽默大赛老韩头一家幽默服装秀这都被他看出来了  今天晒内裤了,室...
乐器名称 乐器名称我在小提琴协奏曲《梁祝》的视频里这种乐器不知叫什么名字,请懂音乐和乐器的朋友给予解答,谢谢。...
电视剧《老马家的幸福往事》中的... 电视剧《老马家的幸福往事》中的马鸣和徐丽娜在马鸣的大学里的图书馆里偷书时用留声机听的歌是什么名字的请...
流鬼的介绍 流鬼的介绍 流鬼,是古代民族,分布在今俄罗斯勘察加半岛,有数万人。
请问为爱所困火吗 请问为爱所困火吗一般般。爱情偶像剧。此剧上一年开播,还上了微博热搜榜我认为很火,为爱所困第二部还有不...
什么是手诊 什么是手诊手诊的概念就是指通过人体手的纹路形态、变化、规律等方式,对人体器官的演变作出推理的一种防治...
双子星公主法和希的有几集,第一... 双子星公主法和希的有几集,第一部第二部都要,如果知道第三部也透露一点,请求不要编,法和希最后怎样了拜...
王熙凤简介 王熙凤简介《红楼梦》中人物,贾琏之妻,王夫人的内侄女。长着一双丹凤三角眼,两弯柳叶吊梢眉,身量苗条,...
大学生应从哪些方面进行自我探索 大学生应从哪些方面进行自我探索兴趣、能力、价值观、性格,这四个是最主要的方面,其中价值观是核心
谁有好看的卡通人物的电脑背景! 谁有好看的卡通人物的电脑背景!卡通人物的背景要清色! 看得清 要男生的 我有Clannad主题...
幼儿园小班孩子座位固定好还是经... 幼儿园小班孩子座位固定好还是经常换好?我家孩子座位老换,我觉得不好,大家觉得呢?... 我家孩子座...
我的爸爸的作文 我的爸爸的作文我的父亲 人们常说父爱如山,可在我看来,我的父亲对我的爱,并非完全如山那样严峻,有时却...
潘朵拉之心第二季动漫什么时候出 潘朵拉之心第二季动漫什么时候出动画只出了第一季 没有要出第二季的消息 可能性估计很小目前漫画还在连载...
时不我待是什么意思 时不我待是什么意思时不我待的意思是时间不等待人,要抓紧时间,不要虚度光阴。出处:日月逝矣,岁不我与。...
葫芦小金刚里大娃怎么被抓的 葫芦小金刚里大娃怎么被抓的掉泥潭被捉的
有一部小说叫穿越千年来爱你还是... 有一部小说叫穿越千年来爱你还是什么的有一部小说叫穿越千年来爱你还是什么的内容讲的是一个女的在路上走着...
火影忍者力 米娜是红眼吗 火影忍者力 米娜是红眼吗红眼?首先这几集是原创,非岸本创作。在岸本的剧情结构里面只有木叶白眼、写轮眼...