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

net: lan966x: Add support for XDP_REDIRECT

Extend lan966x XDP support with the action XDP_REDIRECT. This is similar
with the XDP_TX, so a lot of functionality can be reused.
Signed-off-by: default avatarHoratiu Vultur <horatiu.vultur@microchip.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 19c6f534
// SPDX-License-Identifier: GPL-2.0+ // SPDX-License-Identifier: GPL-2.0+
#include <linux/bpf.h> #include <linux/bpf.h>
#include <linux/filter.h>
#include "lan966x_main.h" #include "lan966x_main.h"
...@@ -390,11 +391,14 @@ static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight) ...@@ -390,11 +391,14 @@ static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight)
{ {
struct lan966x_tx *tx = &lan966x->tx; struct lan966x_tx *tx = &lan966x->tx;
struct lan966x_tx_dcb_buf *dcb_buf; struct lan966x_tx_dcb_buf *dcb_buf;
struct xdp_frame_bulk bq;
struct lan966x_db *db; struct lan966x_db *db;
unsigned long flags; unsigned long flags;
bool clear = false; bool clear = false;
int i; int i;
xdp_frame_bulk_init(&bq);
spin_lock_irqsave(&lan966x->tx_lock, flags); spin_lock_irqsave(&lan966x->tx_lock, flags);
for (i = 0; i < FDMA_DCB_MAX; ++i) { for (i = 0; i < FDMA_DCB_MAX; ++i) {
dcb_buf = &tx->dcbs_buf[i]; dcb_buf = &tx->dcbs_buf[i];
...@@ -419,12 +423,23 @@ static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight) ...@@ -419,12 +423,23 @@ static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight)
if (!dcb_buf->ptp) if (!dcb_buf->ptp)
napi_consume_skb(dcb_buf->data.skb, weight); napi_consume_skb(dcb_buf->data.skb, weight);
} else { } else {
if (dcb_buf->xdp_ndo)
dma_unmap_single(lan966x->dev,
dcb_buf->dma_addr,
dcb_buf->len,
DMA_TO_DEVICE);
if (dcb_buf->xdp_ndo)
xdp_return_frame_bulk(dcb_buf->data.xdpf, &bq);
else
xdp_return_frame_rx_napi(dcb_buf->data.xdpf); xdp_return_frame_rx_napi(dcb_buf->data.xdpf);
} }
clear = true; clear = true;
} }
xdp_flush_frame_bulk(&bq);
if (clear) if (clear)
lan966x_fdma_wakeup_netdev(lan966x); lan966x_fdma_wakeup_netdev(lan966x);
...@@ -531,6 +546,7 @@ static int lan966x_fdma_napi_poll(struct napi_struct *napi, int weight) ...@@ -531,6 +546,7 @@ static int lan966x_fdma_napi_poll(struct napi_struct *napi, int weight)
int dcb_reload = rx->dcb_index; int dcb_reload = rx->dcb_index;
struct lan966x_rx_dcb *old_dcb; struct lan966x_rx_dcb *old_dcb;
struct lan966x_db *db; struct lan966x_db *db;
bool redirect = false;
struct sk_buff *skb; struct sk_buff *skb;
struct page *page; struct page *page;
int counter = 0; int counter = 0;
...@@ -553,6 +569,9 @@ static int lan966x_fdma_napi_poll(struct napi_struct *napi, int weight) ...@@ -553,6 +569,9 @@ 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_REDIRECT:
redirect = true;
fallthrough;
case FDMA_TX: case FDMA_TX:
lan966x_fdma_rx_advance_dcb(rx); lan966x_fdma_rx_advance_dcb(rx);
continue; continue;
...@@ -592,6 +611,9 @@ static int lan966x_fdma_napi_poll(struct napi_struct *napi, int weight) ...@@ -592,6 +611,9 @@ static int lan966x_fdma_napi_poll(struct napi_struct *napi, int weight)
if (counter < weight && napi_complete_done(napi, counter)) if (counter < weight && napi_complete_done(napi, counter))
lan_wr(0xff, lan966x, FDMA_INTR_DB_ENA); lan_wr(0xff, lan966x, FDMA_INTR_DB_ENA);
if (redirect)
xdp_do_flush();
return counter; return counter;
} }
...@@ -679,7 +701,8 @@ static void lan966x_fdma_tx_start(struct lan966x_tx *tx, int next_to_use) ...@@ -679,7 +701,8 @@ static void lan966x_fdma_tx_start(struct lan966x_tx *tx, int next_to_use)
int lan966x_fdma_xmit_xdpf(struct lan966x_port *port, int lan966x_fdma_xmit_xdpf(struct lan966x_port *port,
struct xdp_frame *xdpf, struct xdp_frame *xdpf,
struct page *page) struct page *page,
bool dma_map)
{ {
struct lan966x *lan966x = port->lan966x; struct lan966x *lan966x = port->lan966x;
struct lan966x_tx_dcb_buf *next_dcb_buf; struct lan966x_tx_dcb_buf *next_dcb_buf;
...@@ -700,24 +723,53 @@ int lan966x_fdma_xmit_xdpf(struct lan966x_port *port, ...@@ -700,24 +723,53 @@ int lan966x_fdma_xmit_xdpf(struct lan966x_port *port,
} }
/* Generate new IFH */ /* Generate new IFH */
if (dma_map) {
if (xdpf->headroom < IFH_LEN_BYTES) {
ret = NETDEV_TX_OK;
goto out;
}
ifh = xdpf->data - IFH_LEN_BYTES;
memset(ifh, 0x0, sizeof(__be32) * IFH_LEN);
lan966x_ifh_set_bypass(ifh, 1);
lan966x_ifh_set_port(ifh, BIT_ULL(port->chip_port));
dma_addr = dma_map_single(lan966x->dev,
xdpf->data - IFH_LEN_BYTES,
xdpf->len + IFH_LEN_BYTES,
DMA_TO_DEVICE);
if (dma_mapping_error(lan966x->dev, dma_addr)) {
ret = NETDEV_TX_OK;
goto out;
}
/* Setup next dcb */
lan966x_fdma_tx_setup_dcb(tx, next_to_use,
xdpf->len + IFH_LEN_BYTES,
dma_addr);
} else {
ifh = page_address(page) + XDP_PACKET_HEADROOM; ifh = page_address(page) + XDP_PACKET_HEADROOM;
memset(ifh, 0x0, sizeof(__be32) * IFH_LEN); memset(ifh, 0x0, sizeof(__be32) * IFH_LEN);
lan966x_ifh_set_bypass(ifh, 1); lan966x_ifh_set_bypass(ifh, 1);
lan966x_ifh_set_port(ifh, BIT_ULL(port->chip_port)); lan966x_ifh_set_port(ifh, BIT_ULL(port->chip_port));
dma_addr = page_pool_get_dma_addr(page); dma_addr = page_pool_get_dma_addr(page);
dma_sync_single_for_device(lan966x->dev, dma_addr + XDP_PACKET_HEADROOM, dma_sync_single_for_device(lan966x->dev,
dma_addr + XDP_PACKET_HEADROOM,
xdpf->len + IFH_LEN_BYTES, xdpf->len + IFH_LEN_BYTES,
DMA_TO_DEVICE); DMA_TO_DEVICE);
/* Setup next dcb */ /* Setup next dcb */
lan966x_fdma_tx_setup_dcb(tx, next_to_use, xdpf->len + IFH_LEN_BYTES, lan966x_fdma_tx_setup_dcb(tx, next_to_use,
xdpf->len + IFH_LEN_BYTES,
dma_addr + XDP_PACKET_HEADROOM); dma_addr + XDP_PACKET_HEADROOM);
}
/* Fill up the buffer */ /* Fill up the buffer */
next_dcb_buf = &tx->dcbs_buf[next_to_use]; next_dcb_buf = &tx->dcbs_buf[next_to_use];
next_dcb_buf->use_skb = false; next_dcb_buf->use_skb = false;
next_dcb_buf->data.xdpf = xdpf; next_dcb_buf->data.xdpf = xdpf;
next_dcb_buf->xdp_ndo = dma_map;
next_dcb_buf->len = xdpf->len + IFH_LEN_BYTES; next_dcb_buf->len = xdpf->len + IFH_LEN_BYTES;
next_dcb_buf->dma_addr = dma_addr; next_dcb_buf->dma_addr = dma_addr;
next_dcb_buf->used = true; next_dcb_buf->used = true;
...@@ -790,6 +842,7 @@ int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev) ...@@ -790,6 +842,7 @@ int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev)
next_dcb_buf = &tx->dcbs_buf[next_to_use]; next_dcb_buf = &tx->dcbs_buf[next_to_use];
next_dcb_buf->use_skb = true; next_dcb_buf->use_skb = true;
next_dcb_buf->data.skb = skb; next_dcb_buf->data.skb = skb;
next_dcb_buf->xdp_ndo = false;
next_dcb_buf->len = skb->len; next_dcb_buf->len = skb->len;
next_dcb_buf->dma_addr = dma_addr; next_dcb_buf->dma_addr = dma_addr;
next_dcb_buf->used = true; next_dcb_buf->used = true;
......
...@@ -469,6 +469,7 @@ static const struct net_device_ops lan966x_port_netdev_ops = { ...@@ -469,6 +469,7 @@ static const struct net_device_ops lan966x_port_netdev_ops = {
.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, .ndo_bpf = lan966x_xdp,
.ndo_xdp_xmit = lan966x_xdp_xmit,
}; };
bool lan966x_netdevice_check(const struct net_device *dev) bool lan966x_netdevice_check(const struct net_device *dev)
......
...@@ -106,12 +106,14 @@ enum macaccess_entry_type { ...@@ -106,12 +106,14 @@ enum macaccess_entry_type {
* 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 * FDMA_DROP, frame is dropped, but continue to get more frames
* FDMA_TX, frame is given to TX, but continue to get more frames * FDMA_TX, frame is given to TX, but continue to get more frames
* FDMA_REDIRECT, frame is given to TX, 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, FDMA_DROP,
FDMA_TX, FDMA_TX,
FDMA_REDIRECT,
}; };
struct lan966x_port; struct lan966x_port;
...@@ -185,6 +187,7 @@ struct lan966x_tx_dcb_buf { ...@@ -185,6 +187,7 @@ struct lan966x_tx_dcb_buf {
u32 used : 1; u32 used : 1;
u32 ptp : 1; u32 ptp : 1;
u32 use_skb : 1; u32 use_skb : 1;
u32 xdp_ndo : 1;
}; };
struct lan966x_tx { struct lan966x_tx {
...@@ -470,7 +473,8 @@ int lan966x_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts); ...@@ -470,7 +473,8 @@ int lan966x_ptp_gettime64(struct ptp_clock_info *ptp, struct timespec64 *ts);
int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev); int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev);
int lan966x_fdma_xmit_xdpf(struct lan966x_port *port, int lan966x_fdma_xmit_xdpf(struct lan966x_port *port,
struct xdp_frame *frame, struct xdp_frame *frame,
struct page *page); struct page *page,
bool dma_map);
int lan966x_fdma_change_mtu(struct lan966x *lan966x); int lan966x_fdma_change_mtu(struct lan966x *lan966x);
void lan966x_fdma_netdev_init(struct lan966x *lan966x, struct net_device *dev); void lan966x_fdma_netdev_init(struct lan966x *lan966x, struct net_device *dev);
void lan966x_fdma_netdev_deinit(struct lan966x *lan966x, struct net_device *dev); void lan966x_fdma_netdev_deinit(struct lan966x *lan966x, struct net_device *dev);
...@@ -568,6 +572,10 @@ int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp); ...@@ -568,6 +572,10 @@ int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp);
int lan966x_xdp_run(struct lan966x_port *port, int lan966x_xdp_run(struct lan966x_port *port,
struct page *page, struct page *page,
u32 data_len); u32 data_len);
int lan966x_xdp_xmit(struct net_device *dev,
int n,
struct xdp_frame **frames,
u32 flags);
bool lan966x_xdp_present(struct lan966x *lan966x); bool lan966x_xdp_present(struct lan966x *lan966x);
static inline bool lan966x_xdp_port_present(struct lan966x_port *port) static inline bool lan966x_xdp_port_present(struct lan966x_port *port)
{ {
......
...@@ -50,6 +50,28 @@ int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp) ...@@ -50,6 +50,28 @@ int lan966x_xdp(struct net_device *dev, struct netdev_bpf *xdp)
} }
} }
int lan966x_xdp_xmit(struct net_device *dev,
int n,
struct xdp_frame **frames,
u32 flags)
{
struct lan966x_port *port = netdev_priv(dev);
int nxmit = 0;
for (int i = 0; i < n; ++i) {
struct xdp_frame *xdpf = frames[i];
int err;
err = lan966x_fdma_xmit_xdpf(port, xdpf, NULL, true);
if (err)
break;
nxmit++;
}
return nxmit;
}
int lan966x_xdp_run(struct lan966x_port *port, struct page *page, u32 data_len) int lan966x_xdp_run(struct lan966x_port *port, struct page *page, u32 data_len)
{ {
struct bpf_prog *xdp_prog = port->xdp_prog; struct bpf_prog *xdp_prog = port->xdp_prog;
...@@ -72,8 +94,13 @@ int lan966x_xdp_run(struct lan966x_port *port, struct page *page, u32 data_len) ...@@ -72,8 +94,13 @@ int lan966x_xdp_run(struct lan966x_port *port, struct page *page, u32 data_len)
if (!xdpf) if (!xdpf)
return FDMA_DROP; return FDMA_DROP;
return lan966x_fdma_xmit_xdpf(port, xdpf, page) ? return lan966x_fdma_xmit_xdpf(port, xdpf, page, false) ?
FDMA_DROP : FDMA_TX; FDMA_DROP : FDMA_TX;
case XDP_REDIRECT:
if (xdp_do_redirect(port->dev, &xdp, xdp_prog))
return FDMA_DROP;
return FDMA_REDIRECT;
default: default:
bpf_warn_invalid_xdp_action(port->dev, xdp_prog, act); bpf_warn_invalid_xdp_action(port->dev, xdp_prog, act);
fallthrough; fallthrough;
......
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