summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2017-05-31 17:58:14 -0400
committerDavid S. Miller <davem@davemloft.net>2017-05-31 17:58:14 -0400
commitd2e0ef493ad953048bdf562b06cc4330b3fd9fb7 (patch)
treeb938a4f6c4eaaa6eaf9ee3088aaa4742a70489bc
parentc380e377a50e944a2b9a892133b5a37b3ec90fe3 (diff)
parent47eaa23b4c27d735cb797be71c711a99f99e9ff6 (diff)
downloadlinux-d2e0ef493ad953048bdf562b06cc4330b3fd9fb7.tar.bz2
Merge branch 'nfp-move-BPF-offload-code-into-app'
Jakub Kicinski says: ==================== nfp: move BPF offload code into app This series moves the eBPF offload code out of netdev/vNIC handling and starts building the nfp_app. Port init is moved into the apps as well because various apps associate vNICs, representors with ports differently. First patch adds a helper for updating tc stats which has been waiting in my tree to be included in any moderately related series. Next series will bring communicating with FW using control messages, then representors, BPF maps, tc flower... :) ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tc.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c10
-rw-r--r--drivers/net/ethernet/netronome/nfp/Makefile11
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/jit.c (renamed from drivers/net/ethernet/netronome/nfp/nfp_bpf_jit.c)4
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/main.c160
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/main.h (renamed from drivers/net/ethernet/netronome/nfp/nfp_bpf.h)23
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/offload.c (renamed from drivers/net/ethernet/netronome/nfp/nfp_net_offload.c)61
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/verifier.c (renamed from drivers/net/ethernet/netronome/nfp/nfp_bpf_verifier.c)2
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_app.c21
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_app.h120
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_app_nic.c86
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_asm.h2
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_main.c1
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_main.h6
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net.h16
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_common.c71
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c5
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_main.c86
-rw-r--r--drivers/net/ethernet/netronome/nfp/nic/main.c58
-rw-r--r--include/net/pkt_cls.h19
20 files changed, 600 insertions, 172 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
index d2f90ba2dbc4..7914a32a3036 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c
@@ -1863,9 +1863,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv,
{
struct mlx5e_tc_table *tc = &priv->fs.tc;
struct mlx5e_tc_flow *flow;
- struct tc_action *a;
struct mlx5_fc *counter;
- LIST_HEAD(actions);
u64 bytes;
u64 packets;
u64 lastuse;
@@ -1884,13 +1882,7 @@ int mlx5e_stats_flower(struct mlx5e_priv *priv,
mlx5_fc_query_cached(counter, &bytes, &packets, &lastuse);
- preempt_disable();
-
- tcf_exts_to_list(f->exts, &actions);
- list_for_each_entry(a, &actions, list)
- tcf_action_stats_update(a, bytes, packets, lastuse);
-
- preempt_enable();
+ tcf_exts_stats_update(f->exts, bytes, packets, lastuse);
return 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
index ed75c6a85bc3..13af8e358847 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_flower.c
@@ -397,8 +397,6 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
struct mlxsw_sp *mlxsw_sp = mlxsw_sp_port->mlxsw_sp;
struct mlxsw_sp_acl_ruleset *ruleset;
struct mlxsw_sp_acl_rule *rule;
- struct tc_action *a;
- LIST_HEAD(actions);
u64 packets;
u64 lastuse;
u64 bytes;
@@ -419,13 +417,7 @@ int mlxsw_sp_flower_stats(struct mlxsw_sp_port *mlxsw_sp_port, bool ingress,
if (err)
goto err_rule_get_stats;
- preempt_disable();
-
- tcf_exts_to_list(f->exts, &actions);
- list_for_each_entry(a, &actions, list)
- tcf_action_stats_update(a, bytes, packets, lastuse);
-
- preempt_enable();
+ tcf_exts_stats_update(f->exts, bytes, packets, lastuse);
mlxsw_sp_acl_ruleset_put(mlxsw_sp, ruleset);
return 0;
diff --git a/drivers/net/ethernet/netronome/nfp/Makefile b/drivers/net/ethernet/netronome/nfp/Makefile
index 83039c65e061..5ad9a557f06a 100644
--- a/drivers/net/ethernet/netronome/nfp/Makefile
+++ b/drivers/net/ethernet/netronome/nfp/Makefile
@@ -15,20 +15,23 @@ nfp-objs := \
nfpcore/nfp_rtsym.o \
nfpcore/nfp_target.o \
nfp_app.o \
+ nfp_app_nic.o \
nfp_devlink.o \
nfp_hwmon.o \
nfp_main.o \
nfp_net_common.o \
nfp_net_ethtool.o \
- nfp_net_offload.o \
nfp_net_main.o \
nfp_netvf_main.o \
- nfp_port.o
+ nfp_port.o \
+ bpf/main.o \
+ bpf/offload.o \
+ nic/main.o
ifeq ($(CONFIG_BPF_SYSCALL),y)
nfp-objs += \
- nfp_bpf_verifier.o \
- nfp_bpf_jit.o
+ bpf/verifier.o \
+ bpf/jit.o
endif
nfp-$(CONFIG_NFP_DEBUG) += nfp_net_debugfs.o
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_bpf_jit.c b/drivers/net/ethernet/netronome/nfp/bpf/jit.c
index 97a8f00674d0..8e57fda6b8b5 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_bpf_jit.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/jit.c
@@ -39,8 +39,8 @@
#include <linux/pkt_cls.h>
#include <linux/unistd.h>
-#include "nfp_asm.h"
-#include "nfp_bpf.h"
+#include "main.h"
+#include "../nfp_asm.h"
/* --- NFP prog --- */
/* Foreach "multiple" entries macros provide pos and next<n> pointers.
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.c b/drivers/net/ethernet/netronome/nfp/bpf/main.c
new file mode 100644
index 000000000000..afbdf5fd4e4f
--- /dev/null
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2017 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 <net/pkt_cls.h>
+
+#include "../nfpcore/nfp_cpp.h"
+#include "../nfp_app.h"
+#include "../nfp_main.h"
+#include "../nfp_net.h"
+#include "../nfp_port.h"
+#include "main.h"
+
+static bool nfp_net_ebpf_capable(struct nfp_net *nn)
+{
+ if (nn->cap & NFP_NET_CFG_CTRL_BPF &&
+ nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI)
+ return true;
+ return false;
+}
+
+static int
+nfp_bpf_xdp_offload(struct nfp_app *app, struct nfp_net *nn,
+ struct bpf_prog *prog)
+{
+ struct tc_cls_bpf_offload cmd = {
+ .prog = prog,
+ };
+ int ret;
+
+ if (!nfp_net_ebpf_capable(nn))
+ return -EINVAL;
+
+ if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) {
+ if (!nn->dp.bpf_offload_xdp)
+ return prog ? -EBUSY : 0;
+ cmd.command = prog ? TC_CLSBPF_REPLACE : TC_CLSBPF_DESTROY;
+ } else {
+ if (!prog)
+ return 0;
+ cmd.command = TC_CLSBPF_ADD;
+ }
+
+ ret = nfp_net_bpf_offload(nn, &cmd);
+ /* Stop offload if replace not possible */
+ if (ret && cmd.command == TC_CLSBPF_REPLACE)
+ nfp_bpf_xdp_offload(app, nn, NULL);
+ nn->dp.bpf_offload_xdp = prog && !ret;
+ return ret;
+}
+
+static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn)
+{
+ return nfp_net_ebpf_capable(nn) ? "BPF" : "";
+}
+
+static int
+nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
+{
+ struct nfp_net_bpf_priv *priv;
+ int ret;
+
+ /* Limit to single port, otherwise it's just a NIC */
+ if (id > 0) {
+ nfp_warn(app->cpp,
+ "BPF NIC doesn't support more than one port right now\n");
+ nn->port = nfp_port_alloc(app, NFP_PORT_INVALID, nn->dp.netdev);
+ return PTR_ERR_OR_ZERO(nn->port);
+ }
+
+ priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ nn->app_priv = priv;
+ spin_lock_init(&priv->rx_filter_lock);
+ setup_timer(&priv->rx_filter_stats_timer,
+ nfp_net_filter_stats_timer, (unsigned long)nn);
+
+ ret = nfp_app_nic_vnic_init(app, nn, id);
+ if (ret)
+ kfree(priv);
+
+ return ret;
+}
+
+static void nfp_bpf_vnic_clean(struct nfp_app *app, struct nfp_net *nn)
+{
+ if (nn->dp.bpf_offload_xdp)
+ nfp_bpf_xdp_offload(app, nn, NULL);
+ kfree(nn->app_priv);
+}
+
+static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
+ u32 handle, __be16 proto, struct tc_to_netdev *tc)
+{
+ struct nfp_net *nn = netdev_priv(netdev);
+
+ if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS))
+ return -EOPNOTSUPP;
+ if (proto != htons(ETH_P_ALL))
+ return -EOPNOTSUPP;
+
+ if (tc->type == TC_SETUP_CLSBPF && nfp_net_ebpf_capable(nn)) {
+ if (!nn->dp.bpf_offload_xdp)
+ return nfp_net_bpf_offload(nn, tc->cls_bpf);
+ else
+ return -EBUSY;
+ }
+
+ return -EINVAL;
+}
+
+static bool nfp_bpf_tc_busy(struct nfp_app *app, struct nfp_net *nn)
+{
+ return nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF;
+}
+
+const struct nfp_app_type app_bpf = {
+ .id = NFP_APP_BPF_NIC,
+ .name = "ebpf",
+
+ .extra_cap = nfp_bpf_extra_cap,
+
+ .vnic_init = nfp_bpf_vnic_init,
+ .vnic_clean = nfp_bpf_vnic_clean,
+
+ .setup_tc = nfp_bpf_setup_tc,
+ .tc_busy = nfp_bpf_tc_busy,
+ .xdp_offload = nfp_bpf_xdp_offload,
+};
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_bpf.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h
index 9513c80f7be5..4051e943f363 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_bpf.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h
@@ -39,6 +39,8 @@
#include <linux/list.h>
#include <linux/types.h>
+#include "../nfp_net.h"
+
/* For branch fixup logic use up-most byte of branch instruction as scratch
* area. Remember to clear this before sending instructions to HW!
*/
@@ -198,4 +200,25 @@ nfp_bpf_jit(struct bpf_prog *filter, void *prog, enum nfp_bpf_action_type act,
int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog);
+struct nfp_net;
+struct tc_cls_bpf_offload;
+
+/**
+ * struct nfp_net_bpf_priv - per-vNIC BPF private data
+ * @rx_filter: Filter offload statistics - dropped packets/bytes
+ * @rx_filter_prev: Filter offload statistics - values from previous update
+ * @rx_filter_change: Jiffies when statistics last changed
+ * @rx_filter_stats_timer: Timer for polling filter offload statistics
+ * @rx_filter_lock: Lock protecting timer state changes (teardown)
+ */
+struct nfp_net_bpf_priv {
+ struct nfp_stat_pair rx_filter, rx_filter_prev;
+ unsigned long rx_filter_change;
+ struct timer_list rx_filter_stats_timer;
+ spinlock_t rx_filter_lock;
+};
+
+int nfp_net_bpf_offload(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf);
+void nfp_net_filter_stats_timer(unsigned long data);
+
#endif
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_offload.c b/drivers/net/ethernet/netronome/nfp/bpf/offload.c
index cc823df12c8a..78d80a364edb 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_offload.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/offload.c
@@ -47,60 +47,59 @@
#include <net/tc_act/tc_gact.h>
#include <net/tc_act/tc_mirred.h>
-#include "nfp_bpf.h"
-#include "nfp_net_ctrl.h"
-#include "nfp_net.h"
+#include "main.h"
+#include "../nfp_net_ctrl.h"
+#include "../nfp_net.h"
void nfp_net_filter_stats_timer(unsigned long data)
{
struct nfp_net *nn = (void *)data;
+ struct nfp_net_bpf_priv *priv;
struct nfp_stat_pair latest;
- spin_lock_bh(&nn->rx_filter_lock);
+ priv = nn->app_priv;
+
+ spin_lock_bh(&priv->rx_filter_lock);
if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF)
- mod_timer(&nn->rx_filter_stats_timer,
+ mod_timer(&priv->rx_filter_stats_timer,
jiffies + NFP_NET_STAT_POLL_IVL);
- spin_unlock_bh(&nn->rx_filter_lock);
+ spin_unlock_bh(&priv->rx_filter_lock);
latest.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES);
latest.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES);
- if (latest.pkts != nn->rx_filter.pkts)
- nn->rx_filter_change = jiffies;
+ if (latest.pkts != priv->rx_filter.pkts)
+ priv->rx_filter_change = jiffies;
- nn->rx_filter = latest;
+ priv->rx_filter = latest;
}
static void nfp_net_bpf_stats_reset(struct nfp_net *nn)
{
- nn->rx_filter.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES);
- nn->rx_filter.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES);
- nn->rx_filter_prev = nn->rx_filter;
- nn->rx_filter_change = jiffies;
+ struct nfp_net_bpf_priv *priv = nn->app_priv;
+
+ priv->rx_filter.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES);
+ priv->rx_filter.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES);
+ priv->rx_filter_prev = priv->rx_filter;
+ priv->rx_filter_change = jiffies;
}
static int
nfp_net_bpf_stats_update(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf)
{
- struct tc_action *a;
- LIST_HEAD(actions);
+ struct nfp_net_bpf_priv *priv = nn->app_priv;
u64 bytes, pkts;
- pkts = nn->rx_filter.pkts - nn->rx_filter_prev.pkts;
- bytes = nn->rx_filter.bytes - nn->rx_filter_prev.bytes;
+ pkts = priv->rx_filter.pkts - priv->rx_filter_prev.pkts;
+ bytes = priv->rx_filter.bytes - priv->rx_filter_prev.bytes;
bytes -= pkts * ETH_HLEN;
- nn->rx_filter_prev = nn->rx_filter;
+ priv->rx_filter_prev = priv->rx_filter;
- preempt_disable();
-
- tcf_exts_to_list(cls_bpf->exts, &actions);
- list_for_each_entry(a, &actions, list)
- tcf_action_stats_update(a, bytes, pkts, nn->rx_filter_change);
-
- preempt_enable();
+ tcf_exts_stats_update(cls_bpf->exts,
+ bytes, pkts, priv->rx_filter_change);
return 0;
}
@@ -190,6 +189,7 @@ nfp_net_bpf_load_and_start(struct nfp_net *nn, u32 tc_flags,
unsigned int code_sz, unsigned int n_instr,
bool dense_mode)
{
+ struct nfp_net_bpf_priv *priv = nn->app_priv;
u64 bpf_addr = dma_addr;
int err;
@@ -216,20 +216,23 @@ nfp_net_bpf_load_and_start(struct nfp_net *nn, u32 tc_flags,
dma_free_coherent(nn->dp.dev, code_sz, code, dma_addr);
nfp_net_bpf_stats_reset(nn);
- mod_timer(&nn->rx_filter_stats_timer, jiffies + NFP_NET_STAT_POLL_IVL);
+ mod_timer(&priv->rx_filter_stats_timer,
+ jiffies + NFP_NET_STAT_POLL_IVL);
}
static int nfp_net_bpf_stop(struct nfp_net *nn)
{
+ struct nfp_net_bpf_priv *priv = nn->app_priv;
+
if (!(nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF))
return 0;
- spin_lock_bh(&nn->rx_filter_lock);
+ spin_lock_bh(&priv->rx_filter_lock);
nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_BPF;
- spin_unlock_bh(&nn->rx_filter_lock);
+ spin_unlock_bh(&priv->rx_filter_lock);
nn_writel(nn, NFP_NET_CFG_CTRL, nn->dp.ctrl);
- del_timer_sync(&nn->rx_filter_stats_timer);
+ del_timer_sync(&priv->rx_filter_stats_timer);
nn->dp.bpf_offload_skip_sw = 0;
return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN);
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_bpf_verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
index b3361f9b8e5c..d696ba46f70a 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_bpf_verifier.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
@@ -38,7 +38,7 @@
#include <linux/kernel.h>
#include <linux/pkt_cls.h>
-#include "nfp_bpf.h"
+#include "main.h"
/* Analyzer/verifier definitions */
struct nfp_bpf_analyzer_priv {
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.c b/drivers/net/ethernet/netronome/nfp/nfp_app.c
index 59be638bb60e..cea2090cf063 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_app.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c
@@ -33,12 +33,30 @@
#include <linux/slab.h>
+#include "nfpcore/nfp_cpp.h"
#include "nfp_app.h"
#include "nfp_main.h"
-struct nfp_app *nfp_app_alloc(struct nfp_pf *pf)
+static const struct nfp_app_type *apps[] = {
+ &app_nic,
+ &app_bpf,
+};
+
+struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id)
{
struct nfp_app *app;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(apps); i++)
+ if (apps[i]->id == id)
+ break;
+ if (i == ARRAY_SIZE(apps)) {
+ nfp_err(pf->cpp, "failed to find app with ID 0x%02hhx\n", id);
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (WARN_ON(!apps[i]->name || !apps[i]->vnic_init))
+ return ERR_PTR(-EINVAL);
app = kzalloc(sizeof(*app), GFP_KERNEL);
if (!app)
@@ -47,6 +65,7 @@ struct nfp_app *nfp_app_alloc(struct nfp_pf *pf)
app->pf = pf;
app->cpp = pf->cpp;
app->pdev = pf->pdev;
+ app->type = apps[i];
return app;
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app.h b/drivers/net/ethernet/netronome/nfp/nfp_app.h
index e63425c02c8d..13efdefffa1a 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_app.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_app.h
@@ -34,23 +34,141 @@
#ifndef _NFP_APP_H
#define _NFP_APP_H 1
+struct bpf_prog;
+struct net_device;
struct pci_dev;
+struct tc_to_netdev;
+struct nfp_app;
struct nfp_cpp;
struct nfp_pf;
+struct nfp_net;
+
+enum nfp_app_id {
+ NFP_APP_CORE_NIC = 0x1,
+ NFP_APP_BPF_NIC = 0x2,
+};
+
+extern const struct nfp_app_type app_nic;
+extern const struct nfp_app_type app_bpf;
+
+/**
+ * struct nfp_app_type - application definition
+ * @id: application ID
+ * @name: application name
+ *
+ * Callbacks
+ * @init: perform basic app checks
+ * @extra_cap: extra capabilities string
+ * @vnic_init: init vNICs (assign port types, etc.)
+ * @vnic_clean: clean up app's vNIC state
+ * @setup_tc: setup TC ndo
+ * @tc_busy: TC HW offload busy (rules loaded)
+ * @xdp_offload: offload an XDP program
+ */
+struct nfp_app_type {
+ enum nfp_app_id id;
+ const char *name;
+
+ int (*init)(struct nfp_app *app);
+
+ const char *(*extra_cap)(struct nfp_app *app, struct nfp_net *nn);
+
+ int (*vnic_init)(struct nfp_app *app, struct nfp_net *nn,
+ unsigned int id);
+ void (*vnic_clean)(struct nfp_app *app, struct nfp_net *nn);
+
+ int (*setup_tc)(struct nfp_app *app, struct net_device *netdev,
+ u32 handle, __be16 proto, struct tc_to_netdev *tc);
+ bool (*tc_busy)(struct nfp_app *app, struct nfp_net *nn);
+ int (*xdp_offload)(struct nfp_app *app, struct nfp_net *nn,
+ struct bpf_prog *prog);
+};
/**
* struct nfp_app - NFP application container
* @pdev: backpointer to PCI device
* @pf: backpointer to NFP PF structure
* @cpp: pointer to the CPP handle
+ * @type: pointer to const application ops and info
*/
struct nfp_app {
struct pci_dev *pdev;
struct nfp_pf *pf;
struct nfp_cpp *cpp;
+
+ const struct nfp_app_type *type;
};
-struct nfp_app *nfp_app_alloc(struct nfp_pf *pf);
+static inline int nfp_app_init(struct nfp_app *app)
+{
+ if (!app->type->init)
+ return 0;
+ return app->type->init(app);
+}
+
+static inline int nfp_app_vnic_init(struct nfp_app *app, struct nfp_net *nn,
+ unsigned int id)
+{
+ return app->type->vnic_init(app, nn, id);
+}
+
+static inline void nfp_app_vnic_clean(struct nfp_app *app, struct nfp_net *nn)
+{
+ if (app->type->vnic_clean)
+ app->type->vnic_clean(app, nn);
+}
+
+static inline const char *nfp_app_name(struct nfp_app *app)
+{
+ if (!app)
+ return "";
+ return app->type->name;
+}
+
+static inline const char *nfp_app_extra_cap(struct nfp_app *app,
+ struct nfp_net *nn)
+{
+ if (!app || !app->type->extra_cap)
+ return "";
+ return app->type->extra_cap(app, nn);
+}
+
+static inline bool nfp_app_has_tc(struct nfp_app *app)
+{
+ return app && app->type->setup_tc;
+}
+
+static inline bool nfp_app_tc_busy(struct nfp_app *app, struct nfp_net *nn)
+{
+ if (!app || !app->type->tc_busy)
+ return false;
+ return app->type->tc_busy(app, nn);
+}
+
+static inline int nfp_app_setup_tc(struct nfp_app *app,
+ struct net_device *netdev,
+ u32 handle, __be16 proto,
+ struct tc_to_netdev *tc)
+{
+ if (!app || !app->type->setup_tc)
+ return -EOPNOTSUPP;
+ return app->type->setup_tc(app, netdev, handle, proto, tc);
+}
+
+static inline int nfp_app_xdp_offload(struct nfp_app *app, struct nfp_net *nn,
+ struct bpf_prog *prog)
+{
+ if (!app || !app->type->xdp_offload)
+ return -EOPNOTSUPP;
+ return app->type->xdp_offload(app, nn, prog);
+}
+
+struct nfp_app *nfp_app_alloc(struct nfp_pf *pf, enum nfp_app_id id);
void nfp_app_free(struct nfp_app *app);
+/* Callbacks shared between apps */
+
+int nfp_app_nic_vnic_init(struct nfp_app *app, struct nfp_net *nn,
+ unsigned int id);
+
#endif
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c
new file mode 100644
index 000000000000..1a33ad9f4170
--- /dev/null
+++ b/drivers/net/ethernet/netronome/nfp/nfp_app_nic.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 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 "nfpcore/nfp_cpp.h"
+#include "nfpcore/nfp_nsp.h"
+#include "nfp_app.h"
+#include "nfp_main.h"
+#include "nfp_net.h"
+#include "nfp_port.h"
+
+static int
+nfp_app_nic_vnic_init_phy_port(struct nfp_pf *pf, struct nfp_app *app,
+ struct nfp_net *nn, unsigned int id)
+{
+ if (!pf->eth_tbl)
+ return 0;
+
+ nn->port = nfp_port_alloc(app, NFP_PORT_PHYS_PORT, nn->dp.netdev);
+ if (IS_ERR(nn->port))
+ return PTR_ERR(nn->port);
+
+ nn->port->eth_id = id;
+ nn->port->eth_port = nfp_net_find_port(pf->eth_tbl, id);
+
+ /* Check if vNIC has external port associated and cfg is OK */
+ if (!nn->port->eth_port) {
+ nfp_err(app->cpp,
+ "NSP port entries don't match vNICs (no entry for port #%d)\n",
+ id);
+ nfp_port_free(nn->port);
+ return -EINVAL;
+ }
+ if (nn->port->eth_port->override_changed) {
+ nfp_warn(app->cpp,
+ "Config changed for port #%d, reboot required before port will be operational\n",
+ id);
+ nn->port->type = NFP_PORT_INVALID;
+ return 1;
+ }
+
+ return 0;
+}
+
+int nfp_app_nic_vnic_init(struct nfp_app *app, struct nfp_net *nn,
+ unsigned int id)
+{
+ int err;
+
+ err = nfp_app_nic_vnic_init_phy_port(app->pf, app, nn, id);
+ if (err)
+ return err < 0 ? err : 0;
+
+ nfp_net_get_mac_addr(nn, app->cpp, id);
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_asm.h b/drivers/net/ethernet/netronome/nfp/nfp_asm.h
index 22484b6fd3e8..d2b535739d2b 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_asm.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_asm.h
@@ -34,7 +34,7 @@
#ifndef __NFP_ASM_H__
#define __NFP_ASM_H__ 1
-#include "nfp_bpf.h"
+#include <linux/types.h>
#define REG_NONE 0
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.c b/drivers/net/ethernet/netronome/nfp/nfp_main.c
index 68cd34d5a9fb..0c2e64d217b5 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_main.c
@@ -279,6 +279,7 @@ static int nfp_nsp_init(struct pci_dev *pdev, struct nfp_pf *pf)
err = nfp_fw_load(pdev, pf, nsp);
if (err < 0) {
+ kfree(pf->nspi);
kfree(pf->eth_tbl);
dev_err(&pdev->dev, "Failed to load FW\n");
goto exit_close_nsp;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_main.h b/drivers/net/ethernet/netronome/nfp/nfp_main.h
index 20fad76da5aa..c46d00bbf19d 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_main.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_main.h
@@ -54,6 +54,7 @@ struct pci_dev;
struct nfp_cpp;
struct nfp_cpp_area;
struct nfp_eth_table;
+struct nfp_net;
struct nfp_nsp_identify;
/**
@@ -123,4 +124,9 @@ void nfp_net_pci_remove(struct nfp_pf *pf);
int nfp_hwmon_register(struct nfp_pf *pf);
void nfp_hwmon_unregister(struct nfp_pf *pf);
+struct nfp_eth_table_port *
+nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id);
+void
+nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id);
+
#endif /* NFP_MAIN_H */
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h
index cb7114309656..2e526338f678 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h
@@ -517,11 +517,6 @@ struct nfp_net_dp {
* @rss_cfg: RSS configuration
* @rss_key: RSS secret key
* @rss_itbl: RSS indirection table
- * @rx_filter: Filter offload statistics - dropped packets/bytes
- * @rx_filter_prev: Filter offload statistics - values from previous update
- * @rx_filter_change: Jiffies when statistics last changed
- * @rx_filter_stats_timer: Timer for polling filter offload statistics
- * @rx_filter_lock: Lock protecting timer state changes (teardown)
* @max_r_vecs: Number of allocated interrupt vectors for RX/TX
* @max_tx_rings: Maximum number of TX rings supported by the Firmware
* @max_rx_rings: Maximum number of RX rings supported by the Firmware
@@ -556,6 +551,7 @@ struct nfp_net_dp {
* @pdev: Backpointer to PCI device
* @app: APP handle if available
* @port: Pointer to nfp_port structure if vNIC is a port
+ * @app_priv: APP private data for this vNIC
*/
struct nfp_net {
struct nfp_net_dp dp;
@@ -570,11 +566,6 @@ struct nfp_net {
u8 rss_key[NFP_NET_CFG_RSS_KEY_SZ];
u8 rss_itbl[NFP_NET_CFG_RSS_ITBL_SZ];
- struct nfp_stat_pair rx_filter, rx_filter_prev;
- unsigned long rx_filter_change;
- struct timer_list rx_filter_stats_timer;
- spinlock_t rx_filter_lock;
-
unsigned int max_tx_rings;
unsigned int max_rx_rings;
@@ -627,6 +618,8 @@ struct nfp_net {
struct nfp_app *app;
struct nfp_port *port;
+
+ void *app_priv;
};
/* Functions to read/write from/to a BAR
@@ -867,7 +860,4 @@ static inline void nfp_net_debugfs_dir_clean(struct dentry **dir)
}
#endif /* CONFIG_NFP_DEBUG */
-void nfp_net_filter_stats_timer(unsigned long data);
-int nfp_net_bpf_offload(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf);
-
#endif /* _NFP_NET_H_ */
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index c9a140376621..c3235d03b8eb 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -64,10 +64,10 @@
#include <linux/ktime.h>
-#include <net/pkt_cls.h>
#include <net/vxlan.h>
#include "nfpcore/nfp_nsp.h"
+#include "nfp_app.h"
#include "nfp_net_ctrl.h"
#include "nfp_net.h"
#include "nfp_port.h"
@@ -1687,8 +1687,10 @@ static int nfp_net_rx(struct nfp_net_rx_ring *rx_ring, int budget)
continue;
default:
bpf_warn_invalid_xdp_action(act);
+ /* fall through */
case XDP_ABORTED:
trace_xdp_exception(dp->netdev, xdp_prog, act);
+ /* fall through */
case XDP_DROP:
nfp_net_rx_give_one(dp, rx_ring, rxbuf->frag,
rxbuf->dma_addr);
@@ -2679,33 +2681,13 @@ static void nfp_net_stat64(struct net_device *netdev,
}
}
-static bool nfp_net_ebpf_capable(struct nfp_net *nn)
-{
- if (nn->cap & NFP_NET_CFG_CTRL_BPF &&
- nn_readb(nn, NFP_NET_CFG_BPF_ABI) == NFP_NET_BPF_ABI)
- return true;
- return false;
-}
-
static int
nfp_net_setup_tc(struct net_device *netdev, u32 handle, __be16 proto,
struct tc_to_netdev *tc)
{
struct nfp_net *nn = netdev_priv(netdev);
- if (TC_H_MAJ(handle) != TC_H_MAJ(TC_H_INGRESS))
- return -EOPNOTSUPP;
- if (proto != htons(ETH_P_ALL))
- return -EOPNOTSUPP;
-
- if (tc->type == TC_SETUP_CLSBPF && nfp_net_ebpf_capable(nn)) {
- if (!nn->dp.bpf_offload_xdp)
- return nfp_net_bpf_offload(nn, tc->cls_bpf);
- else
- return -EBUSY;
- }
-
- return -EINVAL;
+ return nfp_app_setup_tc(nn->app, netdev, handle, proto, tc);
}
static int nfp_net_set_features(struct net_device *netdev,
@@ -2763,7 +2745,7 @@ static int nfp_net_set_features(struct net_device *netdev,
new_ctrl &= ~NFP_NET_CFG_CTRL_GATHER;
}
- if (changed & NETIF_F_HW_TC && nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) {
+ if (changed & NETIF_F_HW_TC && nfp_app_tc_busy(nn->app, nn)) {
nn_err(nn, "Cannot disable HW TC offload while in use\n");
return -EBUSY;
}
@@ -2912,34 +2894,6 @@ static void nfp_net_del_vxlan_port(struct net_device *netdev,
nfp_net_set_vxlan_port(nn, idx, 0);
}
-static int nfp_net_xdp_offload(struct nfp_net *nn, struct bpf_prog *prog)
-{
- struct tc_cls_bpf_offload cmd = {
- .prog = prog,
- };
- int ret;
-
- if (!nfp_net_ebpf_capable(nn))
- return -EINVAL;
-
- if (nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF) {
- if (!nn->dp.bpf_offload_xdp)
- return prog ? -EBUSY : 0;
- cmd.command = prog ? TC_CLSBPF_REPLACE : TC_CLSBPF_DESTROY;
- } else {
- if (!prog)
- return 0;
- cmd.command = TC_CLSBPF_ADD;
- }
-
- ret = nfp_net_bpf_offload(nn, &cmd);
- /* Stop offload if replace not possible */
- if (ret && cmd.command == TC_CLSBPF_REPLACE)
- nfp_net_xdp_offload(nn, NULL);
- nn->dp.bpf_offload_xdp = prog && !ret;
- return ret;
-}
-
static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp)
{
struct bpf_prog *old_prog = nn->dp.xdp_prog;
@@ -2952,7 +2906,7 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp)
if (prog && nn->dp.xdp_prog) {
prog = xchg(&nn->dp.xdp_prog, prog);
bpf_prog_put(prog);
- nfp_net_xdp_offload(nn, nn->dp.xdp_prog);
+ nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog);
return 0;
}
@@ -2973,7 +2927,7 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp)
if (old_prog)
bpf_prog_put(old_prog);
- nfp_net_xdp_offload(nn, nn->dp.xdp_prog);
+ nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog);
return 0;
}
@@ -3066,10 +3020,10 @@ void nfp_net_info(struct nfp_net *nn)
nn->cap & NFP_NET_CFG_CTRL_IRQMOD ? "IRQMOD " : "",
nn->cap & NFP_NET_CFG_CTRL_VXLAN ? "VXLAN " : "",
nn->cap & NFP_NET_CFG_CTRL_NVGRE ? "NVGRE " : "",
- nfp_net_ebpf_capable(nn) ? "BPF " : "",
nn->cap & NFP_NET_CFG_CTRL_CSUM_COMPLETE ?
"RXCSUM_COMPLETE " : "",
- nn->cap & NFP_NET_CFG_CTRL_LIVE_ADDR ? "LIVE_ADDR " : "");
+ nn->cap & NFP_NET_CFG_CTRL_LIVE_ADDR ? "LIVE_ADDR " : "",
+ nfp_app_extra_cap(nn->app, nn));
}
/**
@@ -3118,13 +3072,10 @@ struct nfp_net *nfp_net_alloc(struct pci_dev *pdev,
nn->dp.rxd_cnt = NFP_NET_RX_DESCS_DEFAULT;
spin_lock_init(&nn->reconfig_lock);
- spin_lock_init(&nn->rx_filter_lock);
spin_lock_init(&nn->link_status_lock);
setup_timer(&nn->reconfig_timer,
nfp_net_reconfig_timer, (unsigned long)nn);
- setup_timer(&nn->rx_filter_stats_timer,
- nfp_net_filter_stats_timer, (unsigned long)nn);
return nn;
}
@@ -3314,7 +3265,7 @@ int nfp_net_init(struct nfp_net *nn)
netdev->features = netdev->hw_features;
- if (nfp_net_ebpf_capable(nn))
+ if (nfp_app_has_tc(nn->app))
netdev->hw_features |= NETIF_F_HW_TC;
/* Advertise but disable TSO by default. */
@@ -3371,6 +3322,4 @@ void nfp_net_clean(struct nfp_net *nn)
if (nn->dp.xdp_prog)
bpf_prog_put(nn->dp.xdp_prog);
- if (nn->dp.bpf_offload_xdp)
- nfp_net_xdp_offload(nn, NULL);
}
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
index 84fdbc4b835b..83664ca25213 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c
@@ -166,9 +166,10 @@ static void nfp_net_get_drvinfo(struct net_device *netdev,
nfp_net_get_nspinfo(nn->app, nsp_version);
snprintf(drvinfo->fw_version, sizeof(drvinfo->fw_version),
- "%d.%d.%d.%d %s",
+ "%d.%d.%d.%d %s %s",
nn->fw_ver.resv, nn->fw_ver.class,
- nn->fw_ver.major, nn->fw_ver.minor, nsp_version);
+ nn->fw_ver.major, nn->fw_ver.minor, nsp_version,
+ nfp_app_name(nn->app));
strlcpy(drvinfo->bus_info, pci_name(nn->pdev),
sizeof(drvinfo->bus_info));
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
index 388759e047d8..7dd310911d9f 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_main.c
@@ -141,7 +141,7 @@ err_area:
* First try to get the MAC address from NSP ETH table. If that
* fails try HWInfo. As a last resort generate a random address.
*/
-static void
+void
nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id)
{
struct nfp_eth_table_port *eth_port;
@@ -179,7 +179,7 @@ nfp_net_get_mac_addr(struct nfp_net *nn, struct nfp_cpp *cpp, unsigned int id)
ether_addr_copy(dp->netdev->perm_addr, mac_addr);
}
-static struct nfp_eth_table_port *
+struct nfp_eth_table_port *
nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id)
{
int i;
@@ -191,26 +191,38 @@ nfp_net_find_port(struct nfp_eth_table *eth_tbl, unsigned int id)
return NULL;
}
-static unsigned int nfp_net_pf_get_num_ports(struct nfp_pf *pf)
+static int
+nfp_net_pf_rtsym_read_optional(struct nfp_pf *pf, const char *format,
+ unsigned int default_val)
{
char name[256];
int err = 0;
u64 val;
- snprintf(name, sizeof(name), "nfd_cfg_pf%u_num_ports",
- nfp_cppcore_pcie_unit(pf->cpp));
+ snprintf(name, sizeof(name), format, nfp_cppcore_pcie_unit(pf->cpp));
val = nfp_rtsym_read_le(pf->cpp, name, &err);
- /* Default to one port/vNIC */
if (err) {
- if (err != -ENOENT)
- nfp_err(pf->cpp, "Unable to read adapter vNIC count\n");
- val = 1;
+ if (err == -ENOENT)
+ return default_val;
+ nfp_err(pf->cpp, "Unable to read symbol %s\n", name);
+ return err;
}
return val;
}
+static int nfp_net_pf_get_num_ports(struct nfp_pf *pf)
+{
+ return nfp_net_pf_rtsym_read_optional(pf, "nfd_cfg_pf%u_num_ports", 1);
+}
+
+static int nfp_net_pf_get_app_id(struct nfp_pf *pf)
+{
+ return nfp_net_pf_rtsym_read_optional(pf, "_pf%u_net_app_id",
+ NFP_APP_CORE_NIC);
+}
+
static unsigned int
nfp_net_pf_total_qcs(struct nfp_pf *pf, void __iomem *ctrl_bar,
unsigned int stride, u32 start_off, u32 num_off)
@@ -296,9 +308,9 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar,
int stride, struct nfp_net_fw_version *fw_ver,
unsigned int eth_id)
{
- struct nfp_eth_table_port *eth_port;
u32 n_tx_rings, n_rx_rings;
struct nfp_net *nn;
+ int err;
n_tx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_TXRINGS);
n_rx_rings = readl(ctrl_bar + NFP_NET_CFG_MAX_RXRINGS);
@@ -317,16 +329,10 @@ nfp_net_pf_alloc_vnic(struct nfp_pf *pf, void __iomem *ctrl_bar,
nn->stride_rx = stride;
nn->stride_tx = stride;
- eth_port = nfp_net_find_port(pf->eth_tbl, eth_id);
- if (eth_port) {
- nn->port = nfp_port_alloc(pf->app, NFP_PORT_PHYS_PORT,
- nn->dp.netdev);
- if (IS_ERR(nn->port)) {
- nfp_net_free(nn);
- return ERR_CAST(nn->port);
- }
- nn->port->eth_id = eth_id;
- nn->port->eth_port = eth_port;
+ err = nfp_app_vnic_init(pf->app, nn, eth_id);
+ if (err) {
+ nfp_net_free(nn);
+ return ERR_PTR(err);
}
pf->num_vnics++;
@@ -340,9 +346,6 @@ nfp_net_pf_init_vnic(struct nfp_pf *pf, struct nfp_net *nn, unsigned int id)
{
int err;
- /* Get MAC address */
- nfp_net_get_mac_addr(nn, pf->cpp, id);
-
/* Get ME clock frequency from ctrl BAR
* XXX for now frequency is hardcoded until we figure out how
* to get the value from nfp-hwinfo into ctrl bar
@@ -381,12 +384,6 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar,
unsigned int i;
int err;
- if (pf->eth_tbl && pf->max_data_vnics != pf->eth_tbl->count) {
- nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n",
- pf->max_data_vnics, pf->eth_tbl->count);
- return -EINVAL;
- }
-
prev_tx_base = readl(ctrl_bar + NFP_NET_CFG_START_TXQ);
prev_rx_base = readl(ctrl_bar + NFP_NET_CFG_START_RXQ);
@@ -407,14 +404,8 @@ nfp_net_pf_alloc_vnics(struct nfp_pf *pf, void __iomem *ctrl_bar,
ctrl_bar += NFP_PF_CSR_SLICE_SIZE;
- /* Check if vNIC has external port associated and cfg is OK */
- if (pf->eth_tbl && !nn->port) {
- nfp_err(pf->cpp, "NSP port entries don't match vNICs (no entry for port #%d)\n", i);
- err = -EINVAL;
- goto err_free_prev;
- }
- if (nn->port && nn->port->eth_port->override_changed) {
- nfp_warn(pf->cpp, "Config changed for port #%d, reboot required before port will be operational\n", i);
+ /* Kill the vNIC if app init marked it as invalid */
+ if (nn->port && nn->port->type == NFP_PORT_INVALID) {
nfp_net_pf_free_vnic(pf, nn);
continue;
}
@@ -436,6 +427,7 @@ static void nfp_net_pf_clean_vnic(struct nfp_pf *pf, struct nfp_net *nn)
nfp_devlink_port_unregister(nn->port);
nfp_net_debugfs_dir_clean(&nn->debugfs_dir);
nfp_net_clean(nn);
+ nfp_app_vnic_clean(pf->app, nn);
}
static int
@@ -512,9 +504,21 @@ err_nn_free:
static int nfp_net_pf_app_init(struct nfp_pf *pf)
{
- pf->app = nfp_app_alloc(pf);
+ int err;
- return PTR_ERR_OR_ZERO(pf->app);
+ pf->app = nfp_app_alloc(pf, nfp_net_pf_get_app_id(pf));
+ if (IS_ERR(pf->app))
+ return PTR_ERR(pf->app);
+
+ err = nfp_app_init(pf->app);
+ if (err)
+ goto err_free;
+
+ return 0;
+
+err_free:
+ nfp_app_free(pf->app);
+ return err;
}
static void nfp_net_pf_app_clean(struct nfp_pf *pf)
@@ -675,6 +679,10 @@ int nfp_net_pci_probe(struct nfp_pf *pf)
mutex_lock(&pf->lock);
pf->max_data_vnics = nfp_net_pf_get_num_ports(pf);
+ if ((int)pf->max_data_vnics < 0) {
+ err = pf->max_data_vnics;
+ goto err_unlock;
+ }
ctrl_bar = nfp_net_pf_map_ctrl_bar(pf);
if (!ctrl_bar) {
diff --git a/drivers/net/ethernet/netronome/nfp/nic/main.c b/drivers/net/ethernet/netronome/nfp/nic/main.c
new file mode 100644
index 000000000000..520684242b7d
--- /dev/null
+++ b/drivers/net/ethernet/netronome/nfp/nic/main.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 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 "../nfpcore/nfp_cpp.h"
+#include "../nfpcore/nfp_nsp.h"
+#include "../nfp_app.h"
+#include "../nfp_main.h"
+
+static int nfp_nic_init(struct nfp_app *app)
+{
+ struct nfp_pf *pf = app->pf;
+
+ if (pf->eth_tbl && pf->max_data_vnics != pf->eth_tbl->count) {
+ nfp_err(pf->cpp, "ETH entries don't match vNICs (%d vs %d)\n",
+ pf->max_data_vnics, pf->eth_tbl->count);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+const struct nfp_app_type app_nic = {
+ .id = NFP_APP_CORE_NIC,
+ .name = "nic",
+
+ .init = nfp_nic_init,
+ .vnic_init = nfp_app_nic_vnic_init,
+};
diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h
index f7762295b7b8..537d0a0ad4c4 100644
--- a/include/net/pkt_cls.h
+++ b/include/net/pkt_cls.h
@@ -157,6 +157,25 @@ static inline void tcf_exts_to_list(const struct tcf_exts *exts,
#endif
}
+static inline void
+tcf_exts_stats_update(const struct tcf_exts *exts,
+ u64 bytes, u64 packets, u64 lastuse)
+{
+#ifdef CONFIG_NET_CLS_ACT
+ int i;
+
+ preempt_disable();
+
+ for (i = 0; i < exts->nr_actions; i++) {
+ struct tc_action *a = exts->actions[i];
+
+ tcf_action_stats_update(a, bytes, packets, lastuse);
+ }
+
+ preempt_enable();
+#endif
+}
+
/**
* tcf_exts_exec - execute tc filter extensions
* @skb: socket buffer