Commit 73a0329b authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller

nfp: add TLV capabilities to the BAR

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: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: default avatarDirk van der Merwe <dirk.vandermerwe@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bf245f1f
...@@ -22,6 +22,7 @@ nfp-objs := \ ...@@ -22,6 +22,7 @@ nfp-objs := \
nfp_hwmon.o \ nfp_hwmon.o \
nfp_main.o \ nfp_main.o \
nfp_net_common.o \ nfp_net_common.o \
nfp_net_ctrl.o \
nfp_net_debugdump.o \ nfp_net_debugdump.o \
nfp_net_ethtool.o \ nfp_net_ethtool.o \
nfp_net_main.o \ nfp_net_main.o \
......
...@@ -578,6 +578,7 @@ struct nfp_net_dp { ...@@ -578,6 +578,7 @@ struct nfp_net_dp {
* @qcp_cfg: Pointer to QCP queue used for configuration notification * @qcp_cfg: Pointer to QCP queue used for configuration notification
* @tx_bar: Pointer to mapped TX queues * @tx_bar: Pointer to mapped TX queues
* @rx_bar: Pointer to mapped FL/RX queues * @rx_bar: Pointer to mapped FL/RX queues
* @tlv_caps: Parsed TLV capabilities
* @debugfs_dir: Device directory in debugfs * @debugfs_dir: Device directory in debugfs
* @vnic_list: Entry on device vNIC list * @vnic_list: Entry on device vNIC list
* @pdev: Backpointer to PCI device * @pdev: Backpointer to PCI device
...@@ -644,6 +645,8 @@ struct nfp_net { ...@@ -644,6 +645,8 @@ struct nfp_net {
u8 __iomem *tx_bar; u8 __iomem *tx_bar;
u8 __iomem *rx_bar; u8 __iomem *rx_bar;
struct nfp_net_tlv_caps tlv_caps;
struct dentry *debugfs_dir; struct dentry *debugfs_dir;
struct list_head vnic_list; struct list_head vnic_list;
......
...@@ -3815,6 +3815,11 @@ int nfp_net_init(struct nfp_net *nn) ...@@ -3815,6 +3815,11 @@ int nfp_net_init(struct nfp_net *nn)
nn->dp.ctrl |= NFP_NET_CFG_CTRL_IRQMOD; 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) if (nn->dp.netdev)
nfp_net_netdev_init(nn); nfp_net_netdev_init(nn);
......
/*
* 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;
}
...@@ -43,9 +43,7 @@ ...@@ -43,9 +43,7 @@
#ifndef _NFP_NET_CTRL_H_ #ifndef _NFP_NET_CTRL_H_
#define _NFP_NET_CTRL_H_ #define _NFP_NET_CTRL_H_
/* IMPORTANT: This header file is shared with the FW, #include <linux/types.h>
* no OS specific constructs, please!
*/
/** /**
* Configuration BAR size. * Configuration BAR size.
...@@ -235,6 +233,12 @@ ...@@ -235,6 +233,12 @@
#define NFP_NET_CFG_RSS_CAP 0x0054 #define NFP_NET_CFG_RSS_CAP 0x0054
#define NFP_NET_CFG_RSS_CAP_HFUNC 0xff000000 #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 * VXLAN/UDP encap configuration
* %NFP_NET_CFG_VXLAN_PORT: Base address of table of tunnels' UDP dst ports * %NFP_NET_CFG_VXLAN_PORT: Base address of table of tunnels' UDP dst ports
...@@ -429,4 +433,61 @@ ...@@ -429,4 +433,61 @@
#define NFP_NET_CFG_VLAN_FILTER_PROTO (NFP_NET_CFG_VLAN_FILTER + 2) #define NFP_NET_CFG_VLAN_FILTER_PROTO (NFP_NET_CFG_VLAN_FILTER + 2)
#define NFP_NET_CFG_VLAN_FILTER_SZ 0x0004 #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_ */ #endif /* _NFP_NET_CTRL_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment