Commit d2e0ef49 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents c380e377 47eaa23b
......@@ -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;
}
......
......@@ -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;
......
......@@ -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
......@@ -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.
......
/*
* 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,
};
......@@ -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
......@@ -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);
......
......@@ -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 {
......
......@@ -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;
}
......
......@@ -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
/*
* 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;
}
......@@ -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
......
......@@ -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;
......
......@@ -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 */
......@@ -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_ */
......@@ -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);
}
......@@ -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));
......
......@@ -141,7 +141,7 @@ static u8 __iomem *nfp_net_map_area(struct nfp_cpp *cpp,
* 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 @@ nfp_net_pf_spawn_vnics(struct nfp_pf *pf,
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) {
......
/*
* 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,
};
......@@ -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
......
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