⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 netdevice.c

📁 net device driver driver developer can enjoy it
💻 C
📖 第 1 页 / 共 3 页
字号:
    /* Pull off the RFD and put the actual data (minus eth hdr) */
    skb_reserve(skb, sizeof(struct rfd));
    skb_put(skb, actual_size);
    skb->protocol = eth_type_trans(skb, nic->netdev);
 
    if(unlikely(!(rfd_status & cb_ok))) {
       /* Don't indicate if hardware indicates errors */
        dev_kfree_skb_any(skb);
    } else if(actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN) {
       /* Don't indicate oversized frames */
        nic->rx_over_length_errors++;
        dev_kfree_skb_any(skb);
    } else {
        nic->net_stats.rx_packets++;
        nic->net_stats.rx_bytes += actual_size;
        nic->netdev->last_rx = jiffies;
        netif_receive_skb(skb);
        if(work_done)
           (*work_done)++;
    }
 
    rx->skb = NULL;
 
    return 0;
}
收包清除
static inline void e100_rx_clean(struct nic *nic, unsigned int *work_done,
    unsigned int work_to_do)
{
    struct rx *rx;
    int restart_required = 0;
    struct rx *rx_to_start = NULL;
 
    /* are we already rnr? then pay attention!!! this ensures that
     * the state machine progression never allows a start with a 
     * partially cleaned list, avoiding a race between hardware
     * and rx_to_clean when in NAPI mode */
    if(RU_SUSPENDED == nic->ru_running)
        restart_required = 1;
 
    /* Indicate newly arrived packets */
    for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {
       int err = e100_rx_indicate(nic, rx, work_done, work_to_do);
        if(-EAGAIN == err) {
           /* hit quota so have more work to do, restart once
            * cleanup is complete */
           restart_required = 0;
           break;
       } else if(-ENODATA == err)
           break; /* No more to clean */
    }
 
    /* save our starting point as the place we'll restart the receiver */
    if(restart_required)
        rx_to_start = nic->rx_to_clean;
 
    /* Alloc new skbs to refill list */
    for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {
        if(unlikely(e100_rx_alloc_skb(nic, rx)))
           break; /* Better luck next time (see watchdog) */
    }
 
    if(restart_required) {
       // ack the rnr?
        writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);
        e100_start_receiver(nic, rx_to_start);
        if(work_done)
           (*work_done)++;
    }
}
 
static void e100_rx_clean_list(struct nic *nic)
{
    struct rx *rx;
    unsigned int i, count = nic->params.rfds.count;
 
    nic->ru_running = RU_UNINITIALIZED;
 
    if(nic->rxs) {
        for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
           if(rx->skb) {
               pci_unmap_single(nic->pdev, rx->dma_addr,
                   RFD_BUF_LEN, PCI_DMA_FROMDEVICE);
               dev_kfree_skb(rx->skb);
           }
       }
        kfree(nic->rxs);
        nic->rxs = NULL;
    }
 
    nic->rx_to_use = nic->rx_to_clean = NULL;
}
 
static int e100_rx_alloc_list(struct nic *nic)
{
    struct rx *rx;
    unsigned int i, count = nic->params.rfds.count;
 
    nic->rx_to_use = nic->rx_to_clean = NULL;
    nic->ru_running = RU_UNINITIALIZED;
 
    if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))
        return -ENOMEM;
    memset(nic->rxs, 0, sizeof(struct rx) * count);
 
    for(rx = nic->rxs, i = 0; i < count; rx++, i++) {
        rx->next = (i + 1 < count) ? rx + 1 : nic->rxs;
        rx->prev = (i == 0) ? nic->rxs + count - 1 : rx - 1;
        if(e100_rx_alloc_skb(nic, rx)) {
           e100_rx_clean_list(nic);
           return -ENOMEM;
       }
    }
 
    nic->rx_to_use = nic->rx_to_clean = nic->rxs;
    nic->ru_running = RU_SUSPENDED;
 
    return 0;
}
 
static int e100_poll(struct net_device *netdev, int *budget)
{
    struct nic *nic = netdev_priv(netdev);
    unsigned int work_to_do = min(netdev->quota, *budget);
    unsigned int work_done = 0;
    int tx_cleaned;
 
    e100_rx_clean(nic, &work_done, work_to_do);
    tx_cleaned = e100_tx_clean(nic);
 
    /* If no Rx and Tx cleanup work was done, exit polling mode. */
    if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
        netif_rx_complete(netdev);
        e100_enable_irq(nic);
        return 0;
    }
 
    *budget -= work_done;
    netdev->quota -= work_done;
 
    return 1;
}
 
#ifdef CONFIG_NET_POLL_CONTROLLER
static void e100_netpoll(struct net_device *netdev)
{
    struct nic *nic = netdev_priv(netdev);
 
    e100_disable_irq(nic);
    e100_intr(nic->pdev->irq, netdev, NULL);
    e100_tx_clean(nic);
    e100_enable_irq(nic);
}
#endif
 
static struct net_device_stats *e100_get_stats(struct net_device *netdev)
{
    struct nic *nic = netdev_priv(netdev);
    return &nic->net_stats;
}
 
static int e100_set_mac_address(struct net_device *netdev, void *p)
{
    struct nic *nic = netdev_priv(netdev);
    struct sockaddr *addr = p;
 
    if (!is_valid_ether_addr(addr->sa_data))
        return -EADDRNOTAVAIL;
 
    memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
    e100_exec_cb(nic, NULL, e100_setup_iaaddr);
 
    return 0;
}
 
static int e100_change_mtu(struct net_device *netdev, int new_mtu)
{
    if(new_mtu < ETH_ZLEN || new_mtu > ETH_DATA_LEN)
        return -EINVAL;
    netdev->mtu = new_mtu;
    return 0;
}
 
#ifdef CONFIG_PM
static int e100_asf(struct nic *nic);
#endif
 
static int e100_up(struct nic *nic)
{
    int err;
 
    if((err = e100_rx_alloc_list(nic)))
        return err;
    if((err = e100_alloc_cbs(nic)))
       goto err_rx_clean_list;
    if((err = e100_hw_init(nic)))
       goto err_clean_cbs;
    e100_set_multicast_list(nic->netdev);
    e100_start_receiver(nic, 0);
    mod_timer(&nic->watchdog, jiffies);
    if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,
        nic->netdev->name, nic->netdev)))
       goto err_no_irq;
    netif_wake_queue(nic->netdev);
    netif_poll_enable(nic->netdev);
    /* enable ints _after_ enabling poll, preventing a race between
     * disable ints+schedule */
    e100_enable_irq(nic);
    return 0;
 
err_no_irq:
    del_timer_sync(&nic->watchdog);
err_clean_cbs:
    e100_clean_cbs(nic);
err_rx_clean_list:
    e100_rx_clean_list(nic);
    return err;
}
 
static void e100_down(struct nic *nic)
{
    /* wait here for poll to complete */
    netif_poll_disable(nic->netdev);
    netif_stop_queue(nic->netdev);
    e100_hw_reset(nic);
    free_irq(nic->pdev->irq, nic->netdev);
    del_timer_sync(&nic->watchdog);
    netif_carrier_off(nic->netdev);
    e100_clean_cbs(nic);
    e100_rx_clean_list(nic);
}
 
static void e100_tx_timeout(struct net_device *netdev)
{
    struct nic *nic = netdev_priv(netdev);
 
    /* Reset outside of interrupt context, to avoid request_irq 
     * in interrupt context */
    schedule_work(&nic->tx_timeout_task);
}
 
#define MII_LED_CONTROL 0x1B
static void e100_blink_led(unsigned long data)
{
    struct nic *nic = (struct nic *)data;
    enum led_state {
        led_on     = 0x01,
        led_off    = 0x04,
        led_on_559 = 0x05,
        led_on_557 = 0x07,
    };
 
    nic->leds = (nic->leds & led_on) ? led_off :
        (nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559;
    mdio_write(nic->netdev, nic->mii.phy_id, MII_LED_CONTROL, nic->leds);
    mod_timer(&nic->blink_timer, jiffies + HZ / 4);
}
 
static int e100_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
{
    struct nic *nic = netdev_priv(netdev);
    return mii_ethtool_gset(&nic->mii, cmd);
}
 
static int e100_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
{
    struct nic *nic = netdev_priv(netdev);
    int err;
 
    mdio_write(netdev, nic->mii.phy_id, MII_BMCR, BMCR_RESET);
    err = mii_ethtool_sset(&nic->mii, cmd);
    e100_exec_cb(nic, NULL, e100_configure);
 
    return err;
}
 
。。。。。
// 对应标准网卡驱动程序的一些封装函数
static int e100_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
    struct nic *nic = netdev_priv(netdev);
 
    return generic_mii_ioctl(&nic->mii, if_mii(ifr), cmd, NULL);
}
 
static int e100_alloc(struct nic *nic)
{
    nic->mem = pci_alloc_consistent(nic->pdev, sizeof(struct mem),
        &nic->dma_addr);
    return nic->mem ? 0 : -ENOMEM;
}
 
static void e100_free(struct nic *nic)
{
    if(nic->mem) {
        pci_free_consistent(nic->pdev, sizeof(struct mem),
          nic->mem, nic->dma_addr);
        nic->mem = NULL;
    }
}
 
static int e100_open(struct net_device *netdev)
{
    struct nic *nic = netdev_priv(netdev);
    int err = 0;
 
    netif_carrier_off(netdev);
    if((err = e100_up(nic)))
        DPRINTK(IFUP, ERR, "Cannot open interface, aborting.\n");
    return err;
}
 
static int e100_close(struct net_device *netdev)
{
    e100_down(netdev_priv(netdev));
    return 0;
}
 


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1124027



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -