From: Kiran Patil <kiran.pa...@intel.com>

This patch implements feature, which allows user to change
input set mask for flow director using side-band channel.
This patch adds definition of FLOW_TYPE_MASK into the header file.
With this patch, user can now specify less than 4 tuple(src ip, dsp ip,
src port, dst port) for flow type TCP4/UDP4.

Change-Id: I90052508f8c172c0da5a4b78b949704b4a59ea78
Signed-off-by: Kiran Patil <kiran.pa...@intel.com>
Tested-by: Andrew Bowers <andrewx.bow...@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirs...@intel.com>
---
 drivers/net/ethernet/intel/i40e/i40e.h         |   6 ++
 drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 116 +++++++++++++++++++++++++
 drivers/net/ethernet/intel/i40e/i40e_txrx.c    |   2 +-
 3 files changed, 123 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/i40e/i40e.h 
b/drivers/net/ethernet/intel/i40e/i40e.h
index e312adf..c2ac73d 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -240,6 +240,12 @@ struct i40e_fdir_filter {
        u32 fd_id;
 };
 
+#ifndef FLOW_TYPE_MASK
+#define FLOW_TYPE_MASK 0xFF
+#else
+#error FLOW_TYPE_MASK already defined elsewhere
+#endif
+
 #define I40E_ETH_P_LLDP                        0x88cc
 
 #define I40E_DCB_PRIO_TYPE_STRICT      0
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c 
b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index 8e56c43..ada448b 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -2488,6 +2488,116 @@ static int i40e_del_fdir_entry(struct i40e_vsi *vsi,
 }
 
 /**
+ * i40e_handle_input_set - Detect and handle input set changes
+ * @vsi: pointer to the targeted VSI
+ * @fsp: pointer to RX flow classification spec
+ *
+ * Reads register, detect change in input set based on existing register
+ * value and what user has passed. Update input set mask register if needed.
+ **/
+static int i40e_handle_input_set(struct i40e_vsi *vsi,
+                                struct ethtool_rx_flow_spec *fsp)
+{
+       bool inset_mask_change = false;
+       struct i40e_pf *pf;
+       u64 val;
+       u8 idx;
+
+       if (unlikely(!vsi))
+               return -EINVAL;
+
+       pf = vsi->back;
+       switch (fsp->flow_type & FLOW_TYPE_MASK) {
+       case TCP_V4_FLOW:
+               idx = I40E_FILTER_PCTYPE_NONF_IPV4_TCP;
+               break;
+       case UDP_V4_FLOW:
+               idx = I40E_FILTER_PCTYPE_NONF_IPV4_UDP;
+               break;
+       default:
+               /* for all other flow types */
+               return 0;
+       }
+
+       val = ((u64)i40e_read_rx_ctl(&pf->hw,
+                                    I40E_PRTQF_FD_INSET(idx, 1)) << 32) |
+              (u64)i40e_read_rx_ctl(&pf->hw,
+                                    I40E_PRTQF_FD_INSET(idx, 0));
+
+       /* Default input set (TCP/UDP/SCTP) contains following
+        * fields: srcip + dest ip + src port + dest port
+        * For SCTP, there is one extra field, "verification tag"
+        */
+       if (val & I40E_L3_SRC_MASK) {
+               if (!fsp->h_u.tcp_ip4_spec.ip4src) {
+                       val &= ~I40E_L3_SRC_MASK;
+                       inset_mask_change = true;
+               }
+       } else {
+               if (fsp->h_u.tcp_ip4_spec.ip4src) {
+                       val |= I40E_L3_SRC_MASK;
+                       inset_mask_change = true;
+               }
+       }
+       if (val & I40E_L3_DST_MASK) {
+               if (!fsp->h_u.tcp_ip4_spec.ip4dst) {
+                       val &= ~I40E_L3_DST_MASK;
+                       inset_mask_change = true;
+               }
+       } else {
+               if (fsp->h_u.tcp_ip4_spec.ip4dst) {
+                       val |= I40E_L3_DST_MASK;
+                       inset_mask_change = true;
+               }
+       }
+       if (val & I40E_L4_SRC_MASK) {
+               if (!fsp->h_u.tcp_ip4_spec.psrc) {
+                       val &= ~I40E_L4_SRC_MASK;
+                       inset_mask_change = true;
+               }
+       } else {
+               if (fsp->h_u.tcp_ip4_spec.psrc) {
+                       val |= I40E_L4_SRC_MASK;
+                       inset_mask_change = true;
+               }
+       }
+       if (val & I40E_L4_DST_MASK) {
+               if (!fsp->h_u.tcp_ip4_spec.pdst) {
+                       val &= ~I40E_L4_DST_MASK;
+                       inset_mask_change = true;
+               }
+       } else {
+               if (fsp->h_u.tcp_ip4_spec.pdst) {
+                       val |= I40E_L4_DST_MASK;
+                       inset_mask_change = true;
+               }
+       }
+
+       if (inset_mask_change) {
+               if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+                       netif_err(pf, drv, vsi->netdev, "Change of input set is 
not supported when MFP mode is enabled\n");
+                       return -EOPNOTSUPP;
+               }
+               if (pf->fdir_pf_active_filters) {
+                       netif_err(pf, drv, vsi->netdev, "Change of input set is 
not supported when there are existing filters. Please delete them and 
re-try\n");
+                       return -EOPNOTSUPP;
+               }
+
+               if (I40E_DEBUG_FD & pf->hw.debug_mask)
+                       netif_info(pf, drv, vsi->netdev, "FD_INSET mask is 
changing to 0x%016llx\n",
+                                  val);
+               /* Update input mask register since input set mask changed */
+               i40e_write_rx_ctl(&pf->hw, I40E_PRTQF_FD_INSET(idx, 1),
+                                 (u32)(val >> 32));
+               i40e_write_rx_ctl(&pf->hw, I40E_PRTQF_FD_INSET(idx, 0),
+                                 (u32)val);
+               netif_info(pf, drv, vsi->netdev, "Input set mask change has 
been successful. Please note that this and all other interfaces on (related and 
derived from) this part are affected as well.\n");
+       }
+
+       return 0;
+}
+
+/**
  * i40e_add_fdir_ethtool - Add/Remove Flow Director filters
  * @vsi: pointer to the targeted VSI
  * @cmd: command to get or set RX flow classification rules
@@ -2562,6 +2672,12 @@ static int i40e_add_fdir_ethtool(struct i40e_vsi *vsi,
        input->dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src;
        input->src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst;
 
+       ret = i40e_handle_input_set(vsi, fsp);
+       if (ret) {
+               netif_err(pf, drv, vsi->netdev, "Unable to handle change in 
input set mask\n");
+               goto free_input;
+       }
+
        if (ntohl(fsp->m_ext.data[1])) {
                vf_id = ntohl(fsp->h_ext.data[1]);
                if (vf_id >= pf->num_alloc_vfs) {
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c 
b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index 6e44cf1..57af5f6 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -412,7 +412,7 @@ int i40e_add_del_fdir(struct i40e_vsi *vsi,
        struct i40e_pf *pf = vsi->back;
        int ret;
 
-       switch (input->flow_type & ~FLOW_EXT) {
+       switch (input->flow_type & FLOW_TYPE_MASK) {
        case TCP_V4_FLOW:
                ret = i40e_add_del_fdir_tcpv4(vsi, input, add);
                break;
-- 
2.5.5

Reply via email to