From c443b5accedaef8e1d6faf7a1bb921670a90a3d0 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 21 Jun 2017 18:25:05 -0700 Subject: nfp: xdp: move driver XDP setup into a separate function In preparation of XDP offload flags move the driver setup into a function. Otherwise the number of conditions in one function would make it slightly hard to follow. The offload handler may now be called with NULL prog, even if no offload is currently active, but that's fine, offload code can handle that. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- .../net/ethernet/netronome/nfp/nfp_net_common.c | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 2bdddd1ae666..f2188b9c3628 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3274,10 +3274,11 @@ 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; @@ -3286,7 +3287,6 @@ 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_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog); return 0; } @@ -3300,13 +3300,26 @@ 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); + err = nfp_net_ring_reconfig(nn, dp, extack); if (err) return err; if (old_prog) bpf_prog_put(old_prog); + return 0; +} + +static int +nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, + struct netlink_ext_ack *extack) +{ + int err; + + err = nfp_net_xdp_setup_drv(nn, prog, extack); + if (err) + return err; + nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog); return 0; @@ -3318,7 +3331,7 @@ 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); + return nfp_net_xdp_setup(nn, xdp->prog, 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; -- cgit v1.2.3 From 9f82fca9422eab3877ab2b697ccc5eef44c63b54 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 21 Jun 2017 18:25:06 -0700 Subject: nfp: bpf: don't offload XDP programs in DRV_MODE DRV_MODE means that user space wants the program to be run in the driver. Do not try to offload. Only offload if no mode flags have been specified. Remember what the mode is when the program is installed and refuse new setup requests if there is already a program loaded in a different mode. This should leave it open for us to implement simultaneous loading of two programs - one in the drv path and another to the NIC later. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 3 +++ drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 02fd8d4e253c..7952fbfb94d6 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -541,6 +541,7 @@ 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 * @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 +591,8 @@ struct nfp_net { u8 rss_key[NFP_NET_CFG_RSS_KEY_SZ]; u8 rss_itbl[NFP_NET_CFG_RSS_ITBL_SZ]; + u32 xdp_flags; + 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 f2188b9c3628..9563615cf4b7 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3311,16 +3311,23 @@ nfp_net_xdp_setup_drv(struct nfp_net *nn, struct bpf_prog *prog, } static int -nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, +nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, u32 flags, struct netlink_ext_ack *extack) { + struct bpf_prog *offload_prog; int err; + if (nn->dp.xdp_prog && (flags ^ nn->xdp_flags) & XDP_FLAGS_MODES) + return -EBUSY; + + offload_prog = flags & XDP_FLAGS_DRV_MODE ? NULL : prog; + err = nfp_net_xdp_setup_drv(nn, prog, extack); if (err) return err; - nfp_app_xdp_offload(nn->app, nn, nn->dp.xdp_prog); + nfp_app_xdp_offload(nn->app, nn, offload_prog); + nn->xdp_flags = flags; return 0; } @@ -3331,7 +3338,8 @@ 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->prog, xdp->extack); + 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; -- cgit v1.2.3 From 6a8ef5428c9fb5b589c2c912889d157abb50dd61 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 21 Jun 2017 18:25:07 -0700 Subject: nfp: bpf: release the reference on offloaded programs The xdp_prog member of the adapter's data path structure is used for XDP in driver mode. In case a XDP program is loaded with in HW-only mode, we need to store it somewhere else. Add a new XDP prog pointer in the main structure and use that when we need to know whether any XDP program is loaded, not only a driver mode one. Only release our reference on adapter free instead of immediately after netdev unregister to allow offload to be disabled first. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net.h | 2 ++ .../net/ethernet/netronome/nfp/nfp_net_common.c | 34 +++++++++------------- 2 files changed, 15 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net.h b/drivers/net/ethernet/netronome/nfp/nfp_net.h index 7952fbfb94d6..b7446793106d 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net.h +++ b/drivers/net/ethernet/netronome/nfp/nfp_net.h @@ -542,6 +542,7 @@ struct nfp_net_dp { * @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 @@ -592,6 +593,7 @@ struct nfp_net { 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 9563615cf4b7..35b4530a7e02 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3278,15 +3278,10 @@ 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 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); + if (!prog == !nn->dp.xdp_prog) { + WRITE_ONCE(nn->dp.xdp_prog, prog); return 0; } @@ -3300,14 +3295,7 @@ nfp_net_xdp_setup_drv(struct nfp_net *nn, struct bpf_prog *prog, 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, extack); - if (err) - return err; - - if (old_prog) - bpf_prog_put(old_prog); - - return 0; + return nfp_net_ring_reconfig(nn, dp, extack); } static int @@ -3317,7 +3305,7 @@ nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, u32 flags, struct bpf_prog *offload_prog; int err; - if (nn->dp.xdp_prog && (flags ^ nn->xdp_flags) & XDP_FLAGS_MODES) + if (nn->xdp_prog && (flags ^ nn->xdp_flags) & XDP_FLAGS_MODES) return -EBUSY; offload_prog = flags & XDP_FLAGS_DRV_MODE ? NULL : prog; @@ -3327,6 +3315,10 @@ nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, u32 flags, return err; nfp_app_xdp_offload(nn->app, nn, offload_prog); + + if (nn->xdp_prog) + bpf_prog_put(nn->xdp_prog); + nn->xdp_prog = prog; nn->xdp_flags = flags; return 0; @@ -3341,8 +3333,8 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) 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; + xdp->prog_id = nn->xdp_prog ? nn->xdp_prog->aux->id : 0; return 0; default: return -EINVAL; @@ -3500,6 +3492,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 @@ -3757,7 +3752,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); } -- cgit v1.2.3 From cafa92ac255337517ca2466ab05ca9f24c0ca9de Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 21 Jun 2017 18:25:08 -0700 Subject: nfp: bpf: add support for XDP_FLAGS_HW_MODE Respect the XDP_FLAGS_HW_MODE. When it's set install the program on the NIC and skip enabling XDP in the driver. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index 35b4530a7e02..c9fc1df1823e 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3302,19 +3302,25 @@ static int nfp_net_xdp_setup(struct nfp_net *nn, struct bpf_prog *prog, u32 flags, struct netlink_ext_ack *extack) { - struct bpf_prog *offload_prog; + 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, prog, extack); + err = nfp_net_xdp_setup_drv(nn, drv_prog, extack); if (err) return err; - nfp_app_xdp_offload(nn->app, nn, offload_prog); + err = nfp_app_xdp_offload(nn->app, nn, offload_prog); + if (err && flags & XDP_FLAGS_HW_MODE) + return err; if (nn->xdp_prog) bpf_prog_put(nn->xdp_prog); @@ -3330,6 +3336,7 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) switch (xdp->command) { case XDP_SETUP_PROG: + case XDP_SETUP_PROG_HW: return nfp_net_xdp_setup(nn, xdp->prog, xdp->flags, xdp->extack); case XDP_QUERY_PROG: -- cgit v1.2.3 From 149d7a572ae124385973bf1c8e4d80b3f07d8bd4 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 21 Jun 2017 18:25:10 -0700 Subject: nfp: xdp: report if program is offloaded Make use of just added XDP_ATTACHED_HW. Signed-off-by: Jakub Kicinski Signed-off-by: David S. Miller --- drivers/net/ethernet/netronome/nfp/nfp_net_common.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c index c9fc1df1823e..2134493ec8a8 100644 --- a/drivers/net/ethernet/netronome/nfp/nfp_net_common.c +++ b/drivers/net/ethernet/netronome/nfp/nfp_net_common.c @@ -3341,6 +3341,8 @@ static int nfp_net_xdp(struct net_device *netdev, struct netdev_xdp *xdp) xdp->extack); case XDP_QUERY_PROG: 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: -- cgit v1.2.3