net/cxgbe: query firmware for filter resources
authorShagun Agrawal <shaguna@chelsio.com>
Fri, 8 Jun 2018 17:58:11 +0000 (23:28 +0530)
committerFerruh Yigit <ferruh.yigit@intel.com>
Thu, 14 Jun 2018 17:27:50 +0000 (19:27 +0200)
Fetch available filter resources from firmware and allocate table for
book-keeping and managing filters in hardware. Also define the hardware
filter specification (ch_filter_specification) used to describe each
filter rule.

Signed-off-by: Shagun Agrawal <shaguna@chelsio.com>
Signed-off-by: Kumar Sanghvi <kumaras@chelsio.com>
Signed-off-by: Rahul Lakkireddy <rahul.lakkireddy@chelsio.com>
drivers/net/cxgbe/base/adapter.h
drivers/net/cxgbe/base/t4fw_interface.h
drivers/net/cxgbe/cxgbe_filter.h [new file with mode: 0644]
drivers/net/cxgbe/cxgbe_main.c
drivers/net/cxgbe/cxgbe_ofld.h [new file with mode: 0644]

index 55cb2e9..1a0f96e 100644 (file)
 #include <rte_bus_pci.h>
 #include <rte_mbuf.h>
 #include <rte_io.h>
+#include <rte_ethdev.h>
 
 #include "cxgbe_compat.h"
 #include "t4_regs_values.h"
+#include "cxgbe_ofld.h"
 
 enum {
        MAX_ETH_QSETS = 64,           /* # of Ethernet Tx/Rx queue sets */
@@ -306,6 +308,8 @@ struct adapter {
        unsigned int vpd_flag;
 
        int use_unpacked_mode; /* unpacked rx mode state */
+
+       struct tid_info tids;     /* Info used to access TID related tables */
 };
 
 /**
index 852e8f3..95b2aec 100644 (file)
@@ -489,6 +489,10 @@ enum fw_params_mnem {
 enum fw_params_param_dev {
        FW_PARAMS_PARAM_DEV_CCLK        = 0x00, /* chip core clock in khz */
        FW_PARAMS_PARAM_DEV_PORTVEC     = 0x01, /* the port vector */
+       FW_PARAMS_PARAM_DEV_NTID        = 0x02, /* reads the number of TIDs
+                                                * allocated by the device's
+                                                * Lookup Engine
+                                                */
        FW_PARAMS_PARAM_DEV_FWREV       = 0x0B, /* fw version */
        FW_PARAMS_PARAM_DEV_TPREV       = 0x0C, /* tp version */
        FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17,
@@ -498,6 +502,8 @@ enum fw_params_param_dev {
  * physical and virtual function parameters
  */
 enum fw_params_param_pfvf {
+       FW_PARAMS_PARAM_PFVF_FILTER_START = 0x05,
+       FW_PARAMS_PARAM_PFVF_FILTER_END = 0x06,
        FW_PARAMS_PARAM_PFVF_CPLFW4MSG_ENCAP = 0x31,
        FW_PARAMS_PARAM_PFVF_PORT_CAPS32 = 0x3A
 };
diff --git a/drivers/net/cxgbe/cxgbe_filter.h b/drivers/net/cxgbe/cxgbe_filter.h
new file mode 100644 (file)
index 0000000..5af891b
--- /dev/null
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Chelsio Communications.
+ * All rights reserved.
+ */
+
+#ifndef _CXGBE_FILTER_H_
+#define _CXGBE_FILTER_H_
+
+#include "t4_msg.h"
+/*
+ * Defined bit width of user definable filter tuples
+ */
+#define ETHTYPE_BITWIDTH 16
+#define FRAG_BITWIDTH 1
+#define MACIDX_BITWIDTH 9
+#define FCOE_BITWIDTH 1
+#define IPORT_BITWIDTH 3
+#define MATCHTYPE_BITWIDTH 3
+#define PROTO_BITWIDTH 8
+#define TOS_BITWIDTH 8
+#define PF_BITWIDTH 8
+#define VF_BITWIDTH 8
+#define IVLAN_BITWIDTH 16
+#define OVLAN_BITWIDTH 16
+
+/*
+ * Filter matching rules.  These consist of a set of ingress packet field
+ * (value, mask) tuples.  The associated ingress packet field matches the
+ * tuple when ((field & mask) == value).  (Thus a wildcard "don't care" field
+ * rule can be constructed by specifying a tuple of (0, 0).)  A filter rule
+ * matches an ingress packet when all of the individual individual field
+ * matching rules are true.
+ *
+ * Partial field masks are always valid, however, while it may be easy to
+ * understand their meanings for some fields (e.g. IP address to match a
+ * subnet), for others making sensible partial masks is less intuitive (e.g.
+ * MPS match type) ...
+ */
+struct ch_filter_tuple {
+       /*
+        * Compressed header matching field rules.  The TP_VLAN_PRI_MAP
+        * register selects which of these fields will participate in the
+        * filter match rules -- up to a maximum of 36 bits.  Because
+        * TP_VLAN_PRI_MAP is a global register, all filters must use the same
+        * set of fields.
+        */
+       uint32_t ethtype:ETHTYPE_BITWIDTH;      /* Ethernet type */
+       uint32_t frag:FRAG_BITWIDTH;            /* IP fragmentation header */
+       uint32_t ivlan_vld:1;                   /* inner VLAN valid */
+       uint32_t ovlan_vld:1;                   /* outer VLAN valid */
+       uint32_t pfvf_vld:1;                    /* PF/VF valid */
+       uint32_t macidx:MACIDX_BITWIDTH;        /* exact match MAC index */
+       uint32_t fcoe:FCOE_BITWIDTH;            /* FCoE packet */
+       uint32_t iport:IPORT_BITWIDTH;          /* ingress port */
+       uint32_t matchtype:MATCHTYPE_BITWIDTH;  /* MPS match type */
+       uint32_t proto:PROTO_BITWIDTH;          /* protocol type */
+       uint32_t tos:TOS_BITWIDTH;              /* TOS/Traffic Type */
+       uint32_t pf:PF_BITWIDTH;                /* PCI-E PF ID */
+       uint32_t vf:VF_BITWIDTH;                /* PCI-E VF ID */
+       uint32_t ivlan:IVLAN_BITWIDTH;          /* inner VLAN */
+       uint32_t ovlan:OVLAN_BITWIDTH;          /* outer VLAN */
+
+       /*
+        * Uncompressed header matching field rules.  These are always
+        * available for field rules.
+        */
+       uint8_t lip[16];        /* local IP address (IPv4 in [3:0]) */
+       uint8_t fip[16];        /* foreign IP address (IPv4 in [3:0]) */
+       uint16_t lport;         /* local port */
+       uint16_t fport;         /* foreign port */
+
+       /* reservations for future additions */
+       uint8_t rsvd[12];
+};
+
+/*
+ * Filter specification
+ */
+struct ch_filter_specification {
+       /* Filter rule value/mask pairs. */
+       struct ch_filter_tuple val;
+       struct ch_filter_tuple mask;
+};
+
+/*
+ * Host shadow copy of ingress filter entry.  This is in host native format
+ * and doesn't match the ordering or bit order, etc. of the hardware or the
+ * firmware command.
+ */
+struct filter_entry {
+       /*
+        * The filter itself.
+        */
+       struct ch_filter_specification fs;
+};
+
+#endif /* _CXGBE_FILTER_H_ */
index 54eb23d..9880257 100644 (file)
 #include "t4_msg.h"
 #include "cxgbe.h"
 
+/**
+ * Allocate a chunk of memory. The allocated memory is cleared.
+ */
+void *t4_alloc_mem(size_t size)
+{
+       return rte_zmalloc(NULL, size, 0);
+}
+
+/**
+ * Free memory allocated through t4_alloc_mem().
+ */
+void t4_free_mem(void *addr)
+{
+       rte_free(addr);
+}
+
 /*
  * Response queue handler for the FW event queue.
  */
@@ -169,6 +185,59 @@ int cxgb4_set_rspq_intr_params(struct sge_rspq *q, unsigned int us,
        return 0;
 }
 
+/**
+ * Free TID tables.
+ */
+static void tid_free(struct tid_info *t)
+{
+       if (t->tid_tab) {
+               if (t->ftid_bmap)
+                       rte_bitmap_free(t->ftid_bmap);
+
+               if (t->ftid_bmap_array)
+                       t4_os_free(t->ftid_bmap_array);
+
+               t4_os_free(t->tid_tab);
+       }
+
+       memset(t, 0, sizeof(struct tid_info));
+}
+
+/**
+ * Allocate and initialize the TID tables.  Returns 0 on success.
+ */
+static int tid_init(struct tid_info *t)
+{
+       size_t size;
+       unsigned int ftid_bmap_size;
+       unsigned int max_ftids = t->nftids;
+
+       ftid_bmap_size = rte_bitmap_get_memory_footprint(t->nftids);
+       size = t->ntids * sizeof(*t->tid_tab) +
+               max_ftids * sizeof(*t->ftid_tab);
+
+       t->tid_tab = t4_os_alloc(size);
+       if (!t->tid_tab)
+               return -ENOMEM;
+
+       t->ftid_tab = (struct filter_entry *)&t->tid_tab[t->ntids];
+       t->ftid_bmap_array = t4_os_alloc(ftid_bmap_size);
+       if (!t->ftid_bmap_array) {
+               tid_free(t);
+               return -ENOMEM;
+       }
+
+       t4_os_lock_init(&t->ftid_lock);
+       t->ftid_bmap = rte_bitmap_init(t->nftids, t->ftid_bmap_array,
+                                      ftid_bmap_size);
+       if (!t->ftid_bmap) {
+               tid_free(t);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
 static inline bool is_x_1g_port(const struct link_config *lc)
 {
        return (lc->pcaps & FW_PORT_CAP32_SPEED_1G) != 0;
@@ -706,6 +775,7 @@ bye:
 
 static int adap_init0(struct adapter *adap)
 {
+       struct fw_caps_config_cmd caps_cmd;
        int ret = 0;
        u32 v, port_vec;
        enum dev_state state;
@@ -822,6 +892,35 @@ static int adap_init0(struct adapter *adap)
         V_FW_PARAMS_PARAM_Y(0) | \
         V_FW_PARAMS_PARAM_Z(0))
 
+       params[0] = FW_PARAM_PFVF(FILTER_START);
+       params[1] = FW_PARAM_PFVF(FILTER_END);
+       ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 2, params, val);
+       if (ret < 0)
+               goto bye;
+       adap->tids.ftid_base = val[0];
+       adap->tids.nftids = val[1] - val[0] + 1;
+
+       /*
+        * Get device capabilities so we can determine what resources we need
+        * to manage.
+        */
+       memset(&caps_cmd, 0, sizeof(caps_cmd));
+       caps_cmd.op_to_write = htonl(V_FW_CMD_OP(FW_CAPS_CONFIG_CMD) |
+                                    F_FW_CMD_REQUEST | F_FW_CMD_READ);
+       caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
+       ret = t4_wr_mbox(adap, adap->mbox, &caps_cmd, sizeof(caps_cmd),
+                        &caps_cmd);
+       if (ret < 0)
+               goto bye;
+
+       /* query tid-related parameters */
+       params[0] = FW_PARAM_DEV(NTID);
+       ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1,
+                             params, val);
+       if (ret < 0)
+               goto bye;
+       adap->tids.ntids = val[0];
+
        /* If we're running on newer firmware, let it know that we're
         * prepared to deal with encapsulated CPL messages.  Older
         * firmware won't understand this and we'll just get
@@ -1307,6 +1406,7 @@ void cxgbe_close(struct adapter *adapter)
        if (adapter->flags & FULL_INIT_DONE) {
                if (is_pf4(adapter))
                        t4_intr_disable(adapter);
+               tid_free(&adapter->tids);
                t4_sge_tx_monitor_stop(adapter);
                t4_free_sge_resources(adapter);
                for_each_port(adapter, i) {
@@ -1469,6 +1569,12 @@ allocate_mac:
        print_adapter_info(adapter);
        print_port_info(adapter);
 
+       if (tid_init(&adapter->tids) < 0) {
+               /* Disable filtering support */
+               dev_warn(adapter, "could not allocate TID table, "
+                        "filter support disabled. Continuing\n");
+       }
+
        err = init_rss(adapter);
        if (err)
                goto out_free;
diff --git a/drivers/net/cxgbe/cxgbe_ofld.h b/drivers/net/cxgbe/cxgbe_ofld.h
new file mode 100644 (file)
index 0000000..9f382f6
--- /dev/null
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Chelsio Communications.
+ * All rights reserved.
+ */
+
+#ifndef _CXGBE_OFLD_H_
+#define _CXGBE_OFLD_H_
+
+#include <rte_bitmap.h>
+
+#include "cxgbe_filter.h"
+
+/*
+ * Holds the size, base address, free list start, etc of filter TID.
+ * The tables themselves are allocated dynamically.
+ */
+struct tid_info {
+       void **tid_tab;
+       unsigned int ntids;
+       struct filter_entry *ftid_tab;  /* Normal filters */
+       struct rte_bitmap *ftid_bmap;
+       uint8_t *ftid_bmap_array;
+       unsigned int nftids;
+       unsigned int ftid_base;
+       rte_spinlock_t ftid_lock;
+};
+#endif /* _CXGBE_OFLD_H_ */