X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fi40e%2Fi40e_fdir.c;h=84c0a1f5eb561d32b0b795cec9a628c5154d6780;hb=0e7ba7326f2d8f8e8a6286bbd96e0a361455448b;hp=7b1aa6ec3356ed26d246782ea194cfb05471ee7d;hpb=13834ea7c0d8df12ed7fe43f06875d217adbc8df;p=dpdk.git diff --git a/drivers/net/i40e/i40e_fdir.c b/drivers/net/i40e/i40e_fdir.c index 7b1aa6ec33..84c0a1f5eb 100644 --- a/drivers/net/i40e/i40e_fdir.c +++ b/drivers/net/i40e/i40e_fdir.c @@ -52,6 +52,7 @@ #include "i40e_logs.h" #include "base/i40e_type.h" +#include "base/i40e_prototype.h" #include "i40e_ethdev.h" #include "i40e_rxtx.h" @@ -65,14 +66,14 @@ #define I40E_FDIR_IP_DEFAULT_TTL 0x40 #define I40E_FDIR_IP_DEFAULT_VERSION_IHL 0x45 #define I40E_FDIR_TCP_DEFAULT_DATAOFF 0x50 -#define I40E_FDIR_IPv6_DEFAULT_VTC_FLOW 0x60300000 +#define I40E_FDIR_IPv6_DEFAULT_VTC_FLOW 0x60000000 + #define I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS 0xFF #define I40E_FDIR_IPv6_PAYLOAD_LEN 380 #define I40E_FDIR_UDP_DEFAULT_LEN 400 -/* Wait count and interval for fdir filter programming */ -#define I40E_FDIR_WAIT_COUNT 10 -#define I40E_FDIR_WAIT_INTERVAL_US 1000 +/* Wait time for fdir filter programming */ +#define I40E_FDIR_MAX_WAIT_US 10000 /* Wait count and interval for fdir filter flush */ #define I40E_FDIR_FLUSH_RETRY 50 @@ -81,19 +82,6 @@ #define I40E_COUNTER_PF 2 /* Statistic counter index for one pf */ #define I40E_COUNTER_INDEX_FDIR(pf_id) (0 + (pf_id) * I40E_COUNTER_PF) -#define I40E_MAX_FLX_SOURCE_OFF 480 -#define I40E_FLX_OFFSET_IN_FIELD_VECTOR 50 - -#define NONUSE_FLX_PIT_DEST_OFF 63 -#define NONUSE_FLX_PIT_FSIZE 1 -#define MK_FLX_PIT(src_offset, fsize, dst_offset) ( \ - (((src_offset) << I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT) & \ - I40E_PRTQF_FLX_PIT_SOURCE_OFF_MASK) | \ - (((fsize) << I40E_PRTQF_FLX_PIT_FSIZE_SHIFT) & \ - I40E_PRTQF_FLX_PIT_FSIZE_MASK) | \ - ((((dst_offset) + I40E_FLX_OFFSET_IN_FIELD_VECTOR) << \ - I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT) & \ - I40E_PRTQF_FLX_PIT_DEST_OFF_MASK)) #define I40E_FDIR_FLOWS ( \ (1 << RTE_ETH_FLOW_FRAG_IPV4) | \ @@ -108,31 +96,17 @@ (1 << RTE_ETH_FLOW_NONFRAG_IPV6_OTHER) | \ (1 << RTE_ETH_FLOW_L2_PAYLOAD)) -#define I40E_FLEX_WORD_MASK(off) (0x80 >> (off)) - -static int i40e_fdir_rx_queue_init(struct i40e_rx_queue *rxq); -static int i40e_check_fdir_flex_conf( - const struct rte_eth_fdir_flex_conf *conf); -static void i40e_set_flx_pld_cfg(struct i40e_pf *pf, - const struct rte_eth_flex_payload_cfg *cfg); -static void i40e_set_flex_mask_on_pctype(struct i40e_pf *pf, - enum i40e_filter_pctype pctype, - const struct rte_eth_fdir_flex_mask *mask_cfg); -static int i40e_fdir_construct_pkt(struct i40e_pf *pf, - const struct rte_eth_fdir_input *fdir_input, - unsigned char *raw_pkt); -static int i40e_add_del_fdir_filter(struct rte_eth_dev *dev, - const struct rte_eth_fdir_filter *filter, - bool add); static int i40e_fdir_filter_programming(struct i40e_pf *pf, enum i40e_filter_pctype pctype, const struct rte_eth_fdir_filter *filter, bool add); -static int i40e_fdir_flush(struct rte_eth_dev *dev); -static void i40e_fdir_info_get(struct rte_eth_dev *dev, - struct rte_eth_fdir_info *fdir); -static void i40e_fdir_stats_get(struct rte_eth_dev *dev, - struct rte_eth_fdir_stats *stat); +static int i40e_fdir_filter_convert(const struct rte_eth_fdir_filter *input, + struct i40e_fdir_filter *filter); +static struct i40e_fdir_filter * +i40e_sw_fdir_filter_lookup(struct i40e_fdir_info *fdir_info, + const struct rte_eth_fdir_input *input); +static int i40e_sw_fdir_filter_insert(struct i40e_pf *pf, + struct i40e_fdir_filter *filter); static int i40e_fdir_rx_queue_init(struct i40e_rx_queue *rxq) @@ -160,7 +134,7 @@ i40e_fdir_rx_queue_init(struct i40e_rx_queue *rxq) rx_ctx.lrxqthresh = 2; rx_ctx.crcstrip = 0; rx_ctx.l2tsel = 1; - rx_ctx.showiv = 1; + rx_ctx.showiv = 0; rx_ctx.prefena = 1; err = i40e_clear_lan_rx_queue_context(hw, rxq->reg_idx); @@ -264,7 +238,7 @@ i40e_fdir_setup(struct i40e_pf *pf) /* reserve memory for the fdir programming packet */ snprintf(z_name, sizeof(z_name), "%s_%s_%d", - eth_dev->driver->pci_drv.name, + 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); @@ -275,11 +249,8 @@ i40e_fdir_setup(struct i40e_pf *pf) goto fail_mem; } pf->fdir.prg_pkt = mz->addr; -#ifdef RTE_LIBRTE_XEN_DOM0 pf->fdir.dma_addr = rte_mem_phy2mch(mz->memseg_id, mz->phys_addr); -#else - pf->fdir.dma_addr = (uint64_t)mz->phys_addr; -#endif + pf->fdir.match_counter_index = I40E_COUNTER_INDEX_FDIR(hw->pf_id); PMD_DRV_LOG(INFO, "FDIR setup successfully, with programming queue %u.", vsi->base_queue); @@ -310,8 +281,12 @@ i40e_fdir_teardown(struct i40e_pf *pf) vsi = pf->fdir.fdir_vsi; if (!vsi) return; - i40e_switch_tx_queue(hw, vsi->base_queue, FALSE); - i40e_switch_rx_queue(hw, vsi->base_queue, FALSE); + 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); pf->fdir.rxq = NULL; i40e_dev_tx_queue_release(pf->fdir.txq); @@ -369,20 +344,25 @@ i40e_init_flx_pld(struct i40e_pf *pf) /* initialize the masks */ for (pctype = I40E_FILTER_PCTYPE_NONF_IPV4_UDP; pctype <= I40E_FILTER_PCTYPE_L2_PAYLOAD; pctype++) { - if (!I40E_VALID_PCTYPE((enum i40e_filter_pctype)pctype)) - continue; + if (hw->mac.type == I40E_MAC_X722) { + if (!I40E_VALID_PCTYPE_X722( + (enum i40e_filter_pctype)pctype)) + continue; + } else { + if (!I40E_VALID_PCTYPE( + (enum i40e_filter_pctype)pctype)) + continue; + } pf->fdir.flex_mask[pctype].word_mask = 0; - I40E_WRITE_REG(hw, I40E_PRTQF_FD_FLXINSET(pctype), 0); + i40e_write_rx_ctl(hw, I40E_PRTQF_FD_FLXINSET(pctype), 0); for (i = 0; i < I40E_FDIR_BITMASK_NUM_WORD; i++) { pf->fdir.flex_mask[pctype].bitmask[i].offset = 0; pf->fdir.flex_mask[pctype].bitmask[i].mask = 0; - I40E_WRITE_REG(hw, I40E_PRTQF_FD_MSK(pctype, i), 0); + i40e_write_rx_ctl(hw, I40E_PRTQF_FD_MSK(pctype, i), 0); } } } -#define I40E_WORD(hi, lo) (uint16_t)((((hi) << 8) & 0xFF00) | ((lo) & 0xFF)) - #define I40E_VALIDATE_FLEX_PIT(flex_pit1, flex_pit2) do { \ if ((flex_pit2).src_offset < \ (flex_pit1).src_offset + (flex_pit1).size) { \ @@ -621,7 +601,7 @@ i40e_set_flex_mask_on_pctype(struct i40e_pf *pf, flxinset = (flex_mask->word_mask << I40E_PRTQF_FD_FLXINSET_INSET_SHIFT) & I40E_PRTQF_FD_FLXINSET_INSET_MASK; - I40E_WRITE_REG(hw, I40E_PRTQF_FD_FLXINSET(pctype), flxinset); + i40e_write_rx_ctl(hw, I40E_PRTQF_FD_FLXINSET(pctype), flxinset); for (i = 0; i < nb_bitmask; i++) { fd_mask = (flex_mask->bitmask[i].mask << @@ -631,7 +611,7 @@ i40e_set_flex_mask_on_pctype(struct i40e_pf *pf, I40E_FLX_OFFSET_IN_FIELD_VECTOR) << I40E_PRTQF_FD_MSK_OFFSET_SHIFT) & I40E_PRTQF_FD_MSK_OFFSET_MASK; - I40E_WRITE_REG(hw, I40E_PRTQF_FD_MSK(pctype, i), fd_mask); + i40e_write_rx_ctl(hw, I40E_PRTQF_FD_MSK(pctype, i), fd_mask); } } @@ -663,9 +643,9 @@ i40e_fdir_configure(struct rte_eth_dev *dev) } /* enable FDIR filter */ - val = I40E_READ_REG(hw, I40E_PFQF_CTL_0); + val = i40e_read_rx_ctl(hw, I40E_PFQF_CTL_0); val |= I40E_PFQF_CTL_0_FD_ENA_MASK; - I40E_WRITE_REG(hw, I40E_PFQF_CTL_0, val); + i40e_write_rx_ctl(hw, I40E_PFQF_CTL_0, val); i40e_init_flx_pld(pf); /* set flex config to default value */ @@ -680,18 +660,30 @@ i40e_fdir_configure(struct rte_eth_dev *dev) i40e_set_flx_pld_cfg(pf, &conf->flex_set[i]); /* configure flex mask*/ for (i = 0; i < conf->nb_flexmasks; i++) { - pctype = i40e_flowtype_to_pctype(conf->flex_mask[i].flow_type); + if (hw->mac.type == I40E_MAC_X722) { + /* get translated pctype value in fd pctype register */ + pctype = (enum i40e_filter_pctype)i40e_read_rx_ctl( + hw, I40E_GLQF_FD_PCTYPES( + (int)i40e_flowtype_to_pctype( + conf->flex_mask[i].flow_type))); + } else + pctype = i40e_flowtype_to_pctype( + conf->flex_mask[i].flow_type); + i40e_set_flex_mask_on_pctype(pf, pctype, &conf->flex_mask[i]); } return ret; } -static inline void +static inline int i40e_fdir_fill_eth_ip_head(const struct rte_eth_fdir_input *fdir_input, - unsigned char *raw_pkt) + unsigned char *raw_pkt, + bool vlan) { - struct ether_hdr *ether = (struct ether_hdr *)raw_pkt; + static uint8_t vlan_frame[] = {0x81, 0, 0, 0}; + uint16_t *ether_type; + uint8_t len = 2 * sizeof(struct ether_addr); struct ipv4_hdr *ip; struct ipv6_hdr *ip6; static const uint8_t next_proto[] = { @@ -707,22 +699,41 @@ i40e_fdir_fill_eth_ip_head(const struct rte_eth_fdir_input *fdir_input, [RTE_ETH_FLOW_NONFRAG_IPV6_OTHER] = IPPROTO_NONE, }; + raw_pkt += 2 * sizeof(struct ether_addr); + if (vlan && fdir_input->flow_ext.vlan_tci) { + rte_memcpy(raw_pkt, vlan_frame, sizeof(vlan_frame)); + rte_memcpy(raw_pkt + sizeof(uint16_t), + &fdir_input->flow_ext.vlan_tci, + sizeof(uint16_t)); + raw_pkt += sizeof(vlan_frame); + len += sizeof(vlan_frame); + } + ether_type = (uint16_t *)raw_pkt; + raw_pkt += sizeof(uint16_t); + len += sizeof(uint16_t); + switch (fdir_input->flow_type) { case RTE_ETH_FLOW_L2_PAYLOAD: - ether->ether_type = fdir_input->flow.l2_flow.ether_type; + *ether_type = fdir_input->flow.l2_flow.ether_type; break; case RTE_ETH_FLOW_NONFRAG_IPV4_TCP: case RTE_ETH_FLOW_NONFRAG_IPV4_UDP: case RTE_ETH_FLOW_NONFRAG_IPV4_SCTP: case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER: case RTE_ETH_FLOW_FRAG_IPV4: - ip = (struct ipv4_hdr *)(raw_pkt + sizeof(struct ether_hdr)); + ip = (struct ipv4_hdr *)raw_pkt; - ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4); + *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4); ip->version_ihl = I40E_FDIR_IP_DEFAULT_VERSION_IHL; /* set len to by default */ ip->total_length = rte_cpu_to_be_16(I40E_FDIR_IP_DEFAULT_LEN); - ip->time_to_live = I40E_FDIR_IP_DEFAULT_TTL; + ip->next_proto_id = fdir_input->flow.ip4_flow.proto ? + fdir_input->flow.ip4_flow.proto : + next_proto[fdir_input->flow_type]; + ip->time_to_live = fdir_input->flow.ip4_flow.ttl ? + fdir_input->flow.ip4_flow.ttl : + I40E_FDIR_IP_DEFAULT_TTL; + ip->type_of_service = fdir_input->flow.ip4_flow.tos; /* * The source and destination fields in the transmitted packet * need to be presented in a reversed order with respect @@ -730,22 +741,28 @@ i40e_fdir_fill_eth_ip_head(const struct rte_eth_fdir_input *fdir_input, */ ip->src_addr = fdir_input->flow.ip4_flow.dst_ip; ip->dst_addr = fdir_input->flow.ip4_flow.src_ip; - ip->next_proto_id = next_proto[fdir_input->flow_type]; + len += sizeof(struct ipv4_hdr); break; case RTE_ETH_FLOW_NONFRAG_IPV6_TCP: case RTE_ETH_FLOW_NONFRAG_IPV6_UDP: case RTE_ETH_FLOW_NONFRAG_IPV6_SCTP: case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER: case RTE_ETH_FLOW_FRAG_IPV6: - ip6 = (struct ipv6_hdr *)(raw_pkt + sizeof(struct ether_hdr)); + ip6 = (struct ipv6_hdr *)raw_pkt; - ether->ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6); + *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6); ip6->vtc_flow = - rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW); + rte_cpu_to_be_32(I40E_FDIR_IPv6_DEFAULT_VTC_FLOW | + (fdir_input->flow.ipv6_flow.tc << + I40E_FDIR_IPv6_TC_OFFSET)); ip6->payload_len = rte_cpu_to_be_16(I40E_FDIR_IPv6_PAYLOAD_LEN); - ip6->hop_limits = I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS; - + ip6->proto = fdir_input->flow.ipv6_flow.proto ? + fdir_input->flow.ipv6_flow.proto : + next_proto[fdir_input->flow_type]; + ip6->hop_limits = fdir_input->flow.ipv6_flow.hop_limits ? + fdir_input->flow.ipv6_flow.hop_limits : + I40E_FDIR_IPv6_DEFAULT_HOP_LIMITS; /* * The source and destination fields in the transmitted packet * need to be presented in a reversed order with respect @@ -757,13 +774,14 @@ i40e_fdir_fill_eth_ip_head(const struct rte_eth_fdir_input *fdir_input, rte_memcpy(&(ip6->dst_addr), &(fdir_input->flow.ipv6_flow.src_ip), IPV6_ADDR_LEN); - ip6->proto = next_proto[fdir_input->flow_type]; + len += sizeof(struct ipv6_hdr); break; default: PMD_DRV_LOG(ERR, "unknown flow type %u.", fdir_input->flow_type); - break; + return -1; } + return len; } @@ -784,15 +802,18 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf, struct sctp_hdr *sctp; uint8_t size, dst = 0; uint8_t i, pit_idx, set_idx = I40E_FLXPLD_L4_IDX; /* use l4 by default*/ + int len; /* fill the ethernet and IP head */ - i40e_fdir_fill_eth_ip_head(fdir_input, raw_pkt); + len = i40e_fdir_fill_eth_ip_head(fdir_input, raw_pkt, + !!fdir_input->flow_ext.vlan_tci); + if (len < 0) + return -EINVAL; /* fill the L4 head */ switch (fdir_input->flow_type) { case RTE_ETH_FLOW_NONFRAG_IPV4_UDP: - udp = (struct udp_hdr *)(raw_pkt + sizeof(struct ether_hdr) + - sizeof(struct ipv4_hdr)); + udp = (struct udp_hdr *)(raw_pkt + len); payload = (unsigned char *)udp + sizeof(struct udp_hdr); /* * The source and destination fields in the transmitted packet @@ -805,8 +826,7 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf, break; case RTE_ETH_FLOW_NONFRAG_IPV4_TCP: - tcp = (struct tcp_hdr *)(raw_pkt + sizeof(struct ether_hdr) + - sizeof(struct ipv4_hdr)); + tcp = (struct tcp_hdr *)(raw_pkt + len); payload = (unsigned char *)tcp + sizeof(struct tcp_hdr); /* * The source and destination fields in the transmitted packet @@ -819,8 +839,7 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf, break; case RTE_ETH_FLOW_NONFRAG_IPV4_SCTP: - sctp = (struct sctp_hdr *)(raw_pkt + sizeof(struct ether_hdr) + - sizeof(struct ipv4_hdr)); + sctp = (struct sctp_hdr *)(raw_pkt + len); payload = (unsigned char *)sctp + sizeof(struct sctp_hdr); /* * The source and destination fields in the transmitted packet @@ -834,14 +853,12 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf, case RTE_ETH_FLOW_NONFRAG_IPV4_OTHER: case RTE_ETH_FLOW_FRAG_IPV4: - payload = raw_pkt + sizeof(struct ether_hdr) + - sizeof(struct ipv4_hdr); + payload = raw_pkt + len; set_idx = I40E_FLXPLD_L3_IDX; break; case RTE_ETH_FLOW_NONFRAG_IPV6_UDP: - udp = (struct udp_hdr *)(raw_pkt + sizeof(struct ether_hdr) + - sizeof(struct ipv6_hdr)); + udp = (struct udp_hdr *)(raw_pkt + len); payload = (unsigned char *)udp + sizeof(struct udp_hdr); /* * The source and destination fields in the transmitted packet @@ -854,8 +871,7 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf, break; case RTE_ETH_FLOW_NONFRAG_IPV6_TCP: - tcp = (struct tcp_hdr *)(raw_pkt + sizeof(struct ether_hdr) + - sizeof(struct ipv6_hdr)); + tcp = (struct tcp_hdr *)(raw_pkt + len); payload = (unsigned char *)tcp + sizeof(struct tcp_hdr); /* * The source and destination fields in the transmitted packet @@ -868,8 +884,7 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf, break; case RTE_ETH_FLOW_NONFRAG_IPV6_SCTP: - sctp = (struct sctp_hdr *)(raw_pkt + sizeof(struct ether_hdr) + - sizeof(struct ipv6_hdr)); + sctp = (struct sctp_hdr *)(raw_pkt + len); payload = (unsigned char *)sctp + sizeof(struct sctp_hdr); /* * The source and destination fields in the transmitted packet @@ -883,12 +898,11 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf, case RTE_ETH_FLOW_NONFRAG_IPV6_OTHER: case RTE_ETH_FLOW_FRAG_IPV6: - payload = raw_pkt + sizeof(struct ether_hdr) + - sizeof(struct ipv6_hdr); + payload = raw_pkt + len; set_idx = I40E_FLXPLD_L3_IDX; break; case RTE_ETH_FLOW_L2_PAYLOAD: - payload = raw_pkt + sizeof(struct ether_hdr); + payload = raw_pkt + len; /* * ARP packet is a special case on which the payload * starts after the whole ARP header @@ -912,7 +926,7 @@ i40e_fdir_construct_pkt(struct i40e_pf *pf, dst = pf->fdir.flex_set[pit_idx].dst_offset * sizeof(uint16_t); ptr = payload + pf->fdir.flex_set[pit_idx].src_offset * sizeof(uint16_t); - (void)rte_memcpy(ptr, + rte_memcpy(ptr, &fdir_input->flow_ext.flexbytes[dst], size * sizeof(uint16_t)); } @@ -992,20 +1006,92 @@ i40e_check_fdir_programming_status(struct i40e_rx_queue *rxq) return ret; } +static int +i40e_fdir_filter_convert(const struct rte_eth_fdir_filter *input, + struct i40e_fdir_filter *filter) +{ + rte_memcpy(&filter->fdir, input, sizeof(struct rte_eth_fdir_filter)); + return 0; +} + +/* Check if there exists the flow director filter */ +static struct i40e_fdir_filter * +i40e_sw_fdir_filter_lookup(struct i40e_fdir_info *fdir_info, + const struct rte_eth_fdir_input *input) +{ + int ret; + + ret = rte_hash_lookup(fdir_info->hash_table, (const void *)input); + if (ret < 0) + return NULL; + + return fdir_info->hash_map[ret]; +} + +/* Add a flow director filter into the SW list */ +static int +i40e_sw_fdir_filter_insert(struct i40e_pf *pf, struct i40e_fdir_filter *filter) +{ + struct i40e_fdir_info *fdir_info = &pf->fdir; + int ret; + + ret = rte_hash_add_key(fdir_info->hash_table, + &filter->fdir.input); + if (ret < 0) { + PMD_DRV_LOG(ERR, + "Failed to insert fdir filter to hash table %d!", + ret); + return ret; + } + fdir_info->hash_map[ret] = filter; + + TAILQ_INSERT_TAIL(&fdir_info->fdir_list, filter, rules); + + return 0; +} + +/* Delete a flow director filter from the SW list */ +int +i40e_sw_fdir_filter_del(struct i40e_pf *pf, struct rte_eth_fdir_input *input) +{ + struct i40e_fdir_info *fdir_info = &pf->fdir; + struct i40e_fdir_filter *filter; + int ret; + + ret = rte_hash_del_key(fdir_info->hash_table, input); + if (ret < 0) { + PMD_DRV_LOG(ERR, + "Failed to delete fdir filter to hash table %d!", + ret); + return ret; + } + filter = fdir_info->hash_map[ret]; + fdir_info->hash_map[ret] = NULL; + + TAILQ_REMOVE(&fdir_info->fdir_list, filter, rules); + rte_free(filter); + + return 0; +} + /* * i40e_add_del_fdir_filter - add or remove a flow director filter. * @pf: board private structure * @filter: fdir filter entry * @add: 0 - delete, 1 - add */ -static int +int i40e_add_del_fdir_filter(struct rte_eth_dev *dev, const struct rte_eth_fdir_filter *filter, bool add) { + 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; enum i40e_filter_pctype pctype; + struct i40e_fdir_info *fdir_info = &pf->fdir; + struct i40e_fdir_filter *fdir_filter, *node; + struct i40e_fdir_filter check_filter; /* Check if the filter exists */ int ret = 0; if (dev->data->dev_conf.fdir_conf.mode != RTE_FDIR_MODE_PERFECT) { @@ -1028,6 +1114,22 @@ i40e_add_del_fdir_filter(struct rte_eth_dev *dev, return -EINVAL; } + /* 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; + } + memset(pkt, 0, I40E_FDIR_PKT_LEN); ret = i40e_fdir_construct_pkt(pf, &filter->input, pkt); @@ -1035,13 +1137,32 @@ i40e_add_del_fdir_filter(struct rte_eth_dev *dev, PMD_DRV_LOG(ERR, "construct packet for fdir fails."); return ret; } - pctype = i40e_flowtype_to_pctype(filter->input.flow_type); + + if (hw->mac.type == I40E_MAC_X722) { + /* get translated pctype value in fd pctype register */ + pctype = (enum i40e_filter_pctype)i40e_read_rx_ctl( + hw, I40E_GLQF_FD_PCTYPES( + (int)i40e_flowtype_to_pctype( + filter->input.flow_type))); + } else + pctype = i40e_flowtype_to_pctype(filter->input.flow_type); + ret = i40e_fdir_filter_programming(pf, pctype, filter, add); if (ret < 0) { PMD_DRV_LOG(ERR, "fdir programming fails for PCTYPE(%u).", pctype); return ret; } + + if (add) { + fdir_filter = rte_zmalloc("fdir_filter", + sizeof(*fdir_filter), 0); + rte_memcpy(fdir_filter, &check_filter, sizeof(check_filter)); + ret = i40e_sw_fdir_filter_insert(pf, fdir_filter); + } else { + ret = i40e_sw_fdir_filter_del(pf, &node->fdir.input); + } + return ret; } @@ -1052,7 +1173,7 @@ i40e_add_del_fdir_filter(struct rte_eth_dev *dev, * @pf: board private structure * @pctype: pctype * @filter: fdir filter entry - * @add: 0 - delelet, 1 - add + * @add: 0 - delete, 1 - add */ static int i40e_fdir_filter_programming(struct i40e_pf *pf, @@ -1094,7 +1215,7 @@ i40e_fdir_filter_programming(struct i40e_pf *pf, /* Use LAN VSI Id by default */ vsi_id = pf->main_vsi->vsi_id; fdirdp->qindex_flex_ptype_vsi |= - rte_cpu_to_le_32((vsi_id << + rte_cpu_to_le_32(((uint32_t)vsi_id << I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) & I40E_TXD_FLTR_QW0_DEST_VSI_MASK); @@ -1134,7 +1255,8 @@ i40e_fdir_filter_programming(struct i40e_pf *pf, fdirdp->dtype_cmd_cntindex |= rte_cpu_to_le_32(I40E_TXD_FLTR_QW1_CNT_ENA_MASK); fdirdp->dtype_cmd_cntindex |= - rte_cpu_to_le_32((pf->fdir.match_counter_index << + rte_cpu_to_le_32( + ((uint32_t)pf->fdir.match_counter_index << I40E_TXD_FLTR_QW1_CNTINDEX_SHIFT) & I40E_TXD_FLTR_QW1_CNTINDEX_MASK); @@ -1156,35 +1278,34 @@ i40e_fdir_filter_programming(struct i40e_pf *pf, /* Update the tx tail register */ rte_wmb(); I40E_PCI_REG_WRITE(txq->qtx_tail, txq->tx_tail); - - for (i = 0; i < I40E_FDIR_WAIT_COUNT; i++) { - rte_delay_us(I40E_FDIR_WAIT_INTERVAL_US); + 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_WAIT_COUNT) { + 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_WAIT_COUNT - i) * I40E_FDIR_WAIT_INTERVAL_US); - if (i40e_check_fdir_programming_status(rxq) < 0) { - PMD_DRV_LOG(ERR, "Failed to program FDIR filter:" - " programming status reported."); - return -ENOSYS; + for (; i < I40E_FDIR_MAX_WAIT_US; i++) { + if (i40e_check_fdir_programming_status(rxq) >= 0) + return 0; + rte_delay_us(1); } - - return 0; + PMD_DRV_LOG(ERR, + "Failed to program FDIR filter: programming status reported."); + return -ETIMEDOUT; } /* * i40e_fdir_flush - clear all filters of Flow Director table * @pf: board private structure */ -static int +int i40e_fdir_flush(struct rte_eth_dev *dev) { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); @@ -1263,6 +1384,7 @@ i40e_fdir_info_get_flex_mask(struct i40e_pf *pf, { struct i40e_fdir_flex_mask *mask; struct rte_eth_fdir_flex_mask *ptr = flex_mask; + struct i40e_hw *hw = I40E_PF_TO_HW(pf); uint16_t flow_type; uint8_t i, j; uint16_t off_bytes, mask_tmp; @@ -1271,8 +1393,13 @@ i40e_fdir_info_get_flex_mask(struct i40e_pf *pf, i <= I40E_FILTER_PCTYPE_L2_PAYLOAD; i++) { mask = &pf->fdir.flex_mask[i]; - if (!I40E_VALID_PCTYPE((enum i40e_filter_pctype)i)) - continue; + if (hw->mac.type == I40E_MAC_X722) { + if (!I40E_VALID_PCTYPE_X722((enum i40e_filter_pctype)i)) + continue; + } else { + if (!I40E_VALID_PCTYPE((enum i40e_filter_pctype)i)) + continue; + } flow_type = i40e_pctype_to_flowtype((enum i40e_filter_pctype)i); for (j = 0; j < I40E_FDIR_MAX_FLEXWORD_NUM; j++) { if (mask->word_mask & I40E_FLEX_WORD_MASK(j)) { @@ -1361,10 +1488,9 @@ i40e_fdir_stats_get(struct rte_eth_dev *dev, struct rte_eth_fdir_stats *stat) static int i40e_fdir_filter_set(struct rte_eth_dev *dev, - struct rte_eth_hash_filter_info *info) + struct rte_eth_fdir_filter_info *info) { struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private); - struct i40e_hw *hw = I40E_PF_TO_HW(pf); int ret = 0; if (!info) { @@ -1374,8 +1500,8 @@ i40e_fdir_filter_set(struct rte_eth_dev *dev, switch (info->info_type) { case RTE_ETH_FDIR_FILTER_INPUT_SET_SELECT: - ret = i40e_filter_inset_select(hw, - &(info->info.input_set_conf), RTE_ETH_FILTER_FDIR); + ret = i40e_fdir_filter_inset_select(pf, + &(info->info.input_set_conf)); break; default: PMD_DRV_LOG(ERR, "FD filter info type (%d) not supported", @@ -1428,7 +1554,7 @@ i40e_fdir_ctrl_func(struct rte_eth_dev *dev, break; case RTE_ETH_FILTER_SET: ret = i40e_fdir_filter_set(dev, - (struct rte_eth_hash_filter_info *)arg); + (struct rte_eth_fdir_filter_info *)arg); break; case RTE_ETH_FILTER_STATS: i40e_fdir_stats_get(dev, (struct rte_eth_fdir_stats *)arg); @@ -1440,3 +1566,30 @@ i40e_fdir_ctrl_func(struct rte_eth_dev *dev, } return ret; } + +/* Restore flow director filter */ +void +i40e_fdir_filter_restore(struct i40e_pf *pf) +{ + struct rte_eth_dev *dev = I40E_VSI_TO_ETH_DEV(pf->main_vsi); + struct i40e_fdir_filter_list *fdir_list = &pf->fdir.fdir_list; + struct i40e_fdir_filter *f; + struct i40e_hw *hw = I40E_PF_TO_HW(pf); + uint32_t fdstat; + uint32_t guarant_cnt; /**< Number of filters in guaranteed spaces. */ + uint32_t best_cnt; /**< Number of filters in best effort spaces. */ + + TAILQ_FOREACH(f, fdir_list, rules) + i40e_add_del_fdir_filter(dev, &f->fdir, TRUE); + + fdstat = I40E_READ_REG(hw, I40E_PFQF_FDSTAT); + guarant_cnt = + (uint32_t)((fdstat & I40E_PFQF_FDSTAT_GUARANT_CNT_MASK) >> + I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT); + best_cnt = + (uint32_t)((fdstat & I40E_PFQF_FDSTAT_BEST_CNT_MASK) >> + I40E_PFQF_FDSTAT_BEST_CNT_SHIFT); + + PMD_DRV_LOG(INFO, "FDIR: Guarant count: %d, Best count: %d", + guarant_cnt, best_cnt); +}