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 
lan966x_xdp_setup(struct net_device * dev,struct netdev_bpf * xdp)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 	bool old_xdp, new_xdp;
15 	int err;
16 
17 	if (!lan966x->fdma) {
18 		NL_SET_ERR_MSG_MOD(xdp->extack,
19 				   "Allow to set xdp only when using fdma");
20 		return -EOPNOTSUPP;
21 	}
22 
23 	old_xdp = lan966x_xdp_present(lan966x);
24 	old_prog = xchg(&port->xdp_prog, xdp->prog);
25 	new_xdp = lan966x_xdp_present(lan966x);
26 
27 	if (old_xdp == new_xdp)
28 		goto out;
29 
30 	err = lan966x_fdma_reload_page_pool(lan966x);
31 	if (err) {
32 		xchg(&port->xdp_prog, old_prog);
33 		return err;
34 	}
35 
36 out:
37 	if (old_prog)
38 		bpf_prog_put(old_prog);
39 
40 	return 0;
41 }
42 
lan966x_xdp(struct net_device * dev,struct netdev_bpf * xdp)43 int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp)
44 {
45 	switch (xdp->command) {
46 	case XDP_SETUP_PROG:
47 		return lan966x_xdp_setup(dev, xdp);
48 	default:
49 		return -EINVAL;
50 	}
51 }
52 
lan966x_xdp_xmit(struct net_device * dev,int n,struct xdp_frame ** frames,u32 flags)53 int lan966x_xdp_xmit(struct net_device *dev,
54 		     int n,
55 		     struct xdp_frame **frames,
56 		     u32 flags)
57 {
58 	struct lan966x_port *port = netdev_priv(dev);
59 	int nxmit = 0;
60 
61 	for (int i = 0; i < n; ++i) {
62 		struct xdp_frame *xdpf = frames[i];
63 		int err;
64 
65 		err = lan966x_fdma_xmit_xdpf(port, xdpf, NULL, true);
66 		if (err)
67 			break;
68 
69 		nxmit++;
70 	}
71 
72 	return nxmit;
73 }
74 
lan966x_xdp_run(struct lan966x_port * port,struct page * page,u32 data_len)75 int lan966x_xdp_run(struct lan966x_port *port, struct page *page, u32 data_len)
76 {
77 	struct bpf_prog *xdp_prog = port->xdp_prog;
78 	struct lan966x *lan966x = port->lan966x;
79 	struct xdp_frame *xdpf;
80 	struct xdp_buff xdp;
81 	u32 act;
82 
83 	xdp_init_buff(&xdp, PAGE_SIZE << lan966x->rx.page_order,
84 		      &port->xdp_rxq);
85 	xdp_prepare_buff(&xdp, page_address(page),
86 			 IFH_LEN_BYTES + XDP_PACKET_HEADROOM,
87 			 data_len - IFH_LEN_BYTES, false);
88 	act = bpf_prog_run_xdp(xdp_prog, &xdp);
89 	switch (act) {
90 	case XDP_PASS:
91 		return FDMA_PASS;
92 	case XDP_TX:
93 		xdpf = xdp_convert_buff_to_frame(&xdp);
94 		if (!xdpf)
95 			return FDMA_DROP;
96 
97 		return lan966x_fdma_xmit_xdpf(port, xdpf, page, false) ?
98 		       FDMA_DROP : FDMA_TX;
99 	case XDP_REDIRECT:
100 		if (xdp_do_redirect(port->dev, &xdp, xdp_prog))
101 			return FDMA_DROP;
102 
103 		return FDMA_REDIRECT;
104 	default:
105 		bpf_warn_invalid_xdp_action(port->dev, xdp_prog, act);
106 		fallthrough;
107 	case XDP_ABORTED:
108 		trace_xdp_exception(port->dev, xdp_prog, act);
109 		fallthrough;
110 	case XDP_DROP:
111 		return FDMA_DROP;
112 	}
113 }
114 
lan966x_xdp_present(struct lan966x * lan966x)115 bool lan966x_xdp_present(struct lan966x *lan966x)
116 {
117 	for (int p = 0; p < lan966x->num_phys_ports; ++p) {
118 		if (!lan966x->ports[p])
119 			continue;
120 
121 		if (lan966x_xdp_port_present(lan966x->ports[p]))
122 			return true;
123 	}
124 
125 	return false;
126 }
127 
lan966x_xdp_port_init(struct lan966x_port * port)128 int lan966x_xdp_port_init(struct lan966x_port *port)
129 {
130 	struct lan966x *lan966x = port->lan966x;
131 
132 	return xdp_rxq_info_reg(&port->xdp_rxq, port->dev, 0,
133 				lan966x->napi.napi_id);
134 }
135 
lan966x_xdp_port_deinit(struct lan966x_port * port)136 void lan966x_xdp_port_deinit(struct lan966x_port *port)
137 {
138 	if (xdp_rxq_info_is_reg(&port->xdp_rxq))
139 		xdp_rxq_info_unreg(&port->xdp_rxq);
140 }
141