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;
}

net_device_ops的ndo_open和ndo_start_xmit函数相关推荐

  1. 【A113】网卡芯片Realtek RTL8201驱动调试

    前言: 这一篇是对自己调试的一个过程记录,代码看的算是比较熟悉了,过程中一直没调过,没后询问原厂FAE,修改了一下dts一个地址参数,就可以了,最终没有太多成就感,修改了PHY芯片的一个状态寄存器.. ...

  2. 网卡驱动(hisi3536网卡驱动,以及stmmac层)

    一:基本概念 应用程序最终以套接字的形式完成网络设备的接口.,对网络设备定义四个层次:网络协议接口层(数据包的发送接收,向网络层协议提供统一的数据包收发接口,舍得上层协议独立于具体的设备,(ip,ar ...

  3. Linux: 网络数据收发流程简析

    文章目录 1. 前言 2. 背景 3. 网卡数据收发流程 3.1 网络数据接收流程 3.1.1 网卡数据接收流程 3.1.2 网卡数据向上传递给L3,L4的流程 3.2 网卡数据发送流程 1. 前言 ...

  4. linux dev queue xmit,dev_queue_xmi函数详解

    点击(此处)折叠或打开 int dev_queue_xmit(struct sk_buff *skb) { struct net_device *dev = skb->dev; struct n ...

  5. Linux内核网络数据发送(六)——网络设备驱动

    Linux内核网络数据发送(六)--网络设备驱动 1. 前言 2. 驱动回调函数注册 3. `ndo_start_xmit` 发送数据 4. `igb_tx_map` 1. 前言 本文主要介绍设备通过 ...

  6. Linux内核网络设备驱动

    本文首先从宏观上介绍数据包的接收过程,然后详细介绍了Linux网络设备驱动的工作过程,最后介绍网卡监控与调优,包括网络数据包总数.丢包.错包数量的相关统计. 1. 接收数据包过程概述 介绍数据包收包过 ...

  7. linux内核网络协议栈--监控和调优:发送数据(三十)

    译者序 本文翻译自 2017 年的一篇英文博客 Monitoring and Tuning the Linux Networking Stack: Sending Data.如果能看懂英文,建议阅读原 ...

  8. linux内核网络协议栈--linux bridge(十九)

    1 . 前言 本文是参考附录上的资料整理而成,以帮助读者更好的理解kernel中brdige 模块代码. 2. 网桥的原理 2.1 桥接的概念 简单来说,桥接就是把一台机器上的若干个网络接口" ...

  9. linux内核网络协议栈--监控和调优:接收数据(十五)

    译者序 本文翻译自 2016 年的一篇英文博客 Monitoring and Tuning the Linux Networking Stack: Receiving Data.如果能看懂英文,建议阅 ...

  10. DPDK KNI实现(二十五)

    一.为什么要用kni 通常情况下dpdk用于二三层报文转发,接收到来自网卡的报文后,如果是二层报文则查找fdb表: 如果是三层报文,则进行dnat, snat处理后,查找路由表, 将报文转发给下一跳路 ...

最新文章

  1. windows中路径\和 linux中用/
  2. 独家 | 层级聚类和Python实现的初学者指南(附链接)
  3. PAT (Basic Level) Practice (中文)1076 Wifi密码 (15 分)
  4. 记录某一天安服仔的漏洞挖掘过程
  5. OpenGL中shader使用
  6. 无光驱不支持USB设备启动的笔记本,如何使用Ghost来安装系统
  7. jupyter notebook使用入门2——创建一个基于scikit-Learn的线性预测ipynb文件
  8. 01-eclipse打包运行程序总是报错java.lang.NoClassDefFoundError和ava.lang.ClassNotFoundException(打包原理)
  9. python中3 and not 5_python中not、and和or的优先级与详细用法介绍
  10. 非线性方程求根算法的C++实现
  11. 怎么在局域网中设置共享文件夹?
  12. 树的前序、中序、后序遍历 | Tree Walk | C/C++实现
  13. Mac获取系统版本、机型
  14. 2022Android各APP免费加固方案评估
  15. error怎么开机 fan_台式机开机出现cpu fan error怎么办
  16. AUTOCAD——修改坐标轴样式
  17. 【重磅】人民网:分布式存储打开千亿级市场,深入推动行业数字化转型
  18. \\ip 映射 指定的网络名不再可用
  19. 小散量化炒股记|股价如波浪起伏,教你用量化识别波段的极值点
  20. spring开发_Annotation_AOP_Before增强处理

热门文章

  1. PPT怎么画出好看的三维示意图
  2. html5 audio duration,记一次vue中获取audio媒体总时长duration遇到的问题
  3. 傻瓜式自制鼠标光标,超简单
  4. html 空格 正则表达式,正则表达式清除空格和html标签中的 空格
  5. python高频词汇表大全_我们用程序整理出了一份Python英语高频词汇表,拿走不谢!...
  6. ipad显示portal服务器获取不,苹果portal认证失败原因合集
  7. python第七天作业
  8. js字符串时间格式与中国标准时间格式相互转换
  9. php生成中国标准时间,中国时间标准
  10. GTC '19 经典回顾 | 如何编排和创造二次元中的舞蹈?