We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
以联发科 mt7921 无线网卡驱动为例
mt7921
kernel mt7921/ 下有pci,usb接口的驱动,usb接口驱动入口是usb.c。手里有mt7921芯片的USB无线网卡,对应的驱动为mt7921u
mt7921/
usb.c
pci驱动为 mt7921e USB接口 MT7921 外观
mt7921e
PCI接口的MT7921网卡外观
驱动采用USB总线注册到kernel,使用kernel提供的 module_usb_driver(mt7921u_driver);,调用 usb_register_driver进行注册
module_usb_driver(mt7921u_driver);
usb_register_driver
kernel驱动采用callback式,,linux为各种接口设备提供helper
驱动使用kernel module_usb_driver进行注册
module_usb_driver
#define module_usb_driver(__usb_driver) \ module_driver(__usb_driver, usb_register, \ usb_deregister)
经过usb的一系列宏替换,module_init调用usb的通用init函数 usb_register 初始化,最终调用 struct usb_driver#probe 开始驱动初始化
module_init
usb_register
struct usb_driver#probe
#define module_driver(__driver, __register, __unregister, ...) \ static int __init __driver##_init(void) \ { \ return __register(&(__driver) , ##__VA_ARGS__); \ } \ module_init(__driver##_init); \ static void __exit __driver##_exit(void) \ { \ __unregister(&(__driver) , ##__VA_ARGS__); \ } \ module_exit(__driver##_exit);
usb 是接口类型,usb接口探测完成后,驱动调用kernel 80211一系列helper,在kernel中注册为无线网卡。
驱动的80211回调。有数据需要发送kernel则调用.tx
.tx
const struct ieee80211_ops mt7921_ops = { .tx = mt792x_tx, .start = mt7921_start, .stop = mt7921_stop, .add_interface = mt7921_add_interface, .remove_interface = mt792x_remove_interface, .config = mt7921_config, .conf_tx = mt792x_conf_tx, .configure_filter = mt7921_configure_filter, .bss_info_changed = mt7921_bss_info_changed, .start_ap = mt7921_start_ap, .stop_ap = mt7921_stop_ap, .sta_state = mt7921_sta_state, .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, .set_key = mt7921_set_key, .sta_set_decap_offload = mt7921_sta_set_decap_offload, #if IS_ENABLED(CONFIG_IPV6) .ipv6_addr_change = mt7921_ipv6_addr_change, #endif /* CONFIG_IPV6 */ .ampdu_action = mt7921_ampdu_action, .set_rts_threshold = mt7921_set_rts_threshold, .wake_tx_queue = mt76_wake_tx_queue, .release_buffered_frames = mt76_release_buffered_frames, .channel_switch_beacon = mt7921_channel_switch_beacon, .get_txpower = mt76_get_txpower, .get_stats = mt792x_get_stats, .get_et_sset_count = mt792x_get_et_sset_count, .get_et_strings = mt792x_get_et_strings, .get_et_stats = mt792x_get_et_stats, .get_tsf = mt792x_get_tsf, .set_tsf = mt792x_set_tsf, .get_survey = mt76_get_survey, .get_antenna = mt76_get_antenna, .set_antenna = mt7921_set_antenna, .set_coverage_class = mt792x_set_coverage_class, .hw_scan = mt7921_hw_scan, .cancel_hw_scan = mt7921_cancel_hw_scan, .sta_statistics = mt792x_sta_statistics, .sched_scan_start = mt7921_start_sched_scan, .sched_scan_stop = mt7921_stop_sched_scan, CFG80211_TESTMODE_CMD(mt7921_testmode_cmd) CFG80211_TESTMODE_DUMP(mt7921_testmode_dump) #ifdef CONFIG_PM .suspend = mt7921_suspend, .resume = mt7921_resume, .set_wakeup = mt792x_set_wakeup, .set_rekey_data = mt7921_set_rekey_data, #endif /* CONFIG_PM */ .flush = mt792x_flush, .set_sar_specs = mt7921_set_sar_specs, .remain_on_channel = mt7921_remain_on_channel, .cancel_remain_on_channel = mt7921_cancel_remain_on_channel, .add_chanctx = mt7921_add_chanctx, .remove_chanctx = mt7921_remove_chanctx, .change_chanctx = mt7921_change_chanctx, .assign_vif_chanctx = mt792x_assign_vif_chanctx, .unassign_vif_chanctx = mt792x_unassign_vif_chanctx, .mgd_prepare_tx = mt7921_mgd_prepare_tx, .mgd_complete_tx = mt7921_mgd_complete_tx, };
追踪 .tx调用路径
调用路径有两个,pci 接口走的DMA,而USB接口则是kthread polling
int __mt76_worker_fn(void *ptr) { struct mt76_worker *w = ptr; while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); if (kthread_should_park()) { kthread_parkme(); continue; } if (!test_and_clear_bit(MT76_WORKER_SCHEDULED, &w->state)) { schedule(); continue; } set_bit(MT76_WORKER_RUNNING, &w->state); set_current_state(TASK_RUNNING); // kthread 持续调用 mt76u_rx_worker w->fn(w); cond_resched(); clear_bit(MT76_WORKER_RUNNING, &w->state); } return 0; } // https://github.com/torvalds/linux/blob/v6.6/drivers/net/wireless/mediatek/mt76/usb.c#L628 static void mt76u_rx_worker(struct mt76_worker *w) { struct mt76_usb *usb = container_of(w, struct mt76_usb, rx_worker); struct mt76_dev *dev = container_of(usb, struct mt76_dev, usb); int i; rcu_read_lock(); // 遍历每个队列处理rx数据 mt76_for_each_q_rx(dev, i) mt76u_process_rx_queue(dev, &dev->q_rx[i]); rcu_read_unlock(); }
qemu-system-x86_64 --kernel ./arch/x86/boot/bzImage -initrd ./rootfs.cpio -device e1000,netdev=eth0 -netdev user,id=eth0,hostfwd=tcp::5555-:22,net=192.168.76.0/24,dhcpstart=192.168.76.9 -append "nokaslr console=ttyS0" -S -nographic -gdb tcp::1234 -virtfs local,path=/,security_model=none,mount_tag=guestroot -usb -device usb-host,vendorid=0x0e8d,productid=0x7961
The text was updated successfully, but these errors were encountered:
No branches or pull requests
以联发科
mt7921
无线网卡驱动为例pci驱动为
mt7921e
USB接口 MT7921 外观
PCI接口的MT7921网卡外观
驱动采用USB总线注册到kernel,使用kernel提供的
module_usb_driver(mt7921u_driver);
,调用usb_register_driver
进行注册kernel驱动采用callback式,,linux为各种接口设备提供helper
驱动使用kernel
module_usb_driver
进行注册经过usb的一系列宏替换,
module_init
调用usb的通用init函数usb_register
初始化,最终调用struct usb_driver#probe
开始驱动初始化usb 是接口类型,usb接口探测完成后,驱动调用kernel 80211一系列helper,在kernel中注册为无线网卡。
驱动的80211回调。有数据需要发送kernel则调用
.tx
追踪
.tx
调用路径收包送到kernel协议栈路径
调用路径有两个,pci 接口走的DMA,而USB接口则是kthread polling
qemu绑定mt7921u网卡,分析驱动调用栈
qemu-system-x86_64 --kernel ./arch/x86/boot/bzImage -initrd ./rootfs.cpio -device e1000,netdev=eth0 -netdev user,id=eth0,hostfwd=tcp::5555-:22,net=192.168.76.0/24,dhcpstart=192.168.76.9 -append "nokaslr console=ttyS0" -S -nographic -gdb tcp::1234 -virtfs local,path=/,security_model=none,mount_tag=guestroot -usb -device usb-host,vendorid=0x0e8d,productid=0x7961
The text was updated successfully, but these errors were encountered: