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, NULL, true); 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_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 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 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 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