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