Thu, Sep 28, 2017 at 09:22:15PM CEST, amritha.namb...@intel.com wrote:
>On 9/14/2017 1:00 AM, Nambiar, Amritha wrote:
>> On 9/13/2017 6:26 AM, Jiri Pirko wrote:
>>> Wed, Sep 13, 2017 at 11:59:50AM CEST, amritha.namb...@intel.com wrote:
>>>> This patch enables tc-flower based hardware offloads. tc flower
>>>> filter provided by the kernel is configured as driver specific
>>>> cloud filter. The patch implements functions and admin queue
>>>> commands needed to support cloud filters in the driver and
>>>> adds cloud filters to configure these tc-flower filters.
>>>>
>>>> The only action supported is to redirect packets to a traffic class
>>>> on the same device.
>>>
>>> So basically you are not doing redirect, you are just setting tclass for
>>> matched packets, right? Why you use mirred for this? I think that
>>> you might consider extending g_act for that:
>>>
>>> # tc filter add dev eth0 protocol ip ingress \
>>>   prio 1 flower dst_mac 3c:fd:fe:a0:d6:70 skip_sw \
>>>   action tclass 0
>>>
>> Yes, this doesn't work like a typical egress redirect, but is aimed at
>> forwarding the matched packets to a different queue-group/traffic class
>> on the same device, so some sort-of ingress redirect in the hardware. I
>> possibly may not need the mirred-redirect as you say, I'll look into the
>> g_act way of doing this with a new gact tc action.
>> 
>
>I was looking at introducing a new gact tclass action to TC. In the HW
>offload path, this sets a traffic class value for certain matched
>packets so they will be processed in a queue belonging to the traffic class.
>
># tc filter add dev eth0 protocol ip parent ffff:\
>  prio 2 flower dst_ip 192.168.3.5/32\
>  ip_proto udp dst_port 25 skip_sw\
>  action tclass 2
>
>But, I'm having trouble defining what this action means in the kernel
>datapath. For ingress, this action could just take the default path and
>do nothing and only have meaning in the HW offloaded path. For egress,

Sounds ok.


>certain qdiscs like 'multiq' and 'prio' could use this 'tclass' value
>for band selection, while the 'mqprio' qdisc selects the traffic class
>based on the skb priority in netdev_pick_tx(), so what would this action
>mean for the 'mqprio' qdisc?

I don't see why this action would have any special meaning for specific
qdiscs. The qdiscs have already mechanisms for band mapping. I don't see
why to mix it up with tclass action.

Also, you can use tclass action on qdisc clsact egress to do band
mapping. That would be symmetrical with ingress.


>
>It looks like the 'prio' qdisc uses band selection based on the
>'classid', so I was thinking of using the 'classid' through the cls
>flower filter and offload it to HW for the traffic class index, this way
>we would have the same behavior in HW offload and SW fallback and there
>would be no need for a separate tc action.
>
>In HW:
># tc filter add dev eth0 protocol ip parent ffff:\
>  prio 2 flower dst_ip 192.168.3.5/32\
>  ip_proto udp dst_port 25 skip_sw classid 1:2\
>
>filter pref 2 flower chain 0
>filter pref 2 flower chain 0 handle 0x1 classid 1:2
>  eth_type ipv4
>  ip_proto udp
>  dst_ip 192.168.3.5
>  dst_port 25
>  skip_sw
>  in_hw
>
>This will be used to route packets to traffic class 2.
>
>In SW:
># tc filter add dev eth0 protocol ip parent ffff:\
>  prio 2 flower dst_ip 192.168.3.5/32\
>  ip_proto udp dst_port 25 skip_hw classid 1:2
>
>filter pref 2 flower chain 0
>filter pref 2 flower chain 0 handle 0x1 classid 1:2
>  eth_type ipv4
>  ip_proto udp
>  dst_ip 192.168.3.5
>  dst_port 25
>  skip_hw
>  not_in_hw
>
>>>
>>>>
>>>> # tc qdisc add dev eth0 ingress
>>>> # ethtool -K eth0 hw-tc-offload on
>>>>
>>>> # tc filter add dev eth0 protocol ip parent ffff:\
>>>>  prio 1 flower dst_mac 3c:fd:fe:a0:d6:70 skip_sw\
>>>>  action mirred ingress redirect dev eth0 tclass 0
>>>>
>>>> # tc filter add dev eth0 protocol ip parent ffff:\
>>>>  prio 2 flower dst_ip 192.168.3.5/32\
>>>>  ip_proto udp dst_port 25 skip_sw\
>>>>  action mirred ingress redirect dev eth0 tclass 1
>>>>
>>>> # tc filter add dev eth0 protocol ipv6 parent ffff:\
>>>>  prio 3 flower dst_ip fe8::200:1\
>>>>  ip_proto udp dst_port 66 skip_sw\
>>>>  action mirred ingress redirect dev eth0 tclass 1
>>>>
>>>> Delete tc flower filter:
>>>> Example:
>>>>
>>>> # tc filter del dev eth0 parent ffff: prio 3 handle 0x1 flower
>>>> # tc filter del dev eth0 parent ffff:
>>>>
>>>> Flow Director Sideband is disabled while configuring cloud filters
>>>> via tc-flower and until any cloud filter exists.
>>>>
>>>> Unsupported matches when cloud filters are added using enhanced
>>>> big buffer cloud filter mode of underlying switch include:
>>>> 1. source port and source IP
>>>> 2. Combined MAC address and IP fields.
>>>> 3. Not specifying L4 port
>>>>
>>>> These filter matches can however be used to redirect traffic to
>>>> the main VSI (tc 0) which does not require the enhanced big buffer
>>>> cloud filter support.
>>>>
>>>> v3: Cleaned up some lengthy function names. Changed ipv6 address to
>>>> __be32 array instead of u8 array. Used macro for IP version. Minor
>>>> formatting changes.
>>>> v2:
>>>> 1. Moved I40E_SWITCH_MODE_MASK definition to i40e_type.h
>>>> 2. Moved dev_info for add/deleting cloud filters in else condition
>>>> 3. Fixed some format specifier in dev_err logs
>>>> 4. Refactored i40e_get_capabilities to take an additional
>>>>   list_type parameter and use it to query device and function
>>>>   level capabilities.
>>>> 5. Fixed parsing tc redirect action to check for the is_tcf_mirred_tc()
>>>>   to verify if redirect to a traffic class is supported.
>>>> 6. Added comments for Geneve fix in cloud filter big buffer AQ
>>>>   function definitions.
>>>> 7. Cleaned up setup_tc interface to rebase and work with Jiri's
>>>>   updates, separate function to process tc cls flower offloads.
>>>> 8. Changes to make Flow Director Sideband and Cloud filters mutually
>>>>   exclusive.
>>>>
>>>> Signed-off-by: Amritha Nambiar <amritha.namb...@intel.com>
>>>> Signed-off-by: Kiran Patil <kiran.pa...@intel.com>
>>>> Signed-off-by: Anjali Singhai Jain <anjali.sing...@intel.com>
>>>> Signed-off-by: Jingjing Wu <jingjing...@intel.com>
>>>> ---
>>>> drivers/net/ethernet/intel/i40e/i40e.h             |   49 +
>>>> drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h  |    3 
>>>> drivers/net/ethernet/intel/i40e/i40e_common.c      |  189 ++++
>>>> drivers/net/ethernet/intel/i40e/i40e_main.c        |  971 
>>>> +++++++++++++++++++-
>>>> drivers/net/ethernet/intel/i40e/i40e_prototype.h   |   16 
>>>> drivers/net/ethernet/intel/i40e/i40e_type.h        |    1 
>>>> .../net/ethernet/intel/i40evf/i40e_adminq_cmd.h    |    3 
>>>> 7 files changed, 1202 insertions(+), 30 deletions(-)
>>>>
>>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e.h 
>>>> b/drivers/net/ethernet/intel/i40e/i40e.h
>>>> index 6018fb6..b110519 100644
>>>> --- a/drivers/net/ethernet/intel/i40e/i40e.h
>>>> +++ b/drivers/net/ethernet/intel/i40e/i40e.h
>>>> @@ -55,6 +55,8 @@
>>>> #include <linux/net_tstamp.h>
>>>> #include <linux/ptp_clock_kernel.h>
>>>> #include <net/pkt_cls.h>
>>>> +#include <net/tc_act/tc_gact.h>
>>>> +#include <net/tc_act/tc_mirred.h>
>>>> #include "i40e_type.h"
>>>> #include "i40e_prototype.h"
>>>> #include "i40e_client.h"
>>>> @@ -252,9 +254,52 @@ struct i40e_fdir_filter {
>>>>    u32 fd_id;
>>>> };
>>>>
>>>> +#define IPV4_VERSION 4
>>>> +#define IPV6_VERSION 6
>>>> +
>>>> +#define I40E_CLOUD_FIELD_OMAC     0x01
>>>> +#define I40E_CLOUD_FIELD_IMAC     0x02
>>>> +#define I40E_CLOUD_FIELD_IVLAN    0x04
>>>> +#define I40E_CLOUD_FIELD_TEN_ID   0x08
>>>> +#define I40E_CLOUD_FIELD_IIP      0x10
>>>> +
>>>> +#define I40E_CLOUD_FILTER_FLAGS_OMAC      I40E_CLOUD_FIELD_OMAC
>>>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC      I40E_CLOUD_FIELD_IMAC
>>>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN        (I40E_CLOUD_FIELD_IMAC 
>>>> | \
>>>> +                                           I40E_CLOUD_FIELD_IVLAN)
>>>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID       (I40E_CLOUD_FIELD_IMAC 
>>>> | \
>>>> +                                           I40E_CLOUD_FIELD_TEN_ID)
>>>> +#define I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC (I40E_CLOUD_FIELD_OMAC | 
>>>> \
>>>> +                                            I40E_CLOUD_FIELD_IMAC | \
>>>> +                                            I40E_CLOUD_FIELD_TEN_ID)
>>>> +#define I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID (I40E_CLOUD_FIELD_IMAC 
>>>> | \
>>>> +                                             I40E_CLOUD_FIELD_IVLAN | \
>>>> +                                             I40E_CLOUD_FIELD_TEN_ID)
>>>> +#define I40E_CLOUD_FILTER_FLAGS_IIP       I40E_CLOUD_FIELD_IIP
>>>> +
>>>> struct i40e_cloud_filter {
>>>>    struct hlist_node cloud_node;
>>>>    unsigned long cookie;
>>>> +  /* cloud filter input set follows */
>>>> +  u8 dst_mac[ETH_ALEN];
>>>> +  u8 src_mac[ETH_ALEN];
>>>> +  __be16 vlan_id;
>>>> +  __be32 dst_ip;
>>>> +  __be32 src_ip;
>>>> +  __be32 dst_ipv6[4];
>>>> +  __be32 src_ipv6[4];
>>>> +  __be16 dst_port;
>>>> +  __be16 src_port;
>>>> +  u32 ip_version;
>>>> +  u8 ip_proto;    /* IPPROTO value */
>>>> +  /* L4 port type: src or destination port */
>>>> +#define I40E_CLOUD_FILTER_PORT_SRC        0x01
>>>> +#define I40E_CLOUD_FILTER_PORT_DEST       0x02
>>>> +  u8 port_type;
>>>> +  u32 tenant_id;
>>>> +  u8 flags;
>>>> +#define I40E_CLOUD_TNL_TYPE_NONE  0xff
>>>> +  u8 tunnel_type;
>>>>    u16 seid;       /* filter control */
>>>> };
>>>>
>>>> @@ -491,6 +536,8 @@ struct i40e_pf {
>>>> #define I40E_FLAG_LINK_DOWN_ON_CLOSE_ENABLED       BIT(27)
>>>> #define I40E_FLAG_SOURCE_PRUNING_DISABLED  BIT(28)
>>>> #define I40E_FLAG_TC_MQPRIO                        BIT(29)
>>>> +#define I40E_FLAG_FD_SB_INACTIVE          BIT(30)
>>>> +#define I40E_FLAG_FD_SB_TO_CLOUD_FILTER           BIT(31)
>>>>
>>>>    struct i40e_client_instance *cinst;
>>>>    bool stat_offsets_loaded;
>>>> @@ -573,6 +620,8 @@ struct i40e_pf {
>>>>    u16 phy_led_val;
>>>>
>>>>    u16 override_q_count;
>>>> +  u16 last_sw_conf_flags;
>>>> +  u16 last_sw_conf_valid_flags;
>>>> };
>>>>
>>>> /**
>>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h 
>>>> b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
>>>> index 2e567c2..feb3d42 100644
>>>> --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
>>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
>>>> @@ -1392,6 +1392,9 @@ struct i40e_aqc_cloud_filters_element_data {
>>>>            struct {
>>>>                    u8 data[16];
>>>>            } v6;
>>>> +          struct {
>>>> +                  __le16 data[8];
>>>> +          } raw_v6;
>>>>    } ipaddr;
>>>>    __le16  flags;
>>>> #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT                    0
>>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c 
>>>> b/drivers/net/ethernet/intel/i40e/i40e_common.c
>>>> index 9567702..d9c9665 100644
>>>> --- a/drivers/net/ethernet/intel/i40e/i40e_common.c
>>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
>>>> @@ -5434,5 +5434,194 @@ i40e_add_pinfo_to_list(struct i40e_hw *hw,
>>>>
>>>>    status = i40e_aq_write_ppp(hw, (void *)sec, sec->data_end,
>>>>                               track_id, &offset, &info, NULL);
>>>> +
>>>> +  return status;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_aq_add_cloud_filters
>>>> + * @hw: pointer to the hardware structure
>>>> + * @seid: VSI seid to add cloud filters from
>>>> + * @filters: Buffer which contains the filters to be added
>>>> + * @filter_count: number of filters contained in the buffer
>>>> + *
>>>> + * Set the cloud filters for a given VSI.  The contents of the
>>>> + * i40e_aqc_cloud_filters_element_data are filled in by the caller
>>>> + * of the function.
>>>> + *
>>>> + **/
>>>> +enum i40e_status_code
>>>> +i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 seid,
>>>> +                    struct i40e_aqc_cloud_filters_element_data *filters,
>>>> +                    u8 filter_count)
>>>> +{
>>>> +  struct i40e_aq_desc desc;
>>>> +  struct i40e_aqc_add_remove_cloud_filters *cmd =
>>>> +  (struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;
>>>> +  enum i40e_status_code status;
>>>> +  u16 buff_len;
>>>> +
>>>> +  i40e_fill_default_direct_cmd_desc(&desc,
>>>> +                                    i40e_aqc_opc_add_cloud_filters);
>>>> +
>>>> +  buff_len = filter_count * sizeof(*filters);
>>>> +  desc.datalen = cpu_to_le16(buff_len);
>>>> +  desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
>>>> +  cmd->num_filters = filter_count;
>>>> +  cmd->seid = cpu_to_le16(seid);
>>>> +
>>>> +  status = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);
>>>> +
>>>> +  return status;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_aq_add_cloud_filters_bb
>>>> + * @hw: pointer to the hardware structure
>>>> + * @seid: VSI seid to add cloud filters from
>>>> + * @filters: Buffer which contains the filters in big buffer to be added
>>>> + * @filter_count: number of filters contained in the buffer
>>>> + *
>>>> + * Set the big buffer cloud filters for a given VSI.  The contents of the
>>>> + * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the
>>>> + * function.
>>>> + *
>>>> + **/
>>>> +i40e_status
>>>> +i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
>>>> +                       struct i40e_aqc_cloud_filters_element_bb *filters,
>>>> +                       u8 filter_count)
>>>> +{
>>>> +  struct i40e_aq_desc desc;
>>>> +  struct i40e_aqc_add_remove_cloud_filters *cmd =
>>>> +  (struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;
>>>> +  i40e_status status;
>>>> +  u16 buff_len;
>>>> +  int i;
>>>> +
>>>> +  i40e_fill_default_direct_cmd_desc(&desc,
>>>> +                                    i40e_aqc_opc_add_cloud_filters);
>>>> +
>>>> +  buff_len = filter_count * sizeof(*filters);
>>>> +  desc.datalen = cpu_to_le16(buff_len);
>>>> +  desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
>>>> +  cmd->num_filters = filter_count;
>>>> +  cmd->seid = cpu_to_le16(seid);
>>>> +  cmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;
>>>> +
>>>> +  for (i = 0; i < filter_count; i++) {
>>>> +          u16 tnl_type;
>>>> +          u32 ti;
>>>> +
>>>> +          tnl_type = (le16_to_cpu(filters[i].element.flags) &
>>>> +                     I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>
>>>> +                     I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;
>>>> +
>>>> +          /* For Geneve, the VNI should be placed in offset shifted by a
>>>> +           * byte than the offset for the Tenant ID for rest of the
>>>> +           * tunnels.
>>>> +           */
>>>> +          if (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {
>>>> +                  ti = le32_to_cpu(filters[i].element.tenant_id);
>>>> +                  filters[i].element.tenant_id = cpu_to_le32(ti << 8);
>>>> +          }
>>>> +  }
>>>> +
>>>> +  status = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);
>>>> +
>>>> +  return status;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_aq_rem_cloud_filters
>>>> + * @hw: pointer to the hardware structure
>>>> + * @seid: VSI seid to remove cloud filters from
>>>> + * @filters: Buffer which contains the filters to be removed
>>>> + * @filter_count: number of filters contained in the buffer
>>>> + *
>>>> + * Remove the cloud filters for a given VSI.  The contents of the
>>>> + * i40e_aqc_cloud_filters_element_data are filled in by the caller
>>>> + * of the function.
>>>> + *
>>>> + **/
>>>> +enum i40e_status_code
>>>> +i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 seid,
>>>> +                    struct i40e_aqc_cloud_filters_element_data *filters,
>>>> +                    u8 filter_count)
>>>> +{
>>>> +  struct i40e_aq_desc desc;
>>>> +  struct i40e_aqc_add_remove_cloud_filters *cmd =
>>>> +  (struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;
>>>> +  enum i40e_status_code status;
>>>> +  u16 buff_len;
>>>> +
>>>> +  i40e_fill_default_direct_cmd_desc(&desc,
>>>> +                                    i40e_aqc_opc_remove_cloud_filters);
>>>> +
>>>> +  buff_len = filter_count * sizeof(*filters);
>>>> +  desc.datalen = cpu_to_le16(buff_len);
>>>> +  desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
>>>> +  cmd->num_filters = filter_count;
>>>> +  cmd->seid = cpu_to_le16(seid);
>>>> +
>>>> +  status = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);
>>>> +
>>>> +  return status;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_aq_rem_cloud_filters_bb
>>>> + * @hw: pointer to the hardware structure
>>>> + * @seid: VSI seid to remove cloud filters from
>>>> + * @filters: Buffer which contains the filters in big buffer to be removed
>>>> + * @filter_count: number of filters contained in the buffer
>>>> + *
>>>> + * Remove the big buffer cloud filters for a given VSI.  The contents of 
>>>> the
>>>> + * i40e_aqc_cloud_filters_element_bb are filled in by the caller of the
>>>> + * function.
>>>> + *
>>>> + **/
>>>> +i40e_status
>>>> +i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
>>>> +                       struct i40e_aqc_cloud_filters_element_bb *filters,
>>>> +                       u8 filter_count)
>>>> +{
>>>> +  struct i40e_aq_desc desc;
>>>> +  struct i40e_aqc_add_remove_cloud_filters *cmd =
>>>> +  (struct i40e_aqc_add_remove_cloud_filters *)&desc.params.raw;
>>>> +  i40e_status status;
>>>> +  u16 buff_len;
>>>> +  int i;
>>>> +
>>>> +  i40e_fill_default_direct_cmd_desc(&desc,
>>>> +                                    i40e_aqc_opc_remove_cloud_filters);
>>>> +
>>>> +  buff_len = filter_count * sizeof(*filters);
>>>> +  desc.datalen = cpu_to_le16(buff_len);
>>>> +  desc.flags |= cpu_to_le16((u16)(I40E_AQ_FLAG_BUF | I40E_AQ_FLAG_RD));
>>>> +  cmd->num_filters = filter_count;
>>>> +  cmd->seid = cpu_to_le16(seid);
>>>> +  cmd->big_buffer_flag = I40E_AQC_ADD_CLOUD_CMD_BB;
>>>> +
>>>> +  for (i = 0; i < filter_count; i++) {
>>>> +          u16 tnl_type;
>>>> +          u32 ti;
>>>> +
>>>> +          tnl_type = (le16_to_cpu(filters[i].element.flags) &
>>>> +                     I40E_AQC_ADD_CLOUD_TNL_TYPE_MASK) >>
>>>> +                     I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT;
>>>> +
>>>> +          /* For Geneve, the VNI should be placed in offset shifted by a
>>>> +           * byte than the offset for the Tenant ID for rest of the
>>>> +           * tunnels.
>>>> +           */
>>>> +          if (tnl_type == I40E_AQC_ADD_CLOUD_TNL_TYPE_GENEVE) {
>>>> +                  ti = le32_to_cpu(filters[i].element.tenant_id);
>>>> +                  filters[i].element.tenant_id = cpu_to_le32(ti << 8);
>>>> +          }
>>>> +  }
>>>> +
>>>> +  status = i40e_asq_send_command(hw, &desc, filters, buff_len, NULL);
>>>> +
>>>>    return status;
>>>> }
>>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c 
>>>> b/drivers/net/ethernet/intel/i40e/i40e_main.c
>>>> index afcf08a..96ee608 100644
>>>> --- a/drivers/net/ethernet/intel/i40e/i40e_main.c
>>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
>>>> @@ -69,6 +69,15 @@ static int i40e_reset(struct i40e_pf *pf);
>>>> static void i40e_rebuild(struct i40e_pf *pf, bool reinit, bool 
>>>> lock_acquired);
>>>> static void i40e_fdir_sb_setup(struct i40e_pf *pf);
>>>> static int i40e_veb_get_bw_info(struct i40e_veb *veb);
>>>> +static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
>>>> +                               struct i40e_cloud_filter *filter,
>>>> +                               bool add);
>>>> +static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
>>>> +                                       struct i40e_cloud_filter *filter,
>>>> +                                       bool add);
>>>> +static int i40e_get_capabilities(struct i40e_pf *pf,
>>>> +                           enum i40e_admin_queue_opc list_type);
>>>> +
>>>>
>>>> /* i40e_pci_tbl - PCI Device ID Table
>>>>  *
>>>> @@ -5478,7 +5487,11 @@ int i40e_set_bw_limit(struct i40e_vsi *vsi, u16 
>>>> seid, u64 max_tx_rate)
>>>>  **/
>>>> static void i40e_remove_queue_channels(struct i40e_vsi *vsi)
>>>> {
>>>> +  enum i40e_admin_queue_err last_aq_status;
>>>> +  struct i40e_cloud_filter *cfilter;
>>>>    struct i40e_channel *ch, *ch_tmp;
>>>> +  struct i40e_pf *pf = vsi->back;
>>>> +  struct hlist_node *node;
>>>>    int ret, i;
>>>>
>>>>    /* Reset rss size that was stored when reconfiguring rss for
>>>> @@ -5519,6 +5532,29 @@ static void i40e_remove_queue_channels(struct 
>>>> i40e_vsi *vsi)
>>>>                             "Failed to reset tx rate for ch->seid %u\n",
>>>>                             ch->seid);
>>>>
>>>> +          /* delete cloud filters associated with this channel */
>>>> +          hlist_for_each_entry_safe(cfilter, node,
>>>> +                                    &pf->cloud_filter_list, cloud_node) {
>>>> +                  if (cfilter->seid != ch->seid)
>>>> +                          continue;
>>>> +
>>>> +                  hash_del(&cfilter->cloud_node);
>>>> +                  if (cfilter->dst_port)
>>>> +                          ret = i40e_add_del_cloud_filter_big_buf(vsi,
>>>> +                                                                  cfilter,
>>>> +                                                                  false);
>>>> +                  else
>>>> +                          ret = i40e_add_del_cloud_filter(vsi, cfilter,
>>>> +                                                          false);
>>>> +                  last_aq_status = pf->hw.aq.asq_last_status;
>>>> +                  if (ret)
>>>> +                          dev_info(&pf->pdev->dev,
>>>> +                                   "Failed to delete cloud filter, err %s 
>>>> aq_err %s\n",
>>>> +                                   i40e_stat_str(&pf->hw, ret),
>>>> +                                   i40e_aq_str(&pf->hw, last_aq_status));
>>>> +                  kfree(cfilter);
>>>> +          }
>>>> +
>>>>            /* delete VSI from FW */
>>>>            ret = i40e_aq_delete_element(&vsi->back->hw, ch->seid,
>>>>                                         NULL);
>>>> @@ -5970,6 +6006,74 @@ static bool i40e_setup_channel(struct i40e_pf *pf, 
>>>> struct i40e_vsi *vsi,
>>>> }
>>>>
>>>> /**
>>>> + * i40e_validate_and_set_switch_mode - sets up switch mode correctly
>>>> + * @vsi: ptr to VSI which has PF backing
>>>> + * @l4type: true for TCP ond false for UDP
>>>> + * @port_type: true if port is destination and false if port is source
>>>> + *
>>>> + * Sets up switch mode correctly if it needs to be changed and perform
>>>> + * what are allowed modes.
>>>> + **/
>>>> +static int i40e_validate_and_set_switch_mode(struct i40e_vsi *vsi, bool 
>>>> l4type,
>>>> +                                       bool port_type)
>>>> +{
>>>> +  u8 mode;
>>>> +  struct i40e_pf *pf = vsi->back;
>>>> +  struct i40e_hw *hw = &pf->hw;
>>>> +  int ret;
>>>> +
>>>> +  ret = i40e_get_capabilities(pf, i40e_aqc_opc_list_dev_capabilities);
>>>> +  if (ret)
>>>> +          return -EINVAL;
>>>> +
>>>> +  if (hw->dev_caps.switch_mode) {
>>>> +          /* if switch mode is set, support mode2 (non-tunneled for
>>>> +           * cloud filter) for now
>>>> +           */
>>>> +          u32 switch_mode = hw->dev_caps.switch_mode &
>>>> +                                                  I40E_SWITCH_MODE_MASK;
>>>> +          if (switch_mode >= I40E_NVM_IMAGE_TYPE_MODE1) {
>>>> +                  if (switch_mode == I40E_NVM_IMAGE_TYPE_MODE2)
>>>> +                          return 0;
>>>> +                  dev_err(&pf->pdev->dev,
>>>> +                          "Invalid switch_mode (%d), only non-tunneled 
>>>> mode for cloud filter is supported\n",
>>>> +                          hw->dev_caps.switch_mode);
>>>> +                  return -EINVAL;
>>>> +          }
>>>> +  }
>>>> +
>>>> +  /* port_type: true for destination port and false for source port
>>>> +   * For now, supports only destination port type
>>>> +   */
>>>> +  if (!port_type) {
>>>> +          dev_err(&pf->pdev->dev, "src port type not supported\n");
>>>> +          return -EINVAL;
>>>> +  }
>>>> +
>>>> +  /* Set Bit 7 to be valid */
>>>> +  mode = I40E_AQ_SET_SWITCH_BIT7_VALID;
>>>> +
>>>> +  /* Set L4type to both TCP and UDP support */
>>>> +  mode |= I40E_AQ_SET_SWITCH_L4_TYPE_BOTH;
>>>> +
>>>> +  /* Set cloud filter mode */
>>>> +  mode |= I40E_AQ_SET_SWITCH_MODE_NON_TUNNEL;
>>>> +
>>>> +  /* Prep mode field for set_switch_config */
>>>> +  ret = i40e_aq_set_switch_config(hw, pf->last_sw_conf_flags,
>>>> +                                  pf->last_sw_conf_valid_flags,
>>>> +                                  mode, NULL);
>>>> +  if (ret && hw->aq.asq_last_status != I40E_AQ_RC_ESRCH)
>>>> +          dev_err(&pf->pdev->dev,
>>>> +                  "couldn't set switch config bits, err %s aq_err %s\n",
>>>> +                  i40e_stat_str(hw, ret),
>>>> +                  i40e_aq_str(hw,
>>>> +                              hw->aq.asq_last_status));
>>>> +
>>>> +  return ret;
>>>> +}
>>>> +
>>>> +/**
>>>>  * i40e_create_queue_channel - function to create channel
>>>>  * @vsi: VSI to be configured
>>>>  * @ch: ptr to channel (it contains channel specific params)
>>>> @@ -6735,13 +6839,726 @@ static int i40e_setup_tc(struct net_device 
>>>> *netdev, void *type_data)
>>>>    return ret;
>>>> }
>>>>
>>>> +/**
>>>> + * i40e_set_cld_element - sets cloud filter element data
>>>> + * @filter: cloud filter rule
>>>> + * @cld: ptr to cloud filter element data
>>>> + *
>>>> + * This is helper function to copy data into cloud filter element
>>>> + **/
>>>> +static inline void
>>>> +i40e_set_cld_element(struct i40e_cloud_filter *filter,
>>>> +               struct i40e_aqc_cloud_filters_element_data *cld)
>>>> +{
>>>> +  int i, j;
>>>> +  u32 ipa;
>>>> +
>>>> +  memset(cld, 0, sizeof(*cld));
>>>> +  ether_addr_copy(cld->outer_mac, filter->dst_mac);
>>>> +  ether_addr_copy(cld->inner_mac, filter->src_mac);
>>>> +
>>>> +  if (filter->ip_version == IPV6_VERSION) {
>>>> +#define IPV6_MAX_INDEX    (ARRAY_SIZE(filter->dst_ipv6) - 1)
>>>> +          for (i = 0, j = 0; i < 4; i++, j += 2) {
>>>> +                  ipa = be32_to_cpu(filter->dst_ipv6[IPV6_MAX_INDEX - i]);
>>>> +                  ipa = cpu_to_le32(ipa);
>>>> +                  memcpy(&cld->ipaddr.raw_v6.data[j], &ipa, 4);
>>>> +          }
>>>> +  } else {
>>>> +          ipa = be32_to_cpu(filter->dst_ip);
>>>> +          memcpy(&cld->ipaddr.v4.data, &ipa, 4);
>>>> +  }
>>>> +
>>>> +  cld->inner_vlan = cpu_to_le16(ntohs(filter->vlan_id));
>>>> +
>>>> +  /* tenant_id is not supported by FW now, once the support is enabled
>>>> +   * fill the cld->tenant_id with cpu_to_le32(filter->tenant_id)
>>>> +   */
>>>> +  if (filter->tenant_id)
>>>> +          return;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_add_del_cloud_filter - Add/del cloud filter
>>>> + * @vsi: pointer to VSI
>>>> + * @filter: cloud filter rule
>>>> + * @add: if true, add, if false, delete
>>>> + *
>>>> + * Add or delete a cloud filter for a specific flow spec.
>>>> + * Returns 0 if the filter were successfully added.
>>>> + **/
>>>> +static int i40e_add_del_cloud_filter(struct i40e_vsi *vsi,
>>>> +                               struct i40e_cloud_filter *filter, bool add)
>>>> +{
>>>> +  struct i40e_aqc_cloud_filters_element_data cld_filter;
>>>> +  struct i40e_pf *pf = vsi->back;
>>>> +  int ret;
>>>> +  static const u16 flag_table[128] = {
>>>> +          [I40E_CLOUD_FILTER_FLAGS_OMAC]  =
>>>> +                  I40E_AQC_ADD_CLOUD_FILTER_OMAC,
>>>> +          [I40E_CLOUD_FILTER_FLAGS_IMAC]  =
>>>> +                  I40E_AQC_ADD_CLOUD_FILTER_IMAC,
>>>> +          [I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN]  =
>>>> +                  I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN,
>>>> +          [I40E_CLOUD_FILTER_FLAGS_IMAC_TEN_ID] =
>>>> +                  I40E_AQC_ADD_CLOUD_FILTER_IMAC_TEN_ID,
>>>> +          [I40E_CLOUD_FILTER_FLAGS_OMAC_TEN_ID_IMAC] =
>>>> +                  I40E_AQC_ADD_CLOUD_FILTER_OMAC_TEN_ID_IMAC,
>>>> +          [I40E_CLOUD_FILTER_FLAGS_IMAC_IVLAN_TEN_ID] =
>>>> +                  I40E_AQC_ADD_CLOUD_FILTER_IMAC_IVLAN_TEN_ID,
>>>> +          [I40E_CLOUD_FILTER_FLAGS_IIP] =
>>>> +                  I40E_AQC_ADD_CLOUD_FILTER_IIP,
>>>> +  };
>>>> +
>>>> +  if (filter->flags >= ARRAY_SIZE(flag_table))
>>>> +          return I40E_ERR_CONFIG;
>>>> +
>>>> +  /* copy element needed to add cloud filter from filter */
>>>> +  i40e_set_cld_element(filter, &cld_filter);
>>>> +
>>>> +  if (filter->tunnel_type != I40E_CLOUD_TNL_TYPE_NONE)
>>>> +          cld_filter.flags = cpu_to_le16(filter->tunnel_type <<
>>>> +                                       I40E_AQC_ADD_CLOUD_TNL_TYPE_SHIFT);
>>>> +
>>>> +  if (filter->ip_version == IPV6_VERSION)
>>>> +          cld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |
>>>> +                                          I40E_AQC_ADD_CLOUD_FLAGS_IPV6);
>>>> +  else
>>>> +          cld_filter.flags |= cpu_to_le16(flag_table[filter->flags] |
>>>> +                                          I40E_AQC_ADD_CLOUD_FLAGS_IPV4);
>>>> +
>>>> +  if (add)
>>>> +          ret = i40e_aq_add_cloud_filters(&pf->hw, filter->seid,
>>>> +                                          &cld_filter, 1);
>>>> +  else
>>>> +          ret = i40e_aq_rem_cloud_filters(&pf->hw, filter->seid,
>>>> +                                          &cld_filter, 1);
>>>> +  if (ret)
>>>> +          dev_dbg(&pf->pdev->dev,
>>>> +                  "Failed to %s cloud filter using l4 port %u, err %d 
>>>> aq_err %d\n",
>>>> +                  add ? "add" : "delete", filter->dst_port, ret,
>>>> +                  pf->hw.aq.asq_last_status);
>>>> +  else
>>>> +          dev_info(&pf->pdev->dev,
>>>> +                   "%s cloud filter for VSI: %d\n",
>>>> +                   add ? "Added" : "Deleted", filter->seid);
>>>> +  return ret;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_add_del_cloud_filter_big_buf - Add/del cloud filter using big_buf
>>>> + * @vsi: pointer to VSI
>>>> + * @filter: cloud filter rule
>>>> + * @add: if true, add, if false, delete
>>>> + *
>>>> + * Add or delete a cloud filter for a specific flow spec using big buffer.
>>>> + * Returns 0 if the filter were successfully added.
>>>> + **/
>>>> +static int i40e_add_del_cloud_filter_big_buf(struct i40e_vsi *vsi,
>>>> +                                       struct i40e_cloud_filter *filter,
>>>> +                                       bool add)
>>>> +{
>>>> +  struct i40e_aqc_cloud_filters_element_bb cld_filter;
>>>> +  struct i40e_pf *pf = vsi->back;
>>>> +  int ret;
>>>> +
>>>> +  /* Both (Outer/Inner) valid mac_addr are not supported */
>>>> +  if (is_valid_ether_addr(filter->dst_mac) &&
>>>> +      is_valid_ether_addr(filter->src_mac))
>>>> +          return -EINVAL;
>>>> +
>>>> +  /* Make sure port is specified, otherwise bail out, for channel
>>>> +   * specific cloud filter needs 'L4 port' to be non-zero
>>>> +   */
>>>> +  if (!filter->dst_port)
>>>> +          return -EINVAL;
>>>> +
>>>> +  /* adding filter using src_port/src_ip is not supported at this stage */
>>>> +  if (filter->src_port || filter->src_ip ||
>>>> +      !ipv6_addr_any((struct in6_addr *)&filter->src_ipv6))
>>>> +          return -EINVAL;
>>>> +
>>>> +  /* copy element needed to add cloud filter from filter */
>>>> +  i40e_set_cld_element(filter, &cld_filter.element);
>>>> +
>>>> +  if (is_valid_ether_addr(filter->dst_mac) ||
>>>> +      is_valid_ether_addr(filter->src_mac) ||
>>>> +      is_multicast_ether_addr(filter->dst_mac) ||
>>>> +      is_multicast_ether_addr(filter->src_mac)) {
>>>> +          /* MAC + IP : unsupported mode */
>>>> +          if (filter->dst_ip)
>>>> +                  return -EINVAL;
>>>> +
>>>> +          /* since we validated that L4 port must be valid before
>>>> +           * we get here, start with respective "flags" value
>>>> +           * and update if vlan is present or not
>>>> +           */
>>>> +          cld_filter.element.flags =
>>>> +                  cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_PORT);
>>>> +
>>>> +          if (filter->vlan_id) {
>>>> +                  cld_filter.element.flags =
>>>> +                  cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_MAC_VLAN_PORT);
>>>> +          }
>>>> +
>>>> +  } else if (filter->dst_ip || filter->ip_version == IPV6_VERSION) {
>>>> +          cld_filter.element.flags =
>>>> +                          cpu_to_le16(I40E_AQC_ADD_CLOUD_FILTER_IP_PORT);
>>>> +          if (filter->ip_version == IPV6_VERSION)
>>>> +                  cld_filter.element.flags |=
>>>> +                          cpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV6);
>>>> +          else
>>>> +                  cld_filter.element.flags |=
>>>> +                          cpu_to_le16(I40E_AQC_ADD_CLOUD_FLAGS_IPV4);
>>>> +  } else {
>>>> +          dev_err(&pf->pdev->dev,
>>>> +                  "either mac or ip has to be valid for cloud filter\n");
>>>> +          return -EINVAL;
>>>> +  }
>>>> +
>>>> +  /* Now copy L4 port in Byte 6..7 in general fields */
>>>> +  cld_filter.general_fields[I40E_AQC_ADD_CLOUD_FV_FLU_0X16_WORD0] =
>>>> +                                          be16_to_cpu(filter->dst_port);
>>>> +
>>>> +  if (add) {
>>>> +          bool proto_type, port_type;
>>>> +
>>>> +          proto_type = (filter->ip_proto == IPPROTO_TCP) ? true : false;
>>>> +          port_type = (filter->port_type & I40E_CLOUD_FILTER_PORT_DEST) ?
>>>> +                       true : false;
>>>> +
>>>> +          /* For now, src port based cloud filter for channel is not
>>>> +           * supported
>>>> +           */
>>>> +          if (!port_type) {
>>>> +                  dev_err(&pf->pdev->dev,
>>>> +                          "unsupported port type (src port)\n");
>>>> +                  return -EOPNOTSUPP;
>>>> +          }
>>>> +
>>>> +          /* Validate current device switch mode, change if necessary */
>>>> +          ret = i40e_validate_and_set_switch_mode(vsi, proto_type,
>>>> +                                                  port_type);
>>>> +          if (ret) {
>>>> +                  dev_err(&pf->pdev->dev,
>>>> +                          "failed to set switch mode, ret %d\n",
>>>> +                          ret);
>>>> +                  return ret;
>>>> +          }
>>>> +
>>>> +          ret = i40e_aq_add_cloud_filters_bb(&pf->hw, filter->seid,
>>>> +                                             &cld_filter, 1);
>>>> +  } else {
>>>> +          ret = i40e_aq_rem_cloud_filters_bb(&pf->hw, filter->seid,
>>>> +                                             &cld_filter, 1);
>>>> +  }
>>>> +
>>>> +  if (ret)
>>>> +          dev_dbg(&pf->pdev->dev,
>>>> +                  "Failed to %s cloud filter(big buffer) err %d aq_err 
>>>> %d\n",
>>>> +                  add ? "add" : "delete", ret, pf->hw.aq.asq_last_status);
>>>> +  else
>>>> +          dev_info(&pf->pdev->dev,
>>>> +                   "%s cloud filter for VSI: %d, L4 port: %d\n",
>>>> +                   add ? "add" : "delete", filter->seid,
>>>> +                   ntohs(filter->dst_port));
>>>> +  return ret;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_parse_cls_flower - Parse tc flower filters provided by kernel
>>>> + * @vsi: Pointer to VSI
>>>> + * @cls_flower: Pointer to struct tc_cls_flower_offload
>>>> + * @filter: Pointer to cloud filter structure
>>>> + *
>>>> + **/
>>>> +static int i40e_parse_cls_flower(struct i40e_vsi *vsi,
>>>> +                           struct tc_cls_flower_offload *f,
>>>> +                           struct i40e_cloud_filter *filter)
>>>> +{
>>>> +  struct i40e_pf *pf = vsi->back;
>>>> +  u16 addr_type = 0;
>>>> +  u8 field_flags = 0;
>>>> +
>>>> +  if (f->dissector->used_keys &
>>>> +      ~(BIT(FLOW_DISSECTOR_KEY_CONTROL) |
>>>> +        BIT(FLOW_DISSECTOR_KEY_BASIC) |
>>>> +        BIT(FLOW_DISSECTOR_KEY_ETH_ADDRS) |
>>>> +        BIT(FLOW_DISSECTOR_KEY_VLAN) |
>>>> +        BIT(FLOW_DISSECTOR_KEY_IPV4_ADDRS) |
>>>> +        BIT(FLOW_DISSECTOR_KEY_IPV6_ADDRS) |
>>>> +        BIT(FLOW_DISSECTOR_KEY_PORTS) |
>>>> +        BIT(FLOW_DISSECTOR_KEY_ENC_KEYID))) {
>>>> +          dev_err(&pf->pdev->dev, "Unsupported key used: 0x%x\n",
>>>> +                  f->dissector->used_keys);
>>>> +          return -EOPNOTSUPP;
>>>> +  }
>>>> +
>>>> +  if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
>>>> +          struct flow_dissector_key_keyid *key =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_ENC_KEYID,
>>>> +                                            f->key);
>>>> +
>>>> +          struct flow_dissector_key_keyid *mask =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_ENC_KEYID,
>>>> +                                            f->mask);
>>>> +
>>>> +          if (mask->keyid != 0)
>>>> +                  field_flags |= I40E_CLOUD_FIELD_TEN_ID;
>>>> +
>>>> +          filter->tenant_id = be32_to_cpu(key->keyid);
>>>> +  }
>>>> +
>>>> +  if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_BASIC)) {
>>>> +          struct flow_dissector_key_basic *key =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_BASIC,
>>>> +                                            f->key);
>>>> +
>>>> +          filter->ip_proto = key->ip_proto;
>>>> +  }
>>>> +
>>>> +  if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
>>>> +          struct flow_dissector_key_eth_addrs *key =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_ETH_ADDRS,
>>>> +                                            f->key);
>>>> +
>>>> +          struct flow_dissector_key_eth_addrs *mask =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_ETH_ADDRS,
>>>> +                                            f->mask);
>>>> +
>>>> +          /* use is_broadcast and is_zero to check for all 0xf or 0 */
>>>> +          if (!is_zero_ether_addr(mask->dst)) {
>>>> +                  if (is_broadcast_ether_addr(mask->dst)) {
>>>> +                          field_flags |= I40E_CLOUD_FIELD_OMAC;
>>>> +                  } else {
>>>> +                          dev_err(&pf->pdev->dev, "Bad ether dest mask 
>>>> %pM\n",
>>>> +                                  mask->dst);
>>>> +                          return I40E_ERR_CONFIG;
>>>> +                  }
>>>> +          }
>>>> +
>>>> +          if (!is_zero_ether_addr(mask->src)) {
>>>> +                  if (is_broadcast_ether_addr(mask->src)) {
>>>> +                          field_flags |= I40E_CLOUD_FIELD_IMAC;
>>>> +                  } else {
>>>> +                          dev_err(&pf->pdev->dev, "Bad ether src mask 
>>>> %pM\n",
>>>> +                                  mask->src);
>>>> +                          return I40E_ERR_CONFIG;
>>>> +                  }
>>>> +          }
>>>> +          ether_addr_copy(filter->dst_mac, key->dst);
>>>> +          ether_addr_copy(filter->src_mac, key->src);
>>>> +  }
>>>> +
>>>> +  if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_VLAN)) {
>>>> +          struct flow_dissector_key_vlan *key =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_VLAN,
>>>> +                                            f->key);
>>>> +          struct flow_dissector_key_vlan *mask =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_VLAN,
>>>> +                                            f->mask);
>>>> +
>>>> +          if (mask->vlan_id) {
>>>> +                  if (mask->vlan_id == VLAN_VID_MASK) {
>>>> +                          field_flags |= I40E_CLOUD_FIELD_IVLAN;
>>>> +
>>>> +                  } else {
>>>> +                          dev_err(&pf->pdev->dev, "Bad vlan mask 
>>>> 0x%04x\n",
>>>> +                                  mask->vlan_id);
>>>> +                          return I40E_ERR_CONFIG;
>>>> +                  }
>>>> +          }
>>>> +
>>>> +          filter->vlan_id = cpu_to_be16(key->vlan_id);
>>>> +  }
>>>> +
>>>> +  if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_CONTROL)) {
>>>> +          struct flow_dissector_key_control *key =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_CONTROL,
>>>> +                                            f->key);
>>>> +
>>>> +          addr_type = key->addr_type;
>>>> +  }
>>>> +
>>>> +  if (addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
>>>> +          struct flow_dissector_key_ipv4_addrs *key =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_IPV4_ADDRS,
>>>> +                                            f->key);
>>>> +          struct flow_dissector_key_ipv4_addrs *mask =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_IPV4_ADDRS,
>>>> +                                            f->mask);
>>>> +
>>>> +          if (mask->dst) {
>>>> +                  if (mask->dst == cpu_to_be32(0xffffffff)) {
>>>> +                          field_flags |= I40E_CLOUD_FIELD_IIP;
>>>> +                  } else {
>>>> +                          dev_err(&pf->pdev->dev, "Bad ip dst mask 
>>>> 0x%08x\n",
>>>> +                                  be32_to_cpu(mask->dst));
>>>> +                          return I40E_ERR_CONFIG;
>>>> +                  }
>>>> +          }
>>>> +
>>>> +          if (mask->src) {
>>>> +                  if (mask->src == cpu_to_be32(0xffffffff)) {
>>>> +                          field_flags |= I40E_CLOUD_FIELD_IIP;
>>>> +                  } else {
>>>> +                          dev_err(&pf->pdev->dev, "Bad ip src mask 
>>>> 0x%08x\n",
>>>> +                                  be32_to_cpu(mask->dst));
>>>> +                          return I40E_ERR_CONFIG;
>>>> +                  }
>>>> +          }
>>>> +
>>>> +          if (field_flags & I40E_CLOUD_FIELD_TEN_ID) {
>>>> +                  dev_err(&pf->pdev->dev, "Tenant id not allowed for ip 
>>>> filter\n");
>>>> +                  return I40E_ERR_CONFIG;
>>>> +          }
>>>> +          filter->dst_ip = key->dst;
>>>> +          filter->src_ip = key->src;
>>>> +          filter->ip_version = IPV4_VERSION;
>>>> +  }
>>>> +
>>>> +  if (addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
>>>> +          struct flow_dissector_key_ipv6_addrs *key =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_IPV6_ADDRS,
>>>> +                                            f->key);
>>>> +          struct flow_dissector_key_ipv6_addrs *mask =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_IPV6_ADDRS,
>>>> +                                            f->mask);
>>>> +
>>>> +          /* src and dest IPV6 address should not be LOOPBACK
>>>> +           * (0:0:0:0:0:0:0:1), which can be represented as ::1
>>>> +           */
>>>> +          if (ipv6_addr_loopback(&key->dst) ||
>>>> +              ipv6_addr_loopback(&key->src)) {
>>>> +                  dev_err(&pf->pdev->dev,
>>>> +                          "Bad ipv6, addr is LOOPBACK\n");
>>>> +                  return I40E_ERR_CONFIG;
>>>> +          }
>>>> +          if (!ipv6_addr_any(&mask->dst) || !ipv6_addr_any(&mask->src))
>>>> +                  field_flags |= I40E_CLOUD_FIELD_IIP;
>>>> +
>>>> +          memcpy(&filter->src_ipv6, &key->src.s6_addr32,
>>>> +                 sizeof(filter->src_ipv6));
>>>> +          memcpy(&filter->dst_ipv6, &key->dst.s6_addr32,
>>>> +                 sizeof(filter->dst_ipv6));
>>>> +
>>>> +          /* mark it as IPv6 filter, to be used later */
>>>> +          filter->ip_version = IPV6_VERSION;
>>>> +  }
>>>> +
>>>> +  if (dissector_uses_key(f->dissector, FLOW_DISSECTOR_KEY_PORTS)) {
>>>> +          struct flow_dissector_key_ports *key =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_PORTS,
>>>> +                                            f->key);
>>>> +          struct flow_dissector_key_ports *mask =
>>>> +                  skb_flow_dissector_target(f->dissector,
>>>> +                                            FLOW_DISSECTOR_KEY_PORTS,
>>>> +                                            f->mask);
>>>> +
>>>> +          if (mask->src) {
>>>> +                  if (mask->src == cpu_to_be16(0xffff)) {
>>>> +                          field_flags |= I40E_CLOUD_FIELD_IIP;
>>>> +                  } else {
>>>> +                          dev_err(&pf->pdev->dev, "Bad src port mask 
>>>> 0x%04x\n",
>>>> +                                  be16_to_cpu(mask->src));
>>>> +                          return I40E_ERR_CONFIG;
>>>> +                  }
>>>> +          }
>>>> +
>>>> +          if (mask->dst) {
>>>> +                  if (mask->dst == cpu_to_be16(0xffff)) {
>>>> +                          field_flags |= I40E_CLOUD_FIELD_IIP;
>>>> +                  } else {
>>>> +                          dev_err(&pf->pdev->dev, "Bad dst port mask 
>>>> 0x%04x\n",
>>>> +                                  be16_to_cpu(mask->dst));
>>>> +                          return I40E_ERR_CONFIG;
>>>> +                  }
>>>> +          }
>>>> +
>>>> +          filter->dst_port = key->dst;
>>>> +          filter->src_port = key->src;
>>>> +
>>>> +          /* For now, only supports destination port*/
>>>> +          filter->port_type |= I40E_CLOUD_FILTER_PORT_DEST;
>>>> +
>>>> +          switch (filter->ip_proto) {
>>>> +          case IPPROTO_TCP:
>>>> +          case IPPROTO_UDP:
>>>> +                  break;
>>>> +          default:
>>>> +                  dev_err(&pf->pdev->dev,
>>>> +                          "Only UDP and TCP transport are supported\n");
>>>> +                  return -EINVAL;
>>>> +          }
>>>> +  }
>>>> +  filter->flags = field_flags;
>>>> +  return 0;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_handle_redirect_action: Forward to a traffic class on the device
>>>> + * @vsi: Pointer to VSI
>>>> + * @ifindex: ifindex of the device to forwared to
>>>> + * @tc: traffic class index on the device
>>>> + * @filter: Pointer to cloud filter structure
>>>> + *
>>>> + **/
>>>> +static int i40e_handle_redirect_action(struct i40e_vsi *vsi, int ifindex, 
>>>> u8 tc,
>>>> +                                 struct i40e_cloud_filter *filter)
>>>> +{
>>>> +  struct i40e_channel *ch, *ch_tmp;
>>>> +
>>>> +  /* redirect to a traffic class on the same device */
>>>> +  if (vsi->netdev->ifindex == ifindex) {
>>>> +          if (tc == 0) {
>>>> +                  filter->seid = vsi->seid;
>>>> +                  return 0;
>>>> +          } else if (vsi->tc_config.enabled_tc & BIT(tc)) {
>>>> +                  if (!filter->dst_port) {
>>>> +                          dev_err(&vsi->back->pdev->dev,
>>>> +                                  "Specify destination port to redirect 
>>>> to traffic class that is not default\n");
>>>> +                          return -EINVAL;
>>>> +                  }
>>>> +                  if (list_empty(&vsi->ch_list))
>>>> +                          return -EINVAL;
>>>> +                  list_for_each_entry_safe(ch, ch_tmp, &vsi->ch_list,
>>>> +                                           list) {
>>>> +                          if (ch->seid == vsi->tc_seid_map[tc])
>>>> +                                  filter->seid = ch->seid;
>>>> +                  }
>>>> +                  return 0;
>>>> +          }
>>>> +  }
>>>> +  return -EINVAL;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_parse_tc_actions - Parse tc actions
>>>> + * @vsi: Pointer to VSI
>>>> + * @cls_flower: Pointer to struct tc_cls_flower_offload
>>>> + * @filter: Pointer to cloud filter structure
>>>> + *
>>>> + **/
>>>> +static int i40e_parse_tc_actions(struct i40e_vsi *vsi, struct tcf_exts 
>>>> *exts,
>>>> +                           struct i40e_cloud_filter *filter)
>>>> +{
>>>> +  const struct tc_action *a;
>>>> +  LIST_HEAD(actions);
>>>> +  int err;
>>>> +
>>>> +  if (!tcf_exts_has_actions(exts))
>>>> +          return -EINVAL;
>>>> +
>>>> +  tcf_exts_to_list(exts, &actions);
>>>> +  list_for_each_entry(a, &actions, list) {
>>>> +          /* Drop action */
>>>> +          if (is_tcf_gact_shot(a)) {
>>>> +                  dev_err(&vsi->back->pdev->dev,
>>>> +                          "Cloud filters do not support the drop 
>>>> action.\n");
>>>> +                  return -EOPNOTSUPP;
>>>> +          }
>>>> +
>>>> +          /* Redirect to a traffic class on the same device */
>>>> +          if (!is_tcf_mirred_egress_redirect(a) && is_tcf_mirred_tc(a)) {
>>>> +                  int ifindex = tcf_mirred_ifindex(a);
>>>> +                  u8 tc = tcf_mirred_tc(a);
>>>> +
>>>> +                  err = i40e_handle_redirect_action(vsi, ifindex, tc,
>>>> +                                                    filter);
>>>> +                  if (err == 0)
>>>> +                          return err;
>>>> +          }
>>>> +  }
>>>> +  return -EINVAL;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_configure_clsflower - Configure tc flower filters
>>>> + * @vsi: Pointer to VSI
>>>> + * @cls_flower: Pointer to struct tc_cls_flower_offload
>>>> + *
>>>> + **/
>>>> +static int i40e_configure_clsflower(struct i40e_vsi *vsi,
>>>> +                              struct tc_cls_flower_offload *cls_flower)
>>>> +{
>>>> +  struct i40e_cloud_filter *filter = NULL;
>>>> +  struct i40e_pf *pf = vsi->back;
>>>> +  int err = 0;
>>>> +
>>>> +  if (test_bit(__I40E_RESET_RECOVERY_PENDING, pf->state) ||
>>>> +      test_bit(__I40E_RESET_INTR_RECEIVED, pf->state))
>>>> +          return -EBUSY;
>>>> +
>>>> +  if (pf->fdir_pf_active_filters ||
>>>> +      (!hlist_empty(&pf->fdir_filter_list))) {
>>>> +          dev_err(&vsi->back->pdev->dev,
>>>> +                  "Flow Director Sideband filters exists, turn ntuple off 
>>>> to configure cloud filters\n");
>>>> +          return -EINVAL;
>>>> +  }
>>>> +
>>>> +  if (vsi->back->flags & I40E_FLAG_FD_SB_ENABLED) {
>>>> +          dev_err(&vsi->back->pdev->dev,
>>>> +                  "Disable Flow Director Sideband, configuring Cloud 
>>>> filters via tc-flower\n");
>>>> +          vsi->back->flags &= ~I40E_FLAG_FD_SB_ENABLED;
>>>> +          vsi->back->flags |= I40E_FLAG_FD_SB_TO_CLOUD_FILTER;
>>>> +  }
>>>> +
>>>> +  filter = kzalloc(sizeof(*filter), GFP_KERNEL);
>>>> +  if (!filter)
>>>> +          return -ENOMEM;
>>>> +
>>>> +  filter->cookie = cls_flower->cookie;
>>>> +
>>>> +  err = i40e_parse_cls_flower(vsi, cls_flower, filter);
>>>> +  if (err < 0)
>>>> +          goto err;
>>>> +
>>>> +  err = i40e_parse_tc_actions(vsi, cls_flower->exts, filter);
>>>> +  if (err < 0)
>>>> +          goto err;
>>>> +
>>>> +  /* Add cloud filter */
>>>> +  if (filter->dst_port)
>>>> +          err = i40e_add_del_cloud_filter_big_buf(vsi, filter, true);
>>>> +  else
>>>> +          err = i40e_add_del_cloud_filter(vsi, filter, true);
>>>> +
>>>> +  if (err) {
>>>> +          dev_err(&pf->pdev->dev,
>>>> +                  "Failed to add cloud filter, err %s\n",
>>>> +                  i40e_stat_str(&pf->hw, err));
>>>> +          err = i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);
>>>> +          goto err;
>>>> +  }
>>>> +
>>>> +  /* add filter to the ordered list */
>>>> +  INIT_HLIST_NODE(&filter->cloud_node);
>>>> +
>>>> +  hlist_add_head(&filter->cloud_node, &pf->cloud_filter_list);
>>>> +
>>>> +  pf->num_cloud_filters++;
>>>> +
>>>> +  return err;
>>>> +err:
>>>> +  kfree(filter);
>>>> +  return err;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_find_cloud_filter - Find the could filter in the list
>>>> + * @vsi: Pointer to VSI
>>>> + * @cookie: filter specific cookie
>>>> + *
>>>> + **/
>>>> +static struct i40e_cloud_filter *i40e_find_cloud_filter(struct i40e_vsi 
>>>> *vsi,
>>>> +                                                  unsigned long *cookie)
>>>> +{
>>>> +  struct i40e_cloud_filter *filter = NULL;
>>>> +  struct hlist_node *node2;
>>>> +
>>>> +  hlist_for_each_entry_safe(filter, node2,
>>>> +                            &vsi->back->cloud_filter_list, cloud_node)
>>>> +          if (!memcmp(cookie, &filter->cookie, sizeof(filter->cookie)))
>>>> +                  return filter;
>>>> +  return NULL;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_delete_clsflower - Remove tc flower filters
>>>> + * @vsi: Pointer to VSI
>>>> + * @cls_flower: Pointer to struct tc_cls_flower_offload
>>>> + *
>>>> + **/
>>>> +static int i40e_delete_clsflower(struct i40e_vsi *vsi,
>>>> +                           struct tc_cls_flower_offload *cls_flower)
>>>> +{
>>>> +  struct i40e_cloud_filter *filter = NULL;
>>>> +  struct i40e_pf *pf = vsi->back;
>>>> +  int err = 0;
>>>> +
>>>> +  filter = i40e_find_cloud_filter(vsi, &cls_flower->cookie);
>>>> +
>>>> +  if (!filter)
>>>> +          return -EINVAL;
>>>> +
>>>> +  hash_del(&filter->cloud_node);
>>>> +
>>>> +  if (filter->dst_port)
>>>> +          err = i40e_add_del_cloud_filter_big_buf(vsi, filter, false);
>>>> +  else
>>>> +          err = i40e_add_del_cloud_filter(vsi, filter, false);
>>>> +  if (err) {
>>>> +          kfree(filter);
>>>> +          dev_err(&pf->pdev->dev,
>>>> +                  "Failed to delete cloud filter, err %s\n",
>>>> +                  i40e_stat_str(&pf->hw, err));
>>>> +          return i40e_aq_rc_to_posix(err, pf->hw.aq.asq_last_status);
>>>> +  }
>>>> +
>>>> +  kfree(filter);
>>>> +  pf->num_cloud_filters--;
>>>> +
>>>> +  if (!pf->num_cloud_filters)
>>>> +          if ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&
>>>> +              !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {
>>>> +                  pf->flags |= I40E_FLAG_FD_SB_ENABLED;
>>>> +                  pf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;
>>>> +                  pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;
>>>> +          }
>>>> +  return 0;
>>>> +}
>>>> +
>>>> +/**
>>>> + * i40e_setup_tc_cls_flower - flower classifier offloads
>>>> + * @netdev: net device to configure
>>>> + * @type_data: offload data
>>>> + **/
>>>> +static int i40e_setup_tc_cls_flower(struct net_device *netdev,
>>>> +                              struct tc_cls_flower_offload *cls_flower)
>>>> +{
>>>> +  struct i40e_netdev_priv *np = netdev_priv(netdev);
>>>> +  struct i40e_vsi *vsi = np->vsi;
>>>> +
>>>> +  if (!is_classid_clsact_ingress(cls_flower->common.classid) ||
>>>> +      cls_flower->common.chain_index)
>>>> +          return -EOPNOTSUPP;
>>>> +
>>>> +  switch (cls_flower->command) {
>>>> +  case TC_CLSFLOWER_REPLACE:
>>>> +          return i40e_configure_clsflower(vsi, cls_flower);
>>>> +  case TC_CLSFLOWER_DESTROY:
>>>> +          return i40e_delete_clsflower(vsi, cls_flower);
>>>> +  case TC_CLSFLOWER_STATS:
>>>> +          return -EOPNOTSUPP;
>>>> +  default:
>>>> +          return -EINVAL;
>>>> +  }
>>>> +}
>>>> +
>>>> static int __i40e_setup_tc(struct net_device *netdev, enum tc_setup_type 
>>>> type,
>>>>                       void *type_data)
>>>> {
>>>> -  if (type != TC_SETUP_MQPRIO)
>>>> +  switch (type) {
>>>> +  case TC_SETUP_MQPRIO:
>>>> +          return i40e_setup_tc(netdev, type_data);
>>>> +  case TC_SETUP_CLSFLOWER:
>>>> +          return i40e_setup_tc_cls_flower(netdev, type_data);
>>>> +  default:
>>>>            return -EOPNOTSUPP;
>>>> -
>>>> -  return i40e_setup_tc(netdev, type_data);
>>>> +  }
>>>> }
>>>>
>>>> /**
>>>> @@ -6939,6 +7756,13 @@ static void i40e_cloud_filter_exit(struct i40e_pf 
>>>> *pf)
>>>>            kfree(cfilter);
>>>>    }
>>>>    pf->num_cloud_filters = 0;
>>>> +
>>>> +  if ((pf->flags & I40E_FLAG_FD_SB_TO_CLOUD_FILTER) &&
>>>> +      !(pf->flags & I40E_FLAG_FD_SB_INACTIVE)) {
>>>> +          pf->flags |= I40E_FLAG_FD_SB_ENABLED;
>>>> +          pf->flags &= ~I40E_FLAG_FD_SB_TO_CLOUD_FILTER;
>>>> +          pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;
>>>> +  }
>>>> }
>>>>
>>>> /**
>>>> @@ -8046,7 +8870,8 @@ static int i40e_reconstitute_veb(struct i40e_veb 
>>>> *veb)
>>>>  * i40e_get_capabilities - get info about the HW
>>>>  * @pf: the PF struct
>>>>  **/
>>>> -static int i40e_get_capabilities(struct i40e_pf *pf)
>>>> +static int i40e_get_capabilities(struct i40e_pf *pf,
>>>> +                           enum i40e_admin_queue_opc list_type)
>>>> {
>>>>    struct i40e_aqc_list_capabilities_element_resp *cap_buf;
>>>>    u16 data_size;
>>>> @@ -8061,9 +8886,8 @@ static int i40e_get_capabilities(struct i40e_pf *pf)
>>>>
>>>>            /* this loads the data into the hw struct for us */
>>>>            err = i40e_aq_discover_capabilities(&pf->hw, cap_buf, buf_len,
>>>> -                                      &data_size,
>>>> -                                      i40e_aqc_opc_list_func_capabilities,
>>>> -                                      NULL);
>>>> +                                              &data_size, list_type,
>>>> +                                              NULL);
>>>>            /* data loaded, buffer no longer needed */
>>>>            kfree(cap_buf);
>>>>
>>>> @@ -8080,26 +8904,44 @@ static int i40e_get_capabilities(struct i40e_pf 
>>>> *pf)
>>>>            }
>>>>    } while (err);
>>>>
>>>> -  if (pf->hw.debug_mask & I40E_DEBUG_USER)
>>>> -          dev_info(&pf->pdev->dev,
>>>> -                   "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",
>>>> -                   pf->hw.pf_id, pf->hw.func_caps.num_vfs,
>>>> -                   pf->hw.func_caps.num_msix_vectors,
>>>> -                   pf->hw.func_caps.num_msix_vectors_vf,
>>>> -                   pf->hw.func_caps.fd_filters_guaranteed,
>>>> -                   pf->hw.func_caps.fd_filters_best_effort,
>>>> -                   pf->hw.func_caps.num_tx_qp,
>>>> -                   pf->hw.func_caps.num_vsis);
>>>> -
>>>> +  if (pf->hw.debug_mask & I40E_DEBUG_USER) {
>>>> +          if (list_type == i40e_aqc_opc_list_func_capabilities) {
>>>> +                  dev_info(&pf->pdev->dev,
>>>> +                           "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",
>>>> +                           pf->hw.pf_id, pf->hw.func_caps.num_vfs,
>>>> +                           pf->hw.func_caps.num_msix_vectors,
>>>> +                           pf->hw.func_caps.num_msix_vectors_vf,
>>>> +                           pf->hw.func_caps.fd_filters_guaranteed,
>>>> +                           pf->hw.func_caps.fd_filters_best_effort,
>>>> +                           pf->hw.func_caps.num_tx_qp,
>>>> +                           pf->hw.func_caps.num_vsis);
>>>> +          } else if (list_type == i40e_aqc_opc_list_dev_capabilities) {
>>>> +                  dev_info(&pf->pdev->dev,
>>>> +                           "switch_mode=0x%04x, function_valid=0x%08x\n",
>>>> +                           pf->hw.dev_caps.switch_mode,
>>>> +                           pf->hw.dev_caps.valid_functions);
>>>> +                  dev_info(&pf->pdev->dev,
>>>> +                           "SR-IOV=%d, num_vfs for all function=%u\n",
>>>> +                           pf->hw.dev_caps.sr_iov_1_1,
>>>> +                           pf->hw.dev_caps.num_vfs);
>>>> +                  dev_info(&pf->pdev->dev,
>>>> +                           "num_vsis=%u, num_rx:%u, num_tx=%u\n",
>>>> +                           pf->hw.dev_caps.num_vsis,
>>>> +                           pf->hw.dev_caps.num_rx_qp,
>>>> +                           pf->hw.dev_caps.num_tx_qp);
>>>> +          }
>>>> +  }
>>>> +  if (list_type == i40e_aqc_opc_list_func_capabilities) {
>>>> #define DEF_NUM_VSI (1 + (pf->hw.func_caps.fcoe ? 1 : 0) \
>>>>                   + pf->hw.func_caps.num_vfs)
>>>> -  if (pf->hw.revision_id == 0 && (DEF_NUM_VSI > 
>>>> pf->hw.func_caps.num_vsis)) {
>>>> -          dev_info(&pf->pdev->dev,
>>>> -                   "got num_vsis %d, setting num_vsis to %d\n",
>>>> -                   pf->hw.func_caps.num_vsis, DEF_NUM_VSI);
>>>> -          pf->hw.func_caps.num_vsis = DEF_NUM_VSI;
>>>> +          if (pf->hw.revision_id == 0 &&
>>>> +              (pf->hw.func_caps.num_vsis < DEF_NUM_VSI)) {
>>>> +                  dev_info(&pf->pdev->dev,
>>>> +                           "got num_vsis %d, setting num_vsis to %d\n",
>>>> +                           pf->hw.func_caps.num_vsis, DEF_NUM_VSI);
>>>> +                  pf->hw.func_caps.num_vsis = DEF_NUM_VSI;
>>>> +          }
>>>>    }
>>>> -
>>>>    return 0;
>>>> }
>>>>
>>>> @@ -8141,6 +8983,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
>>>>            if (!vsi) {
>>>>                    dev_info(&pf->pdev->dev, "Couldn't create FDir VSI\n");
>>>>                    pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
>>>> +                  pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>>>>                    return;
>>>>            }
>>>>    }
>>>> @@ -8163,6 +9006,48 @@ static void i40e_fdir_teardown(struct i40e_pf *pf)
>>>> }
>>>>
>>>> /**
>>>> + * i40e_rebuild_cloud_filters - Rebuilds cloud filters for VSIs
>>>> + * @vsi: PF main vsi
>>>> + * @seid: seid of main or channel VSIs
>>>> + *
>>>> + * Rebuilds cloud filters associated with main VSI and channel VSIs if 
>>>> they
>>>> + * existed before reset
>>>> + **/
>>>> +static int i40e_rebuild_cloud_filters(struct i40e_vsi *vsi, u16 seid)
>>>> +{
>>>> +  struct i40e_cloud_filter *cfilter;
>>>> +  struct i40e_pf *pf = vsi->back;
>>>> +  struct hlist_node *node;
>>>> +  i40e_status ret;
>>>> +
>>>> +  /* Add cloud filters back if they exist */
>>>> +  if (hlist_empty(&pf->cloud_filter_list))
>>>> +          return 0;
>>>> +
>>>> +  hlist_for_each_entry_safe(cfilter, node, &pf->cloud_filter_list,
>>>> +                            cloud_node) {
>>>> +          if (cfilter->seid != seid)
>>>> +                  continue;
>>>> +
>>>> +          if (cfilter->dst_port)
>>>> +                  ret = i40e_add_del_cloud_filter_big_buf(vsi, cfilter,
>>>> +                                                          true);
>>>> +          else
>>>> +                  ret = i40e_add_del_cloud_filter(vsi, cfilter, true);
>>>> +
>>>> +          if (ret) {
>>>> +                  dev_dbg(&pf->pdev->dev,
>>>> +                          "Failed to rebuild cloud filter, err %s aq_err 
>>>> %s\n",
>>>> +                          i40e_stat_str(&pf->hw, ret),
>>>> +                          i40e_aq_str(&pf->hw,
>>>> +                                      pf->hw.aq.asq_last_status));
>>>> +                  return ret;
>>>> +          }
>>>> +  }
>>>> +  return 0;
>>>> +}
>>>> +
>>>> +/**
>>>>  * i40e_rebuild_channels - Rebuilds channel VSIs if they existed before 
>>>> reset
>>>>  * @vsi: PF main vsi
>>>>  *
>>>> @@ -8199,6 +9084,13 @@ static int i40e_rebuild_channels(struct i40e_vsi 
>>>> *vsi)
>>>>                                            I40E_BW_CREDIT_DIVISOR,
>>>>                            ch->seid);
>>>>            }
>>>> +          ret = i40e_rebuild_cloud_filters(vsi, ch->seid);
>>>> +          if (ret) {
>>>> +                  dev_dbg(&vsi->back->pdev->dev,
>>>> +                          "Failed to rebuild cloud filters for channel 
>>>> VSI %u\n",
>>>> +                          ch->seid);
>>>> +                  return ret;
>>>> +          }
>>>>    }
>>>>    return 0;
>>>> }
>>>> @@ -8365,7 +9257,7 @@ static void i40e_rebuild(struct i40e_pf *pf, bool 
>>>> reinit, bool lock_acquired)
>>>>            i40e_verify_eeprom(pf);
>>>>
>>>>    i40e_clear_pxe_mode(hw);
>>>> -  ret = i40e_get_capabilities(pf);
>>>> +  ret = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);
>>>>    if (ret)
>>>>            goto end_core_reset;
>>>>
>>>> @@ -8482,6 +9374,10 @@ static void i40e_rebuild(struct i40e_pf *pf, bool 
>>>> reinit, bool lock_acquired)
>>>>                    goto end_unlock;
>>>>    }
>>>>
>>>> +  ret = i40e_rebuild_cloud_filters(vsi, vsi->seid);
>>>> +  if (ret)
>>>> +          goto end_unlock;
>>>> +
>>>>    /* PF Main VSI is rebuild by now, go ahead and rebuild channel VSIs
>>>>     * for this main VSI if they exist
>>>>     */
>>>> @@ -9404,6 +10300,7 @@ static int i40e_init_msix(struct i40e_pf *pf)
>>>>        (pf->num_fdsb_msix == 0)) {
>>>>            dev_info(&pf->pdev->dev, "Sideband Flowdir disabled, not enough 
>>>> MSI-X vectors\n");
>>>>            pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
>>>> +          pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>>>>    }
>>>>    if ((pf->flags & I40E_FLAG_VMDQ_ENABLED) &&
>>>>        (pf->num_vmdq_msix == 0)) {
>>>> @@ -9521,6 +10418,7 @@ static int i40e_init_interrupt_scheme(struct 
>>>> i40e_pf *pf)
>>>>                                   I40E_FLAG_FD_SB_ENABLED  |
>>>>                                   I40E_FLAG_FD_ATR_ENABLED |
>>>>                                   I40E_FLAG_VMDQ_ENABLED);
>>>> +                  pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>>>>
>>>>                    /* rework the queue expectations without MSIX */
>>>>                    i40e_determine_queue_usage(pf);
>>>> @@ -10263,9 +11161,13 @@ bool i40e_set_ntuple(struct i40e_pf *pf, 
>>>> netdev_features_t features)
>>>>            /* Enable filters and mark for reset */
>>>>            if (!(pf->flags & I40E_FLAG_FD_SB_ENABLED))
>>>>                    need_reset = true;
>>>> -          /* enable FD_SB only if there is MSI-X vector */
>>>> -          if (pf->num_fdsb_msix > 0)
>>>> +          /* enable FD_SB only if there is MSI-X vector and no cloud
>>>> +           * filters exist
>>>> +           */
>>>> +          if (pf->num_fdsb_msix > 0 && !pf->num_cloud_filters) {
>>>>                    pf->flags |= I40E_FLAG_FD_SB_ENABLED;
>>>> +                  pf->flags &= ~I40E_FLAG_FD_SB_INACTIVE;
>>>> +          }
>>>>    } else {
>>>>            /* turn off filters, mark for reset and clear SW filter list */
>>>>            if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
>>>> @@ -10274,6 +11176,8 @@ bool i40e_set_ntuple(struct i40e_pf *pf, 
>>>> netdev_features_t features)
>>>>            }
>>>>            pf->flags &= ~(I40E_FLAG_FD_SB_ENABLED |
>>>>                           I40E_FLAG_FD_SB_AUTO_DISABLED);
>>>> +          pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>>>> +
>>>>            /* reset fd counters */
>>>>            pf->fd_add_err = 0;
>>>>            pf->fd_atr_cnt = 0;
>>>> @@ -10857,7 +11761,8 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
>>>>            netdev->hw_features |= NETIF_F_NTUPLE;
>>>>    hw_features = hw_enc_features           |
>>>>                  NETIF_F_HW_VLAN_CTAG_TX   |
>>>> -                NETIF_F_HW_VLAN_CTAG_RX;
>>>> +                NETIF_F_HW_VLAN_CTAG_RX   |
>>>> +                NETIF_F_HW_TC;
>>>>
>>>>    netdev->hw_features |= hw_features;
>>>>
>>>> @@ -12159,8 +13064,10 @@ static int i40e_setup_pf_switch(struct i40e_pf 
>>>> *pf, bool reinit)
>>>>    */
>>>>
>>>>    if ((pf->hw.pf_id == 0) &&
>>>> -      !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT))
>>>> +      !(pf->flags & I40E_FLAG_TRUE_PROMISC_SUPPORT)) {
>>>>            flags = I40E_AQ_SET_SWITCH_CFG_PROMISC;
>>>> +          pf->last_sw_conf_flags = flags;
>>>> +  }
>>>>
>>>>    if (pf->hw.pf_id == 0) {
>>>>            u16 valid_flags;
>>>> @@ -12176,6 +13083,7 @@ static int i40e_setup_pf_switch(struct i40e_pf 
>>>> *pf, bool reinit)
>>>>                                         pf->hw.aq.asq_last_status));
>>>>                    /* not a fatal problem, just keep going */
>>>>            }
>>>> +          pf->last_sw_conf_valid_flags = valid_flags;
>>>>    }
>>>>
>>>>    /* first time setup */
>>>> @@ -12273,6 +13181,7 @@ static void i40e_determine_queue_usage(struct 
>>>> i40e_pf *pf)
>>>>                           I40E_FLAG_DCB_ENABLED    |
>>>>                           I40E_FLAG_SRIOV_ENABLED  |
>>>>                           I40E_FLAG_VMDQ_ENABLED);
>>>> +          pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>>>>    } else if (!(pf->flags & (I40E_FLAG_RSS_ENABLED |
>>>>                              I40E_FLAG_FD_SB_ENABLED |
>>>>                              I40E_FLAG_FD_ATR_ENABLED |
>>>> @@ -12287,6 +13196,7 @@ static void i40e_determine_queue_usage(struct 
>>>> i40e_pf *pf)
>>>>                           I40E_FLAG_FD_ATR_ENABLED |
>>>>                           I40E_FLAG_DCB_ENABLED    |
>>>>                           I40E_FLAG_VMDQ_ENABLED);
>>>> +          pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>>>>    } else {
>>>>            /* Not enough queues for all TCs */
>>>>            if ((pf->flags & I40E_FLAG_DCB_CAPABLE) &&
>>>> @@ -12310,6 +13220,7 @@ static void i40e_determine_queue_usage(struct 
>>>> i40e_pf *pf)
>>>>                    queues_left -= 1; /* save 1 queue for FD */
>>>>            } else {
>>>>                    pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
>>>> +                  pf->flags |= I40E_FLAG_FD_SB_INACTIVE;
>>>>                    dev_info(&pf->pdev->dev, "not enough queues for Flow 
>>>> Director. Flow Director feature is disabled\n");
>>>>            }
>>>>    }
>>>> @@ -12613,7 +13524,7 @@ static int i40e_probe(struct pci_dev *pdev, const 
>>>> struct pci_device_id *ent)
>>>>            dev_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");
>>>>
>>>>    i40e_clear_pxe_mode(hw);
>>>> -  err = i40e_get_capabilities(pf);
>>>> +  err = i40e_get_capabilities(pf, i40e_aqc_opc_list_func_capabilities);
>>>>    if (err)
>>>>            goto err_adminq_setup;
>>>>
>>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h 
>>>> b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
>>>> index 92869f5..3bb6659 100644
>>>> --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
>>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
>>>> @@ -283,6 +283,22 @@ i40e_status 
>>>> i40e_aq_query_switch_comp_bw_config(struct i40e_hw *hw,
>>>>            struct i40e_asq_cmd_details *cmd_details);
>>>> i40e_status i40e_aq_resume_port_tx(struct i40e_hw *hw,
>>>>                               struct i40e_asq_cmd_details *cmd_details);
>>>> +i40e_status
>>>> +i40e_aq_add_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
>>>> +                       struct i40e_aqc_cloud_filters_element_bb *filters,
>>>> +                       u8 filter_count);
>>>> +enum i40e_status_code
>>>> +i40e_aq_add_cloud_filters(struct i40e_hw *hw, u16 vsi,
>>>> +                    struct i40e_aqc_cloud_filters_element_data *filters,
>>>> +                    u8 filter_count);
>>>> +enum i40e_status_code
>>>> +i40e_aq_rem_cloud_filters(struct i40e_hw *hw, u16 vsi,
>>>> +                    struct i40e_aqc_cloud_filters_element_data *filters,
>>>> +                    u8 filter_count);
>>>> +i40e_status
>>>> +i40e_aq_rem_cloud_filters_bb(struct i40e_hw *hw, u16 seid,
>>>> +                       struct i40e_aqc_cloud_filters_element_bb *filters,
>>>> +                       u8 filter_count);
>>>> i40e_status i40e_read_lldp_cfg(struct i40e_hw *hw,
>>>>                           struct i40e_lldp_variables *lldp_cfg);
>>>> /* i40e_common */
>>>> diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h 
>>>> b/drivers/net/ethernet/intel/i40e/i40e_type.h
>>>> index c019f46..af38881 100644
>>>> --- a/drivers/net/ethernet/intel/i40e/i40e_type.h
>>>> +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
>>>> @@ -287,6 +287,7 @@ struct i40e_hw_capabilities {
>>>> #define I40E_NVM_IMAGE_TYPE_MODE1  0x6
>>>> #define I40E_NVM_IMAGE_TYPE_MODE2  0x7
>>>> #define I40E_NVM_IMAGE_TYPE_MODE3  0x8
>>>> +#define I40E_SWITCH_MODE_MASK             0xF
>>>>
>>>>    u32  management_mode;
>>>>    u32  mng_protocols_over_mctp;
>>>> diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h 
>>>> b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
>>>> index b8c78bf..4fe27f0 100644
>>>> --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
>>>> +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
>>>> @@ -1360,6 +1360,9 @@ struct i40e_aqc_cloud_filters_element_data {
>>>>            struct {
>>>>                    u8 data[16];
>>>>            } v6;
>>>> +          struct {
>>>> +                  __le16 data[8];
>>>> +          } raw_v6;
>>>>    } ipaddr;
>>>>    __le16  flags;
>>>> #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT                    0
>>>>

Reply via email to