目录

文章目录

  • 目录
  • 总览
  • rte_eth_dev/rte_eth_dev_data 数据结构
  • rte_eth_dev_count 函数
  • rte_eth_dev_configure 函数
    • ixgbe_dev_configure 函数
    • rte_eth_dev_rx_queue_config/rte_eth_dev_tx_queue_config 函数
  • rte_eth_rx_queue_setup 函数
    • ixgbe_dev_rx_queue_setup 函数
  • rte_eth_tx_queue_setup 函数
    • ixgbe_dev_tx_queue_setup 函数
  • rte_eth_dev_start 函数
    • ixgbe_dev_start 函数
  • 参考文档

总览

  • rte_eth_dev_count:获取被 DPDK App 接管的 eth 网卡数量。
  • rte_eth_dev_configure:根据 DPDK App 的需要,配置被 App 接管的 eth 网卡,实际上是配置 eth 网卡的驱动程序。
  • rte_eth_rx_queue_setup/rte_eth_tx_queue_setup:为网卡分配 接收/发送 队列。
  • rte_eth_dev_start:启动网卡。
  • rte_eth_rx_burst/rte_eth_tx_burst:为指定网卡的指定队列的 接收/发送 数据包函数。
  • ixgbe_dev_*:Intel 82599(Intel x500 系列)网卡的驱动程序,作为该型号网卡的 PMD 与 igb_uio 驱动一起实现 kernel-bypass 的效果。

rte_eth_dev/rte_eth_dev_data 数据结构

DPDK 定义了一个 rte_eth_devices 数组,元素类型为 struct rte_eth_dev,一个元素代表一块网卡。struct rte_eth_dev 有四个重要的成员:

  1. rx_pkt_burst:网卡的 burst 收包函数;
  2. tx_pkt_burst:网卡的 burst 发包函数;
  3. dev_ops:网卡驱动注册函数表,类型为 struct eth_dev_ops;
  4. data:包含了网卡的主要信息,类型为 struct rte_eth_dev_data。
struct rte_eth_dev {/* 在 rte_bus_probe() 中注册 rx/tx_pkt_burst */eth_rx_burst_t rx_pkt_burst;  /**< Pointer to PMD receive function. */eth_tx_burst_t tx_pkt_burst;     /**< Pointer to PMD transmit function. */eth_tx_prep_t tx_pkt_prepare;   /**< Pointer to PMD transmit prepare function. */struct rte_eth_dev_data *data;  /**< Pointer to device data *//* 在 rte_bus_probe() 中注册 dev_ops */const struct eth_dev_ops *dev_ops;   /**< Functions exported by PMD */struct rte_device *device;          /**< Backing device */struct rte_intr_handle *intr_handle; /**< Device interrupt handle */
...
} __rte_cache_aligned;struct rte_eth_dev_data {char name[RTE_ETH_NAME_MAX_LEN]; /**< Unique identifier name *//* 接收队列数组 */void **rx_queues;      /**< Array of pointers to RX queues. *//* 发送队列数组 */void **tx_queues;         /**< Array of pointers to TX queues. *//* 接收队列数组长度 */uint16_t nb_rx_queues;  /**< Number of RX queues. *//* 发送队列数组长度 */uint16_t nb_tx_queues;  /**< Number of TX queues. */
...
};struct rte_eth_dev rte_eth_devices[RTE_MAX_ETHPORTS];static struct rte_eth_dev_data *rte_eth_dev_data;

rte_eth_dev_count 函数

uint8_t
rte_eth_dev_count(void)
{uint8_t p;uint8_t count;count = 0;RTE_ETH_FOREACH_DEV(p)count++;return count;
}#define RTE_ETH_FOREACH_DEV(p)                 \for (p = rte_eth_find_next(0);                \(unsigned int)p < (unsigned int)RTE_MAX_ETHPORTS;   \p = rte_eth_find_next(p + 1))/*** 从 port_id 开始遍历 rte_eth_device 数组,找到第一个状态为 RTE_ETH_DEV_ATTACHED 的设备。* 这些设备使用指令 dpdk-devbind.py --bind 进行绑定。*/
uint8_t
rte_eth_find_next(uint8_t port_id)
{while (port_id < RTE_MAX_ETHPORTS &&rte_eth_devices[port_id].state != RTE_ETH_DEV_ATTACHED)port_id++;if (port_id >= RTE_MAX_ETHPORTS)return RTE_MAX_ETHPORTS;return port_id;
}

rte_eth_dev_configure 函数

rte_eth_dev_configure 函数的主要工作是分配接收/发送队列数组,一个数组元素表示一个接收/发送队列,类型为 void *。

int
rte_eth_dev_configure(uint8_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,const struct rte_eth_conf *dev_conf)
{struct rte_eth_dev *dev;struct rte_eth_dev_info dev_info;int diag;/* 检查 port_id 是否合法 */RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);/* 检查接收队列数是否大于 DPDK 的上限 */if (nb_rx_q > RTE_MAX_QUEUES_PER_PORT) {RTE_PMD_DEBUG_TRACE("Number of RX queues requested (%u) is greater than max supported(%d)\n",nb_rx_q, RTE_MAX_QUEUES_PER_PORT);return -EINVAL;}/* 检查发送队列数是否大于 DPDK 上限 */if (nb_tx_q > RTE_MAX_QUEUES_PER_PORT) {RTE_PMD_DEBUG_TRACE("Number of TX queues requested (%u) is greater than max supported(%d)\n",nb_tx_q, RTE_MAX_QUEUES_PER_PORT);return -EINVAL;}/* 得到 port_id 对应的设备 */dev = &rte_eth_devices[port_id];/* 检查 dev_infos_get 和 dev_configure 是否定义 */RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -ENOTSUP);RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_configure, -ENOTSUP);/* 检查设备是否已启动 */if (dev->data->dev_started) {RTE_PMD_DEBUG_TRACE("port %d must be stopped to allow configuration\n", port_id);return -EBUSY;}/*** 复制 dev_conf 到 dev->data->dev_conf。*   - dev_conf 由 DPDK App 定义。*   - dev 结构体将传入到网卡驱动程序。*/memcpy(&dev->data->dev_conf, dev_conf, sizeof(dev->data->dev_conf));/** Check that the numbers of RX and TX queues are not greater* than the maximum number of RX and TX queues supported by the* configured device.*//*** dev->dev_ops 注册了网卡驱动的函数。* 如果是 ixgbe 驱动,则调用 ixgbe_dev_info_get() 函数。*/(*dev->dev_ops->dev_infos_get)(dev, &dev_info);/* 检查接收/发送队列数是否同时为 0 */if (nb_rx_q == 0 && nb_tx_q == 0) {RTE_PMD_DEBUG_TRACE("ethdev port_id=%d both rx and tx queue cannot be 0\n", port_id);return -EINVAL;}/* 检查接收队列数是否大于网卡上限 */if (nb_rx_q > dev_info.max_rx_queues) {RTE_PMD_DEBUG_TRACE("ethdev port_id=%d nb_rx_queues=%d > %d\n",port_id, nb_rx_q, dev_info.max_rx_queues);return -EINVAL;}/* 检查发送队列数是否大于网卡上限 */if (nb_tx_q > dev_info.max_tx_queues) {RTE_PMD_DEBUG_TRACE("ethdev port_id=%d nb_tx_queues=%d > %d\n",port_id, nb_tx_q, dev_info.max_tx_queues);return -EINVAL;}/* Check that the device supports requested interrupts */if ((dev_conf->intr_conf.lsc == 1) &&(!(dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC))) {RTE_PMD_DEBUG_TRACE("driver %s does not support lsc\n",dev->device->driver->name);return -EINVAL;}if ((dev_conf->intr_conf.rmv == 1) &&(!(dev->data->dev_flags & RTE_ETH_DEV_INTR_RMV))) {RTE_PMD_DEBUG_TRACE("driver %s does not support rmv\n",dev->device->driver->name);return -EINVAL;}/** If jumbo frames are enabled, check that the maximum RX packet* length is supported by the configured device.*/if (dev_conf->rxmode.jumbo_frame == 1) {if (dev_conf->rxmode.max_rx_pkt_len >dev_info.max_rx_pktlen) {RTE_PMD_DEBUG_TRACE("ethdev port_id=%d max_rx_pkt_len %u"" > max valid value %u\n",port_id,(unsigned)dev_conf->rxmode.max_rx_pkt_len,(unsigned)dev_info.max_rx_pktlen);return -EINVAL;} else if (dev_conf->rxmode.max_rx_pkt_len < ETHER_MIN_LEN) {RTE_PMD_DEBUG_TRACE("ethdev port_id=%d max_rx_pkt_len %u"" < min valid value %u\n",port_id,(unsigned)dev_conf->rxmode.max_rx_pkt_len,(unsigned)ETHER_MIN_LEN);return -EINVAL;}} else {if (dev_conf->rxmode.max_rx_pkt_len < ETHER_MIN_LEN ||dev_conf->rxmode.max_rx_pkt_len > ETHER_MAX_LEN) /* 小于64或大于1518 *//* Use default value */dev->data->dev_conf.rxmode.max_rx_pkt_len =ETHER_MAX_LEN; /* 默认值为1518 */}/* 分配接收队列数组,地址赋给 dev->data->rx_queues,长度赋给 dev->data->nb_rx_queues */diag = rte_eth_dev_rx_queue_config(dev, nb_rx_q);if (diag != 0) {RTE_PMD_DEBUG_TRACE("port%d rte_eth_dev_rx_queue_config = %d\n",port_id, diag);return diag;}/* 分配发送队列数组,地址赋给 dev->data->tx_queues,长度赋给 dev->data->nb_tx_queues */diag = rte_eth_dev_tx_queue_config(dev, nb_tx_q);if (diag != 0) {RTE_PMD_DEBUG_TRACE("port%d rte_eth_dev_tx_queue_config = %d\n",port_id, diag);rte_eth_dev_rx_queue_config(dev, 0);return diag;}/* 注册了 ixgbe 驱动的 ixgbe_dev_configure() 函数 */diag = (*dev->dev_ops->dev_configure)(dev);if (diag != 0) {RTE_PMD_DEBUG_TRACE("port%d dev_configure = %d\n",port_id, diag);rte_eth_dev_rx_queue_config(dev, 0);rte_eth_dev_tx_queue_config(dev, 0);return diag;}return 0;
}

ixgbe_dev_configure 函数

static int
ixgbe_dev_configure(struct rte_eth_dev *dev)
{.../* multipe queue mode checking */ret  = ixgbe_check_mq_mode(dev);.../** Initialize to TRUE. If any of Rx queues doesn't meet the bulk* allocation or vector Rx preconditions we will reset it.*/adapter->rx_bulk_alloc_allowed = true;adapter->rx_vec_allowed = true;...
}

rte_eth_dev_rx_queue_config/rte_eth_dev_tx_queue_config 函数

static int
rte_eth_dev_rx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
{...dev->data->rx_queues = rte_zmalloc("ethdev->rx_queues",sizeof(dev->data->rx_queues[0]) * nb_queues,RTE_CACHE_LINE_SIZE);...dev->data->nb_rx_queues = nb_queues; /* 更新nb_rx_queues */...
}static int
rte_eth_dev_tx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
{...dev->data->tx_queues = rte_zmalloc("ethdev->tx_queues",sizeof(dev->data->tx_queues[0]) * nb_queues,RTE_CACHE_LINE_SIZE);...dev->data->nb_tx_queues = nb_queues; /* 更新nb_tx_queues */...
}

rte_eth_rx_queue_setup 函数

int
rte_eth_rx_queue_setup(uint8_t port_id, uint16_t rx_queue_id,uint16_t nb_rx_desc, unsigned int socket_id,const struct rte_eth_rxconf *rx_conf,struct rte_mempool *mp)
{int ret;uint32_t mbp_buf_size;struct rte_eth_dev *dev;struct rte_eth_dev_info dev_info;void **rxq;/* 检查 port_id 是否合法 */RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);/* 得到 port_id 对应的设备 */dev = &rte_eth_devices[port_id];if (rx_queue_id >= dev->data->nb_rx_queues) {RTE_PMD_DEBUG_TRACE("Invalid RX queue_id=%d\n", rx_queue_id);return -EINVAL;}/* 检查设备是否已启动 */if (dev->data->dev_started) {RTE_PMD_DEBUG_TRACE("port %d must be stopped to allow configuration\n", port_id);return -EBUSY;}/* 检查 dev_infos_get 和 rx_queue_setup 是否定义 */RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -ENOTSUP);RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rx_queue_setup, -ENOTSUP);/** Check the size of the mbuf data buffer.* This value must be provided in the private data of the memory pool.* First check that the memory pool has a valid private data.*/rte_eth_dev_info_get(port_id, &dev_info);if (mp->private_data_size < sizeof(struct rte_pktmbuf_pool_private)) {RTE_PMD_DEBUG_TRACE("%s private_data_size %d < %d\n",mp->name, (int) mp->private_data_size,(int) sizeof(struct rte_pktmbuf_pool_private));return -ENOSPC;}mbp_buf_size = rte_pktmbuf_data_room_size(mp);if ((mbp_buf_size - RTE_PKTMBUF_HEADROOM) < dev_info.min_rx_bufsize) {RTE_PMD_DEBUG_TRACE("%s mbuf_data_room_size %d < %d ""(RTE_PKTMBUF_HEADROOM=%d + min_rx_bufsize(dev)""=%d)\n",mp->name,(int)mbp_buf_size,(int)(RTE_PKTMBUF_HEADROOM +dev_info.min_rx_bufsize),(int)RTE_PKTMBUF_HEADROOM,(int)dev_info.min_rx_bufsize);return -EINVAL;}/* 检查 nb_rx_desc 是否大于网卡上限 */if (nb_rx_desc > dev_info.rx_desc_lim.nb_max ||nb_rx_desc < dev_info.rx_desc_lim.nb_min ||nb_rx_desc % dev_info.rx_desc_lim.nb_align != 0) {RTE_PMD_DEBUG_TRACE("Invalid value for nb_rx_desc(=%hu), ""should be: <= %hu, = %hu, and a product of %hu\n",nb_rx_desc,dev_info.rx_desc_lim.nb_max,dev_info.rx_desc_lim.nb_min,dev_info.rx_desc_lim.nb_align);return -EINVAL;}/* 得到接收队列数组 */rxq = dev->data->rx_queues;if (rxq[rx_queue_id]) {/* 检查 rx_queue_release 是否定义 */RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rx_queue_release,-ENOTSUP);/* ixgbe 驱动程序注册了 ixgbe_dev_rx_queue_release() 函数 */(*dev->dev_ops->rx_queue_release)(rxq[rx_queue_id]);rxq[rx_queue_id] = NULL;}if (rx_conf == NULL)rx_conf = &dev_info.default_rxconf;/* ixgbe 驱动程序注册了 ixgbe_dev_rx_queue_setup() 函数 */ret = (*dev->dev_ops->rx_queue_setup)(dev, rx_queue_id, nb_rx_desc,socket_id, rx_conf, mp);if (!ret) {if (!dev->data->min_rx_buf_size ||dev->data->min_rx_buf_size > mbp_buf_size)dev->data->min_rx_buf_size = mbp_buf_size;}return ret;
}

ixgbe_dev_rx_queue_setup 函数

int __attribute__((cold))
ixgbe_dev_rx_queue_setup(struct rte_eth_dev *dev,uint16_t queue_idx,uint16_t nb_desc,unsigned int socket_id,const struct rte_eth_rxconf *rx_conf,struct rte_mempool *mp)
{.../* 分配 ixgbe_rx_queue */rxq = rte_zmalloc_socket("ethdev RX queue", sizeof(struct ixgbe_rx_queue),RTE_CACHE_LINE_SIZE, socket_id);.../* 初始化 rxq */rxq->mb_pool = mp;rxq->nb_rx_desc = nb_desc;rxq->rx_free_thresh = rx_conf->rx_free_thresh;rxq->queue_id = queue_idx;rxq->reg_idx = (uint16_t)((RTE_ETH_DEV_SRIOV(dev).active == 0) ?queue_idx : RTE_ETH_DEV_SRIOV(dev).def_pool_q_idx + queue_idx);rxq->port_id = dev->data->port_id;rxq->crc_len = (uint8_t) ((dev->data->dev_conf.rxmode.hw_strip_crc) ?0 : ETHER_CRC_LEN);rxq->drop_en = rx_conf->rx_drop_en;rxq->rx_deferred_start = rx_conf->rx_deferred_start;.../*** 分配 desc(skb 描述符)数组,数组元素类型为 union ixgbe_adv_rx_desc1* (IXGBE_MAX_RING_DESC + RTE_PMD_IXGBE_RX_MAX_BURST) * sizeof(union ixgbe_adv_rx_desc)* (4096 + 32) * sizeof(union ixgbe_adv_rx_desc)*/rz = rte_eth_dma_zone_reserve(dev, "rx_ring", queue_idx,RX_RING_SZ, IXGBE_ALIGN, socket_id);.../* 清零 desc 数组 */memset(rz->addr, 0, RX_RING_SZ); .../* 设置 rdt_reg_addr 为 RDT 寄存器的地址 */rxq->rdt_reg_addr =IXGBE_PCI_REG_ADDR(hw, IXGBE_RDT(rxq->reg_idx));/* 设置 rdh_reg_addr 为 RDH 寄存器的地址 */rxq->rdh_reg_addr =IXGBE_PCI_REG_ADDR(hw, IXGBE_RDH(rxq->reg_idx));.../* rx_ring_phys_addr 指向 desc 数组的总线地址 */rxq->rx_ring_phys_addr = rte_mem_phy2mch(rz->memseg_id, rz->phys_addr);/* rx_ring 指向 desc 数组的虚拟地址 */rxq->rx_ring = (union ixgbe_adv_rx_desc *) rz->addr;.../* 分配 entry 数组,地址赋给 sw_ring */rxq->sw_ring = rte_zmalloc_socket("rxq->sw_ring",sizeof(struct ixgbe_rx_entry) * len,RTE_CACHE_LINE_SIZE, socket_id);.../* rx_queues[queue_idx] 指向 ixgbe_rx_queue */dev->data->rx_queues[queue_idx] = rxq;.../* 设置接收队列参数 */ixgbe_reset_rx_queue(adapter, rxq);...
}static void __attribute__((cold))
ixgbe_reset_rx_queue(struct ixgbe_adapter *adapter, struct ixgbe_rx_queue *rxq)
{...rxq->rx_nb_avail = 0;rxq->rx_next_avail = 0;rxq->rx_free_trigger = (uint16_t)(rxq->rx_free_thresh - 1);rxq->rx_tail = 0;rxq->nb_rx_hold = 0;rxq->pkt_first_seg = NULL;rxq->pkt_last_seg = NULL;...
}

rte_eth_tx_queue_setup 函数

int
rte_eth_tx_queue_setup(uint8_t port_id, uint16_t tx_queue_id,uint16_t nb_tx_desc, unsigned int socket_id,const struct rte_eth_txconf *tx_conf)
{struct rte_eth_dev *dev;struct rte_eth_dev_info dev_info;void **txq;/* 检查 port_id 是否合法 */RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);/* 得到 port_id 对应的设备 */dev = &rte_eth_devices[port_id];if (tx_queue_id >= dev->data->nb_tx_queues) {RTE_PMD_DEBUG_TRACE("Invalid TX queue_id=%d\n", tx_queue_id);return -EINVAL;}/* 检查设备是否已启动 */if (dev->data->dev_started) {RTE_PMD_DEBUG_TRACE("port %d must be stopped to allow configuration\n", port_id);return -EBUSY;}/* 检查 dev_infos_get 和 tx_queue_setup 是否定义 */RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_infos_get, -ENOTSUP);RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->tx_queue_setup, -ENOTSUP);rte_eth_dev_info_get(port_id, &dev_info);/* 检查 nb_tx_desc 是否大于网卡上限 */if (nb_tx_desc > dev_info.tx_desc_lim.nb_max ||nb_tx_desc < dev_info.tx_desc_lim.nb_min ||nb_tx_desc % dev_info.tx_desc_lim.nb_align != 0) {RTE_PMD_DEBUG_TRACE("Invalid value for nb_tx_desc(=%hu), ""should be: <= %hu, = %hu, and a product of %hu\n",nb_tx_desc,dev_info.tx_desc_lim.nb_max,dev_info.tx_desc_lim.nb_min,dev_info.tx_desc_lim.nb_align);return -EINVAL;}/* 得到发送队列数组 */txq = dev->data->tx_queues;if (txq[tx_queue_id]) {/* 检查 tx_queue_release 是否定义 */RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->tx_queue_release,-ENOTSUP);/* ixgbe 驱动程序注册了 ixgbe_dev_tx_queue_release() 函数 */(*dev->dev_ops->tx_queue_release)(txq[tx_queue_id]);txq[tx_queue_id] = NULL;}if (tx_conf == NULL)tx_conf = &dev_info.default_txconf;/* ixgbe 驱动程序注册了 ixgbe_dev_tx_queue_setup() 函数 */return (*dev->dev_ops->tx_queue_setup)(dev, tx_queue_id, nb_tx_desc,socket_id, tx_conf);
}

ixgbe_dev_tx_queue_setup 函数

int __attribute__((cold))
ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,uint16_t queue_idx,uint16_t nb_desc,unsigned int socket_id,const struct rte_eth_txconf *tx_conf)
{.../* 分配 ixgbe_tx_queue */txq = rte_zmalloc_socket("ethdev TX queue", sizeof(struct ixgbe_tx_queue),RTE_CACHE_LINE_SIZE, socket_id);.../*** 分配 desc(skb 描述符)数组,数组元素类型为 union ixgbe_adv_tx_desc* sizeof(union ixgbe_adv_tx_desc) * 4096*/tz = rte_eth_dma_zone_reserve(dev, "tx_ring", queue_idx,sizeof(union ixgbe_adv_tx_desc) * IXGBE_MAX_RING_DESC,IXGBE_ALIGN, socket_id);.../* 初始化 txq */txq->nb_tx_desc = nb_desc;txq->tx_rs_thresh = tx_rs_thresh;txq->tx_free_thresh = tx_free_thresh;txq->pthresh = tx_conf->tx_thresh.pthresh;txq->hthresh = tx_conf->tx_thresh.hthresh;txq->wthresh = tx_conf->tx_thresh.wthresh;txq->queue_id = queue_idx;txq->reg_idx = (uint16_t)((RTE_ETH_DEV_SRIOV(dev).active == 0) ?queue_idx : RTE_ETH_DEV_SRIOV(dev).def_pool_q_idx + queue_idx);txq->port_id = dev->data->port_id;txq->txq_flags = tx_conf->txq_flags;txq->ops = &def_txq_ops;txq->tx_deferred_start = tx_conf->tx_deferred_start;.../* 设置 tdt_reg_addr 为 TDT 寄存器的地址 */txq->tdt_reg_addr = IXGBE_PCI_REG_ADDR(hw, IXGBE_TDT(txq->reg_idx));.../* tx_ring_phys_addr 指向 desc 数组的总线地址 */txq->tx_ring_phys_addr = rte_mem_phy2mch(tz->memseg_id, tz->phys_addr);/* tx_ring 指向 desc 数组的虚拟地址 */txq->tx_ring = (union ixgbe_adv_tx_desc *) tz->addr;.../* 分配 entry 数组,地址赋给 sw_ring */txq->sw_ring = rte_zmalloc_socket("txq->sw_ring",sizeof(struct ixgbe_tx_entry) * nb_desc,RTE_CACHE_LINE_SIZE, socket_id);.../*** ixgbe_reset_tx_queue() 设置发送队列参数*/txq->ops->reset(txq);.../* tx_queues[queue_idx] 指向 ixgbe_tx_queue */dev->data->tx_queues[queue_idx] = txq;...
}static void __attribute__((cold))
ixgbe_reset_tx_queue(struct ixgbe_tx_queue *txq)
{...prev = (uint16_t) (txq->nb_tx_desc - 1);for (i = 0; i < txq->nb_tx_desc; i++) {...txd->wb.status = rte_cpu_to_le_32(IXGBE_TXD_STAT_DD);txe[i].mbuf = NULL;txe[i].last_id = i;txe[prev].next_id = i;prev = i;}...txq->tx_next_dd = (uint16_t)(txq->tx_rs_thresh - 1);txq->tx_next_rs = (uint16_t)(txq->tx_rs_thresh - 1);...txq->tx_tail = 0;txq->nb_tx_used = 0;...txq->last_desc_cleaned = (uint16_t)(txq->nb_tx_desc - 1);txq->nb_tx_free = (uint16_t)(txq->nb_tx_desc - 1);...
}

rte_eth_dev_start 函数

int
rte_eth_dev_start(uint8_t port_id)
{struct rte_eth_dev *dev;int diag;/* 检查 port_id 是否合法 */RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);/* 得到 port_id 对应的设备 */dev = &rte_eth_devices[port_id];/* 检查 dev_start 是否定义 */RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->dev_start, -ENOTSUP);/* 检查设备是否已启动 */if (dev->data->dev_started != 0) {RTE_PMD_DEBUG_TRACE("Device with port_id=%" PRIu8" already started\n",port_id);return 0;}/* ixgbe 驱动程序注册了 ixgbe_dev_start() 函数 */diag = (*dev->dev_ops->dev_start)(dev);if (diag == 0)dev->data->dev_started = 1;elsereturn diag;/* 保存配置 */rte_eth_dev_config_restore(port_id);if (dev->data->dev_conf.intr_conf.lsc == 0) {RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->link_update, -ENOTSUP);(*dev->dev_ops->link_update)(dev, 0);}return 0;
}

ixgbe_dev_start 函数

static int
ixgbe_dev_start(struct rte_eth_dev *dev)
{.../* 为每个 ixgbe_tx_queue 配置网卡的 TDBAL、TDBAH、TDLEN、TDH、TDT */ixgbe_dev_tx_init(dev);.../* 为每个 ixgbe_rx_queue 配置网卡的 RDBAL、RDBAH、RDLEN、RDH、RDT */err = ixgbe_dev_rx_init(dev);...err = ixgbe_dev_rxtx_start(dev);...
}void __attribute__((cold))
ixgbe_dev_tx_init(struct rte_eth_dev *dev)
{...for (i = 0; i < dev->data->nb_tx_queues; i++) {txq = dev->data->tx_queues[i];.../* desc 数组的总线地址 */bus_addr = txq->tx_ring_phys_addr; /* 将 desc 数组的总线地址写入网卡寄存器* TDBAL(TX Descriptor Base Address Low)* TDBAH(TX Descriptor Base Address High)* TDLEN(TX Descriptor Length)* TDH(TX Descriptor Head)* TDT(TX Descriptor Tail)* #define IXGBE_TDBAL(_i)       (0x06000 + ((_i) * 0x40))* #define IXGBE_TDBAH(_i)     (0x06004 + ((_i) * 0x40))* #define IXGBE_TDLEN(_i)     (0x06008 + ((_i) * 0x40))* #define IXGBE_TDH(_i)       (0x06010 + ((_i) * 0x40))* #define IXGBE_TDT(_i)       (0x06018 + ((_i) * 0x40)) */IXGBE_WRITE_REG(hw, IXGBE_TDBAL(txq->reg_idx),(uint32_t)(bus_addr & 0x00000000ffffffffULL));IXGBE_WRITE_REG(hw, IXGBE_TDBAH(txq->reg_idx),(uint32_t)(bus_addr >> 32));IXGBE_WRITE_REG(hw, IXGBE_TDLEN(txq->reg_idx),txq->nb_tx_desc * sizeof(union ixgbe_adv_tx_desc));      /* desc 数组的长度 *//* Setup the HW Tx Head and TX Tail descriptor pointers */IXGBE_WRITE_REG(hw, IXGBE_TDH(txq->reg_idx), 0);               /* 写 TDH 为 0 */IXGBE_WRITE_REG(hw, IXGBE_TDT(txq->reg_idx), 0);              /* 写 TDT 为 0 */...}...
}int __attribute__((cold))
ixgbe_dev_rx_init(struct rte_eth_dev *dev)
{...for (i = 0; i < dev->data->nb_rx_queues; i++) {rxq = dev->data->rx_queues[i];.../* desc 数组的总线地址 */bus_addr = rxq->rx_ring_phys_addr; /* 将 desc 数组的总线地址写入网卡寄存器* RDBAL(RX Descriptor Base Address Low)* RDBAH(RX Descriptor Base Address High)* RDLEN(RX Descriptor Length)* RDH(RX Descriptor Head)* RDT(RX Descriptor Tail)* #define IXGBE_RDBAL(_i)   (((_i) < 64) ? (0x01000 + ((_i) * 0x40)) : \*               (0x0D000 + (((_i) - 64) * 0x40)))* #define IXGBE_RDBAH(_i) (((_i) < 64) ? (0x01004 + ((_i) * 0x40)) : \*               (0x0D004 + (((_i) - 64) * 0x40)))* #define IXGBE_RDLEN(_i) (((_i) < 64) ? (0x01008 + ((_i) * 0x40)) : \*               (0x0D008 + (((_i) - 64) * 0x40)))* #define IXGBE_RDH(_i)   (((_i) < 64) ? (0x01010 + ((_i) * 0x40)) : \*               (0x0D010 + (((_i) - 64) * 0x40)))* #define IXGBE_RDT(_i)   (((_i) < 64) ? (0x01018 + ((_i) * 0x40)) : \*               (0x0D018 + (((_i) - 64) * 0x40))) */IXGBE_WRITE_REG(hw, IXGBE_RDBAL(rxq->reg_idx),(uint32_t)(bus_addr & 0x00000000ffffffffULL));IXGBE_WRITE_REG(hw, IXGBE_RDBAH(rxq->reg_idx),(uint32_t)(bus_addr >> 32));IXGBE_WRITE_REG(hw, IXGBE_RDLEN(rxq->reg_idx),rxq->nb_rx_desc * sizeof(union ixgbe_adv_rx_desc));  /* desc 数组的长度 */IXGBE_WRITE_REG(hw, IXGBE_RDH(rxq->reg_idx), 0);                 /* 写 RDH 为 0 */IXGBE_WRITE_REG(hw, IXGBE_RDT(rxq->reg_idx), 0);              /* 写 RDT 为 0 */...}...
}int __attribute__((cold))
ixgbe_dev_rxtx_start(struct rte_eth_dev *dev)
{...for (i = 0; i < dev->data->nb_tx_queues; i++) {...ret = ixgbe_dev_tx_queue_start(dev, i);...}...for (i = 0; i < dev->data->nb_rx_queues; i++) {...ret = ixgbe_dev_rx_queue_start(dev, i);...}...
}int __attribute__((cold))
ixgbe_dev_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id)
{.../* 使能发送 */txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(txq->reg_idx));txdctl |= IXGBE_TXDCTL_ENABLE;IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(txq->reg_idx), txdctl);.../* 写 TDH 为 0 */IXGBE_WRITE_REG(hw, IXGBE_TDH(txq->reg_idx), 0);/* 写 TDT 为 0 */IXGBE_WRITE_REG(hw, IXGBE_TDT(txq->reg_idx), 0);/* 设置发送队列状态为 RTE_ETH_QUEUE_STATE_STARTED */dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;...
}int __attribute__((cold))
ixgbe_dev_rx_queue_start(struct rte_eth_dev *dev, uint16_t rx_queue_id)
{.../* 为每个接收队列分配 mbuf */if (ixgbe_alloc_rx_queue_mbufs(rxq) != 0) {.../* 使能接收 */rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(rxq->reg_idx));rxdctl |= IXGBE_RXDCTL_ENABLE;IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(rxq->reg_idx), rxdctl);.../* 写 RDH 为 0 */IXGBE_WRITE_REG(hw, IXGBE_RDH(rxq->reg_idx), 0);/* 写 RDT 为 rxq->nb_rx_desc - 1 */IXGBE_WRITE_REG(hw, IXGBE_RDT(rxq->reg_idx), rxq->nb_rx_desc - 1);/* 设置接收队列状态为 RTE_ETH_QUEUE_STATE_STARTED */dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;...
}static int __attribute__((cold))
ixgbe_alloc_rx_queue_mbufs(struct ixgbe_rx_queue *rxq)
{struct ixgbe_rx_entry *rxe = rxq->sw_ring;uint64_t dma_addr;unsigned int i;/* Initialize software ring entries */for (i = 0; i < rxq->nb_rx_desc; i++) {volatile union ixgbe_adv_rx_desc *rxd;struct rte_mbuf *mbuf = rte_mbuf_raw_alloc(rxq->mb_pool); /* 分配mbuf */if (mbuf == NULL) {PMD_INIT_LOG(ERR, "RX mbuf alloc failed queue_id=%u",(unsigned) rxq->queue_id);return -ENOMEM;}mbuf->data_off = RTE_PKTMBUF_HEADROOM;mbuf->port = rxq->port_id;dma_addr =rte_cpu_to_le_64(rte_mbuf_data_dma_addr_default(mbuf)); /* mbuf的总线地址 */rxd = &rxq->rx_ring[i];rxd->read.hdr_addr = 0;rxd->read.pkt_addr = dma_addr;  /* 总线地址赋给 rxd->read.pkt_addr */rxe[i].mbuf = mbuf;           /* 将 mbuf 挂载到 rxe */}return 0;
}

参考文档

https://blog.csdn.net/hz5034/article/details/88367518

DPDK — 网卡初始化流程(Intel 82599 ixgbe 网卡驱动示例)相关推荐

  1. dpdk eal初始化流程梳理

    for dpdk-18.11 这里把dpdk的eal初始化流程简单汇总,尽量把每个函数功能介绍详细,持续更新中 rte_eal_init │ ├──rte_cpu_is_supported:检查cpu ...

  2. AX200网卡支持linux,Intel 9260/AX200网卡在Deepin/UOS/Ubuntu下网速慢的处理

    如果你所使用的是Intel 9260/AX200网卡,遇到网速很慢的问题,可以采取以下方法处理,有Deepin/UOS/Ubuntu等Linux发行版的解决方案. 处理方法 我自己之前更换了Intel ...

  3. DPDK — L2 Forwarding 与网卡设备初始化流程

    目录 文章目录 目录 L2 Forwarding Application 安装部署 部署拓扑 编译运行 L2fwd 测试 L2 转发功能 实现分析 L2 转发原理 代码注释 函数调用关系图 网卡设备初 ...

  4. DPDK — 网卡驱动初始化流程

    目录 文章目录 目录 Intel 82599 ixgbe 网卡驱动示例 rte_eth_dev/rte_eth_dev_data 数据结构 rte_eth_dev_count 函数 rte_eth_d ...

  5. Linux 操作系统原理 — 网卡驱动程序初始化流程

    目录 文章目录 目录 源码版本 1.内核启动流程 2.内核协议栈初始化流程 3.网卡驱动程序注册流程 4.网卡驱动程序初始化流程 net_device 结构体 net_device_ops 结构体 初 ...

  6. ixgbe网卡驱动Ⅱ---- 驱动注册

    目录 1 ixgbe 网卡注册驱动 1.1 ixgbe_driver 类 1.2 ixgbe_driver 注册/注销 2 ixgbe 的 PCI 注册驱动流程 pci_register_driver ...

  7. dpdk 网卡初始化时中断使能的过程

    dpdk pmd 中注册中断回调函数并使能中断 eth_ixgbe_dev_init 是 ixgbe 网卡的初始化函数,在这个函数的最后注册中断回调并使能中断. 在配置了收发队列等等步骤后,注册中断回 ...

  8. Intel 82599网卡异常挂死原因

    前提背景: 生产环境上,服务器网络突然断链,ssh连接失败. 问题初步定位: 查找内核日志,得到网卡异常信息 Jan 24 11:52:43 localhost kernel: ixgbe 0000: ...

  9. 了解ixgbe网卡驱动— 驱动注册(纯代码分享)

    1 ixgbe 网卡注册驱动 和大部分设备驱动一样,网卡驱动是作为一个 module 注册到 kernel 的 通过 module_init() -> ixgbe_init_module() - ...

最新文章

  1. gzcms技术开发文档
  2. 【最短路】【Floyed】医院设置(ssl 1614)
  3. 软件构造-犯错的艺术——健壮性与正确性,异常,防御式编程,debugging与test的思考与总结...
  4. 雷军 1994 年写的代码,你见过吗?厉害了!
  5. 9款WordPress视频插件
  6. jsp网页实现任意进制的数转换成任意进制数
  7. android js交互 数组,Android WebView —— Java 与 JavaScript 交互总结
  8. Linux服务器系统管理优化,Linux服务器性能管理与优化
  9. jQ1.5中的事件系统(低版本的事件系统)
  10. 《Spring Boot极简教程》 第6章 Springboot数据库集成
  11. HTML 计算机代码
  12. ln多少等于2用计算机,ln2(log计算器在线)
  13. 电脑迷你世界,迷你世界电脑版
  14. 爱情不是等你有空才珍惜的
  15. 计算机管理磁盘管理右键无反应,win7系统删除磁盘管理磁盘右键菜单只有“帮助”的解决技巧...
  16. vivo x60pro刷机鸿蒙,vivo X60 Pro:两个好消息,两个坏消息
  17. 电脑开机密码,强制修改,覆盖原密码
  18. ADMIN云计算系统管理
  19. 基于经典蓝牙的安卓蓝牙APP开发(基于蓝牙2.0开发,例:HC-05)
  20. SDUT-程序设计基础-实验4-for循环(下)

热门文章

  1. mysql case when 去重_【Mysql】 case ... when ... 用法
  2. requests payload_python+Requests接口自动化测试之传递 URL 参数
  3. 对人脑如何控制手的新认识:我们为什么削水果时,拿的是刀柄而不会拿刀刃?...
  4. “无路之门”,一款VR恐怖冒险游戏
  5. AutoX江苏超级工厂首曝光!机械臂随处可见,车辆出厂就能完全无人驾驶
  6. 嬴彻CEO:自动驾驶技术只有依托量产,才有持久优势
  7. Arm官宣V9架构,用AI和安全对抗英特尔,最快今年年底用上
  8. 程序员硬核劝告:现在还不是出门的时候
  9. 世道变了!这个AI竞赛不再要刷榜成绩,直接看商业落地计划书
  10. 量子位MEET大会正式启动!邀AI企业共同预见智能科技新未来