diff options
author | Daniel Golle <daniel@makrotopia.org> | 2022-08-29 08:54:41 +0200 |
---|---|---|
committer | Daniel Golle <daniel@makrotopia.org> | 2022-09-22 23:55:02 +0100 |
commit | c93c5365c0eb78ba8b479a9fe0cc5ec96f773978 (patch) | |
tree | b250435d0f0e8e66c56d0486d1151d4eb1fc827e /target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch | |
parent | 524f52a471495d2c4e764539e000cb699610de1f (diff) | |
download | upstream-c93c5365c0eb78ba8b479a9fe0cc5ec96f773978.tar.gz upstream-c93c5365c0eb78ba8b479a9fe0cc5ec96f773978.tar.bz2 upstream-c93c5365c0eb78ba8b479a9fe0cc5ec96f773978.zip |
kernel: pick patches for MediaTek Ethernet from linux-next
Pick patches with several fixes and improvements, preparation for
upcoming WED (TX) [1] as well as basic XDP support [2] with MediaTek's
Filogic SoCs to the mtk_eth_soc driver.
Also pick follow-up patch fixing Ethernet on MT7621 [3].
Tested on Bananapi BPi-R3 (MT7986), Bananapi BPi-R64 (MT7622),
Bananapi BPi-R2 (MT7623), MikroTik RouterBoard M11G (MT7621).
[1]: https://patchwork.kernel.org/project/netdevbpf/list/?series=662108&state=*
[2]: https://patchwork.kernel.org/project/netdevbpf/list/?series=675368&state=*
(the first part of the series adding wed nodes to mt7986a.dtsi was
applied to the copy of mt7986a.dtsi in our tree)
[3]: https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=5e69163d3b9931098922b3fc2f8e786af8c1f37e
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
Diffstat (limited to 'target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch')
-rw-r--r-- | target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch b/target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch new file mode 100644 index 0000000000..b930152dd1 --- /dev/null +++ b/target/linux/generic/backport-5.15/706-01-v6.0-net-ethernet-mtk_eth_soc-add-basic-XDP-support.patch @@ -0,0 +1,291 @@ +From 7c26c20da5d420cde55618263be4aa2f6de53056 Mon Sep 17 00:00:00 2001 +From: Lorenzo Bianconi <lorenzo@kernel.org> +Date: Fri, 22 Jul 2022 09:19:37 +0200 +Subject: [PATCH] net: ethernet: mtk_eth_soc: add basic XDP support + +Introduce basic XDP support to mtk_eth_soc driver. +Supported XDP verdicts: +- XDP_PASS +- XDP_DROP +- XDP_REDIRECT + +Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org> +Signed-off-by: David S. Miller <davem@davemloft.net> +--- + drivers/net/ethernet/mediatek/mtk_eth_soc.c | 162 +++++++++++++++++--- + drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 + + 2 files changed, 145 insertions(+), 19 deletions(-) + +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c +@@ -1388,6 +1388,11 @@ static void mtk_update_rx_cpu_idx(struct + } + } + ++static bool mtk_page_pool_enabled(struct mtk_eth *eth) ++{ ++ return !eth->hwlro; ++} ++ + static struct page_pool *mtk_create_page_pool(struct mtk_eth *eth, + struct xdp_rxq_info *xdp_q, + int id, int size) +@@ -1450,11 +1455,52 @@ static void mtk_rx_put_buff(struct mtk_r + skb_free_frag(data); + } + ++static u32 mtk_xdp_run(struct mtk_eth *eth, struct mtk_rx_ring *ring, ++ struct xdp_buff *xdp, struct net_device *dev) ++{ ++ struct bpf_prog *prog; ++ u32 act = XDP_PASS; ++ ++ rcu_read_lock(); ++ ++ prog = rcu_dereference(eth->prog); ++ if (!prog) ++ goto out; ++ ++ act = bpf_prog_run_xdp(prog, xdp); ++ switch (act) { ++ case XDP_PASS: ++ goto out; ++ case XDP_REDIRECT: ++ if (unlikely(xdp_do_redirect(dev, xdp, prog))) { ++ act = XDP_DROP; ++ break; ++ } ++ goto out; ++ default: ++ bpf_warn_invalid_xdp_action(act); ++ fallthrough; ++ case XDP_ABORTED: ++ trace_xdp_exception(dev, prog, act); ++ fallthrough; ++ case XDP_DROP: ++ break; ++ } ++ ++ page_pool_put_full_page(ring->page_pool, ++ virt_to_head_page(xdp->data), true); ++out: ++ rcu_read_unlock(); ++ ++ return act; ++} ++ + static int mtk_poll_rx(struct napi_struct *napi, int budget, + struct mtk_eth *eth) + { + struct dim_sample dim_sample = {}; + struct mtk_rx_ring *ring; ++ bool xdp_flush = false; + int idx; + struct sk_buff *skb; + u8 *data, *new_data; +@@ -1463,9 +1509,9 @@ static int mtk_poll_rx(struct napi_struc + + while (done < budget) { + unsigned int pktlen, *rxdcsum; +- u32 hash, reason, reserve_len; + struct net_device *netdev; + dma_addr_t dma_addr; ++ u32 hash, reason; + int mac = 0; + + ring = mtk_get_rx_ring(eth); +@@ -1495,8 +1541,14 @@ static int mtk_poll_rx(struct napi_struc + if (unlikely(test_bit(MTK_RESETTING, ð->state))) + goto release_desc; + ++ pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); ++ + /* alloc new buffer */ + if (ring->page_pool) { ++ struct page *page = virt_to_head_page(data); ++ struct xdp_buff xdp; ++ u32 ret; ++ + new_data = mtk_page_pool_get_buff(ring->page_pool, + &dma_addr, + GFP_ATOMIC); +@@ -1504,6 +1556,34 @@ static int mtk_poll_rx(struct napi_struc + netdev->stats.rx_dropped++; + goto release_desc; + } ++ ++ dma_sync_single_for_cpu(eth->dma_dev, ++ page_pool_get_dma_addr(page) + MTK_PP_HEADROOM, ++ pktlen, page_pool_get_dma_dir(ring->page_pool)); ++ ++ xdp_init_buff(&xdp, PAGE_SIZE, &ring->xdp_q); ++ xdp_prepare_buff(&xdp, data, MTK_PP_HEADROOM, pktlen, ++ false); ++ xdp_buff_clear_frags_flag(&xdp); ++ ++ ret = mtk_xdp_run(eth, ring, &xdp, netdev); ++ if (ret == XDP_REDIRECT) ++ xdp_flush = true; ++ ++ if (ret != XDP_PASS) ++ goto skip_rx; ++ ++ skb = build_skb(data, PAGE_SIZE); ++ if (unlikely(!skb)) { ++ page_pool_put_full_page(ring->page_pool, ++ page, true); ++ netdev->stats.rx_dropped++; ++ goto skip_rx; ++ } ++ ++ skb_reserve(skb, xdp.data - xdp.data_hard_start); ++ skb_put(skb, xdp.data_end - xdp.data); ++ skb_mark_for_recycle(skb); + } else { + if (ring->frag_size <= PAGE_SIZE) + new_data = napi_alloc_frag(ring->frag_size); +@@ -1527,27 +1607,20 @@ static int mtk_poll_rx(struct napi_struc + + dma_unmap_single(eth->dma_dev, trxd.rxd1, + ring->buf_size, DMA_FROM_DEVICE); +- } + +- /* receive data */ +- skb = build_skb(data, ring->frag_size); +- if (unlikely(!skb)) { +- mtk_rx_put_buff(ring, data, true); +- netdev->stats.rx_dropped++; +- goto skip_rx; +- } ++ skb = build_skb(data, ring->frag_size); ++ if (unlikely(!skb)) { ++ netdev->stats.rx_dropped++; ++ skb_free_frag(data); ++ goto skip_rx; ++ } + +- if (ring->page_pool) { +- reserve_len = MTK_PP_HEADROOM; +- skb_mark_for_recycle(skb); +- } else { +- reserve_len = NET_SKB_PAD + NET_IP_ALIGN; ++ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); ++ skb_put(skb, pktlen); + } +- skb_reserve(skb, reserve_len); + +- pktlen = RX_DMA_GET_PLEN0(trxd.rxd2); + skb->dev = netdev; +- skb_put(skb, pktlen); ++ bytes += skb->len; + + if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) + rxdcsum = &trxd.rxd3; +@@ -1559,7 +1632,6 @@ static int mtk_poll_rx(struct napi_struc + else + skb_checksum_none_assert(skb); + skb->protocol = eth_type_trans(skb, netdev); +- bytes += pktlen; + + hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY; + if (hash != MTK_RXD4_FOE_ENTRY) { +@@ -1622,6 +1694,9 @@ rx_done: + &dim_sample); + net_dim(ð->rx_dim, dim_sample); + ++ if (xdp_flush) ++ xdp_do_flush_map(); ++ + return done; + } + +@@ -1967,7 +2042,7 @@ static int mtk_rx_alloc(struct mtk_eth * + if (!ring->data) + return -ENOMEM; + +- if (!eth->hwlro) { ++ if (mtk_page_pool_enabled(eth)) { + struct page_pool *pp; + + pp = mtk_create_page_pool(eth, &ring->xdp_q, ring_no, +@@ -2707,6 +2782,48 @@ static int mtk_stop(struct net_device *d + return 0; + } + ++static int mtk_xdp_setup(struct net_device *dev, struct bpf_prog *prog, ++ struct netlink_ext_ack *extack) ++{ ++ struct mtk_mac *mac = netdev_priv(dev); ++ struct mtk_eth *eth = mac->hw; ++ struct bpf_prog *old_prog; ++ bool need_update; ++ ++ if (eth->hwlro) { ++ NL_SET_ERR_MSG_MOD(extack, "XDP not supported with HWLRO"); ++ return -EOPNOTSUPP; ++ } ++ ++ if (dev->mtu > MTK_PP_MAX_BUF_SIZE) { ++ NL_SET_ERR_MSG_MOD(extack, "MTU too large for XDP"); ++ return -EOPNOTSUPP; ++ } ++ ++ need_update = !!eth->prog != !!prog; ++ if (netif_running(dev) && need_update) ++ mtk_stop(dev); ++ ++ old_prog = rcu_replace_pointer(eth->prog, prog, lockdep_rtnl_is_held()); ++ if (old_prog) ++ bpf_prog_put(old_prog); ++ ++ if (netif_running(dev) && need_update) ++ return mtk_open(dev); ++ ++ return 0; ++} ++ ++static int mtk_xdp(struct net_device *dev, struct netdev_bpf *xdp) ++{ ++ switch (xdp->command) { ++ case XDP_SETUP_PROG: ++ return mtk_xdp_setup(dev, xdp->prog, xdp->extack); ++ default: ++ return -EINVAL; ++ } ++} ++ + static void ethsys_reset(struct mtk_eth *eth, u32 reset_bits) + { + regmap_update_bits(eth->ethsys, ETHSYS_RSTCTRL, +@@ -3002,6 +3119,12 @@ static int mtk_change_mtu(struct net_dev + struct mtk_eth *eth = mac->hw; + u32 mcr_cur, mcr_new; + ++ if (rcu_access_pointer(eth->prog) && ++ length > MTK_PP_MAX_BUF_SIZE) { ++ netdev_err(dev, "Invalid MTU for XDP mode\n"); ++ return -EINVAL; ++ } ++ + if (!MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) { + mcr_cur = mtk_r32(mac->hw, MTK_MAC_MCR(mac->id)); + mcr_new = mcr_cur & ~MAC_MCR_MAX_RX_MASK; +@@ -3329,6 +3452,7 @@ static const struct net_device_ops mtk_n + .ndo_poll_controller = mtk_poll_controller, + #endif + .ndo_setup_tc = mtk_eth_setup_tc, ++ .ndo_bpf = mtk_xdp, + }; + + static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np) +--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h ++++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h +@@ -1085,6 +1085,8 @@ struct mtk_eth { + + struct mtk_ppe *ppe; + struct rhashtable flow_table; ++ ++ struct bpf_prog __rcu *prog; + }; + + /* struct mtk_mac - the structure that holds the info about the MACs of the |