xref: /linux/drivers/net/ethernet/microchip/lan966x/lan966x_xdp.c (revision dfd5e53dd72113f37663f59a6337fe9a0dfbf0f6)
1 // SPDX-License-Identifier: GPL-2.0+
2 
3 #include <linux/bpf.h>
4 #include <linux/bpf_trace.h>
5 #include <linux/filter.h>
6 
7 #include "lan966x_main.h"
8 
9 static int lan966x_xdp_setup(struct net_device *dev, struct netdev_bpf *xdp)
10 {
11 	struct lan966x_port *port = netdev_priv(dev);
12 	struct lan966x *lan966x = port->lan966x;
13 	struct bpf_prog *old_prog;
14 
15 	if (!lan966x->fdma) {
16 		NL_SET_ERR_MSG_MOD(xdp->extack,
17 				   "Allow to set xdp only when using fdma");
18 		return -EOPNOTSUPP;
19 	}
20 
21 	old_prog = xchg(&port->xdp_prog, xdp->prog);
22 	if (old_prog)
23 		bpf_prog_put(old_prog);
24 
25 	return 0;
26 }
27 
28 int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp)
29 {
30 	switch (xdp->command) {
31 	case XDP_SETUP_PROG:
32 		return lan966x_xdp_setup(dev, xdp);
33 	default:
34 		return -EINVAL;
35 	}
36 }
37 
38 int lan966x_xdp_run(struct lan966x_port *port, struct page *page, u32 data_len)
39 {
40 	struct bpf_prog *xdp_prog = port->xdp_prog;
41 	struct lan966x *lan966x = port->lan966x;
42 	struct xdp_buff xdp;
43 	u32 act;
44 
45 	xdp_init_buff(&xdp, PAGE_SIZE << lan966x->rx.page_order,
46 		      &port->xdp_rxq);
47 	xdp_prepare_buff(&xdp, page_address(page), IFH_LEN_BYTES,
48 			 data_len - IFH_LEN_BYTES, false);
49 	act = bpf_prog_run_xdp(xdp_prog, &xdp);
50 	switch (act) {
51 	case XDP_PASS:
52 		return FDMA_PASS;
53 	default:
54 		bpf_warn_invalid_xdp_action(port->dev, xdp_prog, act);
55 		fallthrough;
56 	case XDP_ABORTED:
57 		trace_xdp_exception(port->dev, xdp_prog, act);
58 		fallthrough;
59 	case XDP_DROP:
60 		return FDMA_DROP;
61 	}
62 }
63 
64 int lan966x_xdp_port_init(struct lan966x_port *port)
65 {
66 	struct lan966x *lan966x = port->lan966x;
67 
68 	return xdp_rxq_info_reg(&port->xdp_rxq, port->dev, 0,
69 				lan966x->napi.napi_id);
70 }
71 
72 void lan966x_xdp_port_deinit(struct lan966x_port *port)
73 {
74 	if (xdp_rxq_info_is_reg(&port->xdp_rxq))
75 		xdp_rxq_info_unreg(&port->xdp_rxq);
76 }
77