X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_pmd_e1000%2Figb_ethdev.c;h=2a268b8d89f17453b58457f243b9e11dea6b6eae;hb=0c0c43705c89c1705669c75396a811482dcb6679;hp=9e5665feb04d6d0183d06385c0439e5f02aa110b;hpb=90daa93a1cd1760f95c7504065c58ce552fac315;p=dpdk.git diff --git a/lib/librte_pmd_e1000/igb_ethdev.c b/lib/librte_pmd_e1000/igb_ethdev.c index 9e5665feb0..2a268b8d89 100644 --- a/lib/librte_pmd_e1000/igb_ethdev.c +++ b/lib/librte_pmd_e1000/igb_ethdev.c @@ -69,6 +69,12 @@ #define IGB_DEFAULT_TX_HTHRESH 0 #define IGB_DEFAULT_TX_WTHRESH 0 +/* Bit shift and mask */ +#define IGB_4_BIT_WIDTH (CHAR_BIT / 2) +#define IGB_4_BIT_MASK RTE_LEN2MASK(IGB_4_BIT_WIDTH, uint8_t) +#define IGB_8_BIT_WIDTH CHAR_BIT +#define IGB_8_BIT_MASK UINT8_MAX + static int eth_igb_configure(struct rte_eth_dev *dev); static int eth_igb_start(struct rte_eth_dev *dev); static void eth_igb_stop(struct rte_eth_dev *dev); @@ -83,6 +89,8 @@ static void eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats); static void eth_igb_stats_reset(struct rte_eth_dev *dev); static void eth_igb_infos_get(struct rte_eth_dev *dev, + struct rte_eth_dev_info *dev_info); +static void eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info); static int eth_igb_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf); @@ -136,23 +144,16 @@ static int igbvf_vlan_filter_set(struct rte_eth_dev *dev, static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on); static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on); static int eth_igb_rss_reta_update(struct rte_eth_dev *dev, - struct rte_eth_rss_reta *reta_conf); + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size); static int eth_igb_rss_reta_query(struct rte_eth_dev *dev, - struct rte_eth_rss_reta *reta_conf); - + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size); static int eth_igb_add_syn_filter(struct rte_eth_dev *dev, struct rte_syn_filter *filter, uint16_t rx_queue); static int eth_igb_remove_syn_filter(struct rte_eth_dev *dev); static int eth_igb_get_syn_filter(struct rte_eth_dev *dev, struct rte_syn_filter *filter, uint16_t *rx_queue); -static int eth_igb_add_ethertype_filter(struct rte_eth_dev *dev, - uint16_t index, - struct rte_ethertype_filter *filter, uint16_t rx_queue); -static int eth_igb_remove_ethertype_filter(struct rte_eth_dev *dev, - uint16_t index); -static int eth_igb_get_ethertype_filter(struct rte_eth_dev *dev, - uint16_t index, - struct rte_ethertype_filter *filter, uint16_t *rx_queue); static int eth_igb_add_2tuple_filter(struct rte_eth_dev *dev, uint16_t index, struct rte_2tuple_filter *filter, uint16_t rx_queue); @@ -177,6 +178,18 @@ static int eth_igb_remove_5tuple_filter(struct rte_eth_dev *dev, static int eth_igb_get_5tuple_filter(struct rte_eth_dev *dev, uint16_t index, struct rte_5tuple_filter *filter, uint16_t *rx_queue); +static int igb_add_del_ethertype_filter(struct rte_eth_dev *dev, + struct rte_eth_ethertype_filter *filter, + bool add); +static int igb_ethertype_filter_handle(struct rte_eth_dev *dev, + enum rte_filter_op filter_op, + void *arg); +static int igb_get_ethertype_filter(struct rte_eth_dev *dev, + struct rte_eth_ethertype_filter *filter); +static int eth_igb_filter_ctrl(struct rte_eth_dev *dev, + enum rte_filter_type filter_type, + enum rte_filter_op filter_op, + void *arg); /* * Define VF Stats MACRO for Non "cleared on read" register @@ -255,9 +268,6 @@ static struct eth_dev_ops eth_igb_ops = { .add_syn_filter = eth_igb_add_syn_filter, .remove_syn_filter = eth_igb_remove_syn_filter, .get_syn_filter = eth_igb_get_syn_filter, - .add_ethertype_filter = eth_igb_add_ethertype_filter, - .remove_ethertype_filter = eth_igb_remove_ethertype_filter, - .get_ethertype_filter = eth_igb_get_ethertype_filter, .add_2tuple_filter = eth_igb_add_2tuple_filter, .remove_2tuple_filter = eth_igb_remove_2tuple_filter, .get_2tuple_filter = eth_igb_get_2tuple_filter, @@ -267,6 +277,7 @@ static struct eth_dev_ops eth_igb_ops = { .add_5tuple_filter = eth_igb_add_5tuple_filter, .remove_5tuple_filter = eth_igb_remove_5tuple_filter, .get_5tuple_filter = eth_igb_get_5tuple_filter, + .filter_ctrl = eth_igb_filter_ctrl, }; /* @@ -282,7 +293,7 @@ static struct eth_dev_ops igbvf_eth_dev_ops = { .stats_get = eth_igbvf_stats_get, .stats_reset = eth_igbvf_stats_reset, .vlan_filter_set = igbvf_vlan_filter_set, - .dev_infos_get = eth_igb_infos_get, + .dev_infos_get = eth_igbvf_infos_get, .rx_queue_setup = eth_igb_rx_queue_setup, .rx_queue_release = eth_igb_rx_queue_release, .tx_queue_setup = eth_igb_tx_queue_setup, @@ -1239,7 +1250,6 @@ eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) if (rte_stats == NULL) return; - memset(rte_stats, 0, sizeof(*rte_stats)); rte_stats->ipackets = hw_stats->gprc; rte_stats->ibytes = hw_stats->gorc; rte_stats->opackets = hw_stats->gptc; @@ -1268,8 +1278,7 @@ eth_igbvf_stats_reset(struct rte_eth_dev *dev) } static void -eth_igb_infos_get(struct rte_eth_dev *dev, - struct rte_eth_dev_info *dev_info) +eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); @@ -1299,18 +1308,21 @@ eth_igb_infos_get(struct rte_eth_dev *dev, dev_info->max_rx_queues = 16; dev_info->max_tx_queues = 16; dev_info->max_vmdq_pools = ETH_8_POOLS; + dev_info->vmdq_queue_num = 16; break; case e1000_82580: dev_info->max_rx_queues = 8; dev_info->max_tx_queues = 8; dev_info->max_vmdq_pools = ETH_8_POOLS; + dev_info->vmdq_queue_num = 8; break; case e1000_i350: dev_info->max_rx_queues = 8; dev_info->max_tx_queues = 8; dev_info->max_vmdq_pools = ETH_8_POOLS; + dev_info->vmdq_queue_num = 8; break; case e1000_i354: @@ -1330,23 +1342,61 @@ eth_igb_infos_get(struct rte_eth_dev *dev, dev_info->max_vmdq_pools = 0; break; + default: + /* Should not happen */ + break; + } + dev_info->reta_size = ETH_RSS_RETA_SIZE_128; + + dev_info->default_rxconf = (struct rte_eth_rxconf) { + .rx_thresh = { + .pthresh = IGB_DEFAULT_RX_PTHRESH, + .hthresh = IGB_DEFAULT_RX_HTHRESH, + .wthresh = IGB_DEFAULT_RX_WTHRESH, + }, + .rx_free_thresh = IGB_DEFAULT_RX_FREE_THRESH, + .rx_drop_en = 0, + }; + + dev_info->default_txconf = (struct rte_eth_txconf) { + .tx_thresh = { + .pthresh = IGB_DEFAULT_TX_PTHRESH, + .hthresh = IGB_DEFAULT_TX_HTHRESH, + .wthresh = IGB_DEFAULT_TX_WTHRESH, + }, + .txq_flags = 0, + }; +} + +static void +eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + dev_info->min_rx_bufsize = 256; /* See BSIZE field of RCTL register. */ + dev_info->max_rx_pktlen = 0x3FFF; /* See RLPML register. */ + dev_info->max_mac_addrs = hw->mac.rar_entry_count; + dev_info->rx_offload_capa = DEV_RX_OFFLOAD_VLAN_STRIP | + DEV_RX_OFFLOAD_IPV4_CKSUM | + DEV_RX_OFFLOAD_UDP_CKSUM | + DEV_RX_OFFLOAD_TCP_CKSUM; + dev_info->tx_offload_capa = DEV_TX_OFFLOAD_VLAN_INSERT | + DEV_TX_OFFLOAD_IPV4_CKSUM | + DEV_TX_OFFLOAD_UDP_CKSUM | + DEV_TX_OFFLOAD_TCP_CKSUM | + DEV_TX_OFFLOAD_SCTP_CKSUM; + switch (hw->mac.type) { case e1000_vfadapt: dev_info->max_rx_queues = 2; dev_info->max_tx_queues = 2; - dev_info->max_vmdq_pools = 0; break; - case e1000_vfadapt_i350: dev_info->max_rx_queues = 1; dev_info->max_tx_queues = 1; - dev_info->max_vmdq_pools = 0; break; - default: /* Should not happen */ - dev_info->max_rx_queues = 0; - dev_info->max_tx_queues = 0; - dev_info->max_vmdq_pools = 0; + break; } dev_info->default_rxconf = (struct rte_eth_rxconf) { @@ -2048,7 +2098,7 @@ igbvf_stop_adapter(struct rte_eth_dev *dev) struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); memset(&dev_info, 0, sizeof(dev_info)); - eth_igb_infos_get(dev, &dev_info); + eth_igbvf_infos_get(dev, &dev_info); /* Clear interrupt mask to stop from interrupts being generated */ igbvf_intr_disable(hw); @@ -2261,38 +2311,40 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) static int eth_igb_rss_reta_update(struct rte_eth_dev *dev, - struct rte_eth_rss_reta *reta_conf) + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size) { - uint8_t i,j,mask; - uint32_t reta; - struct e1000_hw *hw = - E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint8_t i, j, mask; + uint32_t reta, r; + uint16_t idx, shift; + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - /* - * Update Redirection Table RETA[n],n=0...31,The redirection table has - * 128-entries in 32 registers - */ - for(i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) { - if (i < ETH_RSS_RETA_NUM_ENTRIES/2) - mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF); + if (reta_size != ETH_RSS_RETA_SIZE_128) { + PMD_DRV_LOG(ERR, "The size of hash lookup table configured " + "(%d) doesn't match the number hardware can supported " + "(%d)\n", reta_size, ETH_RSS_RETA_SIZE_128); + return -EINVAL; + } + + for (i = 0; i < reta_size; i += IGB_4_BIT_WIDTH) { + idx = i / RTE_RETA_GROUP_SIZE; + shift = i % RTE_RETA_GROUP_SIZE; + mask = (uint8_t)((reta_conf[idx].mask >> shift) & + IGB_4_BIT_MASK); + if (!mask) + continue; + if (mask == IGB_4_BIT_MASK) + r = 0; else - mask = (uint8_t)((reta_conf->mask_hi >> - (i - ETH_RSS_RETA_NUM_ENTRIES/2)) & 0xF); - if (mask != 0) { - reta = 0; - /* If all 4 entries were set,don't need read RETA register */ - if (mask != 0xF) - reta = E1000_READ_REG(hw,E1000_RETA(i >> 2)); - - for (j = 0; j < 4; j++) { - if (mask & (0x1 << j)) { - if (mask != 0xF) - reta &= ~(0xFF << 8 * j); - reta |= reta_conf->reta[i + j] << 8 * j; - } - } - E1000_WRITE_REG(hw, E1000_RETA(i >> 2),reta); + r = E1000_READ_REG(hw, E1000_RETA(i >> 2)); + for (j = 0, reta = 0; j < IGB_4_BIT_WIDTH; j++) { + if (mask & (0x1 << j)) + reta |= reta_conf[idx].reta[shift + j] << + (CHAR_BIT * j); + else + reta |= r & (IGB_8_BIT_MASK << (CHAR_BIT * j)); } + E1000_WRITE_REG(hw, E1000_RETA(i >> 2), reta); } return 0; @@ -2300,31 +2352,34 @@ eth_igb_rss_reta_update(struct rte_eth_dev *dev, static int eth_igb_rss_reta_query(struct rte_eth_dev *dev, - struct rte_eth_rss_reta *reta_conf) + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size) { - uint8_t i,j,mask; + uint8_t i, j, mask; uint32_t reta; - struct e1000_hw *hw = - E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint16_t idx, shift; + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - /* - * Read Redirection Table RETA[n],n=0...31,The redirection table has - * 128-entries in 32 registers - */ - for(i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) { - if (i < ETH_RSS_RETA_NUM_ENTRIES/2) - mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF); - else - mask = (uint8_t)((reta_conf->mask_hi >> - (i - ETH_RSS_RETA_NUM_ENTRIES/2)) & 0xF); - - if (mask != 0) { - reta = E1000_READ_REG(hw,E1000_RETA(i >> 2)); - for (j = 0; j < 4; j++) { - if (mask & (0x1 << j)) - reta_conf->reta[i + j] = - (uint8_t)((reta >> 8 * j) & 0xFF); - } + if (reta_size != ETH_RSS_RETA_SIZE_128) { + PMD_DRV_LOG(ERR, "The size of hash lookup table configured " + "(%d) doesn't match the number hardware can supported " + "(%d)\n", reta_size, ETH_RSS_RETA_SIZE_128); + return -EINVAL; + } + + for (i = 0; i < reta_size; i += IGB_4_BIT_WIDTH) { + idx = i / RTE_RETA_GROUP_SIZE; + shift = i % RTE_RETA_GROUP_SIZE; + mask = (uint8_t)((reta_conf[idx].mask >> shift) & + IGB_4_BIT_MASK); + if (!mask) + continue; + reta = E1000_READ_REG(hw, E1000_RETA(i >> 2)); + for (j = 0; j < IGB_4_BIT_WIDTH; j++) { + if (mask & (0x1 << j)) + reta_conf[idx].reta[shift + j] = + ((reta >> (CHAR_BIT * j)) & + IGB_8_BIT_MASK); } } @@ -2334,7 +2389,7 @@ eth_igb_rss_reta_query(struct rte_eth_dev *dev, #define MAC_TYPE_FILTER_SUP(type) do {\ if ((type) != e1000_82580 && (type) != e1000_i350 &&\ (type) != e1000_82576)\ - return -ENOSYS;\ + return -ENOTSUP;\ } while (0) /* @@ -2431,111 +2486,6 @@ eth_igb_get_syn_filter(struct rte_eth_dev *dev, return -ENOENT; } -/* - * add an ethertype filter - * - * @param - * dev: Pointer to struct rte_eth_dev. - * index: the index the filter allocates. - * filter: ponter to the filter that will be added. - * rx_queue: the queue id the filter assigned to. - * - * @return - * - On success, zero. - * - On failure, a negative value. - */ -static int -eth_igb_add_ethertype_filter(struct rte_eth_dev *dev, uint16_t index, - struct rte_ethertype_filter *filter, uint16_t rx_queue) -{ - struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t etqf; - - MAC_TYPE_FILTER_SUP(hw->mac.type); - - if (index >= E1000_MAX_ETQF_FILTERS || rx_queue >= IGB_MAX_RX_QUEUE_NUM) - return -EINVAL; - - etqf = E1000_READ_REG(hw, E1000_ETQF(index)); - if (etqf & E1000_ETQF_FILTER_ENABLE) - return -EINVAL; /* filter index is in use. */ - else - etqf = 0; - - etqf |= E1000_ETQF_FILTER_ENABLE | E1000_ETQF_QUEUE_ENABLE; - etqf |= (uint32_t)(filter->ethertype & E1000_ETQF_ETHERTYPE); - etqf |= rx_queue << E1000_ETQF_QUEUE_SHIFT; - - if (filter->priority_en) { - PMD_INIT_LOG(ERR, "vlan and priority (%d) is not supported" - " in E1000.", filter->priority); - return -EINVAL; - } - - E1000_WRITE_REG(hw, E1000_ETQF(index), etqf); - return 0; -} - -/* - * remove an ethertype filter - * - * @param - * dev: Pointer to struct rte_eth_dev. - * index: the index the filter allocates. - * - * @return - * - On success, zero. - * - On failure, a negative value. - */ -static int -eth_igb_remove_ethertype_filter(struct rte_eth_dev *dev, uint16_t index) -{ - struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - - MAC_TYPE_FILTER_SUP(hw->mac.type); - - if (index >= E1000_MAX_ETQF_FILTERS) - return -EINVAL; - - E1000_WRITE_REG(hw, E1000_ETQF(index), 0); - return 0; -} - -/* - * get an ethertype filter - * - * @param - * dev: Pointer to struct rte_eth_dev. - * index: the index the filter allocates. - * filter: ponter to the filter that will be gotten. - * *rx_queue: the ponited of the queue id the filter assigned to. - * - * @return - * - On success, zero. - * - On failure, a negative value. - */ -static int -eth_igb_get_ethertype_filter(struct rte_eth_dev *dev, uint16_t index, - struct rte_ethertype_filter *filter, uint16_t *rx_queue) -{ - struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t etqf; - - MAC_TYPE_FILTER_SUP(hw->mac.type); - - if (index >= E1000_MAX_ETQF_FILTERS) - return -EINVAL; - - etqf = E1000_READ_REG(hw, E1000_ETQF(index)); - if (etqf & E1000_ETQF_FILTER_ENABLE) { - filter->ethertype = etqf & E1000_ETQF_ETHERTYPE; - filter->priority_en = 0; - *rx_queue = (etqf & E1000_ETQF_QUEUE) >> E1000_ETQF_QUEUE_SHIFT; - return 0; - } - return -ENOENT; -} - #define MAC_TYPE_FILTER_SUP_EXT(type) do {\ if ((type) != e1000_82580 && (type) != e1000_i350)\ return -ENOSYS; \ @@ -3095,6 +3045,207 @@ eth_igb_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) return 0; } +static inline int +igb_ethertype_filter_lookup(struct e1000_filter_info *filter_info, + uint16_t ethertype) +{ + int i; + + for (i = 0; i < E1000_MAX_ETQF_FILTERS; i++) { + if (filter_info->ethertype_filters[i] == ethertype && + (filter_info->ethertype_mask & (1 << i))) + return i; + } + return -1; +} + +static inline int +igb_ethertype_filter_insert(struct e1000_filter_info *filter_info, + uint16_t ethertype) +{ + int i; + + for (i = 0; i < E1000_MAX_ETQF_FILTERS; i++) { + if (!(filter_info->ethertype_mask & (1 << i))) { + filter_info->ethertype_mask |= 1 << i; + filter_info->ethertype_filters[i] = ethertype; + return i; + } + } + return -1; +} + +static inline int +igb_ethertype_filter_remove(struct e1000_filter_info *filter_info, + uint8_t idx) +{ + if (idx >= E1000_MAX_ETQF_FILTERS) + return -1; + filter_info->ethertype_mask &= ~(1 << idx); + filter_info->ethertype_filters[idx] = 0; + return idx; +} + + +static int +igb_add_del_ethertype_filter(struct rte_eth_dev *dev, + struct rte_eth_ethertype_filter *filter, + bool add) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private); + uint32_t etqf = 0; + int ret; + + if (filter->ether_type == ETHER_TYPE_IPv4 || + filter->ether_type == ETHER_TYPE_IPv6) { + PMD_DRV_LOG(ERR, "unsupported ether_type(0x%04x) in" + " ethertype filter.", filter->ether_type); + return -EINVAL; + } + + if (filter->flags & RTE_ETHTYPE_FLAGS_MAC) { + PMD_DRV_LOG(ERR, "mac compare is unsupported."); + return -EINVAL; + } + if (filter->flags & RTE_ETHTYPE_FLAGS_DROP) { + PMD_DRV_LOG(ERR, "drop option is unsupported."); + return -EINVAL; + } + + ret = igb_ethertype_filter_lookup(filter_info, filter->ether_type); + if (ret >= 0 && add) { + PMD_DRV_LOG(ERR, "ethertype (0x%04x) filter exists.", + filter->ether_type); + return -EEXIST; + } + if (ret < 0 && !add) { + PMD_DRV_LOG(ERR, "ethertype (0x%04x) filter doesn't exist.", + filter->ether_type); + return -ENOENT; + } + + if (add) { + ret = igb_ethertype_filter_insert(filter_info, + filter->ether_type); + if (ret < 0) { + PMD_DRV_LOG(ERR, "ethertype filters are full."); + return -ENOSYS; + } + + etqf |= E1000_ETQF_FILTER_ENABLE | E1000_ETQF_QUEUE_ENABLE; + etqf |= (uint32_t)(filter->ether_type & E1000_ETQF_ETHERTYPE); + etqf |= filter->queue << E1000_ETQF_QUEUE_SHIFT; + } else { + ret = igb_ethertype_filter_remove(filter_info, (uint8_t)ret); + if (ret < 0) + return -ENOSYS; + } + E1000_WRITE_REG(hw, E1000_ETQF(ret), etqf); + E1000_WRITE_FLUSH(hw); + + return 0; +} + +static int +igb_get_ethertype_filter(struct rte_eth_dev *dev, + struct rte_eth_ethertype_filter *filter) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_filter_info *filter_info = + E1000_DEV_PRIVATE_TO_FILTER_INFO(dev->data->dev_private); + uint32_t etqf; + int ret; + + ret = igb_ethertype_filter_lookup(filter_info, filter->ether_type); + if (ret < 0) { + PMD_DRV_LOG(ERR, "ethertype (0x%04x) filter doesn't exist.", + filter->ether_type); + return -ENOENT; + } + + etqf = E1000_READ_REG(hw, E1000_ETQF(ret)); + if (etqf & E1000_ETQF_FILTER_ENABLE) { + filter->ether_type = etqf & E1000_ETQF_ETHERTYPE; + filter->flags = 0; + filter->queue = (etqf & E1000_ETQF_QUEUE) >> + E1000_ETQF_QUEUE_SHIFT; + return 0; + } + + return -ENOENT; +} + +/* + * igb_ethertype_filter_handle - Handle operations for ethertype filter. + * @dev: pointer to rte_eth_dev structure + * @filter_op:operation will be taken. + * @arg: a pointer to specific structure corresponding to the filter_op + */ +static int +igb_ethertype_filter_handle(struct rte_eth_dev *dev, + enum rte_filter_op filter_op, + void *arg) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int ret; + + MAC_TYPE_FILTER_SUP(hw->mac.type); + + if (filter_op == RTE_ETH_FILTER_NOP) + return 0; + + if (arg == NULL) { + PMD_DRV_LOG(ERR, "arg shouldn't be NULL for operation %u.", + filter_op); + return -EINVAL; + } + + switch (filter_op) { + case RTE_ETH_FILTER_ADD: + ret = igb_add_del_ethertype_filter(dev, + (struct rte_eth_ethertype_filter *)arg, + TRUE); + break; + case RTE_ETH_FILTER_DELETE: + ret = igb_add_del_ethertype_filter(dev, + (struct rte_eth_ethertype_filter *)arg, + FALSE); + break; + case RTE_ETH_FILTER_GET: + ret = igb_get_ethertype_filter(dev, + (struct rte_eth_ethertype_filter *)arg); + break; + default: + PMD_DRV_LOG(ERR, "unsupported operation %u.", filter_op); + ret = -EINVAL; + break; + } + return ret; +} + +static int +eth_igb_filter_ctrl(struct rte_eth_dev *dev, + enum rte_filter_type filter_type, + enum rte_filter_op filter_op, + void *arg) +{ + int ret = -EINVAL; + + switch (filter_type) { + case RTE_ETH_FILTER_ETHERTYPE: + ret = igb_ethertype_filter_handle(dev, filter_op, arg); + break; + default: + PMD_DRV_LOG(WARNING, "Filter type (%d) not supported", + filter_type); + break; + } + + return ret; +} + static struct rte_driver pmd_igb_drv = { .type = PMD_PDEV, .init = rte_igb_pmd_init,