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

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

    /*
     * 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\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;
}

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM