[{"id":1768061,"web_url":"http://patchwork.ozlabs.org/comment/1768061/","msgid":"<20170913132611.GC1981@nanopsycho>","list_archive_url":null,"date":"2017-09-13T13:26:11","subject":"Re: [Intel-wired-lan] [RFC PATCH v3 7/7] i40e: Enable cloud filters\n\tvia tc-flower","submitter":{"id":15321,"url":"http://patchwork.ozlabs.org/api/people/15321/","name":"Jiri Pirko","email":"jiri@resnulli.us"},"content":"Wed, Sep 13, 2017 at 11:59:50AM CEST, amritha.nambiar@intel.com wrote:\n>This patch enables tc-flower based hardware offloads. tc flower\n>filter provided by the kernel is configured as driver specific\n>cloud filter. The patch implements functions and admin queue\n>commands needed to support cloud filters in the driver and\n>adds cloud filters to configure these tc-flower filters.\n>\n>The only action supported is to redirect packets to a traffic class\n>on the same device.\n\nSo basically you are not doing redirect, you are just setting tclass for\nmatched packets, right? Why you use mirred for this? I think that\nyou might consider extending g_act for that:\n\n# tc filter add dev eth0 protocol ip ingress \\\n  prio 1 flower dst_mac 3c:fd:fe:a0:d6:70 skip_sw \\\n  action tclass 0\n\n\n>\n># tc qdisc add dev eth0 ingress\n># ethtool -K eth0 hw-tc-offload on\n>\n># tc filter add dev eth0 protocol ip parent ffff:\\\n>  prio 1 flower dst_mac 3c:fd:fe:a0:d6:70 skip_sw\\\n>  action mirred ingress redirect dev eth0 tclass 0\n>\n># tc filter add dev eth0 protocol ip parent ffff:\\\n>  prio 2 flower dst_ip 192.168.3.5/32\\\n>  ip_proto udp dst_port 25 skip_sw\\\n>  action mirred ingress redirect dev eth0 tclass 1\n>\n># tc filter add dev eth0 protocol ipv6 parent ffff:\\\n>  prio 3 flower dst_ip fe8::200:1\\\n>  ip_proto udp dst_port 66 skip_sw\\\n>  action mirred ingress redirect dev eth0 tclass 1\n>\n>Delete tc flower filter:\n>Example:\n>\n># tc filter del dev eth0 parent ffff: prio 3 handle 0x1 flower\n># tc filter del dev eth0 parent ffff:\n>\n>Flow Director Sideband is disabled while configuring cloud filters\n>via tc-flower and until any cloud filter exists.\n>\n>Unsupported matches when cloud filters are added using enhanced\n>big buffer cloud filter mode of underlying switch include:\n>1. source port and source IP\n>2. Combined MAC address and IP fields.\n>3. Not specifying L4 port\n>\n>These filter matches can however be used to redirect traffic to\n>the main VSI (tc 0) which does not require the enhanced big buffer\n>cloud filter support.\n>\n>v3: Cleaned up some lengthy function names. Changed ipv6 address to\n>__be32 array instead of u8 array. Used macro for IP version. Minor\n>formatting changes.\n>v2:\n>1. Moved I40E_SWITCH_MODE_MASK definition to i40e_type.h\n>2. Moved dev_info for add/deleting cloud filters in else condition\n>3. Fixed some format specifier in dev_err logs\n>4. Refactored i40e_get_capabilities to take an additional\n>   list_type parameter and use it to query device and function\n>   level capabilities.\n>5. Fixed parsing tc redirect action to check for the is_tcf_mirred_tc()\n>   to verify if redirect to a traffic class is supported.\n>6. Added comments for Geneve fix in cloud filter big buffer AQ\n>   function definitions.\n>7. Cleaned up setup_tc interface to rebase and work with Jiri's\n>   updates, separate function to process tc cls flower offloads.\n>8. Changes to make Flow Director Sideband and Cloud filters mutually\n>   exclusive.\n>\n>Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>\n>Signed-off-by: Kiran Patil <kiran.patil@intel.com>\n>Signed-off-by: Anjali Singhai Jain <anjali.singhai@intel.com>\n>Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>\n>---\n> drivers/net/ethernet/intel/i40e/i40e.h             |   49 +\n> drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h  |    3 \n> drivers/net/ethernet/intel/i40e/i40e_common.c      |  189 ++++\n> drivers/net/ethernet/intel/i40e/i40e_main.c        |  971 +++++++++++++++++++-\n> drivers/net/ethernet/intel/i40e/i40e_prototype.h   |   16 \n> drivers/net/ethernet/intel/i40e/i40e_type.h        |    1 \n> .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h    |    3 \n> 7 files changed, 1202 insertions(+), 30 deletions(-)\n>\n>diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h\n>index 6018fb6..b110519 100644\n>--- a/drivers/net/ethernet/intel/i40e/i40e.h\n>+++ b/drivers/net/ethernet/intel/i40e/i40e.h\n>@@ -55,6 +55,8 @@\n> #include <linux/net_tstamp.h>\n> #include <linux/ptp_clock_kernel.h>\n> #include <net/pkt_cls.h>\n>+#include <net/tc_act/tc_gact.h>\n>+#include <net/tc_act/tc_mirred.h>\n> #include \"i40e_type.h\"\n> #include \"i40e_prototype.h\"\n> #include \"i40e_client.h\"\n>@@ -252,9 +254,52 @@ struct i40e_fdir_filter {\n> \tu32 fd_id;\n> };\n> \n>+#define IPV4_VERSION 4\n>+#define IPV6_VERSION 6\n>+\n>+#define I40E_CLOUD_FIELD_OMAC\t0x01\n>+#define I40E_CLOUD_FIELD_IMAC\t0x02\n>+#define I40E_CLOUD_FIELD_IVLAN\t0x04\n>+#define I40E_CLOUD_FIELD_TEN_ID\t0x08\n>+#define I40E_CLOUD_FIELD_IIP\t0x10\n>+\n>+#define I40E_CLOUD_FILTER_FLAGS_OMAC\tI40E_CLOUD_FIELD_OMAC\n>+#define I40E_CLOUD_FILTER_FLAGS_IMAC\tI40E_CLOUD_FIELD_IMAC\n>+#define I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN\t(I40E_CLOUD_FIELD_IMAC | \\\n>+\t\t\t\t\t\t I40E_CLOUD_FIELD_IVLAN)\n>+#define I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID\t(I40E_CLOUD_FIELD_IMAC | \\\n>+\t\t\t\t\t\t I40E_CLOUD_FIELD_TEN_ID)\n>+#define I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC (I40E_CLOUD_FIELD_OMAC | \\\n>+\t\t\t\t\t\t  I40E_CLOUD_FIELD_IMAC | \\\n>+\t\t\t\t\t\t  I40E_CLOUD_FIELD_TEN_ID)\n>+#define I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID (I40E_CLOUD_FIELD_IMAC | \\\n>+\t\t\t\t\t\t   I40E_CLOUD_FIELD_IVLAN | \\\n>+\t\t\t\t\t\t   I40E_CLOUD_FIELD_TEN_ID)\n>+#define I40E_CLOUD_FILTER_FLAGS_IIP\tI40E_CLOUD_FIELD_IIP\n>+\n> struct i40e_cloud_filter {\n> \tstruct hlist_node cloud_node;\n> \tunsigned long cookie;\n>+\t/* cloud filter input set follows */\n>+\tu8 dst_mac[ETH_ALEN];\n>+\tu8 src_mac[ETH_ALEN];\n>+\t__be16 vlan_id;\n>+\t__be32 dst_ip;\n>+\t__be32 src_ip;\n>+\t__be32 dst_ipv6[4];\n>+\t__be32 src_ipv6[4];\n>+\t__be16 dst_port;\n>+\t__be16 src_port;\n>+\tu32 ip_version;\n>+\tu8 ip_proto;\t/* IPPROTO value */\n>+\t/* L4 port type: src or destination port */\n>+#define I40E_CLOUD_FILTER_PORT_SRC\t0x01\n>+#define I40E_CLOUD_FILTER_PORT_DEST\t0x02\n>+\tu8 port_type;\n>+\tu32 tenant_id;\n>+\tu8 flags;\n>+#define I40E_CLOUD_TNL_TYPE_NONE\t0xff\n>+\tu8 tunnel_type;\n> \tu16 seid;\t/* filter control */\n> };\n> \n>@@ -491,6 +536,8 @@ struct i40e_pf {\n> #define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED\tBIT(27)\n> #define I40E_FLAG_SOURCE_PRUNING_DISABLED\tBIT(28)\n> #define I40E_FLAG_TC_MQPRIO\t\t\tBIT(29)\n>+#define I40E_FLAG_FD_SB_INACTIVE\t\tBIT(30)\n>+#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER\t\tBIT(31)\n> \n> \tstruct i40e_client_instance *cinst;\n> \tbool stat_offsets_loaded;\n>@@ -573,6 +620,8 @@ struct i40e_pf {\n> \tu16 phy_led_val;\n> \n> \tu16 override_q_count;\n>+\tu16 last_sw_conf_flags;\n>+\tu16 last_sw_conf_valid_flags;\n> };\n> \n> /**\n>diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h\n>index 2e567c2..feb3d42 100644\n>--- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h\n>+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h\n>@@ -1392,6 +1392,9 @@ struct i40e_aqc_cloud_filters_element_data {\n> \t\tstruct {\n> \t\t\tu8 data[16];\n> \t\t} v6;\n>+\t\tstruct {\n>+\t\t\t__le16 data[8];\n>+\t\t} raw_v6;\n> \t} ipaddr;\n> \t__le16\tflags;\n> #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT\t\t\t0\n>diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c\n>index 9567702..d9c9665 100644\n>--- a/drivers/net/ethernet/intel/i40e/i40e_common.c\n>+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c\n>@@ -5434,5 +5434,194 @@ i40e_add_pinfo_to_list(struct i40e_hw *hw,\n> \n> \tstatus = i40e_aq_write_ppp(hw, (void *)sec, sec->data_end,\n> \t\t\t\t   track_id, &offset, &info, NULL);\n>+\n>+\treturn status;\n>+}\n>+\n>+/**\n>+ * i40e_aq_add_cloud_filters\n>+ * @hw: pointer to the hardware structure\n>+ * @seid: VSI seid to add cloud filters from\n>+ * @filters: Buffer which contains the filters to be added\n>+ * @filter_count: number of filters contained in the buffer\n>+ *\n>+ * Set the cloud filters for a given VSI.  The contents of the\n>+ * i40e_aqc_cloud_filters_element_data are filled in by the caller\n>+ * of the function.\n>+ *\n>+ **/\n>+enum i40e_status_code\n>+i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 seid,\n>+\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>+\t\t\t  u8 filter_count)\n>+{\n>+\tstruct i40e_aq_desc desc;\n>+\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>+\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>+\tenum i40e_status_code status;\n>+\tu16 buff_len;\n>+\n>+\ti40e_fill_default_direct_cmd_desc(&desc,\n>+\t\t\t\t\t  i40e_aqc_opc_add_cloud_filters);\n>+\n>+\tbuff_len = filter_count * sizeof(*filters);\n>+\tdesc.datalen = cpu_to_le16(buff_len);\n>+\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>+\tcmd->num_filters = filter_count;\n>+\tcmd->seid = cpu_to_le16(seid);\n>+\n>+\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>+\n>+\treturn status;\n>+}\n>+\n>+/**\n>+ * i40e_aq_add_cloud_filters_bb\n>+ * @hw: pointer to the hardware structure\n>+ * @seid: VSI seid to add cloud filters from\n>+ * @filters: Buffer which contains the filters in big buffer to be added\n>+ * @filter_count: number of filters contained in the buffer\n>+ *\n>+ * Set the big buffer cloud filters for a given VSI.  The contents of the\n>+ * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the\n>+ * function.\n>+ *\n>+ **/\n>+i40e_status\n>+i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>+\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>+\t\t\t     u8 filter_count)\n>+{\n>+\tstruct i40e_aq_desc desc;\n>+\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>+\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>+\ti40e_status status;\n>+\tu16 buff_len;\n>+\tint i;\n>+\n>+\ti40e_fill_default_direct_cmd_desc(&desc,\n>+\t\t\t\t\t  i40e_aqc_opc_add_cloud_filters);\n>+\n>+\tbuff_len = filter_count * sizeof(*filters);\n>+\tdesc.datalen = cpu_to_le16(buff_len);\n>+\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>+\tcmd->num_filters = filter_count;\n>+\tcmd->seid = cpu_to_le16(seid);\n>+\tcmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;\n>+\n>+\tfor (i = 0; i < filter_count; i++) {\n>+\t\tu16 tnl_type;\n>+\t\tu32 ti;\n>+\n>+\t\ttnl_type = (le16_to_cpu(filters[i].element.flags) &\n>+\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>\n>+\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;\n>+\n>+\t\t/* For Geneve, the VNI should be placed in offset shifted by a\n>+\t\t * byte than the offset for the Tenant ID for rest of the\n>+\t\t * tunnels.\n>+\t\t */\n>+\t\tif (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {\n>+\t\t\tti = le32_to_cpu(filters[i].element.tenant_id);\n>+\t\t\tfilters[i].element.tenant_id = cpu_to_le32(ti << 8);\n>+\t\t}\n>+\t}\n>+\n>+\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>+\n>+\treturn status;\n>+}\n>+\n>+/**\n>+ * i40e_aq_rem_cloud_filters\n>+ * @hw: pointer to the hardware structure\n>+ * @seid: VSI seid to remove cloud filters from\n>+ * @filters: Buffer which contains the filters to be removed\n>+ * @filter_count: number of filters contained in the buffer\n>+ *\n>+ * Remove the cloud filters for a given VSI.  The contents of the\n>+ * i40e_aqc_cloud_filters_element_data are filled in by the caller\n>+ * of the function.\n>+ *\n>+ **/\n>+enum i40e_status_code\n>+i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 seid,\n>+\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>+\t\t\t  u8 filter_count)\n>+{\n>+\tstruct i40e_aq_desc desc;\n>+\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>+\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>+\tenum i40e_status_code status;\n>+\tu16 buff_len;\n>+\n>+\ti40e_fill_default_direct_cmd_desc(&desc,\n>+\t\t\t\t\t  i40e_aqc_opc_remove_cloud_filters);\n>+\n>+\tbuff_len = filter_count * sizeof(*filters);\n>+\tdesc.datalen = cpu_to_le16(buff_len);\n>+\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>+\tcmd->num_filters = filter_count;\n>+\tcmd->seid = cpu_to_le16(seid);\n>+\n>+\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>+\n>+\treturn status;\n>+}\n>+\n>+/**\n>+ * i40e_aq_rem_cloud_filters_bb\n>+ * @hw: pointer to the hardware structure\n>+ * @seid: VSI seid to remove cloud filters from\n>+ * @filters: Buffer which contains the filters in big buffer to be removed\n>+ * @filter_count: number of filters contained in the buffer\n>+ *\n>+ * Remove the big buffer cloud filters for a given VSI.  The contents of the\n>+ * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the\n>+ * function.\n>+ *\n>+ **/\n>+i40e_status\n>+i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>+\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>+\t\t\t     u8 filter_count)\n>+{\n>+\tstruct i40e_aq_desc desc;\n>+\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>+\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>+\ti40e_status status;\n>+\tu16 buff_len;\n>+\tint i;\n>+\n>+\ti40e_fill_default_direct_cmd_desc(&desc,\n>+\t\t\t\t\t  i40e_aqc_opc_remove_cloud_filters);\n>+\n>+\tbuff_len = filter_count * sizeof(*filters);\n>+\tdesc.datalen = cpu_to_le16(buff_len);\n>+\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>+\tcmd->num_filters = filter_count;\n>+\tcmd->seid = cpu_to_le16(seid);\n>+\tcmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;\n>+\n>+\tfor (i = 0; i < filter_count; i++) {\n>+\t\tu16 tnl_type;\n>+\t\tu32 ti;\n>+\n>+\t\ttnl_type = (le16_to_cpu(filters[i].element.flags) &\n>+\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>\n>+\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;\n>+\n>+\t\t/* For Geneve, the VNI should be placed in offset shifted by a\n>+\t\t * byte than the offset for the Tenant ID for rest of the\n>+\t\t * tunnels.\n>+\t\t */\n>+\t\tif (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {\n>+\t\t\tti = le32_to_cpu(filters[i].element.tenant_id);\n>+\t\t\tfilters[i].element.tenant_id = cpu_to_le32(ti << 8);\n>+\t\t}\n>+\t}\n>+\n>+\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>+\n> \treturn status;\n> }\n>diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c\n>index afcf08a..96ee608 100644\n>--- a/drivers/net/ethernet/intel/i40e/i40e_main.c\n>+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c\n>@@ -69,6 +69,15 @@ static int i40e_reset(struct i40e_pf *pf);\n> static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired);\n> static void i40e_fdir_sb_setup(struct i40e_pf *pf);\n> static int i40e_veb_get_bw_info(struct i40e_veb *veb);\n>+static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,\n>+\t\t\t\t     struct i40e_cloud_filter *filter,\n>+\t\t\t\t     bool add);\n>+static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,\n>+\t\t\t\t\t     struct i40e_cloud_filter *filter,\n>+\t\t\t\t\t     bool add);\n>+static int i40e_get_capabilities(struct i40e_pf *pf,\n>+\t\t\t\t enum i40e_admin_queue_opc list_type);\n>+\n> \n> /* i40e_pci_tbl - PCI Device ID Table\n>  *\n>@@ -5478,7 +5487,11 @@ int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate)\n>  **/\n> static void i40e_remove_queue_channels(struct i40e_vsi *vsi)\n> {\n>+\tenum i40e_admin_queue_err last_aq_status;\n>+\tstruct i40e_cloud_filter *cfilter;\n> \tstruct i40e_channel *ch, *ch_tmp;\n>+\tstruct i40e_pf *pf = vsi->back;\n>+\tstruct hlist_node *node;\n> \tint ret, i;\n> \n> \t/* Reset rss size that was stored when reconfiguring rss for\n>@@ -5519,6 +5532,29 @@ static void i40e_remove_queue_channels(struct i40e_vsi *vsi)\n> \t\t\t\t \"Failed to reset tx rate for ch->seid %u\\n\",\n> \t\t\t\t ch->seid);\n> \n>+\t\t/* delete cloud filters associated with this channel */\n>+\t\thlist_for_each_entry_safe(cfilter, node,\n>+\t\t\t\t\t  &pf->cloud_filter_list, cloud_node) {\n>+\t\t\tif (cfilter->seid != ch->seid)\n>+\t\t\t\tcontinue;\n>+\n>+\t\t\thash_del(&cfilter->cloud_node);\n>+\t\t\tif (cfilter->dst_port)\n>+\t\t\t\tret = i40e_add_del_cloud_filter_big_buf(vsi,\n>+\t\t\t\t\t\t\t\t\tcfilter,\n>+\t\t\t\t\t\t\t\t\tfalse);\n>+\t\t\telse\n>+\t\t\t\tret = i40e_add_del_cloud_filter(vsi, cfilter,\n>+\t\t\t\t\t\t\t\tfalse);\n>+\t\t\tlast_aq_status = pf->hw.aq.asq_last_status;\n>+\t\t\tif (ret)\n>+\t\t\t\tdev_info(&pf->pdev->dev,\n>+\t\t\t\t\t \"Failed to delete cloud filter, err %s aq_err %s\\n\",\n>+\t\t\t\t\t i40e_stat_str(&pf->hw, ret),\n>+\t\t\t\t\t i40e_aq_str(&pf->hw, last_aq_status));\n>+\t\t\tkfree(cfilter);\n>+\t\t}\n>+\n> \t\t/* delete VSI from FW */\n> \t\tret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,\n> \t\t\t\t\t     NULL);\n>@@ -5970,6 +6006,74 @@ static bool i40e_setup_channel(struct i40e_pf *pf, struct i40e_vsi *vsi,\n> }\n> \n> /**\n>+ * i40e_validate_and_set_switch_mode - sets up switch mode correctly\n>+ * @vsi: ptr to VSI which has PF backing\n>+ * @l4type: true for TCP ond false for UDP\n>+ * @port_type: true if port is destination and false if port is source\n>+ *\n>+ * Sets up switch mode correctly if it needs to be changed and perform\n>+ * what are allowed modes.\n>+ **/\n>+static int i40e_validate_and_set_switch_mode(struct i40e_vsi *vsi, bool l4type,\n>+\t\t\t\t\t     bool port_type)\n>+{\n>+\tu8 mode;\n>+\tstruct i40e_pf *pf = vsi->back;\n>+\tstruct i40e_hw *hw = &pf->hw;\n>+\tint ret;\n>+\n>+\tret = i40e_get_capabilities(pf, i40e_aqc_opc_list_dev_capabilities);\n>+\tif (ret)\n>+\t\treturn -EINVAL;\n>+\n>+\tif (hw->dev_caps.switch_mode) {\n>+\t\t/* if switch mode is set, support mode2 (non-tunneled for\n>+\t\t * cloud filter) for now\n>+\t\t */\n>+\t\tu32 switch_mode = hw->dev_caps.switch_mode &\n>+\t\t\t\t\t\t\tI40E_SWITCH_MODE_MASK;\n>+\t\tif (switch_mode >= I40E_NVM_IMAGE_TYPE_MODE1) {\n>+\t\t\tif (switch_mode == I40E_NVM_IMAGE_TYPE_MODE2)\n>+\t\t\t\treturn 0;\n>+\t\t\tdev_err(&pf->pdev->dev,\n>+\t\t\t\t\"Invalid switch_mode (%d), only non-tunneled mode for cloud filter is supported\\n\",\n>+\t\t\t\thw->dev_caps.switch_mode);\n>+\t\t\treturn -EINVAL;\n>+\t\t}\n>+\t}\n>+\n>+\t/* port_type: true for destination port and false for source port\n>+\t * For now, supports only destination port type\n>+\t */\n>+\tif (!port_type) {\n>+\t\tdev_err(&pf->pdev->dev, \"src port type not supported\\n\");\n>+\t\treturn -EINVAL;\n>+\t}\n>+\n>+\t/* Set Bit 7 to be valid */\n>+\tmode = I40E_AQ_SET_SWITCH_BIT7_VALID;\n>+\n>+\t/* Set L4type to both TCP and UDP support */\n>+\tmode |= I40E_AQ_SET_SWITCH_L4_TYPE_BOTH;\n>+\n>+\t/* Set cloud filter mode */\n>+\tmode |= I40E_AQ_SET_SWITCH_MODE_NON_TUNNEL;\n>+\n>+\t/* Prep mode field for set_switch_config */\n>+\tret = i40e_aq_set_switch_config(hw, pf->last_sw_conf_flags,\n>+\t\t\t\t\tpf->last_sw_conf_valid_flags,\n>+\t\t\t\t\tmode, NULL);\n>+\tif (ret && hw->aq.asq_last_status != I40E_AQ_RC_ESRCH)\n>+\t\tdev_err(&pf->pdev->dev,\n>+\t\t\t\"couldn't set switch config bits, err %s aq_err %s\\n\",\n>+\t\t\ti40e_stat_str(hw, ret),\n>+\t\t\ti40e_aq_str(hw,\n>+\t\t\t\t    hw->aq.asq_last_status));\n>+\n>+\treturn ret;\n>+}\n>+\n>+/**\n>  * i40e_create_queue_channel - function to create channel\n>  * @vsi: VSI to be configured\n>  * @ch: ptr to channel (it contains channel specific params)\n>@@ -6735,13 +6839,726 @@ static int i40e_setup_tc(struct net_device *netdev, void *type_data)\n> \treturn ret;\n> }\n> \n>+/**\n>+ * i40e_set_cld_element - sets cloud filter element data\n>+ * @filter: cloud filter rule\n>+ * @cld: ptr to cloud filter element data\n>+ *\n>+ * This is helper function to copy data into cloud filter element\n>+ **/\n>+static inline void\n>+i40e_set_cld_element(struct i40e_cloud_filter *filter,\n>+\t\t     struct i40e_aqc_cloud_filters_element_data *cld)\n>+{\n>+\tint i, j;\n>+\tu32 ipa;\n>+\n>+\tmemset(cld, 0, sizeof(*cld));\n>+\tether_addr_copy(cld->outer_mac, filter->dst_mac);\n>+\tether_addr_copy(cld->inner_mac, filter->src_mac);\n>+\n>+\tif (filter->ip_version == IPV6_VERSION) {\n>+#define IPV6_MAX_INDEX\t(ARRAY_SIZE(filter->dst_ipv6) - 1)\n>+\t\tfor (i = 0, j = 0; i < 4; i++, j += 2) {\n>+\t\t\tipa = be32_to_cpu(filter->dst_ipv6[IPV6_MAX_INDEX - i]);\n>+\t\t\tipa = cpu_to_le32(ipa);\n>+\t\t\tmemcpy(&cld->ipaddr.raw_v6.data[j], &ipa, 4);\n>+\t\t}\n>+\t} else {\n>+\t\tipa = be32_to_cpu(filter->dst_ip);\n>+\t\tmemcpy(&cld->ipaddr.v4.data, &ipa, 4);\n>+\t}\n>+\n>+\tcld->inner_vlan = cpu_to_le16(ntohs(filter->vlan_id));\n>+\n>+\t/* tenant_id is not supported by FW now, once the support is enabled\n>+\t * fill the cld->tenant_id with cpu_to_le32(filter->tenant_id)\n>+\t */\n>+\tif (filter->tenant_id)\n>+\t\treturn;\n>+}\n>+\n>+/**\n>+ * i40e_add_del_cloud_filter - Add/del cloud filter\n>+ * @vsi: pointer to VSI\n>+ * @filter: cloud filter rule\n>+ * @add: if true, add, if false, delete\n>+ *\n>+ * Add or delete a cloud filter for a specific flow spec.\n>+ * Returns 0 if the filter were successfully added.\n>+ **/\n>+static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,\n>+\t\t\t\t     struct i40e_cloud_filter *filter, bool add)\n>+{\n>+\tstruct i40e_aqc_cloud_filters_element_data cld_filter;\n>+\tstruct i40e_pf *pf = vsi->back;\n>+\tint ret;\n>+\tstatic const u16 flag_table[128] = {\n>+\t\t[I40E_CLOUD_FILTER_FLAGS_OMAC]  =\n>+\t\t\tI40E_AQC_ADD_CLOUD_FILTER_OMAC,\n>+\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC]  =\n>+\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC,\n>+\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN]  =\n>+\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN,\n>+\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID] =\n>+\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID,\n>+\t\t[I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC] =\n>+\t\t\tI40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC,\n>+\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID] =\n>+\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID,\n>+\t\t[I40E_CLOUD_FILTER_FLAGS_IIP] =\n>+\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IIP,\n>+\t};\n>+\n>+\tif (filter->flags >= ARRAY_SIZE(flag_table))\n>+\t\treturn I40E_ERR_CONFIG;\n>+\n>+\t/* copy element needed to add cloud filter from filter */\n>+\ti40e_set_cld_element(filter, &cld_filter);\n>+\n>+\tif (filter->tunnel_type != I40E_CLOUD_TNL_TYPE_NONE)\n>+\t\tcld_filter.flags = cpu_to_le16(filter->tunnel_type <<\n>+\t\t\t\t\t     I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT);\n>+\n>+\tif (filter->ip_version == IPV6_VERSION)\n>+\t\tcld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |\n>+\t\t\t\t\t\tI40E_AQC_ADD_CLOUD_FLAGS_IPV6);\n>+\telse\n>+\t\tcld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |\n>+\t\t\t\t\t\tI40E_AQC_ADD_CLOUD_FLAGS_IPV4);\n>+\n>+\tif (add)\n>+\t\tret = i40e_aq_add_cloud_filters(&pf->hw, filter->seid,\n>+\t\t\t\t\t\t&cld_filter, 1);\n>+\telse\n>+\t\tret = i40e_aq_rem_cloud_filters(&pf->hw, filter->seid,\n>+\t\t\t\t\t\t&cld_filter, 1);\n>+\tif (ret)\n>+\t\tdev_dbg(&pf->pdev->dev,\n>+\t\t\t\"Failed to %s cloud filter using l4 port %u, err %d aq_err %d\\n\",\n>+\t\t\tadd ? \"add\" : \"delete\", filter->dst_port, ret,\n>+\t\t\tpf->hw.aq.asq_last_status);\n>+\telse\n>+\t\tdev_info(&pf->pdev->dev,\n>+\t\t\t \"%s cloud filter for VSI: %d\\n\",\n>+\t\t\t add ? \"Added\" : \"Deleted\", filter->seid);\n>+\treturn ret;\n>+}\n>+\n>+/**\n>+ * i40e_add_del_cloud_filter_big_buf - Add/del cloud filter using big_buf\n>+ * @vsi: pointer to VSI\n>+ * @filter: cloud filter rule\n>+ * @add: if true, add, if false, delete\n>+ *\n>+ * Add or delete a cloud filter for a specific flow spec using big buffer.\n>+ * Returns 0 if the filter were successfully added.\n>+ **/\n>+static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,\n>+\t\t\t\t\t     struct i40e_cloud_filter *filter,\n>+\t\t\t\t\t     bool add)\n>+{\n>+\tstruct i40e_aqc_cloud_filters_element_bb cld_filter;\n>+\tstruct i40e_pf *pf = vsi->back;\n>+\tint ret;\n>+\n>+\t/* Both (Outer/Inner) valid mac_addr are not supported */\n>+\tif (is_valid_ether_addr(filter->dst_mac) &&\n>+\t    is_valid_ether_addr(filter->src_mac))\n>+\t\treturn -EINVAL;\n>+\n>+\t/* Make sure port is specified, otherwise bail out, for channel\n>+\t * specific cloud filter needs 'L4 port' to be non-zero\n>+\t */\n>+\tif (!filter->dst_port)\n>+\t\treturn -EINVAL;\n>+\n>+\t/* adding filter using src_port/src_ip is not supported at this stage */\n>+\tif (filter->src_port || filter->src_ip ||\n>+\t    !ipv6_addr_any((struct in6_addr *)&filter->src_ipv6))\n>+\t\treturn -EINVAL;\n>+\n>+\t/* copy element needed to add cloud filter from filter */\n>+\ti40e_set_cld_element(filter, &cld_filter.element);\n>+\n>+\tif (is_valid_ether_addr(filter->dst_mac) ||\n>+\t    is_valid_ether_addr(filter->src_mac) ||\n>+\t    is_multicast_ether_addr(filter->dst_mac) ||\n>+\t    is_multicast_ether_addr(filter->src_mac)) {\n>+\t\t/* MAC + IP : unsupported mode */\n>+\t\tif (filter->dst_ip)\n>+\t\t\treturn -EINVAL;\n>+\n>+\t\t/* since we validated that L4 port must be valid before\n>+\t\t * we get here, start with respective \"flags\" value\n>+\t\t * and update if vlan is present or not\n>+\t\t */\n>+\t\tcld_filter.element.flags =\n>+\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT);\n>+\n>+\t\tif (filter->vlan_id) {\n>+\t\t\tcld_filter.element.flags =\n>+\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT);\n>+\t\t}\n>+\n>+\t} else if (filter->dst_ip || filter->ip_version == IPV6_VERSION) {\n>+\t\tcld_filter.element.flags =\n>+\t\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_IP_PORT);\n>+\t\tif (filter->ip_version == IPV6_VERSION)\n>+\t\t\tcld_filter.element.flags |=\n>+\t\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV6);\n>+\t\telse\n>+\t\t\tcld_filter.element.flags |=\n>+\t\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV4);\n>+\t} else {\n>+\t\tdev_err(&pf->pdev->dev,\n>+\t\t\t\"either mac or ip has to be valid for cloud filter\\n\");\n>+\t\treturn -EINVAL;\n>+\t}\n>+\n>+\t/* Now copy L4 port in Byte 6..7 in general fields */\n>+\tcld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0] =\n>+\t\t\t\t\t\tbe16_to_cpu(filter->dst_port);\n>+\n>+\tif (add) {\n>+\t\tbool proto_type, port_type;\n>+\n>+\t\tproto_type = (filter->ip_proto == IPPROTO_TCP) ? true : false;\n>+\t\tport_type = (filter->port_type & I40E_CLOUD_FILTER_PORT_DEST) ?\n>+\t\t\t     true : false;\n>+\n>+\t\t/* For now, src port based cloud filter for channel is not\n>+\t\t * supported\n>+\t\t */\n>+\t\tif (!port_type) {\n>+\t\t\tdev_err(&pf->pdev->dev,\n>+\t\t\t\t\"unsupported port type (src port)\\n\");\n>+\t\t\treturn -EOPNOTSUPP;\n>+\t\t}\n>+\n>+\t\t/* Validate current device switch mode, change if necessary */\n>+\t\tret = i40e_validate_and_set_switch_mode(vsi, proto_type,\n>+\t\t\t\t\t\t\tport_type);\n>+\t\tif (ret) {\n>+\t\t\tdev_err(&pf->pdev->dev,\n>+\t\t\t\t\"failed to set switch mode, ret %d\\n\",\n>+\t\t\t\tret);\n>+\t\t\treturn ret;\n>+\t\t}\n>+\n>+\t\tret = i40e_aq_add_cloud_filters_bb(&pf->hw, filter->seid,\n>+\t\t\t\t\t\t   &cld_filter, 1);\n>+\t} else {\n>+\t\tret = i40e_aq_rem_cloud_filters_bb(&pf->hw, filter->seid,\n>+\t\t\t\t\t\t   &cld_filter, 1);\n>+\t}\n>+\n>+\tif (ret)\n>+\t\tdev_dbg(&pf->pdev->dev,\n>+\t\t\t\"Failed to %s cloud filter(big buffer) err %d aq_err %d\\n\",\n>+\t\t\tadd ? \"add\" : \"delete\", ret, pf->hw.aq.asq_last_status);\n>+\telse\n>+\t\tdev_info(&pf->pdev->dev,\n>+\t\t\t \"%s cloud filter for VSI: %d, L4 port: %d\\n\",\n>+\t\t\t add ? \"add\" : \"delete\", filter->seid,\n>+\t\t\t ntohs(filter->dst_port));\n>+\treturn ret;\n>+}\n>+\n>+/**\n>+ * i40e_parse_cls_flower - Parse tc flower filters provided by kernel\n>+ * @vsi: Pointer to VSI\n>+ * @cls_flower: Pointer to struct tc_cls_flower_offload\n>+ * @filter: Pointer to cloud filter structure\n>+ *\n>+ **/\n>+static int i40e_parse_cls_flower(struct i40e_vsi *vsi,\n>+\t\t\t\t struct tc_cls_flower_offload *f,\n>+\t\t\t\t struct i40e_cloud_filter *filter)\n>+{\n>+\tstruct i40e_pf *pf = vsi->back;\n>+\tu16 addr_type = 0;\n>+\tu8 field_flags = 0;\n>+\n>+\tif (f->dissector->used_keys &\n>+\t    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |\n>+\t      BIT(FLOW_DISSECTOR_KEY_BASIC) |\n>+\t      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |\n>+\t      BIT(FLOW_DISSECTOR_KEY_VLAN) |\n>+\t      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |\n>+\t      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |\n>+\t      BIT(FLOW_DISSECTOR_KEY_PORTS) |\n>+\t      BIT(FLOW_DISSECTOR_KEY_ENC_KEYID))) {\n>+\t\tdev_err(&pf->pdev->dev, \"Unsupported key used: 0x%x\\n\",\n>+\t\t\tf->dissector->used_keys);\n>+\t\treturn -EOPNOTSUPP;\n>+\t}\n>+\n>+\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {\n>+\t\tstruct flow_dissector_key_keyid *key =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ENC_KEYID,\n>+\t\t\t\t\t\t  f->key);\n>+\n>+\t\tstruct flow_dissector_key_keyid *mask =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ENC_KEYID,\n>+\t\t\t\t\t\t  f->mask);\n>+\n>+\t\tif (mask->keyid != 0)\n>+\t\t\tfield_flags |= I40E_CLOUD_FIELD_TEN_ID;\n>+\n>+\t\tfilter->tenant_id = be32_to_cpu(key->keyid);\n>+\t}\n>+\n>+\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {\n>+\t\tstruct flow_dissector_key_basic *key =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_BASIC,\n>+\t\t\t\t\t\t  f->key);\n>+\n>+\t\tfilter->ip_proto = key->ip_proto;\n>+\t}\n>+\n>+\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {\n>+\t\tstruct flow_dissector_key_eth_addrs *key =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ETH_ADDRS,\n>+\t\t\t\t\t\t  f->key);\n>+\n>+\t\tstruct flow_dissector_key_eth_addrs *mask =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ETH_ADDRS,\n>+\t\t\t\t\t\t  f->mask);\n>+\n>+\t\t/* use is_broadcast and is_zero to check for all 0xf or 0 */\n>+\t\tif (!is_zero_ether_addr(mask->dst)) {\n>+\t\t\tif (is_broadcast_ether_addr(mask->dst)) {\n>+\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_OMAC;\n>+\t\t\t} else {\n>+\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ether dest mask %pM\\n\",\n>+\t\t\t\t\tmask->dst);\n>+\t\t\t\treturn I40E_ERR_CONFIG;\n>+\t\t\t}\n>+\t\t}\n>+\n>+\t\tif (!is_zero_ether_addr(mask->src)) {\n>+\t\t\tif (is_broadcast_ether_addr(mask->src)) {\n>+\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IMAC;\n>+\t\t\t} else {\n>+\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ether src mask %pM\\n\",\n>+\t\t\t\t\tmask->src);\n>+\t\t\t\treturn I40E_ERR_CONFIG;\n>+\t\t\t}\n>+\t\t}\n>+\t\tether_addr_copy(filter->dst_mac, key->dst);\n>+\t\tether_addr_copy(filter->src_mac, key->src);\n>+\t}\n>+\n>+\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {\n>+\t\tstruct flow_dissector_key_vlan *key =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_VLAN,\n>+\t\t\t\t\t\t  f->key);\n>+\t\tstruct flow_dissector_key_vlan *mask =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_VLAN,\n>+\t\t\t\t\t\t  f->mask);\n>+\n>+\t\tif (mask->vlan_id) {\n>+\t\t\tif (mask->vlan_id == VLAN_VID_MASK) {\n>+\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IVLAN;\n>+\n>+\t\t\t} else {\n>+\t\t\t\tdev_err(&pf->pdev->dev, \"Bad vlan mask 0x%04x\\n\",\n>+\t\t\t\t\tmask->vlan_id);\n>+\t\t\t\treturn I40E_ERR_CONFIG;\n>+\t\t\t}\n>+\t\t}\n>+\n>+\t\tfilter->vlan_id = cpu_to_be16(key->vlan_id);\n>+\t}\n>+\n>+\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {\n>+\t\tstruct flow_dissector_key_control *key =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_CONTROL,\n>+\t\t\t\t\t\t  f->key);\n>+\n>+\t\taddr_type = key->addr_type;\n>+\t}\n>+\n>+\tif (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {\n>+\t\tstruct flow_dissector_key_ipv4_addrs *key =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV4_ADDRS,\n>+\t\t\t\t\t\t  f->key);\n>+\t\tstruct flow_dissector_key_ipv4_addrs *mask =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV4_ADDRS,\n>+\t\t\t\t\t\t  f->mask);\n>+\n>+\t\tif (mask->dst) {\n>+\t\t\tif (mask->dst == cpu_to_be32(0xffffffff)) {\n>+\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>+\t\t\t} else {\n>+\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ip dst mask 0x%08x\\n\",\n>+\t\t\t\t\tbe32_to_cpu(mask->dst));\n>+\t\t\t\treturn I40E_ERR_CONFIG;\n>+\t\t\t}\n>+\t\t}\n>+\n>+\t\tif (mask->src) {\n>+\t\t\tif (mask->src == cpu_to_be32(0xffffffff)) {\n>+\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>+\t\t\t} else {\n>+\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ip src mask 0x%08x\\n\",\n>+\t\t\t\t\tbe32_to_cpu(mask->dst));\n>+\t\t\t\treturn I40E_ERR_CONFIG;\n>+\t\t\t}\n>+\t\t}\n>+\n>+\t\tif (field_flags & I40E_CLOUD_FIELD_TEN_ID) {\n>+\t\t\tdev_err(&pf->pdev->dev, \"Tenant id not allowed for ip filter\\n\");\n>+\t\t\treturn I40E_ERR_CONFIG;\n>+\t\t}\n>+\t\tfilter->dst_ip = key->dst;\n>+\t\tfilter->src_ip = key->src;\n>+\t\tfilter->ip_version = IPV4_VERSION;\n>+\t}\n>+\n>+\tif (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {\n>+\t\tstruct flow_dissector_key_ipv6_addrs *key =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV6_ADDRS,\n>+\t\t\t\t\t\t  f->key);\n>+\t\tstruct flow_dissector_key_ipv6_addrs *mask =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV6_ADDRS,\n>+\t\t\t\t\t\t  f->mask);\n>+\n>+\t\t/* src and dest IPV6 address should not be LOOPBACK\n>+\t\t * (0:0:0:0:0:0:0:1), which can be represented as ::1\n>+\t\t */\n>+\t\tif (ipv6_addr_loopback(&key->dst) ||\n>+\t\t    ipv6_addr_loopback(&key->src)) {\n>+\t\t\tdev_err(&pf->pdev->dev,\n>+\t\t\t\t\"Bad ipv6, addr is LOOPBACK\\n\");\n>+\t\t\treturn I40E_ERR_CONFIG;\n>+\t\t}\n>+\t\tif (!ipv6_addr_any(&mask->dst) || !ipv6_addr_any(&mask->src))\n>+\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>+\n>+\t\tmemcpy(&filter->src_ipv6, &key->src.s6_addr32,\n>+\t\t       sizeof(filter->src_ipv6));\n>+\t\tmemcpy(&filter->dst_ipv6, &key->dst.s6_addr32,\n>+\t\t       sizeof(filter->dst_ipv6));\n>+\n>+\t\t/* mark it as IPv6 filter, to be used later */\n>+\t\tfilter->ip_version = IPV6_VERSION;\n>+\t}\n>+\n>+\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {\n>+\t\tstruct flow_dissector_key_ports *key =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_PORTS,\n>+\t\t\t\t\t\t  f->key);\n>+\t\tstruct flow_dissector_key_ports *mask =\n>+\t\t\tskb_flow_dissector_target(f->dissector,\n>+\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_PORTS,\n>+\t\t\t\t\t\t  f->mask);\n>+\n>+\t\tif (mask->src) {\n>+\t\t\tif (mask->src == cpu_to_be16(0xffff)) {\n>+\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>+\t\t\t} else {\n>+\t\t\t\tdev_err(&pf->pdev->dev, \"Bad src port mask 0x%04x\\n\",\n>+\t\t\t\t\tbe16_to_cpu(mask->src));\n>+\t\t\t\treturn I40E_ERR_CONFIG;\n>+\t\t\t}\n>+\t\t}\n>+\n>+\t\tif (mask->dst) {\n>+\t\t\tif (mask->dst == cpu_to_be16(0xffff)) {\n>+\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>+\t\t\t} else {\n>+\t\t\t\tdev_err(&pf->pdev->dev, \"Bad dst port mask 0x%04x\\n\",\n>+\t\t\t\t\tbe16_to_cpu(mask->dst));\n>+\t\t\t\treturn I40E_ERR_CONFIG;\n>+\t\t\t}\n>+\t\t}\n>+\n>+\t\tfilter->dst_port = key->dst;\n>+\t\tfilter->src_port = key->src;\n>+\n>+\t\t/* For now, only supports destination port*/\n>+\t\tfilter->port_type |= I40E_CLOUD_FILTER_PORT_DEST;\n>+\n>+\t\tswitch (filter->ip_proto) {\n>+\t\tcase IPPROTO_TCP:\n>+\t\tcase IPPROTO_UDP:\n>+\t\t\tbreak;\n>+\t\tdefault:\n>+\t\t\tdev_err(&pf->pdev->dev,\n>+\t\t\t\t\"Only UDP and TCP transport are supported\\n\");\n>+\t\t\treturn -EINVAL;\n>+\t\t}\n>+\t}\n>+\tfilter->flags = field_flags;\n>+\treturn 0;\n>+}\n>+\n>+/**\n>+ * i40e_handle_redirect_action: Forward to a traffic class on the device\n>+ * @vsi: Pointer to VSI\n>+ * @ifindex: ifindex of the device to forwared to\n>+ * @tc: traffic class index on the device\n>+ * @filter: Pointer to cloud filter structure\n>+ *\n>+ **/\n>+static int i40e_handle_redirect_action(struct i40e_vsi *vsi, int ifindex, u8 tc,\n>+\t\t\t\t       struct i40e_cloud_filter *filter)\n>+{\n>+\tstruct i40e_channel *ch, *ch_tmp;\n>+\n>+\t/* redirect to a traffic class on the same device */\n>+\tif (vsi->netdev->ifindex == ifindex) {\n>+\t\tif (tc == 0) {\n>+\t\t\tfilter->seid = vsi->seid;\n>+\t\t\treturn 0;\n>+\t\t} else if (vsi->tc_config.enabled_tc & BIT(tc)) {\n>+\t\t\tif (!filter->dst_port) {\n>+\t\t\t\tdev_err(&vsi->back->pdev->dev,\n>+\t\t\t\t\t\"Specify destination port to redirect to traffic class that is not default\\n\");\n>+\t\t\t\treturn -EINVAL;\n>+\t\t\t}\n>+\t\t\tif (list_empty(&vsi->ch_list))\n>+\t\t\t\treturn -EINVAL;\n>+\t\t\tlist_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list,\n>+\t\t\t\t\t\t list) {\n>+\t\t\t\tif (ch->seid == vsi->tc_seid_map[tc])\n>+\t\t\t\t\tfilter->seid = ch->seid;\n>+\t\t\t}\n>+\t\t\treturn 0;\n>+\t\t}\n>+\t}\n>+\treturn -EINVAL;\n>+}\n>+\n>+/**\n>+ * i40e_parse_tc_actions - Parse tc actions\n>+ * @vsi: Pointer to VSI\n>+ * @cls_flower: Pointer to struct tc_cls_flower_offload\n>+ * @filter: Pointer to cloud filter structure\n>+ *\n>+ **/\n>+static int i40e_parse_tc_actions(struct i40e_vsi *vsi, struct tcf_exts *exts,\n>+\t\t\t\t struct i40e_cloud_filter *filter)\n>+{\n>+\tconst struct tc_action *a;\n>+\tLIST_HEAD(actions);\n>+\tint err;\n>+\n>+\tif (!tcf_exts_has_actions(exts))\n>+\t\treturn -EINVAL;\n>+\n>+\ttcf_exts_to_list(exts, &actions);\n>+\tlist_for_each_entry(a, &actions, list) {\n>+\t\t/* Drop action */\n>+\t\tif (is_tcf_gact_shot(a)) {\n>+\t\t\tdev_err(&vsi->back->pdev->dev,\n>+\t\t\t\t\"Cloud filters do not support the drop action.\\n\");\n>+\t\t\treturn -EOPNOTSUPP;\n>+\t\t}\n>+\n>+\t\t/* Redirect to a traffic class on the same device */\n>+\t\tif (!is_tcf_mirred_egress_redirect(a) && is_tcf_mirred_tc(a)) {\n>+\t\t\tint ifindex = tcf_mirred_ifindex(a);\n>+\t\t\tu8 tc = tcf_mirred_tc(a);\n>+\n>+\t\t\terr = i40e_handle_redirect_action(vsi, ifindex, tc,\n>+\t\t\t\t\t\t\t  filter);\n>+\t\t\tif (err == 0)\n>+\t\t\t\treturn err;\n>+\t\t}\n>+\t}\n>+\treturn -EINVAL;\n>+}\n>+\n>+/**\n>+ * i40e_configure_clsflower - Configure tc flower filters\n>+ * @vsi: Pointer to VSI\n>+ * @cls_flower: Pointer to struct tc_cls_flower_offload\n>+ *\n>+ **/\n>+static int i40e_configure_clsflower(struct i40e_vsi *vsi,\n>+\t\t\t\t    struct tc_cls_flower_offload *cls_flower)\n>+{\n>+\tstruct i40e_cloud_filter *filter = NULL;\n>+\tstruct i40e_pf *pf = vsi->back;\n>+\tint err = 0;\n>+\n>+\tif (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state) ||\n>+\t    test_bit(__I40E_RESET_INTR_RECEIVED, pf->state))\n>+\t\treturn -EBUSY;\n>+\n>+\tif (pf->fdir_pf_active_filters ||\n>+\t    (!hlist_empty(&pf->fdir_filter_list))) {\n>+\t\tdev_err(&vsi->back->pdev->dev,\n>+\t\t\t\"Flow Director Sideband filters exists, turn ntuple off to configure cloud filters\\n\");\n>+\t\treturn -EINVAL;\n>+\t}\n>+\n>+\tif (vsi->back->flags & I40E_FLAG_FD_SB_ENABLED) {\n>+\t\tdev_err(&vsi->back->pdev->dev,\n>+\t\t\t\"Disable Flow Director Sideband, configuring Cloud filters via tc-flower\\n\");\n>+\t\tvsi->back->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>+\t\tvsi->back->flags |= I40E_FLAG_FD_SB_TO_CLOUD_FILTER;\n>+\t}\n>+\n>+\tfilter = kzalloc(sizeof(*filter), GFP_KERNEL);\n>+\tif (!filter)\n>+\t\treturn -ENOMEM;\n>+\n>+\tfilter->cookie = cls_flower->cookie;\n>+\n>+\terr = i40e_parse_cls_flower(vsi, cls_flower, filter);\n>+\tif (err < 0)\n>+\t\tgoto err;\n>+\n>+\terr = i40e_parse_tc_actions(vsi, cls_flower->exts, filter);\n>+\tif (err < 0)\n>+\t\tgoto err;\n>+\n>+\t/* Add cloud filter */\n>+\tif (filter->dst_port)\n>+\t\terr = i40e_add_del_cloud_filter_big_buf(vsi, filter, true);\n>+\telse\n>+\t\terr = i40e_add_del_cloud_filter(vsi, filter, true);\n>+\n>+\tif (err) {\n>+\t\tdev_err(&pf->pdev->dev,\n>+\t\t\t\"Failed to add cloud filter, err %s\\n\",\n>+\t\t\ti40e_stat_str(&pf->hw, err));\n>+\t\terr = i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);\n>+\t\tgoto err;\n>+\t}\n>+\n>+\t/* add filter to the ordered list */\n>+\tINIT_HLIST_NODE(&filter->cloud_node);\n>+\n>+\thlist_add_head(&filter->cloud_node, &pf->cloud_filter_list);\n>+\n>+\tpf->num_cloud_filters++;\n>+\n>+\treturn err;\n>+err:\n>+\tkfree(filter);\n>+\treturn err;\n>+}\n>+\n>+/**\n>+ * i40e_find_cloud_filter - Find the could filter in the list\n>+ * @vsi: Pointer to VSI\n>+ * @cookie: filter specific cookie\n>+ *\n>+ **/\n>+static struct i40e_cloud_filter *i40e_find_cloud_filter(struct i40e_vsi *vsi,\n>+\t\t\t\t\t\t\tunsigned long *cookie)\n>+{\n>+\tstruct i40e_cloud_filter *filter = NULL;\n>+\tstruct hlist_node *node2;\n>+\n>+\thlist_for_each_entry_safe(filter, node2,\n>+\t\t\t\t  &vsi->back->cloud_filter_list, cloud_node)\n>+\t\tif (!memcmp(cookie, &filter->cookie, sizeof(filter->cookie)))\n>+\t\t\treturn filter;\n>+\treturn NULL;\n>+}\n>+\n>+/**\n>+ * i40e_delete_clsflower - Remove tc flower filters\n>+ * @vsi: Pointer to VSI\n>+ * @cls_flower: Pointer to struct tc_cls_flower_offload\n>+ *\n>+ **/\n>+static int i40e_delete_clsflower(struct i40e_vsi *vsi,\n>+\t\t\t\t struct tc_cls_flower_offload *cls_flower)\n>+{\n>+\tstruct i40e_cloud_filter *filter = NULL;\n>+\tstruct i40e_pf *pf = vsi->back;\n>+\tint err = 0;\n>+\n>+\tfilter = i40e_find_cloud_filter(vsi, &cls_flower->cookie);\n>+\n>+\tif (!filter)\n>+\t\treturn -EINVAL;\n>+\n>+\thash_del(&filter->cloud_node);\n>+\n>+\tif (filter->dst_port)\n>+\t\terr = i40e_add_del_cloud_filter_big_buf(vsi, filter, false);\n>+\telse\n>+\t\terr = i40e_add_del_cloud_filter(vsi, filter, false);\n>+\tif (err) {\n>+\t\tkfree(filter);\n>+\t\tdev_err(&pf->pdev->dev,\n>+\t\t\t\"Failed to delete cloud filter, err %s\\n\",\n>+\t\t\ti40e_stat_str(&pf->hw, err));\n>+\t\treturn i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);\n>+\t}\n>+\n>+\tkfree(filter);\n>+\tpf->num_cloud_filters--;\n>+\n>+\tif (!pf->num_cloud_filters)\n>+\t\tif ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&\n>+\t\t    !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {\n>+\t\t\tpf->flags |= I40E_FLAG_FD_SB_ENABLED;\n>+\t\t\tpf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;\n>+\t\t\tpf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;\n>+\t\t}\n>+\treturn 0;\n>+}\n>+\n>+/**\n>+ * i40e_setup_tc_cls_flower - flower classifier offloads\n>+ * @netdev: net device to configure\n>+ * @type_data: offload data\n>+ **/\n>+static int i40e_setup_tc_cls_flower(struct net_device *netdev,\n>+\t\t\t\t    struct tc_cls_flower_offload *cls_flower)\n>+{\n>+\tstruct i40e_netdev_priv *np = netdev_priv(netdev);\n>+\tstruct i40e_vsi *vsi = np->vsi;\n>+\n>+\tif (!is_classid_clsact_ingress(cls_flower->common.classid) ||\n>+\t    cls_flower->common.chain_index)\n>+\t\treturn -EOPNOTSUPP;\n>+\n>+\tswitch (cls_flower->command) {\n>+\tcase TC_CLSFLOWER_REPLACE:\n>+\t\treturn i40e_configure_clsflower(vsi, cls_flower);\n>+\tcase TC_CLSFLOWER_DESTROY:\n>+\t\treturn i40e_delete_clsflower(vsi, cls_flower);\n>+\tcase TC_CLSFLOWER_STATS:\n>+\t\treturn -EOPNOTSUPP;\n>+\tdefault:\n>+\t\treturn -EINVAL;\n>+\t}\n>+}\n>+\n> static int __i40e_setup_tc(struct net_device *netdev, enum tc_setup_type type,\n> \t\t\t   void *type_data)\n> {\n>-\tif (type != TC_SETUP_MQPRIO)\n>+\tswitch (type) {\n>+\tcase TC_SETUP_MQPRIO:\n>+\t\treturn i40e_setup_tc(netdev, type_data);\n>+\tcase TC_SETUP_CLSFLOWER:\n>+\t\treturn i40e_setup_tc_cls_flower(netdev, type_data);\n>+\tdefault:\n> \t\treturn -EOPNOTSUPP;\n>-\n>-\treturn i40e_setup_tc(netdev, type_data);\n>+\t}\n> }\n> \n> /**\n>@@ -6939,6 +7756,13 @@ static void i40e_cloud_filter_exit(struct i40e_pf *pf)\n> \t\tkfree(cfilter);\n> \t}\n> \tpf->num_cloud_filters = 0;\n>+\n>+\tif ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&\n>+\t    !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {\n>+\t\tpf->flags |= I40E_FLAG_FD_SB_ENABLED;\n>+\t\tpf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;\n>+\t\tpf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;\n>+\t}\n> }\n> \n> /**\n>@@ -8046,7 +8870,8 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb)\n>  * i40e_get_capabilities - get info about the HW\n>  * @pf: the PF struct\n>  **/\n>-static int i40e_get_capabilities(struct i40e_pf *pf)\n>+static int i40e_get_capabilities(struct i40e_pf *pf,\n>+\t\t\t\t enum i40e_admin_queue_opc list_type)\n> {\n> \tstruct i40e_aqc_list_capabilities_element_resp *cap_buf;\n> \tu16 data_size;\n>@@ -8061,9 +8886,8 @@ static int i40e_get_capabilities(struct i40e_pf *pf)\n> \n> \t\t/* this loads the data into the hw struct for us */\n> \t\terr = i40e_aq_discover_capabilities(&pf->hw, cap_buf, buf_len,\n>-\t\t\t\t\t    &data_size,\n>-\t\t\t\t\t    i40e_aqc_opc_list_func_capabilities,\n>-\t\t\t\t\t    NULL);\n>+\t\t\t\t\t\t    &data_size, list_type,\n>+\t\t\t\t\t\t    NULL);\n> \t\t/* data loaded, buffer no longer needed */\n> \t\tkfree(cap_buf);\n> \n>@@ -8080,26 +8904,44 @@ static int i40e_get_capabilities(struct i40e_pf *pf)\n> \t\t}\n> \t} while (err);\n> \n>-\tif (pf->hw.debug_mask & I40E_DEBUG_USER)\n>-\t\tdev_info(&pf->pdev->dev,\n>-\t\t\t \"pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\\n\",\n>-\t\t\t pf->hw.pf_id, pf->hw.func_caps.num_vfs,\n>-\t\t\t pf->hw.func_caps.num_msix_vectors,\n>-\t\t\t pf->hw.func_caps.num_msix_vectors_vf,\n>-\t\t\t pf->hw.func_caps.fd_filters_guaranteed,\n>-\t\t\t pf->hw.func_caps.fd_filters_best_effort,\n>-\t\t\t pf->hw.func_caps.num_tx_qp,\n>-\t\t\t pf->hw.func_caps.num_vsis);\n>-\n>+\tif (pf->hw.debug_mask & I40E_DEBUG_USER) {\n>+\t\tif (list_type == i40e_aqc_opc_list_func_capabilities) {\n>+\t\t\tdev_info(&pf->pdev->dev,\n>+\t\t\t\t \"pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\\n\",\n>+\t\t\t\t pf->hw.pf_id, pf->hw.func_caps.num_vfs,\n>+\t\t\t\t pf->hw.func_caps.num_msix_vectors,\n>+\t\t\t\t pf->hw.func_caps.num_msix_vectors_vf,\n>+\t\t\t\t pf->hw.func_caps.fd_filters_guaranteed,\n>+\t\t\t\t pf->hw.func_caps.fd_filters_best_effort,\n>+\t\t\t\t pf->hw.func_caps.num_tx_qp,\n>+\t\t\t\t pf->hw.func_caps.num_vsis);\n>+\t\t} else if (list_type == i40e_aqc_opc_list_dev_capabilities) {\n>+\t\t\tdev_info(&pf->pdev->dev,\n>+\t\t\t\t \"switch_mode=0x%04x, function_valid=0x%08x\\n\",\n>+\t\t\t\t pf->hw.dev_caps.switch_mode,\n>+\t\t\t\t pf->hw.dev_caps.valid_functions);\n>+\t\t\tdev_info(&pf->pdev->dev,\n>+\t\t\t\t \"SR-IOV=%d, num_vfs for all function=%u\\n\",\n>+\t\t\t\t pf->hw.dev_caps.sr_iov_1_1,\n>+\t\t\t\t pf->hw.dev_caps.num_vfs);\n>+\t\t\tdev_info(&pf->pdev->dev,\n>+\t\t\t\t \"num_vsis=%u, num_rx:%u, num_tx=%u\\n\",\n>+\t\t\t\t pf->hw.dev_caps.num_vsis,\n>+\t\t\t\t pf->hw.dev_caps.num_rx_qp,\n>+\t\t\t\t pf->hw.dev_caps.num_tx_qp);\n>+\t\t}\n>+\t}\n>+\tif (list_type == i40e_aqc_opc_list_func_capabilities) {\n> #define DEF_NUM_VSI (1 + (pf->hw.func_caps.fcoe ? 1 : 0) \\\n> \t\t       + pf->hw.func_caps.num_vfs)\n>-\tif (pf->hw.revision_id == 0 && (DEF_NUM_VSI > pf->hw.func_caps.num_vsis)) {\n>-\t\tdev_info(&pf->pdev->dev,\n>-\t\t\t \"got num_vsis %d, setting num_vsis to %d\\n\",\n>-\t\t\t pf->hw.func_caps.num_vsis, DEF_NUM_VSI);\n>-\t\tpf->hw.func_caps.num_vsis = DEF_NUM_VSI;\n>+\t\tif (pf->hw.revision_id == 0 &&\n>+\t\t    (pf->hw.func_caps.num_vsis < DEF_NUM_VSI)) {\n>+\t\t\tdev_info(&pf->pdev->dev,\n>+\t\t\t\t \"got num_vsis %d, setting num_vsis to %d\\n\",\n>+\t\t\t\t pf->hw.func_caps.num_vsis, DEF_NUM_VSI);\n>+\t\t\tpf->hw.func_caps.num_vsis = DEF_NUM_VSI;\n>+\t\t}\n> \t}\n>-\n> \treturn 0;\n> }\n> \n>@@ -8141,6 +8983,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)\n> \t\tif (!vsi) {\n> \t\t\tdev_info(&pf->pdev->dev, \"Couldn't create FDir VSI\\n\");\n> \t\t\tpf->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>+\t\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n> \t\t\treturn;\n> \t\t}\n> \t}\n>@@ -8163,6 +9006,48 @@ static void i40e_fdir_teardown(struct i40e_pf *pf)\n> }\n> \n> /**\n>+ * i40e_rebuild_cloud_filters - Rebuilds cloud filters for VSIs\n>+ * @vsi: PF main vsi\n>+ * @seid: seid of main or channel VSIs\n>+ *\n>+ * Rebuilds cloud filters associated with main VSI and channel VSIs if they\n>+ * existed before reset\n>+ **/\n>+static int i40e_rebuild_cloud_filters(struct i40e_vsi *vsi, u16 seid)\n>+{\n>+\tstruct i40e_cloud_filter *cfilter;\n>+\tstruct i40e_pf *pf = vsi->back;\n>+\tstruct hlist_node *node;\n>+\ti40e_status ret;\n>+\n>+\t/* Add cloud filters back if they exist */\n>+\tif (hlist_empty(&pf->cloud_filter_list))\n>+\t\treturn 0;\n>+\n>+\thlist_for_each_entry_safe(cfilter, node, &pf->cloud_filter_list,\n>+\t\t\t\t  cloud_node) {\n>+\t\tif (cfilter->seid != seid)\n>+\t\t\tcontinue;\n>+\n>+\t\tif (cfilter->dst_port)\n>+\t\t\tret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter,\n>+\t\t\t\t\t\t\t\ttrue);\n>+\t\telse\n>+\t\t\tret = i40e_add_del_cloud_filter(vsi, cfilter, true);\n>+\n>+\t\tif (ret) {\n>+\t\t\tdev_dbg(&pf->pdev->dev,\n>+\t\t\t\t\"Failed to rebuild cloud filter, err %s aq_err %s\\n\",\n>+\t\t\t\ti40e_stat_str(&pf->hw, ret),\n>+\t\t\t\ti40e_aq_str(&pf->hw,\n>+\t\t\t\t\t    pf->hw.aq.asq_last_status));\n>+\t\t\treturn ret;\n>+\t\t}\n>+\t}\n>+\treturn 0;\n>+}\n>+\n>+/**\n>  * i40e_rebuild_channels - Rebuilds channel VSIs if they existed before reset\n>  * @vsi: PF main vsi\n>  *\n>@@ -8199,6 +9084,13 @@ static int i40e_rebuild_channels(struct i40e_vsi *vsi)\n> \t\t\t\t\t\tI40E_BW_CREDIT_DIVISOR,\n> \t\t\t\tch->seid);\n> \t\t}\n>+\t\tret = i40e_rebuild_cloud_filters(vsi, ch->seid);\n>+\t\tif (ret) {\n>+\t\t\tdev_dbg(&vsi->back->pdev->dev,\n>+\t\t\t\t\"Failed to rebuild cloud filters for channel VSI %u\\n\",\n>+\t\t\t\tch->seid);\n>+\t\t\treturn ret;\n>+\t\t}\n> \t}\n> \treturn 0;\n> }\n>@@ -8365,7 +9257,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)\n> \t\ti40e_verify_eeprom(pf);\n> \n> \ti40e_clear_pxe_mode(hw);\n>-\tret = i40e_get_capabilities(pf);\n>+\tret = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);\n> \tif (ret)\n> \t\tgoto end_core_reset;\n> \n>@@ -8482,6 +9374,10 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)\n> \t\t\tgoto end_unlock;\n> \t}\n> \n>+\tret = i40e_rebuild_cloud_filters(vsi, vsi->seid);\n>+\tif (ret)\n>+\t\tgoto end_unlock;\n>+\n> \t/* PF Main VSI is rebuild by now, go ahead and rebuild channel VSIs\n> \t * for this main VSI if they exist\n> \t */\n>@@ -9404,6 +10300,7 @@ static int i40e_init_msix(struct i40e_pf *pf)\n> \t    (pf->num_fdsb_msix == 0)) {\n> \t\tdev_info(&pf->pdev->dev, \"Sideband Flowdir disabled, not enough MSI-X vectors\\n\");\n> \t\tpf->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>+\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n> \t}\n> \tif ((pf->flags & I40E_FLAG_VMDQ_ENABLED) &&\n> \t    (pf->num_vmdq_msix == 0)) {\n>@@ -9521,6 +10418,7 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)\n> \t\t\t\t       I40E_FLAG_FD_SB_ENABLED\t|\n> \t\t\t\t       I40E_FLAG_FD_ATR_ENABLED\t|\n> \t\t\t\t       I40E_FLAG_VMDQ_ENABLED);\n>+\t\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n> \n> \t\t\t/* rework the queue expectations without MSIX */\n> \t\t\ti40e_determine_queue_usage(pf);\n>@@ -10263,9 +11161,13 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)\n> \t\t/* Enable filters and mark for reset */\n> \t\tif (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))\n> \t\t\tneed_reset = true;\n>-\t\t/* enable FD_SB only if there is MSI-X vector */\n>-\t\tif (pf->num_fdsb_msix > 0)\n>+\t\t/* enable FD_SB only if there is MSI-X vector and no cloud\n>+\t\t * filters exist\n>+\t\t */\n>+\t\tif (pf->num_fdsb_msix > 0 && !pf->num_cloud_filters) {\n> \t\t\tpf->flags |= I40E_FLAG_FD_SB_ENABLED;\n>+\t\t\tpf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;\n>+\t\t}\n> \t} else {\n> \t\t/* turn off filters, mark for reset and clear SW filter list */\n> \t\tif (pf->flags & I40E_FLAG_FD_SB_ENABLED) {\n>@@ -10274,6 +11176,8 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)\n> \t\t}\n> \t\tpf->flags &= ~(I40E_FLAG_FD_SB_ENABLED |\n> \t\t\t       I40E_FLAG_FD_SB_AUTO_DISABLED);\n>+\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>+\n> \t\t/* reset fd counters */\n> \t\tpf->fd_add_err = 0;\n> \t\tpf->fd_atr_cnt = 0;\n>@@ -10857,7 +11761,8 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)\n> \t\tnetdev->hw_features |= NETIF_F_NTUPLE;\n> \thw_features = hw_enc_features\t\t|\n> \t\t      NETIF_F_HW_VLAN_CTAG_TX\t|\n>-\t\t      NETIF_F_HW_VLAN_CTAG_RX;\n>+\t\t      NETIF_F_HW_VLAN_CTAG_RX\t|\n>+\t\t      NETIF_F_HW_TC;\n> \n> \tnetdev->hw_features |= hw_features;\n> \n>@@ -12159,8 +13064,10 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)\n> \t*/\n> \n> \tif ((pf->hw.pf_id == 0) &&\n>-\t    !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT))\n>+\t    !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT)) {\n> \t\tflags = I40E_AQ_SET_SWITCH_CFG_PROMISC;\n>+\t\tpf->last_sw_conf_flags = flags;\n>+\t}\n> \n> \tif (pf->hw.pf_id == 0) {\n> \t\tu16 valid_flags;\n>@@ -12176,6 +13083,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)\n> \t\t\t\t\t     pf->hw.aq.asq_last_status));\n> \t\t\t/* not a fatal problem, just keep going */\n> \t\t}\n>+\t\tpf->last_sw_conf_valid_flags = valid_flags;\n> \t}\n> \n> \t/* first time setup */\n>@@ -12273,6 +13181,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)\n> \t\t\t       I40E_FLAG_DCB_ENABLED\t|\n> \t\t\t       I40E_FLAG_SRIOV_ENABLED\t|\n> \t\t\t       I40E_FLAG_VMDQ_ENABLED);\n>+\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n> \t} else if (!(pf->flags & (I40E_FLAG_RSS_ENABLED |\n> \t\t\t\t  I40E_FLAG_FD_SB_ENABLED |\n> \t\t\t\t  I40E_FLAG_FD_ATR_ENABLED |\n>@@ -12287,6 +13196,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)\n> \t\t\t       I40E_FLAG_FD_ATR_ENABLED\t|\n> \t\t\t       I40E_FLAG_DCB_ENABLED\t|\n> \t\t\t       I40E_FLAG_VMDQ_ENABLED);\n>+\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n> \t} else {\n> \t\t/* Not enough queues for all TCs */\n> \t\tif ((pf->flags & I40E_FLAG_DCB_CAPABLE) &&\n>@@ -12310,6 +13220,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)\n> \t\t\tqueues_left -= 1; /* save 1 queue for FD */\n> \t\t} else {\n> \t\t\tpf->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>+\t\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n> \t\t\tdev_info(&pf->pdev->dev, \"not enough queues for Flow Director. Flow Director feature is disabled\\n\");\n> \t\t}\n> \t}\n>@@ -12613,7 +13524,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n> \t\tdev_warn(&pdev->dev, \"This device is a pre-production adapter/LOM. Please be aware there may be issues with your hardware. If you are experiencing problems please contact your Intel or hardware representative who provided you with this hardware.\\n\");\n> \n> \ti40e_clear_pxe_mode(hw);\n>-\terr = i40e_get_capabilities(pf);\n>+\terr = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);\n> \tif (err)\n> \t\tgoto err_adminq_setup;\n> \n>diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n>index 92869f5..3bb6659 100644\n>--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n>+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n>@@ -283,6 +283,22 @@ i40e_status i40e_aq_query_switch_comp_bw_config(struct i40e_hw *hw,\n> \t\tstruct i40e_asq_cmd_details *cmd_details);\n> i40e_status i40e_aq_resume_port_tx(struct i40e_hw *hw,\n> \t\t\t\t   struct i40e_asq_cmd_details *cmd_details);\n>+i40e_status\n>+i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>+\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>+\t\t\t     u8 filter_count);\n>+enum i40e_status_code\n>+i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 vsi,\n>+\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>+\t\t\t  u8 filter_count);\n>+enum i40e_status_code\n>+i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 vsi,\n>+\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>+\t\t\t  u8 filter_count);\n>+i40e_status\n>+i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>+\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>+\t\t\t     u8 filter_count);\n> i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,\n> \t\t\t       struct i40e_lldp_variables *lldp_cfg);\n> /* i40e_common */\n>diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h\n>index c019f46..af38881 100644\n>--- a/drivers/net/ethernet/intel/i40e/i40e_type.h\n>+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h\n>@@ -287,6 +287,7 @@ struct i40e_hw_capabilities {\n> #define I40E_NVM_IMAGE_TYPE_MODE1\t0x6\n> #define I40E_NVM_IMAGE_TYPE_MODE2\t0x7\n> #define I40E_NVM_IMAGE_TYPE_MODE3\t0x8\n>+#define I40E_SWITCH_MODE_MASK\t\t0xF\n> \n> \tu32  management_mode;\n> \tu32  mng_protocols_over_mctp;\n>diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h\n>index b8c78bf..4fe27f0 100644\n>--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h\n>+++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h\n>@@ -1360,6 +1360,9 @@ struct i40e_aqc_cloud_filters_element_data {\n> \t\tstruct {\n> \t\t\tu8 data[16];\n> \t\t} v6;\n>+\t\tstruct {\n>+\t\t\t__le16 data[8];\n>+\t\t} raw_v6;\n> \t} ipaddr;\n> \t__le16\tflags;\n> #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT\t\t\t0\n>","headers":{"Return-Path":"<intel-wired-lan-bounces@osuosl.org>","X-Original-To":["incoming@patchwork.ozlabs.org","intel-wired-lan@lists.osuosl.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","intel-wired-lan@lists.osuosl.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=osuosl.org\n\t(client-ip=140.211.166.138; helo=whitealder.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=resnulli-us.20150623.gappssmtp.com\n\theader.i=@resnulli-us.20150623.gappssmtp.com\n\theader.b=\"XiXkRuT9\"; dkim-atps=neutral"],"Received":["from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xspvW0d0jz9s03\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 14 Sep 2017 03:44:38 +1000 (AEST)","from localhost (localhost [127.0.0.1])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id 8E21E88E23;\n\tWed, 13 Sep 2017 17:44:37 +0000 (UTC)","from whitealder.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id e72745b0aQOq; Wed, 13 Sep 2017 17:44:29 +0000 (UTC)","from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id 95A0788E18;\n\tWed, 13 Sep 2017 17:44:28 +0000 (UTC)","from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\tby ash.osuosl.org (Postfix) with ESMTP id E308D1BFCA2\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Sep 2017 13:26:18 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id D69A588251\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Sep 2017 13:26:18 +0000 (UTC)","from fraxinus.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id 3sR5tzrVdm12 for <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Sep 2017 13:26:15 +0000 (UTC)","from mail-wm0-f42.google.com (mail-wm0-f42.google.com\n\t[74.125.82.42])\n\tby fraxinus.osuosl.org (Postfix) with ESMTPS id 11C6886DD6\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Sep 2017 13:26:15 +0000 (UTC)","by mail-wm0-f42.google.com with SMTP id g206so6820509wme.0\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tWed, 13 Sep 2017 06:26:14 -0700 (PDT)","from localhost (ip-89-177-125-82.net.upcbroadband.cz.\n\t[89.177.125.82]) by smtp.gmail.com with ESMTPSA id\n\tf89sm1610457wmh.18.2017.09.13.06.26.11\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tWed, 13 Sep 2017 06:26:12 -0700 (PDT)"],"X-Virus-Scanned":["amavisd-new at osuosl.org","amavisd-new at osuosl.org"],"X-Greylist":"from auto-whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=resnulli-us.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to:user-agent;\n\tbh=ymgYYEc4C7l7Mjia+i5xRLITbKwtlrIEVsLSxurgbHw=;\n\tb=XiXkRuT9rnEGkP6WIOJ8Z4cqTw39FSPFMXD/iHhd5H6FWduK+KP6LCxbv0wV5QDiZ/\n\tyFuoV2TDSraG8+WEkYJD+ayZTaJYlRslVt27QE6cYuEWTf0UFFG+p1jf8Ptz7UJOyJnA\n\tfe2Qub/QYT1BEdOnwdMsZgXL3glj5dAFiIcrrgJB0I7Ip045aJthYzooohKCg72rXtYN\n\tY+ESZI9XrUejk+gv7iLVHYoYRNAT6F3LRtBSiXiA18vp1S/ZoQ8HuqUUpatJEiVtMzJp\n\tSdCaAYiYURE45disPMZdNc/aM2qaQdo+aUunM0Ikh1TZTlWiZ5F1VysUnXTxsxiKXKgl\n\tSIJw==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to:user-agent;\n\tbh=ymgYYEc4C7l7Mjia+i5xRLITbKwtlrIEVsLSxurgbHw=;\n\tb=qbsihNdJk+FbRiwPwU1L63zTKUHy6Z5dnCum7dL8Qsc8WCwfmnSXDBLdMuV+cjjee7\n\tohRTMzq3caIsQyLHIxQMGw6a8jj/UWV6QnPk+UWY4FsURLvQgj20BbggrLIV8cjmRuCC\n\txZccJuzMv9oAD/gC/9dGYHVmXGmDMuZXVKCC2dYjaKRAGoScPn6xnxtdosKkPFQO7gFn\n\thOdP4RT9LzJRjtP5ty6n9hXPvWc7bxPidICNvfQtpV5zocBViYOsGOgOxQxVlESTYQVA\n\tWdnQsjBZfiKb3WU5I6OyI/Trc0hs7W7OvLqgjykpgJWdK4Z6bcLyOMXMmBaduscIF6Fn\n\tnyTQ==","X-Gm-Message-State":"AHPjjUjq7o0VWiPZnVZ86gtgFIxPgyVKmPcMVEI7bjGX2aiZHZfgV+ZM\n\tpeio71A8JQxuvZe2BpczhS4nNA==","X-Google-Smtp-Source":"AOwi7QDC4+FCOhT5la+dw9QPaZm97S2lSotvf4bVHOf5qCD28IPDwAjHNJsTFSjcx7dZofis+LPKxQ==","X-Received":"by 10.28.165.75 with SMTP id o72mr2388869wme.12.1505309172883;\n\tWed, 13 Sep 2017 06:26:12 -0700 (PDT)","Date":"Wed, 13 Sep 2017 15:26:11 +0200","From":"Jiri Pirko <jiri@resnulli.us>","To":"Amritha Nambiar <amritha.nambiar@intel.com>","Message-ID":"<20170913132611.GC1981@nanopsycho>","References":"<150529632024.57063.15338545678487601430.stgit@anamdev.jf.intel.com>\n\t<150529679050.57063.3956015681929450874.stgit@anamdev.jf.intel.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<150529679050.57063.3956015681929450874.stgit@anamdev.jf.intel.com>","User-Agent":"Mutt/1.8.3 (2017-05-23)","X-Mailman-Approved-At":"Wed, 13 Sep 2017 17:44:26 +0000","Cc":"netdev@vger.kernel.org, intel-wired-lan@lists.osuosl.org,\n\tmlxsw@mellanox.com","Subject":"Re: [Intel-wired-lan] [RFC PATCH v3 7/7] i40e: Enable cloud filters\n\tvia tc-flower","X-BeenThere":"intel-wired-lan@osuosl.org","X-Mailman-Version":"2.1.18-1","Precedence":"list","List-Id":"Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.osuosl.org>","List-Unsubscribe":"<https://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>","List-Archive":"<http://lists.osuosl.org/pipermail/intel-wired-lan/>","List-Post":"<mailto:intel-wired-lan@osuosl.org>","List-Help":"<mailto:intel-wired-lan-request@osuosl.org?subject=help>","List-Subscribe":"<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"intel-wired-lan-bounces@osuosl.org","Sender":"\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>"}},{"id":1768395,"web_url":"http://patchwork.ozlabs.org/comment/1768395/","msgid":"<82e0a065-c7d6-8fe6-aedc-154dd0dd88d6@intel.com>","list_archive_url":null,"date":"2017-09-14T08:00:13","subject":"Re: [Intel-wired-lan] [RFC PATCH v3 7/7] i40e: Enable cloud filters\n\tvia tc-flower","submitter":{"id":68504,"url":"http://patchwork.ozlabs.org/api/people/68504/","name":"Nambiar, Amritha","email":"amritha.nambiar@intel.com"},"content":"On 9/13/2017 6:26 AM, Jiri Pirko wrote:\n> Wed, Sep 13, 2017 at 11:59:50AM CEST, amritha.nambiar@intel.com wrote:\n>> This patch enables tc-flower based hardware offloads. tc flower\n>> filter provided by the kernel is configured as driver specific\n>> cloud filter. The patch implements functions and admin queue\n>> commands needed to support cloud filters in the driver and\n>> adds cloud filters to configure these tc-flower filters.\n>>\n>> The only action supported is to redirect packets to a traffic class\n>> on the same device.\n> \n> So basically you are not doing redirect, you are just setting tclass for\n> matched packets, right? Why you use mirred for this? I think that\n> you might consider extending g_act for that:\n> \n> # tc filter add dev eth0 protocol ip ingress \\\n>   prio 1 flower dst_mac 3c:fd:fe:a0:d6:70 skip_sw \\\n>   action tclass 0\n> \nYes, this doesn't work like a typical egress redirect, but is aimed at\nforwarding the matched packets to a different queue-group/traffic class\non the same device, so some sort-of ingress redirect in the hardware. I\npossibly may not need the mirred-redirect as you say, I'll look into the\ng_act way of doing this with a new gact tc action.\n\n> \n>>\n>> # tc qdisc add dev eth0 ingress\n>> # ethtool -K eth0 hw-tc-offload on\n>>\n>> # tc filter add dev eth0 protocol ip parent ffff:\\\n>>  prio 1 flower dst_mac 3c:fd:fe:a0:d6:70 skip_sw\\\n>>  action mirred ingress redirect dev eth0 tclass 0\n>>\n>> # tc filter add dev eth0 protocol ip parent ffff:\\\n>>  prio 2 flower dst_ip 192.168.3.5/32\\\n>>  ip_proto udp dst_port 25 skip_sw\\\n>>  action mirred ingress redirect dev eth0 tclass 1\n>>\n>> # tc filter add dev eth0 protocol ipv6 parent ffff:\\\n>>  prio 3 flower dst_ip fe8::200:1\\\n>>  ip_proto udp dst_port 66 skip_sw\\\n>>  action mirred ingress redirect dev eth0 tclass 1\n>>\n>> Delete tc flower filter:\n>> Example:\n>>\n>> # tc filter del dev eth0 parent ffff: prio 3 handle 0x1 flower\n>> # tc filter del dev eth0 parent ffff:\n>>\n>> Flow Director Sideband is disabled while configuring cloud filters\n>> via tc-flower and until any cloud filter exists.\n>>\n>> Unsupported matches when cloud filters are added using enhanced\n>> big buffer cloud filter mode of underlying switch include:\n>> 1. source port and source IP\n>> 2. Combined MAC address and IP fields.\n>> 3. Not specifying L4 port\n>>\n>> These filter matches can however be used to redirect traffic to\n>> the main VSI (tc 0) which does not require the enhanced big buffer\n>> cloud filter support.\n>>\n>> v3: Cleaned up some lengthy function names. Changed ipv6 address to\n>> __be32 array instead of u8 array. Used macro for IP version. Minor\n>> formatting changes.\n>> v2:\n>> 1. Moved I40E_SWITCH_MODE_MASK definition to i40e_type.h\n>> 2. Moved dev_info for add/deleting cloud filters in else condition\n>> 3. Fixed some format specifier in dev_err logs\n>> 4. Refactored i40e_get_capabilities to take an additional\n>>   list_type parameter and use it to query device and function\n>>   level capabilities.\n>> 5. Fixed parsing tc redirect action to check for the is_tcf_mirred_tc()\n>>   to verify if redirect to a traffic class is supported.\n>> 6. Added comments for Geneve fix in cloud filter big buffer AQ\n>>   function definitions.\n>> 7. Cleaned up setup_tc interface to rebase and work with Jiri's\n>>   updates, separate function to process tc cls flower offloads.\n>> 8. Changes to make Flow Director Sideband and Cloud filters mutually\n>>   exclusive.\n>>\n>> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>\n>> Signed-off-by: Kiran Patil <kiran.patil@intel.com>\n>> Signed-off-by: Anjali Singhai Jain <anjali.singhai@intel.com>\n>> Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>\n>> ---\n>> drivers/net/ethernet/intel/i40e/i40e.h             |   49 +\n>> drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h  |    3 \n>> drivers/net/ethernet/intel/i40e/i40e_common.c      |  189 ++++\n>> drivers/net/ethernet/intel/i40e/i40e_main.c        |  971 +++++++++++++++++++-\n>> drivers/net/ethernet/intel/i40e/i40e_prototype.h   |   16 \n>> drivers/net/ethernet/intel/i40e/i40e_type.h        |    1 \n>> .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h    |    3 \n>> 7 files changed, 1202 insertions(+), 30 deletions(-)\n>>\n>> diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h\n>> index 6018fb6..b110519 100644\n>> --- a/drivers/net/ethernet/intel/i40e/i40e.h\n>> +++ b/drivers/net/ethernet/intel/i40e/i40e.h\n>> @@ -55,6 +55,8 @@\n>> #include <linux/net_tstamp.h>\n>> #include <linux/ptp_clock_kernel.h>\n>> #include <net/pkt_cls.h>\n>> +#include <net/tc_act/tc_gact.h>\n>> +#include <net/tc_act/tc_mirred.h>\n>> #include \"i40e_type.h\"\n>> #include \"i40e_prototype.h\"\n>> #include \"i40e_client.h\"\n>> @@ -252,9 +254,52 @@ struct i40e_fdir_filter {\n>> \tu32 fd_id;\n>> };\n>>\n>> +#define IPV4_VERSION 4\n>> +#define IPV6_VERSION 6\n>> +\n>> +#define I40E_CLOUD_FIELD_OMAC\t0x01\n>> +#define I40E_CLOUD_FIELD_IMAC\t0x02\n>> +#define I40E_CLOUD_FIELD_IVLAN\t0x04\n>> +#define I40E_CLOUD_FIELD_TEN_ID\t0x08\n>> +#define I40E_CLOUD_FIELD_IIP\t0x10\n>> +\n>> +#define I40E_CLOUD_FILTER_FLAGS_OMAC\tI40E_CLOUD_FIELD_OMAC\n>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC\tI40E_CLOUD_FIELD_IMAC\n>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN\t(I40E_CLOUD_FIELD_IMAC | \\\n>> +\t\t\t\t\t\t I40E_CLOUD_FIELD_IVLAN)\n>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID\t(I40E_CLOUD_FIELD_IMAC | \\\n>> +\t\t\t\t\t\t I40E_CLOUD_FIELD_TEN_ID)\n>> +#define I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC (I40E_CLOUD_FIELD_OMAC | \\\n>> +\t\t\t\t\t\t  I40E_CLOUD_FIELD_IMAC | \\\n>> +\t\t\t\t\t\t  I40E_CLOUD_FIELD_TEN_ID)\n>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID (I40E_CLOUD_FIELD_IMAC | \\\n>> +\t\t\t\t\t\t   I40E_CLOUD_FIELD_IVLAN | \\\n>> +\t\t\t\t\t\t   I40E_CLOUD_FIELD_TEN_ID)\n>> +#define I40E_CLOUD_FILTER_FLAGS_IIP\tI40E_CLOUD_FIELD_IIP\n>> +\n>> struct i40e_cloud_filter {\n>> \tstruct hlist_node cloud_node;\n>> \tunsigned long cookie;\n>> +\t/* cloud filter input set follows */\n>> +\tu8 dst_mac[ETH_ALEN];\n>> +\tu8 src_mac[ETH_ALEN];\n>> +\t__be16 vlan_id;\n>> +\t__be32 dst_ip;\n>> +\t__be32 src_ip;\n>> +\t__be32 dst_ipv6[4];\n>> +\t__be32 src_ipv6[4];\n>> +\t__be16 dst_port;\n>> +\t__be16 src_port;\n>> +\tu32 ip_version;\n>> +\tu8 ip_proto;\t/* IPPROTO value */\n>> +\t/* L4 port type: src or destination port */\n>> +#define I40E_CLOUD_FILTER_PORT_SRC\t0x01\n>> +#define I40E_CLOUD_FILTER_PORT_DEST\t0x02\n>> +\tu8 port_type;\n>> +\tu32 tenant_id;\n>> +\tu8 flags;\n>> +#define I40E_CLOUD_TNL_TYPE_NONE\t0xff\n>> +\tu8 tunnel_type;\n>> \tu16 seid;\t/* filter control */\n>> };\n>>\n>> @@ -491,6 +536,8 @@ struct i40e_pf {\n>> #define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED\tBIT(27)\n>> #define I40E_FLAG_SOURCE_PRUNING_DISABLED\tBIT(28)\n>> #define I40E_FLAG_TC_MQPRIO\t\t\tBIT(29)\n>> +#define I40E_FLAG_FD_SB_INACTIVE\t\tBIT(30)\n>> +#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER\t\tBIT(31)\n>>\n>> \tstruct i40e_client_instance *cinst;\n>> \tbool stat_offsets_loaded;\n>> @@ -573,6 +620,8 @@ struct i40e_pf {\n>> \tu16 phy_led_val;\n>>\n>> \tu16 override_q_count;\n>> +\tu16 last_sw_conf_flags;\n>> +\tu16 last_sw_conf_valid_flags;\n>> };\n>>\n>> /**\n>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h\n>> index 2e567c2..feb3d42 100644\n>> --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h\n>> +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h\n>> @@ -1392,6 +1392,9 @@ struct i40e_aqc_cloud_filters_element_data {\n>> \t\tstruct {\n>> \t\t\tu8 data[16];\n>> \t\t} v6;\n>> +\t\tstruct {\n>> +\t\t\t__le16 data[8];\n>> +\t\t} raw_v6;\n>> \t} ipaddr;\n>> \t__le16\tflags;\n>> #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT\t\t\t0\n>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c\n>> index 9567702..d9c9665 100644\n>> --- a/drivers/net/ethernet/intel/i40e/i40e_common.c\n>> +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c\n>> @@ -5434,5 +5434,194 @@ i40e_add_pinfo_to_list(struct i40e_hw *hw,\n>>\n>> \tstatus = i40e_aq_write_ppp(hw, (void *)sec, sec->data_end,\n>> \t\t\t\t   track_id, &offset, &info, NULL);\n>> +\n>> +\treturn status;\n>> +}\n>> +\n>> +/**\n>> + * i40e_aq_add_cloud_filters\n>> + * @hw: pointer to the hardware structure\n>> + * @seid: VSI seid to add cloud filters from\n>> + * @filters: Buffer which contains the filters to be added\n>> + * @filter_count: number of filters contained in the buffer\n>> + *\n>> + * Set the cloud filters for a given VSI.  The contents of the\n>> + * i40e_aqc_cloud_filters_element_data are filled in by the caller\n>> + * of the function.\n>> + *\n>> + **/\n>> +enum i40e_status_code\n>> +i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 seid,\n>> +\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>> +\t\t\t  u8 filter_count)\n>> +{\n>> +\tstruct i40e_aq_desc desc;\n>> +\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>> +\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>> +\tenum i40e_status_code status;\n>> +\tu16 buff_len;\n>> +\n>> +\ti40e_fill_default_direct_cmd_desc(&desc,\n>> +\t\t\t\t\t  i40e_aqc_opc_add_cloud_filters);\n>> +\n>> +\tbuff_len = filter_count * sizeof(*filters);\n>> +\tdesc.datalen = cpu_to_le16(buff_len);\n>> +\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>> +\tcmd->num_filters = filter_count;\n>> +\tcmd->seid = cpu_to_le16(seid);\n>> +\n>> +\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>> +\n>> +\treturn status;\n>> +}\n>> +\n>> +/**\n>> + * i40e_aq_add_cloud_filters_bb\n>> + * @hw: pointer to the hardware structure\n>> + * @seid: VSI seid to add cloud filters from\n>> + * @filters: Buffer which contains the filters in big buffer to be added\n>> + * @filter_count: number of filters contained in the buffer\n>> + *\n>> + * Set the big buffer cloud filters for a given VSI.  The contents of the\n>> + * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the\n>> + * function.\n>> + *\n>> + **/\n>> +i40e_status\n>> +i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>> +\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>> +\t\t\t     u8 filter_count)\n>> +{\n>> +\tstruct i40e_aq_desc desc;\n>> +\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>> +\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>> +\ti40e_status status;\n>> +\tu16 buff_len;\n>> +\tint i;\n>> +\n>> +\ti40e_fill_default_direct_cmd_desc(&desc,\n>> +\t\t\t\t\t  i40e_aqc_opc_add_cloud_filters);\n>> +\n>> +\tbuff_len = filter_count * sizeof(*filters);\n>> +\tdesc.datalen = cpu_to_le16(buff_len);\n>> +\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>> +\tcmd->num_filters = filter_count;\n>> +\tcmd->seid = cpu_to_le16(seid);\n>> +\tcmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;\n>> +\n>> +\tfor (i = 0; i < filter_count; i++) {\n>> +\t\tu16 tnl_type;\n>> +\t\tu32 ti;\n>> +\n>> +\t\ttnl_type = (le16_to_cpu(filters[i].element.flags) &\n>> +\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>\n>> +\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;\n>> +\n>> +\t\t/* For Geneve, the VNI should be placed in offset shifted by a\n>> +\t\t * byte than the offset for the Tenant ID for rest of the\n>> +\t\t * tunnels.\n>> +\t\t */\n>> +\t\tif (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {\n>> +\t\t\tti = le32_to_cpu(filters[i].element.tenant_id);\n>> +\t\t\tfilters[i].element.tenant_id = cpu_to_le32(ti << 8);\n>> +\t\t}\n>> +\t}\n>> +\n>> +\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>> +\n>> +\treturn status;\n>> +}\n>> +\n>> +/**\n>> + * i40e_aq_rem_cloud_filters\n>> + * @hw: pointer to the hardware structure\n>> + * @seid: VSI seid to remove cloud filters from\n>> + * @filters: Buffer which contains the filters to be removed\n>> + * @filter_count: number of filters contained in the buffer\n>> + *\n>> + * Remove the cloud filters for a given VSI.  The contents of the\n>> + * i40e_aqc_cloud_filters_element_data are filled in by the caller\n>> + * of the function.\n>> + *\n>> + **/\n>> +enum i40e_status_code\n>> +i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 seid,\n>> +\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>> +\t\t\t  u8 filter_count)\n>> +{\n>> +\tstruct i40e_aq_desc desc;\n>> +\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>> +\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>> +\tenum i40e_status_code status;\n>> +\tu16 buff_len;\n>> +\n>> +\ti40e_fill_default_direct_cmd_desc(&desc,\n>> +\t\t\t\t\t  i40e_aqc_opc_remove_cloud_filters);\n>> +\n>> +\tbuff_len = filter_count * sizeof(*filters);\n>> +\tdesc.datalen = cpu_to_le16(buff_len);\n>> +\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>> +\tcmd->num_filters = filter_count;\n>> +\tcmd->seid = cpu_to_le16(seid);\n>> +\n>> +\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>> +\n>> +\treturn status;\n>> +}\n>> +\n>> +/**\n>> + * i40e_aq_rem_cloud_filters_bb\n>> + * @hw: pointer to the hardware structure\n>> + * @seid: VSI seid to remove cloud filters from\n>> + * @filters: Buffer which contains the filters in big buffer to be removed\n>> + * @filter_count: number of filters contained in the buffer\n>> + *\n>> + * Remove the big buffer cloud filters for a given VSI.  The contents of the\n>> + * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the\n>> + * function.\n>> + *\n>> + **/\n>> +i40e_status\n>> +i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>> +\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>> +\t\t\t     u8 filter_count)\n>> +{\n>> +\tstruct i40e_aq_desc desc;\n>> +\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>> +\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>> +\ti40e_status status;\n>> +\tu16 buff_len;\n>> +\tint i;\n>> +\n>> +\ti40e_fill_default_direct_cmd_desc(&desc,\n>> +\t\t\t\t\t  i40e_aqc_opc_remove_cloud_filters);\n>> +\n>> +\tbuff_len = filter_count * sizeof(*filters);\n>> +\tdesc.datalen = cpu_to_le16(buff_len);\n>> +\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>> +\tcmd->num_filters = filter_count;\n>> +\tcmd->seid = cpu_to_le16(seid);\n>> +\tcmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;\n>> +\n>> +\tfor (i = 0; i < filter_count; i++) {\n>> +\t\tu16 tnl_type;\n>> +\t\tu32 ti;\n>> +\n>> +\t\ttnl_type = (le16_to_cpu(filters[i].element.flags) &\n>> +\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>\n>> +\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;\n>> +\n>> +\t\t/* For Geneve, the VNI should be placed in offset shifted by a\n>> +\t\t * byte than the offset for the Tenant ID for rest of the\n>> +\t\t * tunnels.\n>> +\t\t */\n>> +\t\tif (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {\n>> +\t\t\tti = le32_to_cpu(filters[i].element.tenant_id);\n>> +\t\t\tfilters[i].element.tenant_id = cpu_to_le32(ti << 8);\n>> +\t\t}\n>> +\t}\n>> +\n>> +\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>> +\n>> \treturn status;\n>> }\n>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c\n>> index afcf08a..96ee608 100644\n>> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c\n>> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c\n>> @@ -69,6 +69,15 @@ static int i40e_reset(struct i40e_pf *pf);\n>> static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired);\n>> static void i40e_fdir_sb_setup(struct i40e_pf *pf);\n>> static int i40e_veb_get_bw_info(struct i40e_veb *veb);\n>> +static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,\n>> +\t\t\t\t     struct i40e_cloud_filter *filter,\n>> +\t\t\t\t     bool add);\n>> +static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,\n>> +\t\t\t\t\t     struct i40e_cloud_filter *filter,\n>> +\t\t\t\t\t     bool add);\n>> +static int i40e_get_capabilities(struct i40e_pf *pf,\n>> +\t\t\t\t enum i40e_admin_queue_opc list_type);\n>> +\n>>\n>> /* i40e_pci_tbl - PCI Device ID Table\n>>  *\n>> @@ -5478,7 +5487,11 @@ int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate)\n>>  **/\n>> static void i40e_remove_queue_channels(struct i40e_vsi *vsi)\n>> {\n>> +\tenum i40e_admin_queue_err last_aq_status;\n>> +\tstruct i40e_cloud_filter *cfilter;\n>> \tstruct i40e_channel *ch, *ch_tmp;\n>> +\tstruct i40e_pf *pf = vsi->back;\n>> +\tstruct hlist_node *node;\n>> \tint ret, i;\n>>\n>> \t/* Reset rss size that was stored when reconfiguring rss for\n>> @@ -5519,6 +5532,29 @@ static void i40e_remove_queue_channels(struct i40e_vsi *vsi)\n>> \t\t\t\t \"Failed to reset tx rate for ch->seid %u\\n\",\n>> \t\t\t\t ch->seid);\n>>\n>> +\t\t/* delete cloud filters associated with this channel */\n>> +\t\thlist_for_each_entry_safe(cfilter, node,\n>> +\t\t\t\t\t  &pf->cloud_filter_list, cloud_node) {\n>> +\t\t\tif (cfilter->seid != ch->seid)\n>> +\t\t\t\tcontinue;\n>> +\n>> +\t\t\thash_del(&cfilter->cloud_node);\n>> +\t\t\tif (cfilter->dst_port)\n>> +\t\t\t\tret = i40e_add_del_cloud_filter_big_buf(vsi,\n>> +\t\t\t\t\t\t\t\t\tcfilter,\n>> +\t\t\t\t\t\t\t\t\tfalse);\n>> +\t\t\telse\n>> +\t\t\t\tret = i40e_add_del_cloud_filter(vsi, cfilter,\n>> +\t\t\t\t\t\t\t\tfalse);\n>> +\t\t\tlast_aq_status = pf->hw.aq.asq_last_status;\n>> +\t\t\tif (ret)\n>> +\t\t\t\tdev_info(&pf->pdev->dev,\n>> +\t\t\t\t\t \"Failed to delete cloud filter, err %s aq_err %s\\n\",\n>> +\t\t\t\t\t i40e_stat_str(&pf->hw, ret),\n>> +\t\t\t\t\t i40e_aq_str(&pf->hw, last_aq_status));\n>> +\t\t\tkfree(cfilter);\n>> +\t\t}\n>> +\n>> \t\t/* delete VSI from FW */\n>> \t\tret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,\n>> \t\t\t\t\t     NULL);\n>> @@ -5970,6 +6006,74 @@ static bool i40e_setup_channel(struct i40e_pf *pf, struct i40e_vsi *vsi,\n>> }\n>>\n>> /**\n>> + * i40e_validate_and_set_switch_mode - sets up switch mode correctly\n>> + * @vsi: ptr to VSI which has PF backing\n>> + * @l4type: true for TCP ond false for UDP\n>> + * @port_type: true if port is destination and false if port is source\n>> + *\n>> + * Sets up switch mode correctly if it needs to be changed and perform\n>> + * what are allowed modes.\n>> + **/\n>> +static int i40e_validate_and_set_switch_mode(struct i40e_vsi *vsi, bool l4type,\n>> +\t\t\t\t\t     bool port_type)\n>> +{\n>> +\tu8 mode;\n>> +\tstruct i40e_pf *pf = vsi->back;\n>> +\tstruct i40e_hw *hw = &pf->hw;\n>> +\tint ret;\n>> +\n>> +\tret = i40e_get_capabilities(pf, i40e_aqc_opc_list_dev_capabilities);\n>> +\tif (ret)\n>> +\t\treturn -EINVAL;\n>> +\n>> +\tif (hw->dev_caps.switch_mode) {\n>> +\t\t/* if switch mode is set, support mode2 (non-tunneled for\n>> +\t\t * cloud filter) for now\n>> +\t\t */\n>> +\t\tu32 switch_mode = hw->dev_caps.switch_mode &\n>> +\t\t\t\t\t\t\tI40E_SWITCH_MODE_MASK;\n>> +\t\tif (switch_mode >= I40E_NVM_IMAGE_TYPE_MODE1) {\n>> +\t\t\tif (switch_mode == I40E_NVM_IMAGE_TYPE_MODE2)\n>> +\t\t\t\treturn 0;\n>> +\t\t\tdev_err(&pf->pdev->dev,\n>> +\t\t\t\t\"Invalid switch_mode (%d), only non-tunneled mode for cloud filter is supported\\n\",\n>> +\t\t\t\thw->dev_caps.switch_mode);\n>> +\t\t\treturn -EINVAL;\n>> +\t\t}\n>> +\t}\n>> +\n>> +\t/* port_type: true for destination port and false for source port\n>> +\t * For now, supports only destination port type\n>> +\t */\n>> +\tif (!port_type) {\n>> +\t\tdev_err(&pf->pdev->dev, \"src port type not supported\\n\");\n>> +\t\treturn -EINVAL;\n>> +\t}\n>> +\n>> +\t/* Set Bit 7 to be valid */\n>> +\tmode = I40E_AQ_SET_SWITCH_BIT7_VALID;\n>> +\n>> +\t/* Set L4type to both TCP and UDP support */\n>> +\tmode |= I40E_AQ_SET_SWITCH_L4_TYPE_BOTH;\n>> +\n>> +\t/* Set cloud filter mode */\n>> +\tmode |= I40E_AQ_SET_SWITCH_MODE_NON_TUNNEL;\n>> +\n>> +\t/* Prep mode field for set_switch_config */\n>> +\tret = i40e_aq_set_switch_config(hw, pf->last_sw_conf_flags,\n>> +\t\t\t\t\tpf->last_sw_conf_valid_flags,\n>> +\t\t\t\t\tmode, NULL);\n>> +\tif (ret && hw->aq.asq_last_status != I40E_AQ_RC_ESRCH)\n>> +\t\tdev_err(&pf->pdev->dev,\n>> +\t\t\t\"couldn't set switch config bits, err %s aq_err %s\\n\",\n>> +\t\t\ti40e_stat_str(hw, ret),\n>> +\t\t\ti40e_aq_str(hw,\n>> +\t\t\t\t    hw->aq.asq_last_status));\n>> +\n>> +\treturn ret;\n>> +}\n>> +\n>> +/**\n>>  * i40e_create_queue_channel - function to create channel\n>>  * @vsi: VSI to be configured\n>>  * @ch: ptr to channel (it contains channel specific params)\n>> @@ -6735,13 +6839,726 @@ static int i40e_setup_tc(struct net_device *netdev, void *type_data)\n>> \treturn ret;\n>> }\n>>\n>> +/**\n>> + * i40e_set_cld_element - sets cloud filter element data\n>> + * @filter: cloud filter rule\n>> + * @cld: ptr to cloud filter element data\n>> + *\n>> + * This is helper function to copy data into cloud filter element\n>> + **/\n>> +static inline void\n>> +i40e_set_cld_element(struct i40e_cloud_filter *filter,\n>> +\t\t     struct i40e_aqc_cloud_filters_element_data *cld)\n>> +{\n>> +\tint i, j;\n>> +\tu32 ipa;\n>> +\n>> +\tmemset(cld, 0, sizeof(*cld));\n>> +\tether_addr_copy(cld->outer_mac, filter->dst_mac);\n>> +\tether_addr_copy(cld->inner_mac, filter->src_mac);\n>> +\n>> +\tif (filter->ip_version == IPV6_VERSION) {\n>> +#define IPV6_MAX_INDEX\t(ARRAY_SIZE(filter->dst_ipv6) - 1)\n>> +\t\tfor (i = 0, j = 0; i < 4; i++, j += 2) {\n>> +\t\t\tipa = be32_to_cpu(filter->dst_ipv6[IPV6_MAX_INDEX - i]);\n>> +\t\t\tipa = cpu_to_le32(ipa);\n>> +\t\t\tmemcpy(&cld->ipaddr.raw_v6.data[j], &ipa, 4);\n>> +\t\t}\n>> +\t} else {\n>> +\t\tipa = be32_to_cpu(filter->dst_ip);\n>> +\t\tmemcpy(&cld->ipaddr.v4.data, &ipa, 4);\n>> +\t}\n>> +\n>> +\tcld->inner_vlan = cpu_to_le16(ntohs(filter->vlan_id));\n>> +\n>> +\t/* tenant_id is not supported by FW now, once the support is enabled\n>> +\t * fill the cld->tenant_id with cpu_to_le32(filter->tenant_id)\n>> +\t */\n>> +\tif (filter->tenant_id)\n>> +\t\treturn;\n>> +}\n>> +\n>> +/**\n>> + * i40e_add_del_cloud_filter - Add/del cloud filter\n>> + * @vsi: pointer to VSI\n>> + * @filter: cloud filter rule\n>> + * @add: if true, add, if false, delete\n>> + *\n>> + * Add or delete a cloud filter for a specific flow spec.\n>> + * Returns 0 if the filter were successfully added.\n>> + **/\n>> +static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,\n>> +\t\t\t\t     struct i40e_cloud_filter *filter, bool add)\n>> +{\n>> +\tstruct i40e_aqc_cloud_filters_element_data cld_filter;\n>> +\tstruct i40e_pf *pf = vsi->back;\n>> +\tint ret;\n>> +\tstatic const u16 flag_table[128] = {\n>> +\t\t[I40E_CLOUD_FILTER_FLAGS_OMAC]  =\n>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_OMAC,\n>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC]  =\n>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC,\n>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN]  =\n>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN,\n>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID] =\n>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID,\n>> +\t\t[I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC] =\n>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC,\n>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID] =\n>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID,\n>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IIP] =\n>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IIP,\n>> +\t};\n>> +\n>> +\tif (filter->flags >= ARRAY_SIZE(flag_table))\n>> +\t\treturn I40E_ERR_CONFIG;\n>> +\n>> +\t/* copy element needed to add cloud filter from filter */\n>> +\ti40e_set_cld_element(filter, &cld_filter);\n>> +\n>> +\tif (filter->tunnel_type != I40E_CLOUD_TNL_TYPE_NONE)\n>> +\t\tcld_filter.flags = cpu_to_le16(filter->tunnel_type <<\n>> +\t\t\t\t\t     I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT);\n>> +\n>> +\tif (filter->ip_version == IPV6_VERSION)\n>> +\t\tcld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |\n>> +\t\t\t\t\t\tI40E_AQC_ADD_CLOUD_FLAGS_IPV6);\n>> +\telse\n>> +\t\tcld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |\n>> +\t\t\t\t\t\tI40E_AQC_ADD_CLOUD_FLAGS_IPV4);\n>> +\n>> +\tif (add)\n>> +\t\tret = i40e_aq_add_cloud_filters(&pf->hw, filter->seid,\n>> +\t\t\t\t\t\t&cld_filter, 1);\n>> +\telse\n>> +\t\tret = i40e_aq_rem_cloud_filters(&pf->hw, filter->seid,\n>> +\t\t\t\t\t\t&cld_filter, 1);\n>> +\tif (ret)\n>> +\t\tdev_dbg(&pf->pdev->dev,\n>> +\t\t\t\"Failed to %s cloud filter using l4 port %u, err %d aq_err %d\\n\",\n>> +\t\t\tadd ? \"add\" : \"delete\", filter->dst_port, ret,\n>> +\t\t\tpf->hw.aq.asq_last_status);\n>> +\telse\n>> +\t\tdev_info(&pf->pdev->dev,\n>> +\t\t\t \"%s cloud filter for VSI: %d\\n\",\n>> +\t\t\t add ? \"Added\" : \"Deleted\", filter->seid);\n>> +\treturn ret;\n>> +}\n>> +\n>> +/**\n>> + * i40e_add_del_cloud_filter_big_buf - Add/del cloud filter using big_buf\n>> + * @vsi: pointer to VSI\n>> + * @filter: cloud filter rule\n>> + * @add: if true, add, if false, delete\n>> + *\n>> + * Add or delete a cloud filter for a specific flow spec using big buffer.\n>> + * Returns 0 if the filter were successfully added.\n>> + **/\n>> +static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,\n>> +\t\t\t\t\t     struct i40e_cloud_filter *filter,\n>> +\t\t\t\t\t     bool add)\n>> +{\n>> +\tstruct i40e_aqc_cloud_filters_element_bb cld_filter;\n>> +\tstruct i40e_pf *pf = vsi->back;\n>> +\tint ret;\n>> +\n>> +\t/* Both (Outer/Inner) valid mac_addr are not supported */\n>> +\tif (is_valid_ether_addr(filter->dst_mac) &&\n>> +\t    is_valid_ether_addr(filter->src_mac))\n>> +\t\treturn -EINVAL;\n>> +\n>> +\t/* Make sure port is specified, otherwise bail out, for channel\n>> +\t * specific cloud filter needs 'L4 port' to be non-zero\n>> +\t */\n>> +\tif (!filter->dst_port)\n>> +\t\treturn -EINVAL;\n>> +\n>> +\t/* adding filter using src_port/src_ip is not supported at this stage */\n>> +\tif (filter->src_port || filter->src_ip ||\n>> +\t    !ipv6_addr_any((struct in6_addr *)&filter->src_ipv6))\n>> +\t\treturn -EINVAL;\n>> +\n>> +\t/* copy element needed to add cloud filter from filter */\n>> +\ti40e_set_cld_element(filter, &cld_filter.element);\n>> +\n>> +\tif (is_valid_ether_addr(filter->dst_mac) ||\n>> +\t    is_valid_ether_addr(filter->src_mac) ||\n>> +\t    is_multicast_ether_addr(filter->dst_mac) ||\n>> +\t    is_multicast_ether_addr(filter->src_mac)) {\n>> +\t\t/* MAC + IP : unsupported mode */\n>> +\t\tif (filter->dst_ip)\n>> +\t\t\treturn -EINVAL;\n>> +\n>> +\t\t/* since we validated that L4 port must be valid before\n>> +\t\t * we get here, start with respective \"flags\" value\n>> +\t\t * and update if vlan is present or not\n>> +\t\t */\n>> +\t\tcld_filter.element.flags =\n>> +\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT);\n>> +\n>> +\t\tif (filter->vlan_id) {\n>> +\t\t\tcld_filter.element.flags =\n>> +\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT);\n>> +\t\t}\n>> +\n>> +\t} else if (filter->dst_ip || filter->ip_version == IPV6_VERSION) {\n>> +\t\tcld_filter.element.flags =\n>> +\t\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_IP_PORT);\n>> +\t\tif (filter->ip_version == IPV6_VERSION)\n>> +\t\t\tcld_filter.element.flags |=\n>> +\t\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV6);\n>> +\t\telse\n>> +\t\t\tcld_filter.element.flags |=\n>> +\t\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV4);\n>> +\t} else {\n>> +\t\tdev_err(&pf->pdev->dev,\n>> +\t\t\t\"either mac or ip has to be valid for cloud filter\\n\");\n>> +\t\treturn -EINVAL;\n>> +\t}\n>> +\n>> +\t/* Now copy L4 port in Byte 6..7 in general fields */\n>> +\tcld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0] =\n>> +\t\t\t\t\t\tbe16_to_cpu(filter->dst_port);\n>> +\n>> +\tif (add) {\n>> +\t\tbool proto_type, port_type;\n>> +\n>> +\t\tproto_type = (filter->ip_proto == IPPROTO_TCP) ? true : false;\n>> +\t\tport_type = (filter->port_type & I40E_CLOUD_FILTER_PORT_DEST) ?\n>> +\t\t\t     true : false;\n>> +\n>> +\t\t/* For now, src port based cloud filter for channel is not\n>> +\t\t * supported\n>> +\t\t */\n>> +\t\tif (!port_type) {\n>> +\t\t\tdev_err(&pf->pdev->dev,\n>> +\t\t\t\t\"unsupported port type (src port)\\n\");\n>> +\t\t\treturn -EOPNOTSUPP;\n>> +\t\t}\n>> +\n>> +\t\t/* Validate current device switch mode, change if necessary */\n>> +\t\tret = i40e_validate_and_set_switch_mode(vsi, proto_type,\n>> +\t\t\t\t\t\t\tport_type);\n>> +\t\tif (ret) {\n>> +\t\t\tdev_err(&pf->pdev->dev,\n>> +\t\t\t\t\"failed to set switch mode, ret %d\\n\",\n>> +\t\t\t\tret);\n>> +\t\t\treturn ret;\n>> +\t\t}\n>> +\n>> +\t\tret = i40e_aq_add_cloud_filters_bb(&pf->hw, filter->seid,\n>> +\t\t\t\t\t\t   &cld_filter, 1);\n>> +\t} else {\n>> +\t\tret = i40e_aq_rem_cloud_filters_bb(&pf->hw, filter->seid,\n>> +\t\t\t\t\t\t   &cld_filter, 1);\n>> +\t}\n>> +\n>> +\tif (ret)\n>> +\t\tdev_dbg(&pf->pdev->dev,\n>> +\t\t\t\"Failed to %s cloud filter(big buffer) err %d aq_err %d\\n\",\n>> +\t\t\tadd ? \"add\" : \"delete\", ret, pf->hw.aq.asq_last_status);\n>> +\telse\n>> +\t\tdev_info(&pf->pdev->dev,\n>> +\t\t\t \"%s cloud filter for VSI: %d, L4 port: %d\\n\",\n>> +\t\t\t add ? \"add\" : \"delete\", filter->seid,\n>> +\t\t\t ntohs(filter->dst_port));\n>> +\treturn ret;\n>> +}\n>> +\n>> +/**\n>> + * i40e_parse_cls_flower - Parse tc flower filters provided by kernel\n>> + * @vsi: Pointer to VSI\n>> + * @cls_flower: Pointer to struct tc_cls_flower_offload\n>> + * @filter: Pointer to cloud filter structure\n>> + *\n>> + **/\n>> +static int i40e_parse_cls_flower(struct i40e_vsi *vsi,\n>> +\t\t\t\t struct tc_cls_flower_offload *f,\n>> +\t\t\t\t struct i40e_cloud_filter *filter)\n>> +{\n>> +\tstruct i40e_pf *pf = vsi->back;\n>> +\tu16 addr_type = 0;\n>> +\tu8 field_flags = 0;\n>> +\n>> +\tif (f->dissector->used_keys &\n>> +\t    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |\n>> +\t      BIT(FLOW_DISSECTOR_KEY_BASIC) |\n>> +\t      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |\n>> +\t      BIT(FLOW_DISSECTOR_KEY_VLAN) |\n>> +\t      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |\n>> +\t      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |\n>> +\t      BIT(FLOW_DISSECTOR_KEY_PORTS) |\n>> +\t      BIT(FLOW_DISSECTOR_KEY_ENC_KEYID))) {\n>> +\t\tdev_err(&pf->pdev->dev, \"Unsupported key used: 0x%x\\n\",\n>> +\t\t\tf->dissector->used_keys);\n>> +\t\treturn -EOPNOTSUPP;\n>> +\t}\n>> +\n>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {\n>> +\t\tstruct flow_dissector_key_keyid *key =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ENC_KEYID,\n>> +\t\t\t\t\t\t  f->key);\n>> +\n>> +\t\tstruct flow_dissector_key_keyid *mask =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ENC_KEYID,\n>> +\t\t\t\t\t\t  f->mask);\n>> +\n>> +\t\tif (mask->keyid != 0)\n>> +\t\t\tfield_flags |= I40E_CLOUD_FIELD_TEN_ID;\n>> +\n>> +\t\tfilter->tenant_id = be32_to_cpu(key->keyid);\n>> +\t}\n>> +\n>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {\n>> +\t\tstruct flow_dissector_key_basic *key =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_BASIC,\n>> +\t\t\t\t\t\t  f->key);\n>> +\n>> +\t\tfilter->ip_proto = key->ip_proto;\n>> +\t}\n>> +\n>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {\n>> +\t\tstruct flow_dissector_key_eth_addrs *key =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ETH_ADDRS,\n>> +\t\t\t\t\t\t  f->key);\n>> +\n>> +\t\tstruct flow_dissector_key_eth_addrs *mask =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ETH_ADDRS,\n>> +\t\t\t\t\t\t  f->mask);\n>> +\n>> +\t\t/* use is_broadcast and is_zero to check for all 0xf or 0 */\n>> +\t\tif (!is_zero_ether_addr(mask->dst)) {\n>> +\t\t\tif (is_broadcast_ether_addr(mask->dst)) {\n>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_OMAC;\n>> +\t\t\t} else {\n>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ether dest mask %pM\\n\",\n>> +\t\t\t\t\tmask->dst);\n>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>> +\t\t\t}\n>> +\t\t}\n>> +\n>> +\t\tif (!is_zero_ether_addr(mask->src)) {\n>> +\t\t\tif (is_broadcast_ether_addr(mask->src)) {\n>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IMAC;\n>> +\t\t\t} else {\n>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ether src mask %pM\\n\",\n>> +\t\t\t\t\tmask->src);\n>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>> +\t\t\t}\n>> +\t\t}\n>> +\t\tether_addr_copy(filter->dst_mac, key->dst);\n>> +\t\tether_addr_copy(filter->src_mac, key->src);\n>> +\t}\n>> +\n>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {\n>> +\t\tstruct flow_dissector_key_vlan *key =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_VLAN,\n>> +\t\t\t\t\t\t  f->key);\n>> +\t\tstruct flow_dissector_key_vlan *mask =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_VLAN,\n>> +\t\t\t\t\t\t  f->mask);\n>> +\n>> +\t\tif (mask->vlan_id) {\n>> +\t\t\tif (mask->vlan_id == VLAN_VID_MASK) {\n>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IVLAN;\n>> +\n>> +\t\t\t} else {\n>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad vlan mask 0x%04x\\n\",\n>> +\t\t\t\t\tmask->vlan_id);\n>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>> +\t\t\t}\n>> +\t\t}\n>> +\n>> +\t\tfilter->vlan_id = cpu_to_be16(key->vlan_id);\n>> +\t}\n>> +\n>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {\n>> +\t\tstruct flow_dissector_key_control *key =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_CONTROL,\n>> +\t\t\t\t\t\t  f->key);\n>> +\n>> +\t\taddr_type = key->addr_type;\n>> +\t}\n>> +\n>> +\tif (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {\n>> +\t\tstruct flow_dissector_key_ipv4_addrs *key =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV4_ADDRS,\n>> +\t\t\t\t\t\t  f->key);\n>> +\t\tstruct flow_dissector_key_ipv4_addrs *mask =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV4_ADDRS,\n>> +\t\t\t\t\t\t  f->mask);\n>> +\n>> +\t\tif (mask->dst) {\n>> +\t\t\tif (mask->dst == cpu_to_be32(0xffffffff)) {\n>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>> +\t\t\t} else {\n>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ip dst mask 0x%08x\\n\",\n>> +\t\t\t\t\tbe32_to_cpu(mask->dst));\n>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>> +\t\t\t}\n>> +\t\t}\n>> +\n>> +\t\tif (mask->src) {\n>> +\t\t\tif (mask->src == cpu_to_be32(0xffffffff)) {\n>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>> +\t\t\t} else {\n>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ip src mask 0x%08x\\n\",\n>> +\t\t\t\t\tbe32_to_cpu(mask->dst));\n>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>> +\t\t\t}\n>> +\t\t}\n>> +\n>> +\t\tif (field_flags & I40E_CLOUD_FIELD_TEN_ID) {\n>> +\t\t\tdev_err(&pf->pdev->dev, \"Tenant id not allowed for ip filter\\n\");\n>> +\t\t\treturn I40E_ERR_CONFIG;\n>> +\t\t}\n>> +\t\tfilter->dst_ip = key->dst;\n>> +\t\tfilter->src_ip = key->src;\n>> +\t\tfilter->ip_version = IPV4_VERSION;\n>> +\t}\n>> +\n>> +\tif (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {\n>> +\t\tstruct flow_dissector_key_ipv6_addrs *key =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV6_ADDRS,\n>> +\t\t\t\t\t\t  f->key);\n>> +\t\tstruct flow_dissector_key_ipv6_addrs *mask =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV6_ADDRS,\n>> +\t\t\t\t\t\t  f->mask);\n>> +\n>> +\t\t/* src and dest IPV6 address should not be LOOPBACK\n>> +\t\t * (0:0:0:0:0:0:0:1), which can be represented as ::1\n>> +\t\t */\n>> +\t\tif (ipv6_addr_loopback(&key->dst) ||\n>> +\t\t    ipv6_addr_loopback(&key->src)) {\n>> +\t\t\tdev_err(&pf->pdev->dev,\n>> +\t\t\t\t\"Bad ipv6, addr is LOOPBACK\\n\");\n>> +\t\t\treturn I40E_ERR_CONFIG;\n>> +\t\t}\n>> +\t\tif (!ipv6_addr_any(&mask->dst) || !ipv6_addr_any(&mask->src))\n>> +\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>> +\n>> +\t\tmemcpy(&filter->src_ipv6, &key->src.s6_addr32,\n>> +\t\t       sizeof(filter->src_ipv6));\n>> +\t\tmemcpy(&filter->dst_ipv6, &key->dst.s6_addr32,\n>> +\t\t       sizeof(filter->dst_ipv6));\n>> +\n>> +\t\t/* mark it as IPv6 filter, to be used later */\n>> +\t\tfilter->ip_version = IPV6_VERSION;\n>> +\t}\n>> +\n>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {\n>> +\t\tstruct flow_dissector_key_ports *key =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_PORTS,\n>> +\t\t\t\t\t\t  f->key);\n>> +\t\tstruct flow_dissector_key_ports *mask =\n>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_PORTS,\n>> +\t\t\t\t\t\t  f->mask);\n>> +\n>> +\t\tif (mask->src) {\n>> +\t\t\tif (mask->src == cpu_to_be16(0xffff)) {\n>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>> +\t\t\t} else {\n>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad src port mask 0x%04x\\n\",\n>> +\t\t\t\t\tbe16_to_cpu(mask->src));\n>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>> +\t\t\t}\n>> +\t\t}\n>> +\n>> +\t\tif (mask->dst) {\n>> +\t\t\tif (mask->dst == cpu_to_be16(0xffff)) {\n>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>> +\t\t\t} else {\n>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad dst port mask 0x%04x\\n\",\n>> +\t\t\t\t\tbe16_to_cpu(mask->dst));\n>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>> +\t\t\t}\n>> +\t\t}\n>> +\n>> +\t\tfilter->dst_port = key->dst;\n>> +\t\tfilter->src_port = key->src;\n>> +\n>> +\t\t/* For now, only supports destination port*/\n>> +\t\tfilter->port_type |= I40E_CLOUD_FILTER_PORT_DEST;\n>> +\n>> +\t\tswitch (filter->ip_proto) {\n>> +\t\tcase IPPROTO_TCP:\n>> +\t\tcase IPPROTO_UDP:\n>> +\t\t\tbreak;\n>> +\t\tdefault:\n>> +\t\t\tdev_err(&pf->pdev->dev,\n>> +\t\t\t\t\"Only UDP and TCP transport are supported\\n\");\n>> +\t\t\treturn -EINVAL;\n>> +\t\t}\n>> +\t}\n>> +\tfilter->flags = field_flags;\n>> +\treturn 0;\n>> +}\n>> +\n>> +/**\n>> + * i40e_handle_redirect_action: Forward to a traffic class on the device\n>> + * @vsi: Pointer to VSI\n>> + * @ifindex: ifindex of the device to forwared to\n>> + * @tc: traffic class index on the device\n>> + * @filter: Pointer to cloud filter structure\n>> + *\n>> + **/\n>> +static int i40e_handle_redirect_action(struct i40e_vsi *vsi, int ifindex, u8 tc,\n>> +\t\t\t\t       struct i40e_cloud_filter *filter)\n>> +{\n>> +\tstruct i40e_channel *ch, *ch_tmp;\n>> +\n>> +\t/* redirect to a traffic class on the same device */\n>> +\tif (vsi->netdev->ifindex == ifindex) {\n>> +\t\tif (tc == 0) {\n>> +\t\t\tfilter->seid = vsi->seid;\n>> +\t\t\treturn 0;\n>> +\t\t} else if (vsi->tc_config.enabled_tc & BIT(tc)) {\n>> +\t\t\tif (!filter->dst_port) {\n>> +\t\t\t\tdev_err(&vsi->back->pdev->dev,\n>> +\t\t\t\t\t\"Specify destination port to redirect to traffic class that is not default\\n\");\n>> +\t\t\t\treturn -EINVAL;\n>> +\t\t\t}\n>> +\t\t\tif (list_empty(&vsi->ch_list))\n>> +\t\t\t\treturn -EINVAL;\n>> +\t\t\tlist_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list,\n>> +\t\t\t\t\t\t list) {\n>> +\t\t\t\tif (ch->seid == vsi->tc_seid_map[tc])\n>> +\t\t\t\t\tfilter->seid = ch->seid;\n>> +\t\t\t}\n>> +\t\t\treturn 0;\n>> +\t\t}\n>> +\t}\n>> +\treturn -EINVAL;\n>> +}\n>> +\n>> +/**\n>> + * i40e_parse_tc_actions - Parse tc actions\n>> + * @vsi: Pointer to VSI\n>> + * @cls_flower: Pointer to struct tc_cls_flower_offload\n>> + * @filter: Pointer to cloud filter structure\n>> + *\n>> + **/\n>> +static int i40e_parse_tc_actions(struct i40e_vsi *vsi, struct tcf_exts *exts,\n>> +\t\t\t\t struct i40e_cloud_filter *filter)\n>> +{\n>> +\tconst struct tc_action *a;\n>> +\tLIST_HEAD(actions);\n>> +\tint err;\n>> +\n>> +\tif (!tcf_exts_has_actions(exts))\n>> +\t\treturn -EINVAL;\n>> +\n>> +\ttcf_exts_to_list(exts, &actions);\n>> +\tlist_for_each_entry(a, &actions, list) {\n>> +\t\t/* Drop action */\n>> +\t\tif (is_tcf_gact_shot(a)) {\n>> +\t\t\tdev_err(&vsi->back->pdev->dev,\n>> +\t\t\t\t\"Cloud filters do not support the drop action.\\n\");\n>> +\t\t\treturn -EOPNOTSUPP;\n>> +\t\t}\n>> +\n>> +\t\t/* Redirect to a traffic class on the same device */\n>> +\t\tif (!is_tcf_mirred_egress_redirect(a) && is_tcf_mirred_tc(a)) {\n>> +\t\t\tint ifindex = tcf_mirred_ifindex(a);\n>> +\t\t\tu8 tc = tcf_mirred_tc(a);\n>> +\n>> +\t\t\terr = i40e_handle_redirect_action(vsi, ifindex, tc,\n>> +\t\t\t\t\t\t\t  filter);\n>> +\t\t\tif (err == 0)\n>> +\t\t\t\treturn err;\n>> +\t\t}\n>> +\t}\n>> +\treturn -EINVAL;\n>> +}\n>> +\n>> +/**\n>> + * i40e_configure_clsflower - Configure tc flower filters\n>> + * @vsi: Pointer to VSI\n>> + * @cls_flower: Pointer to struct tc_cls_flower_offload\n>> + *\n>> + **/\n>> +static int i40e_configure_clsflower(struct i40e_vsi *vsi,\n>> +\t\t\t\t    struct tc_cls_flower_offload *cls_flower)\n>> +{\n>> +\tstruct i40e_cloud_filter *filter = NULL;\n>> +\tstruct i40e_pf *pf = vsi->back;\n>> +\tint err = 0;\n>> +\n>> +\tif (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state) ||\n>> +\t    test_bit(__I40E_RESET_INTR_RECEIVED, pf->state))\n>> +\t\treturn -EBUSY;\n>> +\n>> +\tif (pf->fdir_pf_active_filters ||\n>> +\t    (!hlist_empty(&pf->fdir_filter_list))) {\n>> +\t\tdev_err(&vsi->back->pdev->dev,\n>> +\t\t\t\"Flow Director Sideband filters exists, turn ntuple off to configure cloud filters\\n\");\n>> +\t\treturn -EINVAL;\n>> +\t}\n>> +\n>> +\tif (vsi->back->flags & I40E_FLAG_FD_SB_ENABLED) {\n>> +\t\tdev_err(&vsi->back->pdev->dev,\n>> +\t\t\t\"Disable Flow Director Sideband, configuring Cloud filters via tc-flower\\n\");\n>> +\t\tvsi->back->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>> +\t\tvsi->back->flags |= I40E_FLAG_FD_SB_TO_CLOUD_FILTER;\n>> +\t}\n>> +\n>> +\tfilter = kzalloc(sizeof(*filter), GFP_KERNEL);\n>> +\tif (!filter)\n>> +\t\treturn -ENOMEM;\n>> +\n>> +\tfilter->cookie = cls_flower->cookie;\n>> +\n>> +\terr = i40e_parse_cls_flower(vsi, cls_flower, filter);\n>> +\tif (err < 0)\n>> +\t\tgoto err;\n>> +\n>> +\terr = i40e_parse_tc_actions(vsi, cls_flower->exts, filter);\n>> +\tif (err < 0)\n>> +\t\tgoto err;\n>> +\n>> +\t/* Add cloud filter */\n>> +\tif (filter->dst_port)\n>> +\t\terr = i40e_add_del_cloud_filter_big_buf(vsi, filter, true);\n>> +\telse\n>> +\t\terr = i40e_add_del_cloud_filter(vsi, filter, true);\n>> +\n>> +\tif (err) {\n>> +\t\tdev_err(&pf->pdev->dev,\n>> +\t\t\t\"Failed to add cloud filter, err %s\\n\",\n>> +\t\t\ti40e_stat_str(&pf->hw, err));\n>> +\t\terr = i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);\n>> +\t\tgoto err;\n>> +\t}\n>> +\n>> +\t/* add filter to the ordered list */\n>> +\tINIT_HLIST_NODE(&filter->cloud_node);\n>> +\n>> +\thlist_add_head(&filter->cloud_node, &pf->cloud_filter_list);\n>> +\n>> +\tpf->num_cloud_filters++;\n>> +\n>> +\treturn err;\n>> +err:\n>> +\tkfree(filter);\n>> +\treturn err;\n>> +}\n>> +\n>> +/**\n>> + * i40e_find_cloud_filter - Find the could filter in the list\n>> + * @vsi: Pointer to VSI\n>> + * @cookie: filter specific cookie\n>> + *\n>> + **/\n>> +static struct i40e_cloud_filter *i40e_find_cloud_filter(struct i40e_vsi *vsi,\n>> +\t\t\t\t\t\t\tunsigned long *cookie)\n>> +{\n>> +\tstruct i40e_cloud_filter *filter = NULL;\n>> +\tstruct hlist_node *node2;\n>> +\n>> +\thlist_for_each_entry_safe(filter, node2,\n>> +\t\t\t\t  &vsi->back->cloud_filter_list, cloud_node)\n>> +\t\tif (!memcmp(cookie, &filter->cookie, sizeof(filter->cookie)))\n>> +\t\t\treturn filter;\n>> +\treturn NULL;\n>> +}\n>> +\n>> +/**\n>> + * i40e_delete_clsflower - Remove tc flower filters\n>> + * @vsi: Pointer to VSI\n>> + * @cls_flower: Pointer to struct tc_cls_flower_offload\n>> + *\n>> + **/\n>> +static int i40e_delete_clsflower(struct i40e_vsi *vsi,\n>> +\t\t\t\t struct tc_cls_flower_offload *cls_flower)\n>> +{\n>> +\tstruct i40e_cloud_filter *filter = NULL;\n>> +\tstruct i40e_pf *pf = vsi->back;\n>> +\tint err = 0;\n>> +\n>> +\tfilter = i40e_find_cloud_filter(vsi, &cls_flower->cookie);\n>> +\n>> +\tif (!filter)\n>> +\t\treturn -EINVAL;\n>> +\n>> +\thash_del(&filter->cloud_node);\n>> +\n>> +\tif (filter->dst_port)\n>> +\t\terr = i40e_add_del_cloud_filter_big_buf(vsi, filter, false);\n>> +\telse\n>> +\t\terr = i40e_add_del_cloud_filter(vsi, filter, false);\n>> +\tif (err) {\n>> +\t\tkfree(filter);\n>> +\t\tdev_err(&pf->pdev->dev,\n>> +\t\t\t\"Failed to delete cloud filter, err %s\\n\",\n>> +\t\t\ti40e_stat_str(&pf->hw, err));\n>> +\t\treturn i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);\n>> +\t}\n>> +\n>> +\tkfree(filter);\n>> +\tpf->num_cloud_filters--;\n>> +\n>> +\tif (!pf->num_cloud_filters)\n>> +\t\tif ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&\n>> +\t\t    !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {\n>> +\t\t\tpf->flags |= I40E_FLAG_FD_SB_ENABLED;\n>> +\t\t\tpf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;\n>> +\t\t\tpf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;\n>> +\t\t}\n>> +\treturn 0;\n>> +}\n>> +\n>> +/**\n>> + * i40e_setup_tc_cls_flower - flower classifier offloads\n>> + * @netdev: net device to configure\n>> + * @type_data: offload data\n>> + **/\n>> +static int i40e_setup_tc_cls_flower(struct net_device *netdev,\n>> +\t\t\t\t    struct tc_cls_flower_offload *cls_flower)\n>> +{\n>> +\tstruct i40e_netdev_priv *np = netdev_priv(netdev);\n>> +\tstruct i40e_vsi *vsi = np->vsi;\n>> +\n>> +\tif (!is_classid_clsact_ingress(cls_flower->common.classid) ||\n>> +\t    cls_flower->common.chain_index)\n>> +\t\treturn -EOPNOTSUPP;\n>> +\n>> +\tswitch (cls_flower->command) {\n>> +\tcase TC_CLSFLOWER_REPLACE:\n>> +\t\treturn i40e_configure_clsflower(vsi, cls_flower);\n>> +\tcase TC_CLSFLOWER_DESTROY:\n>> +\t\treturn i40e_delete_clsflower(vsi, cls_flower);\n>> +\tcase TC_CLSFLOWER_STATS:\n>> +\t\treturn -EOPNOTSUPP;\n>> +\tdefault:\n>> +\t\treturn -EINVAL;\n>> +\t}\n>> +}\n>> +\n>> static int __i40e_setup_tc(struct net_device *netdev, enum tc_setup_type type,\n>> \t\t\t   void *type_data)\n>> {\n>> -\tif (type != TC_SETUP_MQPRIO)\n>> +\tswitch (type) {\n>> +\tcase TC_SETUP_MQPRIO:\n>> +\t\treturn i40e_setup_tc(netdev, type_data);\n>> +\tcase TC_SETUP_CLSFLOWER:\n>> +\t\treturn i40e_setup_tc_cls_flower(netdev, type_data);\n>> +\tdefault:\n>> \t\treturn -EOPNOTSUPP;\n>> -\n>> -\treturn i40e_setup_tc(netdev, type_data);\n>> +\t}\n>> }\n>>\n>> /**\n>> @@ -6939,6 +7756,13 @@ static void i40e_cloud_filter_exit(struct i40e_pf *pf)\n>> \t\tkfree(cfilter);\n>> \t}\n>> \tpf->num_cloud_filters = 0;\n>> +\n>> +\tif ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&\n>> +\t    !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {\n>> +\t\tpf->flags |= I40E_FLAG_FD_SB_ENABLED;\n>> +\t\tpf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;\n>> +\t\tpf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;\n>> +\t}\n>> }\n>>\n>> /**\n>> @@ -8046,7 +8870,8 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb)\n>>  * i40e_get_capabilities - get info about the HW\n>>  * @pf: the PF struct\n>>  **/\n>> -static int i40e_get_capabilities(struct i40e_pf *pf)\n>> +static int i40e_get_capabilities(struct i40e_pf *pf,\n>> +\t\t\t\t enum i40e_admin_queue_opc list_type)\n>> {\n>> \tstruct i40e_aqc_list_capabilities_element_resp *cap_buf;\n>> \tu16 data_size;\n>> @@ -8061,9 +8886,8 @@ static int i40e_get_capabilities(struct i40e_pf *pf)\n>>\n>> \t\t/* this loads the data into the hw struct for us */\n>> \t\terr = i40e_aq_discover_capabilities(&pf->hw, cap_buf, buf_len,\n>> -\t\t\t\t\t    &data_size,\n>> -\t\t\t\t\t    i40e_aqc_opc_list_func_capabilities,\n>> -\t\t\t\t\t    NULL);\n>> +\t\t\t\t\t\t    &data_size, list_type,\n>> +\t\t\t\t\t\t    NULL);\n>> \t\t/* data loaded, buffer no longer needed */\n>> \t\tkfree(cap_buf);\n>>\n>> @@ -8080,26 +8904,44 @@ static int i40e_get_capabilities(struct i40e_pf *pf)\n>> \t\t}\n>> \t} while (err);\n>>\n>> -\tif (pf->hw.debug_mask & I40E_DEBUG_USER)\n>> -\t\tdev_info(&pf->pdev->dev,\n>> -\t\t\t \"pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\\n\",\n>> -\t\t\t pf->hw.pf_id, pf->hw.func_caps.num_vfs,\n>> -\t\t\t pf->hw.func_caps.num_msix_vectors,\n>> -\t\t\t pf->hw.func_caps.num_msix_vectors_vf,\n>> -\t\t\t pf->hw.func_caps.fd_filters_guaranteed,\n>> -\t\t\t pf->hw.func_caps.fd_filters_best_effort,\n>> -\t\t\t pf->hw.func_caps.num_tx_qp,\n>> -\t\t\t pf->hw.func_caps.num_vsis);\n>> -\n>> +\tif (pf->hw.debug_mask & I40E_DEBUG_USER) {\n>> +\t\tif (list_type == i40e_aqc_opc_list_func_capabilities) {\n>> +\t\t\tdev_info(&pf->pdev->dev,\n>> +\t\t\t\t \"pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\\n\",\n>> +\t\t\t\t pf->hw.pf_id, pf->hw.func_caps.num_vfs,\n>> +\t\t\t\t pf->hw.func_caps.num_msix_vectors,\n>> +\t\t\t\t pf->hw.func_caps.num_msix_vectors_vf,\n>> +\t\t\t\t pf->hw.func_caps.fd_filters_guaranteed,\n>> +\t\t\t\t pf->hw.func_caps.fd_filters_best_effort,\n>> +\t\t\t\t pf->hw.func_caps.num_tx_qp,\n>> +\t\t\t\t pf->hw.func_caps.num_vsis);\n>> +\t\t} else if (list_type == i40e_aqc_opc_list_dev_capabilities) {\n>> +\t\t\tdev_info(&pf->pdev->dev,\n>> +\t\t\t\t \"switch_mode=0x%04x, function_valid=0x%08x\\n\",\n>> +\t\t\t\t pf->hw.dev_caps.switch_mode,\n>> +\t\t\t\t pf->hw.dev_caps.valid_functions);\n>> +\t\t\tdev_info(&pf->pdev->dev,\n>> +\t\t\t\t \"SR-IOV=%d, num_vfs for all function=%u\\n\",\n>> +\t\t\t\t pf->hw.dev_caps.sr_iov_1_1,\n>> +\t\t\t\t pf->hw.dev_caps.num_vfs);\n>> +\t\t\tdev_info(&pf->pdev->dev,\n>> +\t\t\t\t \"num_vsis=%u, num_rx:%u, num_tx=%u\\n\",\n>> +\t\t\t\t pf->hw.dev_caps.num_vsis,\n>> +\t\t\t\t pf->hw.dev_caps.num_rx_qp,\n>> +\t\t\t\t pf->hw.dev_caps.num_tx_qp);\n>> +\t\t}\n>> +\t}\n>> +\tif (list_type == i40e_aqc_opc_list_func_capabilities) {\n>> #define DEF_NUM_VSI (1 + (pf->hw.func_caps.fcoe ? 1 : 0) \\\n>> \t\t       + pf->hw.func_caps.num_vfs)\n>> -\tif (pf->hw.revision_id == 0 && (DEF_NUM_VSI > pf->hw.func_caps.num_vsis)) {\n>> -\t\tdev_info(&pf->pdev->dev,\n>> -\t\t\t \"got num_vsis %d, setting num_vsis to %d\\n\",\n>> -\t\t\t pf->hw.func_caps.num_vsis, DEF_NUM_VSI);\n>> -\t\tpf->hw.func_caps.num_vsis = DEF_NUM_VSI;\n>> +\t\tif (pf->hw.revision_id == 0 &&\n>> +\t\t    (pf->hw.func_caps.num_vsis < DEF_NUM_VSI)) {\n>> +\t\t\tdev_info(&pf->pdev->dev,\n>> +\t\t\t\t \"got num_vsis %d, setting num_vsis to %d\\n\",\n>> +\t\t\t\t pf->hw.func_caps.num_vsis, DEF_NUM_VSI);\n>> +\t\t\tpf->hw.func_caps.num_vsis = DEF_NUM_VSI;\n>> +\t\t}\n>> \t}\n>> -\n>> \treturn 0;\n>> }\n>>\n>> @@ -8141,6 +8983,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)\n>> \t\tif (!vsi) {\n>> \t\t\tdev_info(&pf->pdev->dev, \"Couldn't create FDir VSI\\n\");\n>> \t\t\tpf->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>> +\t\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>> \t\t\treturn;\n>> \t\t}\n>> \t}\n>> @@ -8163,6 +9006,48 @@ static void i40e_fdir_teardown(struct i40e_pf *pf)\n>> }\n>>\n>> /**\n>> + * i40e_rebuild_cloud_filters - Rebuilds cloud filters for VSIs\n>> + * @vsi: PF main vsi\n>> + * @seid: seid of main or channel VSIs\n>> + *\n>> + * Rebuilds cloud filters associated with main VSI and channel VSIs if they\n>> + * existed before reset\n>> + **/\n>> +static int i40e_rebuild_cloud_filters(struct i40e_vsi *vsi, u16 seid)\n>> +{\n>> +\tstruct i40e_cloud_filter *cfilter;\n>> +\tstruct i40e_pf *pf = vsi->back;\n>> +\tstruct hlist_node *node;\n>> +\ti40e_status ret;\n>> +\n>> +\t/* Add cloud filters back if they exist */\n>> +\tif (hlist_empty(&pf->cloud_filter_list))\n>> +\t\treturn 0;\n>> +\n>> +\thlist_for_each_entry_safe(cfilter, node, &pf->cloud_filter_list,\n>> +\t\t\t\t  cloud_node) {\n>> +\t\tif (cfilter->seid != seid)\n>> +\t\t\tcontinue;\n>> +\n>> +\t\tif (cfilter->dst_port)\n>> +\t\t\tret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter,\n>> +\t\t\t\t\t\t\t\ttrue);\n>> +\t\telse\n>> +\t\t\tret = i40e_add_del_cloud_filter(vsi, cfilter, true);\n>> +\n>> +\t\tif (ret) {\n>> +\t\t\tdev_dbg(&pf->pdev->dev,\n>> +\t\t\t\t\"Failed to rebuild cloud filter, err %s aq_err %s\\n\",\n>> +\t\t\t\ti40e_stat_str(&pf->hw, ret),\n>> +\t\t\t\ti40e_aq_str(&pf->hw,\n>> +\t\t\t\t\t    pf->hw.aq.asq_last_status));\n>> +\t\t\treturn ret;\n>> +\t\t}\n>> +\t}\n>> +\treturn 0;\n>> +}\n>> +\n>> +/**\n>>  * i40e_rebuild_channels - Rebuilds channel VSIs if they existed before reset\n>>  * @vsi: PF main vsi\n>>  *\n>> @@ -8199,6 +9084,13 @@ static int i40e_rebuild_channels(struct i40e_vsi *vsi)\n>> \t\t\t\t\t\tI40E_BW_CREDIT_DIVISOR,\n>> \t\t\t\tch->seid);\n>> \t\t}\n>> +\t\tret = i40e_rebuild_cloud_filters(vsi, ch->seid);\n>> +\t\tif (ret) {\n>> +\t\t\tdev_dbg(&vsi->back->pdev->dev,\n>> +\t\t\t\t\"Failed to rebuild cloud filters for channel VSI %u\\n\",\n>> +\t\t\t\tch->seid);\n>> +\t\t\treturn ret;\n>> +\t\t}\n>> \t}\n>> \treturn 0;\n>> }\n>> @@ -8365,7 +9257,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)\n>> \t\ti40e_verify_eeprom(pf);\n>>\n>> \ti40e_clear_pxe_mode(hw);\n>> -\tret = i40e_get_capabilities(pf);\n>> +\tret = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);\n>> \tif (ret)\n>> \t\tgoto end_core_reset;\n>>\n>> @@ -8482,6 +9374,10 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)\n>> \t\t\tgoto end_unlock;\n>> \t}\n>>\n>> +\tret = i40e_rebuild_cloud_filters(vsi, vsi->seid);\n>> +\tif (ret)\n>> +\t\tgoto end_unlock;\n>> +\n>> \t/* PF Main VSI is rebuild by now, go ahead and rebuild channel VSIs\n>> \t * for this main VSI if they exist\n>> \t */\n>> @@ -9404,6 +10300,7 @@ static int i40e_init_msix(struct i40e_pf *pf)\n>> \t    (pf->num_fdsb_msix == 0)) {\n>> \t\tdev_info(&pf->pdev->dev, \"Sideband Flowdir disabled, not enough MSI-X vectors\\n\");\n>> \t\tpf->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>> +\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>> \t}\n>> \tif ((pf->flags & I40E_FLAG_VMDQ_ENABLED) &&\n>> \t    (pf->num_vmdq_msix == 0)) {\n>> @@ -9521,6 +10418,7 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)\n>> \t\t\t\t       I40E_FLAG_FD_SB_ENABLED\t|\n>> \t\t\t\t       I40E_FLAG_FD_ATR_ENABLED\t|\n>> \t\t\t\t       I40E_FLAG_VMDQ_ENABLED);\n>> +\t\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>\n>> \t\t\t/* rework the queue expectations without MSIX */\n>> \t\t\ti40e_determine_queue_usage(pf);\n>> @@ -10263,9 +11161,13 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)\n>> \t\t/* Enable filters and mark for reset */\n>> \t\tif (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))\n>> \t\t\tneed_reset = true;\n>> -\t\t/* enable FD_SB only if there is MSI-X vector */\n>> -\t\tif (pf->num_fdsb_msix > 0)\n>> +\t\t/* enable FD_SB only if there is MSI-X vector and no cloud\n>> +\t\t * filters exist\n>> +\t\t */\n>> +\t\tif (pf->num_fdsb_msix > 0 && !pf->num_cloud_filters) {\n>> \t\t\tpf->flags |= I40E_FLAG_FD_SB_ENABLED;\n>> +\t\t\tpf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;\n>> +\t\t}\n>> \t} else {\n>> \t\t/* turn off filters, mark for reset and clear SW filter list */\n>> \t\tif (pf->flags & I40E_FLAG_FD_SB_ENABLED) {\n>> @@ -10274,6 +11176,8 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)\n>> \t\t}\n>> \t\tpf->flags &= ~(I40E_FLAG_FD_SB_ENABLED |\n>> \t\t\t       I40E_FLAG_FD_SB_AUTO_DISABLED);\n>> +\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>> +\n>> \t\t/* reset fd counters */\n>> \t\tpf->fd_add_err = 0;\n>> \t\tpf->fd_atr_cnt = 0;\n>> @@ -10857,7 +11761,8 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)\n>> \t\tnetdev->hw_features |= NETIF_F_NTUPLE;\n>> \thw_features = hw_enc_features\t\t|\n>> \t\t      NETIF_F_HW_VLAN_CTAG_TX\t|\n>> -\t\t      NETIF_F_HW_VLAN_CTAG_RX;\n>> +\t\t      NETIF_F_HW_VLAN_CTAG_RX\t|\n>> +\t\t      NETIF_F_HW_TC;\n>>\n>> \tnetdev->hw_features |= hw_features;\n>>\n>> @@ -12159,8 +13064,10 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)\n>> \t*/\n>>\n>> \tif ((pf->hw.pf_id == 0) &&\n>> -\t    !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT))\n>> +\t    !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT)) {\n>> \t\tflags = I40E_AQ_SET_SWITCH_CFG_PROMISC;\n>> +\t\tpf->last_sw_conf_flags = flags;\n>> +\t}\n>>\n>> \tif (pf->hw.pf_id == 0) {\n>> \t\tu16 valid_flags;\n>> @@ -12176,6 +13083,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)\n>> \t\t\t\t\t     pf->hw.aq.asq_last_status));\n>> \t\t\t/* not a fatal problem, just keep going */\n>> \t\t}\n>> +\t\tpf->last_sw_conf_valid_flags = valid_flags;\n>> \t}\n>>\n>> \t/* first time setup */\n>> @@ -12273,6 +13181,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)\n>> \t\t\t       I40E_FLAG_DCB_ENABLED\t|\n>> \t\t\t       I40E_FLAG_SRIOV_ENABLED\t|\n>> \t\t\t       I40E_FLAG_VMDQ_ENABLED);\n>> +\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>> \t} else if (!(pf->flags & (I40E_FLAG_RSS_ENABLED |\n>> \t\t\t\t  I40E_FLAG_FD_SB_ENABLED |\n>> \t\t\t\t  I40E_FLAG_FD_ATR_ENABLED |\n>> @@ -12287,6 +13196,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)\n>> \t\t\t       I40E_FLAG_FD_ATR_ENABLED\t|\n>> \t\t\t       I40E_FLAG_DCB_ENABLED\t|\n>> \t\t\t       I40E_FLAG_VMDQ_ENABLED);\n>> +\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>> \t} else {\n>> \t\t/* Not enough queues for all TCs */\n>> \t\tif ((pf->flags & I40E_FLAG_DCB_CAPABLE) &&\n>> @@ -12310,6 +13220,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)\n>> \t\t\tqueues_left -= 1; /* save 1 queue for FD */\n>> \t\t} else {\n>> \t\t\tpf->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>> +\t\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>> \t\t\tdev_info(&pf->pdev->dev, \"not enough queues for Flow Director. Flow Director feature is disabled\\n\");\n>> \t\t}\n>> \t}\n>> @@ -12613,7 +13524,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n>> \t\tdev_warn(&pdev->dev, \"This device is a pre-production adapter/LOM. Please be aware there may be issues with your hardware. If you are experiencing problems please contact your Intel or hardware representative who provided you with this hardware.\\n\");\n>>\n>> \ti40e_clear_pxe_mode(hw);\n>> -\terr = i40e_get_capabilities(pf);\n>> +\terr = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);\n>> \tif (err)\n>> \t\tgoto err_adminq_setup;\n>>\n>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n>> index 92869f5..3bb6659 100644\n>> --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n>> +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n>> @@ -283,6 +283,22 @@ i40e_status i40e_aq_query_switch_comp_bw_config(struct i40e_hw *hw,\n>> \t\tstruct i40e_asq_cmd_details *cmd_details);\n>> i40e_status i40e_aq_resume_port_tx(struct i40e_hw *hw,\n>> \t\t\t\t   struct i40e_asq_cmd_details *cmd_details);\n>> +i40e_status\n>> +i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>> +\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>> +\t\t\t     u8 filter_count);\n>> +enum i40e_status_code\n>> +i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 vsi,\n>> +\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>> +\t\t\t  u8 filter_count);\n>> +enum i40e_status_code\n>> +i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 vsi,\n>> +\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>> +\t\t\t  u8 filter_count);\n>> +i40e_status\n>> +i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>> +\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>> +\t\t\t     u8 filter_count);\n>> i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,\n>> \t\t\t       struct i40e_lldp_variables *lldp_cfg);\n>> /* i40e_common */\n>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h\n>> index c019f46..af38881 100644\n>> --- a/drivers/net/ethernet/intel/i40e/i40e_type.h\n>> +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h\n>> @@ -287,6 +287,7 @@ struct i40e_hw_capabilities {\n>> #define I40E_NVM_IMAGE_TYPE_MODE1\t0x6\n>> #define I40E_NVM_IMAGE_TYPE_MODE2\t0x7\n>> #define I40E_NVM_IMAGE_TYPE_MODE3\t0x8\n>> +#define I40E_SWITCH_MODE_MASK\t\t0xF\n>>\n>> \tu32  management_mode;\n>> \tu32  mng_protocols_over_mctp;\n>> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h\n>> index b8c78bf..4fe27f0 100644\n>> --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h\n>> +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h\n>> @@ -1360,6 +1360,9 @@ struct i40e_aqc_cloud_filters_element_data {\n>> \t\tstruct {\n>> \t\t\tu8 data[16];\n>> \t\t} v6;\n>> +\t\tstruct {\n>> +\t\t\t__le16 data[8];\n>> +\t\t} raw_v6;\n>> \t} ipaddr;\n>> \t__le16\tflags;\n>> #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT\t\t\t0\n>>","headers":{"Return-Path":"<intel-wired-lan-bounces@osuosl.org>","X-Original-To":["incoming@patchwork.ozlabs.org","intel-wired-lan@lists.osuosl.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","intel-wired-lan@lists.osuosl.org"],"Authentication-Results":"ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=osuosl.org\n\t(client-ip=140.211.166.133; helo=hemlock.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)","Received":["from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xt9vL3dbhz9t1t\n\tfor <incoming@patchwork.ozlabs.org>;\n\tThu, 14 Sep 2017 18:00:46 +1000 (AEST)","from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id C43788A888;\n\tThu, 14 Sep 2017 08:00:44 +0000 (UTC)","from hemlock.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id 5on-rWyqrZEn; Thu, 14 Sep 2017 08:00:30 +0000 (UTC)","from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 7150C8AA2D;\n\tThu, 14 Sep 2017 08:00:29 +0000 (UTC)","from silver.osuosl.org (smtp3.osuosl.org [140.211.166.136])\n\tby ash.osuosl.org (Postfix) with ESMTP id 0F5941C26CB\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 14 Sep 2017 08:00:28 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n\tby silver.osuosl.org (Postfix) with ESMTP id 06AE7271C0\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 14 Sep 2017 08:00:28 +0000 (UTC)","from silver.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id TZmniCqm+GiS for <intel-wired-lan@lists.osuosl.org>;\n\tThu, 14 Sep 2017 08:00:14 +0000 (UTC)","from mga11.intel.com (mga11.intel.com [192.55.52.93])\n\tby silver.osuosl.org (Postfix) with ESMTPS id C543D30F79\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 14 Sep 2017 08:00:14 +0000 (UTC)","from fmsmga002.fm.intel.com ([10.253.24.26])\n\tby fmsmga102.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t14 Sep 2017 01:00:14 -0700","from anambiar-mobl.amr.corp.intel.com (HELO [10.254.52.171])\n\t([10.254.52.171])\n\tby fmsmga002.fm.intel.com with ESMTP; 14 Sep 2017 01:00:13 -0700"],"X-Virus-Scanned":["amavisd-new at osuosl.org","amavisd-new at osuosl.org"],"X-Greylist":"domain auto-whitelisted by SQLgrey-1.7.6","X-ExtLoop1":"1","X-IronPort-AV":"E=Sophos; i=\"5.42,391,1500966000\"; d=\"scan'208\";\n\ta=\"1218650485\"","To":"Jiri Pirko <jiri@resnulli.us>","References":"<150529632024.57063.15338545678487601430.stgit@anamdev.jf.intel.com>\n\t<150529679050.57063.3956015681929450874.stgit@anamdev.jf.intel.com>\n\t<20170913132611.GC1981@nanopsycho>","From":"\"Nambiar, Amritha\" <amritha.nambiar@intel.com>","Message-ID":"<82e0a065-c7d6-8fe6-aedc-154dd0dd88d6@intel.com>","Date":"Thu, 14 Sep 2017 01:00:13 -0700","User-Agent":"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:52.0) Gecko/20100101\n\tThunderbird/52.3.0","MIME-Version":"1.0","In-Reply-To":"<20170913132611.GC1981@nanopsycho>","Content-Language":"en-US","Cc":"netdev@vger.kernel.org, intel-wired-lan@lists.osuosl.org,\n\tmlxsw@mellanox.com","Subject":"Re: [Intel-wired-lan] [RFC PATCH v3 7/7] i40e: Enable cloud filters\n\tvia tc-flower","X-BeenThere":"intel-wired-lan@osuosl.org","X-Mailman-Version":"2.1.18-1","Precedence":"list","List-Id":"Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.osuosl.org>","List-Unsubscribe":"<https://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>","List-Archive":"<http://lists.osuosl.org/pipermail/intel-wired-lan/>","List-Post":"<mailto:intel-wired-lan@osuosl.org>","List-Help":"<mailto:intel-wired-lan-request@osuosl.org?subject=help>","List-Subscribe":"<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"intel-wired-lan-bounces@osuosl.org","Sender":"\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>"}},{"id":1777249,"web_url":"http://patchwork.ozlabs.org/comment/1777249/","msgid":"<dd18a4bd-f2fc-002b-2ef9-01de9a5a4162@intel.com>","list_archive_url":null,"date":"2017-09-28T19:22:15","subject":"Re: [Intel-wired-lan] [RFC PATCH v3 7/7] i40e: Enable cloud filters\n\tvia tc-flower","submitter":{"id":68504,"url":"http://patchwork.ozlabs.org/api/people/68504/","name":"Nambiar, Amritha","email":"amritha.nambiar@intel.com"},"content":"On 9/14/2017 1:00 AM, Nambiar, Amritha wrote:\n> On 9/13/2017 6:26 AM, Jiri Pirko wrote:\n>> Wed, Sep 13, 2017 at 11:59:50AM CEST, amritha.nambiar@intel.com wrote:\n>>> This patch enables tc-flower based hardware offloads. tc flower\n>>> filter provided by the kernel is configured as driver specific\n>>> cloud filter. The patch implements functions and admin queue\n>>> commands needed to support cloud filters in the driver and\n>>> adds cloud filters to configure these tc-flower filters.\n>>>\n>>> The only action supported is to redirect packets to a traffic class\n>>> on the same device.\n>>\n>> So basically you are not doing redirect, you are just setting tclass for\n>> matched packets, right? Why you use mirred for this? I think that\n>> you might consider extending g_act for that:\n>>\n>> # tc filter add dev eth0 protocol ip ingress \\\n>>   prio 1 flower dst_mac 3c:fd:fe:a0:d6:70 skip_sw \\\n>>   action tclass 0\n>>\n> Yes, this doesn't work like a typical egress redirect, but is aimed at\n> forwarding the matched packets to a different queue-group/traffic class\n> on the same device, so some sort-of ingress redirect in the hardware. I\n> possibly may not need the mirred-redirect as you say, I'll look into the\n> g_act way of doing this with a new gact tc action.\n> \n\nI was looking at introducing a new gact tclass action to TC. In the HW\noffload path, this sets a traffic class value for certain matched\npackets so they will be processed in a queue belonging to the traffic class.\n\n# tc filter add dev eth0 protocol ip parent ffff:\\\n  prio 2 flower dst_ip 192.168.3.5/32\\\n  ip_proto udp dst_port 25 skip_sw\\\n  action tclass 2\n\nBut, I'm having trouble defining what this action means in the kernel\ndatapath. For ingress, this action could just take the default path and\ndo nothing and only have meaning in the HW offloaded path. For egress,\ncertain qdiscs like 'multiq' and 'prio' could use this 'tclass' value\nfor band selection, while the 'mqprio' qdisc selects the traffic class\nbased on the skb priority in netdev_pick_tx(), so what would this action\nmean for the 'mqprio' qdisc?\n\nIt looks like the 'prio' qdisc uses band selection based on the\n'classid', so I was thinking of using the 'classid' through the cls\nflower filter and offload it to HW for the traffic class index, this way\nwe would have the same behavior in HW offload and SW fallback and there\nwould be no need for a separate tc action.\n\nIn HW:\n# tc filter add dev eth0 protocol ip parent ffff:\\\n  prio 2 flower dst_ip 192.168.3.5/32\\\n  ip_proto udp dst_port 25 skip_sw classid 1:2\\\n\nfilter pref 2 flower chain 0\nfilter pref 2 flower chain 0 handle 0x1 classid 1:2\n  eth_type ipv4\n  ip_proto udp\n  dst_ip 192.168.3.5\n  dst_port 25\n  skip_sw\n  in_hw\n\nThis will be used to route packets to traffic class 2.\n\nIn SW:\n# tc filter add dev eth0 protocol ip parent ffff:\\\n  prio 2 flower dst_ip 192.168.3.5/32\\\n  ip_proto udp dst_port 25 skip_hw classid 1:2\n\nfilter pref 2 flower chain 0\nfilter pref 2 flower chain 0 handle 0x1 classid 1:2\n  eth_type ipv4\n  ip_proto udp\n  dst_ip 192.168.3.5\n  dst_port 25\n  skip_hw\n  not_in_hw\n\n>>\n>>>\n>>> # tc qdisc add dev eth0 ingress\n>>> # ethtool -K eth0 hw-tc-offload on\n>>>\n>>> # tc filter add dev eth0 protocol ip parent ffff:\\\n>>>  prio 1 flower dst_mac 3c:fd:fe:a0:d6:70 skip_sw\\\n>>>  action mirred ingress redirect dev eth0 tclass 0\n>>>\n>>> # tc filter add dev eth0 protocol ip parent ffff:\\\n>>>  prio 2 flower dst_ip 192.168.3.5/32\\\n>>>  ip_proto udp dst_port 25 skip_sw\\\n>>>  action mirred ingress redirect dev eth0 tclass 1\n>>>\n>>> # tc filter add dev eth0 protocol ipv6 parent ffff:\\\n>>>  prio 3 flower dst_ip fe8::200:1\\\n>>>  ip_proto udp dst_port 66 skip_sw\\\n>>>  action mirred ingress redirect dev eth0 tclass 1\n>>>\n>>> Delete tc flower filter:\n>>> Example:\n>>>\n>>> # tc filter del dev eth0 parent ffff: prio 3 handle 0x1 flower\n>>> # tc filter del dev eth0 parent ffff:\n>>>\n>>> Flow Director Sideband is disabled while configuring cloud filters\n>>> via tc-flower and until any cloud filter exists.\n>>>\n>>> Unsupported matches when cloud filters are added using enhanced\n>>> big buffer cloud filter mode of underlying switch include:\n>>> 1. source port and source IP\n>>> 2. Combined MAC address and IP fields.\n>>> 3. Not specifying L4 port\n>>>\n>>> These filter matches can however be used to redirect traffic to\n>>> the main VSI (tc 0) which does not require the enhanced big buffer\n>>> cloud filter support.\n>>>\n>>> v3: Cleaned up some lengthy function names. Changed ipv6 address to\n>>> __be32 array instead of u8 array. Used macro for IP version. Minor\n>>> formatting changes.\n>>> v2:\n>>> 1. Moved I40E_SWITCH_MODE_MASK definition to i40e_type.h\n>>> 2. Moved dev_info for add/deleting cloud filters in else condition\n>>> 3. Fixed some format specifier in dev_err logs\n>>> 4. Refactored i40e_get_capabilities to take an additional\n>>>   list_type parameter and use it to query device and function\n>>>   level capabilities.\n>>> 5. Fixed parsing tc redirect action to check for the is_tcf_mirred_tc()\n>>>   to verify if redirect to a traffic class is supported.\n>>> 6. Added comments for Geneve fix in cloud filter big buffer AQ\n>>>   function definitions.\n>>> 7. Cleaned up setup_tc interface to rebase and work with Jiri's\n>>>   updates, separate function to process tc cls flower offloads.\n>>> 8. Changes to make Flow Director Sideband and Cloud filters mutually\n>>>   exclusive.\n>>>\n>>> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>\n>>> Signed-off-by: Kiran Patil <kiran.patil@intel.com>\n>>> Signed-off-by: Anjali Singhai Jain <anjali.singhai@intel.com>\n>>> Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>\n>>> ---\n>>> drivers/net/ethernet/intel/i40e/i40e.h             |   49 +\n>>> drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h  |    3 \n>>> drivers/net/ethernet/intel/i40e/i40e_common.c      |  189 ++++\n>>> drivers/net/ethernet/intel/i40e/i40e_main.c        |  971 +++++++++++++++++++-\n>>> drivers/net/ethernet/intel/i40e/i40e_prototype.h   |   16 \n>>> drivers/net/ethernet/intel/i40e/i40e_type.h        |    1 \n>>> .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h    |    3 \n>>> 7 files changed, 1202 insertions(+), 30 deletions(-)\n>>>\n>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h\n>>> index 6018fb6..b110519 100644\n>>> --- a/drivers/net/ethernet/intel/i40e/i40e.h\n>>> +++ b/drivers/net/ethernet/intel/i40e/i40e.h\n>>> @@ -55,6 +55,8 @@\n>>> #include <linux/net_tstamp.h>\n>>> #include <linux/ptp_clock_kernel.h>\n>>> #include <net/pkt_cls.h>\n>>> +#include <net/tc_act/tc_gact.h>\n>>> +#include <net/tc_act/tc_mirred.h>\n>>> #include \"i40e_type.h\"\n>>> #include \"i40e_prototype.h\"\n>>> #include \"i40e_client.h\"\n>>> @@ -252,9 +254,52 @@ struct i40e_fdir_filter {\n>>> \tu32 fd_id;\n>>> };\n>>>\n>>> +#define IPV4_VERSION 4\n>>> +#define IPV6_VERSION 6\n>>> +\n>>> +#define I40E_CLOUD_FIELD_OMAC\t0x01\n>>> +#define I40E_CLOUD_FIELD_IMAC\t0x02\n>>> +#define I40E_CLOUD_FIELD_IVLAN\t0x04\n>>> +#define I40E_CLOUD_FIELD_TEN_ID\t0x08\n>>> +#define I40E_CLOUD_FIELD_IIP\t0x10\n>>> +\n>>> +#define I40E_CLOUD_FILTER_FLAGS_OMAC\tI40E_CLOUD_FIELD_OMAC\n>>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC\tI40E_CLOUD_FIELD_IMAC\n>>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN\t(I40E_CLOUD_FIELD_IMAC | \\\n>>> +\t\t\t\t\t\t I40E_CLOUD_FIELD_IVLAN)\n>>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID\t(I40E_CLOUD_FIELD_IMAC | \\\n>>> +\t\t\t\t\t\t I40E_CLOUD_FIELD_TEN_ID)\n>>> +#define I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC (I40E_CLOUD_FIELD_OMAC | \\\n>>> +\t\t\t\t\t\t  I40E_CLOUD_FIELD_IMAC | \\\n>>> +\t\t\t\t\t\t  I40E_CLOUD_FIELD_TEN_ID)\n>>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID (I40E_CLOUD_FIELD_IMAC | \\\n>>> +\t\t\t\t\t\t   I40E_CLOUD_FIELD_IVLAN | \\\n>>> +\t\t\t\t\t\t   I40E_CLOUD_FIELD_TEN_ID)\n>>> +#define I40E_CLOUD_FILTER_FLAGS_IIP\tI40E_CLOUD_FIELD_IIP\n>>> +\n>>> struct i40e_cloud_filter {\n>>> \tstruct hlist_node cloud_node;\n>>> \tunsigned long cookie;\n>>> +\t/* cloud filter input set follows */\n>>> +\tu8 dst_mac[ETH_ALEN];\n>>> +\tu8 src_mac[ETH_ALEN];\n>>> +\t__be16 vlan_id;\n>>> +\t__be32 dst_ip;\n>>> +\t__be32 src_ip;\n>>> +\t__be32 dst_ipv6[4];\n>>> +\t__be32 src_ipv6[4];\n>>> +\t__be16 dst_port;\n>>> +\t__be16 src_port;\n>>> +\tu32 ip_version;\n>>> +\tu8 ip_proto;\t/* IPPROTO value */\n>>> +\t/* L4 port type: src or destination port */\n>>> +#define I40E_CLOUD_FILTER_PORT_SRC\t0x01\n>>> +#define I40E_CLOUD_FILTER_PORT_DEST\t0x02\n>>> +\tu8 port_type;\n>>> +\tu32 tenant_id;\n>>> +\tu8 flags;\n>>> +#define I40E_CLOUD_TNL_TYPE_NONE\t0xff\n>>> +\tu8 tunnel_type;\n>>> \tu16 seid;\t/* filter control */\n>>> };\n>>>\n>>> @@ -491,6 +536,8 @@ struct i40e_pf {\n>>> #define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED\tBIT(27)\n>>> #define I40E_FLAG_SOURCE_PRUNING_DISABLED\tBIT(28)\n>>> #define I40E_FLAG_TC_MQPRIO\t\t\tBIT(29)\n>>> +#define I40E_FLAG_FD_SB_INACTIVE\t\tBIT(30)\n>>> +#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER\t\tBIT(31)\n>>>\n>>> \tstruct i40e_client_instance *cinst;\n>>> \tbool stat_offsets_loaded;\n>>> @@ -573,6 +620,8 @@ struct i40e_pf {\n>>> \tu16 phy_led_val;\n>>>\n>>> \tu16 override_q_count;\n>>> +\tu16 last_sw_conf_flags;\n>>> +\tu16 last_sw_conf_valid_flags;\n>>> };\n>>>\n>>> /**\n>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h\n>>> index 2e567c2..feb3d42 100644\n>>> --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h\n>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h\n>>> @@ -1392,6 +1392,9 @@ struct i40e_aqc_cloud_filters_element_data {\n>>> \t\tstruct {\n>>> \t\t\tu8 data[16];\n>>> \t\t} v6;\n>>> +\t\tstruct {\n>>> +\t\t\t__le16 data[8];\n>>> +\t\t} raw_v6;\n>>> \t} ipaddr;\n>>> \t__le16\tflags;\n>>> #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT\t\t\t0\n>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c\n>>> index 9567702..d9c9665 100644\n>>> --- a/drivers/net/ethernet/intel/i40e/i40e_common.c\n>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c\n>>> @@ -5434,5 +5434,194 @@ i40e_add_pinfo_to_list(struct i40e_hw *hw,\n>>>\n>>> \tstatus = i40e_aq_write_ppp(hw, (void *)sec, sec->data_end,\n>>> \t\t\t\t   track_id, &offset, &info, NULL);\n>>> +\n>>> +\treturn status;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_aq_add_cloud_filters\n>>> + * @hw: pointer to the hardware structure\n>>> + * @seid: VSI seid to add cloud filters from\n>>> + * @filters: Buffer which contains the filters to be added\n>>> + * @filter_count: number of filters contained in the buffer\n>>> + *\n>>> + * Set the cloud filters for a given VSI.  The contents of the\n>>> + * i40e_aqc_cloud_filters_element_data are filled in by the caller\n>>> + * of the function.\n>>> + *\n>>> + **/\n>>> +enum i40e_status_code\n>>> +i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 seid,\n>>> +\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>>> +\t\t\t  u8 filter_count)\n>>> +{\n>>> +\tstruct i40e_aq_desc desc;\n>>> +\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>>> +\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>>> +\tenum i40e_status_code status;\n>>> +\tu16 buff_len;\n>>> +\n>>> +\ti40e_fill_default_direct_cmd_desc(&desc,\n>>> +\t\t\t\t\t  i40e_aqc_opc_add_cloud_filters);\n>>> +\n>>> +\tbuff_len = filter_count * sizeof(*filters);\n>>> +\tdesc.datalen = cpu_to_le16(buff_len);\n>>> +\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>>> +\tcmd->num_filters = filter_count;\n>>> +\tcmd->seid = cpu_to_le16(seid);\n>>> +\n>>> +\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>>> +\n>>> +\treturn status;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_aq_add_cloud_filters_bb\n>>> + * @hw: pointer to the hardware structure\n>>> + * @seid: VSI seid to add cloud filters from\n>>> + * @filters: Buffer which contains the filters in big buffer to be added\n>>> + * @filter_count: number of filters contained in the buffer\n>>> + *\n>>> + * Set the big buffer cloud filters for a given VSI.  The contents of the\n>>> + * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the\n>>> + * function.\n>>> + *\n>>> + **/\n>>> +i40e_status\n>>> +i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>>> +\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>>> +\t\t\t     u8 filter_count)\n>>> +{\n>>> +\tstruct i40e_aq_desc desc;\n>>> +\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>>> +\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>>> +\ti40e_status status;\n>>> +\tu16 buff_len;\n>>> +\tint i;\n>>> +\n>>> +\ti40e_fill_default_direct_cmd_desc(&desc,\n>>> +\t\t\t\t\t  i40e_aqc_opc_add_cloud_filters);\n>>> +\n>>> +\tbuff_len = filter_count * sizeof(*filters);\n>>> +\tdesc.datalen = cpu_to_le16(buff_len);\n>>> +\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>>> +\tcmd->num_filters = filter_count;\n>>> +\tcmd->seid = cpu_to_le16(seid);\n>>> +\tcmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;\n>>> +\n>>> +\tfor (i = 0; i < filter_count; i++) {\n>>> +\t\tu16 tnl_type;\n>>> +\t\tu32 ti;\n>>> +\n>>> +\t\ttnl_type = (le16_to_cpu(filters[i].element.flags) &\n>>> +\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>\n>>> +\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;\n>>> +\n>>> +\t\t/* For Geneve, the VNI should be placed in offset shifted by a\n>>> +\t\t * byte than the offset for the Tenant ID for rest of the\n>>> +\t\t * tunnels.\n>>> +\t\t */\n>>> +\t\tif (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {\n>>> +\t\t\tti = le32_to_cpu(filters[i].element.tenant_id);\n>>> +\t\t\tfilters[i].element.tenant_id = cpu_to_le32(ti << 8);\n>>> +\t\t}\n>>> +\t}\n>>> +\n>>> +\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>>> +\n>>> +\treturn status;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_aq_rem_cloud_filters\n>>> + * @hw: pointer to the hardware structure\n>>> + * @seid: VSI seid to remove cloud filters from\n>>> + * @filters: Buffer which contains the filters to be removed\n>>> + * @filter_count: number of filters contained in the buffer\n>>> + *\n>>> + * Remove the cloud filters for a given VSI.  The contents of the\n>>> + * i40e_aqc_cloud_filters_element_data are filled in by the caller\n>>> + * of the function.\n>>> + *\n>>> + **/\n>>> +enum i40e_status_code\n>>> +i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 seid,\n>>> +\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>>> +\t\t\t  u8 filter_count)\n>>> +{\n>>> +\tstruct i40e_aq_desc desc;\n>>> +\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>>> +\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>>> +\tenum i40e_status_code status;\n>>> +\tu16 buff_len;\n>>> +\n>>> +\ti40e_fill_default_direct_cmd_desc(&desc,\n>>> +\t\t\t\t\t  i40e_aqc_opc_remove_cloud_filters);\n>>> +\n>>> +\tbuff_len = filter_count * sizeof(*filters);\n>>> +\tdesc.datalen = cpu_to_le16(buff_len);\n>>> +\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>>> +\tcmd->num_filters = filter_count;\n>>> +\tcmd->seid = cpu_to_le16(seid);\n>>> +\n>>> +\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>>> +\n>>> +\treturn status;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_aq_rem_cloud_filters_bb\n>>> + * @hw: pointer to the hardware structure\n>>> + * @seid: VSI seid to remove cloud filters from\n>>> + * @filters: Buffer which contains the filters in big buffer to be removed\n>>> + * @filter_count: number of filters contained in the buffer\n>>> + *\n>>> + * Remove the big buffer cloud filters for a given VSI.  The contents of the\n>>> + * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the\n>>> + * function.\n>>> + *\n>>> + **/\n>>> +i40e_status\n>>> +i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>>> +\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>>> +\t\t\t     u8 filter_count)\n>>> +{\n>>> +\tstruct i40e_aq_desc desc;\n>>> +\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>>> +\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>>> +\ti40e_status status;\n>>> +\tu16 buff_len;\n>>> +\tint i;\n>>> +\n>>> +\ti40e_fill_default_direct_cmd_desc(&desc,\n>>> +\t\t\t\t\t  i40e_aqc_opc_remove_cloud_filters);\n>>> +\n>>> +\tbuff_len = filter_count * sizeof(*filters);\n>>> +\tdesc.datalen = cpu_to_le16(buff_len);\n>>> +\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>>> +\tcmd->num_filters = filter_count;\n>>> +\tcmd->seid = cpu_to_le16(seid);\n>>> +\tcmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;\n>>> +\n>>> +\tfor (i = 0; i < filter_count; i++) {\n>>> +\t\tu16 tnl_type;\n>>> +\t\tu32 ti;\n>>> +\n>>> +\t\ttnl_type = (le16_to_cpu(filters[i].element.flags) &\n>>> +\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>\n>>> +\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;\n>>> +\n>>> +\t\t/* For Geneve, the VNI should be placed in offset shifted by a\n>>> +\t\t * byte than the offset for the Tenant ID for rest of the\n>>> +\t\t * tunnels.\n>>> +\t\t */\n>>> +\t\tif (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {\n>>> +\t\t\tti = le32_to_cpu(filters[i].element.tenant_id);\n>>> +\t\t\tfilters[i].element.tenant_id = cpu_to_le32(ti << 8);\n>>> +\t\t}\n>>> +\t}\n>>> +\n>>> +\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>>> +\n>>> \treturn status;\n>>> }\n>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c\n>>> index afcf08a..96ee608 100644\n>>> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c\n>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c\n>>> @@ -69,6 +69,15 @@ static int i40e_reset(struct i40e_pf *pf);\n>>> static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired);\n>>> static void i40e_fdir_sb_setup(struct i40e_pf *pf);\n>>> static int i40e_veb_get_bw_info(struct i40e_veb *veb);\n>>> +static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,\n>>> +\t\t\t\t     struct i40e_cloud_filter *filter,\n>>> +\t\t\t\t     bool add);\n>>> +static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,\n>>> +\t\t\t\t\t     struct i40e_cloud_filter *filter,\n>>> +\t\t\t\t\t     bool add);\n>>> +static int i40e_get_capabilities(struct i40e_pf *pf,\n>>> +\t\t\t\t enum i40e_admin_queue_opc list_type);\n>>> +\n>>>\n>>> /* i40e_pci_tbl - PCI Device ID Table\n>>>  *\n>>> @@ -5478,7 +5487,11 @@ int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate)\n>>>  **/\n>>> static void i40e_remove_queue_channels(struct i40e_vsi *vsi)\n>>> {\n>>> +\tenum i40e_admin_queue_err last_aq_status;\n>>> +\tstruct i40e_cloud_filter *cfilter;\n>>> \tstruct i40e_channel *ch, *ch_tmp;\n>>> +\tstruct i40e_pf *pf = vsi->back;\n>>> +\tstruct hlist_node *node;\n>>> \tint ret, i;\n>>>\n>>> \t/* Reset rss size that was stored when reconfiguring rss for\n>>> @@ -5519,6 +5532,29 @@ static void i40e_remove_queue_channels(struct i40e_vsi *vsi)\n>>> \t\t\t\t \"Failed to reset tx rate for ch->seid %u\\n\",\n>>> \t\t\t\t ch->seid);\n>>>\n>>> +\t\t/* delete cloud filters associated with this channel */\n>>> +\t\thlist_for_each_entry_safe(cfilter, node,\n>>> +\t\t\t\t\t  &pf->cloud_filter_list, cloud_node) {\n>>> +\t\t\tif (cfilter->seid != ch->seid)\n>>> +\t\t\t\tcontinue;\n>>> +\n>>> +\t\t\thash_del(&cfilter->cloud_node);\n>>> +\t\t\tif (cfilter->dst_port)\n>>> +\t\t\t\tret = i40e_add_del_cloud_filter_big_buf(vsi,\n>>> +\t\t\t\t\t\t\t\t\tcfilter,\n>>> +\t\t\t\t\t\t\t\t\tfalse);\n>>> +\t\t\telse\n>>> +\t\t\t\tret = i40e_add_del_cloud_filter(vsi, cfilter,\n>>> +\t\t\t\t\t\t\t\tfalse);\n>>> +\t\t\tlast_aq_status = pf->hw.aq.asq_last_status;\n>>> +\t\t\tif (ret)\n>>> +\t\t\t\tdev_info(&pf->pdev->dev,\n>>> +\t\t\t\t\t \"Failed to delete cloud filter, err %s aq_err %s\\n\",\n>>> +\t\t\t\t\t i40e_stat_str(&pf->hw, ret),\n>>> +\t\t\t\t\t i40e_aq_str(&pf->hw, last_aq_status));\n>>> +\t\t\tkfree(cfilter);\n>>> +\t\t}\n>>> +\n>>> \t\t/* delete VSI from FW */\n>>> \t\tret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,\n>>> \t\t\t\t\t     NULL);\n>>> @@ -5970,6 +6006,74 @@ static bool i40e_setup_channel(struct i40e_pf *pf, struct i40e_vsi *vsi,\n>>> }\n>>>\n>>> /**\n>>> + * i40e_validate_and_set_switch_mode - sets up switch mode correctly\n>>> + * @vsi: ptr to VSI which has PF backing\n>>> + * @l4type: true for TCP ond false for UDP\n>>> + * @port_type: true if port is destination and false if port is source\n>>> + *\n>>> + * Sets up switch mode correctly if it needs to be changed and perform\n>>> + * what are allowed modes.\n>>> + **/\n>>> +static int i40e_validate_and_set_switch_mode(struct i40e_vsi *vsi, bool l4type,\n>>> +\t\t\t\t\t     bool port_type)\n>>> +{\n>>> +\tu8 mode;\n>>> +\tstruct i40e_pf *pf = vsi->back;\n>>> +\tstruct i40e_hw *hw = &pf->hw;\n>>> +\tint ret;\n>>> +\n>>> +\tret = i40e_get_capabilities(pf, i40e_aqc_opc_list_dev_capabilities);\n>>> +\tif (ret)\n>>> +\t\treturn -EINVAL;\n>>> +\n>>> +\tif (hw->dev_caps.switch_mode) {\n>>> +\t\t/* if switch mode is set, support mode2 (non-tunneled for\n>>> +\t\t * cloud filter) for now\n>>> +\t\t */\n>>> +\t\tu32 switch_mode = hw->dev_caps.switch_mode &\n>>> +\t\t\t\t\t\t\tI40E_SWITCH_MODE_MASK;\n>>> +\t\tif (switch_mode >= I40E_NVM_IMAGE_TYPE_MODE1) {\n>>> +\t\t\tif (switch_mode == I40E_NVM_IMAGE_TYPE_MODE2)\n>>> +\t\t\t\treturn 0;\n>>> +\t\t\tdev_err(&pf->pdev->dev,\n>>> +\t\t\t\t\"Invalid switch_mode (%d), only non-tunneled mode for cloud filter is supported\\n\",\n>>> +\t\t\t\thw->dev_caps.switch_mode);\n>>> +\t\t\treturn -EINVAL;\n>>> +\t\t}\n>>> +\t}\n>>> +\n>>> +\t/* port_type: true for destination port and false for source port\n>>> +\t * For now, supports only destination port type\n>>> +\t */\n>>> +\tif (!port_type) {\n>>> +\t\tdev_err(&pf->pdev->dev, \"src port type not supported\\n\");\n>>> +\t\treturn -EINVAL;\n>>> +\t}\n>>> +\n>>> +\t/* Set Bit 7 to be valid */\n>>> +\tmode = I40E_AQ_SET_SWITCH_BIT7_VALID;\n>>> +\n>>> +\t/* Set L4type to both TCP and UDP support */\n>>> +\tmode |= I40E_AQ_SET_SWITCH_L4_TYPE_BOTH;\n>>> +\n>>> +\t/* Set cloud filter mode */\n>>> +\tmode |= I40E_AQ_SET_SWITCH_MODE_NON_TUNNEL;\n>>> +\n>>> +\t/* Prep mode field for set_switch_config */\n>>> +\tret = i40e_aq_set_switch_config(hw, pf->last_sw_conf_flags,\n>>> +\t\t\t\t\tpf->last_sw_conf_valid_flags,\n>>> +\t\t\t\t\tmode, NULL);\n>>> +\tif (ret && hw->aq.asq_last_status != I40E_AQ_RC_ESRCH)\n>>> +\t\tdev_err(&pf->pdev->dev,\n>>> +\t\t\t\"couldn't set switch config bits, err %s aq_err %s\\n\",\n>>> +\t\t\ti40e_stat_str(hw, ret),\n>>> +\t\t\ti40e_aq_str(hw,\n>>> +\t\t\t\t    hw->aq.asq_last_status));\n>>> +\n>>> +\treturn ret;\n>>> +}\n>>> +\n>>> +/**\n>>>  * i40e_create_queue_channel - function to create channel\n>>>  * @vsi: VSI to be configured\n>>>  * @ch: ptr to channel (it contains channel specific params)\n>>> @@ -6735,13 +6839,726 @@ static int i40e_setup_tc(struct net_device *netdev, void *type_data)\n>>> \treturn ret;\n>>> }\n>>>\n>>> +/**\n>>> + * i40e_set_cld_element - sets cloud filter element data\n>>> + * @filter: cloud filter rule\n>>> + * @cld: ptr to cloud filter element data\n>>> + *\n>>> + * This is helper function to copy data into cloud filter element\n>>> + **/\n>>> +static inline void\n>>> +i40e_set_cld_element(struct i40e_cloud_filter *filter,\n>>> +\t\t     struct i40e_aqc_cloud_filters_element_data *cld)\n>>> +{\n>>> +\tint i, j;\n>>> +\tu32 ipa;\n>>> +\n>>> +\tmemset(cld, 0, sizeof(*cld));\n>>> +\tether_addr_copy(cld->outer_mac, filter->dst_mac);\n>>> +\tether_addr_copy(cld->inner_mac, filter->src_mac);\n>>> +\n>>> +\tif (filter->ip_version == IPV6_VERSION) {\n>>> +#define IPV6_MAX_INDEX\t(ARRAY_SIZE(filter->dst_ipv6) - 1)\n>>> +\t\tfor (i = 0, j = 0; i < 4; i++, j += 2) {\n>>> +\t\t\tipa = be32_to_cpu(filter->dst_ipv6[IPV6_MAX_INDEX - i]);\n>>> +\t\t\tipa = cpu_to_le32(ipa);\n>>> +\t\t\tmemcpy(&cld->ipaddr.raw_v6.data[j], &ipa, 4);\n>>> +\t\t}\n>>> +\t} else {\n>>> +\t\tipa = be32_to_cpu(filter->dst_ip);\n>>> +\t\tmemcpy(&cld->ipaddr.v4.data, &ipa, 4);\n>>> +\t}\n>>> +\n>>> +\tcld->inner_vlan = cpu_to_le16(ntohs(filter->vlan_id));\n>>> +\n>>> +\t/* tenant_id is not supported by FW now, once the support is enabled\n>>> +\t * fill the cld->tenant_id with cpu_to_le32(filter->tenant_id)\n>>> +\t */\n>>> +\tif (filter->tenant_id)\n>>> +\t\treturn;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_add_del_cloud_filter - Add/del cloud filter\n>>> + * @vsi: pointer to VSI\n>>> + * @filter: cloud filter rule\n>>> + * @add: if true, add, if false, delete\n>>> + *\n>>> + * Add or delete a cloud filter for a specific flow spec.\n>>> + * Returns 0 if the filter were successfully added.\n>>> + **/\n>>> +static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,\n>>> +\t\t\t\t     struct i40e_cloud_filter *filter, bool add)\n>>> +{\n>>> +\tstruct i40e_aqc_cloud_filters_element_data cld_filter;\n>>> +\tstruct i40e_pf *pf = vsi->back;\n>>> +\tint ret;\n>>> +\tstatic const u16 flag_table[128] = {\n>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_OMAC]  =\n>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_OMAC,\n>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC]  =\n>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC,\n>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN]  =\n>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN,\n>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID] =\n>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID,\n>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC] =\n>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC,\n>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID] =\n>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID,\n>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IIP] =\n>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IIP,\n>>> +\t};\n>>> +\n>>> +\tif (filter->flags >= ARRAY_SIZE(flag_table))\n>>> +\t\treturn I40E_ERR_CONFIG;\n>>> +\n>>> +\t/* copy element needed to add cloud filter from filter */\n>>> +\ti40e_set_cld_element(filter, &cld_filter);\n>>> +\n>>> +\tif (filter->tunnel_type != I40E_CLOUD_TNL_TYPE_NONE)\n>>> +\t\tcld_filter.flags = cpu_to_le16(filter->tunnel_type <<\n>>> +\t\t\t\t\t     I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT);\n>>> +\n>>> +\tif (filter->ip_version == IPV6_VERSION)\n>>> +\t\tcld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |\n>>> +\t\t\t\t\t\tI40E_AQC_ADD_CLOUD_FLAGS_IPV6);\n>>> +\telse\n>>> +\t\tcld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |\n>>> +\t\t\t\t\t\tI40E_AQC_ADD_CLOUD_FLAGS_IPV4);\n>>> +\n>>> +\tif (add)\n>>> +\t\tret = i40e_aq_add_cloud_filters(&pf->hw, filter->seid,\n>>> +\t\t\t\t\t\t&cld_filter, 1);\n>>> +\telse\n>>> +\t\tret = i40e_aq_rem_cloud_filters(&pf->hw, filter->seid,\n>>> +\t\t\t\t\t\t&cld_filter, 1);\n>>> +\tif (ret)\n>>> +\t\tdev_dbg(&pf->pdev->dev,\n>>> +\t\t\t\"Failed to %s cloud filter using l4 port %u, err %d aq_err %d\\n\",\n>>> +\t\t\tadd ? \"add\" : \"delete\", filter->dst_port, ret,\n>>> +\t\t\tpf->hw.aq.asq_last_status);\n>>> +\telse\n>>> +\t\tdev_info(&pf->pdev->dev,\n>>> +\t\t\t \"%s cloud filter for VSI: %d\\n\",\n>>> +\t\t\t add ? \"Added\" : \"Deleted\", filter->seid);\n>>> +\treturn ret;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_add_del_cloud_filter_big_buf - Add/del cloud filter using big_buf\n>>> + * @vsi: pointer to VSI\n>>> + * @filter: cloud filter rule\n>>> + * @add: if true, add, if false, delete\n>>> + *\n>>> + * Add or delete a cloud filter for a specific flow spec using big buffer.\n>>> + * Returns 0 if the filter were successfully added.\n>>> + **/\n>>> +static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,\n>>> +\t\t\t\t\t     struct i40e_cloud_filter *filter,\n>>> +\t\t\t\t\t     bool add)\n>>> +{\n>>> +\tstruct i40e_aqc_cloud_filters_element_bb cld_filter;\n>>> +\tstruct i40e_pf *pf = vsi->back;\n>>> +\tint ret;\n>>> +\n>>> +\t/* Both (Outer/Inner) valid mac_addr are not supported */\n>>> +\tif (is_valid_ether_addr(filter->dst_mac) &&\n>>> +\t    is_valid_ether_addr(filter->src_mac))\n>>> +\t\treturn -EINVAL;\n>>> +\n>>> +\t/* Make sure port is specified, otherwise bail out, for channel\n>>> +\t * specific cloud filter needs 'L4 port' to be non-zero\n>>> +\t */\n>>> +\tif (!filter->dst_port)\n>>> +\t\treturn -EINVAL;\n>>> +\n>>> +\t/* adding filter using src_port/src_ip is not supported at this stage */\n>>> +\tif (filter->src_port || filter->src_ip ||\n>>> +\t    !ipv6_addr_any((struct in6_addr *)&filter->src_ipv6))\n>>> +\t\treturn -EINVAL;\n>>> +\n>>> +\t/* copy element needed to add cloud filter from filter */\n>>> +\ti40e_set_cld_element(filter, &cld_filter.element);\n>>> +\n>>> +\tif (is_valid_ether_addr(filter->dst_mac) ||\n>>> +\t    is_valid_ether_addr(filter->src_mac) ||\n>>> +\t    is_multicast_ether_addr(filter->dst_mac) ||\n>>> +\t    is_multicast_ether_addr(filter->src_mac)) {\n>>> +\t\t/* MAC + IP : unsupported mode */\n>>> +\t\tif (filter->dst_ip)\n>>> +\t\t\treturn -EINVAL;\n>>> +\n>>> +\t\t/* since we validated that L4 port must be valid before\n>>> +\t\t * we get here, start with respective \"flags\" value\n>>> +\t\t * and update if vlan is present or not\n>>> +\t\t */\n>>> +\t\tcld_filter.element.flags =\n>>> +\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT);\n>>> +\n>>> +\t\tif (filter->vlan_id) {\n>>> +\t\t\tcld_filter.element.flags =\n>>> +\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT);\n>>> +\t\t}\n>>> +\n>>> +\t} else if (filter->dst_ip || filter->ip_version == IPV6_VERSION) {\n>>> +\t\tcld_filter.element.flags =\n>>> +\t\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_IP_PORT);\n>>> +\t\tif (filter->ip_version == IPV6_VERSION)\n>>> +\t\t\tcld_filter.element.flags |=\n>>> +\t\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV6);\n>>> +\t\telse\n>>> +\t\t\tcld_filter.element.flags |=\n>>> +\t\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV4);\n>>> +\t} else {\n>>> +\t\tdev_err(&pf->pdev->dev,\n>>> +\t\t\t\"either mac or ip has to be valid for cloud filter\\n\");\n>>> +\t\treturn -EINVAL;\n>>> +\t}\n>>> +\n>>> +\t/* Now copy L4 port in Byte 6..7 in general fields */\n>>> +\tcld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0] =\n>>> +\t\t\t\t\t\tbe16_to_cpu(filter->dst_port);\n>>> +\n>>> +\tif (add) {\n>>> +\t\tbool proto_type, port_type;\n>>> +\n>>> +\t\tproto_type = (filter->ip_proto == IPPROTO_TCP) ? true : false;\n>>> +\t\tport_type = (filter->port_type & I40E_CLOUD_FILTER_PORT_DEST) ?\n>>> +\t\t\t     true : false;\n>>> +\n>>> +\t\t/* For now, src port based cloud filter for channel is not\n>>> +\t\t * supported\n>>> +\t\t */\n>>> +\t\tif (!port_type) {\n>>> +\t\t\tdev_err(&pf->pdev->dev,\n>>> +\t\t\t\t\"unsupported port type (src port)\\n\");\n>>> +\t\t\treturn -EOPNOTSUPP;\n>>> +\t\t}\n>>> +\n>>> +\t\t/* Validate current device switch mode, change if necessary */\n>>> +\t\tret = i40e_validate_and_set_switch_mode(vsi, proto_type,\n>>> +\t\t\t\t\t\t\tport_type);\n>>> +\t\tif (ret) {\n>>> +\t\t\tdev_err(&pf->pdev->dev,\n>>> +\t\t\t\t\"failed to set switch mode, ret %d\\n\",\n>>> +\t\t\t\tret);\n>>> +\t\t\treturn ret;\n>>> +\t\t}\n>>> +\n>>> +\t\tret = i40e_aq_add_cloud_filters_bb(&pf->hw, filter->seid,\n>>> +\t\t\t\t\t\t   &cld_filter, 1);\n>>> +\t} else {\n>>> +\t\tret = i40e_aq_rem_cloud_filters_bb(&pf->hw, filter->seid,\n>>> +\t\t\t\t\t\t   &cld_filter, 1);\n>>> +\t}\n>>> +\n>>> +\tif (ret)\n>>> +\t\tdev_dbg(&pf->pdev->dev,\n>>> +\t\t\t\"Failed to %s cloud filter(big buffer) err %d aq_err %d\\n\",\n>>> +\t\t\tadd ? \"add\" : \"delete\", ret, pf->hw.aq.asq_last_status);\n>>> +\telse\n>>> +\t\tdev_info(&pf->pdev->dev,\n>>> +\t\t\t \"%s cloud filter for VSI: %d, L4 port: %d\\n\",\n>>> +\t\t\t add ? \"add\" : \"delete\", filter->seid,\n>>> +\t\t\t ntohs(filter->dst_port));\n>>> +\treturn ret;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_parse_cls_flower - Parse tc flower filters provided by kernel\n>>> + * @vsi: Pointer to VSI\n>>> + * @cls_flower: Pointer to struct tc_cls_flower_offload\n>>> + * @filter: Pointer to cloud filter structure\n>>> + *\n>>> + **/\n>>> +static int i40e_parse_cls_flower(struct i40e_vsi *vsi,\n>>> +\t\t\t\t struct tc_cls_flower_offload *f,\n>>> +\t\t\t\t struct i40e_cloud_filter *filter)\n>>> +{\n>>> +\tstruct i40e_pf *pf = vsi->back;\n>>> +\tu16 addr_type = 0;\n>>> +\tu8 field_flags = 0;\n>>> +\n>>> +\tif (f->dissector->used_keys &\n>>> +\t    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |\n>>> +\t      BIT(FLOW_DISSECTOR_KEY_BASIC) |\n>>> +\t      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |\n>>> +\t      BIT(FLOW_DISSECTOR_KEY_VLAN) |\n>>> +\t      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |\n>>> +\t      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |\n>>> +\t      BIT(FLOW_DISSECTOR_KEY_PORTS) |\n>>> +\t      BIT(FLOW_DISSECTOR_KEY_ENC_KEYID))) {\n>>> +\t\tdev_err(&pf->pdev->dev, \"Unsupported key used: 0x%x\\n\",\n>>> +\t\t\tf->dissector->used_keys);\n>>> +\t\treturn -EOPNOTSUPP;\n>>> +\t}\n>>> +\n>>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {\n>>> +\t\tstruct flow_dissector_key_keyid *key =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ENC_KEYID,\n>>> +\t\t\t\t\t\t  f->key);\n>>> +\n>>> +\t\tstruct flow_dissector_key_keyid *mask =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ENC_KEYID,\n>>> +\t\t\t\t\t\t  f->mask);\n>>> +\n>>> +\t\tif (mask->keyid != 0)\n>>> +\t\t\tfield_flags |= I40E_CLOUD_FIELD_TEN_ID;\n>>> +\n>>> +\t\tfilter->tenant_id = be32_to_cpu(key->keyid);\n>>> +\t}\n>>> +\n>>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {\n>>> +\t\tstruct flow_dissector_key_basic *key =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_BASIC,\n>>> +\t\t\t\t\t\t  f->key);\n>>> +\n>>> +\t\tfilter->ip_proto = key->ip_proto;\n>>> +\t}\n>>> +\n>>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {\n>>> +\t\tstruct flow_dissector_key_eth_addrs *key =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ETH_ADDRS,\n>>> +\t\t\t\t\t\t  f->key);\n>>> +\n>>> +\t\tstruct flow_dissector_key_eth_addrs *mask =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ETH_ADDRS,\n>>> +\t\t\t\t\t\t  f->mask);\n>>> +\n>>> +\t\t/* use is_broadcast and is_zero to check for all 0xf or 0 */\n>>> +\t\tif (!is_zero_ether_addr(mask->dst)) {\n>>> +\t\t\tif (is_broadcast_ether_addr(mask->dst)) {\n>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_OMAC;\n>>> +\t\t\t} else {\n>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ether dest mask %pM\\n\",\n>>> +\t\t\t\t\tmask->dst);\n>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>> +\t\t\t}\n>>> +\t\t}\n>>> +\n>>> +\t\tif (!is_zero_ether_addr(mask->src)) {\n>>> +\t\t\tif (is_broadcast_ether_addr(mask->src)) {\n>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IMAC;\n>>> +\t\t\t} else {\n>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ether src mask %pM\\n\",\n>>> +\t\t\t\t\tmask->src);\n>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>> +\t\t\t}\n>>> +\t\t}\n>>> +\t\tether_addr_copy(filter->dst_mac, key->dst);\n>>> +\t\tether_addr_copy(filter->src_mac, key->src);\n>>> +\t}\n>>> +\n>>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {\n>>> +\t\tstruct flow_dissector_key_vlan *key =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_VLAN,\n>>> +\t\t\t\t\t\t  f->key);\n>>> +\t\tstruct flow_dissector_key_vlan *mask =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_VLAN,\n>>> +\t\t\t\t\t\t  f->mask);\n>>> +\n>>> +\t\tif (mask->vlan_id) {\n>>> +\t\t\tif (mask->vlan_id == VLAN_VID_MASK) {\n>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IVLAN;\n>>> +\n>>> +\t\t\t} else {\n>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad vlan mask 0x%04x\\n\",\n>>> +\t\t\t\t\tmask->vlan_id);\n>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>> +\t\t\t}\n>>> +\t\t}\n>>> +\n>>> +\t\tfilter->vlan_id = cpu_to_be16(key->vlan_id);\n>>> +\t}\n>>> +\n>>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {\n>>> +\t\tstruct flow_dissector_key_control *key =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_CONTROL,\n>>> +\t\t\t\t\t\t  f->key);\n>>> +\n>>> +\t\taddr_type = key->addr_type;\n>>> +\t}\n>>> +\n>>> +\tif (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {\n>>> +\t\tstruct flow_dissector_key_ipv4_addrs *key =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV4_ADDRS,\n>>> +\t\t\t\t\t\t  f->key);\n>>> +\t\tstruct flow_dissector_key_ipv4_addrs *mask =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV4_ADDRS,\n>>> +\t\t\t\t\t\t  f->mask);\n>>> +\n>>> +\t\tif (mask->dst) {\n>>> +\t\t\tif (mask->dst == cpu_to_be32(0xffffffff)) {\n>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>>> +\t\t\t} else {\n>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ip dst mask 0x%08x\\n\",\n>>> +\t\t\t\t\tbe32_to_cpu(mask->dst));\n>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>> +\t\t\t}\n>>> +\t\t}\n>>> +\n>>> +\t\tif (mask->src) {\n>>> +\t\t\tif (mask->src == cpu_to_be32(0xffffffff)) {\n>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>>> +\t\t\t} else {\n>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ip src mask 0x%08x\\n\",\n>>> +\t\t\t\t\tbe32_to_cpu(mask->dst));\n>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>> +\t\t\t}\n>>> +\t\t}\n>>> +\n>>> +\t\tif (field_flags & I40E_CLOUD_FIELD_TEN_ID) {\n>>> +\t\t\tdev_err(&pf->pdev->dev, \"Tenant id not allowed for ip filter\\n\");\n>>> +\t\t\treturn I40E_ERR_CONFIG;\n>>> +\t\t}\n>>> +\t\tfilter->dst_ip = key->dst;\n>>> +\t\tfilter->src_ip = key->src;\n>>> +\t\tfilter->ip_version = IPV4_VERSION;\n>>> +\t}\n>>> +\n>>> +\tif (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {\n>>> +\t\tstruct flow_dissector_key_ipv6_addrs *key =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV6_ADDRS,\n>>> +\t\t\t\t\t\t  f->key);\n>>> +\t\tstruct flow_dissector_key_ipv6_addrs *mask =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV6_ADDRS,\n>>> +\t\t\t\t\t\t  f->mask);\n>>> +\n>>> +\t\t/* src and dest IPV6 address should not be LOOPBACK\n>>> +\t\t * (0:0:0:0:0:0:0:1), which can be represented as ::1\n>>> +\t\t */\n>>> +\t\tif (ipv6_addr_loopback(&key->dst) ||\n>>> +\t\t    ipv6_addr_loopback(&key->src)) {\n>>> +\t\t\tdev_err(&pf->pdev->dev,\n>>> +\t\t\t\t\"Bad ipv6, addr is LOOPBACK\\n\");\n>>> +\t\t\treturn I40E_ERR_CONFIG;\n>>> +\t\t}\n>>> +\t\tif (!ipv6_addr_any(&mask->dst) || !ipv6_addr_any(&mask->src))\n>>> +\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>>> +\n>>> +\t\tmemcpy(&filter->src_ipv6, &key->src.s6_addr32,\n>>> +\t\t       sizeof(filter->src_ipv6));\n>>> +\t\tmemcpy(&filter->dst_ipv6, &key->dst.s6_addr32,\n>>> +\t\t       sizeof(filter->dst_ipv6));\n>>> +\n>>> +\t\t/* mark it as IPv6 filter, to be used later */\n>>> +\t\tfilter->ip_version = IPV6_VERSION;\n>>> +\t}\n>>> +\n>>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {\n>>> +\t\tstruct flow_dissector_key_ports *key =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_PORTS,\n>>> +\t\t\t\t\t\t  f->key);\n>>> +\t\tstruct flow_dissector_key_ports *mask =\n>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_PORTS,\n>>> +\t\t\t\t\t\t  f->mask);\n>>> +\n>>> +\t\tif (mask->src) {\n>>> +\t\t\tif (mask->src == cpu_to_be16(0xffff)) {\n>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>>> +\t\t\t} else {\n>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad src port mask 0x%04x\\n\",\n>>> +\t\t\t\t\tbe16_to_cpu(mask->src));\n>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>> +\t\t\t}\n>>> +\t\t}\n>>> +\n>>> +\t\tif (mask->dst) {\n>>> +\t\t\tif (mask->dst == cpu_to_be16(0xffff)) {\n>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>>> +\t\t\t} else {\n>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad dst port mask 0x%04x\\n\",\n>>> +\t\t\t\t\tbe16_to_cpu(mask->dst));\n>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>> +\t\t\t}\n>>> +\t\t}\n>>> +\n>>> +\t\tfilter->dst_port = key->dst;\n>>> +\t\tfilter->src_port = key->src;\n>>> +\n>>> +\t\t/* For now, only supports destination port*/\n>>> +\t\tfilter->port_type |= I40E_CLOUD_FILTER_PORT_DEST;\n>>> +\n>>> +\t\tswitch (filter->ip_proto) {\n>>> +\t\tcase IPPROTO_TCP:\n>>> +\t\tcase IPPROTO_UDP:\n>>> +\t\t\tbreak;\n>>> +\t\tdefault:\n>>> +\t\t\tdev_err(&pf->pdev->dev,\n>>> +\t\t\t\t\"Only UDP and TCP transport are supported\\n\");\n>>> +\t\t\treturn -EINVAL;\n>>> +\t\t}\n>>> +\t}\n>>> +\tfilter->flags = field_flags;\n>>> +\treturn 0;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_handle_redirect_action: Forward to a traffic class on the device\n>>> + * @vsi: Pointer to VSI\n>>> + * @ifindex: ifindex of the device to forwared to\n>>> + * @tc: traffic class index on the device\n>>> + * @filter: Pointer to cloud filter structure\n>>> + *\n>>> + **/\n>>> +static int i40e_handle_redirect_action(struct i40e_vsi *vsi, int ifindex, u8 tc,\n>>> +\t\t\t\t       struct i40e_cloud_filter *filter)\n>>> +{\n>>> +\tstruct i40e_channel *ch, *ch_tmp;\n>>> +\n>>> +\t/* redirect to a traffic class on the same device */\n>>> +\tif (vsi->netdev->ifindex == ifindex) {\n>>> +\t\tif (tc == 0) {\n>>> +\t\t\tfilter->seid = vsi->seid;\n>>> +\t\t\treturn 0;\n>>> +\t\t} else if (vsi->tc_config.enabled_tc & BIT(tc)) {\n>>> +\t\t\tif (!filter->dst_port) {\n>>> +\t\t\t\tdev_err(&vsi->back->pdev->dev,\n>>> +\t\t\t\t\t\"Specify destination port to redirect to traffic class that is not default\\n\");\n>>> +\t\t\t\treturn -EINVAL;\n>>> +\t\t\t}\n>>> +\t\t\tif (list_empty(&vsi->ch_list))\n>>> +\t\t\t\treturn -EINVAL;\n>>> +\t\t\tlist_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list,\n>>> +\t\t\t\t\t\t list) {\n>>> +\t\t\t\tif (ch->seid == vsi->tc_seid_map[tc])\n>>> +\t\t\t\t\tfilter->seid = ch->seid;\n>>> +\t\t\t}\n>>> +\t\t\treturn 0;\n>>> +\t\t}\n>>> +\t}\n>>> +\treturn -EINVAL;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_parse_tc_actions - Parse tc actions\n>>> + * @vsi: Pointer to VSI\n>>> + * @cls_flower: Pointer to struct tc_cls_flower_offload\n>>> + * @filter: Pointer to cloud filter structure\n>>> + *\n>>> + **/\n>>> +static int i40e_parse_tc_actions(struct i40e_vsi *vsi, struct tcf_exts *exts,\n>>> +\t\t\t\t struct i40e_cloud_filter *filter)\n>>> +{\n>>> +\tconst struct tc_action *a;\n>>> +\tLIST_HEAD(actions);\n>>> +\tint err;\n>>> +\n>>> +\tif (!tcf_exts_has_actions(exts))\n>>> +\t\treturn -EINVAL;\n>>> +\n>>> +\ttcf_exts_to_list(exts, &actions);\n>>> +\tlist_for_each_entry(a, &actions, list) {\n>>> +\t\t/* Drop action */\n>>> +\t\tif (is_tcf_gact_shot(a)) {\n>>> +\t\t\tdev_err(&vsi->back->pdev->dev,\n>>> +\t\t\t\t\"Cloud filters do not support the drop action.\\n\");\n>>> +\t\t\treturn -EOPNOTSUPP;\n>>> +\t\t}\n>>> +\n>>> +\t\t/* Redirect to a traffic class on the same device */\n>>> +\t\tif (!is_tcf_mirred_egress_redirect(a) && is_tcf_mirred_tc(a)) {\n>>> +\t\t\tint ifindex = tcf_mirred_ifindex(a);\n>>> +\t\t\tu8 tc = tcf_mirred_tc(a);\n>>> +\n>>> +\t\t\terr = i40e_handle_redirect_action(vsi, ifindex, tc,\n>>> +\t\t\t\t\t\t\t  filter);\n>>> +\t\t\tif (err == 0)\n>>> +\t\t\t\treturn err;\n>>> +\t\t}\n>>> +\t}\n>>> +\treturn -EINVAL;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_configure_clsflower - Configure tc flower filters\n>>> + * @vsi: Pointer to VSI\n>>> + * @cls_flower: Pointer to struct tc_cls_flower_offload\n>>> + *\n>>> + **/\n>>> +static int i40e_configure_clsflower(struct i40e_vsi *vsi,\n>>> +\t\t\t\t    struct tc_cls_flower_offload *cls_flower)\n>>> +{\n>>> +\tstruct i40e_cloud_filter *filter = NULL;\n>>> +\tstruct i40e_pf *pf = vsi->back;\n>>> +\tint err = 0;\n>>> +\n>>> +\tif (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state) ||\n>>> +\t    test_bit(__I40E_RESET_INTR_RECEIVED, pf->state))\n>>> +\t\treturn -EBUSY;\n>>> +\n>>> +\tif (pf->fdir_pf_active_filters ||\n>>> +\t    (!hlist_empty(&pf->fdir_filter_list))) {\n>>> +\t\tdev_err(&vsi->back->pdev->dev,\n>>> +\t\t\t\"Flow Director Sideband filters exists, turn ntuple off to configure cloud filters\\n\");\n>>> +\t\treturn -EINVAL;\n>>> +\t}\n>>> +\n>>> +\tif (vsi->back->flags & I40E_FLAG_FD_SB_ENABLED) {\n>>> +\t\tdev_err(&vsi->back->pdev->dev,\n>>> +\t\t\t\"Disable Flow Director Sideband, configuring Cloud filters via tc-flower\\n\");\n>>> +\t\tvsi->back->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>>> +\t\tvsi->back->flags |= I40E_FLAG_FD_SB_TO_CLOUD_FILTER;\n>>> +\t}\n>>> +\n>>> +\tfilter = kzalloc(sizeof(*filter), GFP_KERNEL);\n>>> +\tif (!filter)\n>>> +\t\treturn -ENOMEM;\n>>> +\n>>> +\tfilter->cookie = cls_flower->cookie;\n>>> +\n>>> +\terr = i40e_parse_cls_flower(vsi, cls_flower, filter);\n>>> +\tif (err < 0)\n>>> +\t\tgoto err;\n>>> +\n>>> +\terr = i40e_parse_tc_actions(vsi, cls_flower->exts, filter);\n>>> +\tif (err < 0)\n>>> +\t\tgoto err;\n>>> +\n>>> +\t/* Add cloud filter */\n>>> +\tif (filter->dst_port)\n>>> +\t\terr = i40e_add_del_cloud_filter_big_buf(vsi, filter, true);\n>>> +\telse\n>>> +\t\terr = i40e_add_del_cloud_filter(vsi, filter, true);\n>>> +\n>>> +\tif (err) {\n>>> +\t\tdev_err(&pf->pdev->dev,\n>>> +\t\t\t\"Failed to add cloud filter, err %s\\n\",\n>>> +\t\t\ti40e_stat_str(&pf->hw, err));\n>>> +\t\terr = i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);\n>>> +\t\tgoto err;\n>>> +\t}\n>>> +\n>>> +\t/* add filter to the ordered list */\n>>> +\tINIT_HLIST_NODE(&filter->cloud_node);\n>>> +\n>>> +\thlist_add_head(&filter->cloud_node, &pf->cloud_filter_list);\n>>> +\n>>> +\tpf->num_cloud_filters++;\n>>> +\n>>> +\treturn err;\n>>> +err:\n>>> +\tkfree(filter);\n>>> +\treturn err;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_find_cloud_filter - Find the could filter in the list\n>>> + * @vsi: Pointer to VSI\n>>> + * @cookie: filter specific cookie\n>>> + *\n>>> + **/\n>>> +static struct i40e_cloud_filter *i40e_find_cloud_filter(struct i40e_vsi *vsi,\n>>> +\t\t\t\t\t\t\tunsigned long *cookie)\n>>> +{\n>>> +\tstruct i40e_cloud_filter *filter = NULL;\n>>> +\tstruct hlist_node *node2;\n>>> +\n>>> +\thlist_for_each_entry_safe(filter, node2,\n>>> +\t\t\t\t  &vsi->back->cloud_filter_list, cloud_node)\n>>> +\t\tif (!memcmp(cookie, &filter->cookie, sizeof(filter->cookie)))\n>>> +\t\t\treturn filter;\n>>> +\treturn NULL;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_delete_clsflower - Remove tc flower filters\n>>> + * @vsi: Pointer to VSI\n>>> + * @cls_flower: Pointer to struct tc_cls_flower_offload\n>>> + *\n>>> + **/\n>>> +static int i40e_delete_clsflower(struct i40e_vsi *vsi,\n>>> +\t\t\t\t struct tc_cls_flower_offload *cls_flower)\n>>> +{\n>>> +\tstruct i40e_cloud_filter *filter = NULL;\n>>> +\tstruct i40e_pf *pf = vsi->back;\n>>> +\tint err = 0;\n>>> +\n>>> +\tfilter = i40e_find_cloud_filter(vsi, &cls_flower->cookie);\n>>> +\n>>> +\tif (!filter)\n>>> +\t\treturn -EINVAL;\n>>> +\n>>> +\thash_del(&filter->cloud_node);\n>>> +\n>>> +\tif (filter->dst_port)\n>>> +\t\terr = i40e_add_del_cloud_filter_big_buf(vsi, filter, false);\n>>> +\telse\n>>> +\t\terr = i40e_add_del_cloud_filter(vsi, filter, false);\n>>> +\tif (err) {\n>>> +\t\tkfree(filter);\n>>> +\t\tdev_err(&pf->pdev->dev,\n>>> +\t\t\t\"Failed to delete cloud filter, err %s\\n\",\n>>> +\t\t\ti40e_stat_str(&pf->hw, err));\n>>> +\t\treturn i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);\n>>> +\t}\n>>> +\n>>> +\tkfree(filter);\n>>> +\tpf->num_cloud_filters--;\n>>> +\n>>> +\tif (!pf->num_cloud_filters)\n>>> +\t\tif ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&\n>>> +\t\t    !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {\n>>> +\t\t\tpf->flags |= I40E_FLAG_FD_SB_ENABLED;\n>>> +\t\t\tpf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;\n>>> +\t\t\tpf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;\n>>> +\t\t}\n>>> +\treturn 0;\n>>> +}\n>>> +\n>>> +/**\n>>> + * i40e_setup_tc_cls_flower - flower classifier offloads\n>>> + * @netdev: net device to configure\n>>> + * @type_data: offload data\n>>> + **/\n>>> +static int i40e_setup_tc_cls_flower(struct net_device *netdev,\n>>> +\t\t\t\t    struct tc_cls_flower_offload *cls_flower)\n>>> +{\n>>> +\tstruct i40e_netdev_priv *np = netdev_priv(netdev);\n>>> +\tstruct i40e_vsi *vsi = np->vsi;\n>>> +\n>>> +\tif (!is_classid_clsact_ingress(cls_flower->common.classid) ||\n>>> +\t    cls_flower->common.chain_index)\n>>> +\t\treturn -EOPNOTSUPP;\n>>> +\n>>> +\tswitch (cls_flower->command) {\n>>> +\tcase TC_CLSFLOWER_REPLACE:\n>>> +\t\treturn i40e_configure_clsflower(vsi, cls_flower);\n>>> +\tcase TC_CLSFLOWER_DESTROY:\n>>> +\t\treturn i40e_delete_clsflower(vsi, cls_flower);\n>>> +\tcase TC_CLSFLOWER_STATS:\n>>> +\t\treturn -EOPNOTSUPP;\n>>> +\tdefault:\n>>> +\t\treturn -EINVAL;\n>>> +\t}\n>>> +}\n>>> +\n>>> static int __i40e_setup_tc(struct net_device *netdev, enum tc_setup_type type,\n>>> \t\t\t   void *type_data)\n>>> {\n>>> -\tif (type != TC_SETUP_MQPRIO)\n>>> +\tswitch (type) {\n>>> +\tcase TC_SETUP_MQPRIO:\n>>> +\t\treturn i40e_setup_tc(netdev, type_data);\n>>> +\tcase TC_SETUP_CLSFLOWER:\n>>> +\t\treturn i40e_setup_tc_cls_flower(netdev, type_data);\n>>> +\tdefault:\n>>> \t\treturn -EOPNOTSUPP;\n>>> -\n>>> -\treturn i40e_setup_tc(netdev, type_data);\n>>> +\t}\n>>> }\n>>>\n>>> /**\n>>> @@ -6939,6 +7756,13 @@ static void i40e_cloud_filter_exit(struct i40e_pf *pf)\n>>> \t\tkfree(cfilter);\n>>> \t}\n>>> \tpf->num_cloud_filters = 0;\n>>> +\n>>> +\tif ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&\n>>> +\t    !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {\n>>> +\t\tpf->flags |= I40E_FLAG_FD_SB_ENABLED;\n>>> +\t\tpf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;\n>>> +\t\tpf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;\n>>> +\t}\n>>> }\n>>>\n>>> /**\n>>> @@ -8046,7 +8870,8 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb)\n>>>  * i40e_get_capabilities - get info about the HW\n>>>  * @pf: the PF struct\n>>>  **/\n>>> -static int i40e_get_capabilities(struct i40e_pf *pf)\n>>> +static int i40e_get_capabilities(struct i40e_pf *pf,\n>>> +\t\t\t\t enum i40e_admin_queue_opc list_type)\n>>> {\n>>> \tstruct i40e_aqc_list_capabilities_element_resp *cap_buf;\n>>> \tu16 data_size;\n>>> @@ -8061,9 +8886,8 @@ static int i40e_get_capabilities(struct i40e_pf *pf)\n>>>\n>>> \t\t/* this loads the data into the hw struct for us */\n>>> \t\terr = i40e_aq_discover_capabilities(&pf->hw, cap_buf, buf_len,\n>>> -\t\t\t\t\t    &data_size,\n>>> -\t\t\t\t\t    i40e_aqc_opc_list_func_capabilities,\n>>> -\t\t\t\t\t    NULL);\n>>> +\t\t\t\t\t\t    &data_size, list_type,\n>>> +\t\t\t\t\t\t    NULL);\n>>> \t\t/* data loaded, buffer no longer needed */\n>>> \t\tkfree(cap_buf);\n>>>\n>>> @@ -8080,26 +8904,44 @@ static int i40e_get_capabilities(struct i40e_pf *pf)\n>>> \t\t}\n>>> \t} while (err);\n>>>\n>>> -\tif (pf->hw.debug_mask & I40E_DEBUG_USER)\n>>> -\t\tdev_info(&pf->pdev->dev,\n>>> -\t\t\t \"pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\\n\",\n>>> -\t\t\t pf->hw.pf_id, pf->hw.func_caps.num_vfs,\n>>> -\t\t\t pf->hw.func_caps.num_msix_vectors,\n>>> -\t\t\t pf->hw.func_caps.num_msix_vectors_vf,\n>>> -\t\t\t pf->hw.func_caps.fd_filters_guaranteed,\n>>> -\t\t\t pf->hw.func_caps.fd_filters_best_effort,\n>>> -\t\t\t pf->hw.func_caps.num_tx_qp,\n>>> -\t\t\t pf->hw.func_caps.num_vsis);\n>>> -\n>>> +\tif (pf->hw.debug_mask & I40E_DEBUG_USER) {\n>>> +\t\tif (list_type == i40e_aqc_opc_list_func_capabilities) {\n>>> +\t\t\tdev_info(&pf->pdev->dev,\n>>> +\t\t\t\t \"pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\\n\",\n>>> +\t\t\t\t pf->hw.pf_id, pf->hw.func_caps.num_vfs,\n>>> +\t\t\t\t pf->hw.func_caps.num_msix_vectors,\n>>> +\t\t\t\t pf->hw.func_caps.num_msix_vectors_vf,\n>>> +\t\t\t\t pf->hw.func_caps.fd_filters_guaranteed,\n>>> +\t\t\t\t pf->hw.func_caps.fd_filters_best_effort,\n>>> +\t\t\t\t pf->hw.func_caps.num_tx_qp,\n>>> +\t\t\t\t pf->hw.func_caps.num_vsis);\n>>> +\t\t} else if (list_type == i40e_aqc_opc_list_dev_capabilities) {\n>>> +\t\t\tdev_info(&pf->pdev->dev,\n>>> +\t\t\t\t \"switch_mode=0x%04x, function_valid=0x%08x\\n\",\n>>> +\t\t\t\t pf->hw.dev_caps.switch_mode,\n>>> +\t\t\t\t pf->hw.dev_caps.valid_functions);\n>>> +\t\t\tdev_info(&pf->pdev->dev,\n>>> +\t\t\t\t \"SR-IOV=%d, num_vfs for all function=%u\\n\",\n>>> +\t\t\t\t pf->hw.dev_caps.sr_iov_1_1,\n>>> +\t\t\t\t pf->hw.dev_caps.num_vfs);\n>>> +\t\t\tdev_info(&pf->pdev->dev,\n>>> +\t\t\t\t \"num_vsis=%u, num_rx:%u, num_tx=%u\\n\",\n>>> +\t\t\t\t pf->hw.dev_caps.num_vsis,\n>>> +\t\t\t\t pf->hw.dev_caps.num_rx_qp,\n>>> +\t\t\t\t pf->hw.dev_caps.num_tx_qp);\n>>> +\t\t}\n>>> +\t}\n>>> +\tif (list_type == i40e_aqc_opc_list_func_capabilities) {\n>>> #define DEF_NUM_VSI (1 + (pf->hw.func_caps.fcoe ? 1 : 0) \\\n>>> \t\t       + pf->hw.func_caps.num_vfs)\n>>> -\tif (pf->hw.revision_id == 0 && (DEF_NUM_VSI > pf->hw.func_caps.num_vsis)) {\n>>> -\t\tdev_info(&pf->pdev->dev,\n>>> -\t\t\t \"got num_vsis %d, setting num_vsis to %d\\n\",\n>>> -\t\t\t pf->hw.func_caps.num_vsis, DEF_NUM_VSI);\n>>> -\t\tpf->hw.func_caps.num_vsis = DEF_NUM_VSI;\n>>> +\t\tif (pf->hw.revision_id == 0 &&\n>>> +\t\t    (pf->hw.func_caps.num_vsis < DEF_NUM_VSI)) {\n>>> +\t\t\tdev_info(&pf->pdev->dev,\n>>> +\t\t\t\t \"got num_vsis %d, setting num_vsis to %d\\n\",\n>>> +\t\t\t\t pf->hw.func_caps.num_vsis, DEF_NUM_VSI);\n>>> +\t\t\tpf->hw.func_caps.num_vsis = DEF_NUM_VSI;\n>>> +\t\t}\n>>> \t}\n>>> -\n>>> \treturn 0;\n>>> }\n>>>\n>>> @@ -8141,6 +8983,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)\n>>> \t\tif (!vsi) {\n>>> \t\t\tdev_info(&pf->pdev->dev, \"Couldn't create FDir VSI\\n\");\n>>> \t\t\tpf->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>>> +\t\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>> \t\t\treturn;\n>>> \t\t}\n>>> \t}\n>>> @@ -8163,6 +9006,48 @@ static void i40e_fdir_teardown(struct i40e_pf *pf)\n>>> }\n>>>\n>>> /**\n>>> + * i40e_rebuild_cloud_filters - Rebuilds cloud filters for VSIs\n>>> + * @vsi: PF main vsi\n>>> + * @seid: seid of main or channel VSIs\n>>> + *\n>>> + * Rebuilds cloud filters associated with main VSI and channel VSIs if they\n>>> + * existed before reset\n>>> + **/\n>>> +static int i40e_rebuild_cloud_filters(struct i40e_vsi *vsi, u16 seid)\n>>> +{\n>>> +\tstruct i40e_cloud_filter *cfilter;\n>>> +\tstruct i40e_pf *pf = vsi->back;\n>>> +\tstruct hlist_node *node;\n>>> +\ti40e_status ret;\n>>> +\n>>> +\t/* Add cloud filters back if they exist */\n>>> +\tif (hlist_empty(&pf->cloud_filter_list))\n>>> +\t\treturn 0;\n>>> +\n>>> +\thlist_for_each_entry_safe(cfilter, node, &pf->cloud_filter_list,\n>>> +\t\t\t\t  cloud_node) {\n>>> +\t\tif (cfilter->seid != seid)\n>>> +\t\t\tcontinue;\n>>> +\n>>> +\t\tif (cfilter->dst_port)\n>>> +\t\t\tret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter,\n>>> +\t\t\t\t\t\t\t\ttrue);\n>>> +\t\telse\n>>> +\t\t\tret = i40e_add_del_cloud_filter(vsi, cfilter, true);\n>>> +\n>>> +\t\tif (ret) {\n>>> +\t\t\tdev_dbg(&pf->pdev->dev,\n>>> +\t\t\t\t\"Failed to rebuild cloud filter, err %s aq_err %s\\n\",\n>>> +\t\t\t\ti40e_stat_str(&pf->hw, ret),\n>>> +\t\t\t\ti40e_aq_str(&pf->hw,\n>>> +\t\t\t\t\t    pf->hw.aq.asq_last_status));\n>>> +\t\t\treturn ret;\n>>> +\t\t}\n>>> +\t}\n>>> +\treturn 0;\n>>> +}\n>>> +\n>>> +/**\n>>>  * i40e_rebuild_channels - Rebuilds channel VSIs if they existed before reset\n>>>  * @vsi: PF main vsi\n>>>  *\n>>> @@ -8199,6 +9084,13 @@ static int i40e_rebuild_channels(struct i40e_vsi *vsi)\n>>> \t\t\t\t\t\tI40E_BW_CREDIT_DIVISOR,\n>>> \t\t\t\tch->seid);\n>>> \t\t}\n>>> +\t\tret = i40e_rebuild_cloud_filters(vsi, ch->seid);\n>>> +\t\tif (ret) {\n>>> +\t\t\tdev_dbg(&vsi->back->pdev->dev,\n>>> +\t\t\t\t\"Failed to rebuild cloud filters for channel VSI %u\\n\",\n>>> +\t\t\t\tch->seid);\n>>> +\t\t\treturn ret;\n>>> +\t\t}\n>>> \t}\n>>> \treturn 0;\n>>> }\n>>> @@ -8365,7 +9257,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)\n>>> \t\ti40e_verify_eeprom(pf);\n>>>\n>>> \ti40e_clear_pxe_mode(hw);\n>>> -\tret = i40e_get_capabilities(pf);\n>>> +\tret = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);\n>>> \tif (ret)\n>>> \t\tgoto end_core_reset;\n>>>\n>>> @@ -8482,6 +9374,10 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)\n>>> \t\t\tgoto end_unlock;\n>>> \t}\n>>>\n>>> +\tret = i40e_rebuild_cloud_filters(vsi, vsi->seid);\n>>> +\tif (ret)\n>>> +\t\tgoto end_unlock;\n>>> +\n>>> \t/* PF Main VSI is rebuild by now, go ahead and rebuild channel VSIs\n>>> \t * for this main VSI if they exist\n>>> \t */\n>>> @@ -9404,6 +10300,7 @@ static int i40e_init_msix(struct i40e_pf *pf)\n>>> \t    (pf->num_fdsb_msix == 0)) {\n>>> \t\tdev_info(&pf->pdev->dev, \"Sideband Flowdir disabled, not enough MSI-X vectors\\n\");\n>>> \t\tpf->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>>> +\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>> \t}\n>>> \tif ((pf->flags & I40E_FLAG_VMDQ_ENABLED) &&\n>>> \t    (pf->num_vmdq_msix == 0)) {\n>>> @@ -9521,6 +10418,7 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)\n>>> \t\t\t\t       I40E_FLAG_FD_SB_ENABLED\t|\n>>> \t\t\t\t       I40E_FLAG_FD_ATR_ENABLED\t|\n>>> \t\t\t\t       I40E_FLAG_VMDQ_ENABLED);\n>>> +\t\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>>\n>>> \t\t\t/* rework the queue expectations without MSIX */\n>>> \t\t\ti40e_determine_queue_usage(pf);\n>>> @@ -10263,9 +11161,13 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)\n>>> \t\t/* Enable filters and mark for reset */\n>>> \t\tif (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))\n>>> \t\t\tneed_reset = true;\n>>> -\t\t/* enable FD_SB only if there is MSI-X vector */\n>>> -\t\tif (pf->num_fdsb_msix > 0)\n>>> +\t\t/* enable FD_SB only if there is MSI-X vector and no cloud\n>>> +\t\t * filters exist\n>>> +\t\t */\n>>> +\t\tif (pf->num_fdsb_msix > 0 && !pf->num_cloud_filters) {\n>>> \t\t\tpf->flags |= I40E_FLAG_FD_SB_ENABLED;\n>>> +\t\t\tpf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;\n>>> +\t\t}\n>>> \t} else {\n>>> \t\t/* turn off filters, mark for reset and clear SW filter list */\n>>> \t\tif (pf->flags & I40E_FLAG_FD_SB_ENABLED) {\n>>> @@ -10274,6 +11176,8 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)\n>>> \t\t}\n>>> \t\tpf->flags &= ~(I40E_FLAG_FD_SB_ENABLED |\n>>> \t\t\t       I40E_FLAG_FD_SB_AUTO_DISABLED);\n>>> +\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>> +\n>>> \t\t/* reset fd counters */\n>>> \t\tpf->fd_add_err = 0;\n>>> \t\tpf->fd_atr_cnt = 0;\n>>> @@ -10857,7 +11761,8 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)\n>>> \t\tnetdev->hw_features |= NETIF_F_NTUPLE;\n>>> \thw_features = hw_enc_features\t\t|\n>>> \t\t      NETIF_F_HW_VLAN_CTAG_TX\t|\n>>> -\t\t      NETIF_F_HW_VLAN_CTAG_RX;\n>>> +\t\t      NETIF_F_HW_VLAN_CTAG_RX\t|\n>>> +\t\t      NETIF_F_HW_TC;\n>>>\n>>> \tnetdev->hw_features |= hw_features;\n>>>\n>>> @@ -12159,8 +13064,10 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)\n>>> \t*/\n>>>\n>>> \tif ((pf->hw.pf_id == 0) &&\n>>> -\t    !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT))\n>>> +\t    !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT)) {\n>>> \t\tflags = I40E_AQ_SET_SWITCH_CFG_PROMISC;\n>>> +\t\tpf->last_sw_conf_flags = flags;\n>>> +\t}\n>>>\n>>> \tif (pf->hw.pf_id == 0) {\n>>> \t\tu16 valid_flags;\n>>> @@ -12176,6 +13083,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)\n>>> \t\t\t\t\t     pf->hw.aq.asq_last_status));\n>>> \t\t\t/* not a fatal problem, just keep going */\n>>> \t\t}\n>>> +\t\tpf->last_sw_conf_valid_flags = valid_flags;\n>>> \t}\n>>>\n>>> \t/* first time setup */\n>>> @@ -12273,6 +13181,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)\n>>> \t\t\t       I40E_FLAG_DCB_ENABLED\t|\n>>> \t\t\t       I40E_FLAG_SRIOV_ENABLED\t|\n>>> \t\t\t       I40E_FLAG_VMDQ_ENABLED);\n>>> +\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>> \t} else if (!(pf->flags & (I40E_FLAG_RSS_ENABLED |\n>>> \t\t\t\t  I40E_FLAG_FD_SB_ENABLED |\n>>> \t\t\t\t  I40E_FLAG_FD_ATR_ENABLED |\n>>> @@ -12287,6 +13196,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)\n>>> \t\t\t       I40E_FLAG_FD_ATR_ENABLED\t|\n>>> \t\t\t       I40E_FLAG_DCB_ENABLED\t|\n>>> \t\t\t       I40E_FLAG_VMDQ_ENABLED);\n>>> +\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>> \t} else {\n>>> \t\t/* Not enough queues for all TCs */\n>>> \t\tif ((pf->flags & I40E_FLAG_DCB_CAPABLE) &&\n>>> @@ -12310,6 +13220,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)\n>>> \t\t\tqueues_left -= 1; /* save 1 queue for FD */\n>>> \t\t} else {\n>>> \t\t\tpf->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>>> +\t\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>> \t\t\tdev_info(&pf->pdev->dev, \"not enough queues for Flow Director. Flow Director feature is disabled\\n\");\n>>> \t\t}\n>>> \t}\n>>> @@ -12613,7 +13524,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n>>> \t\tdev_warn(&pdev->dev, \"This device is a pre-production adapter/LOM. Please be aware there may be issues with your hardware. If you are experiencing problems please contact your Intel or hardware representative who provided you with this hardware.\\n\");\n>>>\n>>> \ti40e_clear_pxe_mode(hw);\n>>> -\terr = i40e_get_capabilities(pf);\n>>> +\terr = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);\n>>> \tif (err)\n>>> \t\tgoto err_adminq_setup;\n>>>\n>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n>>> index 92869f5..3bb6659 100644\n>>> --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n>>> @@ -283,6 +283,22 @@ i40e_status i40e_aq_query_switch_comp_bw_config(struct i40e_hw *hw,\n>>> \t\tstruct i40e_asq_cmd_details *cmd_details);\n>>> i40e_status i40e_aq_resume_port_tx(struct i40e_hw *hw,\n>>> \t\t\t\t   struct i40e_asq_cmd_details *cmd_details);\n>>> +i40e_status\n>>> +i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>>> +\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>>> +\t\t\t     u8 filter_count);\n>>> +enum i40e_status_code\n>>> +i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 vsi,\n>>> +\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>>> +\t\t\t  u8 filter_count);\n>>> +enum i40e_status_code\n>>> +i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 vsi,\n>>> +\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>>> +\t\t\t  u8 filter_count);\n>>> +i40e_status\n>>> +i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>>> +\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>>> +\t\t\t     u8 filter_count);\n>>> i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,\n>>> \t\t\t       struct i40e_lldp_variables *lldp_cfg);\n>>> /* i40e_common */\n>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h\n>>> index c019f46..af38881 100644\n>>> --- a/drivers/net/ethernet/intel/i40e/i40e_type.h\n>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h\n>>> @@ -287,6 +287,7 @@ struct i40e_hw_capabilities {\n>>> #define I40E_NVM_IMAGE_TYPE_MODE1\t0x6\n>>> #define I40E_NVM_IMAGE_TYPE_MODE2\t0x7\n>>> #define I40E_NVM_IMAGE_TYPE_MODE3\t0x8\n>>> +#define I40E_SWITCH_MODE_MASK\t\t0xF\n>>>\n>>> \tu32  management_mode;\n>>> \tu32  mng_protocols_over_mctp;\n>>> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h\n>>> index b8c78bf..4fe27f0 100644\n>>> --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h\n>>> +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h\n>>> @@ -1360,6 +1360,9 @@ struct i40e_aqc_cloud_filters_element_data {\n>>> \t\tstruct {\n>>> \t\t\tu8 data[16];\n>>> \t\t} v6;\n>>> +\t\tstruct {\n>>> +\t\t\t__le16 data[8];\n>>> +\t\t} raw_v6;\n>>> \t} ipaddr;\n>>> \t__le16\tflags;\n>>> #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT\t\t\t0\n>>>","headers":{"Return-Path":"<intel-wired-lan-bounces@osuosl.org>","X-Original-To":["incoming@patchwork.ozlabs.org","intel-wired-lan@lists.osuosl.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","intel-wired-lan@lists.osuosl.org"],"Authentication-Results":"ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=osuosl.org\n\t(client-ip=140.211.166.137; helo=fraxinus.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)","Received":["from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y34MT4j51z9t6B\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 29 Sep 2017 05:22:28 +1000 (AEST)","from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id CC714888FF;\n\tThu, 28 Sep 2017 19:22:25 +0000 (UTC)","from fraxinus.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id d1nhOCSjL87q; Thu, 28 Sep 2017 19:22:22 +0000 (UTC)","from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 107A7888EB;\n\tThu, 28 Sep 2017 19:22:22 +0000 (UTC)","from hemlock.osuosl.org (smtp2.osuosl.org [140.211.166.133])\n\tby ash.osuosl.org (Postfix) with ESMTP id 514421C0306\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 28 Sep 2017 19:22:20 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n\tby hemlock.osuosl.org (Postfix) with ESMTP id 459BB89DE2\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 28 Sep 2017 19:22:20 +0000 (UTC)","from hemlock.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id FqN+IPxcQD7Z for <intel-wired-lan@lists.osuosl.org>;\n\tThu, 28 Sep 2017 19:22:17 +0000 (UTC)","from mga06.intel.com (mga06.intel.com [134.134.136.31])\n\tby hemlock.osuosl.org (Postfix) with ESMTPS id 3FDB089DE1\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 28 Sep 2017 19:22:17 +0000 (UTC)","from orsmga001.jf.intel.com ([10.7.209.18])\n\tby orsmga104.jf.intel.com with ESMTP; 28 Sep 2017 12:22:16 -0700","from anambiar-mobl.amr.corp.intel.com (HELO [10.252.135.37])\n\t([10.252.135.37])\n\tby orsmga001.jf.intel.com with ESMTP; 28 Sep 2017 12:22:15 -0700"],"X-Virus-Scanned":["amavisd-new at osuosl.org","amavisd-new at osuosl.org"],"X-Greylist":"domain auto-whitelisted by SQLgrey-1.7.6","X-ExtLoop1":"1","X-IronPort-AV":"E=Sophos; i=\"5.42,450,1500966000\"; d=\"scan'208\";\n\ta=\"1176779751\"","From":"\"Nambiar, Amritha\" <amritha.nambiar@intel.com>","To":"Jiri Pirko <jiri@resnulli.us>","References":"<150529632024.57063.15338545678487601430.stgit@anamdev.jf.intel.com>\n\t<150529679050.57063.3956015681929450874.stgit@anamdev.jf.intel.com>\n\t<20170913132611.GC1981@nanopsycho>\n\t<82e0a065-c7d6-8fe6-aedc-154dd0dd88d6@intel.com>","Message-ID":"<dd18a4bd-f2fc-002b-2ef9-01de9a5a4162@intel.com>","Date":"Thu, 28 Sep 2017 12:22:15 -0700","User-Agent":"Mozilla/5.0 (Windows NT 6.3; WOW64; rv:52.0) Gecko/20100101\n\tThunderbird/52.3.0","MIME-Version":"1.0","In-Reply-To":"<82e0a065-c7d6-8fe6-aedc-154dd0dd88d6@intel.com>","Content-Language":"en-US","Cc":"mlxsw@mellanox.com, netdev@vger.kernel.org,\n\tJamal Hadi Salim <jhs@mojatatu.com>, intel-wired-lan@lists.osuosl.org,\n\tCong Wang <xiyou.wangcong@gmail.com>","Subject":"Re: [Intel-wired-lan] [RFC PATCH v3 7/7] i40e: Enable cloud filters\n\tvia tc-flower","X-BeenThere":"intel-wired-lan@osuosl.org","X-Mailman-Version":"2.1.18-1","Precedence":"list","List-Id":"Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.osuosl.org>","List-Unsubscribe":"<https://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>","List-Archive":"<http://lists.osuosl.org/pipermail/intel-wired-lan/>","List-Post":"<mailto:intel-wired-lan@osuosl.org>","List-Help":"<mailto:intel-wired-lan-request@osuosl.org?subject=help>","List-Subscribe":"<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"intel-wired-lan-bounces@osuosl.org","Sender":"\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>"}},{"id":1777646,"web_url":"http://patchwork.ozlabs.org/comment/1777646/","msgid":"<20170929062035.GB1867@nanopsycho>","list_archive_url":null,"date":"2017-09-29T06:20:35","subject":"Re: [Intel-wired-lan] [RFC PATCH v3 7/7] i40e: Enable cloud filters\n\tvia tc-flower","submitter":{"id":15321,"url":"http://patchwork.ozlabs.org/api/people/15321/","name":"Jiri Pirko","email":"jiri@resnulli.us"},"content":"Thu, Sep 28, 2017 at 09:22:15PM CEST, amritha.nambiar@intel.com wrote:\n>On 9/14/2017 1:00 AM, Nambiar, Amritha wrote:\n>> On 9/13/2017 6:26 AM, Jiri Pirko wrote:\n>>> Wed, Sep 13, 2017 at 11:59:50AM CEST, amritha.nambiar@intel.com wrote:\n>>>> This patch enables tc-flower based hardware offloads. tc flower\n>>>> filter provided by the kernel is configured as driver specific\n>>>> cloud filter. The patch implements functions and admin queue\n>>>> commands needed to support cloud filters in the driver and\n>>>> adds cloud filters to configure these tc-flower filters.\n>>>>\n>>>> The only action supported is to redirect packets to a traffic class\n>>>> on the same device.\n>>>\n>>> So basically you are not doing redirect, you are just setting tclass for\n>>> matched packets, right? Why you use mirred for this? I think that\n>>> you might consider extending g_act for that:\n>>>\n>>> # tc filter add dev eth0 protocol ip ingress \\\n>>>   prio 1 flower dst_mac 3c:fd:fe:a0:d6:70 skip_sw \\\n>>>   action tclass 0\n>>>\n>> Yes, this doesn't work like a typical egress redirect, but is aimed at\n>> forwarding the matched packets to a different queue-group/traffic class\n>> on the same device, so some sort-of ingress redirect in the hardware. I\n>> possibly may not need the mirred-redirect as you say, I'll look into the\n>> g_act way of doing this with a new gact tc action.\n>> \n>\n>I was looking at introducing a new gact tclass action to TC. In the HW\n>offload path, this sets a traffic class value for certain matched\n>packets so they will be processed in a queue belonging to the traffic class.\n>\n># tc filter add dev eth0 protocol ip parent ffff:\\\n>  prio 2 flower dst_ip 192.168.3.5/32\\\n>  ip_proto udp dst_port 25 skip_sw\\\n>  action tclass 2\n>\n>But, I'm having trouble defining what this action means in the kernel\n>datapath. For ingress, this action could just take the default path and\n>do nothing and only have meaning in the HW offloaded path. For egress,\n\nSounds ok.\n\n\n>certain qdiscs like 'multiq' and 'prio' could use this 'tclass' value\n>for band selection, while the 'mqprio' qdisc selects the traffic class\n>based on the skb priority in netdev_pick_tx(), so what would this action\n>mean for the 'mqprio' qdisc?\n\nI don't see why this action would have any special meaning for specific\nqdiscs. The qdiscs have already mechanisms for band mapping. I don't see\nwhy to mix it up with tclass action.\n\nAlso, you can use tclass action on qdisc clsact egress to do band\nmapping. That would be symmetrical with ingress.\n\n\n>\n>It looks like the 'prio' qdisc uses band selection based on the\n>'classid', so I was thinking of using the 'classid' through the cls\n>flower filter and offload it to HW for the traffic class index, this way\n>we would have the same behavior in HW offload and SW fallback and there\n>would be no need for a separate tc action.\n>\n>In HW:\n># tc filter add dev eth0 protocol ip parent ffff:\\\n>  prio 2 flower dst_ip 192.168.3.5/32\\\n>  ip_proto udp dst_port 25 skip_sw classid 1:2\\\n>\n>filter pref 2 flower chain 0\n>filter pref 2 flower chain 0 handle 0x1 classid 1:2\n>  eth_type ipv4\n>  ip_proto udp\n>  dst_ip 192.168.3.5\n>  dst_port 25\n>  skip_sw\n>  in_hw\n>\n>This will be used to route packets to traffic class 2.\n>\n>In SW:\n># tc filter add dev eth0 protocol ip parent ffff:\\\n>  prio 2 flower dst_ip 192.168.3.5/32\\\n>  ip_proto udp dst_port 25 skip_hw classid 1:2\n>\n>filter pref 2 flower chain 0\n>filter pref 2 flower chain 0 handle 0x1 classid 1:2\n>  eth_type ipv4\n>  ip_proto udp\n>  dst_ip 192.168.3.5\n>  dst_port 25\n>  skip_hw\n>  not_in_hw\n>\n>>>\n>>>>\n>>>> # tc qdisc add dev eth0 ingress\n>>>> # ethtool -K eth0 hw-tc-offload on\n>>>>\n>>>> # tc filter add dev eth0 protocol ip parent ffff:\\\n>>>>  prio 1 flower dst_mac 3c:fd:fe:a0:d6:70 skip_sw\\\n>>>>  action mirred ingress redirect dev eth0 tclass 0\n>>>>\n>>>> # tc filter add dev eth0 protocol ip parent ffff:\\\n>>>>  prio 2 flower dst_ip 192.168.3.5/32\\\n>>>>  ip_proto udp dst_port 25 skip_sw\\\n>>>>  action mirred ingress redirect dev eth0 tclass 1\n>>>>\n>>>> # tc filter add dev eth0 protocol ipv6 parent ffff:\\\n>>>>  prio 3 flower dst_ip fe8::200:1\\\n>>>>  ip_proto udp dst_port 66 skip_sw\\\n>>>>  action mirred ingress redirect dev eth0 tclass 1\n>>>>\n>>>> Delete tc flower filter:\n>>>> Example:\n>>>>\n>>>> # tc filter del dev eth0 parent ffff: prio 3 handle 0x1 flower\n>>>> # tc filter del dev eth0 parent ffff:\n>>>>\n>>>> Flow Director Sideband is disabled while configuring cloud filters\n>>>> via tc-flower and until any cloud filter exists.\n>>>>\n>>>> Unsupported matches when cloud filters are added using enhanced\n>>>> big buffer cloud filter mode of underlying switch include:\n>>>> 1. source port and source IP\n>>>> 2. Combined MAC address and IP fields.\n>>>> 3. Not specifying L4 port\n>>>>\n>>>> These filter matches can however be used to redirect traffic to\n>>>> the main VSI (tc 0) which does not require the enhanced big buffer\n>>>> cloud filter support.\n>>>>\n>>>> v3: Cleaned up some lengthy function names. Changed ipv6 address to\n>>>> __be32 array instead of u8 array. Used macro for IP version. Minor\n>>>> formatting changes.\n>>>> v2:\n>>>> 1. Moved I40E_SWITCH_MODE_MASK definition to i40e_type.h\n>>>> 2. Moved dev_info for add/deleting cloud filters in else condition\n>>>> 3. Fixed some format specifier in dev_err logs\n>>>> 4. Refactored i40e_get_capabilities to take an additional\n>>>>   list_type parameter and use it to query device and function\n>>>>   level capabilities.\n>>>> 5. Fixed parsing tc redirect action to check for the is_tcf_mirred_tc()\n>>>>   to verify if redirect to a traffic class is supported.\n>>>> 6. Added comments for Geneve fix in cloud filter big buffer AQ\n>>>>   function definitions.\n>>>> 7. Cleaned up setup_tc interface to rebase and work with Jiri's\n>>>>   updates, separate function to process tc cls flower offloads.\n>>>> 8. Changes to make Flow Director Sideband and Cloud filters mutually\n>>>>   exclusive.\n>>>>\n>>>> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com>\n>>>> Signed-off-by: Kiran Patil <kiran.patil@intel.com>\n>>>> Signed-off-by: Anjali Singhai Jain <anjali.singhai@intel.com>\n>>>> Signed-off-by: Jingjing Wu <jingjing.wu@intel.com>\n>>>> ---\n>>>> drivers/net/ethernet/intel/i40e/i40e.h             |   49 +\n>>>> drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h  |    3 \n>>>> drivers/net/ethernet/intel/i40e/i40e_common.c      |  189 ++++\n>>>> drivers/net/ethernet/intel/i40e/i40e_main.c        |  971 +++++++++++++++++++-\n>>>> drivers/net/ethernet/intel/i40e/i40e_prototype.h   |   16 \n>>>> drivers/net/ethernet/intel/i40e/i40e_type.h        |    1 \n>>>> .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h    |    3 \n>>>> 7 files changed, 1202 insertions(+), 30 deletions(-)\n>>>>\n>>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h\n>>>> index 6018fb6..b110519 100644\n>>>> --- a/drivers/net/ethernet/intel/i40e/i40e.h\n>>>> +++ b/drivers/net/ethernet/intel/i40e/i40e.h\n>>>> @@ -55,6 +55,8 @@\n>>>> #include <linux/net_tstamp.h>\n>>>> #include <linux/ptp_clock_kernel.h>\n>>>> #include <net/pkt_cls.h>\n>>>> +#include <net/tc_act/tc_gact.h>\n>>>> +#include <net/tc_act/tc_mirred.h>\n>>>> #include \"i40e_type.h\"\n>>>> #include \"i40e_prototype.h\"\n>>>> #include \"i40e_client.h\"\n>>>> @@ -252,9 +254,52 @@ struct i40e_fdir_filter {\n>>>> \tu32 fd_id;\n>>>> };\n>>>>\n>>>> +#define IPV4_VERSION 4\n>>>> +#define IPV6_VERSION 6\n>>>> +\n>>>> +#define I40E_CLOUD_FIELD_OMAC\t0x01\n>>>> +#define I40E_CLOUD_FIELD_IMAC\t0x02\n>>>> +#define I40E_CLOUD_FIELD_IVLAN\t0x04\n>>>> +#define I40E_CLOUD_FIELD_TEN_ID\t0x08\n>>>> +#define I40E_CLOUD_FIELD_IIP\t0x10\n>>>> +\n>>>> +#define I40E_CLOUD_FILTER_FLAGS_OMAC\tI40E_CLOUD_FIELD_OMAC\n>>>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC\tI40E_CLOUD_FIELD_IMAC\n>>>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN\t(I40E_CLOUD_FIELD_IMAC | \\\n>>>> +\t\t\t\t\t\t I40E_CLOUD_FIELD_IVLAN)\n>>>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID\t(I40E_CLOUD_FIELD_IMAC | \\\n>>>> +\t\t\t\t\t\t I40E_CLOUD_FIELD_TEN_ID)\n>>>> +#define I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC (I40E_CLOUD_FIELD_OMAC | \\\n>>>> +\t\t\t\t\t\t  I40E_CLOUD_FIELD_IMAC | \\\n>>>> +\t\t\t\t\t\t  I40E_CLOUD_FIELD_TEN_ID)\n>>>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID (I40E_CLOUD_FIELD_IMAC | \\\n>>>> +\t\t\t\t\t\t   I40E_CLOUD_FIELD_IVLAN | \\\n>>>> +\t\t\t\t\t\t   I40E_CLOUD_FIELD_TEN_ID)\n>>>> +#define I40E_CLOUD_FILTER_FLAGS_IIP\tI40E_CLOUD_FIELD_IIP\n>>>> +\n>>>> struct i40e_cloud_filter {\n>>>> \tstruct hlist_node cloud_node;\n>>>> \tunsigned long cookie;\n>>>> +\t/* cloud filter input set follows */\n>>>> +\tu8 dst_mac[ETH_ALEN];\n>>>> +\tu8 src_mac[ETH_ALEN];\n>>>> +\t__be16 vlan_id;\n>>>> +\t__be32 dst_ip;\n>>>> +\t__be32 src_ip;\n>>>> +\t__be32 dst_ipv6[4];\n>>>> +\t__be32 src_ipv6[4];\n>>>> +\t__be16 dst_port;\n>>>> +\t__be16 src_port;\n>>>> +\tu32 ip_version;\n>>>> +\tu8 ip_proto;\t/* IPPROTO value */\n>>>> +\t/* L4 port type: src or destination port */\n>>>> +#define I40E_CLOUD_FILTER_PORT_SRC\t0x01\n>>>> +#define I40E_CLOUD_FILTER_PORT_DEST\t0x02\n>>>> +\tu8 port_type;\n>>>> +\tu32 tenant_id;\n>>>> +\tu8 flags;\n>>>> +#define I40E_CLOUD_TNL_TYPE_NONE\t0xff\n>>>> +\tu8 tunnel_type;\n>>>> \tu16 seid;\t/* filter control */\n>>>> };\n>>>>\n>>>> @@ -491,6 +536,8 @@ struct i40e_pf {\n>>>> #define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED\tBIT(27)\n>>>> #define I40E_FLAG_SOURCE_PRUNING_DISABLED\tBIT(28)\n>>>> #define I40E_FLAG_TC_MQPRIO\t\t\tBIT(29)\n>>>> +#define I40E_FLAG_FD_SB_INACTIVE\t\tBIT(30)\n>>>> +#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER\t\tBIT(31)\n>>>>\n>>>> \tstruct i40e_client_instance *cinst;\n>>>> \tbool stat_offsets_loaded;\n>>>> @@ -573,6 +620,8 @@ struct i40e_pf {\n>>>> \tu16 phy_led_val;\n>>>>\n>>>> \tu16 override_q_count;\n>>>> +\tu16 last_sw_conf_flags;\n>>>> +\tu16 last_sw_conf_valid_flags;\n>>>> };\n>>>>\n>>>> /**\n>>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h\n>>>> index 2e567c2..feb3d42 100644\n>>>> --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h\n>>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h\n>>>> @@ -1392,6 +1392,9 @@ struct i40e_aqc_cloud_filters_element_data {\n>>>> \t\tstruct {\n>>>> \t\t\tu8 data[16];\n>>>> \t\t} v6;\n>>>> +\t\tstruct {\n>>>> +\t\t\t__le16 data[8];\n>>>> +\t\t} raw_v6;\n>>>> \t} ipaddr;\n>>>> \t__le16\tflags;\n>>>> #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT\t\t\t0\n>>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c\n>>>> index 9567702..d9c9665 100644\n>>>> --- a/drivers/net/ethernet/intel/i40e/i40e_common.c\n>>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c\n>>>> @@ -5434,5 +5434,194 @@ i40e_add_pinfo_to_list(struct i40e_hw *hw,\n>>>>\n>>>> \tstatus = i40e_aq_write_ppp(hw, (void *)sec, sec->data_end,\n>>>> \t\t\t\t   track_id, &offset, &info, NULL);\n>>>> +\n>>>> +\treturn status;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_aq_add_cloud_filters\n>>>> + * @hw: pointer to the hardware structure\n>>>> + * @seid: VSI seid to add cloud filters from\n>>>> + * @filters: Buffer which contains the filters to be added\n>>>> + * @filter_count: number of filters contained in the buffer\n>>>> + *\n>>>> + * Set the cloud filters for a given VSI.  The contents of the\n>>>> + * i40e_aqc_cloud_filters_element_data are filled in by the caller\n>>>> + * of the function.\n>>>> + *\n>>>> + **/\n>>>> +enum i40e_status_code\n>>>> +i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 seid,\n>>>> +\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>>>> +\t\t\t  u8 filter_count)\n>>>> +{\n>>>> +\tstruct i40e_aq_desc desc;\n>>>> +\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>>>> +\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>>>> +\tenum i40e_status_code status;\n>>>> +\tu16 buff_len;\n>>>> +\n>>>> +\ti40e_fill_default_direct_cmd_desc(&desc,\n>>>> +\t\t\t\t\t  i40e_aqc_opc_add_cloud_filters);\n>>>> +\n>>>> +\tbuff_len = filter_count * sizeof(*filters);\n>>>> +\tdesc.datalen = cpu_to_le16(buff_len);\n>>>> +\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>>>> +\tcmd->num_filters = filter_count;\n>>>> +\tcmd->seid = cpu_to_le16(seid);\n>>>> +\n>>>> +\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>>>> +\n>>>> +\treturn status;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_aq_add_cloud_filters_bb\n>>>> + * @hw: pointer to the hardware structure\n>>>> + * @seid: VSI seid to add cloud filters from\n>>>> + * @filters: Buffer which contains the filters in big buffer to be added\n>>>> + * @filter_count: number of filters contained in the buffer\n>>>> + *\n>>>> + * Set the big buffer cloud filters for a given VSI.  The contents of the\n>>>> + * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the\n>>>> + * function.\n>>>> + *\n>>>> + **/\n>>>> +i40e_status\n>>>> +i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>>>> +\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>>>> +\t\t\t     u8 filter_count)\n>>>> +{\n>>>> +\tstruct i40e_aq_desc desc;\n>>>> +\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>>>> +\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>>>> +\ti40e_status status;\n>>>> +\tu16 buff_len;\n>>>> +\tint i;\n>>>> +\n>>>> +\ti40e_fill_default_direct_cmd_desc(&desc,\n>>>> +\t\t\t\t\t  i40e_aqc_opc_add_cloud_filters);\n>>>> +\n>>>> +\tbuff_len = filter_count * sizeof(*filters);\n>>>> +\tdesc.datalen = cpu_to_le16(buff_len);\n>>>> +\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>>>> +\tcmd->num_filters = filter_count;\n>>>> +\tcmd->seid = cpu_to_le16(seid);\n>>>> +\tcmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;\n>>>> +\n>>>> +\tfor (i = 0; i < filter_count; i++) {\n>>>> +\t\tu16 tnl_type;\n>>>> +\t\tu32 ti;\n>>>> +\n>>>> +\t\ttnl_type = (le16_to_cpu(filters[i].element.flags) &\n>>>> +\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>\n>>>> +\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;\n>>>> +\n>>>> +\t\t/* For Geneve, the VNI should be placed in offset shifted by a\n>>>> +\t\t * byte than the offset for the Tenant ID for rest of the\n>>>> +\t\t * tunnels.\n>>>> +\t\t */\n>>>> +\t\tif (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {\n>>>> +\t\t\tti = le32_to_cpu(filters[i].element.tenant_id);\n>>>> +\t\t\tfilters[i].element.tenant_id = cpu_to_le32(ti << 8);\n>>>> +\t\t}\n>>>> +\t}\n>>>> +\n>>>> +\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>>>> +\n>>>> +\treturn status;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_aq_rem_cloud_filters\n>>>> + * @hw: pointer to the hardware structure\n>>>> + * @seid: VSI seid to remove cloud filters from\n>>>> + * @filters: Buffer which contains the filters to be removed\n>>>> + * @filter_count: number of filters contained in the buffer\n>>>> + *\n>>>> + * Remove the cloud filters for a given VSI.  The contents of the\n>>>> + * i40e_aqc_cloud_filters_element_data are filled in by the caller\n>>>> + * of the function.\n>>>> + *\n>>>> + **/\n>>>> +enum i40e_status_code\n>>>> +i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 seid,\n>>>> +\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>>>> +\t\t\t  u8 filter_count)\n>>>> +{\n>>>> +\tstruct i40e_aq_desc desc;\n>>>> +\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>>>> +\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>>>> +\tenum i40e_status_code status;\n>>>> +\tu16 buff_len;\n>>>> +\n>>>> +\ti40e_fill_default_direct_cmd_desc(&desc,\n>>>> +\t\t\t\t\t  i40e_aqc_opc_remove_cloud_filters);\n>>>> +\n>>>> +\tbuff_len = filter_count * sizeof(*filters);\n>>>> +\tdesc.datalen = cpu_to_le16(buff_len);\n>>>> +\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>>>> +\tcmd->num_filters = filter_count;\n>>>> +\tcmd->seid = cpu_to_le16(seid);\n>>>> +\n>>>> +\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>>>> +\n>>>> +\treturn status;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_aq_rem_cloud_filters_bb\n>>>> + * @hw: pointer to the hardware structure\n>>>> + * @seid: VSI seid to remove cloud filters from\n>>>> + * @filters: Buffer which contains the filters in big buffer to be removed\n>>>> + * @filter_count: number of filters contained in the buffer\n>>>> + *\n>>>> + * Remove the big buffer cloud filters for a given VSI.  The contents of the\n>>>> + * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the\n>>>> + * function.\n>>>> + *\n>>>> + **/\n>>>> +i40e_status\n>>>> +i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>>>> +\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>>>> +\t\t\t     u8 filter_count)\n>>>> +{\n>>>> +\tstruct i40e_aq_desc desc;\n>>>> +\tstruct i40e_aqc_add_remove_cloud_filters *cmd =\n>>>> +\t(struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;\n>>>> +\ti40e_status status;\n>>>> +\tu16 buff_len;\n>>>> +\tint i;\n>>>> +\n>>>> +\ti40e_fill_default_direct_cmd_desc(&desc,\n>>>> +\t\t\t\t\t  i40e_aqc_opc_remove_cloud_filters);\n>>>> +\n>>>> +\tbuff_len = filter_count * sizeof(*filters);\n>>>> +\tdesc.datalen = cpu_to_le16(buff_len);\n>>>> +\tdesc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));\n>>>> +\tcmd->num_filters = filter_count;\n>>>> +\tcmd->seid = cpu_to_le16(seid);\n>>>> +\tcmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;\n>>>> +\n>>>> +\tfor (i = 0; i < filter_count; i++) {\n>>>> +\t\tu16 tnl_type;\n>>>> +\t\tu32 ti;\n>>>> +\n>>>> +\t\ttnl_type = (le16_to_cpu(filters[i].element.flags) &\n>>>> +\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>\n>>>> +\t\t\t   I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;\n>>>> +\n>>>> +\t\t/* For Geneve, the VNI should be placed in offset shifted by a\n>>>> +\t\t * byte than the offset for the Tenant ID for rest of the\n>>>> +\t\t * tunnels.\n>>>> +\t\t */\n>>>> +\t\tif (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {\n>>>> +\t\t\tti = le32_to_cpu(filters[i].element.tenant_id);\n>>>> +\t\t\tfilters[i].element.tenant_id = cpu_to_le32(ti << 8);\n>>>> +\t\t}\n>>>> +\t}\n>>>> +\n>>>> +\tstatus = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);\n>>>> +\n>>>> \treturn status;\n>>>> }\n>>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c\n>>>> index afcf08a..96ee608 100644\n>>>> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c\n>>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c\n>>>> @@ -69,6 +69,15 @@ static int i40e_reset(struct i40e_pf *pf);\n>>>> static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired);\n>>>> static void i40e_fdir_sb_setup(struct i40e_pf *pf);\n>>>> static int i40e_veb_get_bw_info(struct i40e_veb *veb);\n>>>> +static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,\n>>>> +\t\t\t\t     struct i40e_cloud_filter *filter,\n>>>> +\t\t\t\t     bool add);\n>>>> +static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,\n>>>> +\t\t\t\t\t     struct i40e_cloud_filter *filter,\n>>>> +\t\t\t\t\t     bool add);\n>>>> +static int i40e_get_capabilities(struct i40e_pf *pf,\n>>>> +\t\t\t\t enum i40e_admin_queue_opc list_type);\n>>>> +\n>>>>\n>>>> /* i40e_pci_tbl - PCI Device ID Table\n>>>>  *\n>>>> @@ -5478,7 +5487,11 @@ int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 seid, u64 max_tx_rate)\n>>>>  **/\n>>>> static void i40e_remove_queue_channels(struct i40e_vsi *vsi)\n>>>> {\n>>>> +\tenum i40e_admin_queue_err last_aq_status;\n>>>> +\tstruct i40e_cloud_filter *cfilter;\n>>>> \tstruct i40e_channel *ch, *ch_tmp;\n>>>> +\tstruct i40e_pf *pf = vsi->back;\n>>>> +\tstruct hlist_node *node;\n>>>> \tint ret, i;\n>>>>\n>>>> \t/* Reset rss size that was stored when reconfiguring rss for\n>>>> @@ -5519,6 +5532,29 @@ static void i40e_remove_queue_channels(struct i40e_vsi *vsi)\n>>>> \t\t\t\t \"Failed to reset tx rate for ch->seid %u\\n\",\n>>>> \t\t\t\t ch->seid);\n>>>>\n>>>> +\t\t/* delete cloud filters associated with this channel */\n>>>> +\t\thlist_for_each_entry_safe(cfilter, node,\n>>>> +\t\t\t\t\t  &pf->cloud_filter_list, cloud_node) {\n>>>> +\t\t\tif (cfilter->seid != ch->seid)\n>>>> +\t\t\t\tcontinue;\n>>>> +\n>>>> +\t\t\thash_del(&cfilter->cloud_node);\n>>>> +\t\t\tif (cfilter->dst_port)\n>>>> +\t\t\t\tret = i40e_add_del_cloud_filter_big_buf(vsi,\n>>>> +\t\t\t\t\t\t\t\t\tcfilter,\n>>>> +\t\t\t\t\t\t\t\t\tfalse);\n>>>> +\t\t\telse\n>>>> +\t\t\t\tret = i40e_add_del_cloud_filter(vsi, cfilter,\n>>>> +\t\t\t\t\t\t\t\tfalse);\n>>>> +\t\t\tlast_aq_status = pf->hw.aq.asq_last_status;\n>>>> +\t\t\tif (ret)\n>>>> +\t\t\t\tdev_info(&pf->pdev->dev,\n>>>> +\t\t\t\t\t \"Failed to delete cloud filter, err %s aq_err %s\\n\",\n>>>> +\t\t\t\t\t i40e_stat_str(&pf->hw, ret),\n>>>> +\t\t\t\t\t i40e_aq_str(&pf->hw, last_aq_status));\n>>>> +\t\t\tkfree(cfilter);\n>>>> +\t\t}\n>>>> +\n>>>> \t\t/* delete VSI from FW */\n>>>> \t\tret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,\n>>>> \t\t\t\t\t     NULL);\n>>>> @@ -5970,6 +6006,74 @@ static bool i40e_setup_channel(struct i40e_pf *pf, struct i40e_vsi *vsi,\n>>>> }\n>>>>\n>>>> /**\n>>>> + * i40e_validate_and_set_switch_mode - sets up switch mode correctly\n>>>> + * @vsi: ptr to VSI which has PF backing\n>>>> + * @l4type: true for TCP ond false for UDP\n>>>> + * @port_type: true if port is destination and false if port is source\n>>>> + *\n>>>> + * Sets up switch mode correctly if it needs to be changed and perform\n>>>> + * what are allowed modes.\n>>>> + **/\n>>>> +static int i40e_validate_and_set_switch_mode(struct i40e_vsi *vsi, bool l4type,\n>>>> +\t\t\t\t\t     bool port_type)\n>>>> +{\n>>>> +\tu8 mode;\n>>>> +\tstruct i40e_pf *pf = vsi->back;\n>>>> +\tstruct i40e_hw *hw = &pf->hw;\n>>>> +\tint ret;\n>>>> +\n>>>> +\tret = i40e_get_capabilities(pf, i40e_aqc_opc_list_dev_capabilities);\n>>>> +\tif (ret)\n>>>> +\t\treturn -EINVAL;\n>>>> +\n>>>> +\tif (hw->dev_caps.switch_mode) {\n>>>> +\t\t/* if switch mode is set, support mode2 (non-tunneled for\n>>>> +\t\t * cloud filter) for now\n>>>> +\t\t */\n>>>> +\t\tu32 switch_mode = hw->dev_caps.switch_mode &\n>>>> +\t\t\t\t\t\t\tI40E_SWITCH_MODE_MASK;\n>>>> +\t\tif (switch_mode >= I40E_NVM_IMAGE_TYPE_MODE1) {\n>>>> +\t\t\tif (switch_mode == I40E_NVM_IMAGE_TYPE_MODE2)\n>>>> +\t\t\t\treturn 0;\n>>>> +\t\t\tdev_err(&pf->pdev->dev,\n>>>> +\t\t\t\t\"Invalid switch_mode (%d), only non-tunneled mode for cloud filter is supported\\n\",\n>>>> +\t\t\t\thw->dev_caps.switch_mode);\n>>>> +\t\t\treturn -EINVAL;\n>>>> +\t\t}\n>>>> +\t}\n>>>> +\n>>>> +\t/* port_type: true for destination port and false for source port\n>>>> +\t * For now, supports only destination port type\n>>>> +\t */\n>>>> +\tif (!port_type) {\n>>>> +\t\tdev_err(&pf->pdev->dev, \"src port type not supported\\n\");\n>>>> +\t\treturn -EINVAL;\n>>>> +\t}\n>>>> +\n>>>> +\t/* Set Bit 7 to be valid */\n>>>> +\tmode = I40E_AQ_SET_SWITCH_BIT7_VALID;\n>>>> +\n>>>> +\t/* Set L4type to both TCP and UDP support */\n>>>> +\tmode |= I40E_AQ_SET_SWITCH_L4_TYPE_BOTH;\n>>>> +\n>>>> +\t/* Set cloud filter mode */\n>>>> +\tmode |= I40E_AQ_SET_SWITCH_MODE_NON_TUNNEL;\n>>>> +\n>>>> +\t/* Prep mode field for set_switch_config */\n>>>> +\tret = i40e_aq_set_switch_config(hw, pf->last_sw_conf_flags,\n>>>> +\t\t\t\t\tpf->last_sw_conf_valid_flags,\n>>>> +\t\t\t\t\tmode, NULL);\n>>>> +\tif (ret && hw->aq.asq_last_status != I40E_AQ_RC_ESRCH)\n>>>> +\t\tdev_err(&pf->pdev->dev,\n>>>> +\t\t\t\"couldn't set switch config bits, err %s aq_err %s\\n\",\n>>>> +\t\t\ti40e_stat_str(hw, ret),\n>>>> +\t\t\ti40e_aq_str(hw,\n>>>> +\t\t\t\t    hw->aq.asq_last_status));\n>>>> +\n>>>> +\treturn ret;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>>  * i40e_create_queue_channel - function to create channel\n>>>>  * @vsi: VSI to be configured\n>>>>  * @ch: ptr to channel (it contains channel specific params)\n>>>> @@ -6735,13 +6839,726 @@ static int i40e_setup_tc(struct net_device *netdev, void *type_data)\n>>>> \treturn ret;\n>>>> }\n>>>>\n>>>> +/**\n>>>> + * i40e_set_cld_element - sets cloud filter element data\n>>>> + * @filter: cloud filter rule\n>>>> + * @cld: ptr to cloud filter element data\n>>>> + *\n>>>> + * This is helper function to copy data into cloud filter element\n>>>> + **/\n>>>> +static inline void\n>>>> +i40e_set_cld_element(struct i40e_cloud_filter *filter,\n>>>> +\t\t     struct i40e_aqc_cloud_filters_element_data *cld)\n>>>> +{\n>>>> +\tint i, j;\n>>>> +\tu32 ipa;\n>>>> +\n>>>> +\tmemset(cld, 0, sizeof(*cld));\n>>>> +\tether_addr_copy(cld->outer_mac, filter->dst_mac);\n>>>> +\tether_addr_copy(cld->inner_mac, filter->src_mac);\n>>>> +\n>>>> +\tif (filter->ip_version == IPV6_VERSION) {\n>>>> +#define IPV6_MAX_INDEX\t(ARRAY_SIZE(filter->dst_ipv6) - 1)\n>>>> +\t\tfor (i = 0, j = 0; i < 4; i++, j += 2) {\n>>>> +\t\t\tipa = be32_to_cpu(filter->dst_ipv6[IPV6_MAX_INDEX - i]);\n>>>> +\t\t\tipa = cpu_to_le32(ipa);\n>>>> +\t\t\tmemcpy(&cld->ipaddr.raw_v6.data[j], &ipa, 4);\n>>>> +\t\t}\n>>>> +\t} else {\n>>>> +\t\tipa = be32_to_cpu(filter->dst_ip);\n>>>> +\t\tmemcpy(&cld->ipaddr.v4.data, &ipa, 4);\n>>>> +\t}\n>>>> +\n>>>> +\tcld->inner_vlan = cpu_to_le16(ntohs(filter->vlan_id));\n>>>> +\n>>>> +\t/* tenant_id is not supported by FW now, once the support is enabled\n>>>> +\t * fill the cld->tenant_id with cpu_to_le32(filter->tenant_id)\n>>>> +\t */\n>>>> +\tif (filter->tenant_id)\n>>>> +\t\treturn;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_add_del_cloud_filter - Add/del cloud filter\n>>>> + * @vsi: pointer to VSI\n>>>> + * @filter: cloud filter rule\n>>>> + * @add: if true, add, if false, delete\n>>>> + *\n>>>> + * Add or delete a cloud filter for a specific flow spec.\n>>>> + * Returns 0 if the filter were successfully added.\n>>>> + **/\n>>>> +static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,\n>>>> +\t\t\t\t     struct i40e_cloud_filter *filter, bool add)\n>>>> +{\n>>>> +\tstruct i40e_aqc_cloud_filters_element_data cld_filter;\n>>>> +\tstruct i40e_pf *pf = vsi->back;\n>>>> +\tint ret;\n>>>> +\tstatic const u16 flag_table[128] = {\n>>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_OMAC]  =\n>>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_OMAC,\n>>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC]  =\n>>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC,\n>>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN]  =\n>>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN,\n>>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID] =\n>>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID,\n>>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC] =\n>>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC,\n>>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID] =\n>>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID,\n>>>> +\t\t[I40E_CLOUD_FILTER_FLAGS_IIP] =\n>>>> +\t\t\tI40E_AQC_ADD_CLOUD_FILTER_IIP,\n>>>> +\t};\n>>>> +\n>>>> +\tif (filter->flags >= ARRAY_SIZE(flag_table))\n>>>> +\t\treturn I40E_ERR_CONFIG;\n>>>> +\n>>>> +\t/* copy element needed to add cloud filter from filter */\n>>>> +\ti40e_set_cld_element(filter, &cld_filter);\n>>>> +\n>>>> +\tif (filter->tunnel_type != I40E_CLOUD_TNL_TYPE_NONE)\n>>>> +\t\tcld_filter.flags = cpu_to_le16(filter->tunnel_type <<\n>>>> +\t\t\t\t\t     I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT);\n>>>> +\n>>>> +\tif (filter->ip_version == IPV6_VERSION)\n>>>> +\t\tcld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |\n>>>> +\t\t\t\t\t\tI40E_AQC_ADD_CLOUD_FLAGS_IPV6);\n>>>> +\telse\n>>>> +\t\tcld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |\n>>>> +\t\t\t\t\t\tI40E_AQC_ADD_CLOUD_FLAGS_IPV4);\n>>>> +\n>>>> +\tif (add)\n>>>> +\t\tret = i40e_aq_add_cloud_filters(&pf->hw, filter->seid,\n>>>> +\t\t\t\t\t\t&cld_filter, 1);\n>>>> +\telse\n>>>> +\t\tret = i40e_aq_rem_cloud_filters(&pf->hw, filter->seid,\n>>>> +\t\t\t\t\t\t&cld_filter, 1);\n>>>> +\tif (ret)\n>>>> +\t\tdev_dbg(&pf->pdev->dev,\n>>>> +\t\t\t\"Failed to %s cloud filter using l4 port %u, err %d aq_err %d\\n\",\n>>>> +\t\t\tadd ? \"add\" : \"delete\", filter->dst_port, ret,\n>>>> +\t\t\tpf->hw.aq.asq_last_status);\n>>>> +\telse\n>>>> +\t\tdev_info(&pf->pdev->dev,\n>>>> +\t\t\t \"%s cloud filter for VSI: %d\\n\",\n>>>> +\t\t\t add ? \"Added\" : \"Deleted\", filter->seid);\n>>>> +\treturn ret;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_add_del_cloud_filter_big_buf - Add/del cloud filter using big_buf\n>>>> + * @vsi: pointer to VSI\n>>>> + * @filter: cloud filter rule\n>>>> + * @add: if true, add, if false, delete\n>>>> + *\n>>>> + * Add or delete a cloud filter for a specific flow spec using big buffer.\n>>>> + * Returns 0 if the filter were successfully added.\n>>>> + **/\n>>>> +static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,\n>>>> +\t\t\t\t\t     struct i40e_cloud_filter *filter,\n>>>> +\t\t\t\t\t     bool add)\n>>>> +{\n>>>> +\tstruct i40e_aqc_cloud_filters_element_bb cld_filter;\n>>>> +\tstruct i40e_pf *pf = vsi->back;\n>>>> +\tint ret;\n>>>> +\n>>>> +\t/* Both (Outer/Inner) valid mac_addr are not supported */\n>>>> +\tif (is_valid_ether_addr(filter->dst_mac) &&\n>>>> +\t    is_valid_ether_addr(filter->src_mac))\n>>>> +\t\treturn -EINVAL;\n>>>> +\n>>>> +\t/* Make sure port is specified, otherwise bail out, for channel\n>>>> +\t * specific cloud filter needs 'L4 port' to be non-zero\n>>>> +\t */\n>>>> +\tif (!filter->dst_port)\n>>>> +\t\treturn -EINVAL;\n>>>> +\n>>>> +\t/* adding filter using src_port/src_ip is not supported at this stage */\n>>>> +\tif (filter->src_port || filter->src_ip ||\n>>>> +\t    !ipv6_addr_any((struct in6_addr *)&filter->src_ipv6))\n>>>> +\t\treturn -EINVAL;\n>>>> +\n>>>> +\t/* copy element needed to add cloud filter from filter */\n>>>> +\ti40e_set_cld_element(filter, &cld_filter.element);\n>>>> +\n>>>> +\tif (is_valid_ether_addr(filter->dst_mac) ||\n>>>> +\t    is_valid_ether_addr(filter->src_mac) ||\n>>>> +\t    is_multicast_ether_addr(filter->dst_mac) ||\n>>>> +\t    is_multicast_ether_addr(filter->src_mac)) {\n>>>> +\t\t/* MAC + IP : unsupported mode */\n>>>> +\t\tif (filter->dst_ip)\n>>>> +\t\t\treturn -EINVAL;\n>>>> +\n>>>> +\t\t/* since we validated that L4 port must be valid before\n>>>> +\t\t * we get here, start with respective \"flags\" value\n>>>> +\t\t * and update if vlan is present or not\n>>>> +\t\t */\n>>>> +\t\tcld_filter.element.flags =\n>>>> +\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT);\n>>>> +\n>>>> +\t\tif (filter->vlan_id) {\n>>>> +\t\t\tcld_filter.element.flags =\n>>>> +\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT);\n>>>> +\t\t}\n>>>> +\n>>>> +\t} else if (filter->dst_ip || filter->ip_version == IPV6_VERSION) {\n>>>> +\t\tcld_filter.element.flags =\n>>>> +\t\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_IP_PORT);\n>>>> +\t\tif (filter->ip_version == IPV6_VERSION)\n>>>> +\t\t\tcld_filter.element.flags |=\n>>>> +\t\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV6);\n>>>> +\t\telse\n>>>> +\t\t\tcld_filter.element.flags |=\n>>>> +\t\t\t\tcpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV4);\n>>>> +\t} else {\n>>>> +\t\tdev_err(&pf->pdev->dev,\n>>>> +\t\t\t\"either mac or ip has to be valid for cloud filter\\n\");\n>>>> +\t\treturn -EINVAL;\n>>>> +\t}\n>>>> +\n>>>> +\t/* Now copy L4 port in Byte 6..7 in general fields */\n>>>> +\tcld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0] =\n>>>> +\t\t\t\t\t\tbe16_to_cpu(filter->dst_port);\n>>>> +\n>>>> +\tif (add) {\n>>>> +\t\tbool proto_type, port_type;\n>>>> +\n>>>> +\t\tproto_type = (filter->ip_proto == IPPROTO_TCP) ? true : false;\n>>>> +\t\tport_type = (filter->port_type & I40E_CLOUD_FILTER_PORT_DEST) ?\n>>>> +\t\t\t     true : false;\n>>>> +\n>>>> +\t\t/* For now, src port based cloud filter for channel is not\n>>>> +\t\t * supported\n>>>> +\t\t */\n>>>> +\t\tif (!port_type) {\n>>>> +\t\t\tdev_err(&pf->pdev->dev,\n>>>> +\t\t\t\t\"unsupported port type (src port)\\n\");\n>>>> +\t\t\treturn -EOPNOTSUPP;\n>>>> +\t\t}\n>>>> +\n>>>> +\t\t/* Validate current device switch mode, change if necessary */\n>>>> +\t\tret = i40e_validate_and_set_switch_mode(vsi, proto_type,\n>>>> +\t\t\t\t\t\t\tport_type);\n>>>> +\t\tif (ret) {\n>>>> +\t\t\tdev_err(&pf->pdev->dev,\n>>>> +\t\t\t\t\"failed to set switch mode, ret %d\\n\",\n>>>> +\t\t\t\tret);\n>>>> +\t\t\treturn ret;\n>>>> +\t\t}\n>>>> +\n>>>> +\t\tret = i40e_aq_add_cloud_filters_bb(&pf->hw, filter->seid,\n>>>> +\t\t\t\t\t\t   &cld_filter, 1);\n>>>> +\t} else {\n>>>> +\t\tret = i40e_aq_rem_cloud_filters_bb(&pf->hw, filter->seid,\n>>>> +\t\t\t\t\t\t   &cld_filter, 1);\n>>>> +\t}\n>>>> +\n>>>> +\tif (ret)\n>>>> +\t\tdev_dbg(&pf->pdev->dev,\n>>>> +\t\t\t\"Failed to %s cloud filter(big buffer) err %d aq_err %d\\n\",\n>>>> +\t\t\tadd ? \"add\" : \"delete\", ret, pf->hw.aq.asq_last_status);\n>>>> +\telse\n>>>> +\t\tdev_info(&pf->pdev->dev,\n>>>> +\t\t\t \"%s cloud filter for VSI: %d, L4 port: %d\\n\",\n>>>> +\t\t\t add ? \"add\" : \"delete\", filter->seid,\n>>>> +\t\t\t ntohs(filter->dst_port));\n>>>> +\treturn ret;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_parse_cls_flower - Parse tc flower filters provided by kernel\n>>>> + * @vsi: Pointer to VSI\n>>>> + * @cls_flower: Pointer to struct tc_cls_flower_offload\n>>>> + * @filter: Pointer to cloud filter structure\n>>>> + *\n>>>> + **/\n>>>> +static int i40e_parse_cls_flower(struct i40e_vsi *vsi,\n>>>> +\t\t\t\t struct tc_cls_flower_offload *f,\n>>>> +\t\t\t\t struct i40e_cloud_filter *filter)\n>>>> +{\n>>>> +\tstruct i40e_pf *pf = vsi->back;\n>>>> +\tu16 addr_type = 0;\n>>>> +\tu8 field_flags = 0;\n>>>> +\n>>>> +\tif (f->dissector->used_keys &\n>>>> +\t    ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |\n>>>> +\t      BIT(FLOW_DISSECTOR_KEY_BASIC) |\n>>>> +\t      BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |\n>>>> +\t      BIT(FLOW_DISSECTOR_KEY_VLAN) |\n>>>> +\t      BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |\n>>>> +\t      BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |\n>>>> +\t      BIT(FLOW_DISSECTOR_KEY_PORTS) |\n>>>> +\t      BIT(FLOW_DISSECTOR_KEY_ENC_KEYID))) {\n>>>> +\t\tdev_err(&pf->pdev->dev, \"Unsupported key used: 0x%x\\n\",\n>>>> +\t\t\tf->dissector->used_keys);\n>>>> +\t\treturn -EOPNOTSUPP;\n>>>> +\t}\n>>>> +\n>>>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {\n>>>> +\t\tstruct flow_dissector_key_keyid *key =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ENC_KEYID,\n>>>> +\t\t\t\t\t\t  f->key);\n>>>> +\n>>>> +\t\tstruct flow_dissector_key_keyid *mask =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ENC_KEYID,\n>>>> +\t\t\t\t\t\t  f->mask);\n>>>> +\n>>>> +\t\tif (mask->keyid != 0)\n>>>> +\t\t\tfield_flags |= I40E_CLOUD_FIELD_TEN_ID;\n>>>> +\n>>>> +\t\tfilter->tenant_id = be32_to_cpu(key->keyid);\n>>>> +\t}\n>>>> +\n>>>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {\n>>>> +\t\tstruct flow_dissector_key_basic *key =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_BASIC,\n>>>> +\t\t\t\t\t\t  f->key);\n>>>> +\n>>>> +\t\tfilter->ip_proto = key->ip_proto;\n>>>> +\t}\n>>>> +\n>>>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {\n>>>> +\t\tstruct flow_dissector_key_eth_addrs *key =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ETH_ADDRS,\n>>>> +\t\t\t\t\t\t  f->key);\n>>>> +\n>>>> +\t\tstruct flow_dissector_key_eth_addrs *mask =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_ETH_ADDRS,\n>>>> +\t\t\t\t\t\t  f->mask);\n>>>> +\n>>>> +\t\t/* use is_broadcast and is_zero to check for all 0xf or 0 */\n>>>> +\t\tif (!is_zero_ether_addr(mask->dst)) {\n>>>> +\t\t\tif (is_broadcast_ether_addr(mask->dst)) {\n>>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_OMAC;\n>>>> +\t\t\t} else {\n>>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ether dest mask %pM\\n\",\n>>>> +\t\t\t\t\tmask->dst);\n>>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>>> +\t\t\t}\n>>>> +\t\t}\n>>>> +\n>>>> +\t\tif (!is_zero_ether_addr(mask->src)) {\n>>>> +\t\t\tif (is_broadcast_ether_addr(mask->src)) {\n>>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IMAC;\n>>>> +\t\t\t} else {\n>>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ether src mask %pM\\n\",\n>>>> +\t\t\t\t\tmask->src);\n>>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>>> +\t\t\t}\n>>>> +\t\t}\n>>>> +\t\tether_addr_copy(filter->dst_mac, key->dst);\n>>>> +\t\tether_addr_copy(filter->src_mac, key->src);\n>>>> +\t}\n>>>> +\n>>>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {\n>>>> +\t\tstruct flow_dissector_key_vlan *key =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_VLAN,\n>>>> +\t\t\t\t\t\t  f->key);\n>>>> +\t\tstruct flow_dissector_key_vlan *mask =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_VLAN,\n>>>> +\t\t\t\t\t\t  f->mask);\n>>>> +\n>>>> +\t\tif (mask->vlan_id) {\n>>>> +\t\t\tif (mask->vlan_id == VLAN_VID_MASK) {\n>>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IVLAN;\n>>>> +\n>>>> +\t\t\t} else {\n>>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad vlan mask 0x%04x\\n\",\n>>>> +\t\t\t\t\tmask->vlan_id);\n>>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>>> +\t\t\t}\n>>>> +\t\t}\n>>>> +\n>>>> +\t\tfilter->vlan_id = cpu_to_be16(key->vlan_id);\n>>>> +\t}\n>>>> +\n>>>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {\n>>>> +\t\tstruct flow_dissector_key_control *key =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_CONTROL,\n>>>> +\t\t\t\t\t\t  f->key);\n>>>> +\n>>>> +\t\taddr_type = key->addr_type;\n>>>> +\t}\n>>>> +\n>>>> +\tif (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {\n>>>> +\t\tstruct flow_dissector_key_ipv4_addrs *key =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV4_ADDRS,\n>>>> +\t\t\t\t\t\t  f->key);\n>>>> +\t\tstruct flow_dissector_key_ipv4_addrs *mask =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV4_ADDRS,\n>>>> +\t\t\t\t\t\t  f->mask);\n>>>> +\n>>>> +\t\tif (mask->dst) {\n>>>> +\t\t\tif (mask->dst == cpu_to_be32(0xffffffff)) {\n>>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>>>> +\t\t\t} else {\n>>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ip dst mask 0x%08x\\n\",\n>>>> +\t\t\t\t\tbe32_to_cpu(mask->dst));\n>>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>>> +\t\t\t}\n>>>> +\t\t}\n>>>> +\n>>>> +\t\tif (mask->src) {\n>>>> +\t\t\tif (mask->src == cpu_to_be32(0xffffffff)) {\n>>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>>>> +\t\t\t} else {\n>>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad ip src mask 0x%08x\\n\",\n>>>> +\t\t\t\t\tbe32_to_cpu(mask->dst));\n>>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>>> +\t\t\t}\n>>>> +\t\t}\n>>>> +\n>>>> +\t\tif (field_flags & I40E_CLOUD_FIELD_TEN_ID) {\n>>>> +\t\t\tdev_err(&pf->pdev->dev, \"Tenant id not allowed for ip filter\\n\");\n>>>> +\t\t\treturn I40E_ERR_CONFIG;\n>>>> +\t\t}\n>>>> +\t\tfilter->dst_ip = key->dst;\n>>>> +\t\tfilter->src_ip = key->src;\n>>>> +\t\tfilter->ip_version = IPV4_VERSION;\n>>>> +\t}\n>>>> +\n>>>> +\tif (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {\n>>>> +\t\tstruct flow_dissector_key_ipv6_addrs *key =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV6_ADDRS,\n>>>> +\t\t\t\t\t\t  f->key);\n>>>> +\t\tstruct flow_dissector_key_ipv6_addrs *mask =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_IPV6_ADDRS,\n>>>> +\t\t\t\t\t\t  f->mask);\n>>>> +\n>>>> +\t\t/* src and dest IPV6 address should not be LOOPBACK\n>>>> +\t\t * (0:0:0:0:0:0:0:1), which can be represented as ::1\n>>>> +\t\t */\n>>>> +\t\tif (ipv6_addr_loopback(&key->dst) ||\n>>>> +\t\t    ipv6_addr_loopback(&key->src)) {\n>>>> +\t\t\tdev_err(&pf->pdev->dev,\n>>>> +\t\t\t\t\"Bad ipv6, addr is LOOPBACK\\n\");\n>>>> +\t\t\treturn I40E_ERR_CONFIG;\n>>>> +\t\t}\n>>>> +\t\tif (!ipv6_addr_any(&mask->dst) || !ipv6_addr_any(&mask->src))\n>>>> +\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>>>> +\n>>>> +\t\tmemcpy(&filter->src_ipv6, &key->src.s6_addr32,\n>>>> +\t\t       sizeof(filter->src_ipv6));\n>>>> +\t\tmemcpy(&filter->dst_ipv6, &key->dst.s6_addr32,\n>>>> +\t\t       sizeof(filter->dst_ipv6));\n>>>> +\n>>>> +\t\t/* mark it as IPv6 filter, to be used later */\n>>>> +\t\tfilter->ip_version = IPV6_VERSION;\n>>>> +\t}\n>>>> +\n>>>> +\tif (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {\n>>>> +\t\tstruct flow_dissector_key_ports *key =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_PORTS,\n>>>> +\t\t\t\t\t\t  f->key);\n>>>> +\t\tstruct flow_dissector_key_ports *mask =\n>>>> +\t\t\tskb_flow_dissector_target(f->dissector,\n>>>> +\t\t\t\t\t\t  FLOW_DISSECTOR_KEY_PORTS,\n>>>> +\t\t\t\t\t\t  f->mask);\n>>>> +\n>>>> +\t\tif (mask->src) {\n>>>> +\t\t\tif (mask->src == cpu_to_be16(0xffff)) {\n>>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>>>> +\t\t\t} else {\n>>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad src port mask 0x%04x\\n\",\n>>>> +\t\t\t\t\tbe16_to_cpu(mask->src));\n>>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>>> +\t\t\t}\n>>>> +\t\t}\n>>>> +\n>>>> +\t\tif (mask->dst) {\n>>>> +\t\t\tif (mask->dst == cpu_to_be16(0xffff)) {\n>>>> +\t\t\t\tfield_flags |= I40E_CLOUD_FIELD_IIP;\n>>>> +\t\t\t} else {\n>>>> +\t\t\t\tdev_err(&pf->pdev->dev, \"Bad dst port mask 0x%04x\\n\",\n>>>> +\t\t\t\t\tbe16_to_cpu(mask->dst));\n>>>> +\t\t\t\treturn I40E_ERR_CONFIG;\n>>>> +\t\t\t}\n>>>> +\t\t}\n>>>> +\n>>>> +\t\tfilter->dst_port = key->dst;\n>>>> +\t\tfilter->src_port = key->src;\n>>>> +\n>>>> +\t\t/* For now, only supports destination port*/\n>>>> +\t\tfilter->port_type |= I40E_CLOUD_FILTER_PORT_DEST;\n>>>> +\n>>>> +\t\tswitch (filter->ip_proto) {\n>>>> +\t\tcase IPPROTO_TCP:\n>>>> +\t\tcase IPPROTO_UDP:\n>>>> +\t\t\tbreak;\n>>>> +\t\tdefault:\n>>>> +\t\t\tdev_err(&pf->pdev->dev,\n>>>> +\t\t\t\t\"Only UDP and TCP transport are supported\\n\");\n>>>> +\t\t\treturn -EINVAL;\n>>>> +\t\t}\n>>>> +\t}\n>>>> +\tfilter->flags = field_flags;\n>>>> +\treturn 0;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_handle_redirect_action: Forward to a traffic class on the device\n>>>> + * @vsi: Pointer to VSI\n>>>> + * @ifindex: ifindex of the device to forwared to\n>>>> + * @tc: traffic class index on the device\n>>>> + * @filter: Pointer to cloud filter structure\n>>>> + *\n>>>> + **/\n>>>> +static int i40e_handle_redirect_action(struct i40e_vsi *vsi, int ifindex, u8 tc,\n>>>> +\t\t\t\t       struct i40e_cloud_filter *filter)\n>>>> +{\n>>>> +\tstruct i40e_channel *ch, *ch_tmp;\n>>>> +\n>>>> +\t/* redirect to a traffic class on the same device */\n>>>> +\tif (vsi->netdev->ifindex == ifindex) {\n>>>> +\t\tif (tc == 0) {\n>>>> +\t\t\tfilter->seid = vsi->seid;\n>>>> +\t\t\treturn 0;\n>>>> +\t\t} else if (vsi->tc_config.enabled_tc & BIT(tc)) {\n>>>> +\t\t\tif (!filter->dst_port) {\n>>>> +\t\t\t\tdev_err(&vsi->back->pdev->dev,\n>>>> +\t\t\t\t\t\"Specify destination port to redirect to traffic class that is not default\\n\");\n>>>> +\t\t\t\treturn -EINVAL;\n>>>> +\t\t\t}\n>>>> +\t\t\tif (list_empty(&vsi->ch_list))\n>>>> +\t\t\t\treturn -EINVAL;\n>>>> +\t\t\tlist_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list,\n>>>> +\t\t\t\t\t\t list) {\n>>>> +\t\t\t\tif (ch->seid == vsi->tc_seid_map[tc])\n>>>> +\t\t\t\t\tfilter->seid = ch->seid;\n>>>> +\t\t\t}\n>>>> +\t\t\treturn 0;\n>>>> +\t\t}\n>>>> +\t}\n>>>> +\treturn -EINVAL;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_parse_tc_actions - Parse tc actions\n>>>> + * @vsi: Pointer to VSI\n>>>> + * @cls_flower: Pointer to struct tc_cls_flower_offload\n>>>> + * @filter: Pointer to cloud filter structure\n>>>> + *\n>>>> + **/\n>>>> +static int i40e_parse_tc_actions(struct i40e_vsi *vsi, struct tcf_exts *exts,\n>>>> +\t\t\t\t struct i40e_cloud_filter *filter)\n>>>> +{\n>>>> +\tconst struct tc_action *a;\n>>>> +\tLIST_HEAD(actions);\n>>>> +\tint err;\n>>>> +\n>>>> +\tif (!tcf_exts_has_actions(exts))\n>>>> +\t\treturn -EINVAL;\n>>>> +\n>>>> +\ttcf_exts_to_list(exts, &actions);\n>>>> +\tlist_for_each_entry(a, &actions, list) {\n>>>> +\t\t/* Drop action */\n>>>> +\t\tif (is_tcf_gact_shot(a)) {\n>>>> +\t\t\tdev_err(&vsi->back->pdev->dev,\n>>>> +\t\t\t\t\"Cloud filters do not support the drop action.\\n\");\n>>>> +\t\t\treturn -EOPNOTSUPP;\n>>>> +\t\t}\n>>>> +\n>>>> +\t\t/* Redirect to a traffic class on the same device */\n>>>> +\t\tif (!is_tcf_mirred_egress_redirect(a) && is_tcf_mirred_tc(a)) {\n>>>> +\t\t\tint ifindex = tcf_mirred_ifindex(a);\n>>>> +\t\t\tu8 tc = tcf_mirred_tc(a);\n>>>> +\n>>>> +\t\t\terr = i40e_handle_redirect_action(vsi, ifindex, tc,\n>>>> +\t\t\t\t\t\t\t  filter);\n>>>> +\t\t\tif (err == 0)\n>>>> +\t\t\t\treturn err;\n>>>> +\t\t}\n>>>> +\t}\n>>>> +\treturn -EINVAL;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_configure_clsflower - Configure tc flower filters\n>>>> + * @vsi: Pointer to VSI\n>>>> + * @cls_flower: Pointer to struct tc_cls_flower_offload\n>>>> + *\n>>>> + **/\n>>>> +static int i40e_configure_clsflower(struct i40e_vsi *vsi,\n>>>> +\t\t\t\t    struct tc_cls_flower_offload *cls_flower)\n>>>> +{\n>>>> +\tstruct i40e_cloud_filter *filter = NULL;\n>>>> +\tstruct i40e_pf *pf = vsi->back;\n>>>> +\tint err = 0;\n>>>> +\n>>>> +\tif (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state) ||\n>>>> +\t    test_bit(__I40E_RESET_INTR_RECEIVED, pf->state))\n>>>> +\t\treturn -EBUSY;\n>>>> +\n>>>> +\tif (pf->fdir_pf_active_filters ||\n>>>> +\t    (!hlist_empty(&pf->fdir_filter_list))) {\n>>>> +\t\tdev_err(&vsi->back->pdev->dev,\n>>>> +\t\t\t\"Flow Director Sideband filters exists, turn ntuple off to configure cloud filters\\n\");\n>>>> +\t\treturn -EINVAL;\n>>>> +\t}\n>>>> +\n>>>> +\tif (vsi->back->flags & I40E_FLAG_FD_SB_ENABLED) {\n>>>> +\t\tdev_err(&vsi->back->pdev->dev,\n>>>> +\t\t\t\"Disable Flow Director Sideband, configuring Cloud filters via tc-flower\\n\");\n>>>> +\t\tvsi->back->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>>>> +\t\tvsi->back->flags |= I40E_FLAG_FD_SB_TO_CLOUD_FILTER;\n>>>> +\t}\n>>>> +\n>>>> +\tfilter = kzalloc(sizeof(*filter), GFP_KERNEL);\n>>>> +\tif (!filter)\n>>>> +\t\treturn -ENOMEM;\n>>>> +\n>>>> +\tfilter->cookie = cls_flower->cookie;\n>>>> +\n>>>> +\terr = i40e_parse_cls_flower(vsi, cls_flower, filter);\n>>>> +\tif (err < 0)\n>>>> +\t\tgoto err;\n>>>> +\n>>>> +\terr = i40e_parse_tc_actions(vsi, cls_flower->exts, filter);\n>>>> +\tif (err < 0)\n>>>> +\t\tgoto err;\n>>>> +\n>>>> +\t/* Add cloud filter */\n>>>> +\tif (filter->dst_port)\n>>>> +\t\terr = i40e_add_del_cloud_filter_big_buf(vsi, filter, true);\n>>>> +\telse\n>>>> +\t\terr = i40e_add_del_cloud_filter(vsi, filter, true);\n>>>> +\n>>>> +\tif (err) {\n>>>> +\t\tdev_err(&pf->pdev->dev,\n>>>> +\t\t\t\"Failed to add cloud filter, err %s\\n\",\n>>>> +\t\t\ti40e_stat_str(&pf->hw, err));\n>>>> +\t\terr = i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);\n>>>> +\t\tgoto err;\n>>>> +\t}\n>>>> +\n>>>> +\t/* add filter to the ordered list */\n>>>> +\tINIT_HLIST_NODE(&filter->cloud_node);\n>>>> +\n>>>> +\thlist_add_head(&filter->cloud_node, &pf->cloud_filter_list);\n>>>> +\n>>>> +\tpf->num_cloud_filters++;\n>>>> +\n>>>> +\treturn err;\n>>>> +err:\n>>>> +\tkfree(filter);\n>>>> +\treturn err;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_find_cloud_filter - Find the could filter in the list\n>>>> + * @vsi: Pointer to VSI\n>>>> + * @cookie: filter specific cookie\n>>>> + *\n>>>> + **/\n>>>> +static struct i40e_cloud_filter *i40e_find_cloud_filter(struct i40e_vsi *vsi,\n>>>> +\t\t\t\t\t\t\tunsigned long *cookie)\n>>>> +{\n>>>> +\tstruct i40e_cloud_filter *filter = NULL;\n>>>> +\tstruct hlist_node *node2;\n>>>> +\n>>>> +\thlist_for_each_entry_safe(filter, node2,\n>>>> +\t\t\t\t  &vsi->back->cloud_filter_list, cloud_node)\n>>>> +\t\tif (!memcmp(cookie, &filter->cookie, sizeof(filter->cookie)))\n>>>> +\t\t\treturn filter;\n>>>> +\treturn NULL;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_delete_clsflower - Remove tc flower filters\n>>>> + * @vsi: Pointer to VSI\n>>>> + * @cls_flower: Pointer to struct tc_cls_flower_offload\n>>>> + *\n>>>> + **/\n>>>> +static int i40e_delete_clsflower(struct i40e_vsi *vsi,\n>>>> +\t\t\t\t struct tc_cls_flower_offload *cls_flower)\n>>>> +{\n>>>> +\tstruct i40e_cloud_filter *filter = NULL;\n>>>> +\tstruct i40e_pf *pf = vsi->back;\n>>>> +\tint err = 0;\n>>>> +\n>>>> +\tfilter = i40e_find_cloud_filter(vsi, &cls_flower->cookie);\n>>>> +\n>>>> +\tif (!filter)\n>>>> +\t\treturn -EINVAL;\n>>>> +\n>>>> +\thash_del(&filter->cloud_node);\n>>>> +\n>>>> +\tif (filter->dst_port)\n>>>> +\t\terr = i40e_add_del_cloud_filter_big_buf(vsi, filter, false);\n>>>> +\telse\n>>>> +\t\terr = i40e_add_del_cloud_filter(vsi, filter, false);\n>>>> +\tif (err) {\n>>>> +\t\tkfree(filter);\n>>>> +\t\tdev_err(&pf->pdev->dev,\n>>>> +\t\t\t\"Failed to delete cloud filter, err %s\\n\",\n>>>> +\t\t\ti40e_stat_str(&pf->hw, err));\n>>>> +\t\treturn i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);\n>>>> +\t}\n>>>> +\n>>>> +\tkfree(filter);\n>>>> +\tpf->num_cloud_filters--;\n>>>> +\n>>>> +\tif (!pf->num_cloud_filters)\n>>>> +\t\tif ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&\n>>>> +\t\t    !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {\n>>>> +\t\t\tpf->flags |= I40E_FLAG_FD_SB_ENABLED;\n>>>> +\t\t\tpf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;\n>>>> +\t\t\tpf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;\n>>>> +\t\t}\n>>>> +\treturn 0;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>> + * i40e_setup_tc_cls_flower - flower classifier offloads\n>>>> + * @netdev: net device to configure\n>>>> + * @type_data: offload data\n>>>> + **/\n>>>> +static int i40e_setup_tc_cls_flower(struct net_device *netdev,\n>>>> +\t\t\t\t    struct tc_cls_flower_offload *cls_flower)\n>>>> +{\n>>>> +\tstruct i40e_netdev_priv *np = netdev_priv(netdev);\n>>>> +\tstruct i40e_vsi *vsi = np->vsi;\n>>>> +\n>>>> +\tif (!is_classid_clsact_ingress(cls_flower->common.classid) ||\n>>>> +\t    cls_flower->common.chain_index)\n>>>> +\t\treturn -EOPNOTSUPP;\n>>>> +\n>>>> +\tswitch (cls_flower->command) {\n>>>> +\tcase TC_CLSFLOWER_REPLACE:\n>>>> +\t\treturn i40e_configure_clsflower(vsi, cls_flower);\n>>>> +\tcase TC_CLSFLOWER_DESTROY:\n>>>> +\t\treturn i40e_delete_clsflower(vsi, cls_flower);\n>>>> +\tcase TC_CLSFLOWER_STATS:\n>>>> +\t\treturn -EOPNOTSUPP;\n>>>> +\tdefault:\n>>>> +\t\treturn -EINVAL;\n>>>> +\t}\n>>>> +}\n>>>> +\n>>>> static int __i40e_setup_tc(struct net_device *netdev, enum tc_setup_type type,\n>>>> \t\t\t   void *type_data)\n>>>> {\n>>>> -\tif (type != TC_SETUP_MQPRIO)\n>>>> +\tswitch (type) {\n>>>> +\tcase TC_SETUP_MQPRIO:\n>>>> +\t\treturn i40e_setup_tc(netdev, type_data);\n>>>> +\tcase TC_SETUP_CLSFLOWER:\n>>>> +\t\treturn i40e_setup_tc_cls_flower(netdev, type_data);\n>>>> +\tdefault:\n>>>> \t\treturn -EOPNOTSUPP;\n>>>> -\n>>>> -\treturn i40e_setup_tc(netdev, type_data);\n>>>> +\t}\n>>>> }\n>>>>\n>>>> /**\n>>>> @@ -6939,6 +7756,13 @@ static void i40e_cloud_filter_exit(struct i40e_pf *pf)\n>>>> \t\tkfree(cfilter);\n>>>> \t}\n>>>> \tpf->num_cloud_filters = 0;\n>>>> +\n>>>> +\tif ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&\n>>>> +\t    !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {\n>>>> +\t\tpf->flags |= I40E_FLAG_FD_SB_ENABLED;\n>>>> +\t\tpf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;\n>>>> +\t\tpf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;\n>>>> +\t}\n>>>> }\n>>>>\n>>>> /**\n>>>> @@ -8046,7 +8870,8 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb)\n>>>>  * i40e_get_capabilities - get info about the HW\n>>>>  * @pf: the PF struct\n>>>>  **/\n>>>> -static int i40e_get_capabilities(struct i40e_pf *pf)\n>>>> +static int i40e_get_capabilities(struct i40e_pf *pf,\n>>>> +\t\t\t\t enum i40e_admin_queue_opc list_type)\n>>>> {\n>>>> \tstruct i40e_aqc_list_capabilities_element_resp *cap_buf;\n>>>> \tu16 data_size;\n>>>> @@ -8061,9 +8886,8 @@ static int i40e_get_capabilities(struct i40e_pf *pf)\n>>>>\n>>>> \t\t/* this loads the data into the hw struct for us */\n>>>> \t\terr = i40e_aq_discover_capabilities(&pf->hw, cap_buf, buf_len,\n>>>> -\t\t\t\t\t    &data_size,\n>>>> -\t\t\t\t\t    i40e_aqc_opc_list_func_capabilities,\n>>>> -\t\t\t\t\t    NULL);\n>>>> +\t\t\t\t\t\t    &data_size, list_type,\n>>>> +\t\t\t\t\t\t    NULL);\n>>>> \t\t/* data loaded, buffer no longer needed */\n>>>> \t\tkfree(cap_buf);\n>>>>\n>>>> @@ -8080,26 +8904,44 @@ static int i40e_get_capabilities(struct i40e_pf *pf)\n>>>> \t\t}\n>>>> \t} while (err);\n>>>>\n>>>> -\tif (pf->hw.debug_mask & I40E_DEBUG_USER)\n>>>> -\t\tdev_info(&pf->pdev->dev,\n>>>> -\t\t\t \"pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\\n\",\n>>>> -\t\t\t pf->hw.pf_id, pf->hw.func_caps.num_vfs,\n>>>> -\t\t\t pf->hw.func_caps.num_msix_vectors,\n>>>> -\t\t\t pf->hw.func_caps.num_msix_vectors_vf,\n>>>> -\t\t\t pf->hw.func_caps.fd_filters_guaranteed,\n>>>> -\t\t\t pf->hw.func_caps.fd_filters_best_effort,\n>>>> -\t\t\t pf->hw.func_caps.num_tx_qp,\n>>>> -\t\t\t pf->hw.func_caps.num_vsis);\n>>>> -\n>>>> +\tif (pf->hw.debug_mask & I40E_DEBUG_USER) {\n>>>> +\t\tif (list_type == i40e_aqc_opc_list_func_capabilities) {\n>>>> +\t\t\tdev_info(&pf->pdev->dev,\n>>>> +\t\t\t\t \"pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\\n\",\n>>>> +\t\t\t\t pf->hw.pf_id, pf->hw.func_caps.num_vfs,\n>>>> +\t\t\t\t pf->hw.func_caps.num_msix_vectors,\n>>>> +\t\t\t\t pf->hw.func_caps.num_msix_vectors_vf,\n>>>> +\t\t\t\t pf->hw.func_caps.fd_filters_guaranteed,\n>>>> +\t\t\t\t pf->hw.func_caps.fd_filters_best_effort,\n>>>> +\t\t\t\t pf->hw.func_caps.num_tx_qp,\n>>>> +\t\t\t\t pf->hw.func_caps.num_vsis);\n>>>> +\t\t} else if (list_type == i40e_aqc_opc_list_dev_capabilities) {\n>>>> +\t\t\tdev_info(&pf->pdev->dev,\n>>>> +\t\t\t\t \"switch_mode=0x%04x, function_valid=0x%08x\\n\",\n>>>> +\t\t\t\t pf->hw.dev_caps.switch_mode,\n>>>> +\t\t\t\t pf->hw.dev_caps.valid_functions);\n>>>> +\t\t\tdev_info(&pf->pdev->dev,\n>>>> +\t\t\t\t \"SR-IOV=%d, num_vfs for all function=%u\\n\",\n>>>> +\t\t\t\t pf->hw.dev_caps.sr_iov_1_1,\n>>>> +\t\t\t\t pf->hw.dev_caps.num_vfs);\n>>>> +\t\t\tdev_info(&pf->pdev->dev,\n>>>> +\t\t\t\t \"num_vsis=%u, num_rx:%u, num_tx=%u\\n\",\n>>>> +\t\t\t\t pf->hw.dev_caps.num_vsis,\n>>>> +\t\t\t\t pf->hw.dev_caps.num_rx_qp,\n>>>> +\t\t\t\t pf->hw.dev_caps.num_tx_qp);\n>>>> +\t\t}\n>>>> +\t}\n>>>> +\tif (list_type == i40e_aqc_opc_list_func_capabilities) {\n>>>> #define DEF_NUM_VSI (1 + (pf->hw.func_caps.fcoe ? 1 : 0) \\\n>>>> \t\t       + pf->hw.func_caps.num_vfs)\n>>>> -\tif (pf->hw.revision_id == 0 && (DEF_NUM_VSI > pf->hw.func_caps.num_vsis)) {\n>>>> -\t\tdev_info(&pf->pdev->dev,\n>>>> -\t\t\t \"got num_vsis %d, setting num_vsis to %d\\n\",\n>>>> -\t\t\t pf->hw.func_caps.num_vsis, DEF_NUM_VSI);\n>>>> -\t\tpf->hw.func_caps.num_vsis = DEF_NUM_VSI;\n>>>> +\t\tif (pf->hw.revision_id == 0 &&\n>>>> +\t\t    (pf->hw.func_caps.num_vsis < DEF_NUM_VSI)) {\n>>>> +\t\t\tdev_info(&pf->pdev->dev,\n>>>> +\t\t\t\t \"got num_vsis %d, setting num_vsis to %d\\n\",\n>>>> +\t\t\t\t pf->hw.func_caps.num_vsis, DEF_NUM_VSI);\n>>>> +\t\t\tpf->hw.func_caps.num_vsis = DEF_NUM_VSI;\n>>>> +\t\t}\n>>>> \t}\n>>>> -\n>>>> \treturn 0;\n>>>> }\n>>>>\n>>>> @@ -8141,6 +8983,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)\n>>>> \t\tif (!vsi) {\n>>>> \t\t\tdev_info(&pf->pdev->dev, \"Couldn't create FDir VSI\\n\");\n>>>> \t\t\tpf->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>>>> +\t\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>>> \t\t\treturn;\n>>>> \t\t}\n>>>> \t}\n>>>> @@ -8163,6 +9006,48 @@ static void i40e_fdir_teardown(struct i40e_pf *pf)\n>>>> }\n>>>>\n>>>> /**\n>>>> + * i40e_rebuild_cloud_filters - Rebuilds cloud filters for VSIs\n>>>> + * @vsi: PF main vsi\n>>>> + * @seid: seid of main or channel VSIs\n>>>> + *\n>>>> + * Rebuilds cloud filters associated with main VSI and channel VSIs if they\n>>>> + * existed before reset\n>>>> + **/\n>>>> +static int i40e_rebuild_cloud_filters(struct i40e_vsi *vsi, u16 seid)\n>>>> +{\n>>>> +\tstruct i40e_cloud_filter *cfilter;\n>>>> +\tstruct i40e_pf *pf = vsi->back;\n>>>> +\tstruct hlist_node *node;\n>>>> +\ti40e_status ret;\n>>>> +\n>>>> +\t/* Add cloud filters back if they exist */\n>>>> +\tif (hlist_empty(&pf->cloud_filter_list))\n>>>> +\t\treturn 0;\n>>>> +\n>>>> +\thlist_for_each_entry_safe(cfilter, node, &pf->cloud_filter_list,\n>>>> +\t\t\t\t  cloud_node) {\n>>>> +\t\tif (cfilter->seid != seid)\n>>>> +\t\t\tcontinue;\n>>>> +\n>>>> +\t\tif (cfilter->dst_port)\n>>>> +\t\t\tret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter,\n>>>> +\t\t\t\t\t\t\t\ttrue);\n>>>> +\t\telse\n>>>> +\t\t\tret = i40e_add_del_cloud_filter(vsi, cfilter, true);\n>>>> +\n>>>> +\t\tif (ret) {\n>>>> +\t\t\tdev_dbg(&pf->pdev->dev,\n>>>> +\t\t\t\t\"Failed to rebuild cloud filter, err %s aq_err %s\\n\",\n>>>> +\t\t\t\ti40e_stat_str(&pf->hw, ret),\n>>>> +\t\t\t\ti40e_aq_str(&pf->hw,\n>>>> +\t\t\t\t\t    pf->hw.aq.asq_last_status));\n>>>> +\t\t\treturn ret;\n>>>> +\t\t}\n>>>> +\t}\n>>>> +\treturn 0;\n>>>> +}\n>>>> +\n>>>> +/**\n>>>>  * i40e_rebuild_channels - Rebuilds channel VSIs if they existed before reset\n>>>>  * @vsi: PF main vsi\n>>>>  *\n>>>> @@ -8199,6 +9084,13 @@ static int i40e_rebuild_channels(struct i40e_vsi *vsi)\n>>>> \t\t\t\t\t\tI40E_BW_CREDIT_DIVISOR,\n>>>> \t\t\t\tch->seid);\n>>>> \t\t}\n>>>> +\t\tret = i40e_rebuild_cloud_filters(vsi, ch->seid);\n>>>> +\t\tif (ret) {\n>>>> +\t\t\tdev_dbg(&vsi->back->pdev->dev,\n>>>> +\t\t\t\t\"Failed to rebuild cloud filters for channel VSI %u\\n\",\n>>>> +\t\t\t\tch->seid);\n>>>> +\t\t\treturn ret;\n>>>> +\t\t}\n>>>> \t}\n>>>> \treturn 0;\n>>>> }\n>>>> @@ -8365,7 +9257,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)\n>>>> \t\ti40e_verify_eeprom(pf);\n>>>>\n>>>> \ti40e_clear_pxe_mode(hw);\n>>>> -\tret = i40e_get_capabilities(pf);\n>>>> +\tret = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);\n>>>> \tif (ret)\n>>>> \t\tgoto end_core_reset;\n>>>>\n>>>> @@ -8482,6 +9374,10 @@ static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool lock_acquired)\n>>>> \t\t\tgoto end_unlock;\n>>>> \t}\n>>>>\n>>>> +\tret = i40e_rebuild_cloud_filters(vsi, vsi->seid);\n>>>> +\tif (ret)\n>>>> +\t\tgoto end_unlock;\n>>>> +\n>>>> \t/* PF Main VSI is rebuild by now, go ahead and rebuild channel VSIs\n>>>> \t * for this main VSI if they exist\n>>>> \t */\n>>>> @@ -9404,6 +10300,7 @@ static int i40e_init_msix(struct i40e_pf *pf)\n>>>> \t    (pf->num_fdsb_msix == 0)) {\n>>>> \t\tdev_info(&pf->pdev->dev, \"Sideband Flowdir disabled, not enough MSI-X vectors\\n\");\n>>>> \t\tpf->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>>>> +\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>>> \t}\n>>>> \tif ((pf->flags & I40E_FLAG_VMDQ_ENABLED) &&\n>>>> \t    (pf->num_vmdq_msix == 0)) {\n>>>> @@ -9521,6 +10418,7 @@ static int i40e_init_interrupt_scheme(struct i40e_pf *pf)\n>>>> \t\t\t\t       I40E_FLAG_FD_SB_ENABLED\t|\n>>>> \t\t\t\t       I40E_FLAG_FD_ATR_ENABLED\t|\n>>>> \t\t\t\t       I40E_FLAG_VMDQ_ENABLED);\n>>>> +\t\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>>>\n>>>> \t\t\t/* rework the queue expectations without MSIX */\n>>>> \t\t\ti40e_determine_queue_usage(pf);\n>>>> @@ -10263,9 +11161,13 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)\n>>>> \t\t/* Enable filters and mark for reset */\n>>>> \t\tif (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))\n>>>> \t\t\tneed_reset = true;\n>>>> -\t\t/* enable FD_SB only if there is MSI-X vector */\n>>>> -\t\tif (pf->num_fdsb_msix > 0)\n>>>> +\t\t/* enable FD_SB only if there is MSI-X vector and no cloud\n>>>> +\t\t * filters exist\n>>>> +\t\t */\n>>>> +\t\tif (pf->num_fdsb_msix > 0 && !pf->num_cloud_filters) {\n>>>> \t\t\tpf->flags |= I40E_FLAG_FD_SB_ENABLED;\n>>>> +\t\t\tpf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;\n>>>> +\t\t}\n>>>> \t} else {\n>>>> \t\t/* turn off filters, mark for reset and clear SW filter list */\n>>>> \t\tif (pf->flags & I40E_FLAG_FD_SB_ENABLED) {\n>>>> @@ -10274,6 +11176,8 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)\n>>>> \t\t}\n>>>> \t\tpf->flags &= ~(I40E_FLAG_FD_SB_ENABLED |\n>>>> \t\t\t       I40E_FLAG_FD_SB_AUTO_DISABLED);\n>>>> +\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>>> +\n>>>> \t\t/* reset fd counters */\n>>>> \t\tpf->fd_add_err = 0;\n>>>> \t\tpf->fd_atr_cnt = 0;\n>>>> @@ -10857,7 +11761,8 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)\n>>>> \t\tnetdev->hw_features |= NETIF_F_NTUPLE;\n>>>> \thw_features = hw_enc_features\t\t|\n>>>> \t\t      NETIF_F_HW_VLAN_CTAG_TX\t|\n>>>> -\t\t      NETIF_F_HW_VLAN_CTAG_RX;\n>>>> +\t\t      NETIF_F_HW_VLAN_CTAG_RX\t|\n>>>> +\t\t      NETIF_F_HW_TC;\n>>>>\n>>>> \tnetdev->hw_features |= hw_features;\n>>>>\n>>>> @@ -12159,8 +13064,10 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)\n>>>> \t*/\n>>>>\n>>>> \tif ((pf->hw.pf_id == 0) &&\n>>>> -\t    !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT))\n>>>> +\t    !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT)) {\n>>>> \t\tflags = I40E_AQ_SET_SWITCH_CFG_PROMISC;\n>>>> +\t\tpf->last_sw_conf_flags = flags;\n>>>> +\t}\n>>>>\n>>>> \tif (pf->hw.pf_id == 0) {\n>>>> \t\tu16 valid_flags;\n>>>> @@ -12176,6 +13083,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)\n>>>> \t\t\t\t\t     pf->hw.aq.asq_last_status));\n>>>> \t\t\t/* not a fatal problem, just keep going */\n>>>> \t\t}\n>>>> +\t\tpf->last_sw_conf_valid_flags = valid_flags;\n>>>> \t}\n>>>>\n>>>> \t/* first time setup */\n>>>> @@ -12273,6 +13181,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)\n>>>> \t\t\t       I40E_FLAG_DCB_ENABLED\t|\n>>>> \t\t\t       I40E_FLAG_SRIOV_ENABLED\t|\n>>>> \t\t\t       I40E_FLAG_VMDQ_ENABLED);\n>>>> +\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>>> \t} else if (!(pf->flags & (I40E_FLAG_RSS_ENABLED |\n>>>> \t\t\t\t  I40E_FLAG_FD_SB_ENABLED |\n>>>> \t\t\t\t  I40E_FLAG_FD_ATR_ENABLED |\n>>>> @@ -12287,6 +13196,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)\n>>>> \t\t\t       I40E_FLAG_FD_ATR_ENABLED\t|\n>>>> \t\t\t       I40E_FLAG_DCB_ENABLED\t|\n>>>> \t\t\t       I40E_FLAG_VMDQ_ENABLED);\n>>>> +\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>>> \t} else {\n>>>> \t\t/* Not enough queues for all TCs */\n>>>> \t\tif ((pf->flags & I40E_FLAG_DCB_CAPABLE) &&\n>>>> @@ -12310,6 +13220,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)\n>>>> \t\t\tqueues_left -= 1; /* save 1 queue for FD */\n>>>> \t\t} else {\n>>>> \t\t\tpf->flags &= ~I40E_FLAG_FD_SB_ENABLED;\n>>>> +\t\t\tpf->flags |= I40E_FLAG_FD_SB_INACTIVE;\n>>>> \t\t\tdev_info(&pf->pdev->dev, \"not enough queues for Flow Director. Flow Director feature is disabled\\n\");\n>>>> \t\t}\n>>>> \t}\n>>>> @@ -12613,7 +13524,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)\n>>>> \t\tdev_warn(&pdev->dev, \"This device is a pre-production adapter/LOM. Please be aware there may be issues with your hardware. If you are experiencing problems please contact your Intel or hardware representative who provided you with this hardware.\\n\");\n>>>>\n>>>> \ti40e_clear_pxe_mode(hw);\n>>>> -\terr = i40e_get_capabilities(pf);\n>>>> +\terr = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);\n>>>> \tif (err)\n>>>> \t\tgoto err_adminq_setup;\n>>>>\n>>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n>>>> index 92869f5..3bb6659 100644\n>>>> --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n>>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h\n>>>> @@ -283,6 +283,22 @@ i40e_status i40e_aq_query_switch_comp_bw_config(struct i40e_hw *hw,\n>>>> \t\tstruct i40e_asq_cmd_details *cmd_details);\n>>>> i40e_status i40e_aq_resume_port_tx(struct i40e_hw *hw,\n>>>> \t\t\t\t   struct i40e_asq_cmd_details *cmd_details);\n>>>> +i40e_status\n>>>> +i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>>>> +\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>>>> +\t\t\t     u8 filter_count);\n>>>> +enum i40e_status_code\n>>>> +i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 vsi,\n>>>> +\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>>>> +\t\t\t  u8 filter_count);\n>>>> +enum i40e_status_code\n>>>> +i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 vsi,\n>>>> +\t\t\t  struct i40e_aqc_cloud_filters_element_data *filters,\n>>>> +\t\t\t  u8 filter_count);\n>>>> +i40e_status\n>>>> +i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,\n>>>> +\t\t\t     struct i40e_aqc_cloud_filters_element_bb *filters,\n>>>> +\t\t\t     u8 filter_count);\n>>>> i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,\n>>>> \t\t\t       struct i40e_lldp_variables *lldp_cfg);\n>>>> /* i40e_common */\n>>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h\n>>>> index c019f46..af38881 100644\n>>>> --- a/drivers/net/ethernet/intel/i40e/i40e_type.h\n>>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h\n>>>> @@ -287,6 +287,7 @@ struct i40e_hw_capabilities {\n>>>> #define I40E_NVM_IMAGE_TYPE_MODE1\t0x6\n>>>> #define I40E_NVM_IMAGE_TYPE_MODE2\t0x7\n>>>> #define I40E_NVM_IMAGE_TYPE_MODE3\t0x8\n>>>> +#define I40E_SWITCH_MODE_MASK\t\t0xF\n>>>>\n>>>> \tu32  management_mode;\n>>>> \tu32  mng_protocols_over_mctp;\n>>>> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h\n>>>> index b8c78bf..4fe27f0 100644\n>>>> --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h\n>>>> +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h\n>>>> @@ -1360,6 +1360,9 @@ struct i40e_aqc_cloud_filters_element_data {\n>>>> \t\tstruct {\n>>>> \t\t\tu8 data[16];\n>>>> \t\t} v6;\n>>>> +\t\tstruct {\n>>>> +\t\t\t__le16 data[8];\n>>>> +\t\t} raw_v6;\n>>>> \t} ipaddr;\n>>>> \t__le16\tflags;\n>>>> #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT\t\t\t0\n>>>>","headers":{"Return-Path":"<intel-wired-lan-bounces@osuosl.org>","X-Original-To":["incoming@patchwork.ozlabs.org","intel-wired-lan@lists.osuosl.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","intel-wired-lan@lists.osuosl.org"],"Authentication-Results":["ozlabs.org;\n\tspf=pass (mailfrom) smtp.mailfrom=osuosl.org\n\t(client-ip=140.211.166.138; helo=whitealder.osuosl.org;\n\tenvelope-from=intel-wired-lan-bounces@osuosl.org;\n\treceiver=<UNKNOWN>)","ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (2048-bit key;\n\tunprotected) header.d=resnulli-us.20150623.gappssmtp.com\n\theader.i=@resnulli-us.20150623.gappssmtp.com\n\theader.b=\"aXUo0Btn\"; dkim-atps=neutral"],"Received":["from whitealder.osuosl.org (smtp1.osuosl.org [140.211.166.138])\n\t(using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3y3cpJ46Jkz9sRW\n\tfor <incoming@patchwork.ozlabs.org>;\n\tSat, 30 Sep 2017 02:44:08 +1000 (AEST)","from localhost (localhost [127.0.0.1])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id ADD9389B35;\n\tFri, 29 Sep 2017 16:44:06 +0000 (UTC)","from whitealder.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id aohea1XL5dxn; Fri, 29 Sep 2017 16:44:00 +0000 (UTC)","from ash.osuosl.org (ash.osuosl.org [140.211.166.34])\n\tby whitealder.osuosl.org (Postfix) with ESMTP id 1F7D089B34;\n\tFri, 29 Sep 2017 16:44:00 +0000 (UTC)","from fraxinus.osuosl.org (smtp4.osuosl.org [140.211.166.137])\n\tby ash.osuosl.org (Postfix) with ESMTP id A12791C25D4\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tFri, 29 Sep 2017 06:20:43 +0000 (UTC)","from localhost (localhost [127.0.0.1])\n\tby fraxinus.osuosl.org (Postfix) with ESMTP id 99A1B847B1\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tFri, 29 Sep 2017 06:20:43 +0000 (UTC)","from fraxinus.osuosl.org ([127.0.0.1])\n\tby localhost (.osuosl.org [127.0.0.1]) (amavisd-new, port 10024)\n\twith ESMTP id 7mBSoYjgyHFs for <intel-wired-lan@lists.osuosl.org>;\n\tFri, 29 Sep 2017 06:20:40 +0000 (UTC)","from mail-wr0-f196.google.com (mail-wr0-f196.google.com\n\t[209.85.128.196])\n\tby fraxinus.osuosl.org (Postfix) with ESMTPS id EC63A84620\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tFri, 29 Sep 2017 06:20:39 +0000 (UTC)","by mail-wr0-f196.google.com with SMTP id 45so376305wry.5\n\tfor <intel-wired-lan@lists.osuosl.org>;\n\tThu, 28 Sep 2017 23:20:39 -0700 (PDT)","from localhost (jirka.pirko.cz. [84.16.102.26])\n\tby smtp.gmail.com with ESMTPSA id\n\tc56sm3767683wrc.1.2017.09.28.23.20.36\n\t(version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256);\n\tThu, 28 Sep 2017 23:20:36 -0700 (PDT)"],"X-Virus-Scanned":["amavisd-new at osuosl.org","amavisd-new at osuosl.org"],"X-Greylist":"from auto-whitelisted by SQLgrey-1.7.6","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=resnulli-us.20150623.gappssmtp.com; s=20150623;\n\th=date:from:to:cc:subject:message-id:references:mime-version\n\t:content-disposition:in-reply-to:user-agent;\n\tbh=Mj/C620cTgpPesbPfSSgrCJlFZty27inuUsKXkOZB0s=;\n\tb=aXUo0BtnanDo9LsrlR059lJIVBKnTOgAjlf/41QJLg5dzMAFVzw8jYRzbgi+cq2mA6\n\tF2OAidIQn+AFVagt5PuyXf8aHvsd+wuV5nJtcM1ImM+vp/ENi3mS4BGhmgEZ9fvTfoqL\n\tjvCm0H2De+tICMQUp7QUY4EIUVElfEM8Lyb2xeOc+z8lzfbYNjdPjucjjQppBbG95dXN\n\tj+XK2S0nALwpiZkcLjCBPS+MZoe4hFDGQ0lTQ8HX+bFBN8oNsmQFXaE+QB4r9ZOldOh4\n\tWe/uGvrkMOlcRWYMyy6a9nNgMo51NqCVLBp0noIBtft4Ch0tMr2PKDhwOrRHayo7jGP9\n\tZ4YQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n\td=1e100.net; s=20161025;\n\th=x-gm-message-state:date:from:to:cc:subject:message-id:references\n\t:mime-version:content-disposition:in-reply-to:user-agent;\n\tbh=Mj/C620cTgpPesbPfSSgrCJlFZty27inuUsKXkOZB0s=;\n\tb=pvKMAGGib42bNqoibeMZ9F3mDhuhqlKxm7yGFxOECaeRm65dXlNBr6KYtM1fhTa3/l\n\tpUNBvOah09VIynJDH8Axkzq8x3VsX9GIYbEpD7gjhWFHP6uyJH8SmiWFCwh9kRbDDAjO\n\tASBCdmAhBy8iJIngtOkjof7rIV75wiDsnoP/P6g8Boxk37HEW+P5TeR73amlyW1L/y2w\n\taf9TLOsEEV3NT7VMRHNsVk4ZB9zmIZ0W+CrPvRcGdZdBLA9f8kUedFmPTmhpcAVe9oez\n\t47NxmRTdWzlVefp9Tkc1dZ8ONouGArBAvEBdKpHmvRa0zKZE3giZtIqgcvWqkB8f8HlO\n\tI3ZA==","X-Gm-Message-State":"AHPjjUgCiW+atqO3lTwRWTZJefyNdQgeiO+r71+JgVaE1MtfXH5bBBzl\n\tkpcEcDDRY+5MPw6tdSUyJX50sw==","X-Google-Smtp-Source":"AOwi7QBfVSYkGPLrI8jTJKpAo+U8gyRcWwY3IXciVfNaD2rEc8f9YmH71oNFohvvHMWyNRo+19tibQ==","X-Received":"by 10.223.197.72 with SMTP id s8mr7325649wrf.120.1506666036955; \n\tThu, 28 Sep 2017 23:20:36 -0700 (PDT)","Date":"Fri, 29 Sep 2017 08:20:35 +0200","From":"Jiri Pirko <jiri@resnulli.us>","To":"\"Nambiar, Amritha\" <amritha.nambiar@intel.com>","Message-ID":"<20170929062035.GB1867@nanopsycho>","References":"<150529632024.57063.15338545678487601430.stgit@anamdev.jf.intel.com>\n\t<150529679050.57063.3956015681929450874.stgit@anamdev.jf.intel.com>\n\t<20170913132611.GC1981@nanopsycho>\n\t<82e0a065-c7d6-8fe6-aedc-154dd0dd88d6@intel.com>\n\t<dd18a4bd-f2fc-002b-2ef9-01de9a5a4162@intel.com>","MIME-Version":"1.0","Content-Disposition":"inline","In-Reply-To":"<dd18a4bd-f2fc-002b-2ef9-01de9a5a4162@intel.com>","User-Agent":"Mutt/1.8.3 (2017-05-23)","X-Mailman-Approved-At":"Fri, 29 Sep 2017 16:43:58 +0000","Cc":"mlxsw@mellanox.com, netdev@vger.kernel.org,\n\tJamal Hadi Salim <jhs@mojatatu.com>, intel-wired-lan@lists.osuosl.org,\n\tCong Wang <xiyou.wangcong@gmail.com>","Subject":"Re: [Intel-wired-lan] [RFC PATCH v3 7/7] i40e: Enable cloud filters\n\tvia tc-flower","X-BeenThere":"intel-wired-lan@osuosl.org","X-Mailman-Version":"2.1.18-1","Precedence":"list","List-Id":"Intel Wired Ethernet Linux Kernel Driver Development\n\t<intel-wired-lan.osuosl.org>","List-Unsubscribe":"<https://lists.osuosl.org/mailman/options/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=unsubscribe>","List-Archive":"<http://lists.osuosl.org/pipermail/intel-wired-lan/>","List-Post":"<mailto:intel-wired-lan@osuosl.org>","List-Help":"<mailto:intel-wired-lan-request@osuosl.org?subject=help>","List-Subscribe":"<https://lists.osuosl.org/mailman/listinfo/intel-wired-lan>, \n\t<mailto:intel-wired-lan-request@osuosl.org?subject=subscribe>","Content-Type":"text/plain; charset=\"us-ascii\"","Content-Transfer-Encoding":"7bit","Errors-To":"intel-wired-lan-bounces@osuosl.org","Sender":"\"Intel-wired-lan\" <intel-wired-lan-bounces@osuosl.org>"}}]