aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Brooks <brian.brooks@linaro.org>2018-08-27 07:37:15 -0500
committerBrian Brooks <brian.brooks@linaro.org>2018-08-27 07:38:54 -0500
commit831b54f325808a891cd69318b24fe88fdcee59f9 (patch)
tree1db9a36104fe310c13363a30872ff83b38ad9be3
parent9a76aba02a37718242d7cdc294f0a3901928aa57 (diff)
downloadmachiattobin-xdp-mvpp2-xdp.tar.gz
[WIP] net: mvpp2: add XDP supportmvpp2-xdp
Signed-off-by: Brian Brooks <brian.brooks@linaro.org>
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2.h8
-rw-r--r--drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c103
2 files changed, 111 insertions, 0 deletions
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
index 67b9e81b7c02..1846d1a21df5 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
@@ -9,11 +9,14 @@
#ifndef _MVPP2_H_
#define _MVPP2_H_
+#include <linux/bpf.h>
+#include <linux/bpf_trace.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/phy.h>
#include <linux/phylink.h>
+#include <net/xdp.h>
/* Fifo Registers */
#define MVPP2_RX_DATA_FIFO_SIZE_REG(port) (0x00 + 4 * (port))
@@ -818,6 +821,9 @@ struct mvpp2_port {
unsigned int ntxqs;
struct net_device *dev;
+ struct xdp_attachment_info xdp;
+ struct bpf_prog *xdp_prog;
+
int pkt_size;
/* Per-CPU port control */
@@ -1057,6 +1063,8 @@ struct mvpp2_rx_queue {
/* Port's logic RXQ number to which physical RXQ is mapped */
int logic_rxq;
+
+ struct xdp_rxq_info xdp_rxq;
};
struct mvpp2_bm_pool {
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index 32d785b616e1..bf91a77cf4d8 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -2093,6 +2093,9 @@ static int mvpp2_rxq_init(struct mvpp2_port *port,
/* Add number of descriptors ready for receiving packets */
mvpp2_rxq_status_update(port, rxq->id, 0, rxq->size);
+ if (xdp_rxq_info_reg(&rxq->xdp_rxq, port->dev, rxq->id) < 0)
+ netdev_err(port->dev, "xdp_rxq_info_reg failed\n");
+
return 0;
}
@@ -2149,6 +2152,8 @@ static void mvpp2_rxq_deinit(struct mvpp2_port *port,
mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_DESC_ADDR_REG, 0);
mvpp2_percpu_write(port->priv, cpu, MVPP2_RXQ_DESC_SIZE_REG, 0);
put_cpu();
+
+ xdp_rxq_info_unreg(&rxq->xdp_rxq);
}
/* Create and initialize a Tx queue */
@@ -2628,11 +2633,17 @@ static int mvpp2_rx(struct mvpp2_port *port, struct napi_struct *napi,
int rx_todo, struct mvpp2_rx_queue *rxq)
{
struct net_device *dev = port->dev;
+ struct bpf_prog *xdp_prog;
+ struct xdp_buff xdp;
int rx_received;
int rx_done = 0;
u32 rcvd_pkts = 0;
u32 rcvd_bytes = 0;
+ rcu_read_lock();
+ xdp_prog = READ_ONCE(port->xdp_prog);
+ xdp.rxq = &rxq->xdp_rxq;
+
/* Get number of received packets and clamp the to-do */
rx_received = mvpp2_rxq_received(port, rxq->id);
if (rx_todo > rx_received)
@@ -2680,6 +2691,39 @@ err_drop_frame:
else
frag_size = bm_pool->frag_size;
+ if (xdp_prog) {
+ int act;
+
+ xdp.data = data + MVPP2_MH_SIZE + NET_SKB_PAD;
+ xdp.data_end = xdp.data + rx_bytes;
+ xdp.data_meta = xdp.data;
+ xdp.data_hard_start = data;
+
+ act = bpf_prog_run_xdp(xdp_prog, &xdp);
+
+ switch (act) {
+ case XDP_PASS:
+ break;
+ case XDP_REDIRECT:
+ err = xdp_do_redirect(dev, &xdp, xdp_prog);
+ if (unlikely(err))
+ goto xdp_abort;
+ /* Return the buffer to the pool */
+ mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
+ default:
+ bpf_warn_invalid_xdp_action(act);
+ /* fallthrough */
+xdp_abort:
+ case XDP_ABORTED:
+ trace_xdp_exception(port->dev, xdp_prog, act);
+ /* fallthrough */
+ case XDP_DROP:
+ /* Return the buffer to the pool */
+ mvpp2_bm_pool_put(port, pool, dma_addr, phys_addr);
+ continue;
+ }
+ }
+
skb = build_skb(data, frag_size);
if (!skb) {
netdev_warn(port->dev, "skb build failed\n");
@@ -2706,6 +2750,8 @@ err_drop_frame:
napi_gro_receive(napi, skb);
}
+ rcu_read_unlock();
+
if (rcvd_pkts) {
struct mvpp2_pcpu_stats *stats = this_cpu_ptr(port->stats);
@@ -3638,6 +3684,62 @@ static int mvpp2_set_features(struct net_device *dev,
return 0;
}
+static int mvpp2_xdp_setup(struct mvpp2_port *port, struct netdev_bpf *bpf)
+{
+ struct bpf_prog *prog = bpf->prog;
+ int ret;
+
+ if (!xdp_attachment_flags_ok(&port->xdp, bpf))
+ return -EBUSY;
+
+ if (!prog == !port->xdp_prog) {
+ // NULL - NULL
+ // prog - prog
+ WRITE_ONCE(port->xdp_prog, prog);
+ xdp_attachment_setup(&port->xdp, bpf);
+ return 0;
+ }
+ // NULL - prog
+ // prog - NULL
+
+ mvpp2_stop_dev(port);
+ mvpp2_cleanup_rxqs(port);
+ mvpp2_cleanup_txqs(port);
+
+ port->xdp_prog = prog;
+ // TODO: Map DMA buffers as BIDIR
+ // TODO: XDP TX queues
+ // TODO: Adjust headroom
+
+ ret = mvpp2_setup_rxqs(port);
+ if (ret)
+ netdev_err(port->dev, "mvpp2_setup_rxqs failed\n");
+ ret = mvpp2_setup_txqs(port);
+ if (ret)
+ netdev_err(port->dev, "mvpp2_setup_txqs failed\n");
+
+ mvpp2_start_dev(port);
+ mvpp2_egress_enable(port);
+ mvpp2_ingress_enable(port);
+
+ xdp_attachment_setup(&port->xdp, bpf);
+ return 0;
+}
+
+static int mvpp2_xdp(struct net_device *dev, struct netdev_bpf *xdp)
+{
+ struct mvpp2_port *port = netdev_priv(dev);
+
+ switch (xdp->command) {
+ case XDP_SETUP_PROG:
+ return mvpp2_xdp_setup(port, xdp);
+ case XDP_QUERY_PROG:
+ return xdp_attachment_query(&port->xdp, xdp);
+ default:
+ return -EINVAL;
+ }
+}
+
/* Ethtool methods */
static int mvpp2_ethtool_nway_reset(struct net_device *dev)
@@ -3924,6 +4026,7 @@ static const struct net_device_ops mvpp2_netdev_ops = {
.ndo_vlan_rx_add_vid = mvpp2_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = mvpp2_vlan_rx_kill_vid,
.ndo_set_features = mvpp2_set_features,
+ .ndo_bpf = mvpp2_xdp,
};
static const struct ethtool_ops mvpp2_eth_tool_ops = {