zoukankan      html  css  js  c++  java
  • dpdk 网卡队列初始化 + 收发包

     

                                     

                     ixgbe_dev_rx_queue_start   设置好dma地址

         IXGBE_WRITE_REG(hw, IXGBE_RDH(rxq->reg_idx), 0);
            IXGBE_WRITE_REG(hw, IXGBE_RDT(rxq->reg_idx), rxq->nb_rx_desc - 1);
    recv
    {
      rxdp = &rx_ring[rx_id];
            /* 若网卡回写的DD为0,跳出循环 */
            staterr = rxdp->wb.upper.status_error;
            if (!(staterr & rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD)))
                break;
                rxd = *rxdp;
     /* 分配新mbuf */
            nmb = rte_mbuf_raw_alloc(rxq->mb_pool);
            rxe = &sw_ring[rx_id]; /* 得到旧mbuf */
            rxm = rxe->mbuf; /* rxm指向旧mbuf */
            rxe->mbuf = nmb; /* rxe->mbuf指向新mbuf */
            dma_addr =
                rte_cpu_to_le_64(rte_mbuf_data_dma_addr_default(nmb)); /* 得到新mbuf的总线地址 */
            rxdp->read.hdr_addr = 0; /* 清零新mbuf对应的desc的DD,后续网卡会读desc */
            rxdp->read.pkt_addr = dma_addr; /* 设置新mbuf对应的desc的总线地址,后续网卡会读desc */
    }

     

    每个队列都要设置

       /* Allocate and set up 1 RX queue per Ethernet port. */
            for (q = 0; q < rx_rings; q++) {
                    retval = rte_eth_rx_queue_setup(port, q, nb_rxd,
                                    rte_eth_dev_socket_id(port), NULL, mbuf_pool);
                    if (retval < 0)
                            return retval;
            }
    ret = (*dev->dev_ops->rx_queue_setup)(dev, rx_queue_id, nb_rx_desc,
                                                  socket_id, &local_conf, mp);

    ixgbe_dev_rx_queue_setup()

    /**
     * Structure associated with each descriptor of the RX ring of a RX queue.
     */
    struct ixgbe_rx_entry {
            struct rte_mbuf *mbuf; /**< mbuf associated with RX descriptor. */
    };
    
     
    struct ixgbe_tx_entry {
            struct rte_mbuf *mbuf; /**< mbuf associated with TX desc, if any. */
            uint16_t next_id; /**< Index of next descriptor in ring. */
            uint16_t last_id; /**< Index of last scattered descriptor. */
    };
    struct ixgbe_rx_queue {
            struct rte_mempool  *mb_pool; /**< mbuf pool to populate RX ring. */
            volatile union ixgbe_adv_rx_desc *rx_ring; /**< RX ring virtual address. */      -----------------每个queue都有一个设备描述符
            uint64_t            rx_ring_phys_addr; /**< RX ring DMA address. */
            volatile uint32_t   *rdt_reg_addr; /**< RDT register address. */
            volatile uint32_t   *rdh_reg_addr; /**< RDH register address. */
            struct ixgbe_rx_entry *sw_ring; /**< address of RX software ring. */
            
            }







    • pkt_addr:报文数据的物理地址,网卡DMA将报文数据通过该物理地址写入对应的内存空间。
    • hdr_addr:报文的头信息,hdr_addr的最后一个bit为DD位,因为是union结构,即status_error的最后一个bit也对应DD位

     

    DD位(Descriptor Done Status)用于标志标识一个描述符buf是否可用。

    • 网卡每次来了新的数据包,就检查rx_ring当前这个buf的DD位是否为0,如果为0那么表示当前buf可以使用,就让DMA将数据包copy到这个buf中,然后设置DD为1。如果为1,那么网卡就认为rx_ring队列满了,直接会将这个包给丢弃掉,记录一次imiss。(0->1)
    • 对于应用而言,DD位使用恰恰相反,在读取数据包时,先检查DD位是否为1,如果为1,表示网卡已经把数据包放到了内存中,可以读取,读取完后,再放入一个新的buf并把对应DD位设置为0。如果为0,就表示没有数据包可读。(1->0)
    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数组,数组元素类型为union ixgbe_adv_rx_desc
         * (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);
        ...
        memset(rz->addr, 0, RX_RING_SZ); /* 清零desc数组 */
        ...
        /* 设置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;   
    //
    dev->data->rx_queues = rte_zmalloc

    ...
    /* 设置接收队列参数 */ ixgbe_reset_rx_queue(adapter, rxq); ... }

    ixgbe_recv_pkts()

    接收时回写:
    1、网卡使用DMA写Rx FIFO中的Frame到Rx Ring Buffer中的mbuf,设置desc的DD为1
    2、网卡驱动取走mbuf后,设置desc的DD为0,更新RDT

    uint16_t
    ixgbe_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts,
            uint16_t nb_pkts)
    {
        ...
        nb_rx = 0;
        nb_hold = 0;
        rxq = rx_queue;
        rx_id = rxq->rx_tail; /* 相当于ixgbe的next_to_clean */
        rx_ring = rxq->rx_ring;
        sw_ring = rxq->sw_ring;
        ...
        while (nb_rx < nb_pkts) {
            ...
            /* 得到rx_tail指向的desc的指针 */
            rxdp = &rx_ring[rx_id];
            /* 若网卡回写的DD为0,跳出循环 */
            staterr = rxdp->wb.upper.status_error;
            if (!(staterr & rte_cpu_to_le_32(IXGBE_RXDADV_STAT_DD)))
                break;
            /* 得到rx_tail指向的desc */
            rxd = *rxdp;
            ...
            /* 分配新mbuf */
            nmb = rte_mbuf_raw_alloc(rxq->mb_pool);
            ...
            nb_hold++; /* 统计接收的mbuf数 */
            rxe = &sw_ring[rx_id]; /* 得到旧mbuf */
            rx_id++; /* 得到下一个desc的index,注意是一个环形缓冲区 */
            if (rx_id == rxq->nb_rx_desc)
                rx_id = 0;
            ...
            rte_ixgbe_prefetch(sw_ring[rx_id].mbuf); /* 预取下一个mbuf */
            ...
            if ((rx_id & 0x3) == 0) {
                rte_ixgbe_prefetch(&rx_ring[rx_id]);
                rte_ixgbe_prefetch(&sw_ring[rx_id]);
            }
            ...
            rxm = rxe->mbuf; /* rxm指向旧mbuf */
            rxe->mbuf = nmb; /* rxe->mbuf指向新mbuf */
            dma_addr =
                rte_cpu_to_le_64(rte_mbuf_data_dma_addr_default(nmb)); /* 得到新mbuf的总线地址 */
            rxdp->read.hdr_addr = 0; /* 清零新mbuf对应的desc的DD,后续网卡会读desc */
            rxdp->read.pkt_addr = dma_addr; /* 设置新mbuf对应的desc的总线地址,后续网卡会读desc */
            ...
            pkt_len = (uint16_t) (rte_le_to_cpu_16(rxd.wb.upper.length) -
                          rxq->crc_len); /* 包长 */
            rxm->data_off = RTE_PKTMBUF_HEADROOM;
            rte_packet_prefetch((char *)rxm->buf_addr + rxm->data_off);
            rxm->nb_segs = 1;
            rxm->next = NULL;
            rxm->pkt_len = pkt_len;
            rxm->data_len = pkt_len;
            rxm->port = rxq->port_id;
            ...
            if (likely(pkt_flags & PKT_RX_RSS_HASH)) /* RSS */
                rxm->hash.rss = rte_le_to_cpu_32(
                            rxd.wb.lower.hi_dword.rss);
            else if (pkt_flags & PKT_RX_FDIR) { /* FDIR */
                rxm->hash.fdir.hash = rte_le_to_cpu_16(
                        rxd.wb.lower.hi_dword.csum_ip.csum) &
                        IXGBE_ATR_HASH_MASK;
                rxm->hash.fdir.id = rte_le_to_cpu_16(
                        rxd.wb.lower.hi_dword.csum_ip.ip_id);
            }
            ...
            rx_pkts[nb_rx++] = rxm; /* 将旧mbuf放入rx_pkts数组 */
        }
        rxq->rx_tail = rx_id; /* rx_tail指向下一个desc */
        ...
        nb_hold = (uint16_t) (nb_hold + rxq->nb_rx_hold);
        /* 若已处理的mbuf数大于上限(默认为32),更新RDT */
        if (nb_hold > rxq->rx_free_thresh) {
            ...
            rx_id = (uint16_t) ((rx_id == 0) ?
                         (rxq->nb_rx_desc - 1) : (rx_id - 1));
            IXGBE_PCI_REG_WRITE(rxq->rdt_reg_addr, rx_id); /* 将rx_id写入RDT */
            nb_hold = 0; /* 清零nb_hold */
        }
        rxq->nb_rx_hold = nb_hold; /* 更新nb_rx_hold */
        return nb_rx;
    }

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

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

    函数功能
    rte_eth_dev_count() 网卡数
    rte_eth_dev_configure() 配置网卡
    rte_eth_rx_queue_setup()
    rte_eth_tx_queue_setup()
    为网卡分配接收/发送队列
    rte_eth_dev_start() 启动网卡
    rte_eth_rx_burst()
    rte_eth_tx_burst()
    基于指定网卡指定队列的收/发包函数

    rte_eth_dev / rte_eth_dev_data

    DPDK定义了一个rte_eth_devices数组,数组元素类型为struct rte_eth_dev,一个数组元素表示一块网卡。struct rte_eth_dev有四个重要的成员:rx/tx_pkt_burst、dev_ops、data,其中前两者分别是网卡的burst收/发包函数;dev_ops是网卡驱动注册的函数表,类型为struct eth_dev_ops;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 */
        /** User application callbacks for NIC interrupts */
        struct rte_eth_dev_cb_list link_intr_cbs;
        /**
         * User-supplied functions called from rx_burst to post-process
         * received packets before passing them to the user
         */
        struct rte_eth_rxtx_callback *post_rx_burst_cbs[RTE_MAX_QUEUES_PER_PORT];
        /**
         * User-supplied functions called from tx_burst to pre-process
         * received packets before passing them to the driver for transmission.
         */
        struct rte_eth_rxtx_callback *pre_tx_burst_cbs[RTE_MAX_QUEUES_PER_PORT];
        enum rte_eth_dev_state state; /**< Flag indicating the port state */
    } __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_sriov sriov;    /**< SRIOV data */
    
        void *dev_private;              /**< PMD-specific private data */
    
        struct rte_eth_link dev_link;
        /**< Link-level information & status */
    
        struct rte_eth_conf dev_conf;   /**< Configuration applied to device. */
        uint16_t mtu;                   /**< Maximum Transmission Unit. */
    
        uint32_t min_rx_buf_size;
        /**< Common rx buffer size handled by all queues */
    
        uint64_t rx_mbuf_alloc_failed; /**< RX ring mbuf allocation failures. */
        struct ether_addr* mac_addrs;/**< Device Ethernet Link address. */
        uint64_t mac_pool_sel[ETH_NUM_RECEIVE_MAC_ADDR];
        /** bitmap array of associating Ethernet MAC addresses to pools */
        struct ether_addr* hash_mac_addrs;
        /** Device Ethernet MAC addresses of hash filtering. */
        uint8_t port_id;           /**< Device [external] port identifier. */
        __extension__
        uint8_t promiscuous   : 1, /**< RX promiscuous mode ON(1) / OFF(0). */
            scattered_rx : 1,  /**< RX of scattered packets is ON(1) / OFF(0) */
            all_multicast : 1, /**< RX all multicast mode ON(1) / OFF(0). */
            dev_started : 1,   /**< Device state: STARTED(1) / STOPPED(0). */
            lro         : 1;   /**< RX LRO is ON(1) / OFF(0) */
        uint8_t rx_queue_state[RTE_MAX_QUEUES_PER_PORT];
        /** Queues state: STARTED(1) / STOPPED(0) */
        uint8_t tx_queue_state[RTE_MAX_QUEUES_PER_PORT];
        /** Queues state: STARTED(1) / STOPPED(0) */
        uint32_t dev_flags; /**< Capabilities */
        enum rte_kernel_driver kdrv;    /**< Kernel driver passthrough */
        int numa_node;  /**< NUMA node connection */
        struct rte_vlan_filter_conf vlan_filter_conf;
        /**< VLAN filter configuration. */
    };
    
    struct rte_eth_dev rte_eth_devices[RTE_MAX_ETHPORTS];
    
    static struct rte_eth_dev_data *rte_eth_dev_data;

    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)
    ",
                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)
    ",
                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
    ", port_id);
            return -EBUSY;
        }
    
        /* Copy the dev_conf parameter into the dev structure */
        /* 复制dev_conf到dev->data->dev_conf */
        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.
         */
        /* 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
    ", 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
    ",
                    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
    ",
                    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
    ",
                        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
    ",
                        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
    ",
                    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
    ",
                    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 */
        }
    
        /*
         * Setup new number of RX/TX queues and reconfigure device.
         */
        /* 分配接收队列数组,地址赋给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
    ",
                    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
    ",
                    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
    ",
                    port_id, diag);
            rte_eth_dev_rx_queue_config(dev, 0);
            rte_eth_dev_tx_queue_config(dev, 0);
            return diag;
        }
    
        return 0;
    }

    rte_eth_dev_rx_queue_config()  -------------创建多个rx队列

    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 */
        ...
    }

    rte_eth_dev_tx_queue_config()

    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 */
        ...
    }

    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;
        ...
    }
    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;
    }
  • 相关阅读:
    C语言ll作业01
    C语言寒假大作战04
    C语言寒假大作战03
    C语言寒假大作战02
    C语言寒假大作战01
    C语言I作业12—学期总结
    C语言I博客作业11
    C语言I博客作业10
    C语言I博客作业08
    C语言寒假大作战02
  • 原文地址:https://www.cnblogs.com/dream397/p/13608829.html
Copyright © 2011-2022 走看看