Commit 6a2159be authored by Horatiu Vultur's avatar Horatiu Vultur Committed by David S. Miller

net: lan966x: Add basic XDP support

Introduce basic XDP support to lan966x driver. Currently the driver
supports only the actions XDP_PASS, XDP_DROP and XDP_ABORTED.
Signed-off-by: default avatarHoratiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4a00b0c7
...@@ -11,4 +11,5 @@ lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \ ...@@ -11,4 +11,5 @@ lan966x-switch-objs := lan966x_main.o lan966x_phylink.o lan966x_port.o \
lan966x_ptp.o lan966x_fdma.o lan966x_lag.o \ lan966x_ptp.o lan966x_fdma.o lan966x_lag.o \
lan966x_tc.o lan966x_mqprio.o lan966x_taprio.o \ lan966x_tc.o lan966x_mqprio.o lan966x_taprio.o \
lan966x_tbf.o lan966x_cbs.o lan966x_ets.o \ lan966x_tbf.o lan966x_cbs.o lan966x_ets.o \
lan966x_tc_matchall.o lan966x_police.o lan966x_mirror.o lan966x_tc_matchall.o lan966x_police.o lan966x_mirror.o \
lan966x_xdp.o
...@@ -423,6 +423,7 @@ static bool lan966x_fdma_rx_more_frames(struct lan966x_rx *rx) ...@@ -423,6 +423,7 @@ static bool lan966x_fdma_rx_more_frames(struct lan966x_rx *rx)
static int lan966x_fdma_rx_check_frame(struct lan966x_rx *rx, u64 *src_port) static int lan966x_fdma_rx_check_frame(struct lan966x_rx *rx, u64 *src_port)
{ {
struct lan966x *lan966x = rx->lan966x; struct lan966x *lan966x = rx->lan966x;
struct lan966x_port *port;
struct lan966x_db *db; struct lan966x_db *db;
struct page *page; struct page *page;
...@@ -443,7 +444,11 @@ static int lan966x_fdma_rx_check_frame(struct lan966x_rx *rx, u64 *src_port) ...@@ -443,7 +444,11 @@ static int lan966x_fdma_rx_check_frame(struct lan966x_rx *rx, u64 *src_port)
if (WARN_ON(*src_port >= lan966x->num_phys_ports)) if (WARN_ON(*src_port >= lan966x->num_phys_ports))
return FDMA_ERROR; return FDMA_ERROR;
return FDMA_PASS; port = lan966x->ports[*src_port];
if (!lan966x_xdp_port_present(port))
return FDMA_PASS;
return lan966x_xdp_run(port, page, FDMA_DCB_STATUS_BLOCKL(db->status));
} }
static struct sk_buff *lan966x_fdma_rx_get_frame(struct lan966x_rx *rx, static struct sk_buff *lan966x_fdma_rx_get_frame(struct lan966x_rx *rx,
...@@ -524,6 +529,10 @@ static int lan966x_fdma_napi_poll(struct napi_struct *napi, int weight) ...@@ -524,6 +529,10 @@ static int lan966x_fdma_napi_poll(struct napi_struct *napi, int weight)
lan966x_fdma_rx_free_page(rx); lan966x_fdma_rx_free_page(rx);
lan966x_fdma_rx_advance_dcb(rx); lan966x_fdma_rx_advance_dcb(rx);
goto allocate_new; goto allocate_new;
case FDMA_DROP:
lan966x_fdma_rx_free_page(rx);
lan966x_fdma_rx_advance_dcb(rx);
continue;
} }
skb = lan966x_fdma_rx_get_frame(rx, src_port); skb = lan966x_fdma_rx_get_frame(rx, src_port);
......
...@@ -468,6 +468,7 @@ static const struct net_device_ops lan966x_port_netdev_ops = { ...@@ -468,6 +468,7 @@ static const struct net_device_ops lan966x_port_netdev_ops = {
.ndo_get_port_parent_id = lan966x_port_get_parent_id, .ndo_get_port_parent_id = lan966x_port_get_parent_id,
.ndo_eth_ioctl = lan966x_port_ioctl, .ndo_eth_ioctl = lan966x_port_ioctl,
.ndo_setup_tc = lan966x_tc_setup, .ndo_setup_tc = lan966x_tc_setup,
.ndo_bpf = lan966x_xdp,
}; };
bool lan966x_netdevice_check(const struct net_device *dev) bool lan966x_netdevice_check(const struct net_device *dev)
...@@ -694,6 +695,7 @@ static void lan966x_cleanup_ports(struct lan966x *lan966x) ...@@ -694,6 +695,7 @@ static void lan966x_cleanup_ports(struct lan966x *lan966x)
if (port->dev) if (port->dev)
unregister_netdev(port->dev); unregister_netdev(port->dev);
lan966x_xdp_port_deinit(port);
if (lan966x->fdma && lan966x->fdma_ndev == port->dev) if (lan966x->fdma && lan966x->fdma_ndev == port->dev)
lan966x_fdma_netdev_deinit(lan966x, port->dev); lan966x_fdma_netdev_deinit(lan966x, port->dev);
...@@ -1136,6 +1138,9 @@ static int lan966x_probe(struct platform_device *pdev) ...@@ -1136,6 +1138,9 @@ static int lan966x_probe(struct platform_device *pdev)
lan966x->ports[p]->serdes = serdes; lan966x->ports[p]->serdes = serdes;
lan966x_port_init(lan966x->ports[p]); lan966x_port_init(lan966x->ports[p]);
err = lan966x_xdp_port_init(lan966x->ports[p]);
if (err)
goto cleanup_ports;
} }
lan966x_mdb_init(lan966x); lan966x_mdb_init(lan966x);
......
...@@ -103,10 +103,12 @@ enum macaccess_entry_type { ...@@ -103,10 +103,12 @@ enum macaccess_entry_type {
/* FDMA return action codes for checking if the frame is valid /* FDMA return action codes for checking if the frame is valid
* FDMA_PASS, frame is valid and can be used * FDMA_PASS, frame is valid and can be used
* FDMA_ERROR, something went wrong, stop getting more frames * FDMA_ERROR, something went wrong, stop getting more frames
* FDMA_DROP, frame is dropped, but continue to get more frames
*/ */
enum lan966x_fdma_action { enum lan966x_fdma_action {
FDMA_PASS = 0, FDMA_PASS = 0,
FDMA_ERROR, FDMA_ERROR,
FDMA_DROP,
}; };
struct lan966x_port; struct lan966x_port;
...@@ -329,6 +331,9 @@ struct lan966x_port { ...@@ -329,6 +331,9 @@ struct lan966x_port {
enum netdev_lag_hash hash_type; enum netdev_lag_hash hash_type;
struct lan966x_port_tc tc; struct lan966x_port_tc tc;
struct bpf_prog *xdp_prog;
struct xdp_rxq_info xdp_rxq;
}; };
extern const struct phylink_mac_ops lan966x_phylink_mac_ops; extern const struct phylink_mac_ops lan966x_phylink_mac_ops;
...@@ -536,6 +541,17 @@ void lan966x_mirror_port_stats(struct lan966x_port *port, ...@@ -536,6 +541,17 @@ void lan966x_mirror_port_stats(struct lan966x_port *port,
struct flow_stats *stats, struct flow_stats *stats,
bool ingress); bool ingress);
int lan966x_xdp_port_init(struct lan966x_port *port);
void lan966x_xdp_port_deinit(struct lan966x_port *port);
int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp);
int lan966x_xdp_run(struct lan966x_port *port,
struct page *page,
u32 data_len);
static inline bool lan966x_xdp_port_present(struct lan966x_port *port)
{
return !!port->xdp_prog;
}
static inline void __iomem *lan_addr(void __iomem *base[], static inline void __iomem *lan_addr(void __iomem *base[],
int id, int tinst, int tcnt, int id, int tinst, int tcnt,
int gbase, int ginst, int gbase, int ginst,
......
// SPDX-License-Identifier: GPL-2.0+
#include <linux/bpf.h>
#include <linux/bpf_trace.h>
#include <linux/filter.h>
#include "lan966x_main.h"
static int lan966x_xdp_setup(struct net_device *dev, struct netdev_bpf *xdp)
{
struct lan966x_port *port = netdev_priv(dev);
struct lan966x *lan966x = port->lan966x;
struct bpf_prog *old_prog;
if (!lan966x->fdma) {
NL_SET_ERR_MSG_MOD(xdp->extack,
"Allow to set xdp only when using fdma");
return -EOPNOTSUPP;
}
old_prog = xchg(&port->xdp_prog, xdp->prog);
if (old_prog)
bpf_prog_put(old_prog);
return 0;
}
int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp)
{
switch (xdp->command) {
case XDP_SETUP_PROG:
return lan966x_xdp_setup(dev, xdp);
default:
return -EINVAL;
}
}
int lan966x_xdp_run(struct lan966x_port *port, struct page *page, u32 data_len)
{
struct bpf_prog *xdp_prog = port->xdp_prog;
struct lan966x *lan966x = port->lan966x;
struct xdp_buff xdp;
u32 act;
xdp_init_buff(&xdp, PAGE_SIZE << lan966x->rx.page_order,
&port->xdp_rxq);
xdp_prepare_buff(&xdp, page_address(page), IFH_LEN_BYTES,
data_len - IFH_LEN_BYTES, false);
act = bpf_prog_run_xdp(xdp_prog, &xdp);
switch (act) {
case XDP_PASS:
return FDMA_PASS;
default:
bpf_warn_invalid_xdp_action(port->dev, xdp_prog, act);
fallthrough;
case XDP_ABORTED:
trace_xdp_exception(port->dev, xdp_prog, act);
fallthrough;
case XDP_DROP:
return FDMA_DROP;
}
}
int lan966x_xdp_port_init(struct lan966x_port *port)
{
struct lan966x *lan966x = port->lan966x;
return xdp_rxq_info_reg(&port->xdp_rxq, port->dev, 0,
lan966x->napi.napi_id);
}
void lan966x_xdp_port_deinit(struct lan966x_port *port)
{
if (xdp_rxq_info_is_reg(&port->xdp_rxq))
xdp_rxq_info_unreg(&port->xdp_rxq);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment