对于没有内置EMAC的处理器,如全志F1C100S等,如果需要连接有线网,一般只有2种办法:SPI接口扩展(DM9051NP)和USB接口扩展。本文提供SPI接口的DM9051的驱动,以及官方的驱动问题修正。
环境:
处理器:F1C100S
软件环境:Linux-4.15
DM9051驱动,一般提供轮询(Poll)方式和中断(Interrupt)方式,对于现在网上能下载到的驱动,如1.69.3等,如果使用轮询方式,也可以工作,但CPU占用率非常高,很不实际。因此中断方式是首选。然而对于中断方式,1.69版本驱动及可收集到的驱动,要注意以下情况:
1、对于IRQ引脚中断,原本驱动中设置成IRQF_TRIG_NONE。如果DTS设备树中未指定该引脚的中断方式,需要在驱动中进行指定。要注意的是,因为spi通讯不支持并发,因此必须带有IRQF_ONESHOT,以保证不会嵌套触发中断。同时,如果配置为下降沿触发(IRQF_TRIG_FALLING),当中断程序中处理较大数据帧较耗时的情况下,极有可能出现无法触发下一次中断,导致无法进行接收数据包。
因此,中断方式驱动时,设置为电平触发是稳妥的。我的配置是低电平触发,即 IRQF_TRIG_LOW | IRQF_ONESHOT 。
ret = request_threaded_irq(spi->irq, NULL, dm951_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
ndev->name, db);
2、官方驱动中存在bug,导致的现象是 Ping延迟从100ms渐渐降低到1ms,然后再次循环。原因在于官方驱动在函数dm9051_start_xmit 中,虽然正确启动了任务 dm9051_tx_work ,但在函数dm9051_tx_work 中错误的使用了rx_work结构来获取当前db结构数据,导致dm9051_tx函数中判断db->bt.prob_cntStopped为0。
而官方驱动还是能工作的原因在于,在中断服务程序中,判断了是否需要发送数据,如果需要发送,则进行发送。因此导致了Ping的延迟不稳定。
/* 系统发送数据包函数 */
static netdev_tx_t
dm9051_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
board_info_t *db = netdev_priv(dev);
spin_lock(&db->statelock);//mutex_lock(&db->addr_lock);
toend_stop_queue1(dev, db->bt.prob_cntStopped++ );
skb_queue_tail(&db->txq, skb); // JJ: a skb add to the tail of the list '&db->txq'
driver_dtxt_step(db, '0'); //driver_dtxt_step(db, 'q'); // Normal
spin_unlock(&db->statelock);//mutex_unlock(&db->addr_lock);
schedule_work(&db->tx_work);
return NETDEV_TX_OK;
}
/* 实际向DM9051发送数据包函数 */
static void dm9051_tx_work(struct work_struct *work)
{
board_info_t *db = container_of(work, board_info_t, rxctrl_work); /* 这里不应该使用rxctrl_work,而应该是tx_work */
dm9051_tx(db);
}
static void dm9051_tx(board_info_t *db)
{
struct net_device *dev = db->ndev;
if (db->bt.prob_cntStopped) // This is more exactly right!!
{
#if LOOP_XMIT
mutex_lock(&db->addr_lock);
dm9051_continue_xmit_inRX(db); //=dm9051_continue_poll_xmit
opening_wake_queue1(dev);
mutex_unlock(&db->addr_lock);
#endif //LOOP_XMIT
}
}
修正了这两个之后,驱动即可以正常工作。 |