mirror of
https://github.com/openwrt/openwrt.git
synced 2025-01-21 03:55:06 +00:00
mediatek: add patches for MT7622 WED (wireless ethernet dispatch)
This series also contains other improvement for hardware flow offload support
Signed-off-by: Felix Fietkau <nbd@nbd.name>
(cherry-picked from commit 0f029b3d2b
)
This commit is contained in:
parent
5ff900e0ad
commit
77e123340f
@ -19,7 +19,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -1618,6 +1618,7 @@ enum netdev_priv_flags {
|
||||
@@ -1625,6 +1625,7 @@ enum netdev_priv_flags {
|
||||
IFF_FAILOVER_SLAVE = 1<<28,
|
||||
IFF_L3MDEV_RX_HANDLER = 1<<29,
|
||||
IFF_LIVE_RENAME_OK = 1<<30,
|
||||
@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
};
|
||||
|
||||
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
|
||||
@@ -1650,6 +1651,7 @@ enum netdev_priv_flags {
|
||||
@@ -1657,6 +1658,7 @@ enum netdev_priv_flags {
|
||||
#define IFF_FAILOVER_SLAVE IFF_FAILOVER_SLAVE
|
||||
#define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER
|
||||
#define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK
|
||||
@ -35,7 +35,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
/* Specifies the type of the struct net_device::ml_priv pointer */
|
||||
enum netdev_ml_priv_type {
|
||||
@@ -1990,6 +1992,11 @@ struct net_device {
|
||||
@@ -1997,6 +1999,11 @@ struct net_device {
|
||||
const struct tlsdev_ops *tlsdev_ops;
|
||||
#endif
|
||||
|
||||
@ -47,7 +47,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
const struct header_ops *header_ops;
|
||||
|
||||
unsigned int flags;
|
||||
@@ -2080,6 +2087,10 @@ struct net_device {
|
||||
@@ -2087,6 +2094,10 @@ struct net_device {
|
||||
struct mpls_dev __rcu *mpls_ptr;
|
||||
#endif
|
||||
|
||||
@ -105,7 +105,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
help
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -3646,6 +3646,11 @@ static int xmit_one(struct sk_buff *skb,
|
||||
@@ -3650,6 +3650,11 @@ static int xmit_one(struct sk_buff *skb,
|
||||
if (dev_nit_active(dev))
|
||||
dev_queue_xmit_nit(skb, dev);
|
||||
|
||||
|
@ -0,0 +1,327 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 5 Feb 2022 17:59:07 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for coherent
|
||||
DMA
|
||||
|
||||
It improves performance by eliminating the need for a cache flush on rx and tx
|
||||
In preparation for supporting WED (Wireless Ethernet Dispatch), also add a
|
||||
function for disabling coherent DMA at runtime.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_mdio.h>
|
||||
#include <linux/of_net.h>
|
||||
+#include <linux/of_address.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
@@ -821,7 +822,7 @@ static int mtk_init_fq_dma(struct mtk_et
|
||||
dma_addr_t dma_addr;
|
||||
int i;
|
||||
|
||||
- eth->scratch_ring = dma_alloc_coherent(eth->dev,
|
||||
+ eth->scratch_ring = dma_alloc_coherent(eth->dma_dev,
|
||||
cnt * sizeof(struct mtk_tx_dma),
|
||||
ð->phy_scratch_ring,
|
||||
GFP_ATOMIC);
|
||||
@@ -833,10 +834,10 @@ static int mtk_init_fq_dma(struct mtk_et
|
||||
if (unlikely(!eth->scratch_head))
|
||||
return -ENOMEM;
|
||||
|
||||
- dma_addr = dma_map_single(eth->dev,
|
||||
+ dma_addr = dma_map_single(eth->dma_dev,
|
||||
eth->scratch_head, cnt * MTK_QDMA_PAGE_SIZE,
|
||||
DMA_FROM_DEVICE);
|
||||
- if (unlikely(dma_mapping_error(eth->dev, dma_addr)))
|
||||
+ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr)))
|
||||
return -ENOMEM;
|
||||
|
||||
phy_ring_tail = eth->phy_scratch_ring +
|
||||
@@ -890,26 +891,26 @@ static void mtk_tx_unmap(struct mtk_eth
|
||||
{
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
|
||||
if (tx_buf->flags & MTK_TX_FLAGS_SINGLE0) {
|
||||
- dma_unmap_single(eth->dev,
|
||||
+ dma_unmap_single(eth->dma_dev,
|
||||
dma_unmap_addr(tx_buf, dma_addr0),
|
||||
dma_unmap_len(tx_buf, dma_len0),
|
||||
DMA_TO_DEVICE);
|
||||
} else if (tx_buf->flags & MTK_TX_FLAGS_PAGE0) {
|
||||
- dma_unmap_page(eth->dev,
|
||||
+ dma_unmap_page(eth->dma_dev,
|
||||
dma_unmap_addr(tx_buf, dma_addr0),
|
||||
dma_unmap_len(tx_buf, dma_len0),
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
} else {
|
||||
if (dma_unmap_len(tx_buf, dma_len0)) {
|
||||
- dma_unmap_page(eth->dev,
|
||||
+ dma_unmap_page(eth->dma_dev,
|
||||
dma_unmap_addr(tx_buf, dma_addr0),
|
||||
dma_unmap_len(tx_buf, dma_len0),
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
if (dma_unmap_len(tx_buf, dma_len1)) {
|
||||
- dma_unmap_page(eth->dev,
|
||||
+ dma_unmap_page(eth->dma_dev,
|
||||
dma_unmap_addr(tx_buf, dma_addr1),
|
||||
dma_unmap_len(tx_buf, dma_len1),
|
||||
DMA_TO_DEVICE);
|
||||
@@ -987,9 +988,9 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
if (skb_vlan_tag_present(skb))
|
||||
txd4 |= TX_DMA_INS_VLAN | skb_vlan_tag_get(skb);
|
||||
|
||||
- mapped_addr = dma_map_single(eth->dev, skb->data,
|
||||
+ mapped_addr = dma_map_single(eth->dma_dev, skb->data,
|
||||
skb_headlen(skb), DMA_TO_DEVICE);
|
||||
- if (unlikely(dma_mapping_error(eth->dev, mapped_addr)))
|
||||
+ if (unlikely(dma_mapping_error(eth->dma_dev, mapped_addr)))
|
||||
return -ENOMEM;
|
||||
|
||||
WRITE_ONCE(itxd->txd1, mapped_addr);
|
||||
@@ -1028,10 +1029,10 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
|
||||
|
||||
frag_map_size = min(frag_size, MTK_TX_DMA_BUF_LEN);
|
||||
- mapped_addr = skb_frag_dma_map(eth->dev, frag, offset,
|
||||
+ mapped_addr = skb_frag_dma_map(eth->dma_dev, frag, offset,
|
||||
frag_map_size,
|
||||
DMA_TO_DEVICE);
|
||||
- if (unlikely(dma_mapping_error(eth->dev, mapped_addr)))
|
||||
+ if (unlikely(dma_mapping_error(eth->dma_dev, mapped_addr)))
|
||||
goto err_dma;
|
||||
|
||||
if (i == nr_frags - 1 &&
|
||||
@@ -1309,18 +1310,18 @@ static int mtk_poll_rx(struct napi_struc
|
||||
netdev->stats.rx_dropped++;
|
||||
goto release_desc;
|
||||
}
|
||||
- dma_addr = dma_map_single(eth->dev,
|
||||
+ dma_addr = dma_map_single(eth->dma_dev,
|
||||
new_data + NET_SKB_PAD +
|
||||
eth->ip_align,
|
||||
ring->buf_size,
|
||||
DMA_FROM_DEVICE);
|
||||
- if (unlikely(dma_mapping_error(eth->dev, dma_addr))) {
|
||||
+ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr))) {
|
||||
skb_free_frag(new_data);
|
||||
netdev->stats.rx_dropped++;
|
||||
goto release_desc;
|
||||
}
|
||||
|
||||
- dma_unmap_single(eth->dev, trxd.rxd1,
|
||||
+ dma_unmap_single(eth->dma_dev, trxd.rxd1,
|
||||
ring->buf_size, DMA_FROM_DEVICE);
|
||||
|
||||
/* receive data */
|
||||
@@ -1593,7 +1594,7 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
if (!ring->buf)
|
||||
goto no_tx_mem;
|
||||
|
||||
- ring->dma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz,
|
||||
+ ring->dma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz,
|
||||
&ring->phys, GFP_ATOMIC);
|
||||
if (!ring->dma)
|
||||
goto no_tx_mem;
|
||||
@@ -1611,7 +1612,7 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
* descriptors in ring->dma_pdma.
|
||||
*/
|
||||
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
|
||||
- ring->dma_pdma = dma_alloc_coherent(eth->dev, MTK_DMA_SIZE * sz,
|
||||
+ ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz,
|
||||
&ring->phys_pdma,
|
||||
GFP_ATOMIC);
|
||||
if (!ring->dma_pdma)
|
||||
@@ -1670,7 +1671,7 @@ static void mtk_tx_clean(struct mtk_eth
|
||||
}
|
||||
|
||||
if (ring->dma) {
|
||||
- dma_free_coherent(eth->dev,
|
||||
+ dma_free_coherent(eth->dma_dev,
|
||||
MTK_DMA_SIZE * sizeof(*ring->dma),
|
||||
ring->dma,
|
||||
ring->phys);
|
||||
@@ -1678,7 +1679,7 @@ static void mtk_tx_clean(struct mtk_eth
|
||||
}
|
||||
|
||||
if (ring->dma_pdma) {
|
||||
- dma_free_coherent(eth->dev,
|
||||
+ dma_free_coherent(eth->dma_dev,
|
||||
MTK_DMA_SIZE * sizeof(*ring->dma_pdma),
|
||||
ring->dma_pdma,
|
||||
ring->phys_pdma);
|
||||
@@ -1723,18 +1724,18 @@ static int mtk_rx_alloc(struct mtk_eth *
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
- ring->dma = dma_alloc_coherent(eth->dev,
|
||||
+ ring->dma = dma_alloc_coherent(eth->dma_dev,
|
||||
rx_dma_size * sizeof(*ring->dma),
|
||||
&ring->phys, GFP_ATOMIC);
|
||||
if (!ring->dma)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < rx_dma_size; i++) {
|
||||
- dma_addr_t dma_addr = dma_map_single(eth->dev,
|
||||
+ dma_addr_t dma_addr = dma_map_single(eth->dma_dev,
|
||||
ring->data[i] + NET_SKB_PAD + eth->ip_align,
|
||||
ring->buf_size,
|
||||
DMA_FROM_DEVICE);
|
||||
- if (unlikely(dma_mapping_error(eth->dev, dma_addr)))
|
||||
+ if (unlikely(dma_mapping_error(eth->dma_dev, dma_addr)))
|
||||
return -ENOMEM;
|
||||
ring->dma[i].rxd1 = (unsigned int)dma_addr;
|
||||
|
||||
@@ -1770,7 +1771,7 @@ static void mtk_rx_clean(struct mtk_eth
|
||||
continue;
|
||||
if (!ring->dma[i].rxd1)
|
||||
continue;
|
||||
- dma_unmap_single(eth->dev,
|
||||
+ dma_unmap_single(eth->dma_dev,
|
||||
ring->dma[i].rxd1,
|
||||
ring->buf_size,
|
||||
DMA_FROM_DEVICE);
|
||||
@@ -1781,7 +1782,7 @@ static void mtk_rx_clean(struct mtk_eth
|
||||
}
|
||||
|
||||
if (ring->dma) {
|
||||
- dma_free_coherent(eth->dev,
|
||||
+ dma_free_coherent(eth->dma_dev,
|
||||
ring->dma_size * sizeof(*ring->dma),
|
||||
ring->dma,
|
||||
ring->phys);
|
||||
@@ -2134,7 +2135,7 @@ static void mtk_dma_free(struct mtk_eth
|
||||
if (eth->netdev[i])
|
||||
netdev_reset_queue(eth->netdev[i]);
|
||||
if (eth->scratch_ring) {
|
||||
- dma_free_coherent(eth->dev,
|
||||
+ dma_free_coherent(eth->dma_dev,
|
||||
MTK_DMA_SIZE * sizeof(struct mtk_tx_dma),
|
||||
eth->scratch_ring,
|
||||
eth->phy_scratch_ring);
|
||||
@@ -2482,6 +2483,8 @@ static void mtk_dim_tx(struct work_struc
|
||||
|
||||
static int mtk_hw_init(struct mtk_eth *eth)
|
||||
{
|
||||
+ u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA |
|
||||
+ ETHSYS_DMA_AG_MAP_PPE;
|
||||
int i, val, ret;
|
||||
|
||||
if (test_and_set_bit(MTK_HW_INIT, ð->state))
|
||||
@@ -2494,6 +2497,10 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
if (ret)
|
||||
goto err_disable_pm;
|
||||
|
||||
+ if (eth->ethsys)
|
||||
+ regmap_update_bits(eth->ethsys, ETHSYS_DMA_AG_MAP, dma_mask,
|
||||
+ of_dma_is_coherent(eth->dma_dev->of_node) * dma_mask);
|
||||
+
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
|
||||
ret = device_reset(eth->dev);
|
||||
if (ret) {
|
||||
@@ -3043,6 +3050,35 @@ free_netdev:
|
||||
return err;
|
||||
}
|
||||
|
||||
+void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev)
|
||||
+{
|
||||
+ struct net_device *dev, *tmp;
|
||||
+ LIST_HEAD(dev_list);
|
||||
+ int i;
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+
|
||||
+ for (i = 0; i < MTK_MAC_COUNT; i++) {
|
||||
+ dev = eth->netdev[i];
|
||||
+
|
||||
+ if (!dev || !(dev->flags & IFF_UP))
|
||||
+ continue;
|
||||
+
|
||||
+ list_add_tail(&dev->close_list, &dev_list);
|
||||
+ }
|
||||
+
|
||||
+ dev_close_many(&dev_list, false);
|
||||
+
|
||||
+ eth->dma_dev = dma_dev;
|
||||
+
|
||||
+ list_for_each_entry_safe(dev, tmp, &dev_list, close_list) {
|
||||
+ list_del_init(&dev->close_list);
|
||||
+ dev_open(dev, NULL);
|
||||
+ }
|
||||
+
|
||||
+ rtnl_unlock();
|
||||
+}
|
||||
+
|
||||
static int mtk_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *mac_np;
|
||||
@@ -3056,6 +3092,7 @@ static int mtk_probe(struct platform_dev
|
||||
eth->soc = of_device_get_match_data(&pdev->dev);
|
||||
|
||||
eth->dev = &pdev->dev;
|
||||
+ eth->dma_dev = &pdev->dev;
|
||||
eth->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(eth->base))
|
||||
return PTR_ERR(eth->base);
|
||||
@@ -3104,6 +3141,16 @@ static int mtk_probe(struct platform_dev
|
||||
}
|
||||
}
|
||||
|
||||
+ if (of_dma_is_coherent(pdev->dev.of_node)) {
|
||||
+ struct regmap *cci;
|
||||
+
|
||||
+ cci = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||
+ "mediatek,cci-control");
|
||||
+ /* enable CPU/bus coherency */
|
||||
+ if (!IS_ERR(cci))
|
||||
+ regmap_write(cci, 0, 3);
|
||||
+ }
|
||||
+
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
|
||||
eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii),
|
||||
GFP_KERNEL);
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -456,6 +456,12 @@
|
||||
#define RSTCTRL_FE BIT(6)
|
||||
#define RSTCTRL_PPE BIT(31)
|
||||
|
||||
+/* ethernet dma channel agent map */
|
||||
+#define ETHSYS_DMA_AG_MAP 0x408
|
||||
+#define ETHSYS_DMA_AG_MAP_PDMA BIT(0)
|
||||
+#define ETHSYS_DMA_AG_MAP_QDMA BIT(1)
|
||||
+#define ETHSYS_DMA_AG_MAP_PPE BIT(2)
|
||||
+
|
||||
/* SGMII subsystem config registers */
|
||||
/* Register to auto-negotiation restart */
|
||||
#define SGMSYS_PCS_CONTROL_1 0x0
|
||||
@@ -873,6 +879,7 @@ struct mtk_sgmii {
|
||||
/* struct mtk_eth - This is the main datasructure for holding the state
|
||||
* of the driver
|
||||
* @dev: The device pointer
|
||||
+ * @dev: The device pointer used for dma mapping/alloc
|
||||
* @base: The mapped register i/o base
|
||||
* @page_lock: Make sure that register operations are atomic
|
||||
* @tx_irq__lock: Make sure that IRQ register operations are atomic
|
||||
@@ -916,6 +923,7 @@ struct mtk_sgmii {
|
||||
|
||||
struct mtk_eth {
|
||||
struct device *dev;
|
||||
+ struct device *dma_dev;
|
||||
void __iomem *base;
|
||||
spinlock_t page_lock;
|
||||
spinlock_t tx_irq_lock;
|
||||
@@ -1014,6 +1022,7 @@ int mtk_gmac_rgmii_path_setup(struct mtk
|
||||
int mtk_eth_offload_init(struct mtk_eth *eth);
|
||||
int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
|
||||
void *type_data);
|
||||
+void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
|
||||
|
||||
|
||||
#endif /* MTK_ETH_H */
|
@ -0,0 +1,30 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 7 Feb 2022 10:27:22 +0100
|
||||
Subject: [PATCH] arm64: dts: mediatek: mt7622: add support for coherent
|
||||
DMA
|
||||
|
||||
It improves performance by eliminating the need for a cache flush on rx and tx
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
|
||||
+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
|
||||
@@ -357,7 +357,7 @@
|
||||
};
|
||||
|
||||
cci_control2: slave-if@5000 {
|
||||
- compatible = "arm,cci-400-ctrl-if";
|
||||
+ compatible = "arm,cci-400-ctrl-if", "syscon";
|
||||
interface-type = "ace";
|
||||
reg = <0x5000 0x1000>;
|
||||
};
|
||||
@@ -936,6 +936,8 @@
|
||||
power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>;
|
||||
mediatek,ethsys = <ðsys>;
|
||||
mediatek,sgmiisys = <&sgmiisys>;
|
||||
+ mediatek,cci-control = <&cci_control2>;
|
||||
+ dma-coherent;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,269 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 5 Feb 2022 18:29:22 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: implement flow offloading
|
||||
to WED devices
|
||||
|
||||
This allows hardware flow offloading from Ethernet to WLAN on MT7622 SoC
|
||||
|
||||
Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
@@ -329,6 +329,24 @@ int mtk_foe_entry_set_pppoe(struct mtk_f
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
|
||||
+ int bss, int wcid)
|
||||
+{
|
||||
+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
|
||||
+ u32 *ib2 = mtk_foe_entry_ib2(entry);
|
||||
+
|
||||
+ *ib2 &= ~MTK_FOE_IB2_PORT_MG;
|
||||
+ *ib2 |= MTK_FOE_IB2_WDMA_WINFO;
|
||||
+ if (wdma_idx)
|
||||
+ *ib2 |= MTK_FOE_IB2_WDMA_DEVIDX;
|
||||
+
|
||||
+ l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) |
|
||||
+ FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) |
|
||||
+ FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry)
|
||||
{
|
||||
return !(entry->ib1 & MTK_FOE_IB1_STATIC) &&
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
@@ -48,9 +48,9 @@ enum {
|
||||
#define MTK_FOE_IB2_DEST_PORT GENMASK(7, 5)
|
||||
#define MTK_FOE_IB2_MULTICAST BIT(8)
|
||||
|
||||
-#define MTK_FOE_IB2_WHNAT_QID2 GENMASK(13, 12)
|
||||
-#define MTK_FOE_IB2_WHNAT_DEVIDX BIT(16)
|
||||
-#define MTK_FOE_IB2_WHNAT_NAT BIT(17)
|
||||
+#define MTK_FOE_IB2_WDMA_QID2 GENMASK(13, 12)
|
||||
+#define MTK_FOE_IB2_WDMA_DEVIDX BIT(16)
|
||||
+#define MTK_FOE_IB2_WDMA_WINFO BIT(17)
|
||||
|
||||
#define MTK_FOE_IB2_PORT_MG GENMASK(17, 12)
|
||||
|
||||
@@ -58,9 +58,9 @@ enum {
|
||||
|
||||
#define MTK_FOE_IB2_DSCP GENMASK(31, 24)
|
||||
|
||||
-#define MTK_FOE_VLAN2_WHNAT_BSS GEMMASK(5, 0)
|
||||
-#define MTK_FOE_VLAN2_WHNAT_WCID GENMASK(13, 6)
|
||||
-#define MTK_FOE_VLAN2_WHNAT_RING GENMASK(15, 14)
|
||||
+#define MTK_FOE_VLAN2_WINFO_BSS GENMASK(5, 0)
|
||||
+#define MTK_FOE_VLAN2_WINFO_WCID GENMASK(13, 6)
|
||||
+#define MTK_FOE_VLAN2_WINFO_RING GENMASK(15, 14)
|
||||
|
||||
enum {
|
||||
MTK_FOE_STATE_INVALID,
|
||||
@@ -281,6 +281,8 @@ int mtk_foe_entry_set_ipv6_tuple(struct
|
||||
int mtk_foe_entry_set_dsa(struct mtk_foe_entry *entry, int port);
|
||||
int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
|
||||
int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
|
||||
+int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
|
||||
+ int bss, int wcid);
|
||||
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
|
||||
u16 timestamp);
|
||||
int mtk_ppe_debugfs_init(struct mtk_ppe *ppe);
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <net/pkt_cls.h>
|
||||
#include <net/dsa.h>
|
||||
#include "mtk_eth_soc.h"
|
||||
+#include "mtk_wed.h"
|
||||
|
||||
struct mtk_flow_data {
|
||||
struct ethhdr eth;
|
||||
@@ -40,6 +41,7 @@ struct mtk_flow_entry {
|
||||
struct rhash_head node;
|
||||
unsigned long cookie;
|
||||
u16 hash;
|
||||
+ s8 wed_index;
|
||||
};
|
||||
|
||||
static const struct rhashtable_params mtk_flow_ht_params = {
|
||||
@@ -81,6 +83,35 @@ mtk_flow_offload_mangle_eth(const struct
|
||||
memcpy(dest, src, act->mangle.mask ? 2 : 4);
|
||||
}
|
||||
|
||||
+static int
|
||||
+mtk_flow_get_wdma_info(struct net_device *dev, const u8 *addr, struct mtk_wdma_info *info)
|
||||
+{
|
||||
+ struct net_device_path_ctx ctx = {
|
||||
+ .dev = dev,
|
||||
+ .daddr = addr,
|
||||
+ };
|
||||
+ struct net_device_path path = {};
|
||||
+
|
||||
+ if (!IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED))
|
||||
+ return -1;
|
||||
+
|
||||
+ if (!dev->netdev_ops->ndo_fill_forward_path)
|
||||
+ return -1;
|
||||
+
|
||||
+ if (dev->netdev_ops->ndo_fill_forward_path(&ctx, &path))
|
||||
+ return -1;
|
||||
+
|
||||
+ if (path.type != DEV_PATH_MTK_WDMA)
|
||||
+ return -1;
|
||||
+
|
||||
+ info->wdma_idx = path.mtk_wdma.wdma_idx;
|
||||
+ info->queue = path.mtk_wdma.queue;
|
||||
+ info->bss = path.mtk_wdma.bss;
|
||||
+ info->wcid = path.mtk_wdma.wcid;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
|
||||
static int
|
||||
mtk_flow_mangle_ports(const struct flow_action_entry *act,
|
||||
@@ -150,10 +181,20 @@ mtk_flow_get_dsa_port(struct net_device
|
||||
|
||||
static int
|
||||
mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
|
||||
- struct net_device *dev)
|
||||
+ struct net_device *dev, const u8 *dest_mac,
|
||||
+ int *wed_index)
|
||||
{
|
||||
+ struct mtk_wdma_info info = {};
|
||||
int pse_port, dsa_port;
|
||||
|
||||
+ if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) {
|
||||
+ mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss,
|
||||
+ info.wcid);
|
||||
+ pse_port = 3;
|
||||
+ *wed_index = info.wdma_idx;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
dsa_port = mtk_flow_get_dsa_port(&dev);
|
||||
if (dsa_port >= 0)
|
||||
mtk_foe_entry_set_dsa(foe, dsa_port);
|
||||
@@ -165,6 +206,7 @@ mtk_flow_set_output_device(struct mtk_et
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
+out:
|
||||
mtk_foe_entry_set_pse_port(foe, pse_port);
|
||||
|
||||
return 0;
|
||||
@@ -180,6 +222,7 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
struct net_device *odev = NULL;
|
||||
struct mtk_flow_entry *entry;
|
||||
int offload_type = 0;
|
||||
+ int wed_index = -1;
|
||||
u16 addr_type = 0;
|
||||
u32 timestamp;
|
||||
u8 l4proto = 0;
|
||||
@@ -327,10 +370,14 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
if (data.pppoe.num == 1)
|
||||
mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
|
||||
|
||||
- err = mtk_flow_set_output_device(eth, &foe, odev);
|
||||
+ err = mtk_flow_set_output_device(eth, &foe, odev, data.eth.h_dest,
|
||||
+ &wed_index);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
+ if (wed_index >= 0 && (err = mtk_wed_flow_add(wed_index)) < 0)
|
||||
+ return err;
|
||||
+
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
@@ -344,6 +391,7 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
}
|
||||
|
||||
entry->hash = hash;
|
||||
+ entry->wed_index = wed_index;
|
||||
err = rhashtable_insert_fast(ð->flow_table, &entry->node,
|
||||
mtk_flow_ht_params);
|
||||
if (err < 0)
|
||||
@@ -354,6 +402,8 @@ clear_flow:
|
||||
mtk_foe_entry_clear(ð->ppe, hash);
|
||||
free:
|
||||
kfree(entry);
|
||||
+ if (wed_index >= 0)
|
||||
+ mtk_wed_flow_remove(wed_index);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -370,6 +420,8 @@ mtk_flow_offload_destroy(struct mtk_eth
|
||||
mtk_foe_entry_clear(ð->ppe, entry->hash);
|
||||
rhashtable_remove_fast(ð->flow_table, &entry->node,
|
||||
mtk_flow_ht_params);
|
||||
+ if (entry->wed_index >= 0)
|
||||
+ mtk_wed_flow_remove(entry->wed_index);
|
||||
kfree(entry);
|
||||
|
||||
return 0;
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_wed.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed.h
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <linux/soc/mediatek/mtk_wed.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/regmap.h>
|
||||
+#include <linux/netdevice.h>
|
||||
|
||||
struct mtk_eth;
|
||||
|
||||
@@ -27,6 +28,12 @@ struct mtk_wed_hw {
|
||||
int index;
|
||||
};
|
||||
|
||||
+struct mtk_wdma_info {
|
||||
+ u8 wdma_idx;
|
||||
+ u8 queue;
|
||||
+ u16 wcid;
|
||||
+ u8 bss;
|
||||
+};
|
||||
|
||||
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
|
||||
static inline void
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -833,6 +833,7 @@ enum net_device_path_type {
|
||||
DEV_PATH_BRIDGE,
|
||||
DEV_PATH_PPPOE,
|
||||
DEV_PATH_DSA,
|
||||
+ DEV_PATH_MTK_WDMA,
|
||||
};
|
||||
|
||||
struct net_device_path {
|
||||
@@ -858,6 +859,12 @@ struct net_device_path {
|
||||
int port;
|
||||
u16 proto;
|
||||
} dsa;
|
||||
+ struct {
|
||||
+ u8 wdma_idx;
|
||||
+ u8 queue;
|
||||
+ u16 wcid;
|
||||
+ u8 bss;
|
||||
+ } mtk_wdma;
|
||||
};
|
||||
};
|
||||
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -883,6 +883,10 @@ int dev_fill_forward_path(const struct n
|
||||
if (WARN_ON_ONCE(last_dev == ctx.dev))
|
||||
return -1;
|
||||
}
|
||||
+
|
||||
+ if (!ctx.dev)
|
||||
+ return ret;
|
||||
+
|
||||
path = dev_fwd_path(stack);
|
||||
if (!path)
|
||||
return -1;
|
@ -0,0 +1,62 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 5 Feb 2022 18:36:36 +0100
|
||||
Subject: [PATCH] arm64: dts: mediatek: mt7622: introduce nodes for
|
||||
Wireless Ethernet Dispatch
|
||||
|
||||
Introduce wed0 and wed1 nodes in order to enable offloading forwarding
|
||||
between ethernet and wireless devices on the mt7622 chipset.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
|
||||
+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
|
||||
@@ -892,6 +892,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ hifsys: syscon@1af00000 {
|
||||
+ compatible = "mediatek,mt7622-hifsys", "syscon";
|
||||
+ reg = <0 0x1af00000 0 0x70>;
|
||||
+ };
|
||||
+
|
||||
ethsys: syscon@1b000000 {
|
||||
compatible = "mediatek,mt7622-ethsys",
|
||||
"syscon";
|
||||
@@ -910,6 +915,26 @@
|
||||
#dma-cells = <1>;
|
||||
};
|
||||
|
||||
+ pcie_mirror: pcie-mirror@10000400 {
|
||||
+ compatible = "mediatek,mt7622-pcie-mirror",
|
||||
+ "syscon";
|
||||
+ reg = <0 0x10000400 0 0x10>;
|
||||
+ };
|
||||
+
|
||||
+ wed0: wed@1020a000 {
|
||||
+ compatible = "mediatek,mt7622-wed",
|
||||
+ "syscon";
|
||||
+ reg = <0 0x1020a000 0 0x1000>;
|
||||
+ interrupts = <GIC_SPI 214 IRQ_TYPE_LEVEL_LOW>;
|
||||
+ };
|
||||
+
|
||||
+ wed1: wed@1020b000 {
|
||||
+ compatible = "mediatek,mt7622-wed",
|
||||
+ "syscon";
|
||||
+ reg = <0 0x1020b000 0 0x1000>;
|
||||
+ interrupts = <GIC_SPI 215 IRQ_TYPE_LEVEL_LOW>;
|
||||
+ };
|
||||
+
|
||||
eth: ethernet@1b100000 {
|
||||
compatible = "mediatek,mt7622-eth",
|
||||
"mediatek,mt2701-eth",
|
||||
@@ -937,6 +962,9 @@
|
||||
mediatek,ethsys = <ðsys>;
|
||||
mediatek,sgmiisys = <&sgmiisys>;
|
||||
mediatek,cci-control = <&cci_control2>;
|
||||
+ mediatek,wed = <&wed0>, <&wed1>;
|
||||
+ mediatek,pcie-mirror = <&pcie_mirror>;
|
||||
+ mediatek,hifsys = <&hifsys>;
|
||||
dma-coherent;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
@ -1,3 +1,17 @@
|
||||
From: David Bentham <db260179@gmail.com>
|
||||
Date: Mon, 21 Feb 2022 15:36:16 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: add ipv6 flow offload
|
||||
support
|
||||
|
||||
Add the missing IPv6 flow offloading support for routing only.
|
||||
Hardware flow offloading is done by the packet processing engine (PPE)
|
||||
of the Ethernet MAC and as it doesn't support mangling of IPv6 packets,
|
||||
IPv6 NAT cannot be supported.
|
||||
|
||||
Signed-off-by: David Bentham <db260179@gmail.com>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -7,6 +7,7 @@
|
||||
@ -8,7 +22,7 @@
|
||||
#include <net/flow_offload.h>
|
||||
#include <net/pkt_cls.h>
|
||||
#include <net/dsa.h>
|
||||
@@ -20,6 +21,11 @@ struct mtk_flow_data {
|
||||
@@ -21,6 +22,11 @@ struct mtk_flow_data {
|
||||
__be32 src_addr;
|
||||
__be32 dst_addr;
|
||||
} v4;
|
||||
@ -20,7 +34,7 @@
|
||||
};
|
||||
|
||||
__be16 src_port;
|
||||
@@ -64,6 +70,14 @@ mtk_flow_set_ipv4_addr(struct mtk_foe_en
|
||||
@@ -66,6 +72,14 @@ mtk_flow_set_ipv4_addr(struct mtk_foe_en
|
||||
data->v4.dst_addr, data->dst_port);
|
||||
}
|
||||
|
||||
@ -35,7 +49,7 @@
|
||||
static void
|
||||
mtk_flow_offload_mangle_eth(const struct flow_action_entry *act, void *eth)
|
||||
{
|
||||
@@ -254,6 +268,9 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
@@ -297,6 +311,9 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
|
||||
offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT;
|
||||
break;
|
||||
@ -45,7 +59,7 @@
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
@@ -289,6 +306,17 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
@@ -332,6 +349,17 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
mtk_flow_set_ipv4_addr(&foe, &data, false);
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 21 Feb 2022 15:37:21 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: support TC_SETUP_BLOCK for
|
||||
PPE offload
|
||||
|
||||
This allows offload entries to be created from user space
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -564,10 +564,13 @@ mtk_eth_setup_tc_block(struct net_device
|
||||
int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
|
||||
void *type_data)
|
||||
{
|
||||
- if (type == TC_SETUP_FT)
|
||||
+ switch (type) {
|
||||
+ case TC_SETUP_BLOCK:
|
||||
+ case TC_SETUP_FT:
|
||||
return mtk_eth_setup_tc_block(dev, type_data);
|
||||
-
|
||||
- return -EOPNOTSUPP;
|
||||
+ default:
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
}
|
||||
|
||||
int mtk_eth_offload_init(struct mtk_eth *eth)
|
@ -0,0 +1,159 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 21 Feb 2022 15:38:20 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: allocate struct mtk_ppe
|
||||
separately
|
||||
|
||||
Preparation for adding more data to it, which will increase its size.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -2305,7 +2305,7 @@ static int mtk_open(struct net_device *d
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
- if (eth->soc->offload_version && mtk_ppe_start(ð->ppe) == 0)
|
||||
+ if (eth->soc->offload_version && mtk_ppe_start(eth->ppe) == 0)
|
||||
gdm_config = MTK_GDMA_TO_PPE;
|
||||
|
||||
mtk_gdm_config(eth, gdm_config);
|
||||
@@ -2379,7 +2379,7 @@ static int mtk_stop(struct net_device *d
|
||||
mtk_dma_free(eth);
|
||||
|
||||
if (eth->soc->offload_version)
|
||||
- mtk_ppe_stop(ð->ppe);
|
||||
+ mtk_ppe_stop(eth->ppe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3265,10 +3265,11 @@ static int mtk_probe(struct platform_dev
|
||||
}
|
||||
|
||||
if (eth->soc->offload_version) {
|
||||
- err = mtk_ppe_init(ð->ppe, eth->dev,
|
||||
- eth->base + MTK_ETH_PPE_BASE, 2);
|
||||
- if (err)
|
||||
+ eth->ppe = mtk_ppe_init(eth->dev, eth->base + MTK_ETH_PPE_BASE, 2);
|
||||
+ if (!eth->ppe) {
|
||||
+ err = -ENOMEM;
|
||||
goto err_free_dev;
|
||||
+ }
|
||||
|
||||
err = mtk_eth_offload_init(eth);
|
||||
if (err)
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -976,7 +976,7 @@ struct mtk_eth {
|
||||
u32 rx_dma_l4_valid;
|
||||
int ip_align;
|
||||
|
||||
- struct mtk_ppe ppe;
|
||||
+ struct mtk_ppe *ppe;
|
||||
struct rhashtable flow_table;
|
||||
};
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
@@ -384,10 +384,15 @@ int mtk_foe_entry_commit(struct mtk_ppe
|
||||
return hash;
|
||||
}
|
||||
|
||||
-int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base,
|
||||
+struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base,
|
||||
int version)
|
||||
{
|
||||
struct mtk_foe_entry *foe;
|
||||
+ struct mtk_ppe *ppe;
|
||||
+
|
||||
+ ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL);
|
||||
+ if (!ppe)
|
||||
+ return NULL;
|
||||
|
||||
/* need to allocate a separate device, since it PPE DMA access is
|
||||
* not coherent.
|
||||
@@ -399,13 +404,13 @@ int mtk_ppe_init(struct mtk_ppe *ppe, st
|
||||
foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe),
|
||||
&ppe->foe_phys, GFP_KERNEL);
|
||||
if (!foe)
|
||||
- return -ENOMEM;
|
||||
+ return NULL;
|
||||
|
||||
ppe->foe_table = foe;
|
||||
|
||||
mtk_ppe_debugfs_init(ppe);
|
||||
|
||||
- return 0;
|
||||
+ return ppe;
|
||||
}
|
||||
|
||||
static void mtk_ppe_init_foe_table(struct mtk_ppe *ppe)
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
@@ -246,8 +246,7 @@ struct mtk_ppe {
|
||||
void *acct_table;
|
||||
};
|
||||
|
||||
-int mtk_ppe_init(struct mtk_ppe *ppe, struct device *dev, void __iomem *base,
|
||||
- int version);
|
||||
+struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base, int version);
|
||||
int mtk_ppe_start(struct mtk_ppe *ppe);
|
||||
int mtk_ppe_stop(struct mtk_ppe *ppe);
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -412,7 +412,7 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
|
||||
entry->cookie = f->cookie;
|
||||
timestamp = mtk_eth_timestamp(eth);
|
||||
- hash = mtk_foe_entry_commit(ð->ppe, &foe, timestamp);
|
||||
+ hash = mtk_foe_entry_commit(eth->ppe, &foe, timestamp);
|
||||
if (hash < 0) {
|
||||
err = hash;
|
||||
goto free;
|
||||
@@ -427,7 +427,7 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
|
||||
return 0;
|
||||
clear_flow:
|
||||
- mtk_foe_entry_clear(ð->ppe, hash);
|
||||
+ mtk_foe_entry_clear(eth->ppe, hash);
|
||||
free:
|
||||
kfree(entry);
|
||||
if (wed_index >= 0)
|
||||
@@ -445,7 +445,7 @@ mtk_flow_offload_destroy(struct mtk_eth
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
|
||||
- mtk_foe_entry_clear(ð->ppe, entry->hash);
|
||||
+ mtk_foe_entry_clear(eth->ppe, entry->hash);
|
||||
rhashtable_remove_fast(ð->flow_table, &entry->node,
|
||||
mtk_flow_ht_params);
|
||||
if (entry->wed_index >= 0)
|
||||
@@ -467,7 +467,7 @@ mtk_flow_offload_stats(struct mtk_eth *e
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
|
||||
- timestamp = mtk_foe_entry_timestamp(ð->ppe, entry->hash);
|
||||
+ timestamp = mtk_foe_entry_timestamp(eth->ppe, entry->hash);
|
||||
if (timestamp < 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
@@ -523,7 +523,7 @@ mtk_eth_setup_tc_block(struct net_device
|
||||
struct flow_block_cb *block_cb;
|
||||
flow_setup_cb_t *cb;
|
||||
|
||||
- if (!eth->ppe.foe_table)
|
||||
+ if (!eth->ppe || !eth->ppe->foe_table)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
|
||||
@@ -575,7 +575,7 @@ int mtk_eth_setup_tc(struct net_device *
|
||||
|
||||
int mtk_eth_offload_init(struct mtk_eth *eth)
|
||||
{
|
||||
- if (!eth->ppe.foe_table)
|
||||
+ if (!eth->ppe || !eth->ppe->foe_table)
|
||||
return 0;
|
||||
|
||||
return rhashtable_init(ð->flow_table, &mtk_flow_ht_params);
|
@ -0,0 +1,424 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 21 Feb 2022 15:39:18 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: rework hardware flow table
|
||||
management
|
||||
|
||||
The hardware was designed to handle flow detection and creation of flow entries
|
||||
by itself, relying on the software primarily for filling in egress routing
|
||||
information.
|
||||
When there is a hash collision between multiple flows, this allows the hardware
|
||||
to maintain the entry for the most active flow.
|
||||
Additionally, the hardware only keeps offloading active for entries with at
|
||||
least 30 packets per second.
|
||||
|
||||
With this rework, the code no longer creates a hardware entries directly.
|
||||
Instead, the hardware entry is only created when the PPE reports a matching
|
||||
unbound flow with the minimum target rate.
|
||||
In order to reduce CPU overhead, looking for flows belonging to a hash entry
|
||||
is rate limited to once every 100ms.
|
||||
|
||||
This rework is also used as preparation for emulating bridge offload by
|
||||
managing L4 offload entries on demand.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <linux/pinctrl/devinfo.h>
|
||||
#include <linux/phylink.h>
|
||||
#include <linux/jhash.h>
|
||||
+#include <linux/bitfield.h>
|
||||
#include <net/dsa.h>
|
||||
|
||||
#include "mtk_eth_soc.h"
|
||||
@@ -1274,7 +1275,7 @@ static int mtk_poll_rx(struct napi_struc
|
||||
struct net_device *netdev;
|
||||
unsigned int pktlen;
|
||||
dma_addr_t dma_addr;
|
||||
- u32 hash;
|
||||
+ u32 hash, reason;
|
||||
int mac;
|
||||
|
||||
ring = mtk_get_rx_ring(eth);
|
||||
@@ -1350,6 +1351,11 @@ static int mtk_poll_rx(struct napi_struc
|
||||
skb_set_hash(skb, hash, PKT_HASH_TYPE_L4);
|
||||
}
|
||||
|
||||
+ reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4);
|
||||
+ if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
|
||||
+ mtk_ppe_check_skb(eth->ppe, skb,
|
||||
+ trxd.rxd4 & MTK_RXD4_FOE_ENTRY);
|
||||
+
|
||||
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX &&
|
||||
(trxd.rxd2 & RX_DMA_VTAG))
|
||||
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
|
||||
@@ -3265,7 +3271,7 @@ static int mtk_probe(struct platform_dev
|
||||
}
|
||||
|
||||
if (eth->soc->offload_version) {
|
||||
- eth->ppe = mtk_ppe_init(eth->dev, eth->base + MTK_ETH_PPE_BASE, 2);
|
||||
+ eth->ppe = mtk_ppe_init(eth, eth->base + MTK_ETH_PPE_BASE, 2);
|
||||
if (!eth->ppe) {
|
||||
err = -ENOMEM;
|
||||
goto err_free_dev;
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
@@ -6,9 +6,12 @@
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/platform_device.h>
|
||||
+#include "mtk_eth_soc.h"
|
||||
#include "mtk_ppe.h"
|
||||
#include "mtk_ppe_regs.h"
|
||||
|
||||
+static DEFINE_SPINLOCK(ppe_lock);
|
||||
+
|
||||
static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val)
|
||||
{
|
||||
writel(val, ppe->base + reg);
|
||||
@@ -41,6 +44,11 @@ static u32 ppe_clear(struct mtk_ppe *ppe
|
||||
return ppe_m32(ppe, reg, val, 0);
|
||||
}
|
||||
|
||||
+static u32 mtk_eth_timestamp(struct mtk_eth *eth)
|
||||
+{
|
||||
+ return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+}
|
||||
+
|
||||
static int mtk_ppe_wait_busy(struct mtk_ppe *ppe)
|
||||
{
|
||||
int ret;
|
||||
@@ -353,26 +361,59 @@ static inline bool mtk_foe_entry_usable(
|
||||
FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND;
|
||||
}
|
||||
|
||||
-int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
|
||||
- u16 timestamp)
|
||||
+static bool
|
||||
+mtk_flow_entry_match(struct mtk_flow_entry *entry, struct mtk_foe_entry *data)
|
||||
+{
|
||||
+ int type, len;
|
||||
+
|
||||
+ if ((data->ib1 ^ entry->data.ib1) & MTK_FOE_IB1_UDP)
|
||||
+ return false;
|
||||
+
|
||||
+ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1);
|
||||
+ if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE)
|
||||
+ len = offsetof(struct mtk_foe_entry, ipv6._rsv);
|
||||
+ else
|
||||
+ len = offsetof(struct mtk_foe_entry, ipv4.ib2);
|
||||
+
|
||||
+ return !memcmp(&entry->data.data, &data->data, len - 4);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
{
|
||||
struct mtk_foe_entry *hwe;
|
||||
- u32 hash;
|
||||
+ struct mtk_foe_entry foe;
|
||||
|
||||
+ spin_lock_bh(&ppe_lock);
|
||||
+ if (entry->hash == 0xffff)
|
||||
+ goto out;
|
||||
+
|
||||
+ hwe = &ppe->foe_table[entry->hash];
|
||||
+ memcpy(&foe, hwe, sizeof(foe));
|
||||
+ if (!mtk_flow_entry_match(entry, &foe)) {
|
||||
+ entry->hash = 0xffff;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ entry->data.ib1 = foe.ib1;
|
||||
+
|
||||
+out:
|
||||
+ spin_unlock_bh(&ppe_lock);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+__mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
|
||||
+ u16 hash)
|
||||
+{
|
||||
+ struct mtk_foe_entry *hwe;
|
||||
+ u16 timestamp;
|
||||
+
|
||||
+ timestamp = mtk_eth_timestamp(ppe->eth);
|
||||
timestamp &= MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
entry->ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
entry->ib1 |= FIELD_PREP(MTK_FOE_IB1_BIND_TIMESTAMP, timestamp);
|
||||
|
||||
- hash = mtk_ppe_hash_entry(entry);
|
||||
hwe = &ppe->foe_table[hash];
|
||||
- if (!mtk_foe_entry_usable(hwe)) {
|
||||
- hwe++;
|
||||
- hash++;
|
||||
-
|
||||
- if (!mtk_foe_entry_usable(hwe))
|
||||
- return -ENOSPC;
|
||||
- }
|
||||
-
|
||||
memcpy(&hwe->data, &entry->data, sizeof(hwe->data));
|
||||
wmb();
|
||||
hwe->ib1 = entry->ib1;
|
||||
@@ -380,13 +421,77 @@ int mtk_foe_entry_commit(struct mtk_ppe
|
||||
dma_wmb();
|
||||
|
||||
mtk_ppe_cache_clear(ppe);
|
||||
+}
|
||||
|
||||
- return hash;
|
||||
+void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
+{
|
||||
+ spin_lock_bh(&ppe_lock);
|
||||
+ hlist_del_init(&entry->list);
|
||||
+ if (entry->hash != 0xffff) {
|
||||
+ ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE;
|
||||
+ ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE,
|
||||
+ MTK_FOE_STATE_BIND);
|
||||
+ dma_wmb();
|
||||
+ }
|
||||
+ entry->hash = 0xffff;
|
||||
+ spin_unlock_bh(&ppe_lock);
|
||||
+}
|
||||
+
|
||||
+int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
+{
|
||||
+ u32 hash = mtk_ppe_hash_entry(&entry->data);
|
||||
+
|
||||
+ entry->hash = 0xffff;
|
||||
+ spin_lock_bh(&ppe_lock);
|
||||
+ hlist_add_head(&entry->list, &ppe->foe_flow[hash / 2]);
|
||||
+ spin_unlock_bh(&ppe_lock);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
|
||||
+{
|
||||
+ struct hlist_head *head = &ppe->foe_flow[hash / 2];
|
||||
+ struct mtk_flow_entry *entry;
|
||||
+ struct mtk_foe_entry *hwe = &ppe->foe_table[hash];
|
||||
+ bool found = false;
|
||||
+
|
||||
+ if (hlist_empty(head))
|
||||
+ return;
|
||||
+
|
||||
+ spin_lock_bh(&ppe_lock);
|
||||
+ hlist_for_each_entry(entry, head, list) {
|
||||
+ if (found || !mtk_flow_entry_match(entry, hwe)) {
|
||||
+ if (entry->hash != 0xffff)
|
||||
+ entry->hash = 0xffff;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ entry->hash = hash;
|
||||
+ __mtk_foe_entry_commit(ppe, &entry->data, hash);
|
||||
+ found = true;
|
||||
+ }
|
||||
+ spin_unlock_bh(&ppe_lock);
|
||||
+}
|
||||
+
|
||||
+int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
+{
|
||||
+ u16 now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+ u16 timestamp;
|
||||
+
|
||||
+ mtk_flow_entry_update(ppe, entry);
|
||||
+ timestamp = entry->data.ib1 & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+
|
||||
+ if (timestamp > now)
|
||||
+ return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now;
|
||||
+ else
|
||||
+ return now - timestamp;
|
||||
}
|
||||
|
||||
-struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base,
|
||||
+struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
|
||||
int version)
|
||||
{
|
||||
+ struct device *dev = eth->dev;
|
||||
struct mtk_foe_entry *foe;
|
||||
struct mtk_ppe *ppe;
|
||||
|
||||
@@ -398,6 +503,7 @@ struct mtk_ppe *mtk_ppe_init(struct devi
|
||||
* not coherent.
|
||||
*/
|
||||
ppe->base = base;
|
||||
+ ppe->eth = eth;
|
||||
ppe->dev = dev;
|
||||
ppe->version = version;
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
@@ -235,7 +235,17 @@ enum {
|
||||
MTK_PPE_CPU_REASON_INVALID = 0x1f,
|
||||
};
|
||||
|
||||
+struct mtk_flow_entry {
|
||||
+ struct rhash_head node;
|
||||
+ struct hlist_node list;
|
||||
+ unsigned long cookie;
|
||||
+ struct mtk_foe_entry data;
|
||||
+ u16 hash;
|
||||
+ s8 wed_index;
|
||||
+};
|
||||
+
|
||||
struct mtk_ppe {
|
||||
+ struct mtk_eth *eth;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
int version;
|
||||
@@ -243,18 +253,33 @@ struct mtk_ppe {
|
||||
struct mtk_foe_entry *foe_table;
|
||||
dma_addr_t foe_phys;
|
||||
|
||||
+ u16 foe_check_time[MTK_PPE_ENTRIES];
|
||||
+ struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2];
|
||||
+
|
||||
void *acct_table;
|
||||
};
|
||||
|
||||
-struct mtk_ppe *mtk_ppe_init(struct device *dev, void __iomem *base, int version);
|
||||
+struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version);
|
||||
int mtk_ppe_start(struct mtk_ppe *ppe);
|
||||
int mtk_ppe_stop(struct mtk_ppe *ppe);
|
||||
|
||||
+void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash);
|
||||
+
|
||||
static inline void
|
||||
-mtk_foe_entry_clear(struct mtk_ppe *ppe, u16 hash)
|
||||
+mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
|
||||
{
|
||||
- ppe->foe_table[hash].ib1 = 0;
|
||||
- dma_wmb();
|
||||
+ u16 now, diff;
|
||||
+
|
||||
+ if (!ppe)
|
||||
+ return;
|
||||
+
|
||||
+ now = (u16)jiffies;
|
||||
+ diff = now - ppe->foe_check_time[hash];
|
||||
+ if (diff < HZ / 10)
|
||||
+ return;
|
||||
+
|
||||
+ ppe->foe_check_time[hash] = now;
|
||||
+ __mtk_ppe_check_skb(ppe, skb, hash);
|
||||
}
|
||||
|
||||
static inline int
|
||||
@@ -282,8 +307,9 @@ int mtk_foe_entry_set_vlan(struct mtk_fo
|
||||
int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
|
||||
int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
|
||||
int bss, int wcid);
|
||||
-int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
|
||||
- u16 timestamp);
|
||||
+int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
|
||||
+void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
|
||||
+int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
|
||||
int mtk_ppe_debugfs_init(struct mtk_ppe *ppe);
|
||||
|
||||
#endif
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -43,13 +43,6 @@ struct mtk_flow_data {
|
||||
} pppoe;
|
||||
};
|
||||
|
||||
-struct mtk_flow_entry {
|
||||
- struct rhash_head node;
|
||||
- unsigned long cookie;
|
||||
- u16 hash;
|
||||
- s8 wed_index;
|
||||
-};
|
||||
-
|
||||
static const struct rhashtable_params mtk_flow_ht_params = {
|
||||
.head_offset = offsetof(struct mtk_flow_entry, node),
|
||||
.key_offset = offsetof(struct mtk_flow_entry, cookie),
|
||||
@@ -57,12 +50,6 @@ static const struct rhashtable_params mt
|
||||
.automatic_shrinking = true,
|
||||
};
|
||||
|
||||
-static u32
|
||||
-mtk_eth_timestamp(struct mtk_eth *eth)
|
||||
-{
|
||||
- return mtk_r32(eth, 0x0010) & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
-}
|
||||
-
|
||||
static int
|
||||
mtk_flow_set_ipv4_addr(struct mtk_foe_entry *foe, struct mtk_flow_data *data,
|
||||
bool egress)
|
||||
@@ -238,10 +225,8 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
int offload_type = 0;
|
||||
int wed_index = -1;
|
||||
u16 addr_type = 0;
|
||||
- u32 timestamp;
|
||||
u8 l4proto = 0;
|
||||
int err = 0;
|
||||
- int hash;
|
||||
int i;
|
||||
|
||||
if (rhashtable_lookup(ð->flow_table, &f->cookie, mtk_flow_ht_params))
|
||||
@@ -411,23 +396,21 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
return -ENOMEM;
|
||||
|
||||
entry->cookie = f->cookie;
|
||||
- timestamp = mtk_eth_timestamp(eth);
|
||||
- hash = mtk_foe_entry_commit(eth->ppe, &foe, timestamp);
|
||||
- if (hash < 0) {
|
||||
- err = hash;
|
||||
+ memcpy(&entry->data, &foe, sizeof(entry->data));
|
||||
+ entry->wed_index = wed_index;
|
||||
+
|
||||
+ if (mtk_foe_entry_commit(eth->ppe, entry) < 0)
|
||||
goto free;
|
||||
- }
|
||||
|
||||
- entry->hash = hash;
|
||||
- entry->wed_index = wed_index;
|
||||
err = rhashtable_insert_fast(ð->flow_table, &entry->node,
|
||||
mtk_flow_ht_params);
|
||||
if (err < 0)
|
||||
- goto clear_flow;
|
||||
+ goto clear;
|
||||
|
||||
return 0;
|
||||
-clear_flow:
|
||||
- mtk_foe_entry_clear(eth->ppe, hash);
|
||||
+
|
||||
+clear:
|
||||
+ mtk_foe_entry_clear(eth->ppe, entry);
|
||||
free:
|
||||
kfree(entry);
|
||||
if (wed_index >= 0)
|
||||
@@ -445,7 +428,7 @@ mtk_flow_offload_destroy(struct mtk_eth
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
|
||||
- mtk_foe_entry_clear(eth->ppe, entry->hash);
|
||||
+ mtk_foe_entry_clear(eth->ppe, entry);
|
||||
rhashtable_remove_fast(ð->flow_table, &entry->node,
|
||||
mtk_flow_ht_params);
|
||||
if (entry->wed_index >= 0)
|
||||
@@ -459,7 +442,6 @@ static int
|
||||
mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
|
||||
{
|
||||
struct mtk_flow_entry *entry;
|
||||
- int timestamp;
|
||||
u32 idle;
|
||||
|
||||
entry = rhashtable_lookup(ð->flow_table, &f->cookie,
|
||||
@@ -467,11 +449,7 @@ mtk_flow_offload_stats(struct mtk_eth *e
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
|
||||
- timestamp = mtk_foe_entry_timestamp(eth->ppe, entry->hash);
|
||||
- if (timestamp < 0)
|
||||
- return -ETIMEDOUT;
|
||||
-
|
||||
- idle = mtk_eth_timestamp(eth) - timestamp;
|
||||
+ idle = mtk_foe_entry_idle_time(eth->ppe, entry);
|
||||
f->stats.lastused = jiffies - idle * HZ;
|
||||
|
||||
return 0;
|
@ -0,0 +1,44 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 21 Feb 2022 15:55:19 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: remove bridge flow offload
|
||||
type entry support
|
||||
|
||||
According to MediaTek, this feature is not supported in current hardware
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
@@ -84,13 +84,6 @@ static u32 mtk_ppe_hash_entry(struct mtk
|
||||
u32 hash;
|
||||
|
||||
switch (FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, e->ib1)) {
|
||||
- case MTK_PPE_PKT_TYPE_BRIDGE:
|
||||
- hv1 = e->bridge.src_mac_lo;
|
||||
- hv1 ^= ((e->bridge.src_mac_hi & 0xffff) << 16);
|
||||
- hv2 = e->bridge.src_mac_hi >> 16;
|
||||
- hv2 ^= e->bridge.dest_mac_lo;
|
||||
- hv3 = e->bridge.dest_mac_hi;
|
||||
- break;
|
||||
case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
|
||||
case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
|
||||
hv1 = e->ipv4.orig.ports;
|
||||
@@ -572,7 +565,6 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
|
||||
MTK_PPE_FLOW_CFG_IP4_NAT |
|
||||
MTK_PPE_FLOW_CFG_IP4_NAPT |
|
||||
MTK_PPE_FLOW_CFG_IP4_DSLITE |
|
||||
- MTK_PPE_FLOW_CFG_L2_BRIDGE |
|
||||
MTK_PPE_FLOW_CFG_IP4_NAT_FRAG;
|
||||
ppe_w32(ppe, MTK_PPE_FLOW_CFG, val);
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
|
||||
@@ -32,7 +32,6 @@ static const char *mtk_foe_pkt_type_str(
|
||||
static const char * const type_str[] = {
|
||||
[MTK_PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T",
|
||||
[MTK_PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T",
|
||||
- [MTK_PPE_PKT_TYPE_BRIDGE] = "L2",
|
||||
[MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE",
|
||||
[MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T",
|
||||
[MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T",
|
@ -0,0 +1,553 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 23 Feb 2022 10:56:34 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: support creating mac
|
||||
address based offload entries
|
||||
|
||||
This will be used to implement a limited form of bridge offloading.
|
||||
Since the hardware does not support flow table entries with just source
|
||||
and destination MAC address, the driver has to emulate it.
|
||||
|
||||
The hardware automatically creates entries entries for incoming flows, even
|
||||
when they are bridged instead of routed, and reports when packets for these
|
||||
flows have reached the minimum PPS rate for offloading.
|
||||
|
||||
After this happens, we look up the L2 flow offload entry based on the MAC
|
||||
header and fill in the output routing information in the flow table.
|
||||
The dynamically created per-flow entries are automatically removed when
|
||||
either the hardware flowtable entry expires, is replaced, or if the offload
|
||||
rule they belong to is removed
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
@@ -6,12 +6,22 @@
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/platform_device.h>
|
||||
+#include <linux/if_ether.h>
|
||||
+#include <linux/if_vlan.h>
|
||||
+#include <net/dsa.h>
|
||||
#include "mtk_eth_soc.h"
|
||||
#include "mtk_ppe.h"
|
||||
#include "mtk_ppe_regs.h"
|
||||
|
||||
static DEFINE_SPINLOCK(ppe_lock);
|
||||
|
||||
+static const struct rhashtable_params mtk_flow_l2_ht_params = {
|
||||
+ .head_offset = offsetof(struct mtk_flow_entry, l2_node),
|
||||
+ .key_offset = offsetof(struct mtk_flow_entry, data.bridge),
|
||||
+ .key_len = offsetof(struct mtk_foe_bridge, key_end),
|
||||
+ .automatic_shrinking = true,
|
||||
+};
|
||||
+
|
||||
static void ppe_w32(struct mtk_ppe *ppe, u32 reg, u32 val)
|
||||
{
|
||||
writel(val, ppe->base + reg);
|
||||
@@ -123,6 +133,9 @@ mtk_foe_entry_l2(struct mtk_foe_entry *e
|
||||
{
|
||||
int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
|
||||
|
||||
+ if (type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ return &entry->bridge.l2;
|
||||
+
|
||||
if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE)
|
||||
return &entry->ipv6.l2;
|
||||
|
||||
@@ -134,6 +147,9 @@ mtk_foe_entry_ib2(struct mtk_foe_entry *
|
||||
{
|
||||
int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
|
||||
|
||||
+ if (type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ return &entry->bridge.ib2;
|
||||
+
|
||||
if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE)
|
||||
return &entry->ipv6.ib2;
|
||||
|
||||
@@ -168,7 +184,12 @@ int mtk_foe_entry_prepare(struct mtk_foe
|
||||
if (type == MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T)
|
||||
entry->ipv6.ports = ports_pad;
|
||||
|
||||
- if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
|
||||
+ if (type == MTK_PPE_PKT_TYPE_BRIDGE) {
|
||||
+ ether_addr_copy(entry->bridge.src_mac, src_mac);
|
||||
+ ether_addr_copy(entry->bridge.dest_mac, dest_mac);
|
||||
+ entry->bridge.ib2 = val;
|
||||
+ l2 = &entry->bridge.l2;
|
||||
+ } else if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
|
||||
entry->ipv6.ib2 = val;
|
||||
l2 = &entry->ipv6.l2;
|
||||
} else {
|
||||
@@ -372,12 +393,96 @@ mtk_flow_entry_match(struct mtk_flow_ent
|
||||
}
|
||||
|
||||
static void
|
||||
+__mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
+{
|
||||
+ struct hlist_head *head;
|
||||
+ struct hlist_node *tmp;
|
||||
+
|
||||
+ if (entry->type == MTK_FLOW_TYPE_L2) {
|
||||
+ rhashtable_remove_fast(&ppe->l2_flows, &entry->l2_node,
|
||||
+ mtk_flow_l2_ht_params);
|
||||
+
|
||||
+ head = &entry->l2_flows;
|
||||
+ hlist_for_each_entry_safe(entry, tmp, head, l2_data.list)
|
||||
+ __mtk_foe_entry_clear(ppe, entry);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ hlist_del_init(&entry->list);
|
||||
+ if (entry->hash != 0xffff) {
|
||||
+ ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE;
|
||||
+ ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE,
|
||||
+ MTK_FOE_STATE_BIND);
|
||||
+ dma_wmb();
|
||||
+ }
|
||||
+ entry->hash = 0xffff;
|
||||
+
|
||||
+ if (entry->type != MTK_FLOW_TYPE_L2_SUBFLOW)
|
||||
+ return;
|
||||
+
|
||||
+ hlist_del_init(&entry->l2_data.list);
|
||||
+ kfree(entry);
|
||||
+}
|
||||
+
|
||||
+static int __mtk_foe_entry_idle_time(struct mtk_ppe *ppe, u32 ib1)
|
||||
+{
|
||||
+ u16 timestamp;
|
||||
+ u16 now;
|
||||
+
|
||||
+ now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+ timestamp = ib1 & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+
|
||||
+ if (timestamp > now)
|
||||
+ return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now;
|
||||
+ else
|
||||
+ return now - timestamp;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_flow_entry_update_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
+{
|
||||
+ struct mtk_flow_entry *cur;
|
||||
+ struct mtk_foe_entry *hwe;
|
||||
+ struct hlist_node *tmp;
|
||||
+ int idle;
|
||||
+
|
||||
+ idle = __mtk_foe_entry_idle_time(ppe, entry->data.ib1);
|
||||
+ hlist_for_each_entry_safe(cur, tmp, &entry->l2_flows, l2_data.list) {
|
||||
+ int cur_idle;
|
||||
+ u32 ib1;
|
||||
+
|
||||
+ hwe = &ppe->foe_table[cur->hash];
|
||||
+ ib1 = READ_ONCE(hwe->ib1);
|
||||
+
|
||||
+ if (FIELD_GET(MTK_FOE_IB1_STATE, ib1) != MTK_FOE_STATE_BIND) {
|
||||
+ cur->hash = 0xffff;
|
||||
+ __mtk_foe_entry_clear(ppe, cur);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ cur_idle = __mtk_foe_entry_idle_time(ppe, ib1);
|
||||
+ if (cur_idle >= idle)
|
||||
+ continue;
|
||||
+
|
||||
+ idle = cur_idle;
|
||||
+ entry->data.ib1 &= ~MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+ entry->data.ib1 |= hwe->ib1 & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
mtk_flow_entry_update(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
{
|
||||
struct mtk_foe_entry *hwe;
|
||||
struct mtk_foe_entry foe;
|
||||
|
||||
spin_lock_bh(&ppe_lock);
|
||||
+
|
||||
+ if (entry->type == MTK_FLOW_TYPE_L2) {
|
||||
+ mtk_flow_entry_update_l2(ppe, entry);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
if (entry->hash == 0xffff)
|
||||
goto out;
|
||||
|
||||
@@ -419,21 +524,28 @@ __mtk_foe_entry_commit(struct mtk_ppe *p
|
||||
void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
{
|
||||
spin_lock_bh(&ppe_lock);
|
||||
- hlist_del_init(&entry->list);
|
||||
- if (entry->hash != 0xffff) {
|
||||
- ppe->foe_table[entry->hash].ib1 &= ~MTK_FOE_IB1_STATE;
|
||||
- ppe->foe_table[entry->hash].ib1 |= FIELD_PREP(MTK_FOE_IB1_STATE,
|
||||
- MTK_FOE_STATE_BIND);
|
||||
- dma_wmb();
|
||||
- }
|
||||
- entry->hash = 0xffff;
|
||||
+ __mtk_foe_entry_clear(ppe, entry);
|
||||
spin_unlock_bh(&ppe_lock);
|
||||
}
|
||||
|
||||
+static int
|
||||
+mtk_foe_entry_commit_l2(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
+{
|
||||
+ entry->type = MTK_FLOW_TYPE_L2;
|
||||
+
|
||||
+ return rhashtable_insert_fast(&ppe->l2_flows, &entry->l2_node,
|
||||
+ mtk_flow_l2_ht_params);
|
||||
+}
|
||||
+
|
||||
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
{
|
||||
- u32 hash = mtk_ppe_hash_entry(&entry->data);
|
||||
+ int type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->data.ib1);
|
||||
+ u32 hash;
|
||||
+
|
||||
+ if (type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ return mtk_foe_entry_commit_l2(ppe, entry);
|
||||
|
||||
+ hash = mtk_ppe_hash_entry(&entry->data);
|
||||
entry->hash = 0xffff;
|
||||
spin_lock_bh(&ppe_lock);
|
||||
hlist_add_head(&entry->list, &ppe->foe_flow[hash / 2]);
|
||||
@@ -442,18 +554,72 @@ int mtk_foe_entry_commit(struct mtk_ppe
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void
|
||||
+mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry,
|
||||
+ u16 hash)
|
||||
+{
|
||||
+ struct mtk_flow_entry *flow_info;
|
||||
+ struct mtk_foe_entry foe, *hwe;
|
||||
+ struct mtk_foe_mac_info *l2;
|
||||
+ u32 ib1_mask = MTK_FOE_IB1_PACKET_TYPE | MTK_FOE_IB1_UDP;
|
||||
+ int type;
|
||||
+
|
||||
+ flow_info = kzalloc(offsetof(struct mtk_flow_entry, l2_data.end),
|
||||
+ GFP_ATOMIC);
|
||||
+ if (!flow_info)
|
||||
+ return;
|
||||
+
|
||||
+ flow_info->l2_data.base_flow = entry;
|
||||
+ flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW;
|
||||
+ flow_info->hash = hash;
|
||||
+ hlist_add_head(&flow_info->list, &ppe->foe_flow[hash / 2]);
|
||||
+ hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows);
|
||||
+
|
||||
+ hwe = &ppe->foe_table[hash];
|
||||
+ memcpy(&foe, hwe, sizeof(foe));
|
||||
+ foe.ib1 &= ib1_mask;
|
||||
+ foe.ib1 |= entry->data.ib1 & ~ib1_mask;
|
||||
+
|
||||
+ l2 = mtk_foe_entry_l2(&foe);
|
||||
+ memcpy(l2, &entry->data.bridge.l2, sizeof(*l2));
|
||||
+
|
||||
+ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, foe.ib1);
|
||||
+ if (type == MTK_PPE_PKT_TYPE_IPV4_HNAPT)
|
||||
+ memcpy(&foe.ipv4.new, &foe.ipv4.orig, sizeof(foe.ipv4.new));
|
||||
+ else if (type >= MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T && l2->etype == ETH_P_IP)
|
||||
+ l2->etype = ETH_P_IPV6;
|
||||
+
|
||||
+ *mtk_foe_entry_ib2(&foe) = entry->data.bridge.ib2;
|
||||
+
|
||||
+ __mtk_foe_entry_commit(ppe, &foe, hash);
|
||||
+}
|
||||
+
|
||||
void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
|
||||
{
|
||||
struct hlist_head *head = &ppe->foe_flow[hash / 2];
|
||||
- struct mtk_flow_entry *entry;
|
||||
struct mtk_foe_entry *hwe = &ppe->foe_table[hash];
|
||||
+ struct mtk_flow_entry *entry;
|
||||
+ struct mtk_foe_bridge key = {};
|
||||
+ struct ethhdr *eh;
|
||||
bool found = false;
|
||||
-
|
||||
- if (hlist_empty(head))
|
||||
- return;
|
||||
+ u8 *tag;
|
||||
|
||||
spin_lock_bh(&ppe_lock);
|
||||
+
|
||||
+ if (FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) == MTK_FOE_STATE_BIND)
|
||||
+ goto out;
|
||||
+
|
||||
hlist_for_each_entry(entry, head, list) {
|
||||
+ if (entry->type == MTK_FLOW_TYPE_L2_SUBFLOW) {
|
||||
+ if (unlikely(FIELD_GET(MTK_FOE_IB1_STATE, hwe->ib1) ==
|
||||
+ MTK_FOE_STATE_BIND))
|
||||
+ continue;
|
||||
+
|
||||
+ entry->hash = 0xffff;
|
||||
+ __mtk_foe_entry_clear(ppe, entry);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
if (found || !mtk_flow_entry_match(entry, hwe)) {
|
||||
if (entry->hash != 0xffff)
|
||||
entry->hash = 0xffff;
|
||||
@@ -464,21 +630,50 @@ void __mtk_ppe_check_skb(struct mtk_ppe
|
||||
__mtk_foe_entry_commit(ppe, &entry->data, hash);
|
||||
found = true;
|
||||
}
|
||||
+
|
||||
+ if (found)
|
||||
+ goto out;
|
||||
+
|
||||
+ eh = eth_hdr(skb);
|
||||
+ ether_addr_copy(key.dest_mac, eh->h_dest);
|
||||
+ ether_addr_copy(key.src_mac, eh->h_source);
|
||||
+ tag = skb->data - 2;
|
||||
+ key.vlan = 0;
|
||||
+ switch (skb->protocol) {
|
||||
+#if IS_ENABLED(CONFIG_NET_DSA)
|
||||
+ case htons(ETH_P_XDSA):
|
||||
+ if (!netdev_uses_dsa(skb->dev) ||
|
||||
+ skb->dev->dsa_ptr->tag_ops->proto != DSA_TAG_PROTO_MTK)
|
||||
+ goto out;
|
||||
+
|
||||
+ tag += 4;
|
||||
+ if (get_unaligned_be16(tag) != ETH_P_8021Q)
|
||||
+ break;
|
||||
+
|
||||
+ fallthrough;
|
||||
+#endif
|
||||
+ case htons(ETH_P_8021Q):
|
||||
+ key.vlan = get_unaligned_be16(tag + 2) & VLAN_VID_MASK;
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ entry = rhashtable_lookup_fast(&ppe->l2_flows, &key, mtk_flow_l2_ht_params);
|
||||
+ if (!entry)
|
||||
+ goto out;
|
||||
+
|
||||
+ mtk_foe_entry_commit_subflow(ppe, entry, hash);
|
||||
+
|
||||
+out:
|
||||
spin_unlock_bh(&ppe_lock);
|
||||
}
|
||||
|
||||
int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
|
||||
{
|
||||
- u16 now = mtk_eth_timestamp(ppe->eth) & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
- u16 timestamp;
|
||||
-
|
||||
mtk_flow_entry_update(ppe, entry);
|
||||
- timestamp = entry->data.ib1 & MTK_FOE_IB1_BIND_TIMESTAMP;
|
||||
|
||||
- if (timestamp > now)
|
||||
- return MTK_FOE_IB1_BIND_TIMESTAMP + 1 - timestamp + now;
|
||||
- else
|
||||
- return now - timestamp;
|
||||
+ return __mtk_foe_entry_idle_time(ppe, entry->data.ib1);
|
||||
}
|
||||
|
||||
struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
|
||||
@@ -492,6 +687,8 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_
|
||||
if (!ppe)
|
||||
return NULL;
|
||||
|
||||
+ rhashtable_init(&ppe->l2_flows, &mtk_flow_l2_ht_params);
|
||||
+
|
||||
/* need to allocate a separate device, since it PPE DMA access is
|
||||
* not coherent.
|
||||
*/
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/bitfield.h>
|
||||
+#include <linux/rhashtable.h>
|
||||
|
||||
#define MTK_ETH_PPE_BASE 0xc00
|
||||
|
||||
@@ -84,19 +85,16 @@ struct mtk_foe_mac_info {
|
||||
u16 src_mac_lo;
|
||||
};
|
||||
|
||||
+/* software-only entry type */
|
||||
struct mtk_foe_bridge {
|
||||
- u32 dest_mac_hi;
|
||||
-
|
||||
- u16 src_mac_lo;
|
||||
- u16 dest_mac_lo;
|
||||
+ u8 dest_mac[ETH_ALEN];
|
||||
+ u8 src_mac[ETH_ALEN];
|
||||
+ u16 vlan;
|
||||
|
||||
- u32 src_mac_hi;
|
||||
+ struct {} key_end;
|
||||
|
||||
u32 ib2;
|
||||
|
||||
- u32 _rsv[5];
|
||||
-
|
||||
- u32 udf_tsid;
|
||||
struct mtk_foe_mac_info l2;
|
||||
};
|
||||
|
||||
@@ -235,13 +233,33 @@ enum {
|
||||
MTK_PPE_CPU_REASON_INVALID = 0x1f,
|
||||
};
|
||||
|
||||
+enum {
|
||||
+ MTK_FLOW_TYPE_L4,
|
||||
+ MTK_FLOW_TYPE_L2,
|
||||
+ MTK_FLOW_TYPE_L2_SUBFLOW,
|
||||
+};
|
||||
+
|
||||
struct mtk_flow_entry {
|
||||
+ union {
|
||||
+ struct hlist_node list;
|
||||
+ struct {
|
||||
+ struct rhash_head l2_node;
|
||||
+ struct hlist_head l2_flows;
|
||||
+ };
|
||||
+ };
|
||||
+ u8 type;
|
||||
+ s8 wed_index;
|
||||
+ u16 hash;
|
||||
+ union {
|
||||
+ struct mtk_foe_entry data;
|
||||
+ struct {
|
||||
+ struct mtk_flow_entry *base_flow;
|
||||
+ struct hlist_node list;
|
||||
+ struct {} end;
|
||||
+ } l2_data;
|
||||
+ };
|
||||
struct rhash_head node;
|
||||
- struct hlist_node list;
|
||||
unsigned long cookie;
|
||||
- struct mtk_foe_entry data;
|
||||
- u16 hash;
|
||||
- s8 wed_index;
|
||||
};
|
||||
|
||||
struct mtk_ppe {
|
||||
@@ -256,6 +274,8 @@ struct mtk_ppe {
|
||||
u16 foe_check_time[MTK_PPE_ENTRIES];
|
||||
struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2];
|
||||
|
||||
+ struct rhashtable l2_flows;
|
||||
+
|
||||
void *acct_table;
|
||||
};
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -32,6 +32,8 @@ struct mtk_flow_data {
|
||||
__be16 src_port;
|
||||
__be16 dst_port;
|
||||
|
||||
+ u16 vlan_in;
|
||||
+
|
||||
struct {
|
||||
u16 id;
|
||||
__be16 proto;
|
||||
@@ -258,9 +260,45 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
+ switch (addr_type) {
|
||||
+ case 0:
|
||||
+ offload_type = MTK_PPE_PKT_TYPE_BRIDGE;
|
||||
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
|
||||
+ struct flow_match_eth_addrs match;
|
||||
+
|
||||
+ flow_rule_match_eth_addrs(rule, &match);
|
||||
+ memcpy(data.eth.h_dest, match.key->dst, ETH_ALEN);
|
||||
+ memcpy(data.eth.h_source, match.key->src, ETH_ALEN);
|
||||
+ } else {
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+
|
||||
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_VLAN)) {
|
||||
+ struct flow_match_vlan match;
|
||||
+
|
||||
+ flow_rule_match_vlan(rule, &match);
|
||||
+
|
||||
+ if (match.key->vlan_tpid != cpu_to_be16(ETH_P_8021Q))
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
+ data.vlan_in = match.key->vlan_id;
|
||||
+ }
|
||||
+ break;
|
||||
+ case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
|
||||
+ offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT;
|
||||
+ break;
|
||||
+ case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
|
||||
+ offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EOPNOTSUPP;
|
||||
+ }
|
||||
+
|
||||
flow_action_for_each(i, act, &rule->action) {
|
||||
switch (act->id) {
|
||||
case FLOW_ACTION_MANGLE:
|
||||
+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ return -EOPNOTSUPP;
|
||||
if (act->mangle.htype == FLOW_ACT_MANGLE_HDR_TYPE_ETH)
|
||||
mtk_flow_offload_mangle_eth(act, &data.eth);
|
||||
break;
|
||||
@@ -292,17 +330,6 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
}
|
||||
}
|
||||
|
||||
- switch (addr_type) {
|
||||
- case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
|
||||
- offload_type = MTK_PPE_PKT_TYPE_IPV4_HNAPT;
|
||||
- break;
|
||||
- case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
|
||||
- offload_type = MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T;
|
||||
- break;
|
||||
- default:
|
||||
- return -EOPNOTSUPP;
|
||||
- }
|
||||
-
|
||||
if (!is_valid_ether_addr(data.eth.h_source) ||
|
||||
!is_valid_ether_addr(data.eth.h_dest))
|
||||
return -EINVAL;
|
||||
@@ -316,10 +343,13 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
|
||||
struct flow_match_ports ports;
|
||||
|
||||
+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
flow_rule_match_ports(rule, &ports);
|
||||
data.src_port = ports.key->src;
|
||||
data.dst_port = ports.key->dst;
|
||||
- } else {
|
||||
+ } else if (offload_type != MTK_PPE_PKT_TYPE_BRIDGE) {
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@@ -349,6 +379,9 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
if (act->id != FLOW_ACTION_MANGLE)
|
||||
continue;
|
||||
|
||||
+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
switch (act->mangle.htype) {
|
||||
case FLOW_ACT_MANGLE_HDR_TYPE_TCP:
|
||||
case FLOW_ACT_MANGLE_HDR_TYPE_UDP:
|
||||
@@ -374,6 +407,9 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
return err;
|
||||
}
|
||||
|
||||
+ if (offload_type == MTK_PPE_PKT_TYPE_BRIDGE)
|
||||
+ foe.bridge.vlan = data.vlan_in;
|
||||
+
|
||||
if (data.vlan.num == 1) {
|
||||
if (data.vlan.proto != htons(ETH_P_8021Q))
|
||||
return -EOPNOTSUPP;
|
@ -14,7 +14,7 @@ Signed-off-by: Frank Wunderlich <frank-w@public-files.de>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -3302,6 +3302,7 @@ static const struct mtk_soc_data mt7623_
|
||||
@@ -3373,6 +3373,7 @@ static const struct mtk_soc_data mt7623_
|
||||
.hw_features = MTK_HW_FEATURES,
|
||||
.required_clks = MT7623_CLKS_BITMAP,
|
||||
.required_pctl = true,
|
||||
|
@ -1,85 +0,0 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 4 Sep 2020 18:36:06 +0200
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: add support for coherent DMA
|
||||
|
||||
It improves performance by eliminating the need for a cache flush on rx and tx
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/arch/arm64/boot/dts/mediatek/mt7622.dtsi
|
||||
+++ b/arch/arm64/boot/dts/mediatek/mt7622.dtsi
|
||||
@@ -364,7 +364,7 @@
|
||||
};
|
||||
|
||||
cci_control2: slave-if@5000 {
|
||||
- compatible = "arm,cci-400-ctrl-if";
|
||||
+ compatible = "arm,cci-400-ctrl-if", "syscon";
|
||||
interface-type = "ace";
|
||||
reg = <0x5000 0x1000>;
|
||||
};
|
||||
@@ -977,6 +977,8 @@
|
||||
power-domains = <&scpsys MT7622_POWER_DOMAIN_ETHSYS>;
|
||||
mediatek,ethsys = <ðsys>;
|
||||
mediatek,sgmiisys = <&sgmiisys>;
|
||||
+ mediatek,cci-control = <&cci_control2>;
|
||||
+ dma-coherent;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
status = "disabled";
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_mdio.h>
|
||||
#include <linux/of_net.h>
|
||||
+#include <linux/of_address.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/clk.h>
|
||||
@@ -2494,6 +2495,13 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
if (ret)
|
||||
goto err_disable_pm;
|
||||
|
||||
+ if (of_dma_is_coherent(eth->dev->of_node)) {
|
||||
+ u32 mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA |
|
||||
+ ETHSYS_DMA_AG_MAP_PPE;
|
||||
+
|
||||
+ regmap_update_bits(eth->ethsys, ETHSYS_DMA_AG_MAP, mask, mask);
|
||||
+ }
|
||||
+
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628)) {
|
||||
ret = device_reset(eth->dev);
|
||||
if (ret) {
|
||||
@@ -3104,6 +3112,16 @@ static int mtk_probe(struct platform_dev
|
||||
}
|
||||
}
|
||||
|
||||
+ if (of_dma_is_coherent(pdev->dev.of_node)) {
|
||||
+ struct regmap *cci;
|
||||
+
|
||||
+ cci = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||
+ "mediatek,cci-control");
|
||||
+ /* enable CPU/bus coherency */
|
||||
+ if (!IS_ERR(cci))
|
||||
+ regmap_write(cci, 0, 3);
|
||||
+ }
|
||||
+
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_SGMII)) {
|
||||
eth->sgmii = devm_kzalloc(eth->dev, sizeof(*eth->sgmii),
|
||||
GFP_KERNEL);
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -456,6 +456,12 @@
|
||||
#define RSTCTRL_FE BIT(6)
|
||||
#define RSTCTRL_PPE BIT(31)
|
||||
|
||||
+/* ethernet dma channel agent map */
|
||||
+#define ETHSYS_DMA_AG_MAP 0x408
|
||||
+#define ETHSYS_DMA_AG_MAP_PDMA BIT(0)
|
||||
+#define ETHSYS_DMA_AG_MAP_QDMA BIT(1)
|
||||
+#define ETHSYS_DMA_AG_MAP_PPE BIT(2)
|
||||
+
|
||||
/* SGMII subsystem config registers */
|
||||
/* Register to auto-negotiation restart */
|
||||
#define SGMSYS_PCS_CONTROL_1 0x0
|
@ -22,7 +22,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -92,46 +92,53 @@ static int mtk_mdio_busy_wait(struct mtk
|
||||
@@ -94,46 +94,53 @@ static int mtk_mdio_busy_wait(struct mtk
|
||||
}
|
||||
|
||||
dev_err(eth->dev, "mdio: MDIO timeout\n");
|
||||
@ -103,7 +103,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
static int mtk_mdio_write(struct mii_bus *bus, int phy_addr,
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -341,11 +341,17 @@
|
||||
@@ -344,11 +344,17 @@
|
||||
/* PHY Indirect Access Control registers */
|
||||
#define MTK_PHY_IAC 0x10004
|
||||
#define PHY_IAC_ACCESS BIT(31)
|
||||
|
@ -20,7 +20,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -104,13 +104,35 @@ static int _mtk_mdio_write(struct mtk_et
|
||||
@@ -106,13 +106,35 @@ static int _mtk_mdio_write(struct mtk_et
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -63,7 +63,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
ret = mtk_mdio_busy_wait(eth);
|
||||
if (ret < 0)
|
||||
@@ -127,12 +149,33 @@ static int _mtk_mdio_read(struct mtk_eth
|
||||
@@ -129,12 +151,33 @@ static int _mtk_mdio_read(struct mtk_eth
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -103,7 +103,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
ret = mtk_mdio_busy_wait(eth);
|
||||
if (ret < 0)
|
||||
@@ -591,6 +634,7 @@ static int mtk_mdio_init(struct mtk_eth
|
||||
@@ -593,6 +636,7 @@ static int mtk_mdio_init(struct mtk_eth
|
||||
eth->mii_bus->name = "mdio";
|
||||
eth->mii_bus->read = mtk_mdio_read;
|
||||
eth->mii_bus->write = mtk_mdio_write;
|
||||
@ -113,7 +113,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -346,9 +346,12 @@
|
||||
@@ -349,9 +349,12 @@
|
||||
#define PHY_IAC_ADDR_MASK GENMASK(24, 20)
|
||||
#define PHY_IAC_ADDR(x) FIELD_PREP(PHY_IAC_ADDR_MASK, (x))
|
||||
#define PHY_IAC_CMD_MASK GENMASK(19, 18)
|
||||
|
@ -1,6 +1,6 @@
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -575,6 +575,7 @@ static void mtk_validate(struct phylink_
|
||||
@@ -577,6 +577,7 @@ static void mtk_validate(struct phylink_
|
||||
if (MTK_HAS_CAPS(mac->hw->soc->caps, MTK_SGMII)) {
|
||||
phylink_set(mask, 1000baseT_Full);
|
||||
phylink_set(mask, 1000baseX_Full);
|
||||
|
@ -44,18 +44,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
slot1: pcie@1,0 {
|
||||
reg = <0x0800 0 0 0 0>;
|
||||
@@ -933,6 +939,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
+ hifsys: syscon@1af00000 {
|
||||
+ compatible = "mediatek,mt7622-hifsys", "syscon";
|
||||
+ reg = <0 0x1af00000 0 0x70>;
|
||||
+ };
|
||||
+
|
||||
ethsys: syscon@1b000000 {
|
||||
compatible = "mediatek,mt7622-ethsys",
|
||||
"syscon";
|
||||
--- a/drivers/pci/controller/pcie-mediatek.c
|
||||
+++ b/drivers/pci/controller/pcie-mediatek.c
|
||||
@@ -20,6 +20,7 @@
|
||||
|
@ -14,7 +14,7 @@ Signed-off-by: René van Dorst <opensource@vdorst.com>
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -2941,6 +2941,7 @@ static const struct net_device_ops mtk_n
|
||||
@@ -2949,6 +2949,7 @@ static const struct net_device_ops mtk_n
|
||||
|
||||
static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
|
||||
{
|
||||
@ -22,7 +22,7 @@ Signed-off-by: René van Dorst <opensource@vdorst.com>
|
||||
const __be32 *_id = of_get_property(np, "reg", NULL);
|
||||
phy_interface_t phy_mode;
|
||||
struct phylink *phylink;
|
||||
@@ -3036,6 +3037,9 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
@@ -3044,6 +3045,9 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
else
|
||||
eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH_2K - MTK_RX_ETH_HLEN;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user