使用cansend命令时ndo_start_xmit()未被调用的CAN驱动问题
问题分析与解决思路
核心问题定位
你的现象说明CAN设备的发送路径未被正确唤醒:单独执行cansend时帧被内核缓存,未推送到驱动的can_start_xmit函数;只有当candump运行(触发接收路径的唤醒事件)时,缓存的发送帧才被处理。本质是驱动未正确初始化发送队列的调度状态,导致内核认为设备发送路径未就绪。
具体排查与修复步骤
1. 检查struct net_device的发送回调与队列配置
- 确认驱动中
netdev->netdev_ops->ndo_start_xmit已绑定你的can_start_xmit函数,避免回调指针为空或错误赋值 - 确保设置合理的发送队列长度:
netdev->tx_queue_len = 10;(根据实际场景调整,默认值可能为0导致帧无法缓存)
2. 修复设备启动时的状态标记
在设备打开(ndo_open)回调中,必须补充以下关键调用,告知内核设备发送路径已就绪:
static int can_dev_open(struct net_device *netdev) { // 原有硬件初始化、接收路径配置逻辑... // 标记设备物理链路就绪 netif_carrier_on(netdev); // 启动所有发送队列 netif_tx_start_all_queues(netdev); // 唤醒发送队列调度 netif_wake_queue(netdev); pr_info("CAN device can0 opened, tx queues activated\n"); return 0; }
如果缺少这些调用,内核会将发送帧缓存,直到接收中断等事件触发队列唤醒(也就是candump运行时的监听动作)。
3. 排查发送队列的暂停逻辑
检查驱动中是否存在错误调用netif_stop_queue(netdev)的代码,且未在合适时机调用netif_wake_queue(netdev)恢复队列。比如在处理发送超时或硬件忙时,若未正确恢复队列,会导致后续发送帧一直被阻塞。
4. 验证发送触发逻辑
- 重新编译驱动后加载,执行
ip link set can0 up,查看dmesg确认设备打开时的状态打印 - 单独执行
cansend can0 123#DEADBEEF,此时dmesg应能看到can_start_xmit的打印信息,帧也会被正常转发到STM32侧
内容的提问来源于stack exchange,提问作者thePhisitian
相关产品推荐
相关产品推荐

