DM9000网卡驱动接受数据从中断方式改成NAPI方式小记

平台是最最经典的s3c2440了,说了要做这件事情很久了,就是改几行代码,一直没有做。前几天逼了自己一下,终于给做了,拖延症患者伤不起。

以下是需要读者对napi机制有所熟悉:

step1:在board_info结构体里面增加struct napi_struct napi;(这个还用说……)

step2:在dm9000_probe函数中增加netif_napi_add(ndev, &db->napi, dm9000_napi_poll, 64);

dm9000_napi_poll函数实现如下:

static int dm9000_napi_poll(struct napi_struct *napi, int budget)
{
    board_info_t *db = container_of(napi, board_info_t, napi);
    unsigned long flags;
    u8 reg_save;
    
    spin_lock_irqsave(&db->lock, flags);
    
    reg_save = readb(db->io_addr);
    
    dm9000_rx(db->ndev, budget);
    
    napi_complete(napi);
    
    iow(db, DM9000_IMR, db->imr_all);
    
    writeb(reg_save, db->io_addr);
    
    spin_unlock_irqrestore(&db->lock, flags);
    
    return 0;
}

step3:在dm9000_open函数中增加napi_enable(&db->napi);//使能 NAPI

    在dm9000_stop函数中增加napi_disable(&db->napi);//禁止 NAPI

step4:修改dm9000_interrupt中断函数,如下

static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
{
    struct net_device *dev = dev_id;
    board_info_t *db = netdev_priv(dev);
    int int_status;
    unsigned long flags;
    u8 reg_save;

    dm9000_dbg(db, 3, "entering %s\n", __func__);

    /* A real interrupt coming */

    /* holders of db->lock must always block IRQs */
    spin_lock_irqsave(&db->lock, flags);

    /* Save previous register address */
    reg_save = readb(db->io_addr);

    /* Disable all interrupts */
    iow(db, DM9000_IMR, IMR_PAR);

    /* Got DM9000 interrupt status */
    int_status = ior(db, DM9000_ISR);    /* Got ISR */
    iow(db, DM9000_ISR, int_status);    /* Clear ISR status */

    if (netif_msg_intr(db))
        dev_dbg(db->dev, "interrupt status %02x\n", int_status);

    /* Received the coming packet */
    if (int_status & ISR_PRS)//接受中断的话执行napi_schedule
    {
        napi_schedule(&db->napi);
    }

    /* Trnasmit Interrupt check */
    if (int_status & ISR_PTS)
        dm9000_tx_done(dev, db);

    if (db->type != TYPE_DM9000E) {
        if (int_status & ISR_LNKCHNG) {
            /* fire a link-change request */
            schedule_delayed_work(&db->phy_poll, 1);
        }
    }

  /* Re-enable interrupt mask */
    if ((int_status & ISR_PRS) == 0)//如果不是接收函数,可以重新使能中断
    iow(db, DM9000_IMR, db->imr_all);

    /* Restore previous register address */
    writeb(reg_save, db->io_addr);

    spin_unlock_irqrestore(&db->lock, flags);

    return IRQ_HANDLED;
}

step5:修改接受函数,如下:

static void
dm9000_rx(struct net_device *dev, int budget)
{
    board_info_t *db = netdev_priv(dev);
    struct dm9000_rxhdr rxhdr;
    struct sk_buff *skb;
    u8 rxbyte, *rdptr;
    bool GoodPacket;
    int RxLen, rxTime = 0;

    /* Check packet ready or not */
    do {
        ior(db, DM9000_MRCMDX);    /* Dummy read */

        /* Get most updated data */
        rxbyte = readb(db->io_data);

        /* Status check: this byte must be 0 or 1 */
        if (rxbyte & DM9000_PKT_ERR) {
            dev_warn(db->dev, "status check fail: %d\n", rxbyte);
            iow(db, DM9000_RCR, 0x00);    /* Stop Device */
            iow(db, DM9000_ISR, IMR_PAR);    /* Stop INT request */
            break;
        }

        if (!(rxbyte & DM9000_PKT_RDY))
            break;

        /* A packet ready now  & Get status/length */
        GoodPacket = true;
        writeb(DM9000_MRCMD, db->io_addr);

        (db->inblk)(db->io_data, &rxhdr, sizeof(rxhdr));

        RxLen = le16_to_cpu(rxhdr.RxLen);

        if (netif_msg_rx_status(db))
            dev_dbg(db->dev, "RX: status %02x, length %04x\n",
                rxhdr.RxStatus, RxLen);

        /* Packet Status check */
        if (RxLen < 0x40) {
            GoodPacket = false;
            if (netif_msg_rx_err(db))
                dev_dbg(db->dev, "RX: Bad Packet (runt)\n");
        }

        if (RxLen > DM9000_PKT_MAX) {
            dev_dbg(db->dev, "RST: RX Len:%x\n", RxLen);
        }

        /* rxhdr.RxStatus is identical to RSR register. */
        if (rxhdr.RxStatus & (RSR_FOE | RSR_CE | RSR_AE |
                      RSR_PLE | RSR_RWTO |
                      RSR_LCS | RSR_RF)) {
            GoodPacket = false;
            if (rxhdr.RxStatus & RSR_FOE) {
                if (netif_msg_rx_err(db))
                    dev_dbg(db->dev, "fifo error\n");
                dev->stats.rx_fifo_errors++;
            }
            if (rxhdr.RxStatus & RSR_CE) {
                if (netif_msg_rx_err(db))
                    dev_dbg(db->dev, "crc error\n");
                dev->stats.rx_crc_errors++;
            }
            if (rxhdr.RxStatus & RSR_RF) {
                if (netif_msg_rx_err(db))
                    dev_dbg(db->dev, "length error\n");
                dev->stats.rx_length_errors++;
            }
        }

        /* Move data from DM9000 */
        if (GoodPacket &&
            ((skb = dev_alloc_skb(RxLen + 4)) != NULL)) {
            skb_reserve(skb, 2);
            rdptr = (u8 *) skb_put(skb, RxLen - 4);

            /* Read received packet from RX SRAM */

            (db->inblk)(db->io_data, rdptr, RxLen);
            dev->stats.rx_bytes += RxLen;

            /* Pass to upper layer */
            skb->protocol = eth_type_trans(skb, dev);
            if (db->rx_csum) {
                if ((((rxbyte & 0x1c) << 3) & rxbyte) == 0)
                    skb->ip_summed = CHECKSUM_UNNECESSARY;
                else
                    skb_checksum_none_assert(skb);
            }
            netif_rx(skb);
            dev->stats.rx_packets++;
        } else {
            /* need to dump the packet's data */

            (db->dumpblk)(db->io_data, RxLen);
        }
        rxTime++;
    } while ((rxbyte & DM9000_PKT_RDY)&&(rxTime < budget));
//    printk("rxTime:%d\n", rxTime);
}

改完了就可以开始测试了。

不过保险起见,最好在timeout、suspend、resume三个函数中增加响应的enable和disable函数。

性能上面的提升?呵呵~~~~~

移植中犯的一个错误,在中断函数里判断到是接收中断就直接调用完napi_schedule退出了,忽略了进中断的时候可能发送中断也被置位了的情况,结果老是timeout出错,这个是一个要注意的地方。进中断之后,可能是发送和接收中断同时置位了。

接下来就是要把dma机制移植上去,估计要花点时间了这个。

原文地址:https://www.cnblogs.com/masky/p/3439062.html