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

nfp: move basic eBPF stats to app-specific code

Allow apps to associate private data with vNICs and move
BPF-specific fields of nfp_net to such structure.
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bb45e51c
...@@ -86,6 +86,9 @@ static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn) ...@@ -86,6 +86,9 @@ static const char *nfp_bpf_extra_cap(struct nfp_app *app, struct nfp_net *nn)
static int static int
nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id) 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 */ /* Limit to single port, otherwise it's just a NIC */
if (id > 0) { if (id > 0) {
nfp_warn(app->cpp, nfp_warn(app->cpp,
...@@ -94,13 +97,27 @@ nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id) ...@@ -94,13 +97,27 @@ nfp_bpf_vnic_init(struct nfp_app *app, struct nfp_net *nn, unsigned int id)
return PTR_ERR_OR_ZERO(nn->port); return PTR_ERR_OR_ZERO(nn->port);
} }
return nfp_app_nic_vnic_init(app, nn, id); 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) static void nfp_bpf_vnic_clean(struct nfp_app *app, struct nfp_net *nn)
{ {
if (nn->dp.bpf_offload_xdp) if (nn->dp.bpf_offload_xdp)
nfp_bpf_xdp_offload(app, nn, NULL); 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, static int nfp_bpf_setup_tc(struct nfp_app *app, struct net_device *netdev,
......
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/types.h> #include <linux/types.h>
#include "../nfp_net.h"
/* For branch fixup logic use up-most byte of branch instruction as scratch /* For branch fixup logic use up-most byte of branch instruction as scratch
* area. Remember to clear this before sending instructions to HW! * area. Remember to clear this before sending instructions to HW!
*/ */
...@@ -201,6 +203,22 @@ int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog); ...@@ -201,6 +203,22 @@ int nfp_prog_verify(struct nfp_prog *nfp_prog, struct bpf_prog *prog);
struct nfp_net; struct nfp_net;
struct tc_cls_bpf_offload; 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); 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 #endif
...@@ -54,46 +54,52 @@ ...@@ -54,46 +54,52 @@
void nfp_net_filter_stats_timer(unsigned long data) void nfp_net_filter_stats_timer(unsigned long data)
{ {
struct nfp_net *nn = (void *)data; struct nfp_net *nn = (void *)data;
struct nfp_net_bpf_priv *priv;
struct nfp_stat_pair latest; 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) 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); 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.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES);
latest.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES); latest.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES);
if (latest.pkts != nn->rx_filter.pkts) if (latest.pkts != priv->rx_filter.pkts)
nn->rx_filter_change = jiffies; priv->rx_filter_change = jiffies;
nn->rx_filter = latest; priv->rx_filter = latest;
} }
static void nfp_net_bpf_stats_reset(struct nfp_net *nn) static void nfp_net_bpf_stats_reset(struct nfp_net *nn)
{ {
nn->rx_filter.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES); struct nfp_net_bpf_priv *priv = nn->app_priv;
nn->rx_filter.bytes = nn_readq(nn, NFP_NET_CFG_STATS_APP1_BYTES);
nn->rx_filter_prev = nn->rx_filter; priv->rx_filter.pkts = nn_readq(nn, NFP_NET_CFG_STATS_APP1_FRAMES);
nn->rx_filter_change = jiffies; 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 static int
nfp_net_bpf_stats_update(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf) nfp_net_bpf_stats_update(struct nfp_net *nn, struct tc_cls_bpf_offload *cls_bpf)
{ {
struct nfp_net_bpf_priv *priv = nn->app_priv;
u64 bytes, pkts; u64 bytes, pkts;
pkts = nn->rx_filter.pkts - nn->rx_filter_prev.pkts; pkts = priv->rx_filter.pkts - priv->rx_filter_prev.pkts;
bytes = nn->rx_filter.bytes - nn->rx_filter_prev.bytes; bytes = priv->rx_filter.bytes - priv->rx_filter_prev.bytes;
bytes -= pkts * ETH_HLEN; bytes -= pkts * ETH_HLEN;
nn->rx_filter_prev = nn->rx_filter; priv->rx_filter_prev = priv->rx_filter;
tcf_exts_stats_update(cls_bpf->exts, tcf_exts_stats_update(cls_bpf->exts,
bytes, pkts, nn->rx_filter_change); bytes, pkts, priv->rx_filter_change);
return 0; return 0;
} }
...@@ -183,6 +189,7 @@ nfp_net_bpf_load_and_start(struct nfp_net *nn, u32 tc_flags, ...@@ -183,6 +189,7 @@ nfp_net_bpf_load_and_start(struct nfp_net *nn, u32 tc_flags,
unsigned int code_sz, unsigned int n_instr, unsigned int code_sz, unsigned int n_instr,
bool dense_mode) bool dense_mode)
{ {
struct nfp_net_bpf_priv *priv = nn->app_priv;
u64 bpf_addr = dma_addr; u64 bpf_addr = dma_addr;
int err; int err;
...@@ -209,20 +216,23 @@ nfp_net_bpf_load_and_start(struct nfp_net *nn, u32 tc_flags, ...@@ -209,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); dma_free_coherent(nn->dp.dev, code_sz, code, dma_addr);
nfp_net_bpf_stats_reset(nn); 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) 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)) if (!(nn->dp.ctrl & NFP_NET_CFG_CTRL_BPF))
return 0; return 0;
spin_lock_bh(&nn->rx_filter_lock); spin_lock_bh(&priv->rx_filter_lock);
nn->dp.ctrl &= ~NFP_NET_CFG_CTRL_BPF; 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); 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; nn->dp.bpf_offload_skip_sw = 0;
return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN); return nfp_net_reconfig(nn, NFP_NET_CFG_UPDATE_GEN);
......
...@@ -517,11 +517,6 @@ struct nfp_net_dp { ...@@ -517,11 +517,6 @@ struct nfp_net_dp {
* @rss_cfg: RSS configuration * @rss_cfg: RSS configuration
* @rss_key: RSS secret key * @rss_key: RSS secret key
* @rss_itbl: RSS indirection table * @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_r_vecs: Number of allocated interrupt vectors for RX/TX
* @max_tx_rings: Maximum number of TX rings supported by the Firmware * @max_tx_rings: Maximum number of TX rings supported by the Firmware
* @max_rx_rings: Maximum number of RX 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 { ...@@ -556,6 +551,7 @@ struct nfp_net_dp {
* @pdev: Backpointer to PCI device * @pdev: Backpointer to PCI device
* @app: APP handle if available * @app: APP handle if available
* @port: Pointer to nfp_port structure if vNIC is a port * @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 {
struct nfp_net_dp dp; struct nfp_net_dp dp;
...@@ -570,11 +566,6 @@ struct nfp_net { ...@@ -570,11 +566,6 @@ struct nfp_net {
u8 rss_key[NFP_NET_CFG_RSS_KEY_SZ]; u8 rss_key[NFP_NET_CFG_RSS_KEY_SZ];
u8 rss_itbl[NFP_NET_CFG_RSS_ITBL_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_tx_rings;
unsigned int max_rx_rings; unsigned int max_rx_rings;
...@@ -627,6 +618,8 @@ struct nfp_net { ...@@ -627,6 +618,8 @@ struct nfp_net {
struct nfp_app *app; struct nfp_app *app;
struct nfp_port *port; struct nfp_port *port;
void *app_priv;
}; };
/* Functions to read/write from/to a BAR /* Functions to read/write from/to a BAR
...@@ -867,6 +860,4 @@ static inline void nfp_net_debugfs_dir_clean(struct dentry **dir) ...@@ -867,6 +860,4 @@ static inline void nfp_net_debugfs_dir_clean(struct dentry **dir)
} }
#endif /* CONFIG_NFP_DEBUG */ #endif /* CONFIG_NFP_DEBUG */
void nfp_net_filter_stats_timer(unsigned long data);
#endif /* _NFP_NET_H_ */ #endif /* _NFP_NET_H_ */
...@@ -3072,13 +3072,10 @@ struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, ...@@ -3072,13 +3072,10 @@ struct nfp_net *nfp_net_alloc(struct pci_dev *pdev,
nn->dp.rxd_cnt = NFP_NET_RX_DESCS_DEFAULT; nn->dp.rxd_cnt = NFP_NET_RX_DESCS_DEFAULT;
spin_lock_init(&nn->reconfig_lock); spin_lock_init(&nn->reconfig_lock);
spin_lock_init(&nn->rx_filter_lock);
spin_lock_init(&nn->link_status_lock); spin_lock_init(&nn->link_status_lock);
setup_timer(&nn->reconfig_timer, setup_timer(&nn->reconfig_timer,
nfp_net_reconfig_timer, (unsigned long)nn); nfp_net_reconfig_timer, (unsigned long)nn);
setup_timer(&nn->rx_filter_stats_timer,
nfp_net_filter_stats_timer, (unsigned long)nn);
return nn; return nn;
} }
......
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