diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index d2f90ba2dbc404fc2506d0400f7131420e3dd403..7914a32a3036e5bd6bf621414ab4eccc9e22c2f9 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 ed75c6a85bc3635be11a6083451658cd54010bb7..13af8e3588479b31903345ff94e4634cb3d1060c 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 83039c65e0619b37588326f2e15c8e67e504c2e3..5ad9a557f06a29aaf15f14db39b92927b4d9642a 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 similarity index 99% rename from drivers/net/ethernet/netronome/nfp/nfp_bpf_jit.c rename to drivers/net/ethernet/netronome/nfp/bpf/jit.c index 97a8f00674d01c46901f8c8bdb7e59207dd39422..8e57fda6b8b54135729fc0a4a356a0411adfd304 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 #include -#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 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 0000000000000000000000000000000000000000..afbdf5fd4e4feed91852e150f8c6ef53894900ff --- /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 + +#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 similarity index 88% rename from drivers/net/ethernet/netronome/nfp/nfp_bpf.h rename to drivers/net/ethernet/netronome/nfp/bpf/main.h index 9513c80f7be5c9bfa2ddc4802ebe6cc508f43c52..4051e943f3633049f3aba599cf3478e3b30a7e4e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_bpf.h +++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h @@ -39,6 +39,8 @@ #include #include +#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 similarity index 85% rename from drivers/net/ethernet/netronome/nfp/nfp_net_offload.c rename to drivers/net/ethernet/netronome/nfp/bpf/offload.c index cc823df12c8a83b3ef6f2f33f9c53a062d45be71..78d80a364edb4cdb0f1b301e7fdf02232d050cdd 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 #include -#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 similarity index 99% rename from drivers/net/ethernet/netronome/nfp/nfp_bpf_verifier.c rename to drivers/net/ethernet/netronome/nfp/bpf/verifier.c index b3361f9b8e5c156c9ce58b156126993e5258fa68..d696ba46f70a6511bea71764cf1dd9578c287929 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 #include -#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 59be638bb60e002bd709cba4d160e1e94e755c8e..cea2090cf063e9d2df892c2932a197d809e31467 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_app.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_app.c @@ -33,12 +33,30 @@ #include +#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 e63425c02c8dcaeb63af466caf0e488d20f69791..13efdefffa1addb1257b174571c6d805766bdae5 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 0000000000000000000000000000000000000000..1a33ad9f4170c0f75e4af35e9a38902b620185a6 --- /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 22484b6fd3e8bb5dd6497defade140fcf9495faa..d2b535739d2b6f113b6e36b105921937596524ba 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 #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 68cd34d5a9fbd6c0cde28cf8b68f3e5ad4a10a94..0c2e64d217b5aa6f14725abb5faacb65a7e4ae55 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 20fad76da5aae3e6a0dd44947731b1dbb27697ff..c46d00bbf19d264b9c854f9ecb58e432cf1a4dfe 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 cb71143096560931bd72b6bdb15f2be1e40f88ca..2e526338f6780cad897f7b53d338c686dad197a8 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 c9a140376621430f996af2ed260f33396f726a18..c3235d03b8ebf83d2e1e3e44294c1a76978efc7e 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 -#include #include #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 84fdbc4b835b917711b20a6fa7c263425c5cb5cb..83664ca2521382cde49fdaa1ec7d8969bd96a6c4 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 388759e047d8866fade95bed1f8fbb928acb51cf..7dd310911d9f5533de48e0968adf177fdde7a646 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 @@ 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) { 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 0000000000000000000000000000000000000000..520684242b7dd2e045fd8b3e54bbe4feb3646f8a --- /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 f7762295b7b8d407e41a14d02be032c28adb1f0a..537d0a0ad4c4615449414ffdb9fbea8110e2c008 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