• 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机制移植上去,估计要花点时间了这个。

  • 相关阅读:
    python 将png图片格式转换生成gif动画
    JetBrains系IDE的设置Pycharm PHPStorm
    Nginx 静态页面POST 请求提示405 Not Allowed
    安装SSL证书 and 根域名跳转www域名
    Linux 安装qt5-designer并集成到Pycharm
    Deepin 自动挂载win NTFS磁盘
    Nginx+DNS负载均衡实现
    swoole websocket服务推送
    Linux版 php5.4 升级php7
    百度 Javascript开发 API
  • 原文地址:https://www.cnblogs.com/masky/p/3439062.html
Copyright © 2020-2023  润新知