16a2159beSHoratiu Vultur // SPDX-License-Identifier: GPL-2.0+
26a2159beSHoratiu Vultur 
36a2159beSHoratiu Vultur #include <linux/bpf.h>
46a2159beSHoratiu Vultur #include <linux/bpf_trace.h>
56a2159beSHoratiu Vultur #include <linux/filter.h>
66a2159beSHoratiu Vultur 
76a2159beSHoratiu Vultur #include "lan966x_main.h"
86a2159beSHoratiu Vultur 
lan966x_xdp_setup(struct net_device * dev,struct netdev_bpf * xdp)96a2159beSHoratiu Vultur static int lan966x_xdp_setup(struct net_device *dev, struct netdev_bpf *xdp)
106a2159beSHoratiu Vultur {
116a2159beSHoratiu Vultur 	struct lan966x_port *port = netdev_priv(dev);
126a2159beSHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
136a2159beSHoratiu Vultur 	struct bpf_prog *old_prog;
14560c7223SHoratiu Vultur 	bool old_xdp, new_xdp;
15560c7223SHoratiu Vultur 	int err;
166a2159beSHoratiu Vultur 
176a2159beSHoratiu Vultur 	if (!lan966x->fdma) {
186a2159beSHoratiu Vultur 		NL_SET_ERR_MSG_MOD(xdp->extack,
196a2159beSHoratiu Vultur 				   "Allow to set xdp only when using fdma");
206a2159beSHoratiu Vultur 		return -EOPNOTSUPP;
216a2159beSHoratiu Vultur 	}
226a2159beSHoratiu Vultur 
23560c7223SHoratiu Vultur 	old_xdp = lan966x_xdp_present(lan966x);
246a2159beSHoratiu Vultur 	old_prog = xchg(&port->xdp_prog, xdp->prog);
25560c7223SHoratiu Vultur 	new_xdp = lan966x_xdp_present(lan966x);
26560c7223SHoratiu Vultur 
27560c7223SHoratiu Vultur 	if (old_xdp == new_xdp)
28560c7223SHoratiu Vultur 		goto out;
29560c7223SHoratiu Vultur 
30560c7223SHoratiu Vultur 	err = lan966x_fdma_reload_page_pool(lan966x);
31560c7223SHoratiu Vultur 	if (err) {
32560c7223SHoratiu Vultur 		xchg(&port->xdp_prog, old_prog);
33560c7223SHoratiu Vultur 		return err;
34560c7223SHoratiu Vultur 	}
35560c7223SHoratiu Vultur 
36560c7223SHoratiu Vultur out:
376a2159beSHoratiu Vultur 	if (old_prog)
386a2159beSHoratiu Vultur 		bpf_prog_put(old_prog);
396a2159beSHoratiu Vultur 
406a2159beSHoratiu Vultur 	return 0;
416a2159beSHoratiu Vultur }
426a2159beSHoratiu Vultur 
lan966x_xdp(struct net_device * dev,struct netdev_bpf * xdp)436a2159beSHoratiu Vultur int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp)
446a2159beSHoratiu Vultur {
456a2159beSHoratiu Vultur 	switch (xdp->command) {
466a2159beSHoratiu Vultur 	case XDP_SETUP_PROG:
476a2159beSHoratiu Vultur 		return lan966x_xdp_setup(dev, xdp);
486a2159beSHoratiu Vultur 	default:
496a2159beSHoratiu Vultur 		return -EINVAL;
506a2159beSHoratiu Vultur 	}
516a2159beSHoratiu Vultur }
526a2159beSHoratiu Vultur 
lan966x_xdp_xmit(struct net_device * dev,int n,struct xdp_frame ** frames,u32 flags)53a825b611SHoratiu Vultur int lan966x_xdp_xmit(struct net_device *dev,
54a825b611SHoratiu Vultur 		     int n,
55a825b611SHoratiu Vultur 		     struct xdp_frame **frames,
56a825b611SHoratiu Vultur 		     u32 flags)
57a825b611SHoratiu Vultur {
58a825b611SHoratiu Vultur 	struct lan966x_port *port = netdev_priv(dev);
59a825b611SHoratiu Vultur 	int nxmit = 0;
60a825b611SHoratiu Vultur 
61a825b611SHoratiu Vultur 	for (int i = 0; i < n; ++i) {
62a825b611SHoratiu Vultur 		struct xdp_frame *xdpf = frames[i];
63a825b611SHoratiu Vultur 		int err;
64a825b611SHoratiu Vultur 
65*700f11ebSHoratiu Vultur 		err = lan966x_fdma_xmit_xdpf(port, xdpf, 0);
66a825b611SHoratiu Vultur 		if (err)
67a825b611SHoratiu Vultur 			break;
68a825b611SHoratiu Vultur 
69a825b611SHoratiu Vultur 		nxmit++;
70a825b611SHoratiu Vultur 	}
71a825b611SHoratiu Vultur 
72a825b611SHoratiu Vultur 	return nxmit;
73a825b611SHoratiu Vultur }
74a825b611SHoratiu Vultur 
lan966x_xdp_run(struct lan966x_port * port,struct page * page,u32 data_len)756a2159beSHoratiu Vultur int lan966x_xdp_run(struct lan966x_port *port, struct page *page, u32 data_len)
766a2159beSHoratiu Vultur {
776a2159beSHoratiu Vultur 	struct bpf_prog *xdp_prog = port->xdp_prog;
786a2159beSHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
796a2159beSHoratiu Vultur 	struct xdp_buff xdp;
806a2159beSHoratiu Vultur 	u32 act;
816a2159beSHoratiu Vultur 
826a2159beSHoratiu Vultur 	xdp_init_buff(&xdp, PAGE_SIZE << lan966x->rx.page_order,
836a2159beSHoratiu Vultur 		      &port->xdp_rxq);
847292bb06SHoratiu Vultur 	xdp_prepare_buff(&xdp, page_address(page),
857292bb06SHoratiu Vultur 			 IFH_LEN_BYTES + XDP_PACKET_HEADROOM,
866a2159beSHoratiu Vultur 			 data_len - IFH_LEN_BYTES, false);
876a2159beSHoratiu Vultur 	act = bpf_prog_run_xdp(xdp_prog, &xdp);
886a2159beSHoratiu Vultur 	switch (act) {
896a2159beSHoratiu Vultur 	case XDP_PASS:
906a2159beSHoratiu Vultur 		return FDMA_PASS;
9119c6f534SHoratiu Vultur 	case XDP_TX:
92*700f11ebSHoratiu Vultur 		return lan966x_fdma_xmit_xdpf(port, page,
93*700f11ebSHoratiu Vultur 					      data_len - IFH_LEN_BYTES) ?
9419c6f534SHoratiu Vultur 		       FDMA_DROP : FDMA_TX;
95a825b611SHoratiu Vultur 	case XDP_REDIRECT:
96a825b611SHoratiu Vultur 		if (xdp_do_redirect(port->dev, &xdp, xdp_prog))
97a825b611SHoratiu Vultur 			return FDMA_DROP;
98a825b611SHoratiu Vultur 
99a825b611SHoratiu Vultur 		return FDMA_REDIRECT;
1006a2159beSHoratiu Vultur 	default:
1016a2159beSHoratiu Vultur 		bpf_warn_invalid_xdp_action(port->dev, xdp_prog, act);
1026a2159beSHoratiu Vultur 		fallthrough;
1036a2159beSHoratiu Vultur 	case XDP_ABORTED:
1046a2159beSHoratiu Vultur 		trace_xdp_exception(port->dev, xdp_prog, act);
1056a2159beSHoratiu Vultur 		fallthrough;
1066a2159beSHoratiu Vultur 	case XDP_DROP:
1076a2159beSHoratiu Vultur 		return FDMA_DROP;
1086a2159beSHoratiu Vultur 	}
1096a2159beSHoratiu Vultur }
1106a2159beSHoratiu Vultur 
lan966x_xdp_present(struct lan966x * lan966x)111560c7223SHoratiu Vultur bool lan966x_xdp_present(struct lan966x *lan966x)
112560c7223SHoratiu Vultur {
113560c7223SHoratiu Vultur 	for (int p = 0; p < lan966x->num_phys_ports; ++p) {
114560c7223SHoratiu Vultur 		if (!lan966x->ports[p])
115560c7223SHoratiu Vultur 			continue;
116560c7223SHoratiu Vultur 
117560c7223SHoratiu Vultur 		if (lan966x_xdp_port_present(lan966x->ports[p]))
118560c7223SHoratiu Vultur 			return true;
119560c7223SHoratiu Vultur 	}
120560c7223SHoratiu Vultur 
121560c7223SHoratiu Vultur 	return false;
122560c7223SHoratiu Vultur }
123560c7223SHoratiu Vultur 
lan966x_xdp_port_init(struct lan966x_port * port)1246a2159beSHoratiu Vultur int lan966x_xdp_port_init(struct lan966x_port *port)
1256a2159beSHoratiu Vultur {
1266a2159beSHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
1276a2159beSHoratiu Vultur 
1286a2159beSHoratiu Vultur 	return xdp_rxq_info_reg(&port->xdp_rxq, port->dev, 0,
1296a2159beSHoratiu Vultur 				lan966x->napi.napi_id);
1306a2159beSHoratiu Vultur }
1316a2159beSHoratiu Vultur 
lan966x_xdp_port_deinit(struct lan966x_port * port)1326a2159beSHoratiu Vultur void lan966x_xdp_port_deinit(struct lan966x_port *port)
1336a2159beSHoratiu Vultur {
1346a2159beSHoratiu Vultur 	if (xdp_rxq_info_is_reg(&port->xdp_rxq))
1356a2159beSHoratiu Vultur 		xdp_rxq_info_unreg(&port->xdp_rxq);
1366a2159beSHoratiu Vultur }
137