nfp: add TLV capabilities to the BAR
authorJakub Kicinski <jakub.kicinski@netronome.com>
Thu, 18 Jan 2018 02:51:01 +0000 (18:51 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 19 Jan 2018 20:44:18 +0000 (15:44 -0500)
NFP is entirely programmable, including the PCI data interface.
Using a fixed control BAR layout certainly makes implementations
easier, but require careful considerations when space is allocated.
Once BAR area is allocated to one feature nothing else can use it.
Allocating space statically also requires it to be sized upfront,
which leads to either unnecessary limitation or wastage.

We currently have a 32bit capability word defined which tells drivers
which application FW features are supported.   Most of the bits
are exhausted.  The same bits are also reused for enabling specific
features.  Bulk of capabilities don't have a need for an enable bit,
however, leading to confusion and wastage.

TLVs seems like a better fit for expressing capabilities of applications
running on programmable hardware.

This patch leaves the front of the BAR as is, and declares a TLV
capability start at offset 0x58.  Most of the space up to 0x0d90
is already allocated, but the used space can be wrapped with RESERVED
TLVs.  E.g.:

Address    Type         Length
 0x0058    RESERVED      0xe00  /* Wrap basic structures */
 0x0e5c    FEATURE_A     0x004
 0x0e64    FEATURE_B     0x004
 0x0e6c    RESERVED      0x990  /* Wrap qeueue stats */
 0x1800    FEATURE_C     0x100

Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: Dirk van der Merwe <dirk.vandermerwe@netronome.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/netronome/nfp/Makefile
drivers/net/ethernet/netronome/nfp/nfp_net.h
drivers/net/ethernet/netronome/nfp/nfp_net_common.c
drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c [new file with mode: 0644]
drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.h

index 064f00e23a1920255bf5c849f988170992d40ee3..d5866d708dfa3f3a5dd3a5d28ad0c04a8f3d0313 100644 (file)
@@ -22,6 +22,7 @@ nfp-objs := \
            nfp_hwmon.o \
            nfp_main.o \
            nfp_net_common.o \
+           nfp_net_ctrl.o \
            nfp_net_debugdump.o \
            nfp_net_ethtool.o \
            nfp_net_main.o \
index 6f6e3d6fd93568d0a45ad0228073632cc47fefb5..d88eda9707e68359cec2e6624a5a7037d615c3e9 100644 (file)
@@ -578,6 +578,7 @@ struct nfp_net_dp {
  * @qcp_cfg:            Pointer to QCP queue used for configuration notification
  * @tx_bar:             Pointer to mapped TX queues
  * @rx_bar:             Pointer to mapped FL/RX queues
+ * @tlv_caps:          Parsed TLV capabilities
  * @debugfs_dir:       Device directory in debugfs
  * @vnic_list:         Entry on device vNIC list
  * @pdev:              Backpointer to PCI device
@@ -644,6 +645,8 @@ struct nfp_net {
        u8 __iomem *tx_bar;
        u8 __iomem *rx_bar;
 
+       struct nfp_net_tlv_caps tlv_caps;
+
        struct dentry *debugfs_dir;
 
        struct list_head vnic_list;
index 2b5cad3069a7f648ef7ffb0eb947635dc0f7197f..b47da7ff01dda061fa72b59cec9e107c8ffd548e 100644 (file)
@@ -3815,6 +3815,11 @@ int nfp_net_init(struct nfp_net *nn)
                nn->dp.ctrl |= NFP_NET_CFG_CTRL_IRQMOD;
        }
 
+       err = nfp_net_tlv_caps_parse(&nn->pdev->dev, nn->dp.ctrl_bar,
+                                    &nn->tlv_caps);
+       if (err)
+               return err;
+
        if (nn->dp.netdev)
                nfp_net_netdev_init(nn);
 
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ctrl.c
new file mode 100644 (file)
index 0000000..ff15524
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2018 Netronome Systems, Inc.
+ *
+ * This software is dual licensed under the GNU General License Version 2,
+ * June 1991 as shown in the file COPYING in the top-level directory of this
+ * source tree or the BSD 2-Clause License provided below.  You have the
+ * option to license this software under the complete terms of either license.
+ *
+ * The BSD 2-Clause License:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      1. Redistributions of source code must retain the above
+ *         copyright notice, this list of conditions and the following
+ *         disclaimer.
+ *
+ *      2. Redistributions in binary form must reproduce the above
+ *         copyright notice, this list of conditions and the following
+ *         disclaimer in the documentation and/or other materials
+ *         provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include "nfp_net_ctrl.h"
+#include "nfp_net.h"
+
+static void nfp_net_tlv_caps_reset(struct nfp_net_tlv_caps *caps)
+{
+       memset(caps, 0, sizeof(*caps));
+}
+
+int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem,
+                          struct nfp_net_tlv_caps *caps)
+{
+       u8 __iomem *data = ctrl_mem + NFP_NET_CFG_TLV_BASE;
+       u8 __iomem *end = ctrl_mem + NFP_NET_CFG_BAR_SZ;
+       u32 hdr;
+
+       nfp_net_tlv_caps_reset(caps);
+
+       hdr = readl(data);
+       if (!hdr)
+               return 0;
+
+       while (true) {
+               unsigned int length, offset;
+               u32 hdr = readl(data);
+
+               length = FIELD_GET(NFP_NET_CFG_TLV_HEADER_LENGTH, hdr);
+               offset = data - ctrl_mem + NFP_NET_CFG_TLV_BASE;
+
+               /* Advance past the header */
+               data += 4;
+
+               if (length % NFP_NET_CFG_TLV_LENGTH_INC) {
+                       dev_err(dev, "TLV size not multiple of %u len:%u\n",
+                               NFP_NET_CFG_TLV_LENGTH_INC, length);
+                       return -EINVAL;
+               }
+               if (data + length > end) {
+                       dev_err(dev, "oversized TLV offset:%u len:%u\n",
+                               offset, length);
+                       return -EINVAL;
+               }
+
+               switch (FIELD_GET(NFP_NET_CFG_TLV_HEADER_TYPE, hdr)) {
+               case NFP_NET_CFG_TLV_TYPE_UNKNOWN:
+                       dev_err(dev, "NULL TLV at offset:%u\n", offset);
+                       return -EINVAL;
+               case NFP_NET_CFG_TLV_TYPE_RESERVED:
+                       break;
+               case NFP_NET_CFG_TLV_TYPE_END:
+                       if (!length)
+                               return 0;
+
+                       dev_err(dev, "END TLV should be empty, has len:%d\n",
+                               length);
+                       return -EINVAL;
+               default:
+                       if (!FIELD_GET(NFP_NET_CFG_TLV_HEADER_REQUIRED, hdr))
+                               break;
+
+                       dev_err(dev, "unknown TLV type:%u offset:%u len:%u\n",
+                               FIELD_GET(NFP_NET_CFG_TLV_HEADER_TYPE, hdr),
+                               offset, length);
+                       return -EINVAL;
+               }
+
+               data += length;
+               if (data + 4 > end) {
+                       dev_err(dev, "reached end of BAR without END TLV\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* Not reached */
+       return -EINVAL;
+}
index 25c36001bffa6722854da55ff9d250ca3c97e7c1..cb058050e079be6f8aa804f4cce2621fd502e42f 100644 (file)
@@ -43,9 +43,7 @@
 #ifndef _NFP_NET_CTRL_H_
 #define _NFP_NET_CTRL_H_
 
-/* IMPORTANT: This header file is shared with the FW,
- *           no OS specific constructs, please!
- */
+#include <linux/types.h>
 
 /**
  * Configuration BAR size.
 #define NFP_NET_CFG_RSS_CAP            0x0054
 #define   NFP_NET_CFG_RSS_CAP_HFUNC      0xff000000
 
+/**
+ * TLV area start
+ * %NFP_NET_CFG_TLV_BASE:      start anchor of the TLV area
+ */
+#define NFP_NET_CFG_TLV_BASE           0x0058
+
 /**
  * VXLAN/UDP encap configuration
  * %NFP_NET_CFG_VXLAN_PORT:    Base address of table of tunnels' UDP dst ports
 #define  NFP_NET_CFG_VLAN_FILTER_PROTO  (NFP_NET_CFG_VLAN_FILTER + 2)
 #define NFP_NET_CFG_VLAN_FILTER_SZ      0x0004
 
+/**
+ * TLV capabilities
+ * %NFP_NET_CFG_TLV_TYPE:      Offset of type within the TLV
+ * %NFP_NET_CFG_TLV_TYPE_REQUIRED: Driver must be able to parse the TLV
+ * %NFP_NET_CFG_TLV_LENGTH:    Offset of length within the TLV
+ * %NFP_NET_CFG_TLV_LENGTH_INC:        TLV length increments
+ * %NFP_NET_CFG_TLV_VALUE:     Offset of value with the TLV
+ *
+ * List of simple TLV structures, first one starts at %NFP_NET_CFG_TLV_BASE.
+ * Last structure must be of type %NFP_NET_CFG_TLV_TYPE_END.  Presence of TLVs
+ * is indicated by %NFP_NET_CFG_TLV_BASE being non-zero.  TLV structures may
+ * fill the entire remainder of the BAR or be shorter.  FW must make sure TLVs
+ * don't conflict with other features which allocate space beyond
+ * %NFP_NET_CFG_TLV_BASE.  %NFP_NET_CFG_TLV_TYPE_RESERVED should be used to wrap
+ * space used by such features.
+ * Note that the 4 byte TLV header is not counted in %NFP_NET_CFG_TLV_LENGTH.
+ */
+#define NFP_NET_CFG_TLV_TYPE           0x00
+#define   NFP_NET_CFG_TLV_TYPE_REQUIRED          0x8000
+#define NFP_NET_CFG_TLV_LENGTH         0x02
+#define   NFP_NET_CFG_TLV_LENGTH_INC     4
+#define NFP_NET_CFG_TLV_VALUE          0x04
+
+#define NFP_NET_CFG_TLV_HEADER_REQUIRED        0x80000000
+#define NFP_NET_CFG_TLV_HEADER_TYPE    0x7fff0000
+#define NFP_NET_CFG_TLV_HEADER_LENGTH  0x0000ffff
+
+/**
+ * Capability TLV types
+ *
+ * %NFP_NET_CFG_TLV_TYPE_UNKNOWN:
+ * Special TLV type to catch bugs, should never be encountered.  Drivers should
+ * treat encountering this type as error and refuse to probe.
+ *
+ * %NFP_NET_CFG_TLV_TYPE_RESERVED:
+ * Reserved space, may contain legacy fixed-offset fields, or be used for
+ * padding.  The use of this type should be otherwise avoided.
+ *
+ * %NFP_NET_CFG_TLV_TYPE_END:
+ * Empty, end of TLV list.  Must be the last TLV.  Drivers will stop processing
+ * further TLVs when encountered.
+ */
+#define NFP_NET_CFG_TLV_TYPE_UNKNOWN           0
+#define NFP_NET_CFG_TLV_TYPE_RESERVED          1
+#define NFP_NET_CFG_TLV_TYPE_END               2
+
+struct device;
+
+/**
+ * struct nfp_net_tlv_caps - parsed control BAR TLV capabilities
+ */
+struct nfp_net_tlv_caps {
+};
+
+int nfp_net_tlv_caps_parse(struct device *dev, u8 __iomem *ctrl_mem,
+                          struct nfp_net_tlv_caps *caps);
+
 #endif /* _NFP_NET_CTRL_H_ */