Linux2.6.39下dm9k驱动源码分析(二)

2.3、网卡打开操作

问题:open函数在什么时候调用?

答:网卡打开的时候,命令#ifconfig eth0 up,此时网卡被打开,在网卡open函数中应该完成以下操作:

注册中断;设置寄存器,启动设备;启动发送队列,初始化dm9000,复位芯片,检查MII接口。
static int dm9000_open(struct net_device *dev)
{
    board_info_t *db = netdev_priv(dev);
    unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK;

    if (netif_msg_ifup(db))
        dev_dbg(db->dev, "enabling %s\n", dev->name);

    /* If there is no IRQ type specified, default to something that
     * may work, and tell the user that this is a problem */

    if (irqflags == IRQF_TRIGGER_NONE)
        dev_warn(db->dev, "WARNING: no IRQ resource flags set.\n");
   //注册中断
    irqflags |= IRQF_SHARED;
  
    if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
        return -EAGAIN;

    /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */
    iow(db, DM9000_GPR, 0);    /* REG_1F bit0 activate phyxcer */
    mdelay(1); /* delay needs by DM9000B */

    /* Initialize DM9000 board */
    dm9000_reset(db);//复位芯片
    dm9000_init_dm9000(dev);//初始化dm9K,初始化芯片的寄存器

    /* Init driver variable */
    db->dbug_cnt = 0;

   //检查MII接口
    mii_check_media(&db->mii, netif_msg_link(db), 1);
    /**开启网络接口发送数据队列*/
    netif_start_queue(dev);
    /*之前在probe函数中已经使用 INIT_DELAYED_WORK来初始化一个延迟工作队列并关联了一个操作函数dm9000_poll_work(), 此时运行schedule来调用这个函数*/  
    dm9000_schedule_poll(db);

    return 0;
}

/* dm9k复位操作往network ctl 控制寄存器写数据*/

static void dm9000_reset(board_info_t * db)
{
    dev_dbg(db->dev, "resetting device\n");

    /* RESET device */
    //写地址 00h
    writeb(DM9000_NCR, db->io_addr);
    udelay(200);
    //写1
    writeb(NCR_RST, db->io_data);
    udelay(200);
}

/*
 *初始化dm9k硬件信息
 */
static void dm9000_init_dm9000(struct net_device *dev)
{
    board_info_t *db = netdev_priv(dev);
    unsigned int imr;
    unsigned int ncr;

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

    /* I/O mode */
    //读中断状态寄存器
    db->io_mode = ior(db, DM9000_ISR) >> 6;    /* ISR bit7:6 keeps I/O mode */

    /* Checksum mode */
    dm9000_set_rx_csum_unlocked(dev, db->rx_csum);//校验模式

    iow(db, DM9000_GPCR, GPCR_GEP_CNTL);    /* Let GPIO0 output */

    ncr = (db->flags & DM9000_PLATF_EXT_PHY) ? NCR_EXT_PHY : 0;

    /* if wol is needed, then always set NCR_WAKEEN otherwise we end
     * up dumping the wake events if we disable this. There is already
     * a wake-mask in DM9000_WCR */
    if (db->wake_supported)
        ncr |= NCR_WAKEEN;

    iow(db, DM9000_NCR, ncr);

    /* Program operating register */
    iow(db, DM9000_TCR, 0);            /* TX Polling clear */
    iow(db, DM9000_BPTR, 0x3f);    /* Less 3Kb, 200us */
    iow(db, DM9000_FCR, 0xff);    /* Flow Control */
    iow(db, DM9000_SMCR, 0);        /* Special Mode */
    /* clear TX status */
    iow(db, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END);
    iow(db, DM9000_ISR, ISR_CLR_STATUS); /* Clear interrupt status */

    /* Set address filter table */
    dm9000_hash_table_unlocked(dev);

    imr = IMR_PAR | IMR_PTM | IMR_PRM;
    if (db->type != TYPE_DM9000E)
        imr |= IMR_LNKCHNG;

    db->imr_all = imr;

    /* Enable TX/RX interrupt mask */
    iow(db, DM9000_IMR, imr);

    /* Init Driver variable */
    db->tx_pkt_cnt = 0;
    db->queue_pkt_len = 0;
    dev->trans_start = jiffies;
}

2.4、数据发送

问题:数据发送函数在什么时候调用

答:当网卡有数据要发送的时候,该函数被调用

/*
 *  Hardware start transmission.
 *  Send a packet to media from the upper layer.
 */
static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
    unsigned long flags;
    board_info_t *db = netdev_priv(dev);//获取net_device私有数据

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

    if (db->tx_pkt_cnt > 1)
        return NETDEV_TX_BUSY;
    //屏蔽自旋锁并将目前的的状态写入flags中
    spin_lock_irqsave(&db->lock, flags);
   // 将skb中的data部分写入DM9000的TX RAM,
    /* Move data to DM9000 TX RAM */
    writeb(DM9000_MWCMD, db->io_addr);
    //更新已经发送的字节数和字节计数
    (db->outblk)(db->io_data, skb->data, skb->len);
    dev->stats.tx_bytes += skb->len;

    db->tx_pkt_cnt++;
    /* TX control: First packet immediately send, second packet queue */
    if (db->tx_pkt_cnt == 1) {
        dm9000_send_packet(dev, skb->ip_summed, skb->len);
    } else {
        /* Second packet */
        db->queue_pkt_len = skb->len;
        db->queue_ip_summed = skb->ip_summed;
        netif_stop_queue(dev);
    }
     //恢复之前的自旋锁
    spin_unlock_irqrestore(&db->lock, flags);

    /* free this SKB */
    dev_kfree_skb(skb);

    return NETDEV_TX_OK;
}

static void dm9000_send_packet(struct net_device *dev,
                   int ip_summed,
                   u16 pkt_len)
{
    board_info_t *dm = to_dm9000_board(dev);

    /* The DM9000 is not smart enough to leave fragmented packets alone. */
    if (dm->ip_summed != ip_summed) {
        if (ip_summed == CHECKSUM_NONE)
            iow(dm, DM9000_TCCR, 0);
        else
            iow(dm, DM9000_TCCR, TCCR_IP | TCCR_UDP | TCCR_TCP);
        dm->ip_summed = ip_summed;
    }
    //配置TX长度
    /* Set TX length to DM9000 */
    iow(dm, DM9000_TXPLL, pkt_len);
    iow(dm, DM9000_TXPLH, pkt_len >> 8);
    //发送数据将TX控制寄存器的0位配置1
    /* Issue TX polling command */
    iow(dm, DM9000_TCR, TCR_TXREQ);    /* Cleared after TX complete */
}

2.4、中断处理函数

问题:网卡有几种类型的中断

答:网卡有三种中断:新报文到达中断,报文发送完成中断,出错中断,当数据包发送完后会出发该中断函数

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);
    //保存之前的IO地址
    /* 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)
        dm9000_rx(dev);
    //报文发送完成中断
    /* 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 */
    iow(db, DM9000_IMR, db->imr_all);
    //恢复之前的IO地址
    /* Restore previous register address */
    writeb(reg_save, db->io_addr);
    
    spin_unlock_irqrestore(&db->lock, flags);

    return IRQ_HANDLED;
}

2.5、包接收

当网卡接收到数据时,产生中断,在中断处理函数中通过中断状态寄存器判断出是否接收中断,接着使用函数dm9000_rx处理接收到的数据

/*
 *  Received a packet and pass to upper layer
 */
static void
dm9000_rx(struct net_device *dev)
{
    board_info_t *db = netdev_priv(dev);
    struct dm9000_rxhdr rxhdr;
    struct sk_buff *skb;
    u8 rxbyte, *rdptr;
    bool GoodPacket;
    int RxLen;

    /* 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 */
            return;
        }

        if (!(rxbyte & DM9000_PKT_RDY))
            return;

        /* 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);
        }
    } while (rxbyte & DM9000_PKT_RDY);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值