net_device_ops的ndo_open和ndo_start_xmit函数

来源:互联网 发布:家用路由器 知乎 编辑:程序博客网 时间:2024/06/06 10:46
net_device_ops的ndo_open 函数实在dev_open->__dev_open 中打开的.
    if (!ret && ops->ndo_open)
        ret = ops->ndo_open(dev);

static int hns_nic_net_open(struct net_device *ndev)
{
    struct hns_nic_priv *priv = netdev_priv(ndev);
    struct hnae_handle *h = priv->ae_handle;
    int ret;
//如果是testing 则退出
    if (test_bit(NIC_STATE_TESTING, &priv->state))
        return -EBUSY;

    priv->link = 0;
    netif_carrier_off(ndev);
//设置tx queue的个数
    ret = netif_set_real_num_tx_queues(ndev, h->q_num);
    if (ret < 0) {
        netdev_err(ndev, "netif_set_real_num_tx_queues fail, ret=%d!\n",
               ret);
        return ret;
    }
//设置rx queue的个数
    ret = netif_set_real_num_rx_queues(ndev, h->q_num);
    if (ret < 0) {
        netdev_err(ndev,
               "netif_set_real_num_rx_queues fail, ret=%d!\n", ret);
        return ret;
    }

    ret = hns_nic_net_up(ndev);
    if (ret) {
        netdev_err(ndev,
               "hns net up fail, ret=%d!\n", ret);
        return ret;
    }

    return 0;
}
static int hns_nic_net_up(struct net_device *ndev)
{
    struct hns_nic_priv *priv = netdev_priv(ndev);
    struct hnae_handle *h = priv->ae_handle;
    int i, j;
    int ret;
//初始化中断,并设置中断函数为hns_irq_handle,每个rx和tx queue都对应一个中断
    ret = hns_nic_init_irq(priv);
    if (ret != 0) {
        netdev_err(ndev, "hns init irq failed! ret=%d\n", ret);
        return ret;
    }

    for (i = 0; i < h->q_num * 2; i++) {
//使能中断,使能napi
        ret = hns_nic_ring_open(ndev, i);
        if (ret)
            goto out_has_some_queues;
    }
//设置mac地址
    ret = h->dev->ops->set_mac_addr(h, ndev->dev_addr);
    if (ret)
        goto out_set_mac_addr_err;
//hns的start函数为null
    ret = h->dev->ops->start ? h->dev->ops->start(h) : 0;
    if (ret)
        goto out_start_err;
//启动phy
    if (ndev->phydev)
        phy_start(ndev->phydev);

    clear_bit(NIC_STATE_DOWN, &priv->state);
修改time 每一秒到期一次
    (void)mod_timer(&priv->service_timer, jiffies + SERVICE_TIMER_HZ);

    return 0;

out_start_err:
    netif_stop_queue(ndev);
out_set_mac_addr_err:
out_has_some_queues:
    for (j = i - 1; j >= 0; j--)
        hns_nic_ring_close(ndev, j);

    set_bit(NIC_STATE_DOWN, &priv->state);

    return ret;
}
static int hns_nic_init_irq(struct hns_nic_priv *priv)
{
    struct hnae_handle *h = priv->ae_handle;
    struct hns_nic_ring_data *rd;
    int i;
    int ret;
    int cpu;
//这里的rx和tx的queue 个数都是h->q_num,因此h->q_num * 2表示为每个rx和tx都申请一个中断
    for (i = 0; i < h->q_num * 2; i++) {
        rd = &priv->ring_data[i];

        if (rd->ring->irq_init_flag == RCB_IRQ_INITED)
            break;

        snprintf(rd->ring->ring_name, RCB_RING_NAME_LEN,
             "%s-%s%d", priv->netdev->name,
             (is_tx_ring(rd->ring) ? "tx" : "rx"), rd->queue_index);

        rd->ring->ring_name[RCB_RING_NAME_LEN - 1] = '\0';
//中断的处理函数为hns_irq_handle
        ret = request_irq(rd->ring->irq,
                  hns_irq_handle, 0, rd->ring->ring_name, rd);
        if (ret) {
            netdev_err(priv->netdev, "request irq(%d) fail\n",
                   rd->ring->irq);
            return ret;
        }
//为了要设置irq的affinity,暂时disable irq
        disable_irq(rd->ring->irq);

        cpu = hns_nic_init_affinity_mask(h->q_num, i,
                         rd->ring, &rd->mask);
//通过irq_set_affinity_hint 设置irq affintiy
        if (cpu_online(cpu))
            irq_set_affinity_hint(rd->ring->irq,
                          &rd->mask);

        rd->ring->irq_init_flag = RCB_IRQ_INITED;
    }

    return 0;
}

static int hns_nic_ring_open(struct net_device *netdev, int idx)
{
    struct hns_nic_priv *priv = netdev_priv(netdev);
    struct hnae_handle *h = priv->ae_handle;
//先是能napi 再使能中断
    napi_enable(&priv->ring_data[idx].napi);

    enable_irq(priv->ring_data[idx].ring->irq);
    h->dev->ops->toggle_ring_irq(priv->ring_data[idx].ring, 0);

    return 0;
}

要从协议层想设备中发送数据,会调用dev_queue_xmit函数。
dev_queue_xmit->__dev_queue_xmit->dev_hard_start_xmit->xmit_one->netdev_start_xmit->__netdev_start_xmit
static inline netdev_tx_t __netdev_start_xmit(const struct net_device_ops *ops,
                          struct sk_buff *skb, struct net_device *dev,
                          bool more)
{
    skb->xmit_more = more ? 1 : 0;
    return ops->ndo_start_xmit(skb, dev);
}
最终调用net device自己的ndo_start_xmit函数来发送,下面这个hns_nic_netdev_ops 中的ndo_start_xmit对应的函数是hns_nic_net_xmit
static const struct net_device_ops hns_nic_netdev_ops = {
    .ndo_open = hns_nic_net_open,
    .ndo_start_xmit = hns_nic_net_xmit,

};

static netdev_tx_t hns_nic_net_xmit(struct sk_buff *skb,
                    struct net_device *ndev)
{
    struct hns_nic_priv *priv = netdev_priv(ndev);
    int ret;

    assert(skb->queue_mapping < ndev->ae_handle->q_num);
    ret = hns_nic_net_xmit_hw(ndev, skb,
                  &tx_ring_data(priv, skb->queue_mapping));
    if (ret == NETDEV_TX_OK) {
        netif_trans_update(ndev);
        ndev->stats.tx_bytes += skb->len;
        ndev->stats.tx_packets++;
    }
    return (netdev_tx_t)ret;
}
最终调用hns_nic_net_xmit_hw 发送数据
int hns_nic_net_xmit_hw(struct net_device *ndev,
            struct sk_buff *skb,
            struct hns_nic_ring_data *ring_data)
{
    struct hns_nic_priv *priv = netdev_priv(ndev);
    struct hnae_ring *ring = ring_data->ring;
    struct device *dev = ring_to_dev(ring);
    struct netdev_queue *dev_queue;
    struct skb_frag_struct *frag;
    int buf_num;
    int seg_num;
    dma_addr_t dma;
    int size, next_to_use;
    int i;

    switch (priv->ops.maybe_stop_tx(&skb, &buf_num, ring)) {
    case -EBUSY:
        ring->stats.tx_busy++;
        goto out_net_tx_busy;
    case -ENOMEM:
        ring->stats.sw_err_cnt++;
        netdev_err(ndev, "no memory to xmit!\n");
        goto out_err_tx_ok;
    default:
        break;
    }

    /* no. of segments (plus a header) */
    seg_num = skb_shinfo(skb)->nr_frags + 1;
    next_to_use = ring->next_to_use;

    /* fill the first part */
//得到skb的size
    size = skb_headlen(skb);
    dma = dma_map_single(dev, skb->data, size, DMA_TO_DEVICE);
    if (dma_mapping_error(dev, dma)) {
        netdev_err(ndev, "TX head DMA map failed\n");
        ring->stats.sw_err_cnt++;
        goto out_err_tx_ok;
    }
//填充需要发送的数据
    priv->ops.fill_desc(ring, skb, size, dma, seg_num == 1 ? 1 : 0,
                buf_num, DESC_TYPE_SKB, ndev->mtu);

    /* fill the fragments */
    for (i = 1; i < seg_num; i++) {
        frag = &skb_shinfo(skb)->frags[i - 1];
        size = skb_frag_size(frag);
        dma = skb_frag_dma_map(dev, frag, 0, size, DMA_TO_DEVICE);
        if (dma_mapping_error(dev, dma)) {
            netdev_err(ndev, "TX frag(%d) DMA map failed\n", i);
            ring->stats.sw_err_cnt++;
            goto out_map_frag_fail;
        }
        priv->ops.fill_desc(ring, skb_frag_page(frag), size, dma,
                    seg_num - 1 == i ? 1 : 0, buf_num,
                    DESC_TYPE_PAGE, ndev->mtu);
    }

    /*complete translate all packets*/
    dev_queue = netdev_get_tx_queue(ndev, skb->queue_mapping);
    netdev_tx_sent_queue(dev_queue, skb->len);

    wmb(); /* commit all data before submit */
    assert(skb->queue_mapping < priv->ae_handle->q_num);
//触发硬件发送数据
    hnae_queue_xmit(priv->ae_handle->qs[skb->queue_mapping], buf_num);
    ring->stats.tx_pkts++;
    ring->stats.tx_bytes += skb->len;

    return NETDEV_TX_OK;

out_map_frag_fail:

    while (ring->next_to_use != next_to_use) {
        unfill_desc(ring);
        if (ring->next_to_use != next_to_use)
            dma_unmap_page(dev,
                       ring->desc_cb[ring->next_to_use].dma,
                       ring->desc_cb[ring->next_to_use].length,
                       DMA_TO_DEVICE);
        else
            dma_unmap_single(dev,
                     ring->desc_cb[next_to_use].dma,
                     ring->desc_cb[next_to_use].length,
                     DMA_TO_DEVICE);
    }

out_err_tx_ok:

    dev_kfree_skb_any(skb);
    return NETDEV_TX_OK;

out_net_tx_busy:

    netif_stop_subqueue(ndev, skb->queue_mapping);

    /* Herbert's original patch had:
     *  smp_mb__after_netif_stop_queue();
     * but since that doesn't exist yet, just open code it.
     */
    smp_mb();
    return NETDEV_TX_BUSY;
}
原创粉丝点击