summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2017-06-23 13:42:21 -0400
committerDavid S. Miller <davem@davemloft.net>2017-06-23 13:42:21 -0400
commit1847d3d0a4de609523a685d68458529caacacdcc (patch)
tree00bbc360b28f362542756d7ca67f953d7394f2c3 /drivers
parent9bd780f5e0663035d41a95a6b87eced011ba7e2a (diff)
parent149d7a572ae124385973bf1c8e4d80b3f07d8bd4 (diff)
Merge branch 'xdp-offload-mode'
Jakub Kicinski says: ==================== xdp: offload mode While we discuss the representors.. :) This set adds XDP flag for forcing offload and a attachment mode for reporting to user space that program has been offloaded. The nfp driver is modified to make use of the new flags, but also to adhere to the DRV_MODE flag which should disable the HW offload. The intended driver behaviour is: DRV mode offload no flags yes attempted DRV_MODE yes no HW_MODE no yes Where 'yes' means required, and error will be returned if setup fails. 'Attempted' means the offload will only happen automatically if HW is capable and offloading the program will cause no change in system behaviour (e.g. maps don't have to bound). Thanks to loading the program both to the driver and HW by default we can fallback to the driver mode without disruption in case user replaces the program with one which cannot be offloaded later. Note that the NFP driver currently claims XDP offload support but lacks most basic features like direct packet access. Only change compared to the RFC is fixing the double bpf_prog_put() which Daniel has spotted (patch 5). ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net.h5
-rw-r--r--drivers/net/ethernet/netronome/nfp/nfp_net_common.c62
2 files changed, 47 insertions, 20 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h
index 02fd8d4e253c..b7446793106d 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net.h
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h
@@ -541,6 +541,8 @@ struct nfp_net_dp {
* @rss_cfg: RSS configuration
* @rss_key: RSS secret key
* @rss_itbl: RSS indirection table
+ * @xdp_flags: Flags with which XDP prog was loaded
+ * @xdp_prog: XDP prog (for ctrl path, both DRV and HW modes)
* @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
@@ -590,6 +592,9 @@ struct nfp_net {
u8 rss_key[NFP_NET_CFG_RSS_KEY_SZ];
u8 rss_itbl[NFP_NET_CFG_RSS_ITBL_SZ];
+ u32 xdp_flags;
+ struct bpf_prog *xdp_prog;
+
unsigned int max_tx_rings;
unsigned int max_rx_rings;
diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
index 2bdddd1ae666..2134493ec8a8 100644
--- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
+++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c
@@ -3274,19 +3274,14 @@ static void nfp_net_del_vxlan_port(struct net_device *netdev,
nfp_net_set_vxlan_port(nn, idx, 0);
}
-static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp)
+static int
+nfp_net_xdp_setup_drv(struct nfp_net *nn, struct bpf_prog *prog,
+ struct netlink_ext_ack *extack)
{
- struct bpf_prog *old_prog = nn->dp.xdp_prog;
- struct bpf_prog *prog = xdp->prog;
struct nfp_net_dp *dp;
- int err;
- if (!prog && !nn->dp.xdp_prog)
- return 0;
- if (prog && nn->dp.xdp_prog) {
- prog = xchg(&nn->dp.xdp_prog, prog);
- bpf_prog_put(prog);
- nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog);
+ if (!prog == !nn->dp.xdp_prog) {
+ WRITE_ONCE(nn->dp.xdp_prog, prog);
return 0;
}
@@ -3300,14 +3295,37 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct netdev_xdp *xdp)
dp->rx_dma_off = prog ? XDP_PACKET_HEADROOM - nn->dp.rx_offset : 0;
/* We need RX reconfig to remap the buffers (BIDIR vs FROM_DEV) */
- err = nfp_net_ring_reconfig(nn, dp, xdp->extack);
+ return nfp_net_ring_reconfig(nn, dp, extack);
+}
+
+static int
+nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, u32 flags,
+ struct netlink_ext_ack *extack)
+{
+ struct bpf_prog *drv_prog, *offload_prog;
+ int err;
+
+ if (nn->xdp_prog && (flags ^ nn->xdp_flags) & XDP_FLAGS_MODES)
+ return -EBUSY;
+
+ /* Load both when no flags set to allow easy activation of driver path
+ * when program is replaced by one which can't be offloaded.
+ */
+ drv_prog = flags & XDP_FLAGS_HW_MODE ? NULL : prog;
+ offload_prog = flags & XDP_FLAGS_DRV_MODE ? NULL : prog;
+
+ err = nfp_net_xdp_setup_drv(nn, drv_prog, extack);
if (err)
return err;
- if (old_prog)
- bpf_prog_put(old_prog);
+ err = nfp_app_xdp_offload(nn->app, nn, offload_prog);
+ if (err && flags & XDP_FLAGS_HW_MODE)
+ return err;
- nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog);
+ if (nn->xdp_prog)
+ bpf_prog_put(nn->xdp_prog);
+ nn->xdp_prog = prog;
+ nn->xdp_flags = flags;
return 0;
}
@@ -3318,10 +3336,14 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp)
switch (xdp->command) {
case XDP_SETUP_PROG:
- return nfp_net_xdp_setup(nn, xdp);
+ case XDP_SETUP_PROG_HW:
+ return nfp_net_xdp_setup(nn, xdp->prog, xdp->flags,
+ xdp->extack);
case XDP_QUERY_PROG:
- xdp->prog_attached = !!nn->dp.xdp_prog;
- xdp->prog_id = nn->dp.xdp_prog ? nn->dp.xdp_prog->aux->id : 0;
+ xdp->prog_attached = !!nn->xdp_prog;
+ if (nn->dp.bpf_offload_xdp)
+ xdp->prog_attached = XDP_ATTACHED_HW;
+ xdp->prog_id = nn->xdp_prog ? nn->xdp_prog->aux->id : 0;
return 0;
default:
return -EINVAL;
@@ -3479,6 +3501,9 @@ struct nfp_net *nfp_net_alloc(struct pci_dev *pdev, bool needs_netdev,
*/
void nfp_net_free(struct nfp_net *nn)
{
+ if (nn->xdp_prog)
+ bpf_prog_put(nn->xdp_prog);
+
if (nn->dp.netdev)
free_netdev(nn->dp.netdev);
else
@@ -3736,7 +3761,4 @@ void nfp_net_clean(struct nfp_net *nn)
return;
unregister_netdev(nn->dp.netdev);
-
- if (nn->dp.xdp_prog)
- bpf_prog_put(nn->dp.xdp_prog);
}