dpdk l2fwd(2)

/* txq不为空,释放原先的队列中的mbuf和txq */

/* Free memory prior to re-allocation if needed... */ if (dev->data->tx_queues[queue_idx] != NULL) {

em_tx_queue_release(dev->data->tx_queues[queue_idx]); dev->data->tx_queues[queue_idx] = NULL; }

/* 分配名为rte_em_pmd_tx_ring_p_q的memzone, 用于存放EM_MAX_RING_DESC个tx descriptor */ /*

* Allocate TX ring hardware descriptors. A memzone large enough to * handle the maximum ring size is allocated in order to allow for * resizing in later calls to the queue setup function. */

tsize = sizeof (txq->tx_ring[0]) * EM_MAX_RING_DESC;

if ((tz = ring_dma_zone_reserve(dev, \ socket_id)) == NULL) return (-ENOMEM);

/* txq内存分配 */

/* Allocate the tx queue data structure. */

if ((txq = rte_zmalloc(\ CACHE_LINE_SIZE)) == NULL) return (-ENOMEM);

/* txq sw_ring内存分配 */ /* Allocate software ring */

if ((txq->sw_ring = rte_zmalloc(\ sizeof(txq->sw_ring[0]) * nb_desc, CACHE_LINE_SIZE)) == NULL) { em_tx_queue_release(txq); return (-ENOMEM); }

txq->nb_tx_desc = nb_desc;

txq->tx_free_thresh = tx_free_thresh; txq->tx_rs_thresh = tx_rs_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->port_id = dev->data->port_id;

txq->tdt_reg_addr = E1000_PCI_REG_ADDR(hw, E1000_TDT(queue_idx));

/* tx_ring的物理地址 */ #ifndef RTE_LIBRTE_XEN_DOM0

txq->tx_ring_phys_addr = (uint64_t) tz->phys_addr; #else

txq->tx_ring_phys_addr = rte_mem_phy2mch(tz->memseg_id, tz->phys_addr); #endif

/* tx_ring的虚拟地址 */

txq->tx_ring = (struct e1000_data_desc *) tz->addr;

PMD_INIT_LOG(DEBUG, \dma_addr=0x%\

txq->sw_ring, txq->tx_ring, txq->tx_ring_phys_addr);

/* 环状队列初始化,每个entry的next指向下一个,最后一个指向第一个 */

em_reset_tx_queue(txq);

dev->data->tx_queues[queue_idx] = txq; return (0); }

端口初始化的最后一步是使能端口收发包功能,其中主要是通知E1000驱动tx ring和rx ring的地址, 细节就不再跟进 void

eth_em_tx_init(struct rte_eth_dev *dev) {

struct e1000_hw *hw; struct em_tx_queue *txq; uint32_t tctl;

uint32_t txdctl;

uint16_t i;

hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);

/* 把每一个queue的tx ring的物理地址通告给E1000驱动 */ /* Setup the Base and Length of the Tx Descriptor Rings. */ for (i = 0; i < dev->data->nb_tx_queues; i++) { uint64_t bus_addr;

txq = dev->data->tx_queues[i]; bus_addr = txq->tx_ring_phys_addr; E1000_WRITE_REG(hw, E1000_TDLEN(i), txq->nb_tx_desc *

sizeof(*txq->tx_ring)); E1000_WRITE_REG(hw, E1000_TDBAH(i), (uint32_t)(bus_addr >> 32));

E1000_WRITE_REG(hw, E1000_TDBAL(i), (uint32_t)bus_addr);

/* Setup the HW Tx Head and Tail descriptor pointers. */ E1000_WRITE_REG(hw, E1000_TDT(i), 0);

E1000_WRITE_REG(hw, E1000_TDH(i), 0);

/* Setup Transmit threshold registers. */ txdctl = E1000_READ_REG(hw, E1000_TXDCTL(i)); /*

* bit 22 is reserved, on some models should always be 0, * on others - always 1. */

txdctl &= E1000_TXDCTL_COUNT_DESC; txdctl |= txq->pthresh & 0x3F;

txdctl |= (txq->hthresh & 0x3F) << 8; txdctl |= (txq->wthresh & 0x3F) << 16; txdctl |= E1000_TXDCTL_GRAN;

E1000_WRITE_REG(hw, E1000_TXDCTL(i), txdctl); }

/* Program the Transmit Control Register. */ tctl = E1000_READ_REG(hw, E1000_TCTL);

tctl &= ~E1000_TCTL_CT;

tctl |= (E1000_TCTL_PSP | E1000_TCTL_RTLC | E1000_TCTL_EN | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT));

/* This write will effectively turn on the transmit unit. */ E1000_WRITE_REG(hw, E1000_TCTL, tctl); }

int

eth_em_rx_init(struct rte_eth_dev *dev) {

struct e1000_hw *hw; struct em_rx_queue *rxq; uint32_t rctl; uint32_t rfctl; uint32_t rxcsum; uint32_t rctl_bsize; uint16_t i;

int ret;

hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);

/*

* Make sure receives are disabled while setting * up the descriptor ring. */

rctl = E1000_READ_REG(hw, E1000_RCTL);

E1000_WRITE_REG(hw, E1000_RCTL, rctl & ~E1000_RCTL_EN);

rfctl = E1000_READ_REG(hw, E1000_RFCTL);

/* Disable extended descriptor type. */ rfctl &= ~E1000_RFCTL_EXTEN;

/* Disable accelerated acknowledge */ if (hw->mac.type == e1000_82574) rfctl |= E1000_RFCTL_ACK_DIS;

联系客服:779662525#qq.com(#替换为@)