X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fi40e%2Fi40e_fdir.c;h=aa8e7294958dbc91bef879ec812894ae62ecae22;hb=be797cbf4582f3c474f208aeb3d1baa4001a6156;hp=71eb31fb8bc84fab3ac21f7efbf693080042addd;hpb=460d1679586e7095709d3229257cdce0032706c3;p=dpdk.git diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c index 71eb31fb8b..aa8e729495 100644 --- a/drivers/net/i40e/i40e_fdir.c +++ b/drivers/net/i40e/i40e_fdir.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "i40e_logs.h" #include "base/i40e_type.h" @@ -99,7 +100,7 @@ static int i40e_flow_fdir_filter_programming(struct i40e_pf *pf, enum i40e_filter_pctype pctype, const struct i40e_fdir_filter_conf *filter, - bool add); + bool add, bool wait_status); static int i40e_fdir_rx_queue_init(struct i40e_rx_queue *rxq) @@ -163,6 +164,7 @@ i40e_fdir_setup(struct i40e_pf *pf) char z_name[RTE_MEMZONE_NAMESIZE]; const struct rte_memzone *mz = NULL; struct rte_eth_dev *eth_dev = pf->adapter->eth_dev; + uint16_t i; if ((pf->flags & I40E_FLAG_FDIR) == 0) { PMD_INIT_LOG(ERR, "HW doesn't support FDIR"); @@ -179,6 +181,7 @@ i40e_fdir_setup(struct i40e_pf *pf) PMD_DRV_LOG(INFO, "FDIR initialization has been done."); return I40E_SUCCESS; } + /* make new FDIR VSI */ vsi = i40e_vsi_setup(pf, I40E_VSI_FDIR, pf->main_vsi, 0); if (!vsi) { @@ -228,22 +231,37 @@ i40e_fdir_setup(struct i40e_pf *pf) goto fail_mem; } + /* enable FDIR MSIX interrupt */ + vsi->nb_used_qps = 1; + i40e_vsi_queues_bind_intr(vsi, I40E_ITR_INDEX_NONE); + i40e_vsi_enable_queues_intr(vsi); + /* reserve memory for the fdir programming packet */ snprintf(z_name, sizeof(z_name), "%s_%s_%d", eth_dev->device->driver->name, I40E_FDIR_MZ_NAME, eth_dev->data->port_id); - mz = i40e_memzone_reserve(z_name, I40E_FDIR_PKT_LEN, SOCKET_ID_ANY); + mz = i40e_memzone_reserve(z_name, I40E_FDIR_PKT_LEN * + I40E_FDIR_PRG_PKT_CNT, SOCKET_ID_ANY); if (!mz) { PMD_DRV_LOG(ERR, "Cannot init memzone for " "flow director program packet."); err = I40E_ERR_NO_MEMORY; goto fail_mem; } - pf->fdir.prg_pkt = mz->addr; - pf->fdir.dma_addr = mz->iova; + + for (i = 0; i < I40E_FDIR_PRG_PKT_CNT; i++) { + pf->fdir.prg_pkt[i] = (uint8_t *)mz->addr + + I40E_FDIR_PKT_LEN * i; + pf->fdir.dma_addr[i] = mz->iova + + I40E_FDIR_PKT_LEN * i; + } pf->fdir.match_counter_index = I40E_COUNTER_INDEX_FDIR(hw->pf_id); + pf->fdir.fdir_actual_cnt = 0; + pf->fdir.fdir_guarantee_free_space = + pf->fdir.fdir_guarantee_total_space; + PMD_DRV_LOG(INFO, "FDIR setup successfully, with programming queue %u.", vsi->base_queue); return I40E_SUCCESS; @@ -274,12 +292,18 @@ i40e_fdir_teardown(struct i40e_pf *pf) vsi = pf->fdir.fdir_vsi; if (!vsi) return; + + /* disable FDIR MSIX interrupt */ + i40e_vsi_queues_unbind_intr(vsi); + i40e_vsi_disable_queues_intr(vsi); + int err = i40e_switch_tx_queue(hw, vsi->base_queue, FALSE); if (err) PMD_DRV_LOG(DEBUG, "Failed to do FDIR TX switch off"); err = i40e_switch_rx_queue(hw, vsi->base_queue, FALSE); if (err) PMD_DRV_LOG(DEBUG, "Failed to do FDIR RX switch off"); + i40e_dev_rx_queue_release(pf->fdir.rxq); rte_eth_dma_zone_free(dev, "fdir_rx_ring", pf->fdir.rxq->queue_id); pf->fdir.rxq = NULL; @@ -1525,6 +1549,17 @@ i40e_check_fdir_programming_status(struct i40e_rx_queue *rxq) return ret; } +static inline void +i40e_fdir_programming_status_cleanup(struct i40e_rx_queue *rxq) +{ + uint16_t retry_count = 0; + + /* capture the previous error report(if any) from rx ring */ + while ((i40e_check_fdir_programming_status(rxq) < 0) && + (++retry_count < I40E_FDIR_NUM_RX_DESC)) + PMD_DRV_LOG(INFO, "error report captured."); +} + static int i40e_fdir_filter_convert(const struct i40e_fdir_filter_conf *input, struct i40e_fdir_filter *filter) @@ -1565,6 +1600,7 @@ static int i40e_sw_fdir_filter_insert(struct i40e_pf *pf, struct i40e_fdir_filter *filter) { struct i40e_fdir_info *fdir_info = &pf->fdir; + struct i40e_fdir_filter *hash_filter; int ret; if (filter->fdir.input.flow_ext.pkt_template) @@ -1580,9 +1616,14 @@ i40e_sw_fdir_filter_insert(struct i40e_pf *pf, struct i40e_fdir_filter *filter) ret); return ret; } - fdir_info->hash_map[ret] = filter; - TAILQ_INSERT_TAIL(&fdir_info->fdir_list, filter, rules); + if (fdir_info->hash_map[ret]) + return -1; + + hash_filter = &fdir_info->fdir_filter_array[ret]; + rte_memcpy(hash_filter, filter, sizeof(*filter)); + fdir_info->hash_map[ret] = hash_filter; + TAILQ_INSERT_TAIL(&fdir_info->fdir_list, hash_filter, rules); return 0; } @@ -1611,11 +1652,57 @@ i40e_sw_fdir_filter_del(struct i40e_pf *pf, struct i40e_fdir_input *input) fdir_info->hash_map[ret] = NULL; TAILQ_REMOVE(&fdir_info->fdir_list, filter, rules); - rte_free(filter); return 0; } +struct rte_flow * +i40e_fdir_entry_pool_get(struct i40e_fdir_info *fdir_info) +{ + struct rte_flow *flow = NULL; + uint64_t slab = 0; + uint32_t pos = 0; + uint32_t i = 0; + int ret; + + if (fdir_info->fdir_actual_cnt >= + fdir_info->fdir_space_size) { + PMD_DRV_LOG(ERR, "Fdir space full"); + return NULL; + } + + ret = rte_bitmap_scan(fdir_info->fdir_flow_pool.bitmap, &pos, + &slab); + + /* normally this won't happen as the fdir_actual_cnt should be + * same with the number of the set bits in fdir_flow_pool, + * but anyway handle this error condition here for safe + */ + if (ret == 0) { + PMD_DRV_LOG(ERR, "fdir_actual_cnt out of sync"); + return NULL; + } + + i = rte_bsf64(slab); + pos += i; + rte_bitmap_clear(fdir_info->fdir_flow_pool.bitmap, pos); + flow = &fdir_info->fdir_flow_pool.pool[pos].flow; + + memset(flow, 0, sizeof(struct rte_flow)); + + return flow; +} + +void +i40e_fdir_entry_pool_put(struct i40e_fdir_info *fdir_info, + struct rte_flow *flow) +{ + struct i40e_fdir_entry *f; + + f = FLOW_TO_FLOW_BITMAP(flow); + rte_bitmap_set(fdir_info->fdir_flow_pool.bitmap, f->idx); +} + /* * i40e_add_del_fdir_filter - add or remove a flow director filter. * @pf: board private structure @@ -1629,7 +1716,7 @@ i40e_add_del_fdir_filter(struct rte_eth_dev *dev, { struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - unsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt; + unsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt[0]; enum i40e_filter_pctype pctype; int ret = 0; @@ -1678,6 +1765,45 @@ i40e_add_del_fdir_filter(struct rte_eth_dev *dev, return ret; } +static inline unsigned char * +i40e_find_available_buffer(struct rte_eth_dev *dev) +{ + struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); + struct i40e_fdir_info *fdir_info = &pf->fdir; + struct i40e_tx_queue *txq = pf->fdir.txq; + + /* no available buffer + * search for more available buffers from the current + * descriptor, until an unavailable one + */ + if (fdir_info->txq_available_buf_count <= 0) { + uint16_t tmp_tail; + volatile struct i40e_tx_desc *tmp_txdp; + + tmp_tail = txq->tx_tail; + tmp_txdp = &txq->tx_ring[tmp_tail + 1]; + + do { + if ((tmp_txdp->cmd_type_offset_bsz & + rte_cpu_to_le_64(I40E_TXD_QW1_DTYPE_MASK)) == + rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE)) + fdir_info->txq_available_buf_count++; + else + break; + + tmp_tail += 2; + if (tmp_tail >= txq->nb_tx_desc) + tmp_tail = 0; + } while (tmp_tail != txq->tx_tail); + } + + if (fdir_info->txq_available_buf_count > 0) + fdir_info->txq_available_buf_count--; + else + return NULL; + return (unsigned char *)fdir_info->prg_pkt[txq->tx_tail >> 1]; +} + /** * i40e_flow_add_del_fdir_filter - add or remove a flow director filter. * @pf: board private structure @@ -1691,11 +1817,12 @@ i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev, { struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private); struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - unsigned char *pkt = (unsigned char *)pf->fdir.prg_pkt; + unsigned char *pkt = NULL; enum i40e_filter_pctype pctype; struct i40e_fdir_info *fdir_info = &pf->fdir; - struct i40e_fdir_filter *fdir_filter, *node; + struct i40e_fdir_filter *node; struct i40e_fdir_filter check_filter; /* Check if the filter exists */ + bool wait_status = true; int ret = 0; if (pf->fdir.fdir_vsi == NULL) { @@ -1727,25 +1854,50 @@ i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev, /* Check if there is the filter in SW list */ memset(&check_filter, 0, sizeof(check_filter)); i40e_fdir_filter_convert(filter, &check_filter); - node = i40e_sw_fdir_filter_lookup(fdir_info, &check_filter.fdir.input); - if (add && node) { - PMD_DRV_LOG(ERR, - "Conflict with existing flow director rules!"); - return -EINVAL; - } - if (!add && !node) { - PMD_DRV_LOG(ERR, - "There's no corresponding flow firector filter!"); - return -EINVAL; + if (add) { + ret = i40e_sw_fdir_filter_insert(pf, &check_filter); + if (ret < 0) { + PMD_DRV_LOG(ERR, + "Conflict with existing flow director rules!"); + return -EINVAL; + } + + if (fdir_info->fdir_invalprio == 1 && + fdir_info->fdir_guarantee_free_space > 0) + wait_status = false; + } else { + node = i40e_sw_fdir_filter_lookup(fdir_info, + &check_filter.fdir.input); + if (!node) { + PMD_DRV_LOG(ERR, + "There's no corresponding flow firector filter!"); + return -EINVAL; + } + + ret = i40e_sw_fdir_filter_del(pf, &node->fdir.input); + if (ret < 0) { + PMD_DRV_LOG(ERR, + "Error deleting fdir rule from hash table!"); + return -EINVAL; + } + + pf->fdir.flex_mask_flag[pctype] = 0; + + if (fdir_info->fdir_invalprio == 1) + wait_status = false; } - memset(pkt, 0, I40E_FDIR_PKT_LEN); + /* find a buffer to store the pkt */ + pkt = i40e_find_available_buffer(dev); + if (pkt == NULL) + goto error_op; + memset(pkt, 0, I40E_FDIR_PKT_LEN); ret = i40e_flow_fdir_construct_pkt(pf, &filter->input, pkt); if (ret < 0) { PMD_DRV_LOG(ERR, "construct packet for fdir fails."); - return ret; + goto error_op; } if (hw->mac.type == I40E_MAC_X722) { @@ -1754,30 +1906,37 @@ i40e_flow_add_del_fdir_filter(struct rte_eth_dev *dev, hw, I40E_GLQF_FD_PCTYPES((int)pctype)); } - ret = i40e_flow_fdir_filter_programming(pf, pctype, filter, add); + ret = i40e_flow_fdir_filter_programming(pf, pctype, filter, add, + wait_status); if (ret < 0) { PMD_DRV_LOG(ERR, "fdir programming fails for PCTYPE(%u).", pctype); - return ret; + goto error_op; } if (add) { - fdir_filter = rte_zmalloc("fdir_filter", - sizeof(*fdir_filter), 0); - if (fdir_filter == NULL) { - PMD_DRV_LOG(ERR, "Failed to alloc memory."); - return -ENOMEM; - } - - rte_memcpy(fdir_filter, &check_filter, sizeof(check_filter)); - ret = i40e_sw_fdir_filter_insert(pf, fdir_filter); - if (ret < 0) - rte_free(fdir_filter); + fdir_info->fdir_actual_cnt++; + if (fdir_info->fdir_invalprio == 1 && + fdir_info->fdir_guarantee_free_space > 0) + fdir_info->fdir_guarantee_free_space--; } else { - ret = i40e_sw_fdir_filter_del(pf, &node->fdir.input); + fdir_info->fdir_actual_cnt--; + if (fdir_info->fdir_invalprio == 1 && + fdir_info->fdir_guarantee_free_space < + fdir_info->fdir_guarantee_total_space) + fdir_info->fdir_guarantee_free_space++; } return ret; + +error_op: + /* roll back */ + if (add) + i40e_sw_fdir_filter_del(pf, &check_filter.fdir.input); + else + i40e_sw_fdir_filter_insert(pf, &check_filter); + + return ret; } /* @@ -1878,7 +2037,7 @@ i40e_fdir_filter_programming(struct i40e_pf *pf, PMD_DRV_LOG(INFO, "filling transmit descriptor."); txdp = &(txq->tx_ring[txq->tx_tail + 1]); - txdp->buffer_addr = rte_cpu_to_le_64(pf->fdir.dma_addr); + txdp->buffer_addr = rte_cpu_to_le_64(pf->fdir.dma_addr[0]); td_cmd = I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS | I40E_TX_DESC_CMD_DUMMY; @@ -1928,7 +2087,7 @@ static int i40e_flow_fdir_filter_programming(struct i40e_pf *pf, enum i40e_filter_pctype pctype, const struct i40e_fdir_filter_conf *filter, - bool add) + bool add, bool wait_status) { struct i40e_tx_queue *txq = pf->fdir.txq; struct i40e_rx_queue *rxq = pf->fdir.rxq; @@ -1936,8 +2095,9 @@ i40e_flow_fdir_filter_programming(struct i40e_pf *pf, volatile struct i40e_tx_desc *txdp; volatile struct i40e_filter_program_desc *fdirdp; uint32_t td_cmd; - uint16_t vsi_id, i; + uint16_t vsi_id; uint8_t dest; + uint32_t i; PMD_DRV_LOG(INFO, "filling filter programming descriptor."); fdirdp = (volatile struct i40e_filter_program_desc *) @@ -2012,7 +2172,8 @@ i40e_flow_fdir_filter_programming(struct i40e_pf *pf, PMD_DRV_LOG(INFO, "filling transmit descriptor."); txdp = &txq->tx_ring[txq->tx_tail + 1]; - txdp->buffer_addr = rte_cpu_to_le_64(pf->fdir.dma_addr); + txdp->buffer_addr = rte_cpu_to_le_64(pf->fdir.dma_addr[txq->tx_tail >> 1]); + td_cmd = I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS | I40E_TX_DESC_CMD_DUMMY; @@ -2025,25 +2186,32 @@ i40e_flow_fdir_filter_programming(struct i40e_pf *pf, txq->tx_tail = 0; /* Update the tx tail register */ rte_wmb(); + + /* fdir program rx queue cleanup */ + i40e_fdir_programming_status_cleanup(rxq); + I40E_PCI_REG_WRITE(txq->qtx_tail, txq->tx_tail); - for (i = 0; i < I40E_FDIR_MAX_WAIT_US; i++) { - if ((txdp->cmd_type_offset_bsz & - rte_cpu_to_le_64(I40E_TXD_QW1_DTYPE_MASK)) == - rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE)) - break; - rte_delay_us(1); - } - if (i >= I40E_FDIR_MAX_WAIT_US) { - PMD_DRV_LOG(ERR, - "Failed to program FDIR filter: time out to get DD on tx queue."); - return -ETIMEDOUT; - } - /* totally delay 10 ms to check programming status*/ - rte_delay_us(I40E_FDIR_MAX_WAIT_US); - if (i40e_check_fdir_programming_status(rxq) < 0) { - PMD_DRV_LOG(ERR, - "Failed to program FDIR filter: programming status reported."); - return -ETIMEDOUT; + + if (wait_status) { + for (i = 0; i < I40E_FDIR_MAX_WAIT_US; i++) { + if ((txdp->cmd_type_offset_bsz & + rte_cpu_to_le_64(I40E_TXD_QW1_DTYPE_MASK)) == + rte_cpu_to_le_64(I40E_TX_DESC_DTYPE_DESC_DONE)) + break; + rte_delay_us(1); + } + if (i >= I40E_FDIR_MAX_WAIT_US) { + PMD_DRV_LOG(ERR, + "Failed to program FDIR filter: time out to get DD on tx queue."); + return -ETIMEDOUT; + } + /* totally delay 10 ms to check programming status*/ + rte_delay_us(I40E_FDIR_MAX_WAIT_US); + if (i40e_check_fdir_programming_status(rxq) < 0) { + PMD_DRV_LOG(ERR, + "Failed to program FDIR filter: programming status reported."); + return -ETIMEDOUT; + } } return 0;