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
9static 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
36out:
37 if (old_prog)
38 bpf_prog_put(prog: old_prog);
39
40 return 0;
41}
42
43int 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
53int 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, ptr: xdpf, len: 0);
66 if (err)
67 break;
68
69 nxmit++;
70 }
71
72 return nxmit;
73}
74
75int 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_buff xdp;
80 u32 act;
81
82 xdp_init_buff(xdp: &xdp, PAGE_SIZE << lan966x->rx.page_order,
83 rxq: &port->xdp_rxq);
84 xdp_prepare_buff(xdp: &xdp, page_address(page),
85 IFH_LEN_BYTES + XDP_PACKET_HEADROOM,
86 data_len: data_len - IFH_LEN_BYTES, meta_valid: false);
87 act = bpf_prog_run_xdp(prog: xdp_prog, xdp: &xdp);
88 switch (act) {
89 case XDP_PASS:
90 return FDMA_PASS;
91 case XDP_TX:
92 return lan966x_fdma_xmit_xdpf(port, ptr: page,
93 len: data_len - IFH_LEN_BYTES) ?
94 FDMA_DROP : FDMA_TX;
95 case XDP_REDIRECT:
96 if (xdp_do_redirect(dev: port->dev, xdp: &xdp, prog: xdp_prog))
97 return FDMA_DROP;
98
99 return FDMA_REDIRECT;
100 default:
101 bpf_warn_invalid_xdp_action(dev: port->dev, prog: xdp_prog, act);
102 fallthrough;
103 case XDP_ABORTED:
104 trace_xdp_exception(dev: port->dev, xdp: xdp_prog, act);
105 fallthrough;
106 case XDP_DROP:
107 return FDMA_DROP;
108 }
109}
110
111bool lan966x_xdp_present(struct lan966x *lan966x)
112{
113 for (int p = 0; p < lan966x->num_phys_ports; ++p) {
114 if (!lan966x->ports[p])
115 continue;
116
117 if (lan966x_xdp_port_present(port: lan966x->ports[p]))
118 return true;
119 }
120
121 return false;
122}
123
124int lan966x_xdp_port_init(struct lan966x_port *port)
125{
126 struct lan966x *lan966x = port->lan966x;
127
128 return xdp_rxq_info_reg(xdp_rxq: &port->xdp_rxq, dev: port->dev, queue_index: 0,
129 napi_id: lan966x->napi.napi_id);
130}
131
132void lan966x_xdp_port_deinit(struct lan966x_port *port)
133{
134 if (xdp_rxq_info_is_reg(xdp_rxq: &port->xdp_rxq))
135 xdp_rxq_info_unreg(xdp_rxq: &port->xdp_rxq);
136}
137

source code of linux/drivers/net/ethernet/microchip/lan966x/lan966x_xdp.c