Commit 8781994a authored by David S. Miller's avatar David S. Miller

Merge branch 'lan966x-extend-xdp-support'

Horatiu Vultur says:

====================
net: lan966x: Extend xdp support

Extend the current support of XDP in lan966x with the action XDP_TX and
XDP_REDIRECT.
The first patches just prepare the things such that it would be easier
to add XDP_TX and XDP_REDIRECT actions. Like adding XDP_PACKET_HEADROOM,
introduce helper functions, use the correct dma_dir for the page pool
The last 2 patches introduce the XDP actions XDP_TX and XDP_REDIRECT.

v4->v5:
- add iterator declaration inside for loops
- move the scope of port inside the function lan966x_fdma_rx_alloc_page_pool
- create union for skb and xdpf inside struct lan966x_tx_dcb_buf

v3->v4:
- use napi_consume_skb instead of dev_kfree_skb_any
- arrange members in struct lan966x_tx_dcb_buf not to have holes
- fix when xdp program is added the check for determining if page pool
  needs to be recreated was wrong
- change type for len in lan966x_tx_dcb_buf to u32

v2->v3:
- make sure to update rxq memory model
- update the page pool direction if there is any xdp program
- in case of action XDP_TX give back to reuse the page
- in case of action XDP_REDIRECT, remap the frame and make sure to
  unmap it when is transmitted.

v1->v2:
- use skb_reserve of using skb_put and skb_pull
- make sure that data_len doesn't include XDP_PACKET_HEADROOM
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 46da4aa2 a825b611
...@@ -302,13 +302,13 @@ static int lan966x_port_ifh_xmit(struct sk_buff *skb, ...@@ -302,13 +302,13 @@ static int lan966x_port_ifh_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY; return NETDEV_TX_BUSY;
} }
static void lan966x_ifh_set_bypass(void *ifh, u64 bypass) void lan966x_ifh_set_bypass(void *ifh, u64 bypass)
{ {
packing(ifh, &bypass, IFH_POS_BYPASS + IFH_WID_BYPASS - 1, packing(ifh, &bypass, IFH_POS_BYPASS + IFH_WID_BYPASS - 1,
IFH_POS_BYPASS, IFH_LEN * 4, PACK, 0); IFH_POS_BYPASS, IFH_LEN * 4, PACK, 0);
} }
static void lan966x_ifh_set_port(void *ifh, u64 bypass) void lan966x_ifh_set_port(void *ifh, u64 bypass)
{ {
packing(ifh, &bypass, IFH_POS_DSTS + IFH_WID_DSTS - 1, packing(ifh, &bypass, IFH_POS_DSTS + IFH_WID_DSTS - 1,
IFH_POS_DSTS, IFH_LEN * 4, PACK, 0); IFH_POS_DSTS, IFH_LEN * 4, PACK, 0);
...@@ -469,6 +469,7 @@ static const struct net_device_ops lan966x_port_netdev_ops = { ...@@ -469,6 +469,7 @@ static const struct net_device_ops lan966x_port_netdev_ops = {
.ndo_eth_ioctl = lan966x_port_ioctl, .ndo_eth_ioctl = lan966x_port_ioctl,
.ndo_setup_tc = lan966x_tc_setup, .ndo_setup_tc = lan966x_tc_setup,
.ndo_bpf = lan966x_xdp, .ndo_bpf = lan966x_xdp,
.ndo_xdp_xmit = lan966x_xdp_xmit,
}; };
bool lan966x_netdevice_check(const struct net_device *dev) bool lan966x_netdevice_check(const struct net_device *dev)
......
...@@ -105,11 +105,15 @@ enum macaccess_entry_type { ...@@ -105,11 +105,15 @@ enum macaccess_entry_type {
* FDMA_PASS, frame is valid and can be used * FDMA_PASS, frame is valid and can be used
* FDMA_ERROR, something went wrong, stop getting more frames * FDMA_ERROR, something went wrong, stop getting more frames
* FDMA_DROP, frame is dropped, but continue to get more frames * FDMA_DROP, frame is dropped, but continue to get more frames
* FDMA_TX, frame is given to TX, but continue to get more frames
* FDMA_REDIRECT, frame is given to TX, but continue to get more frames
*/ */
enum lan966x_fdma_action { enum lan966x_fdma_action {
FDMA_PASS = 0, FDMA_PASS = 0,
FDMA_ERROR, FDMA_ERROR,
FDMA_DROP, FDMA_DROP,
FDMA_TX,
FDMA_REDIRECT,
}; };
struct lan966x_port; struct lan966x_port;
...@@ -173,11 +177,17 @@ struct lan966x_rx { ...@@ -173,11 +177,17 @@ struct lan966x_rx {
}; };
struct lan966x_tx_dcb_buf { struct lan966x_tx_dcb_buf {
dma_addr_t dma_addr;
struct net_device *dev; struct net_device *dev;
union {
struct sk_buff *skb; struct sk_buff *skb;
dma_addr_t dma_addr; struct xdp_frame *xdpf;
bool used; } data;
bool ptp; u32 len;
u32 used : 1;
u32 ptp : 1;
u32 use_skb : 1;
u32 xdp_ndo : 1;
}; };
struct lan966x_tx { struct lan966x_tx {
...@@ -359,6 +369,8 @@ bool lan966x_hw_offload(struct lan966x *lan966x, u32 port, struct sk_buff *skb); ...@@ -359,6 +369,8 @@ bool lan966x_hw_offload(struct lan966x *lan966x, u32 port, struct sk_buff *skb);
void lan966x_ifh_get_src_port(void *ifh, u64 *src_port); void lan966x_ifh_get_src_port(void *ifh, u64 *src_port);
void lan966x_ifh_get_timestamp(void *ifh, u64 *timestamp); void lan966x_ifh_get_timestamp(void *ifh, u64 *timestamp);
void lan966x_ifh_set_bypass(void *ifh, u64 bypass);
void lan966x_ifh_set_port(void *ifh, u64 bypass);
void lan966x_stats_get(struct net_device *dev, void lan966x_stats_get(struct net_device *dev,
struct rtnl_link_stats64 *stats); struct rtnl_link_stats64 *stats);
...@@ -459,12 +471,17 @@ u32 lan966x_ptp_get_period_ps(void); ...@@ -459,12 +471,17 @@ u32 lan966x_ptp_get_period_ps(void);
int lan966x_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts); int lan966x_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev); int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev);
int lan966x_fdma_xmit_xdpf(struct lan966x_port *port,
struct xdp_frame *frame,
struct page *page,
bool dma_map);
int lan966x_fdma_change_mtu(struct lan966x *lan966x); int lan966x_fdma_change_mtu(struct lan966x *lan966x);
void lan966x_fdma_netdev_init(struct lan966x *lan966x, struct net_device *dev); void lan966x_fdma_netdev_init(struct lan966x *lan966x, struct net_device *dev);
void lan966x_fdma_netdev_deinit(struct lan966x *lan966x, struct net_device *dev); void lan966x_fdma_netdev_deinit(struct lan966x *lan966x, struct net_device *dev);
int lan966x_fdma_init(struct lan966x *lan966x); int lan966x_fdma_init(struct lan966x *lan966x);
void lan966x_fdma_deinit(struct lan966x *lan966x); void lan966x_fdma_deinit(struct lan966x *lan966x);
irqreturn_t lan966x_fdma_irq_handler(int irq, void *args); irqreturn_t lan966x_fdma_irq_handler(int irq, void *args);
int lan966x_fdma_reload_page_pool(struct lan966x *lan966x);
int lan966x_lag_port_join(struct lan966x_port *port, int lan966x_lag_port_join(struct lan966x_port *port,
struct net_device *brport_dev, struct net_device *brport_dev,
...@@ -555,6 +572,11 @@ int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp); ...@@ -555,6 +572,11 @@ int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp);
int lan966x_xdp_run(struct lan966x_port *port, int lan966x_xdp_run(struct lan966x_port *port,
struct page *page, struct page *page,
u32 data_len); u32 data_len);
int lan966x_xdp_xmit(struct net_device *dev,
int n,
struct xdp_frame **frames,
u32 flags);
bool lan966x_xdp_present(struct lan966x *lan966x);
static inline bool lan966x_xdp_port_present(struct lan966x_port *port) static inline bool lan966x_xdp_port_present(struct lan966x_port *port)
{ {
return !!port->xdp_prog; return !!port->xdp_prog;
......
...@@ -11,6 +11,8 @@ static int lan966x_xdp_setup(struct net_device *dev, struct netdev_bpf *xdp) ...@@ -11,6 +11,8 @@ static int lan966x_xdp_setup(struct net_device *dev, struct netdev_bpf *xdp)
struct lan966x_port *port = netdev_priv(dev); struct lan966x_port *port = netdev_priv(dev);
struct lan966x *lan966x = port->lan966x; struct lan966x *lan966x = port->lan966x;
struct bpf_prog *old_prog; struct bpf_prog *old_prog;
bool old_xdp, new_xdp;
int err;
if (!lan966x->fdma) { if (!lan966x->fdma) {
NL_SET_ERR_MSG_MOD(xdp->extack, NL_SET_ERR_MSG_MOD(xdp->extack,
...@@ -18,7 +20,20 @@ static int lan966x_xdp_setup(struct net_device *dev, struct netdev_bpf *xdp) ...@@ -18,7 +20,20 @@ static int lan966x_xdp_setup(struct net_device *dev, struct netdev_bpf *xdp)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
old_xdp = lan966x_xdp_present(lan966x);
old_prog = xchg(&port->xdp_prog, xdp->prog); old_prog = xchg(&port->xdp_prog, xdp->prog);
new_xdp = lan966x_xdp_present(lan966x);
if (old_xdp == new_xdp)
goto out;
err = lan966x_fdma_reload_page_pool(lan966x);
if (err) {
xchg(&port->xdp_prog, old_prog);
return err;
}
out:
if (old_prog) if (old_prog)
bpf_prog_put(old_prog); bpf_prog_put(old_prog);
...@@ -35,21 +50,57 @@ int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp) ...@@ -35,21 +50,57 @@ int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp)
} }
} }
int lan966x_xdp_xmit(struct net_device *dev,
int n,
struct xdp_frame **frames,
u32 flags)
{
struct lan966x_port *port = netdev_priv(dev);
int nxmit = 0;
for (int i = 0; i < n; ++i) {
struct xdp_frame *xdpf = frames[i];
int err;
err = lan966x_fdma_xmit_xdpf(port, xdpf, NULL, true);
if (err)
break;
nxmit++;
}
return nxmit;
}
int lan966x_xdp_run(struct lan966x_port *port, struct page *page, u32 data_len) int lan966x_xdp_run(struct lan966x_port *port, struct page *page, u32 data_len)
{ {
struct bpf_prog *xdp_prog = port->xdp_prog; struct bpf_prog *xdp_prog = port->xdp_prog;
struct lan966x *lan966x = port->lan966x; struct lan966x *lan966x = port->lan966x;
struct xdp_frame *xdpf;
struct xdp_buff xdp; struct xdp_buff xdp;
u32 act; u32 act;
xdp_init_buff(&xdp, PAGE_SIZE << lan966x->rx.page_order, xdp_init_buff(&xdp, PAGE_SIZE << lan966x->rx.page_order,
&port->xdp_rxq); &port->xdp_rxq);
xdp_prepare_buff(&xdp, page_address(page), IFH_LEN_BYTES, xdp_prepare_buff(&xdp, page_address(page),
IFH_LEN_BYTES + XDP_PACKET_HEADROOM,
data_len - IFH_LEN_BYTES, false); data_len - IFH_LEN_BYTES, false);
act = bpf_prog_run_xdp(xdp_prog, &xdp); act = bpf_prog_run_xdp(xdp_prog, &xdp);
switch (act) { switch (act) {
case XDP_PASS: case XDP_PASS:
return FDMA_PASS; return FDMA_PASS;
case XDP_TX:
xdpf = xdp_convert_buff_to_frame(&xdp);
if (!xdpf)
return FDMA_DROP;
return lan966x_fdma_xmit_xdpf(port, xdpf, page, false) ?
FDMA_DROP : FDMA_TX;
case XDP_REDIRECT:
if (xdp_do_redirect(port->dev, &xdp, xdp_prog))
return FDMA_DROP;
return FDMA_REDIRECT;
default: default:
bpf_warn_invalid_xdp_action(port->dev, xdp_prog, act); bpf_warn_invalid_xdp_action(port->dev, xdp_prog, act);
fallthrough; fallthrough;
...@@ -61,6 +112,19 @@ int lan966x_xdp_run(struct lan966x_port *port, struct page *page, u32 data_len) ...@@ -61,6 +112,19 @@ int lan966x_xdp_run(struct lan966x_port *port, struct page *page, u32 data_len)
} }
} }
bool lan966x_xdp_present(struct lan966x *lan966x)
{
for (int p = 0; p < lan966x->num_phys_ports; ++p) {
if (!lan966x->ports[p])
continue;
if (lan966x_xdp_port_present(lan966x->ports[p]))
return true;
}
return false;
}
int lan966x_xdp_port_init(struct lan966x_port *port) int lan966x_xdp_port_init(struct lan966x_port *port)
{ {
struct lan966x *lan966x = port->lan966x; struct lan966x *lan966x = port->lan966x;
......
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