+
+/* Restore ethertype filter */
+static void
+i40e_ethertype_filter_restore(struct i40e_pf *pf)
+{
+ struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+ struct i40e_ethertype_filter_list
+ *ethertype_list = &pf->ethertype.ethertype_list;
+ struct i40e_ethertype_filter *f;
+ struct i40e_control_filter_stats stats;
+ uint16_t flags;
+
+ TAILQ_FOREACH(f, ethertype_list, rules) {
+ flags = 0;
+ if (!(f->flags & RTE_ETHTYPE_FLAGS_MAC))
+ flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_IGNORE_MAC;
+ if (f->flags & RTE_ETHTYPE_FLAGS_DROP)
+ flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_DROP;
+ flags |= I40E_AQC_ADD_CONTROL_PACKET_FLAGS_TO_QUEUE;
+
+ memset(&stats, 0, sizeof(stats));
+ i40e_aq_add_rem_control_packet_filter(hw,
+ f->input.mac_addr.addr_bytes,
+ f->input.ether_type,
+ flags, pf->main_vsi->seid,
+ f->queue, 1, &stats, NULL);
+ }
+ PMD_DRV_LOG(INFO, "Ethertype filter:"
+ " mac_etype_used = %u, etype_used = %u,"
+ " mac_etype_free = %u, etype_free = %u",
+ stats.mac_etype_used, stats.etype_used,
+ stats.mac_etype_free, stats.etype_free);
+}
+
+/* Restore tunnel filter */
+static void
+i40e_tunnel_filter_restore(struct i40e_pf *pf)
+{
+ struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+ struct i40e_vsi *vsi;
+ struct i40e_pf_vf *vf;
+ struct i40e_tunnel_filter_list
+ *tunnel_list = &pf->tunnel.tunnel_list;
+ struct i40e_tunnel_filter *f;
+ struct i40e_aqc_cloud_filters_element_bb cld_filter;
+ bool big_buffer = 0;
+
+ TAILQ_FOREACH(f, tunnel_list, rules) {
+ if (!f->is_to_vf)
+ vsi = pf->main_vsi;
+ else {
+ vf = &pf->vfs[f->vf_id];
+ vsi = vf->vsi;
+ }
+ memset(&cld_filter, 0, sizeof(cld_filter));
+ rte_ether_addr_copy((struct rte_ether_addr *)
+ &f->input.outer_mac,
+ (struct rte_ether_addr *)&cld_filter.element.outer_mac);
+ rte_ether_addr_copy((struct rte_ether_addr *)
+ &f->input.inner_mac,
+ (struct rte_ether_addr *)&cld_filter.element.inner_mac);
+ cld_filter.element.inner_vlan = f->input.inner_vlan;
+ cld_filter.element.flags = f->input.flags;
+ cld_filter.element.tenant_id = f->input.tenant_id;
+ cld_filter.element.queue_number = f->queue;
+ rte_memcpy(cld_filter.general_fields,
+ f->input.general_fields,
+ sizeof(f->input.general_fields));
+
+ if (((f->input.flags &
+ I40E_AQC_ADD_CLOUD_FILTER_0X11) ==
+ I40E_AQC_ADD_CLOUD_FILTER_0X11) ||
+ ((f->input.flags &
+ I40E_AQC_ADD_CLOUD_FILTER_0X12) ==
+ I40E_AQC_ADD_CLOUD_FILTER_0X12) ||
+ ((f->input.flags &
+ I40E_AQC_ADD_CLOUD_FILTER_0X10) ==
+ I40E_AQC_ADD_CLOUD_FILTER_0X10))
+ big_buffer = 1;
+
+ if (big_buffer)
+ i40e_aq_add_cloud_filters_bb(hw,
+ vsi->seid, &cld_filter, 1);
+ else
+ i40e_aq_add_cloud_filters(hw, vsi->seid,
+ &cld_filter.element, 1);
+ }
+}
+
+/* Restore rss filter */
+static inline void
+i40e_rss_filter_restore(struct i40e_pf *pf)
+{
+ struct i40e_rte_flow_rss_conf *conf =
+ &pf->rss_info;
+ if (conf->conf.queue_num)
+ i40e_config_rss_filter(pf, conf, TRUE);
+}
+
+static void
+i40e_filter_restore(struct i40e_pf *pf)
+{
+ i40e_ethertype_filter_restore(pf);
+ i40e_tunnel_filter_restore(pf);
+ i40e_fdir_filter_restore(pf);
+ i40e_rss_filter_restore(pf);
+}
+
+bool
+is_device_supported(struct rte_eth_dev *dev, struct rte_pci_driver *drv)
+{
+ if (strcmp(dev->device->driver->name, drv->driver.name))
+ return false;
+
+ return true;
+}
+
+bool
+is_i40e_supported(struct rte_eth_dev *dev)
+{
+ return is_device_supported(dev, &rte_i40e_pmd);
+}
+
+struct i40e_customized_pctype*
+i40e_find_customized_pctype(struct i40e_pf *pf, uint8_t index)
+{
+ int i;
+
+ for (i = 0; i < I40E_CUSTOMIZED_MAX; i++) {
+ if (pf->customized_pctype[i].index == index)
+ return &pf->customized_pctype[i];
+ }
+ return NULL;
+}
+
+static int
+i40e_update_customized_pctype(struct rte_eth_dev *dev, uint8_t *pkg,
+ uint32_t pkg_size, uint32_t proto_num,
+ struct rte_pmd_i40e_proto_info *proto,
+ enum rte_pmd_i40e_package_op op)
+{
+ struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ uint32_t pctype_num;
+ struct rte_pmd_i40e_ptype_info *pctype;
+ uint32_t buff_size;
+ struct i40e_customized_pctype *new_pctype = NULL;
+ uint8_t proto_id;
+ uint8_t pctype_value;
+ char name[64];
+ uint32_t i, j, n;
+ int ret;
+
+ if (op != RTE_PMD_I40E_PKG_OP_WR_ADD &&
+ op != RTE_PMD_I40E_PKG_OP_WR_DEL) {
+ PMD_DRV_LOG(ERR, "Unsupported operation.");
+ return -1;
+ }
+
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)&pctype_num, sizeof(pctype_num),
+ RTE_PMD_I40E_PKG_INFO_PCTYPE_NUM);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Failed to get pctype number");
+ return -1;
+ }
+ if (!pctype_num) {
+ PMD_DRV_LOG(INFO, "No new pctype added");
+ return -1;
+ }
+
+ buff_size = pctype_num * sizeof(struct rte_pmd_i40e_proto_info);
+ pctype = rte_zmalloc("new_pctype", buff_size, 0);
+ if (!pctype) {
+ PMD_DRV_LOG(ERR, "Failed to allocate memory");
+ return -1;
+ }
+ /* get information about new pctype list */
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)pctype, buff_size,
+ RTE_PMD_I40E_PKG_INFO_PCTYPE_LIST);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Failed to get pctype list");
+ rte_free(pctype);
+ return -1;
+ }
+
+ /* Update customized pctype. */
+ for (i = 0; i < pctype_num; i++) {
+ pctype_value = pctype[i].ptype_id;
+ memset(name, 0, sizeof(name));
+ for (j = 0; j < RTE_PMD_I40E_PROTO_NUM; j++) {
+ proto_id = pctype[i].protocols[j];
+ if (proto_id == RTE_PMD_I40E_PROTO_UNUSED)
+ continue;
+ for (n = 0; n < proto_num; n++) {
+ if (proto[n].proto_id != proto_id)
+ continue;
+ strlcat(name, proto[n].name, sizeof(name));
+ strlcat(name, "_", sizeof(name));
+ break;
+ }
+ }
+ name[strlen(name) - 1] = '\0';
+ if (!strcmp(name, "GTPC"))
+ new_pctype =
+ i40e_find_customized_pctype(pf,
+ I40E_CUSTOMIZED_GTPC);
+ else if (!strcmp(name, "GTPU_IPV4"))
+ new_pctype =
+ i40e_find_customized_pctype(pf,
+ I40E_CUSTOMIZED_GTPU_IPV4);
+ else if (!strcmp(name, "GTPU_IPV6"))
+ new_pctype =
+ i40e_find_customized_pctype(pf,
+ I40E_CUSTOMIZED_GTPU_IPV6);
+ else if (!strcmp(name, "GTPU"))
+ new_pctype =
+ i40e_find_customized_pctype(pf,
+ I40E_CUSTOMIZED_GTPU);
+ if (new_pctype) {
+ if (op == RTE_PMD_I40E_PKG_OP_WR_ADD) {
+ new_pctype->pctype = pctype_value;
+ new_pctype->valid = true;
+ } else {
+ new_pctype->pctype = I40E_FILTER_PCTYPE_INVALID;
+ new_pctype->valid = false;
+ }
+ }
+ }
+
+ rte_free(pctype);
+ return 0;
+}
+
+static int
+i40e_update_customized_ptype(struct rte_eth_dev *dev, uint8_t *pkg,
+ uint32_t pkg_size, uint32_t proto_num,
+ struct rte_pmd_i40e_proto_info *proto,
+ enum rte_pmd_i40e_package_op op)
+{
+ struct rte_pmd_i40e_ptype_mapping *ptype_mapping;
+ uint16_t port_id = dev->data->port_id;
+ uint32_t ptype_num;
+ struct rte_pmd_i40e_ptype_info *ptype;
+ uint32_t buff_size;
+ uint8_t proto_id;
+ char name[RTE_PMD_I40E_DDP_NAME_SIZE];
+ uint32_t i, j, n;
+ bool in_tunnel;
+ int ret;
+
+ if (op != RTE_PMD_I40E_PKG_OP_WR_ADD &&
+ op != RTE_PMD_I40E_PKG_OP_WR_DEL) {
+ PMD_DRV_LOG(ERR, "Unsupported operation.");
+ return -1;
+ }
+
+ if (op == RTE_PMD_I40E_PKG_OP_WR_DEL) {
+ rte_pmd_i40e_ptype_mapping_reset(port_id);
+ return 0;
+ }
+
+ /* get information about new ptype num */
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)&ptype_num, sizeof(ptype_num),
+ RTE_PMD_I40E_PKG_INFO_PTYPE_NUM);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Failed to get ptype number");
+ return ret;
+ }
+ if (!ptype_num) {
+ PMD_DRV_LOG(INFO, "No new ptype added");
+ return -1;
+ }
+
+ buff_size = ptype_num * sizeof(struct rte_pmd_i40e_ptype_info);
+ ptype = rte_zmalloc("new_ptype", buff_size, 0);
+ if (!ptype) {
+ PMD_DRV_LOG(ERR, "Failed to allocate memory");
+ return -1;
+ }
+
+ /* get information about new ptype list */
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)ptype, buff_size,
+ RTE_PMD_I40E_PKG_INFO_PTYPE_LIST);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Failed to get ptype list");
+ rte_free(ptype);
+ return ret;
+ }
+
+ buff_size = ptype_num * sizeof(struct rte_pmd_i40e_ptype_mapping);
+ ptype_mapping = rte_zmalloc("ptype_mapping", buff_size, 0);
+ if (!ptype_mapping) {
+ PMD_DRV_LOG(ERR, "Failed to allocate memory");
+ rte_free(ptype);
+ return -1;
+ }
+
+ /* Update ptype mapping table. */
+ for (i = 0; i < ptype_num; i++) {
+ ptype_mapping[i].hw_ptype = ptype[i].ptype_id;
+ ptype_mapping[i].sw_ptype = 0;
+ in_tunnel = false;
+ for (j = 0; j < RTE_PMD_I40E_PROTO_NUM; j++) {
+ proto_id = ptype[i].protocols[j];
+ if (proto_id == RTE_PMD_I40E_PROTO_UNUSED)
+ continue;
+ for (n = 0; n < proto_num; n++) {
+ if (proto[n].proto_id != proto_id)
+ continue;
+ memset(name, 0, sizeof(name));
+ strcpy(name, proto[n].name);
+ if (!strncasecmp(name, "PPPOE", 5))
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L2_ETHER_PPPOE;
+ else if (!strncasecmp(name, "IPV4FRAG", 8) &&
+ !in_tunnel) {
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L4_FRAG;
+ } else if (!strncasecmp(name, "IPV4FRAG", 8) &&
+ in_tunnel) {
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN;
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_INNER_L4_FRAG;
+ } else if (!strncasecmp(name, "OIPV4", 5)) {
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+ in_tunnel = true;
+ } else if (!strncasecmp(name, "IPV4", 4) &&
+ !in_tunnel)
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
+ else if (!strncasecmp(name, "IPV4", 4) &&
+ in_tunnel)
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN;
+ else if (!strncasecmp(name, "IPV6FRAG", 8) &&
+ !in_tunnel) {
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L4_FRAG;
+ } else if (!strncasecmp(name, "IPV6FRAG", 8) &&
+ in_tunnel) {
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN;
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_INNER_L4_FRAG;
+ } else if (!strncasecmp(name, "OIPV6", 5)) {
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
+ in_tunnel = true;
+ } else if (!strncasecmp(name, "IPV6", 4) &&
+ !in_tunnel)
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
+ else if (!strncasecmp(name, "IPV6", 4) &&
+ in_tunnel)
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN;
+ else if (!strncasecmp(name, "UDP", 3) &&
+ !in_tunnel)
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L4_UDP;
+ else if (!strncasecmp(name, "UDP", 3) &&
+ in_tunnel)
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_INNER_L4_UDP;
+ else if (!strncasecmp(name, "TCP", 3) &&
+ !in_tunnel)
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L4_TCP;
+ else if (!strncasecmp(name, "TCP", 3) &&
+ in_tunnel)
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_INNER_L4_TCP;
+ else if (!strncasecmp(name, "SCTP", 4) &&
+ !in_tunnel)
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L4_SCTP;
+ else if (!strncasecmp(name, "SCTP", 4) &&
+ in_tunnel)
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_INNER_L4_SCTP;
+ else if ((!strncasecmp(name, "ICMP", 4) ||
+ !strncasecmp(name, "ICMPV6", 6)) &&
+ !in_tunnel)
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_L4_ICMP;
+ else if ((!strncasecmp(name, "ICMP", 4) ||
+ !strncasecmp(name, "ICMPV6", 6)) &&
+ in_tunnel)
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_INNER_L4_ICMP;
+ else if (!strncasecmp(name, "GTPC", 4)) {
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_TUNNEL_GTPC;
+ in_tunnel = true;
+ } else if (!strncasecmp(name, "GTPU", 4)) {
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_TUNNEL_GTPU;
+ in_tunnel = true;
+ } else if (!strncasecmp(name, "GRENAT", 6)) {
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_TUNNEL_GRENAT;
+ in_tunnel = true;
+ } else if (!strncasecmp(name, "L2TPV2CTL", 9) ||
+ !strncasecmp(name, "L2TPV2", 6)) {
+ ptype_mapping[i].sw_ptype |=
+ RTE_PTYPE_TUNNEL_L2TP;
+ in_tunnel = true;
+ }
+
+ break;
+ }
+ }
+ }
+
+ ret = rte_pmd_i40e_ptype_mapping_update(port_id, ptype_mapping,
+ ptype_num, 0);
+ if (ret)
+ PMD_DRV_LOG(ERR, "Failed to update mapping table.");
+
+ rte_free(ptype_mapping);
+ rte_free(ptype);
+ return ret;
+}
+
+void
+i40e_update_customized_info(struct rte_eth_dev *dev, uint8_t *pkg,
+ uint32_t pkg_size, enum rte_pmd_i40e_package_op op)
+{
+ struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+ uint32_t proto_num;
+ struct rte_pmd_i40e_proto_info *proto;
+ uint32_t buff_size;
+ uint32_t i;
+ int ret;
+
+ if (op != RTE_PMD_I40E_PKG_OP_WR_ADD &&
+ op != RTE_PMD_I40E_PKG_OP_WR_DEL) {
+ PMD_DRV_LOG(ERR, "Unsupported operation.");
+ return;
+ }
+
+ /* get information about protocol number */
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)&proto_num, sizeof(proto_num),
+ RTE_PMD_I40E_PKG_INFO_PROTOCOL_NUM);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Failed to get protocol number");
+ return;
+ }
+ if (!proto_num) {
+ PMD_DRV_LOG(INFO, "No new protocol added");
+ return;
+ }
+
+ buff_size = proto_num * sizeof(struct rte_pmd_i40e_proto_info);
+ proto = rte_zmalloc("new_proto", buff_size, 0);
+ if (!proto) {
+ PMD_DRV_LOG(ERR, "Failed to allocate memory");
+ return;
+ }
+
+ /* get information about protocol list */
+ ret = rte_pmd_i40e_get_ddp_info(pkg, pkg_size,
+ (uint8_t *)proto, buff_size,
+ RTE_PMD_I40E_PKG_INFO_PROTOCOL_LIST);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Failed to get protocol list");
+ rte_free(proto);
+ return;
+ }
+
+ /* Check if GTP is supported. */
+ for (i = 0; i < proto_num; i++) {
+ if (!strncmp(proto[i].name, "GTP", 3)) {
+ if (op == RTE_PMD_I40E_PKG_OP_WR_ADD)
+ pf->gtp_support = true;
+ else
+ pf->gtp_support = false;
+ break;
+ }
+ }
+
+ /* Update customized pctype info */
+ ret = i40e_update_customized_pctype(dev, pkg, pkg_size,
+ proto_num, proto, op);
+ if (ret)
+ PMD_DRV_LOG(INFO, "No pctype is updated.");
+
+ /* Update customized ptype info */
+ ret = i40e_update_customized_ptype(dev, pkg, pkg_size,
+ proto_num, proto, op);
+ if (ret)
+ PMD_DRV_LOG(INFO, "No ptype is updated.");
+
+ rte_free(proto);
+}
+
+/* Create a QinQ cloud filter
+ *
+ * The Fortville NIC has limited resources for tunnel filters,
+ * so we can only reuse existing filters.
+ *
+ * In step 1 we define which Field Vector fields can be used for
+ * filter types.
+ * As we do not have the inner tag defined as a field,
+ * we have to define it first, by reusing one of L1 entries.
+ *
+ * In step 2 we are replacing one of existing filter types with
+ * a new one for QinQ.
+ * As we reusing L1 and replacing L2, some of the default filter
+ * types will disappear,which depends on L1 and L2 entries we reuse.
+ *
+ * Step 1: Create L1 filter of outer vlan (12b) + inner vlan (12b)
+ *
+ * 1. Create L1 filter of outer vlan (12b) which will be in use
+ * later when we define the cloud filter.
+ * a. Valid_flags.replace_cloud = 0
+ * b. Old_filter = 10 (Stag_Inner_Vlan)
+ * c. New_filter = 0x10
+ * d. TR bit = 0xff (optional, not used here)
+ * e. Buffer – 2 entries:
+ * i. Byte 0 = 8 (outer vlan FV index).
+ * Byte 1 = 0 (rsv)
+ * Byte 2-3 = 0x0fff
+ * ii. Byte 0 = 37 (inner vlan FV index).
+ * Byte 1 =0 (rsv)
+ * Byte 2-3 = 0x0fff
+ *
+ * Step 2:
+ * 2. Create cloud filter using two L1 filters entries: stag and
+ * new filter(outer vlan+ inner vlan)
+ * a. Valid_flags.replace_cloud = 1
+ * b. Old_filter = 1 (instead of outer IP)
+ * c. New_filter = 0x10
+ * d. Buffer – 2 entries:
+ * i. Byte 0 = 0x80 | 7 (valid | Stag).
+ * Byte 1-3 = 0 (rsv)
+ * ii. Byte 8 = 0x80 | 0x10 (valid | new l1 filter step1)
+ * Byte 9-11 = 0 (rsv)
+ */
+static int
+i40e_cloud_filter_qinq_create(struct i40e_pf *pf)
+{
+ int ret = -ENOTSUP;
+ struct i40e_aqc_replace_cloud_filters_cmd filter_replace;
+ struct i40e_aqc_replace_cloud_filters_cmd_buf filter_replace_buf;
+ struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+ struct rte_eth_dev *dev = ((struct i40e_adapter *)hw->back)->eth_dev;
+
+ if (pf->support_multi_driver) {
+ PMD_DRV_LOG(ERR, "Replace cloud filter is not supported.");
+ return ret;
+ }
+
+ /* Init */
+ memset(&filter_replace, 0,
+ sizeof(struct i40e_aqc_replace_cloud_filters_cmd));
+ memset(&filter_replace_buf, 0,
+ sizeof(struct i40e_aqc_replace_cloud_filters_cmd_buf));
+
+ /* create L1 filter */
+ filter_replace.old_filter_type =
+ I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG_IVLAN;
+ filter_replace.new_filter_type = I40E_AQC_ADD_CLOUD_FILTER_0X10;
+ filter_replace.tr_bit = 0;
+
+ /* Prepare the buffer, 2 entries */
+ filter_replace_buf.data[0] = I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_VLAN;
+ filter_replace_buf.data[0] |=
+ I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+ /* Field Vector 12b mask */
+ filter_replace_buf.data[2] = 0xff;
+ filter_replace_buf.data[3] = 0x0f;
+ filter_replace_buf.data[4] =
+ I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_INNER_VLAN;
+ filter_replace_buf.data[4] |=
+ I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+ /* Field Vector 12b mask */
+ filter_replace_buf.data[6] = 0xff;
+ filter_replace_buf.data[7] = 0x0f;
+ ret = i40e_aq_replace_cloud_filters(hw, &filter_replace,
+ &filter_replace_buf);
+ if (ret != I40E_SUCCESS)
+ return ret;
+
+ if (filter_replace.old_filter_type !=
+ filter_replace.new_filter_type)
+ PMD_DRV_LOG(WARNING, "i40e device %s changed cloud l1 type."
+ " original: 0x%x, new: 0x%x",
+ dev->device->name,
+ filter_replace.old_filter_type,
+ filter_replace.new_filter_type);
+
+ /* Apply the second L2 cloud filter */
+ memset(&filter_replace, 0,
+ sizeof(struct i40e_aqc_replace_cloud_filters_cmd));
+ memset(&filter_replace_buf, 0,
+ sizeof(struct i40e_aqc_replace_cloud_filters_cmd_buf));
+
+ /* create L2 filter, input for L2 filter will be L1 filter */
+ filter_replace.valid_flags = I40E_AQC_REPLACE_CLOUD_FILTER;
+ filter_replace.old_filter_type = I40E_AQC_ADD_CLOUD_FILTER_OIP;
+ filter_replace.new_filter_type = I40E_AQC_ADD_CLOUD_FILTER_0X10;
+
+ /* Prepare the buffer, 2 entries */
+ filter_replace_buf.data[0] = I40E_AQC_REPLACE_CLOUD_CMD_INPUT_FV_STAG;
+ filter_replace_buf.data[0] |=
+ I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+ filter_replace_buf.data[4] = I40E_AQC_ADD_CLOUD_FILTER_0X10;
+ filter_replace_buf.data[4] |=
+ I40E_AQC_REPLACE_CLOUD_CMD_INPUT_VALIDATED;
+ ret = i40e_aq_replace_cloud_filters(hw, &filter_replace,
+ &filter_replace_buf);
+ if (!ret && (filter_replace.old_filter_type !=
+ filter_replace.new_filter_type))
+ PMD_DRV_LOG(WARNING, "i40e device %s changed cloud filter type."
+ " original: 0x%x, new: 0x%x",
+ dev->device->name,
+ filter_replace.old_filter_type,
+ filter_replace.new_filter_type);
+
+ return ret;
+}
+
+int
+i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out,
+ const struct rte_flow_action_rss *in)
+{
+ if (in->key_len > RTE_DIM(out->key) ||
+ in->queue_num > RTE_DIM(out->queue))
+ return -EINVAL;
+ if (!in->key && in->key_len)
+ return -EINVAL;
+ out->conf = (struct rte_flow_action_rss){
+ .func = in->func,
+ .level = in->level,
+ .types = in->types,
+ .key_len = in->key_len,
+ .queue_num = in->queue_num,
+ .queue = memcpy(out->queue, in->queue,
+ sizeof(*in->queue) * in->queue_num),
+ };
+ if (in->key)
+ out->conf.key = memcpy(out->key, in->key, in->key_len);
+ return 0;
+}
+
+int
+i40e_action_rss_same(const struct rte_flow_action_rss *comp,
+ const struct rte_flow_action_rss *with)
+{
+ return (comp->func == with->func &&
+ comp->level == with->level &&
+ comp->types == with->types &&
+ comp->key_len == with->key_len &&
+ comp->queue_num == with->queue_num &&
+ !memcmp(comp->key, with->key, with->key_len) &&
+ !memcmp(comp->queue, with->queue,
+ sizeof(*with->queue) * with->queue_num));
+}
+
+int
+i40e_config_rss_filter(struct i40e_pf *pf,
+ struct i40e_rte_flow_rss_conf *conf, bool add)
+{
+ struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+ uint32_t i, lut = 0;
+ uint16_t j, num;
+ struct rte_eth_rss_conf rss_conf = {
+ .rss_key = conf->conf.key_len ?
+ (void *)(uintptr_t)conf->conf.key : NULL,
+ .rss_key_len = conf->conf.key_len,
+ .rss_hf = conf->conf.types,
+ };
+ struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
+
+ if (!add) {
+ if (i40e_action_rss_same(&rss_info->conf, &conf->conf)) {
+ i40e_pf_disable_rss(pf);
+ memset(rss_info, 0,
+ sizeof(struct i40e_rte_flow_rss_conf));
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+ /* If both VMDQ and RSS enabled, not all of PF queues are configured.
+ * It's necessary to calculate the actual PF queues that are configured.
+ */
+ if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG)
+ num = i40e_pf_calc_configured_queues_num(pf);
+ else
+ num = pf->dev_data->nb_rx_queues;
+
+ num = RTE_MIN(num, conf->conf.queue_num);
+ PMD_DRV_LOG(INFO, "Max of contiguous %u PF queues are configured",
+ num);
+
+ if (num == 0) {
+ PMD_DRV_LOG(ERR, "No PF queues are configured to enable RSS");
+ return -ENOTSUP;
+ }
+
+ /* Fill in redirection table */
+ for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) {
+ if (j == num)
+ j = 0;
+ lut = (lut << 8) | (conf->conf.queue[j] & ((0x1 <<
+ hw->func_caps.rss_table_entry_width) - 1));
+ if ((i & 3) == 3)
+ I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut);
+ }
+
+ if ((rss_conf.rss_hf & pf->adapter->flow_types_mask) == 0) {
+ i40e_pf_disable_rss(pf);
+ return 0;
+ }
+ if (rss_conf.rss_key == NULL || rss_conf.rss_key_len <
+ (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
+ /* Random default keys */
+ static uint32_t rss_key_default[] = {0x6b793944,
+ 0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
+ 0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
+ 0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
+
+ rss_conf.rss_key = (uint8_t *)rss_key_default;
+ rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
+ sizeof(uint32_t);
+ PMD_DRV_LOG(INFO,
+ "No valid RSS key config for i40e, using default\n");
+ }
+
+ i40e_hw_rss_hash_set(pf, &rss_conf);
+
+ if (i40e_rss_conf_init(rss_info, &conf->conf))
+ return -EINVAL;
+
+ return 0;
+}
+
+RTE_INIT(i40e_init_log)
+{
+ i40e_logtype_init = rte_log_register("pmd.net.i40e.init");
+ if (i40e_logtype_init >= 0)
+ rte_log_set_level(i40e_logtype_init, RTE_LOG_NOTICE);
+ i40e_logtype_driver = rte_log_register("pmd.net.i40e.driver");
+ if (i40e_logtype_driver >= 0)
+ rte_log_set_level(i40e_logtype_driver, RTE_LOG_NOTICE);
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_RX
+ i40e_logtype_rx = rte_log_register("pmd.net.i40e.rx");
+ if (i40e_logtype_rx >= 0)
+ rte_log_set_level(i40e_logtype_rx, RTE_LOG_DEBUG);
+#endif
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_TX
+ i40e_logtype_tx = rte_log_register("pmd.net.i40e.tx");
+ if (i40e_logtype_tx >= 0)
+ rte_log_set_level(i40e_logtype_tx, RTE_LOG_DEBUG);
+#endif
+
+#ifdef RTE_LIBRTE_I40E_DEBUG_TX_FREE
+ i40e_logtype_tx_free = rte_log_register("pmd.net.i40e.tx_free");
+ if (i40e_logtype_tx_free >= 0)
+ rte_log_set_level(i40e_logtype_tx_free, RTE_LOG_DEBUG);
+#endif
+}
+
+RTE_PMD_REGISTER_PARAM_STRING(net_i40e,
+ ETH_I40E_FLOATING_VEB_ARG "=1"
+ ETH_I40E_FLOATING_VEB_LIST_ARG "=<string>"
+ ETH_I40E_QUEUE_NUM_PER_VF_ARG "=1|2|4|8|16"
+ ETH_I40E_SUPPORT_MULTI_DRIVER "=1"
+ ETH_I40E_USE_LATEST_VEC "=0|1");