mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-16 04:13:31 +00:00
kernel: add WED rx support for mediatek on mt76 with MT7986 and MT7915
This commit is contained in:
parent
da4a9aaee0
commit
b1e4d3d413
@ -363,7 +363,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov
|
||||
return 0;
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -494,6 +494,7 @@ static int
|
||||
@@ -491,6 +491,7 @@ static int
|
||||
mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
|
||||
{
|
||||
struct mtk_flow_entry *entry;
|
||||
@ -371,7 +371,7 @@ v2: fix wrong variable name in return value check spotted by Denis Kirjanov
|
||||
u32 idle;
|
||||
|
||||
entry = rhashtable_lookup(ð->flow_table, &f->cookie,
|
||||
@@ -504,6 +505,12 @@ mtk_flow_offload_stats(struct mtk_eth *e
|
||||
@@ -501,6 +502,12 @@ mtk_flow_offload_stats(struct mtk_eth *e
|
||||
idle = mtk_foe_entry_idle_time(eth->ppe[entry->ppe_index], entry);
|
||||
f->stats.lastused = jiffies - idle * HZ;
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 27 Oct 2022 19:50:31 +0200
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: account for vlan in rx
|
||||
header length
|
||||
|
||||
The network stack assumes that devices can handle an extra VLAN tag without
|
||||
increasing the MTU
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -29,7 +29,7 @@
|
||||
#define MTK_TX_DMA_BUF_LEN_V2 0xffff
|
||||
#define MTK_DMA_SIZE 512
|
||||
#define MTK_MAC_COUNT 2
|
||||
-#define MTK_RX_ETH_HLEN (ETH_HLEN + ETH_FCS_LEN)
|
||||
+#define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + ETH_FCS_LEN)
|
||||
#define MTK_RX_HLEN (NET_SKB_PAD + MTK_RX_ETH_HLEN + NET_IP_ALIGN)
|
||||
#define MTK_DMA_DUMMY_DESC 0xffffffff
|
||||
#define MTK_DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | \
|
@ -0,0 +1,143 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 27 Oct 2022 19:53:57 +0200
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: increase tx ring side for
|
||||
QDMA devices
|
||||
|
||||
In order to use the hardware traffic shaper feature, a larger tx ring is
|
||||
needed, especially for the scratch ring, which the hardware shaper uses to
|
||||
reorder packets.
|
||||
|
||||
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
|
||||
@@ -894,7 +894,7 @@ static int mtk_init_fq_dma(struct mtk_et
|
||||
{
|
||||
const struct mtk_soc_data *soc = eth->soc;
|
||||
dma_addr_t phy_ring_tail;
|
||||
- int cnt = MTK_DMA_SIZE;
|
||||
+ int cnt = MTK_QDMA_RING_SIZE;
|
||||
dma_addr_t dma_addr;
|
||||
int i;
|
||||
|
||||
@@ -2148,19 +2148,25 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
struct mtk_tx_ring *ring = ð->tx_ring;
|
||||
int i, sz = soc->txrx.txd_size;
|
||||
struct mtk_tx_dma_v2 *txd;
|
||||
+ int ring_size;
|
||||
|
||||
- ring->buf = kcalloc(MTK_DMA_SIZE, sizeof(*ring->buf),
|
||||
+ if (MTK_HAS_CAPS(soc->caps, MTK_QDMA))
|
||||
+ ring_size = MTK_QDMA_RING_SIZE;
|
||||
+ else
|
||||
+ ring_size = MTK_DMA_SIZE;
|
||||
+
|
||||
+ ring->buf = kcalloc(ring_size, sizeof(*ring->buf),
|
||||
GFP_KERNEL);
|
||||
if (!ring->buf)
|
||||
goto no_tx_mem;
|
||||
|
||||
- ring->dma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz,
|
||||
+ ring->dma = dma_alloc_coherent(eth->dma_dev, ring_size * sz,
|
||||
&ring->phys, GFP_KERNEL);
|
||||
if (!ring->dma)
|
||||
goto no_tx_mem;
|
||||
|
||||
- for (i = 0; i < MTK_DMA_SIZE; i++) {
|
||||
- int next = (i + 1) % MTK_DMA_SIZE;
|
||||
+ for (i = 0; i < ring_size; i++) {
|
||||
+ int next = (i + 1) % ring_size;
|
||||
u32 next_ptr = ring->phys + next * sz;
|
||||
|
||||
txd = ring->dma + i * sz;
|
||||
@@ -2180,22 +2186,22 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
* descriptors in ring->dma_pdma.
|
||||
*/
|
||||
if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA)) {
|
||||
- ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, MTK_DMA_SIZE * sz,
|
||||
+ ring->dma_pdma = dma_alloc_coherent(eth->dma_dev, ring_size * sz,
|
||||
&ring->phys_pdma, GFP_KERNEL);
|
||||
if (!ring->dma_pdma)
|
||||
goto no_tx_mem;
|
||||
|
||||
- for (i = 0; i < MTK_DMA_SIZE; i++) {
|
||||
+ for (i = 0; i < ring_size; i++) {
|
||||
ring->dma_pdma[i].txd2 = TX_DMA_DESP2_DEF;
|
||||
ring->dma_pdma[i].txd4 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
- ring->dma_size = MTK_DMA_SIZE;
|
||||
- atomic_set(&ring->free_count, MTK_DMA_SIZE - 2);
|
||||
+ ring->dma_size = ring_size;
|
||||
+ atomic_set(&ring->free_count, ring_size - 2);
|
||||
ring->next_free = ring->dma;
|
||||
ring->last_free = (void *)txd;
|
||||
- ring->last_free_ptr = (u32)(ring->phys + ((MTK_DMA_SIZE - 1) * sz));
|
||||
+ ring->last_free_ptr = (u32)(ring->phys + ((ring_size - 1) * sz));
|
||||
ring->thresh = MAX_SKB_FRAGS;
|
||||
|
||||
/* make sure that all changes to the dma ring are flushed before we
|
||||
@@ -2207,14 +2213,14 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
mtk_w32(eth, ring->phys, soc->reg_map->qdma.ctx_ptr);
|
||||
mtk_w32(eth, ring->phys, soc->reg_map->qdma.dtx_ptr);
|
||||
mtk_w32(eth,
|
||||
- ring->phys + ((MTK_DMA_SIZE - 1) * sz),
|
||||
+ ring->phys + ((ring_size - 1) * sz),
|
||||
soc->reg_map->qdma.crx_ptr);
|
||||
mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr);
|
||||
mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES,
|
||||
soc->reg_map->qdma.qtx_cfg);
|
||||
} else {
|
||||
mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0);
|
||||
- mtk_w32(eth, MTK_DMA_SIZE, MT7628_TX_MAX_CNT0);
|
||||
+ mtk_w32(eth, ring_size, MT7628_TX_MAX_CNT0);
|
||||
mtk_w32(eth, 0, MT7628_TX_CTX_IDX0);
|
||||
mtk_w32(eth, MT7628_PST_DTX_IDX0, soc->reg_map->pdma.rst_idx);
|
||||
}
|
||||
@@ -2232,7 +2238,7 @@ static void mtk_tx_clean(struct mtk_eth
|
||||
int i;
|
||||
|
||||
if (ring->buf) {
|
||||
- for (i = 0; i < MTK_DMA_SIZE; i++)
|
||||
+ for (i = 0; i < ring->dma_size; i++)
|
||||
mtk_tx_unmap(eth, &ring->buf[i], false);
|
||||
kfree(ring->buf);
|
||||
ring->buf = NULL;
|
||||
@@ -2240,14 +2246,14 @@ static void mtk_tx_clean(struct mtk_eth
|
||||
|
||||
if (ring->dma) {
|
||||
dma_free_coherent(eth->dma_dev,
|
||||
- MTK_DMA_SIZE * soc->txrx.txd_size,
|
||||
+ ring->dma_size * soc->txrx.txd_size,
|
||||
ring->dma, ring->phys);
|
||||
ring->dma = NULL;
|
||||
}
|
||||
|
||||
if (ring->dma_pdma) {
|
||||
dma_free_coherent(eth->dma_dev,
|
||||
- MTK_DMA_SIZE * soc->txrx.txd_size,
|
||||
+ ring->dma_size * soc->txrx.txd_size,
|
||||
ring->dma_pdma, ring->phys_pdma);
|
||||
ring->dma_pdma = NULL;
|
||||
}
|
||||
@@ -2767,7 +2773,7 @@ static void mtk_dma_free(struct mtk_eth
|
||||
netdev_reset_queue(eth->netdev[i]);
|
||||
if (eth->scratch_ring) {
|
||||
dma_free_coherent(eth->dma_dev,
|
||||
- MTK_DMA_SIZE * soc->txrx.txd_size,
|
||||
+ MTK_QDMA_RING_SIZE * soc->txrx.txd_size,
|
||||
eth->scratch_ring, eth->phy_scratch_ring);
|
||||
eth->scratch_ring = NULL;
|
||||
eth->phy_scratch_ring = 0;
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -27,6 +27,7 @@
|
||||
#define MTK_MAX_RX_LENGTH_2K 2048
|
||||
#define MTK_TX_DMA_BUF_LEN 0x3fff
|
||||
#define MTK_TX_DMA_BUF_LEN_V2 0xffff
|
||||
+#define MTK_QDMA_RING_SIZE 2048
|
||||
#define MTK_DMA_SIZE 512
|
||||
#define MTK_MAC_COUNT 2
|
||||
#define MTK_RX_ETH_HLEN (VLAN_ETH_HLEN + ETH_FCS_LEN)
|
@ -0,0 +1,52 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 4 Nov 2022 19:49:08 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: avoid port_mg assignment on
|
||||
MT7622 and newer
|
||||
|
||||
On newer chips, this field is unused and contains some bits related to queue
|
||||
assignment. Initialize it to 0 in those cases.
|
||||
Fix offload_version on MT7621 and MT7623, which still need the previous value.
|
||||
|
||||
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
|
||||
@@ -4197,7 +4197,7 @@ static const struct mtk_soc_data mt7621_
|
||||
.hw_features = MTK_HW_FEATURES,
|
||||
.required_clks = MT7621_CLKS_BITMAP,
|
||||
.required_pctl = false,
|
||||
- .offload_version = 2,
|
||||
+ .offload_version = 1,
|
||||
.hash_offset = 2,
|
||||
.foe_entry_size = sizeof(struct mtk_foe_entry) - 16,
|
||||
.txrx = {
|
||||
@@ -4237,7 +4237,7 @@ static const struct mtk_soc_data mt7623_
|
||||
.hw_features = MTK_HW_FEATURES,
|
||||
.required_clks = MT7623_CLKS_BITMAP,
|
||||
.required_pctl = true,
|
||||
- .offload_version = 2,
|
||||
+ .offload_version = 1,
|
||||
.hash_offset = 2,
|
||||
.foe_entry_size = sizeof(struct mtk_foe_entry) - 16,
|
||||
.txrx = {
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
@@ -215,6 +215,8 @@ int mtk_foe_entry_prepare(struct mtk_eth
|
||||
val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT_V2, pse_port) |
|
||||
FIELD_PREP(MTK_FOE_IB2_PORT_AG_V2, 0xf);
|
||||
} else {
|
||||
+ int port_mg = eth->soc->offload_version > 1 ? 0 : 0x3f;
|
||||
+
|
||||
val = FIELD_PREP(MTK_FOE_IB1_STATE, MTK_FOE_STATE_BIND) |
|
||||
FIELD_PREP(MTK_FOE_IB1_PACKET_TYPE, type) |
|
||||
FIELD_PREP(MTK_FOE_IB1_UDP, l4proto == IPPROTO_UDP) |
|
||||
@@ -222,7 +224,7 @@ int mtk_foe_entry_prepare(struct mtk_eth
|
||||
entry->ib1 = val;
|
||||
|
||||
val = FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port) |
|
||||
- FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) |
|
||||
+ FIELD_PREP(MTK_FOE_IB2_PORT_MG, port_mg) |
|
||||
FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f);
|
||||
}
|
||||
|
@ -0,0 +1,654 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 27 Oct 2022 20:17:27 +0200
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: implement multi-queue
|
||||
support for per-port queues
|
||||
|
||||
When sending traffic to multiple ports with different link speeds, queued
|
||||
packets to one port can drown out tx to other ports.
|
||||
In order to better handle transmission to multiple ports, use the hardware
|
||||
shaper feature to implement weighted fair queueing between ports.
|
||||
Weight and maximum rate are automatically adjusted based on the link speed
|
||||
of the port.
|
||||
The first 3 queues are unrestricted and reserved for non-DSA direct tx on
|
||||
GMAC ports. The following queues are automatically assigned by the MTK DSA
|
||||
tag driver based on the target port number.
|
||||
The PPE offload code configures the queues for offloaded traffic in the same
|
||||
way.
|
||||
This feature is only supported on devices supporting QDMA. All queues still
|
||||
share the same DMA ring and descriptor pool.
|
||||
|
||||
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
|
||||
@@ -54,6 +54,7 @@ static const struct mtk_reg_map mtk_reg_
|
||||
},
|
||||
.qdma = {
|
||||
.qtx_cfg = 0x1800,
|
||||
+ .qtx_sch = 0x1804,
|
||||
.rx_ptr = 0x1900,
|
||||
.rx_cnt_cfg = 0x1904,
|
||||
.qcrx_ptr = 0x1908,
|
||||
@@ -61,6 +62,7 @@ static const struct mtk_reg_map mtk_reg_
|
||||
.rst_idx = 0x1a08,
|
||||
.delay_irq = 0x1a0c,
|
||||
.fc_th = 0x1a10,
|
||||
+ .tx_sch_rate = 0x1a14,
|
||||
.int_grp = 0x1a20,
|
||||
.hred = 0x1a44,
|
||||
.ctx_ptr = 0x1b00,
|
||||
@@ -113,6 +115,7 @@ static const struct mtk_reg_map mt7986_r
|
||||
},
|
||||
.qdma = {
|
||||
.qtx_cfg = 0x4400,
|
||||
+ .qtx_sch = 0x4404,
|
||||
.rx_ptr = 0x4500,
|
||||
.rx_cnt_cfg = 0x4504,
|
||||
.qcrx_ptr = 0x4508,
|
||||
@@ -130,6 +133,7 @@ static const struct mtk_reg_map mt7986_r
|
||||
.fq_tail = 0x4724,
|
||||
.fq_count = 0x4728,
|
||||
.fq_blen = 0x472c,
|
||||
+ .tx_sch_rate = 0x4798,
|
||||
},
|
||||
.gdm1_cnt = 0x1c00,
|
||||
.gdma_to_ppe0 = 0x3333,
|
||||
@@ -570,6 +574,75 @@ static void mtk_mac_link_down(struct phy
|
||||
mtk_w32(mac->hw, mcr, MTK_MAC_MCR(mac->id));
|
||||
}
|
||||
|
||||
+static void mtk_set_queue_speed(struct mtk_eth *eth, unsigned int idx,
|
||||
+ int speed)
|
||||
+{
|
||||
+ const struct mtk_soc_data *soc = eth->soc;
|
||||
+ u32 ofs, val;
|
||||
+
|
||||
+ if (!MTK_HAS_CAPS(soc->caps, MTK_QDMA))
|
||||
+ return;
|
||||
+
|
||||
+ val = MTK_QTX_SCH_MIN_RATE_EN |
|
||||
+ /* minimum: 10 Mbps */
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
|
||||
+ MTK_QTX_SCH_LEAKY_BUCKET_SIZE;
|
||||
+ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
|
||||
+ val |= MTK_QTX_SCH_LEAKY_BUCKET_EN;
|
||||
+
|
||||
+ if (IS_ENABLED(CONFIG_SOC_MT7621)) {
|
||||
+ switch (speed) {
|
||||
+ case SPEED_10:
|
||||
+ val |= MTK_QTX_SCH_MAX_RATE_EN |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 103) |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 2) |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1);
|
||||
+ break;
|
||||
+ case SPEED_100:
|
||||
+ val |= MTK_QTX_SCH_MAX_RATE_EN |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 103) |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 3);
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1);
|
||||
+ break;
|
||||
+ case SPEED_1000:
|
||||
+ val |= MTK_QTX_SCH_MAX_RATE_EN |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 105) |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 4) |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 10);
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ } else {
|
||||
+ switch (speed) {
|
||||
+ case SPEED_10:
|
||||
+ val |= MTK_QTX_SCH_MAX_RATE_EN |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 1) |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 4) |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1);
|
||||
+ break;
|
||||
+ case SPEED_100:
|
||||
+ val |= MTK_QTX_SCH_MAX_RATE_EN |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 1) |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 5);
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 1);
|
||||
+ break;
|
||||
+ case SPEED_1000:
|
||||
+ val |= MTK_QTX_SCH_MAX_RATE_EN |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 10) |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 5) |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 10);
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ ofs = MTK_QTX_OFFSET * idx;
|
||||
+ mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs);
|
||||
+}
|
||||
+
|
||||
static void mtk_mac_link_up(struct phylink_config *config,
|
||||
struct phy_device *phy,
|
||||
unsigned int mode, phy_interface_t interface,
|
||||
@@ -595,6 +668,8 @@ static void mtk_mac_link_up(struct phyli
|
||||
break;
|
||||
}
|
||||
|
||||
+ mtk_set_queue_speed(mac->hw, mac->id, speed);
|
||||
+
|
||||
/* Configure duplex */
|
||||
if (duplex == DUPLEX_FULL)
|
||||
mcr |= MAC_MCR_FORCE_DPX;
|
||||
@@ -1053,7 +1128,8 @@ static void mtk_tx_set_dma_desc_v1(struc
|
||||
|
||||
WRITE_ONCE(desc->txd1, info->addr);
|
||||
|
||||
- data = TX_DMA_SWC | TX_DMA_PLEN0(info->size);
|
||||
+ data = TX_DMA_SWC | TX_DMA_PLEN0(info->size) |
|
||||
+ FIELD_PREP(TX_DMA_PQID, info->qid);
|
||||
if (info->last)
|
||||
data |= TX_DMA_LS0;
|
||||
WRITE_ONCE(desc->txd3, data);
|
||||
@@ -1087,9 +1163,6 @@ static void mtk_tx_set_dma_desc_v2(struc
|
||||
data |= TX_DMA_LS0;
|
||||
WRITE_ONCE(desc->txd3, data);
|
||||
|
||||
- if (!info->qid && mac->id)
|
||||
- info->qid = MTK_QDMA_GMAC2_QID;
|
||||
-
|
||||
data = (mac->id + 1) << TX_DMA_FPORT_SHIFT_V2; /* forward port */
|
||||
data |= TX_DMA_SWC_V2 | QID_BITS_V2(info->qid);
|
||||
WRITE_ONCE(desc->txd4, data);
|
||||
@@ -1133,11 +1206,12 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
.gso = gso,
|
||||
.csum = skb->ip_summed == CHECKSUM_PARTIAL,
|
||||
.vlan = skb_vlan_tag_present(skb),
|
||||
- .qid = skb->mark & MTK_QDMA_TX_MASK,
|
||||
+ .qid = skb_get_queue_mapping(skb),
|
||||
.vlan_tci = skb_vlan_tag_get(skb),
|
||||
.first = true,
|
||||
.last = !skb_is_nonlinear(skb),
|
||||
};
|
||||
+ struct netdev_queue *txq;
|
||||
struct mtk_mac *mac = netdev_priv(dev);
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
const struct mtk_soc_data *soc = eth->soc;
|
||||
@@ -1145,8 +1219,10 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
struct mtk_tx_dma *itxd_pdma, *txd_pdma;
|
||||
struct mtk_tx_buf *itx_buf, *tx_buf;
|
||||
int i, n_desc = 1;
|
||||
+ int queue = skb_get_queue_mapping(skb);
|
||||
int k = 0;
|
||||
|
||||
+ txq = netdev_get_tx_queue(dev, queue);
|
||||
itxd = ring->next_free;
|
||||
itxd_pdma = qdma_to_pdma(ring, itxd);
|
||||
if (itxd == ring->last_free)
|
||||
@@ -1195,7 +1271,7 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info));
|
||||
txd_info.size = min_t(unsigned int, frag_size,
|
||||
soc->txrx.dma_max_len);
|
||||
- txd_info.qid = skb->mark & MTK_QDMA_TX_MASK;
|
||||
+ txd_info.qid = queue;
|
||||
txd_info.last = i == skb_shinfo(skb)->nr_frags - 1 &&
|
||||
!(frag_size - txd_info.size);
|
||||
txd_info.addr = skb_frag_dma_map(eth->dma_dev, frag,
|
||||
@@ -1234,7 +1310,7 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
txd_pdma->txd2 |= TX_DMA_LS1;
|
||||
}
|
||||
|
||||
- netdev_sent_queue(dev, skb->len);
|
||||
+ netdev_tx_sent_queue(txq, skb->len);
|
||||
skb_tx_timestamp(skb);
|
||||
|
||||
ring->next_free = mtk_qdma_phys_to_virt(ring, txd->txd2);
|
||||
@@ -1246,8 +1322,7 @@ static int mtk_tx_map(struct sk_buff *sk
|
||||
wmb();
|
||||
|
||||
if (MTK_HAS_CAPS(soc->caps, MTK_QDMA)) {
|
||||
- if (netif_xmit_stopped(netdev_get_tx_queue(dev, 0)) ||
|
||||
- !netdev_xmit_more())
|
||||
+ if (netif_xmit_stopped(txq) || !netdev_xmit_more())
|
||||
mtk_w32(eth, txd->txd2, soc->reg_map->qdma.ctx_ptr);
|
||||
} else {
|
||||
int next_idx;
|
||||
@@ -1316,7 +1391,7 @@ static void mtk_wake_queue(struct mtk_et
|
||||
for (i = 0; i < MTK_MAC_COUNT; i++) {
|
||||
if (!eth->netdev[i])
|
||||
continue;
|
||||
- netif_wake_queue(eth->netdev[i]);
|
||||
+ netif_tx_wake_all_queues(eth->netdev[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1340,7 +1415,7 @@ static netdev_tx_t mtk_start_xmit(struct
|
||||
|
||||
tx_num = mtk_cal_txd_req(eth, skb);
|
||||
if (unlikely(atomic_read(&ring->free_count) <= tx_num)) {
|
||||
- netif_stop_queue(dev);
|
||||
+ netif_tx_stop_all_queues(dev);
|
||||
netif_err(eth, tx_queued, dev,
|
||||
"Tx Ring full when queue awake!\n");
|
||||
spin_unlock(ð->page_lock);
|
||||
@@ -1366,7 +1441,7 @@ static netdev_tx_t mtk_start_xmit(struct
|
||||
goto drop;
|
||||
|
||||
if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))
|
||||
- netif_stop_queue(dev);
|
||||
+ netif_tx_stop_all_queues(dev);
|
||||
|
||||
spin_unlock(ð->page_lock);
|
||||
|
||||
@@ -1533,10 +1608,12 @@ static int mtk_xdp_submit_frame(struct m
|
||||
struct skb_shared_info *sinfo = xdp_get_shared_info_from_frame(xdpf);
|
||||
const struct mtk_soc_data *soc = eth->soc;
|
||||
struct mtk_tx_ring *ring = ð->tx_ring;
|
||||
+ struct mtk_mac *mac = netdev_priv(dev);
|
||||
struct mtk_tx_dma_desc_info txd_info = {
|
||||
.size = xdpf->len,
|
||||
.first = true,
|
||||
.last = !xdp_frame_has_frags(xdpf),
|
||||
+ .qid = mac->id,
|
||||
};
|
||||
int err, index = 0, n_desc = 1, nr_frags;
|
||||
struct mtk_tx_dma *htxd, *txd, *txd_pdma;
|
||||
@@ -1587,6 +1664,7 @@ static int mtk_xdp_submit_frame(struct m
|
||||
memset(&txd_info, 0, sizeof(struct mtk_tx_dma_desc_info));
|
||||
txd_info.size = skb_frag_size(&sinfo->frags[index]);
|
||||
txd_info.last = index + 1 == nr_frags;
|
||||
+ txd_info.qid = mac->id;
|
||||
data = skb_frag_address(&sinfo->frags[index]);
|
||||
|
||||
index++;
|
||||
@@ -1938,8 +2016,46 @@ rx_done:
|
||||
return done;
|
||||
}
|
||||
|
||||
+struct mtk_poll_state {
|
||||
+ struct netdev_queue *txq;
|
||||
+ unsigned int total;
|
||||
+ unsigned int done;
|
||||
+ unsigned int bytes;
|
||||
+};
|
||||
+
|
||||
+static void
|
||||
+mtk_poll_tx_done(struct mtk_eth *eth, struct mtk_poll_state *state, u8 mac,
|
||||
+ struct sk_buff *skb)
|
||||
+{
|
||||
+ struct netdev_queue *txq;
|
||||
+ struct net_device *dev;
|
||||
+ unsigned int bytes = skb->len;
|
||||
+
|
||||
+ state->total++;
|
||||
+ eth->tx_packets++;
|
||||
+ eth->tx_bytes += bytes;
|
||||
+
|
||||
+ dev = eth->netdev[mac];
|
||||
+ if (!dev)
|
||||
+ return;
|
||||
+
|
||||
+ txq = netdev_get_tx_queue(dev, skb_get_queue_mapping(skb));
|
||||
+ if (state->txq == txq) {
|
||||
+ state->done++;
|
||||
+ state->bytes += bytes;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (state->txq)
|
||||
+ netdev_tx_completed_queue(state->txq, state->done, state->bytes);
|
||||
+
|
||||
+ state->txq = txq;
|
||||
+ state->done = 1;
|
||||
+ state->bytes = bytes;
|
||||
+}
|
||||
+
|
||||
static int mtk_poll_tx_qdma(struct mtk_eth *eth, int budget,
|
||||
- unsigned int *done, unsigned int *bytes)
|
||||
+ struct mtk_poll_state *state)
|
||||
{
|
||||
const struct mtk_reg_map *reg_map = eth->soc->reg_map;
|
||||
struct mtk_tx_ring *ring = ð->tx_ring;
|
||||
@@ -1969,12 +2085,9 @@ static int mtk_poll_tx_qdma(struct mtk_e
|
||||
break;
|
||||
|
||||
if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) {
|
||||
- if (tx_buf->type == MTK_TYPE_SKB) {
|
||||
- struct sk_buff *skb = tx_buf->data;
|
||||
+ if (tx_buf->type == MTK_TYPE_SKB)
|
||||
+ mtk_poll_tx_done(eth, state, mac, tx_buf->data);
|
||||
|
||||
- bytes[mac] += skb->len;
|
||||
- done[mac]++;
|
||||
- }
|
||||
budget--;
|
||||
}
|
||||
mtk_tx_unmap(eth, tx_buf, true);
|
||||
@@ -1992,7 +2105,7 @@ static int mtk_poll_tx_qdma(struct mtk_e
|
||||
}
|
||||
|
||||
static int mtk_poll_tx_pdma(struct mtk_eth *eth, int budget,
|
||||
- unsigned int *done, unsigned int *bytes)
|
||||
+ struct mtk_poll_state *state)
|
||||
{
|
||||
struct mtk_tx_ring *ring = ð->tx_ring;
|
||||
struct mtk_tx_buf *tx_buf;
|
||||
@@ -2008,12 +2121,8 @@ static int mtk_poll_tx_pdma(struct mtk_e
|
||||
break;
|
||||
|
||||
if (tx_buf->data != (void *)MTK_DMA_DUMMY_DESC) {
|
||||
- if (tx_buf->type == MTK_TYPE_SKB) {
|
||||
- struct sk_buff *skb = tx_buf->data;
|
||||
-
|
||||
- bytes[0] += skb->len;
|
||||
- done[0]++;
|
||||
- }
|
||||
+ if (tx_buf->type == MTK_TYPE_SKB)
|
||||
+ mtk_poll_tx_done(eth, state, 0, tx_buf->data);
|
||||
budget--;
|
||||
}
|
||||
mtk_tx_unmap(eth, tx_buf, true);
|
||||
@@ -2034,26 +2143,15 @@ static int mtk_poll_tx(struct mtk_eth *e
|
||||
{
|
||||
struct mtk_tx_ring *ring = ð->tx_ring;
|
||||
struct dim_sample dim_sample = {};
|
||||
- unsigned int done[MTK_MAX_DEVS];
|
||||
- unsigned int bytes[MTK_MAX_DEVS];
|
||||
- int total = 0, i;
|
||||
-
|
||||
- memset(done, 0, sizeof(done));
|
||||
- memset(bytes, 0, sizeof(bytes));
|
||||
+ struct mtk_poll_state state = {};
|
||||
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
|
||||
- budget = mtk_poll_tx_qdma(eth, budget, done, bytes);
|
||||
+ budget = mtk_poll_tx_qdma(eth, budget, &state);
|
||||
else
|
||||
- budget = mtk_poll_tx_pdma(eth, budget, done, bytes);
|
||||
+ budget = mtk_poll_tx_pdma(eth, budget, &state);
|
||||
|
||||
- for (i = 0; i < MTK_MAC_COUNT; i++) {
|
||||
- if (!eth->netdev[i] || !done[i])
|
||||
- continue;
|
||||
- netdev_completed_queue(eth->netdev[i], done[i], bytes[i]);
|
||||
- total += done[i];
|
||||
- eth->tx_packets += done[i];
|
||||
- eth->tx_bytes += bytes[i];
|
||||
- }
|
||||
+ if (state.txq)
|
||||
+ netdev_tx_completed_queue(state.txq, state.done, state.bytes);
|
||||
|
||||
dim_update_sample(eth->tx_events, eth->tx_packets, eth->tx_bytes,
|
||||
&dim_sample);
|
||||
@@ -2063,7 +2161,7 @@ static int mtk_poll_tx(struct mtk_eth *e
|
||||
(atomic_read(&ring->free_count) > ring->thresh))
|
||||
mtk_wake_queue(eth);
|
||||
|
||||
- return total;
|
||||
+ return state.total;
|
||||
}
|
||||
|
||||
static void mtk_handle_status_irq(struct mtk_eth *eth)
|
||||
@@ -2149,6 +2247,7 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
int i, sz = soc->txrx.txd_size;
|
||||
struct mtk_tx_dma_v2 *txd;
|
||||
int ring_size;
|
||||
+ u32 ofs, val;
|
||||
|
||||
if (MTK_HAS_CAPS(soc->caps, MTK_QDMA))
|
||||
ring_size = MTK_QDMA_RING_SIZE;
|
||||
@@ -2216,8 +2315,25 @@ static int mtk_tx_alloc(struct mtk_eth *
|
||||
ring->phys + ((ring_size - 1) * sz),
|
||||
soc->reg_map->qdma.crx_ptr);
|
||||
mtk_w32(eth, ring->last_free_ptr, soc->reg_map->qdma.drx_ptr);
|
||||
- mtk_w32(eth, (QDMA_RES_THRES << 8) | QDMA_RES_THRES,
|
||||
- soc->reg_map->qdma.qtx_cfg);
|
||||
+
|
||||
+ for (i = 0, ofs = 0; i < MTK_QDMA_NUM_QUEUES; i++) {
|
||||
+ val = (QDMA_RES_THRES << 8) | QDMA_RES_THRES;
|
||||
+ mtk_w32(eth, val, soc->reg_map->qdma.qtx_cfg + ofs);
|
||||
+
|
||||
+ val = MTK_QTX_SCH_MIN_RATE_EN |
|
||||
+ /* minimum: 10 Mbps */
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
|
||||
+ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
|
||||
+ MTK_QTX_SCH_LEAKY_BUCKET_SIZE;
|
||||
+ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
|
||||
+ val |= MTK_QTX_SCH_LEAKY_BUCKET_EN;
|
||||
+ mtk_w32(eth, val, soc->reg_map->qdma.qtx_sch + ofs);
|
||||
+ ofs += MTK_QTX_OFFSET;
|
||||
+ }
|
||||
+ val = MTK_QDMA_TX_SCH_MAX_WFQ | (MTK_QDMA_TX_SCH_MAX_WFQ << 16);
|
||||
+ mtk_w32(eth, val, soc->reg_map->qdma.tx_sch_rate);
|
||||
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
|
||||
+ mtk_w32(eth, val, soc->reg_map->qdma.tx_sch_rate + 4);
|
||||
} else {
|
||||
mtk_w32(eth, ring->phys_pdma, MT7628_TX_BASE_PTR0);
|
||||
mtk_w32(eth, ring_size, MT7628_TX_MAX_CNT0);
|
||||
@@ -2882,7 +2998,7 @@ static int mtk_start_dma(struct mtk_eth
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
|
||||
val |= MTK_MUTLI_CNT | MTK_RESV_BUF |
|
||||
MTK_WCOMP_EN | MTK_DMAD_WR_WDONE |
|
||||
- MTK_CHK_DDONE_EN;
|
||||
+ MTK_CHK_DDONE_EN | MTK_LEAKY_BUCKET_EN;
|
||||
else
|
||||
val |= MTK_RX_BT_32DWORDS;
|
||||
mtk_w32(eth, val, reg_map->qdma.glo_cfg);
|
||||
@@ -2928,6 +3044,45 @@ static void mtk_gdm_config(struct mtk_et
|
||||
mtk_w32(eth, 0, MTK_RST_GL);
|
||||
}
|
||||
|
||||
+static int mtk_device_event(struct notifier_block *n, unsigned long event, void *ptr)
|
||||
+{
|
||||
+ struct mtk_mac *mac = container_of(n, struct mtk_mac, device_notifier);
|
||||
+ struct mtk_eth *eth = mac->hw;
|
||||
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
+ struct ethtool_link_ksettings s;
|
||||
+ struct net_device *ldev;
|
||||
+ struct list_head *iter;
|
||||
+ struct dsa_port *dp;
|
||||
+
|
||||
+ if (event != NETDEV_CHANGE)
|
||||
+ return NOTIFY_DONE;
|
||||
+
|
||||
+ netdev_for_each_lower_dev(dev, ldev, iter) {
|
||||
+ if (netdev_priv(ldev) == mac)
|
||||
+ goto found;
|
||||
+ }
|
||||
+
|
||||
+ return NOTIFY_DONE;
|
||||
+
|
||||
+found:
|
||||
+ if (!dsa_slave_dev_check(dev))
|
||||
+ return NOTIFY_DONE;
|
||||
+
|
||||
+ if (__ethtool_get_link_ksettings(dev, &s))
|
||||
+ return NOTIFY_DONE;
|
||||
+
|
||||
+ if (s.base.speed == 0 || s.base.speed == ((__u32)-1))
|
||||
+ return NOTIFY_DONE;
|
||||
+
|
||||
+ dp = dsa_port_from_netdev(dev);
|
||||
+ if (dp->index >= MTK_QDMA_NUM_QUEUES)
|
||||
+ return NOTIFY_DONE;
|
||||
+
|
||||
+ mtk_set_queue_speed(eth, dp->index + 3, s.base.speed);
|
||||
+
|
||||
+ return NOTIFY_DONE;
|
||||
+}
|
||||
+
|
||||
static int mtk_open(struct net_device *dev)
|
||||
{
|
||||
struct mtk_mac *mac = netdev_priv(dev);
|
||||
@@ -2970,7 +3125,8 @@ static int mtk_open(struct net_device *d
|
||||
refcount_inc(ð->dma_refcnt);
|
||||
|
||||
phylink_start(mac->phylink);
|
||||
- netif_start_queue(dev);
|
||||
+ netif_tx_start_all_queues(dev);
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3486,8 +3642,12 @@ static int mtk_unreg_dev(struct mtk_eth
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MTK_MAC_COUNT; i++) {
|
||||
+ struct mtk_mac *mac;
|
||||
if (!eth->netdev[i])
|
||||
continue;
|
||||
+ mac = netdev_priv(eth->netdev[i]);
|
||||
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
|
||||
+ unregister_netdevice_notifier(&mac->device_notifier);
|
||||
unregister_netdev(eth->netdev[i]);
|
||||
}
|
||||
|
||||
@@ -3703,6 +3863,23 @@ static int mtk_set_rxnfc(struct net_devi
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static u16 mtk_select_queue(struct net_device *dev, struct sk_buff *skb,
|
||||
+ struct net_device *sb_dev)
|
||||
+{
|
||||
+ struct mtk_mac *mac = netdev_priv(dev);
|
||||
+ unsigned int queue = 0;
|
||||
+
|
||||
+ if (netdev_uses_dsa(dev))
|
||||
+ queue = skb_get_queue_mapping(skb) + 3;
|
||||
+ else
|
||||
+ queue = mac->id;
|
||||
+
|
||||
+ if (queue >= dev->num_tx_queues)
|
||||
+ queue = 0;
|
||||
+
|
||||
+ return queue;
|
||||
+}
|
||||
+
|
||||
static const struct ethtool_ops mtk_ethtool_ops = {
|
||||
.get_link_ksettings = mtk_get_link_ksettings,
|
||||
.set_link_ksettings = mtk_set_link_ksettings,
|
||||
@@ -3738,6 +3915,7 @@ static const struct net_device_ops mtk_n
|
||||
.ndo_setup_tc = mtk_eth_setup_tc,
|
||||
.ndo_bpf = mtk_xdp,
|
||||
.ndo_xdp_xmit = mtk_xdp_xmit,
|
||||
+ .ndo_select_queue = mtk_select_queue,
|
||||
};
|
||||
|
||||
static int mtk_add_mac(struct mtk_eth *eth, struct device_node *np)
|
||||
@@ -3747,6 +3925,7 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
struct phylink *phylink;
|
||||
struct mtk_mac *mac;
|
||||
int id, err;
|
||||
+ int txqs = 1;
|
||||
|
||||
if (!_id) {
|
||||
dev_err(eth->dev, "missing mac id\n");
|
||||
@@ -3764,7 +3943,10 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
- eth->netdev[id] = alloc_etherdev(sizeof(*mac));
|
||||
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA))
|
||||
+ txqs = MTK_QDMA_NUM_QUEUES;
|
||||
+
|
||||
+ eth->netdev[id] = alloc_etherdev_mqs(sizeof(*mac), txqs, 1);
|
||||
if (!eth->netdev[id]) {
|
||||
dev_err(eth->dev, "alloc_etherdev failed\n");
|
||||
return -ENOMEM;
|
||||
@@ -3861,6 +4043,11 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
else
|
||||
eth->netdev[id]->max_mtu = MTK_MAX_RX_LENGTH_2K - MTK_RX_ETH_HLEN;
|
||||
|
||||
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_QDMA)) {
|
||||
+ mac->device_notifier.notifier_call = mtk_device_event;
|
||||
+ register_netdevice_notifier(&mac->device_notifier);
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
|
||||
free_netdev:
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <linux/bpf_trace.h>
|
||||
#include "mtk_ppe.h"
|
||||
|
||||
+#define MTK_QDMA_NUM_QUEUES 16
|
||||
#define MTK_QDMA_PAGE_SIZE 2048
|
||||
#define MTK_MAX_RX_LENGTH 1536
|
||||
#define MTK_MAX_RX_LENGTH_2K 2048
|
||||
@@ -203,8 +204,26 @@
|
||||
#define MTK_RING_MAX_AGG_CNT_H ((MTK_HW_LRO_MAX_AGG_CNT >> 6) & 0x3)
|
||||
|
||||
/* QDMA TX Queue Configuration Registers */
|
||||
+#define MTK_QTX_OFFSET 0x10
|
||||
#define QDMA_RES_THRES 4
|
||||
|
||||
+/* QDMA Tx Queue Scheduler Configuration Registers */
|
||||
+#define MTK_QTX_SCH_TX_SEL BIT(31)
|
||||
+#define MTK_QTX_SCH_TX_SEL_V2 GENMASK(31, 30)
|
||||
+
|
||||
+#define MTK_QTX_SCH_LEAKY_BUCKET_EN BIT(30)
|
||||
+#define MTK_QTX_SCH_LEAKY_BUCKET_SIZE GENMASK(29, 28)
|
||||
+#define MTK_QTX_SCH_MIN_RATE_EN BIT(27)
|
||||
+#define MTK_QTX_SCH_MIN_RATE_MAN GENMASK(26, 20)
|
||||
+#define MTK_QTX_SCH_MIN_RATE_EXP GENMASK(19, 16)
|
||||
+#define MTK_QTX_SCH_MAX_RATE_WEIGHT GENMASK(15, 12)
|
||||
+#define MTK_QTX_SCH_MAX_RATE_EN BIT(11)
|
||||
+#define MTK_QTX_SCH_MAX_RATE_MAN GENMASK(10, 4)
|
||||
+#define MTK_QTX_SCH_MAX_RATE_EXP GENMASK(3, 0)
|
||||
+
|
||||
+/* QDMA TX Scheduler Rate Control Register */
|
||||
+#define MTK_QDMA_TX_SCH_MAX_WFQ BIT(15)
|
||||
+
|
||||
/* QDMA Global Configuration Register */
|
||||
#define MTK_RX_2B_OFFSET BIT(31)
|
||||
#define MTK_RX_BT_32DWORDS (3 << 11)
|
||||
@@ -223,6 +242,7 @@
|
||||
#define MTK_WCOMP_EN BIT(24)
|
||||
#define MTK_RESV_BUF (0x40 << 16)
|
||||
#define MTK_MUTLI_CNT (0x4 << 12)
|
||||
+#define MTK_LEAKY_BUCKET_EN BIT(11)
|
||||
|
||||
/* QDMA Flow Control Register */
|
||||
#define FC_THRES_DROP_MODE BIT(20)
|
||||
@@ -251,8 +271,6 @@
|
||||
#define MTK_STAT_OFFSET 0x40
|
||||
|
||||
/* QDMA TX NUM */
|
||||
-#define MTK_QDMA_TX_NUM 16
|
||||
-#define MTK_QDMA_TX_MASK (MTK_QDMA_TX_NUM - 1)
|
||||
#define QID_BITS_V2(x) (((x) & 0x3f) << 16)
|
||||
#define MTK_QDMA_GMAC2_QID 8
|
||||
|
||||
@@ -282,6 +300,7 @@
|
||||
#define TX_DMA_PLEN0(x) (((x) & eth->soc->txrx.dma_max_len) << eth->soc->txrx.dma_len_offset)
|
||||
#define TX_DMA_PLEN1(x) ((x) & eth->soc->txrx.dma_max_len)
|
||||
#define TX_DMA_SWC BIT(14)
|
||||
+#define TX_DMA_PQID GENMASK(3, 0)
|
||||
|
||||
/* PDMA on MT7628 */
|
||||
#define TX_DMA_DONE BIT(31)
|
||||
@@ -930,6 +949,7 @@ struct mtk_reg_map {
|
||||
} pdma;
|
||||
struct {
|
||||
u32 qtx_cfg; /* tx queue configuration */
|
||||
+ u32 qtx_sch; /* tx queue scheduler configuration */
|
||||
u32 rx_ptr; /* rx base pointer */
|
||||
u32 rx_cnt_cfg; /* rx max count configuration */
|
||||
u32 qcrx_ptr; /* rx cpu pointer */
|
||||
@@ -947,6 +967,7 @@ struct mtk_reg_map {
|
||||
u32 fq_tail; /* fq tail pointer */
|
||||
u32 fq_count; /* fq free page count */
|
||||
u32 fq_blen; /* fq free page buffer length */
|
||||
+ u32 tx_sch_rate; /* tx scheduler rate control registers */
|
||||
} qdma;
|
||||
u32 gdm1_cnt;
|
||||
u32 gdma_to_ppe0;
|
||||
@@ -1139,6 +1160,7 @@ struct mtk_mac {
|
||||
__be32 hwlro_ip[MTK_MAX_LRO_IP_CNT];
|
||||
int hwlro_ip_cnt;
|
||||
unsigned int syscfg0;
|
||||
+ struct notifier_block device_notifier;
|
||||
};
|
||||
|
||||
/* the struct describing the SoC. these are declared in the soc_xyz.c files */
|
@ -0,0 +1,20 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 28 Oct 2022 18:16:03 +0200
|
||||
Subject: [PATCH] net: dsa: tag_mtk: assign per-port queues
|
||||
|
||||
Keeps traffic sent to the switch within link speed limits
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/dsa/tag_mtk.c
|
||||
+++ b/net/dsa/tag_mtk.c
|
||||
@@ -33,6 +33,8 @@ static struct sk_buff *mtk_tag_xmit(stru
|
||||
if (__skb_put_padto(skb, ETH_ZLEN + MTK_HDR_LEN, false))
|
||||
return NULL;
|
||||
|
||||
+ skb_set_queue_mapping(skb, dp->index);
|
||||
+
|
||||
/* Build the special tag after the MAC Source Address. If VLAN header
|
||||
* is present, it's required that VLAN header and special tag is
|
||||
* being combined. Only in this way we can allow the switch can parse
|
@ -0,0 +1,93 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 3 Nov 2022 17:49:44 +0100
|
||||
Subject: [PATCH] net: ethernet: mediatek: ppe: assign per-port queues
|
||||
for offloaded traffic
|
||||
|
||||
Keeps traffic sent to the switch within link speed limits
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
|
||||
@@ -445,6 +445,24 @@ static inline bool mtk_foe_entry_usable(
|
||||
FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND;
|
||||
}
|
||||
|
||||
+int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry,
|
||||
+ unsigned int queue)
|
||||
+{
|
||||
+ u32 *ib2 = mtk_foe_entry_ib2(eth, entry);
|
||||
+
|
||||
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
|
||||
+ *ib2 &= ~MTK_FOE_IB2_QID_V2;
|
||||
+ *ib2 |= FIELD_PREP(MTK_FOE_IB2_QID_V2, queue);
|
||||
+ *ib2 |= MTK_FOE_IB2_PSE_QOS_V2;
|
||||
+ } else {
|
||||
+ *ib2 &= ~MTK_FOE_IB2_QID;
|
||||
+ *ib2 |= FIELD_PREP(MTK_FOE_IB2_QID, queue);
|
||||
+ *ib2 |= MTK_FOE_IB2_PSE_QOS;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static bool
|
||||
mtk_flow_entry_match(struct mtk_eth *eth, struct mtk_flow_entry *entry,
|
||||
struct mtk_foe_entry *data)
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
|
||||
@@ -69,7 +69,9 @@ enum {
|
||||
#define MTK_FOE_IB2_DSCP GENMASK(31, 24)
|
||||
|
||||
/* CONFIG_MEDIATEK_NETSYS_V2 */
|
||||
+#define MTK_FOE_IB2_QID_V2 GENMASK(6, 0)
|
||||
#define MTK_FOE_IB2_PORT_MG_V2 BIT(7)
|
||||
+#define MTK_FOE_IB2_PSE_QOS_V2 BIT(8)
|
||||
#define MTK_FOE_IB2_DEST_PORT_V2 GENMASK(12, 9)
|
||||
#define MTK_FOE_IB2_MULTICAST_V2 BIT(13)
|
||||
#define MTK_FOE_IB2_WDMA_WINFO_V2 BIT(19)
|
||||
@@ -369,6 +371,8 @@ int mtk_foe_entry_set_pppoe(struct mtk_e
|
||||
int sid);
|
||||
int mtk_foe_entry_set_wdma(struct mtk_eth *eth, struct mtk_foe_entry *entry,
|
||||
int wdma_idx, int txq, int bss, int wcid);
|
||||
+int mtk_foe_entry_set_queue(struct mtk_eth *eth, struct mtk_foe_entry *entry,
|
||||
+ unsigned int queue);
|
||||
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);
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -188,7 +188,7 @@ mtk_flow_set_output_device(struct mtk_et
|
||||
int *wed_index)
|
||||
{
|
||||
struct mtk_wdma_info info = {};
|
||||
- int pse_port, dsa_port;
|
||||
+ int pse_port, dsa_port, queue;
|
||||
|
||||
if (mtk_flow_get_wdma_info(dev, dest_mac, &info) == 0) {
|
||||
mtk_foe_entry_set_wdma(eth, foe, info.wdma_idx, info.queue,
|
||||
@@ -212,8 +212,6 @@ mtk_flow_set_output_device(struct mtk_et
|
||||
}
|
||||
|
||||
dsa_port = mtk_flow_get_dsa_port(&dev);
|
||||
- if (dsa_port >= 0)
|
||||
- mtk_foe_entry_set_dsa(eth, foe, dsa_port);
|
||||
|
||||
if (dev == eth->netdev[0])
|
||||
pse_port = 1;
|
||||
@@ -222,6 +220,14 @@ mtk_flow_set_output_device(struct mtk_et
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
+ if (dsa_port >= 0) {
|
||||
+ mtk_foe_entry_set_dsa(eth, foe, dsa_port);
|
||||
+ queue = 3 + dsa_port;
|
||||
+ } else {
|
||||
+ queue = pse_port - 1;
|
||||
+ }
|
||||
+ mtk_foe_entry_set_queue(eth, foe, queue);
|
||||
+
|
||||
out:
|
||||
mtk_foe_entry_set_pse_port(eth, foe, pse_port);
|
||||
|
@ -0,0 +1,28 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 27 Oct 2022 23:39:52 +0200
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: compile out netsys v2 code
|
||||
on mt7621
|
||||
|
||||
Avoid some branches in the hot path on low-end devices with limited CPU power,
|
||||
and reduce code size
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -895,7 +895,13 @@ enum mkt_eth_capabilities {
|
||||
#define MTK_MUX_GMAC12_TO_GEPHY_SGMII \
|
||||
(MTK_ETH_MUX_GMAC12_TO_GEPHY_SGMII | MTK_MUX)
|
||||
|
||||
-#define MTK_HAS_CAPS(caps, _x) (((caps) & (_x)) == (_x))
|
||||
+#ifdef CONFIG_SOC_MT7621
|
||||
+#define MTK_CAP_MASK MTK_NETSYS_V2
|
||||
+#else
|
||||
+#define MTK_CAP_MASK 0
|
||||
+#endif
|
||||
+
|
||||
+#define MTK_HAS_CAPS(caps, _x) (((caps) & (_x) & ~(MTK_CAP_MASK)) == (_x))
|
||||
|
||||
#define MT7621_CAPS (MTK_GMAC1_RGMII | MTK_GMAC1_TRGMII | \
|
||||
MTK_GMAC2_RGMII | MTK_SHARED_INT | \
|
@ -0,0 +1,72 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Tue, 8 Nov 2022 15:03:15 +0100
|
||||
Subject: [PATCH] net: dsa: add support for DSA rx offloading via
|
||||
metadata dst
|
||||
|
||||
If a metadata dst is present with the type METADATA_HW_PORT_MUX on a dsa cpu
|
||||
port netdev, assume that it carries the port number and that there is no DSA
|
||||
tag present in the skb data.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/core/flow_dissector.c
|
||||
+++ b/net/core/flow_dissector.c
|
||||
@@ -940,12 +940,14 @@ bool __skb_flow_dissect(const struct net
|
||||
#if IS_ENABLED(CONFIG_NET_DSA)
|
||||
if (unlikely(skb->dev && netdev_uses_dsa(skb->dev) &&
|
||||
proto == htons(ETH_P_XDSA))) {
|
||||
+ struct metadata_dst *md_dst = skb_metadata_dst(skb);
|
||||
const struct dsa_device_ops *ops;
|
||||
int offset = 0;
|
||||
|
||||
ops = skb->dev->dsa_ptr->tag_ops;
|
||||
/* Only DSA header taggers break flow dissection */
|
||||
- if (ops->needed_headroom) {
|
||||
+ if (ops->needed_headroom &&
|
||||
+ (!md_dst || md_dst->type != METADATA_HW_PORT_MUX)) {
|
||||
if (ops->flow_dissect)
|
||||
ops->flow_dissect(skb, &proto, &offset);
|
||||
else
|
||||
--- a/net/dsa/dsa.c
|
||||
+++ b/net/dsa/dsa.c
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <linux/phy_fixed.h>
|
||||
#include <linux/ptp_classify.h>
|
||||
#include <linux/etherdevice.h>
|
||||
+#include <net/dst_metadata.h>
|
||||
|
||||
#include "dsa_priv.h"
|
||||
|
||||
@@ -225,6 +226,7 @@ static bool dsa_skb_defer_rx_timestamp(s
|
||||
static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *pt, struct net_device *unused)
|
||||
{
|
||||
+ struct metadata_dst *md_dst = skb_metadata_dst(skb);
|
||||
struct dsa_port *cpu_dp = dev->dsa_ptr;
|
||||
struct sk_buff *nskb = NULL;
|
||||
struct dsa_slave_priv *p;
|
||||
@@ -238,7 +240,22 @@ static int dsa_switch_rcv(struct sk_buff
|
||||
if (!skb)
|
||||
return 0;
|
||||
|
||||
- nskb = cpu_dp->rcv(skb, dev);
|
||||
+ if (md_dst && md_dst->type == METADATA_HW_PORT_MUX) {
|
||||
+ unsigned int port = md_dst->u.port_info.port_id;
|
||||
+
|
||||
+ skb_dst_drop(skb);
|
||||
+ if (!skb_has_extensions(skb))
|
||||
+ skb->slow_gro = 0;
|
||||
+
|
||||
+ skb->dev = dsa_master_find_slave(dev, 0, port);
|
||||
+ if (likely(skb->dev)) {
|
||||
+ dsa_default_offload_fwd_mark(skb);
|
||||
+ nskb = skb;
|
||||
+ }
|
||||
+ } else {
|
||||
+ nskb = cpu_dp->rcv(skb, dev);
|
||||
+ }
|
||||
+
|
||||
if (!nskb) {
|
||||
kfree_skb(skb);
|
||||
return 0;
|
@ -0,0 +1,192 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 28 Oct 2022 11:01:12 +0200
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: fix VLAN rx hardware
|
||||
acceleration
|
||||
|
||||
- enable VLAN untagging for PDMA rx
|
||||
- make it possible to disable the feature via ethtool
|
||||
- pass VLAN tag to the DSA driver
|
||||
- untag special tag on PDMA only if no non-DSA devices are in use
|
||||
- disable special tag untagging on 7986 for now, since it's not working yet
|
||||
|
||||
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
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <linux/jhash.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <net/dsa.h>
|
||||
+#include <net/dst_metadata.h>
|
||||
|
||||
#include "mtk_eth_soc.h"
|
||||
#include "mtk_wed.h"
|
||||
@@ -1967,16 +1968,22 @@ static int mtk_poll_rx(struct napi_struc
|
||||
htons(RX_DMA_VPID(trxd.rxd4)),
|
||||
RX_DMA_VID(trxd.rxd4));
|
||||
} else if (trxd.rxd2 & RX_DMA_VTAG) {
|
||||
- __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
|
||||
+ __vlan_hwaccel_put_tag(skb, htons(RX_DMA_VPID(trxd.rxd3)),
|
||||
RX_DMA_VID(trxd.rxd3));
|
||||
}
|
||||
+ }
|
||||
+
|
||||
+ /* When using VLAN untagging in combination with DSA, the
|
||||
+ * hardware treats the MTK special tag as a VLAN and untags it.
|
||||
+ */
|
||||
+ if (skb_vlan_tag_present(skb) && netdev_uses_dsa(netdev)) {
|
||||
+ unsigned int port = ntohs(skb->vlan_proto) & GENMASK(2, 0);
|
||||
|
||||
- /* If the device is attached to a dsa switch, the special
|
||||
- * tag inserted in VLAN field by hw switch can * be offloaded
|
||||
- * by RX HW VLAN offload. Clear vlan info.
|
||||
- */
|
||||
- if (netdev_uses_dsa(netdev))
|
||||
- __vlan_hwaccel_clear_tag(skb);
|
||||
+ if (port < ARRAY_SIZE(eth->dsa_meta) &&
|
||||
+ eth->dsa_meta[port])
|
||||
+ skb_dst_set_noref(skb, ð->dsa_meta[port]->dst);
|
||||
+
|
||||
+ __vlan_hwaccel_clear_tag(skb);
|
||||
}
|
||||
|
||||
skb_record_rx_queue(skb, 0);
|
||||
@@ -2793,15 +2800,30 @@ static netdev_features_t mtk_fix_feature
|
||||
|
||||
static int mtk_set_features(struct net_device *dev, netdev_features_t features)
|
||||
{
|
||||
- int err = 0;
|
||||
+ struct mtk_mac *mac = netdev_priv(dev);
|
||||
+ struct mtk_eth *eth = mac->hw;
|
||||
+ netdev_features_t diff = dev->features ^ features;
|
||||
+ int i;
|
||||
+
|
||||
+ if ((diff & NETIF_F_LRO) && !(features & NETIF_F_LRO))
|
||||
+ mtk_hwlro_netdev_disable(dev);
|
||||
|
||||
- if (!((dev->features ^ features) & NETIF_F_LRO))
|
||||
+ /* Set RX VLAN offloading */
|
||||
+ if (!(diff & NETIF_F_HW_VLAN_CTAG_RX))
|
||||
return 0;
|
||||
|
||||
- if (!(features & NETIF_F_LRO))
|
||||
- mtk_hwlro_netdev_disable(dev);
|
||||
+ mtk_w32(eth, !!(features & NETIF_F_HW_VLAN_CTAG_RX),
|
||||
+ MTK_CDMP_EG_CTRL);
|
||||
|
||||
- return err;
|
||||
+ /* sync features with other MAC */
|
||||
+ for (i = 0; i < MTK_MAC_COUNT; i++) {
|
||||
+ if (!eth->netdev[i] || eth->netdev[i] == dev)
|
||||
+ continue;
|
||||
+ eth->netdev[i]->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
|
||||
+ eth->netdev[i]->features |= features & NETIF_F_HW_VLAN_CTAG_RX;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/* wait for DMA to finish whatever it is doing before we start using it again */
|
||||
@@ -3083,11 +3105,45 @@ found:
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
+static bool mtk_uses_dsa(struct net_device *dev)
|
||||
+{
|
||||
+#if IS_ENABLED(CONFIG_NET_DSA)
|
||||
+ return netdev_uses_dsa(dev) &&
|
||||
+ dev->dsa_ptr->tag_ops->proto == DSA_TAG_PROTO_MTK;
|
||||
+#else
|
||||
+ return false;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
static int mtk_open(struct net_device *dev)
|
||||
{
|
||||
struct mtk_mac *mac = netdev_priv(dev);
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
- int err;
|
||||
+ int i, err;
|
||||
+
|
||||
+ if (mtk_uses_dsa(dev) && !eth->prog) {
|
||||
+ for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) {
|
||||
+ struct metadata_dst *md_dst = eth->dsa_meta[i];
|
||||
+
|
||||
+ if (md_dst)
|
||||
+ continue;
|
||||
+
|
||||
+ md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!md_dst)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ md_dst->u.port_info.port_id = i;
|
||||
+ eth->dsa_meta[i] = md_dst;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Hardware special tag parsing needs to be disabled if at least
|
||||
+ * one MAC does not use DSA.
|
||||
+ */
|
||||
+ u32 val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
|
||||
+ val &= ~MTK_CDMP_STAG_EN;
|
||||
+ mtk_w32(eth, val, MTK_CDMP_IG_CTRL);
|
||||
+ }
|
||||
|
||||
err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0);
|
||||
if (err) {
|
||||
@@ -3417,6 +3473,10 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
*/
|
||||
val = mtk_r32(eth, MTK_CDMQ_IG_CTRL);
|
||||
mtk_w32(eth, val | MTK_CDMQ_STAG_EN, MTK_CDMQ_IG_CTRL);
|
||||
+ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
|
||||
+ val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
|
||||
+ mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
|
||||
+ }
|
||||
|
||||
/* Enable RX VLan Offloading */
|
||||
mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
|
||||
@@ -3634,6 +3694,12 @@ static int mtk_free_dev(struct mtk_eth *
|
||||
free_netdev(eth->netdev[i]);
|
||||
}
|
||||
|
||||
+ for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) {
|
||||
+ if (!eth->dsa_meta[i])
|
||||
+ break;
|
||||
+ metadata_dst_free(eth->dsa_meta[i]);
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -22,6 +22,9 @@
|
||||
#include <linux/bpf_trace.h>
|
||||
#include "mtk_ppe.h"
|
||||
|
||||
+#define MTK_MAX_DSA_PORTS 7
|
||||
+#define MTK_DSA_PORT_MASK GENMASK(2, 0)
|
||||
+
|
||||
#define MTK_QDMA_NUM_QUEUES 16
|
||||
#define MTK_QDMA_PAGE_SIZE 2048
|
||||
#define MTK_MAX_RX_LENGTH 1536
|
||||
@@ -93,6 +96,9 @@
|
||||
#define MTK_CDMQ_IG_CTRL 0x1400
|
||||
#define MTK_CDMQ_STAG_EN BIT(0)
|
||||
|
||||
+/* CDMQ Exgress Control Register */
|
||||
+#define MTK_CDMQ_EG_CTRL 0x1404
|
||||
+
|
||||
/* CDMP Ingress Control Register */
|
||||
#define MTK_CDMP_IG_CTRL 0x400
|
||||
#define MTK_CDMP_STAG_EN BIT(0)
|
||||
@@ -1140,6 +1146,8 @@ struct mtk_eth {
|
||||
|
||||
int ip_align;
|
||||
|
||||
+ struct metadata_dst *dsa_meta[MTK_MAX_DSA_PORTS];
|
||||
+
|
||||
struct mtk_ppe *ppe[2];
|
||||
struct rhashtable flow_table;
|
||||
|
@ -0,0 +1,78 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 3 Nov 2022 12:38:49 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: work around issue with
|
||||
sending small fragments
|
||||
|
||||
When frames are sent with very small fragments, the DMA engine appears to
|
||||
lock up and transmit attempts time out. Fix this by detecting the presence
|
||||
of small fragments and use skb_gso_segment + skb_linearize to deal with
|
||||
them
|
||||
|
||||
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
|
||||
@@ -1396,12 +1396,28 @@ static void mtk_wake_queue(struct mtk_et
|
||||
}
|
||||
}
|
||||
|
||||
+static bool mtk_skb_has_small_frag(struct sk_buff *skb)
|
||||
+{
|
||||
+ int min_size = 16;
|
||||
+ int i;
|
||||
+
|
||||
+ if (skb_headlen(skb) < min_size)
|
||||
+ return true;
|
||||
+
|
||||
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
|
||||
+ if (skb_frag_size(&skb_shinfo(skb)->frags[i]) < min_size)
|
||||
+ return true;
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
static netdev_tx_t mtk_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct mtk_mac *mac = netdev_priv(dev);
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
struct mtk_tx_ring *ring = ð->tx_ring;
|
||||
struct net_device_stats *stats = &dev->stats;
|
||||
+ struct sk_buff *segs, *next;
|
||||
bool gso = false;
|
||||
int tx_num;
|
||||
|
||||
@@ -1423,6 +1439,17 @@ static netdev_tx_t mtk_start_xmit(struct
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
+ if (skb_is_gso(skb) && mtk_skb_has_small_frag(skb)) {
|
||||
+ segs = skb_gso_segment(skb, dev->features & ~NETIF_F_ALL_TSO);
|
||||
+ if (IS_ERR(segs))
|
||||
+ goto drop;
|
||||
+
|
||||
+ if (segs) {
|
||||
+ consume_skb(skb);
|
||||
+ skb = segs;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* TSO: fill MSS info in tcp checksum field */
|
||||
if (skb_is_gso(skb)) {
|
||||
if (skb_cow_head(skb, 0)) {
|
||||
@@ -1438,8 +1465,13 @@ static netdev_tx_t mtk_start_xmit(struct
|
||||
}
|
||||
}
|
||||
|
||||
- if (mtk_tx_map(skb, dev, tx_num, ring, gso) < 0)
|
||||
- goto drop;
|
||||
+ skb_list_walk_safe(skb, skb, next) {
|
||||
+ if ((mtk_skb_has_small_frag(skb) && skb_linearize(skb)) ||
|
||||
+ mtk_tx_map(skb, dev, tx_num, ring, gso) < 0) {
|
||||
+ stats->tx_dropped++;
|
||||
+ dev_kfree_skb_any(skb);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
if (unlikely(atomic_read(&ring->free_count) <= ring->thresh))
|
||||
netif_tx_stop_all_queues(dev);
|
@ -0,0 +1,21 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 28 Oct 2022 12:54:48 +0200
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: set NETIF_F_ALL_TSO
|
||||
|
||||
Significantly improves performance by avoiding unnecessary segmentation
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -49,8 +49,7 @@
|
||||
NETIF_F_RXCSUM | \
|
||||
NETIF_F_HW_VLAN_CTAG_TX | \
|
||||
NETIF_F_HW_VLAN_CTAG_RX | \
|
||||
- NETIF_F_SG | NETIF_F_TSO | \
|
||||
- NETIF_F_TSO6 | \
|
||||
+ NETIF_F_SG | NETIF_F_ALL_TSO | \
|
||||
NETIF_F_IPV6_CSUM |\
|
||||
NETIF_F_HW_TC)
|
||||
#define MTK_HW_FEATURES_MT7628 (NETIF_F_SG | NETIF_F_RXCSUM)
|
@ -0,0 +1,37 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 3 Nov 2022 17:46:25 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: drop packets to WDMA if the
|
||||
ring is full
|
||||
|
||||
Improves handling of DMA ring overflow.
|
||||
Clarify other WDMA drop related comment.
|
||||
|
||||
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
|
||||
@@ -3529,9 +3529,12 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
mtk_w32(eth, 0x21021000, MTK_FE_INT_GRP);
|
||||
|
||||
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
|
||||
- /* PSE should not drop port8 and port9 packets */
|
||||
+ /* PSE should not drop port8 and port9 packets from WDMA Tx */
|
||||
mtk_w32(eth, 0x00000300, PSE_DROP_CFG);
|
||||
|
||||
+ /* PSE should drop packets to port 8/9 on WDMA Rx ring full */
|
||||
+ mtk_w32(eth, 0x00000300, PSE_PPE0_DROP);
|
||||
+
|
||||
/* PSE Free Queue Flow Control */
|
||||
mtk_w32(eth, 0x01fa01f4, PSE_FQFC_CFG2);
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -127,6 +127,7 @@
|
||||
#define PSE_FQFC_CFG1 0x100
|
||||
#define PSE_FQFC_CFG2 0x104
|
||||
#define PSE_DROP_CFG 0x108
|
||||
+#define PSE_PPE0_DROP 0x110
|
||||
|
||||
/* PSE Input Queue Reservation Register*/
|
||||
#define PSE_IQ_REV(x) (0x140 + (((x) - 1) << 2))
|
@ -0,0 +1,52 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 17 Nov 2022 11:58:21 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: fix flow_offload related refcount
|
||||
bug
|
||||
|
||||
Since we call flow_block_cb_decref on FLOW_BLOCK_UNBIND, we need to call
|
||||
flow_block_cb_incref unconditionally, even for a newly allocated cb.
|
||||
Fixes a use-after-free bug
|
||||
|
||||
Fixes: 502e84e2382d ("net: ethernet: mtk_eth_soc: add flow offloading support")
|
||||
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
|
||||
@@ -561,6 +561,7 @@ mtk_eth_setup_tc_block(struct net_device
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
static LIST_HEAD(block_cb_list);
|
||||
struct flow_block_cb *block_cb;
|
||||
+ bool register_block = false;
|
||||
flow_setup_cb_t *cb;
|
||||
|
||||
if (!eth->soc->offload_version)
|
||||
@@ -575,16 +576,20 @@ mtk_eth_setup_tc_block(struct net_device
|
||||
switch (f->command) {
|
||||
case FLOW_BLOCK_BIND:
|
||||
block_cb = flow_block_cb_lookup(f->block, cb, dev);
|
||||
- if (block_cb) {
|
||||
- flow_block_cb_incref(block_cb);
|
||||
- return 0;
|
||||
+ if (!block_cb) {
|
||||
+ block_cb = flow_block_cb_alloc(cb, dev, dev, NULL);
|
||||
+ if (IS_ERR(block_cb))
|
||||
+ return PTR_ERR(block_cb);
|
||||
+
|
||||
+ register_block = true;
|
||||
}
|
||||
- block_cb = flow_block_cb_alloc(cb, dev, dev, NULL);
|
||||
- if (IS_ERR(block_cb))
|
||||
- return PTR_ERR(block_cb);
|
||||
|
||||
- flow_block_cb_add(block_cb, f);
|
||||
- list_add_tail(&block_cb->driver_list, &block_cb_list);
|
||||
+ flow_block_cb_incref(block_cb);
|
||||
+
|
||||
+ if (register_block) {
|
||||
+ flow_block_cb_add(block_cb, f);
|
||||
+ list_add_tail(&block_cb->driver_list, &block_cb_list);
|
||||
+ }
|
||||
return 0;
|
||||
case FLOW_BLOCK_UNBIND:
|
||||
block_cb = flow_block_cb_lookup(f->block, cb, dev);
|
@ -0,0 +1,181 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sun, 20 Nov 2022 23:01:00 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: drop generic vlan rx offload,
|
||||
only use DSA untagging
|
||||
|
||||
Through testing I found out that hardware vlan rx offload support seems to
|
||||
have some hardware issues. At least when using multiple MACs and when receiving
|
||||
tagged packets on the secondary MAC, the hardware can sometimes start to emit
|
||||
wrong tags on the first MAC as well.
|
||||
|
||||
In order to avoid such issues, drop the feature configuration and use the
|
||||
offload feature only for DSA hardware untagging on MT7621/MT7622 devices which
|
||||
only use one MAC.
|
||||
|
||||
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
|
||||
@@ -1993,29 +1993,16 @@ static int mtk_poll_rx(struct napi_struc
|
||||
if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
|
||||
mtk_ppe_check_skb(eth->ppe[0], skb, hash);
|
||||
|
||||
- if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
|
||||
- if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
|
||||
- if (trxd.rxd3 & RX_DMA_VTAG_V2)
|
||||
- __vlan_hwaccel_put_tag(skb,
|
||||
- htons(RX_DMA_VPID(trxd.rxd4)),
|
||||
- RX_DMA_VID(trxd.rxd4));
|
||||
- } else if (trxd.rxd2 & RX_DMA_VTAG) {
|
||||
- __vlan_hwaccel_put_tag(skb, htons(RX_DMA_VPID(trxd.rxd3)),
|
||||
- RX_DMA_VID(trxd.rxd3));
|
||||
- }
|
||||
- }
|
||||
-
|
||||
/* When using VLAN untagging in combination with DSA, the
|
||||
* hardware treats the MTK special tag as a VLAN and untags it.
|
||||
*/
|
||||
- if (skb_vlan_tag_present(skb) && netdev_uses_dsa(netdev)) {
|
||||
- unsigned int port = ntohs(skb->vlan_proto) & GENMASK(2, 0);
|
||||
+ if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2) &&
|
||||
+ (trxd.rxd2 & RX_DMA_VTAG) && netdev_uses_dsa(netdev)) {
|
||||
+ unsigned int port = RX_DMA_VPID(trxd.rxd3) & GENMASK(2, 0);
|
||||
|
||||
if (port < ARRAY_SIZE(eth->dsa_meta) &&
|
||||
eth->dsa_meta[port])
|
||||
skb_dst_set_noref(skb, ð->dsa_meta[port]->dst);
|
||||
-
|
||||
- __vlan_hwaccel_clear_tag(skb);
|
||||
}
|
||||
|
||||
skb_record_rx_queue(skb, 0);
|
||||
@@ -2832,29 +2819,11 @@ static netdev_features_t mtk_fix_feature
|
||||
|
||||
static int mtk_set_features(struct net_device *dev, netdev_features_t features)
|
||||
{
|
||||
- struct mtk_mac *mac = netdev_priv(dev);
|
||||
- struct mtk_eth *eth = mac->hw;
|
||||
netdev_features_t diff = dev->features ^ features;
|
||||
- int i;
|
||||
|
||||
if ((diff & NETIF_F_LRO) && !(features & NETIF_F_LRO))
|
||||
mtk_hwlro_netdev_disable(dev);
|
||||
|
||||
- /* Set RX VLAN offloading */
|
||||
- if (!(diff & NETIF_F_HW_VLAN_CTAG_RX))
|
||||
- return 0;
|
||||
-
|
||||
- mtk_w32(eth, !!(features & NETIF_F_HW_VLAN_CTAG_RX),
|
||||
- MTK_CDMP_EG_CTRL);
|
||||
-
|
||||
- /* sync features with other MAC */
|
||||
- for (i = 0; i < MTK_MAC_COUNT; i++) {
|
||||
- if (!eth->netdev[i] || eth->netdev[i] == dev)
|
||||
- continue;
|
||||
- eth->netdev[i]->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
|
||||
- eth->netdev[i]->features |= features & NETIF_F_HW_VLAN_CTAG_RX;
|
||||
- }
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3153,30 +3122,6 @@ static int mtk_open(struct net_device *d
|
||||
struct mtk_eth *eth = mac->hw;
|
||||
int i, err;
|
||||
|
||||
- if (mtk_uses_dsa(dev) && !eth->prog) {
|
||||
- for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) {
|
||||
- struct metadata_dst *md_dst = eth->dsa_meta[i];
|
||||
-
|
||||
- if (md_dst)
|
||||
- continue;
|
||||
-
|
||||
- md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX,
|
||||
- GFP_KERNEL);
|
||||
- if (!md_dst)
|
||||
- return -ENOMEM;
|
||||
-
|
||||
- md_dst->u.port_info.port_id = i;
|
||||
- eth->dsa_meta[i] = md_dst;
|
||||
- }
|
||||
- } else {
|
||||
- /* Hardware special tag parsing needs to be disabled if at least
|
||||
- * one MAC does not use DSA.
|
||||
- */
|
||||
- u32 val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
|
||||
- val &= ~MTK_CDMP_STAG_EN;
|
||||
- mtk_w32(eth, val, MTK_CDMP_IG_CTRL);
|
||||
- }
|
||||
-
|
||||
err = phylink_of_phy_connect(mac->phylink, mac->of_node, 0);
|
||||
if (err) {
|
||||
netdev_err(dev, "%s: could not attach PHY: %d\n", __func__,
|
||||
@@ -3215,6 +3160,35 @@ static int mtk_open(struct net_device *d
|
||||
phylink_start(mac->phylink);
|
||||
netif_tx_start_all_queues(dev);
|
||||
|
||||
+ if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (mtk_uses_dsa(dev) && !eth->prog) {
|
||||
+ for (i = 0; i < ARRAY_SIZE(eth->dsa_meta); i++) {
|
||||
+ struct metadata_dst *md_dst = eth->dsa_meta[i];
|
||||
+
|
||||
+ if (md_dst)
|
||||
+ continue;
|
||||
+
|
||||
+ md_dst = metadata_dst_alloc(0, METADATA_HW_PORT_MUX,
|
||||
+ GFP_KERNEL);
|
||||
+ if (!md_dst)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ md_dst->u.port_info.port_id = i;
|
||||
+ eth->dsa_meta[i] = md_dst;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Hardware special tag parsing needs to be disabled if at least
|
||||
+ * one MAC does not use DSA.
|
||||
+ */
|
||||
+ u32 val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
|
||||
+ val &= ~MTK_CDMP_STAG_EN;
|
||||
+ mtk_w32(eth, val, MTK_CDMP_IG_CTRL);
|
||||
+
|
||||
+ mtk_w32(eth, 0, MTK_CDMP_EG_CTRL);
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3508,10 +3482,9 @@ static int mtk_hw_init(struct mtk_eth *e
|
||||
if (!MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2)) {
|
||||
val = mtk_r32(eth, MTK_CDMP_IG_CTRL);
|
||||
mtk_w32(eth, val | MTK_CDMP_STAG_EN, MTK_CDMP_IG_CTRL);
|
||||
- }
|
||||
|
||||
- /* Enable RX VLan Offloading */
|
||||
- mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
|
||||
+ mtk_w32(eth, 1, MTK_CDMP_EG_CTRL);
|
||||
+ }
|
||||
|
||||
/* set interrupt delays based on current Net DIM sample */
|
||||
mtk_dim_rx(ð->rx_dim.work);
|
||||
@@ -4132,7 +4105,7 @@ static int mtk_add_mac(struct mtk_eth *e
|
||||
eth->netdev[id]->hw_features |= NETIF_F_LRO;
|
||||
|
||||
eth->netdev[id]->vlan_features = eth->soc->hw_features &
|
||||
- ~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX);
|
||||
+ ~NETIF_F_HW_VLAN_CTAG_TX;
|
||||
eth->netdev[id]->features |= eth->soc->hw_features;
|
||||
eth->netdev[id]->ethtool_ops = &mtk_ethtool_ops;
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
|
||||
@@ -48,7 +48,6 @@
|
||||
#define MTK_HW_FEATURES (NETIF_F_IP_CSUM | \
|
||||
NETIF_F_RXCSUM | \
|
||||
NETIF_F_HW_VLAN_CTAG_TX | \
|
||||
- NETIF_F_HW_VLAN_CTAG_RX | \
|
||||
NETIF_F_SG | NETIF_F_ALL_TSO | \
|
||||
NETIF_F_IPV6_CSUM |\
|
||||
NETIF_F_HW_TC)
|
@ -0,0 +1,591 @@
|
||||
From: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
Date: Sat, 5 Nov 2022 23:36:18 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_wed: introduce wed mcu support
|
||||
|
||||
Introduce WED mcu support used to configure WED WO chip.
|
||||
This is a preliminary patch in order to add RX Wireless
|
||||
Ethernet Dispatch available on MT7986 SoC.
|
||||
|
||||
Tested-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_mcu.c
|
||||
create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_wo.h
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/Makefile
|
||||
+++ b/drivers/net/ethernet/mediatek/Makefile
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
|
||||
mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o
|
||||
-mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o
|
||||
+mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o
|
||||
ifdef CONFIG_DEBUG_FS
|
||||
mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o
|
||||
endif
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
|
||||
@@ -0,0 +1,359 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+/* Copyright (C) 2022 MediaTek Inc.
|
||||
+ *
|
||||
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
+ * Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/firmware.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/of_reserved_mem.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/soc/mediatek/mtk_wed.h>
|
||||
+
|
||||
+#include "mtk_wed_regs.h"
|
||||
+#include "mtk_wed_wo.h"
|
||||
+#include "mtk_wed.h"
|
||||
+
|
||||
+static u32 wo_r32(struct mtk_wed_wo *wo, u32 reg)
|
||||
+{
|
||||
+ return readl(wo->boot.addr + reg);
|
||||
+}
|
||||
+
|
||||
+static void wo_w32(struct mtk_wed_wo *wo, u32 reg, u32 val)
|
||||
+{
|
||||
+ writel(val, wo->boot.addr + reg);
|
||||
+}
|
||||
+
|
||||
+static struct sk_buff *
|
||||
+mtk_wed_mcu_msg_alloc(const void *data, int data_len)
|
||||
+{
|
||||
+ int length = sizeof(struct mtk_wed_mcu_hdr) + data_len;
|
||||
+ struct sk_buff *skb;
|
||||
+
|
||||
+ skb = alloc_skb(length, GFP_KERNEL);
|
||||
+ if (!skb)
|
||||
+ return NULL;
|
||||
+
|
||||
+ memset(skb->head, 0, length);
|
||||
+ skb_reserve(skb, sizeof(struct mtk_wed_mcu_hdr));
|
||||
+ if (data && data_len)
|
||||
+ skb_put_data(skb, data, data_len);
|
||||
+
|
||||
+ return skb;
|
||||
+}
|
||||
+
|
||||
+static struct sk_buff *
|
||||
+mtk_wed_mcu_get_response(struct mtk_wed_wo *wo, unsigned long expires)
|
||||
+{
|
||||
+ if (!time_is_after_jiffies(expires))
|
||||
+ return NULL;
|
||||
+
|
||||
+ wait_event_timeout(wo->mcu.wait, !skb_queue_empty(&wo->mcu.res_q),
|
||||
+ expires - jiffies);
|
||||
+ return skb_dequeue(&wo->mcu.res_q);
|
||||
+}
|
||||
+
|
||||
+void mtk_wed_mcu_rx_event(struct mtk_wed_wo *wo, struct sk_buff *skb)
|
||||
+{
|
||||
+ skb_queue_tail(&wo->mcu.res_q, skb);
|
||||
+ wake_up(&wo->mcu.wait);
|
||||
+}
|
||||
+
|
||||
+void mtk_wed_mcu_rx_unsolicited_event(struct mtk_wed_wo *wo,
|
||||
+ struct sk_buff *skb)
|
||||
+{
|
||||
+ struct mtk_wed_mcu_hdr *hdr = (struct mtk_wed_mcu_hdr *)skb->data;
|
||||
+
|
||||
+ switch (hdr->cmd) {
|
||||
+ case MTK_WED_WO_EVT_LOG_DUMP: {
|
||||
+ const char *msg = (const char *)(skb->data + sizeof(*hdr));
|
||||
+
|
||||
+ dev_notice(wo->hw->dev, "%s\n", msg);
|
||||
+ break;
|
||||
+ }
|
||||
+ case MTK_WED_WO_EVT_PROFILING: {
|
||||
+ struct mtk_wed_wo_log_info *info;
|
||||
+ u32 count = (skb->len - sizeof(*hdr)) / sizeof(*info);
|
||||
+ int i;
|
||||
+
|
||||
+ info = (struct mtk_wed_wo_log_info *)(skb->data + sizeof(*hdr));
|
||||
+ for (i = 0 ; i < count ; i++)
|
||||
+ dev_notice(wo->hw->dev,
|
||||
+ "SN:%u latency: total=%u, rro:%u, mod:%u\n",
|
||||
+ le32_to_cpu(info[i].sn),
|
||||
+ le32_to_cpu(info[i].total),
|
||||
+ le32_to_cpu(info[i].rro),
|
||||
+ le32_to_cpu(info[i].mod));
|
||||
+ break;
|
||||
+ }
|
||||
+ case MTK_WED_WO_EVT_RXCNT_INFO:
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ dev_kfree_skb(skb);
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mtk_wed_mcu_skb_send_msg(struct mtk_wed_wo *wo, struct sk_buff *skb,
|
||||
+ int id, int cmd, u16 *wait_seq, bool wait_resp)
|
||||
+{
|
||||
+ struct mtk_wed_mcu_hdr *hdr;
|
||||
+
|
||||
+ /* TODO: make it dynamic based on cmd */
|
||||
+ wo->mcu.timeout = 20 * HZ;
|
||||
+
|
||||
+ hdr = (struct mtk_wed_mcu_hdr *)skb_push(skb, sizeof(*hdr));
|
||||
+ hdr->cmd = cmd;
|
||||
+ hdr->length = cpu_to_le16(skb->len);
|
||||
+
|
||||
+ if (wait_resp && wait_seq) {
|
||||
+ u16 seq = ++wo->mcu.seq;
|
||||
+
|
||||
+ if (!seq)
|
||||
+ seq = ++wo->mcu.seq;
|
||||
+ *wait_seq = seq;
|
||||
+
|
||||
+ hdr->flag |= cpu_to_le16(MTK_WED_WARP_CMD_FLAG_NEED_RSP);
|
||||
+ hdr->seq = cpu_to_le16(seq);
|
||||
+ }
|
||||
+ if (id == MTK_WED_MODULE_ID_WO)
|
||||
+ hdr->flag |= cpu_to_le16(MTK_WED_WARP_CMD_FLAG_FROM_TO_WO);
|
||||
+
|
||||
+ dev_kfree_skb(skb);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mtk_wed_mcu_parse_response(struct mtk_wed_wo *wo, struct sk_buff *skb,
|
||||
+ int cmd, int seq)
|
||||
+{
|
||||
+ struct mtk_wed_mcu_hdr *hdr;
|
||||
+
|
||||
+ if (!skb) {
|
||||
+ dev_err(wo->hw->dev, "Message %08x (seq %d) timeout\n",
|
||||
+ cmd, seq);
|
||||
+ return -ETIMEDOUT;
|
||||
+ }
|
||||
+
|
||||
+ hdr = (struct mtk_wed_mcu_hdr *)skb->data;
|
||||
+ if (le16_to_cpu(hdr->seq) != seq)
|
||||
+ return -EAGAIN;
|
||||
+
|
||||
+ skb_pull(skb, sizeof(*hdr));
|
||||
+ switch (cmd) {
|
||||
+ case MTK_WED_WO_CMD_RXCNT_INFO:
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int mtk_wed_mcu_send_msg(struct mtk_wed_wo *wo, int id, int cmd,
|
||||
+ const void *data, int len, bool wait_resp)
|
||||
+{
|
||||
+ unsigned long expires;
|
||||
+ struct sk_buff *skb;
|
||||
+ u16 seq;
|
||||
+ int ret;
|
||||
+
|
||||
+ skb = mtk_wed_mcu_msg_alloc(data, len);
|
||||
+ if (!skb)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mutex_lock(&wo->mcu.mutex);
|
||||
+
|
||||
+ ret = mtk_wed_mcu_skb_send_msg(wo, skb, id, cmd, &seq, wait_resp);
|
||||
+ if (ret || !wait_resp)
|
||||
+ goto unlock;
|
||||
+
|
||||
+ expires = jiffies + wo->mcu.timeout;
|
||||
+ do {
|
||||
+ skb = mtk_wed_mcu_get_response(wo, expires);
|
||||
+ ret = mtk_wed_mcu_parse_response(wo, skb, cmd, seq);
|
||||
+ dev_kfree_skb(skb);
|
||||
+ } while (ret == -EAGAIN);
|
||||
+
|
||||
+unlock:
|
||||
+ mutex_unlock(&wo->mcu.mutex);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mtk_wed_get_memory_region(struct mtk_wed_wo *wo,
|
||||
+ struct mtk_wed_wo_memory_region *region)
|
||||
+{
|
||||
+ struct reserved_mem *rmem;
|
||||
+ struct device_node *np;
|
||||
+ int index;
|
||||
+
|
||||
+ index = of_property_match_string(wo->hw->node, "memory-region-names",
|
||||
+ region->name);
|
||||
+ if (index < 0)
|
||||
+ return index;
|
||||
+
|
||||
+ np = of_parse_phandle(wo->hw->node, "memory-region", index);
|
||||
+ if (!np)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ rmem = of_reserved_mem_lookup(np);
|
||||
+ of_node_put(np);
|
||||
+
|
||||
+ if (!rmem)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ region->phy_addr = rmem->base;
|
||||
+ region->size = rmem->size;
|
||||
+ region->addr = devm_ioremap(wo->hw->dev, region->phy_addr, region->size);
|
||||
+
|
||||
+ return !region->addr ? -EINVAL : 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mtk_wed_mcu_run_firmware(struct mtk_wed_wo *wo, const struct firmware *fw,
|
||||
+ struct mtk_wed_wo_memory_region *region)
|
||||
+{
|
||||
+ const u8 *first_region_ptr, *region_ptr, *trailer_ptr, *ptr = fw->data;
|
||||
+ const struct mtk_wed_fw_trailer *trailer;
|
||||
+ const struct mtk_wed_fw_region *fw_region;
|
||||
+
|
||||
+ trailer_ptr = fw->data + fw->size - sizeof(*trailer);
|
||||
+ trailer = (const struct mtk_wed_fw_trailer *)trailer_ptr;
|
||||
+ region_ptr = trailer_ptr - trailer->num_region * sizeof(*fw_region);
|
||||
+ first_region_ptr = region_ptr;
|
||||
+
|
||||
+ while (region_ptr < trailer_ptr) {
|
||||
+ u32 length;
|
||||
+
|
||||
+ fw_region = (const struct mtk_wed_fw_region *)region_ptr;
|
||||
+ length = le32_to_cpu(fw_region->len);
|
||||
+
|
||||
+ if (region->phy_addr != le32_to_cpu(fw_region->addr))
|
||||
+ goto next;
|
||||
+
|
||||
+ if (region->size < length)
|
||||
+ goto next;
|
||||
+
|
||||
+ if (first_region_ptr < ptr + length)
|
||||
+ goto next;
|
||||
+
|
||||
+ if (region->shared && region->consumed)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (!region->shared || !region->consumed) {
|
||||
+ memcpy_toio(region->addr, ptr, length);
|
||||
+ region->consumed = true;
|
||||
+ return 0;
|
||||
+ }
|
||||
+next:
|
||||
+ region_ptr += sizeof(*fw_region);
|
||||
+ ptr += length;
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mtk_wed_mcu_load_firmware(struct mtk_wed_wo *wo)
|
||||
+{
|
||||
+ static struct mtk_wed_wo_memory_region mem_region[] = {
|
||||
+ [MTK_WED_WO_REGION_EMI] = {
|
||||
+ .name = "wo-emi",
|
||||
+ },
|
||||
+ [MTK_WED_WO_REGION_ILM] = {
|
||||
+ .name = "wo-ilm",
|
||||
+ },
|
||||
+ [MTK_WED_WO_REGION_DATA] = {
|
||||
+ .name = "wo-data",
|
||||
+ .shared = true,
|
||||
+ },
|
||||
+ };
|
||||
+ const struct mtk_wed_fw_trailer *trailer;
|
||||
+ const struct firmware *fw;
|
||||
+ const char *fw_name;
|
||||
+ u32 val, boot_cr;
|
||||
+ int ret, i;
|
||||
+
|
||||
+ /* load firmware region metadata */
|
||||
+ for (i = 0; i < ARRAY_SIZE(mem_region); i++) {
|
||||
+ ret = mtk_wed_get_memory_region(wo, &mem_region[i]);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ wo->boot.name = "wo-boot";
|
||||
+ ret = mtk_wed_get_memory_region(wo, &wo->boot);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* set dummy cr */
|
||||
+ wed_w32(wo->hw->wed_dev, MTK_WED_SCR0 + 4 * MTK_WED_DUMMY_CR_FWDL,
|
||||
+ wo->hw->index + 1);
|
||||
+
|
||||
+ /* load firmware */
|
||||
+ fw_name = wo->hw->index ? MT7986_FIRMWARE_WO1 : MT7986_FIRMWARE_WO0;
|
||||
+ ret = request_firmware(&fw, fw_name, wo->hw->dev);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ trailer = (void *)(fw->data + fw->size -
|
||||
+ sizeof(struct mtk_wed_fw_trailer));
|
||||
+ dev_info(wo->hw->dev,
|
||||
+ "MTK WED WO Firmware Version: %.10s, Build Time: %.15s\n",
|
||||
+ trailer->fw_ver, trailer->build_date);
|
||||
+ dev_info(wo->hw->dev, "MTK WED WO Chip ID %02x Region %d\n",
|
||||
+ trailer->chip_id, trailer->num_region);
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(mem_region); i++) {
|
||||
+ ret = mtk_wed_mcu_run_firmware(wo, fw, &mem_region[i]);
|
||||
+ if (ret)
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ /* set the start address */
|
||||
+ boot_cr = wo->hw->index ? MTK_WO_MCU_CFG_LS_WA_BOOT_ADDR_ADDR
|
||||
+ : MTK_WO_MCU_CFG_LS_WM_BOOT_ADDR_ADDR;
|
||||
+ wo_w32(wo, boot_cr, mem_region[MTK_WED_WO_REGION_EMI].phy_addr >> 16);
|
||||
+ /* wo firmware reset */
|
||||
+ wo_w32(wo, MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR, 0xc00);
|
||||
+
|
||||
+ val = wo_r32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR);
|
||||
+ val |= wo->hw->index ? MTK_WO_MCU_CFG_LS_WF_WM_WA_WA_CPU_RSTB_MASK
|
||||
+ : MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK;
|
||||
+ wo_w32(wo, MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR, val);
|
||||
+out:
|
||||
+ release_firmware(fw);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static u32
|
||||
+mtk_wed_mcu_read_fw_dl(struct mtk_wed_wo *wo)
|
||||
+{
|
||||
+ return wed_r32(wo->hw->wed_dev,
|
||||
+ MTK_WED_SCR0 + 4 * MTK_WED_DUMMY_CR_FWDL);
|
||||
+}
|
||||
+
|
||||
+int mtk_wed_mcu_init(struct mtk_wed_wo *wo)
|
||||
+{
|
||||
+ u32 val;
|
||||
+ int ret;
|
||||
+
|
||||
+ skb_queue_head_init(&wo->mcu.res_q);
|
||||
+ init_waitqueue_head(&wo->mcu.wait);
|
||||
+ mutex_init(&wo->mcu.mutex);
|
||||
+
|
||||
+ ret = mtk_wed_mcu_load_firmware(wo);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return readx_poll_timeout(mtk_wed_mcu_read_fw_dl, wo, val, !val,
|
||||
+ 100, MTK_FW_DL_TIMEOUT);
|
||||
+}
|
||||
+
|
||||
+MODULE_FIRMWARE(MT7986_FIRMWARE_WO0);
|
||||
+MODULE_FIRMWARE(MT7986_FIRMWARE_WO1);
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
|
||||
@@ -152,6 +152,7 @@ struct mtk_wdma_desc {
|
||||
|
||||
#define MTK_WED_RING_RX(_n) (0x400 + (_n) * 0x10)
|
||||
|
||||
+#define MTK_WED_SCR0 0x3c0
|
||||
#define MTK_WED_WPDMA_INT_TRIGGER 0x504
|
||||
#define MTK_WED_WPDMA_INT_TRIGGER_RX_DONE BIT(1)
|
||||
#define MTK_WED_WPDMA_INT_TRIGGER_TX_DONE GENMASK(5, 4)
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
|
||||
@@ -0,0 +1,150 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
+/* Copyright (C) 2022 Lorenzo Bianconi <lorenzo@kernel.org> */
|
||||
+
|
||||
+#ifndef __MTK_WED_WO_H
|
||||
+#define __MTK_WED_WO_H
|
||||
+
|
||||
+#include <linux/skbuff.h>
|
||||
+#include <linux/netdevice.h>
|
||||
+
|
||||
+struct mtk_wed_hw;
|
||||
+
|
||||
+struct mtk_wed_mcu_hdr {
|
||||
+ /* DW0 */
|
||||
+ u8 version;
|
||||
+ u8 cmd;
|
||||
+ __le16 length;
|
||||
+
|
||||
+ /* DW1 */
|
||||
+ __le16 seq;
|
||||
+ __le16 flag;
|
||||
+
|
||||
+ /* DW2 */
|
||||
+ __le32 status;
|
||||
+
|
||||
+ /* DW3 */
|
||||
+ u8 rsv[20];
|
||||
+};
|
||||
+
|
||||
+struct mtk_wed_wo_log_info {
|
||||
+ __le32 sn;
|
||||
+ __le32 total;
|
||||
+ __le32 rro;
|
||||
+ __le32 mod;
|
||||
+};
|
||||
+
|
||||
+enum mtk_wed_wo_event {
|
||||
+ MTK_WED_WO_EVT_LOG_DUMP = 0x1,
|
||||
+ MTK_WED_WO_EVT_PROFILING = 0x2,
|
||||
+ MTK_WED_WO_EVT_RXCNT_INFO = 0x3,
|
||||
+};
|
||||
+
|
||||
+#define MTK_WED_MODULE_ID_WO 1
|
||||
+#define MTK_FW_DL_TIMEOUT 4000000 /* us */
|
||||
+#define MTK_WOCPU_TIMEOUT 2000000 /* us */
|
||||
+
|
||||
+enum {
|
||||
+ MTK_WED_WARP_CMD_FLAG_RSP = BIT(0),
|
||||
+ MTK_WED_WARP_CMD_FLAG_NEED_RSP = BIT(1),
|
||||
+ MTK_WED_WARP_CMD_FLAG_FROM_TO_WO = BIT(2),
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ MTK_WED_WO_REGION_EMI,
|
||||
+ MTK_WED_WO_REGION_ILM,
|
||||
+ MTK_WED_WO_REGION_DATA,
|
||||
+ MTK_WED_WO_REGION_BOOT,
|
||||
+ __MTK_WED_WO_REGION_MAX,
|
||||
+};
|
||||
+
|
||||
+enum mtk_wed_dummy_cr_idx {
|
||||
+ MTK_WED_DUMMY_CR_FWDL,
|
||||
+ MTK_WED_DUMMY_CR_WO_STATUS,
|
||||
+};
|
||||
+
|
||||
+#define MT7986_FIRMWARE_WO0 "mediatek/mt7986_wo_0.bin"
|
||||
+#define MT7986_FIRMWARE_WO1 "mediatek/mt7986_wo_1.bin"
|
||||
+
|
||||
+#define MTK_WO_MCU_CFG_LS_BASE 0
|
||||
+#define MTK_WO_MCU_CFG_LS_HW_VER_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x000)
|
||||
+#define MTK_WO_MCU_CFG_LS_FW_VER_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x004)
|
||||
+#define MTK_WO_MCU_CFG_LS_CFG_DBG1_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x00c)
|
||||
+#define MTK_WO_MCU_CFG_LS_CFG_DBG2_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x010)
|
||||
+#define MTK_WO_MCU_CFG_LS_WF_MCCR_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x014)
|
||||
+#define MTK_WO_MCU_CFG_LS_WF_MCCR_SET_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x018)
|
||||
+#define MTK_WO_MCU_CFG_LS_WF_MCCR_CLR_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x01c)
|
||||
+#define MTK_WO_MCU_CFG_LS_WF_MCU_CFG_WM_WA_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x050)
|
||||
+#define MTK_WO_MCU_CFG_LS_WM_BOOT_ADDR_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x060)
|
||||
+#define MTK_WO_MCU_CFG_LS_WA_BOOT_ADDR_ADDR (MTK_WO_MCU_CFG_LS_BASE + 0x064)
|
||||
+
|
||||
+#define MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK BIT(5)
|
||||
+#define MTK_WO_MCU_CFG_LS_WF_WM_WA_WA_CPU_RSTB_MASK BIT(0)
|
||||
+
|
||||
+struct mtk_wed_wo_memory_region {
|
||||
+ const char *name;
|
||||
+ void __iomem *addr;
|
||||
+ phys_addr_t phy_addr;
|
||||
+ u32 size;
|
||||
+ bool shared:1;
|
||||
+ bool consumed:1;
|
||||
+};
|
||||
+
|
||||
+struct mtk_wed_fw_region {
|
||||
+ __le32 decomp_crc;
|
||||
+ __le32 decomp_len;
|
||||
+ __le32 decomp_blk_sz;
|
||||
+ u8 rsv0[4];
|
||||
+ __le32 addr;
|
||||
+ __le32 len;
|
||||
+ u8 feature_set;
|
||||
+ u8 rsv1[15];
|
||||
+} __packed;
|
||||
+
|
||||
+struct mtk_wed_fw_trailer {
|
||||
+ u8 chip_id;
|
||||
+ u8 eco_code;
|
||||
+ u8 num_region;
|
||||
+ u8 format_ver;
|
||||
+ u8 format_flag;
|
||||
+ u8 rsv[2];
|
||||
+ char fw_ver[10];
|
||||
+ char build_date[15];
|
||||
+ u32 crc;
|
||||
+};
|
||||
+
|
||||
+struct mtk_wed_wo {
|
||||
+ struct mtk_wed_hw *hw;
|
||||
+ struct mtk_wed_wo_memory_region boot;
|
||||
+
|
||||
+ struct {
|
||||
+ struct mutex mutex;
|
||||
+ int timeout;
|
||||
+ u16 seq;
|
||||
+
|
||||
+ struct sk_buff_head res_q;
|
||||
+ wait_queue_head_t wait;
|
||||
+ } mcu;
|
||||
+};
|
||||
+
|
||||
+static inline int
|
||||
+mtk_wed_mcu_check_msg(struct mtk_wed_wo *wo, struct sk_buff *skb)
|
||||
+{
|
||||
+ struct mtk_wed_mcu_hdr *hdr = (struct mtk_wed_mcu_hdr *)skb->data;
|
||||
+
|
||||
+ if (hdr->version)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (skb->len < sizeof(*hdr) || skb->len != le16_to_cpu(hdr->length))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void mtk_wed_mcu_rx_event(struct mtk_wed_wo *wo, struct sk_buff *skb);
|
||||
+void mtk_wed_mcu_rx_unsolicited_event(struct mtk_wed_wo *wo,
|
||||
+ struct sk_buff *skb);
|
||||
+int mtk_wed_mcu_send_msg(struct mtk_wed_wo *wo, int id, int cmd,
|
||||
+ const void *data, int len, bool wait_resp);
|
||||
+int mtk_wed_mcu_init(struct mtk_wed_wo *wo);
|
||||
+
|
||||
+#endif /* __MTK_WED_WO_H */
|
||||
--- a/include/linux/soc/mediatek/mtk_wed.h
|
||||
+++ b/include/linux/soc/mediatek/mtk_wed.h
|
||||
@@ -11,6 +11,35 @@
|
||||
struct mtk_wed_hw;
|
||||
struct mtk_wdma_desc;
|
||||
|
||||
+enum mtk_wed_wo_cmd {
|
||||
+ MTK_WED_WO_CMD_WED_CFG,
|
||||
+ MTK_WED_WO_CMD_WED_RX_STAT,
|
||||
+ MTK_WED_WO_CMD_RRO_SER,
|
||||
+ MTK_WED_WO_CMD_DBG_INFO,
|
||||
+ MTK_WED_WO_CMD_DEV_INFO,
|
||||
+ MTK_WED_WO_CMD_BSS_INFO,
|
||||
+ MTK_WED_WO_CMD_STA_REC,
|
||||
+ MTK_WED_WO_CMD_DEV_INFO_DUMP,
|
||||
+ MTK_WED_WO_CMD_BSS_INFO_DUMP,
|
||||
+ MTK_WED_WO_CMD_STA_REC_DUMP,
|
||||
+ MTK_WED_WO_CMD_BA_INFO_DUMP,
|
||||
+ MTK_WED_WO_CMD_FBCMD_Q_DUMP,
|
||||
+ MTK_WED_WO_CMD_FW_LOG_CTRL,
|
||||
+ MTK_WED_WO_CMD_LOG_FLUSH,
|
||||
+ MTK_WED_WO_CMD_CHANGE_STATE,
|
||||
+ MTK_WED_WO_CMD_CPU_STATS_ENABLE,
|
||||
+ MTK_WED_WO_CMD_CPU_STATS_DUMP,
|
||||
+ MTK_WED_WO_CMD_EXCEPTION_INIT,
|
||||
+ MTK_WED_WO_CMD_PROF_CTRL,
|
||||
+ MTK_WED_WO_CMD_STA_BA_DUMP,
|
||||
+ MTK_WED_WO_CMD_BA_CTRL_DUMP,
|
||||
+ MTK_WED_WO_CMD_RXCNT_CTRL,
|
||||
+ MTK_WED_WO_CMD_RXCNT_INFO,
|
||||
+ MTK_WED_WO_CMD_SET_CAP,
|
||||
+ MTK_WED_WO_CMD_CCIF_RING_DUMP,
|
||||
+ MTK_WED_WO_CMD_WED_END
|
||||
+};
|
||||
+
|
||||
enum mtk_wed_bus_tye {
|
||||
MTK_WED_BUS_PCIE,
|
||||
MTK_WED_BUS_AXI,
|
@ -0,0 +1,737 @@
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Sat, 5 Nov 2022 23:36:19 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_wed: introduce wed wo support
|
||||
|
||||
Introduce WO chip support to mtk wed driver. MTK WED WO is used to
|
||||
implement RX Wireless Ethernet Dispatch and offload traffic received by
|
||||
wlan nic to the wired interface.
|
||||
|
||||
Tested-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Co-developed-by: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
create mode 100644 drivers/net/ethernet/mediatek/mtk_wed_wo.c
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/Makefile
|
||||
+++ b/drivers/net/ethernet/mediatek/Makefile
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
|
||||
mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_eth_path.o mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o
|
||||
-mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o
|
||||
+mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o mtk_wed_mcu.o mtk_wed_wo.o
|
||||
ifdef CONFIG_DEBUG_FS
|
||||
mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o
|
||||
endif
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "mtk_wed_regs.h"
|
||||
#include "mtk_wed.h"
|
||||
#include "mtk_ppe.h"
|
||||
+#include "mtk_wed_wo.h"
|
||||
|
||||
#define MTK_PCIE_BASE(n) (0x1a143000 + (n) * 0x2000)
|
||||
|
||||
@@ -355,6 +356,8 @@ mtk_wed_detach(struct mtk_wed_device *de
|
||||
|
||||
mtk_wed_free_buffer(dev);
|
||||
mtk_wed_free_tx_rings(dev);
|
||||
+ if (hw->version != 1)
|
||||
+ mtk_wed_wo_deinit(hw);
|
||||
|
||||
if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) {
|
||||
struct device_node *wlan_node;
|
||||
@@ -885,9 +888,11 @@ mtk_wed_attach(struct mtk_wed_device *de
|
||||
}
|
||||
|
||||
mtk_wed_hw_init_early(dev);
|
||||
- if (hw->hifsys)
|
||||
+ if (hw->version == 1)
|
||||
regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
|
||||
BIT(hw->index), 0);
|
||||
+ else
|
||||
+ ret = mtk_wed_wo_init(hw);
|
||||
|
||||
out:
|
||||
mutex_unlock(&hw_lock);
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_wed.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed.h
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
struct mtk_eth;
|
||||
+struct mtk_wed_wo;
|
||||
|
||||
struct mtk_wed_hw {
|
||||
struct device_node *node;
|
||||
@@ -22,6 +23,7 @@ struct mtk_wed_hw {
|
||||
struct regmap *mirror;
|
||||
struct dentry *debugfs_dir;
|
||||
struct mtk_wed_device *wed_dev;
|
||||
+ struct mtk_wed_wo *wed_wo;
|
||||
u32 debugfs_reg;
|
||||
u32 num_flows;
|
||||
u8 version;
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
|
||||
@@ -122,8 +122,7 @@ mtk_wed_mcu_skb_send_msg(struct mtk_wed_
|
||||
if (id == MTK_WED_MODULE_ID_WO)
|
||||
hdr->flag |= cpu_to_le16(MTK_WED_WARP_CMD_FLAG_FROM_TO_WO);
|
||||
|
||||
- dev_kfree_skb(skb);
|
||||
- return 0;
|
||||
+ return mtk_wed_wo_queue_tx_skb(wo, &wo->q_tx, skb);
|
||||
}
|
||||
|
||||
static int
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
|
||||
@@ -0,0 +1,508 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-only
|
||||
+/* Copyright (C) 2022 MediaTek Inc.
|
||||
+ *
|
||||
+ * Author: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
+ * Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/dma-mapping.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/interrupt.h>
|
||||
+#include <linux/of_address.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/of_irq.h>
|
||||
+#include <linux/bitfield.h>
|
||||
+
|
||||
+#include "mtk_wed.h"
|
||||
+#include "mtk_wed_regs.h"
|
||||
+#include "mtk_wed_wo.h"
|
||||
+
|
||||
+static u32
|
||||
+mtk_wed_mmio_r32(struct mtk_wed_wo *wo, u32 reg)
|
||||
+{
|
||||
+ u32 val;
|
||||
+
|
||||
+ if (regmap_read(wo->mmio.regs, reg, &val))
|
||||
+ val = ~0;
|
||||
+
|
||||
+ return val;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_mmio_w32(struct mtk_wed_wo *wo, u32 reg, u32 val)
|
||||
+{
|
||||
+ regmap_write(wo->mmio.regs, reg, val);
|
||||
+}
|
||||
+
|
||||
+static u32
|
||||
+mtk_wed_wo_get_isr(struct mtk_wed_wo *wo)
|
||||
+{
|
||||
+ u32 val = mtk_wed_mmio_r32(wo, MTK_WED_WO_CCIF_RCHNUM);
|
||||
+
|
||||
+ return val & MTK_WED_WO_CCIF_RCHNUM_MASK;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_set_isr(struct mtk_wed_wo *wo, u32 mask)
|
||||
+{
|
||||
+ mtk_wed_mmio_w32(wo, MTK_WED_WO_CCIF_IRQ0_MASK, mask);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_set_ack(struct mtk_wed_wo *wo, u32 mask)
|
||||
+{
|
||||
+ mtk_wed_mmio_w32(wo, MTK_WED_WO_CCIF_ACK, mask);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_set_isr_mask(struct mtk_wed_wo *wo, u32 mask, u32 val, bool set)
|
||||
+{
|
||||
+ unsigned long flags;
|
||||
+
|
||||
+ spin_lock_irqsave(&wo->mmio.lock, flags);
|
||||
+ wo->mmio.irq_mask &= ~mask;
|
||||
+ wo->mmio.irq_mask |= val;
|
||||
+ if (set)
|
||||
+ mtk_wed_wo_set_isr(wo, wo->mmio.irq_mask);
|
||||
+ spin_unlock_irqrestore(&wo->mmio.lock, flags);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_irq_enable(struct mtk_wed_wo *wo, u32 mask)
|
||||
+{
|
||||
+ mtk_wed_wo_set_isr_mask(wo, 0, mask, false);
|
||||
+ tasklet_schedule(&wo->mmio.irq_tasklet);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_irq_disable(struct mtk_wed_wo *wo, u32 mask)
|
||||
+{
|
||||
+ mtk_wed_wo_set_isr_mask(wo, mask, 0, true);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_kickout(struct mtk_wed_wo *wo)
|
||||
+{
|
||||
+ mtk_wed_mmio_w32(wo, MTK_WED_WO_CCIF_BUSY, 1 << MTK_WED_WO_TXCH_NUM);
|
||||
+ mtk_wed_mmio_w32(wo, MTK_WED_WO_CCIF_TCHNUM, MTK_WED_WO_TXCH_NUM);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_queue_kick(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q,
|
||||
+ u32 val)
|
||||
+{
|
||||
+ wmb();
|
||||
+ mtk_wed_mmio_w32(wo, q->regs.cpu_idx, val);
|
||||
+}
|
||||
+
|
||||
+static void *
|
||||
+mtk_wed_wo_dequeue(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q, u32 *len,
|
||||
+ bool flush)
|
||||
+{
|
||||
+ int buf_len = SKB_WITH_OVERHEAD(q->buf_size);
|
||||
+ int index = (q->tail + 1) % q->n_desc;
|
||||
+ struct mtk_wed_wo_queue_entry *entry;
|
||||
+ struct mtk_wed_wo_queue_desc *desc;
|
||||
+ void *buf;
|
||||
+
|
||||
+ if (!q->queued)
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (flush)
|
||||
+ q->desc[index].ctrl |= cpu_to_le32(MTK_WED_WO_CTL_DMA_DONE);
|
||||
+ else if (!(q->desc[index].ctrl & cpu_to_le32(MTK_WED_WO_CTL_DMA_DONE)))
|
||||
+ return NULL;
|
||||
+
|
||||
+ q->tail = index;
|
||||
+ q->queued--;
|
||||
+
|
||||
+ desc = &q->desc[index];
|
||||
+ entry = &q->entry[index];
|
||||
+ buf = entry->buf;
|
||||
+ if (len)
|
||||
+ *len = FIELD_GET(MTK_WED_WO_CTL_SD_LEN0,
|
||||
+ le32_to_cpu(READ_ONCE(desc->ctrl)));
|
||||
+ if (buf)
|
||||
+ dma_unmap_single(wo->hw->dev, entry->addr, buf_len,
|
||||
+ DMA_FROM_DEVICE);
|
||||
+ entry->buf = NULL;
|
||||
+
|
||||
+ return buf;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mtk_wed_wo_queue_refill(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q,
|
||||
+ gfp_t gfp, bool rx)
|
||||
+{
|
||||
+ enum dma_data_direction dir = rx ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
||||
+ int n_buf = 0;
|
||||
+
|
||||
+ spin_lock_bh(&q->lock);
|
||||
+ while (q->queued < q->n_desc) {
|
||||
+ void *buf = page_frag_alloc(&q->cache, q->buf_size, gfp);
|
||||
+ struct mtk_wed_wo_queue_entry *entry;
|
||||
+ dma_addr_t addr;
|
||||
+
|
||||
+ if (!buf)
|
||||
+ break;
|
||||
+
|
||||
+ addr = dma_map_single(wo->hw->dev, buf, q->buf_size, dir);
|
||||
+ if (unlikely(dma_mapping_error(wo->hw->dev, addr))) {
|
||||
+ skb_free_frag(buf);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ q->head = (q->head + 1) % q->n_desc;
|
||||
+ entry = &q->entry[q->head];
|
||||
+ entry->addr = addr;
|
||||
+ entry->len = q->buf_size;
|
||||
+ q->entry[q->head].buf = buf;
|
||||
+
|
||||
+ if (rx) {
|
||||
+ struct mtk_wed_wo_queue_desc *desc = &q->desc[q->head];
|
||||
+ u32 ctrl = MTK_WED_WO_CTL_LAST_SEC0 |
|
||||
+ FIELD_PREP(MTK_WED_WO_CTL_SD_LEN0,
|
||||
+ entry->len);
|
||||
+
|
||||
+ WRITE_ONCE(desc->buf0, cpu_to_le32(addr));
|
||||
+ WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));
|
||||
+ }
|
||||
+ q->queued++;
|
||||
+ n_buf++;
|
||||
+ }
|
||||
+ spin_unlock_bh(&q->lock);
|
||||
+
|
||||
+ return n_buf;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_rx_complete(struct mtk_wed_wo *wo)
|
||||
+{
|
||||
+ mtk_wed_wo_set_ack(wo, MTK_WED_WO_RXCH_INT_MASK);
|
||||
+ mtk_wed_wo_irq_enable(wo, MTK_WED_WO_RXCH_INT_MASK);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_rx_run_queue(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q)
|
||||
+{
|
||||
+ for (;;) {
|
||||
+ struct mtk_wed_mcu_hdr *hdr;
|
||||
+ struct sk_buff *skb;
|
||||
+ void *data;
|
||||
+ u32 len;
|
||||
+
|
||||
+ data = mtk_wed_wo_dequeue(wo, q, &len, false);
|
||||
+ if (!data)
|
||||
+ break;
|
||||
+
|
||||
+ skb = build_skb(data, q->buf_size);
|
||||
+ if (!skb) {
|
||||
+ skb_free_frag(data);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ __skb_put(skb, len);
|
||||
+ if (mtk_wed_mcu_check_msg(wo, skb)) {
|
||||
+ dev_kfree_skb(skb);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ hdr = (struct mtk_wed_mcu_hdr *)skb->data;
|
||||
+ if (hdr->flag & cpu_to_le16(MTK_WED_WARP_CMD_FLAG_RSP))
|
||||
+ mtk_wed_mcu_rx_event(wo, skb);
|
||||
+ else
|
||||
+ mtk_wed_mcu_rx_unsolicited_event(wo, skb);
|
||||
+ }
|
||||
+
|
||||
+ if (mtk_wed_wo_queue_refill(wo, q, GFP_ATOMIC, true)) {
|
||||
+ u32 index = (q->head - 1) % q->n_desc;
|
||||
+
|
||||
+ mtk_wed_wo_queue_kick(wo, q, index);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t
|
||||
+mtk_wed_wo_irq_handler(int irq, void *data)
|
||||
+{
|
||||
+ struct mtk_wed_wo *wo = data;
|
||||
+
|
||||
+ mtk_wed_wo_set_isr(wo, 0);
|
||||
+ tasklet_schedule(&wo->mmio.irq_tasklet);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
+static void mtk_wed_wo_irq_tasklet(struct tasklet_struct *t)
|
||||
+{
|
||||
+ struct mtk_wed_wo *wo = from_tasklet(wo, t, mmio.irq_tasklet);
|
||||
+ u32 intr, mask;
|
||||
+
|
||||
+ /* disable interrupts */
|
||||
+ mtk_wed_wo_set_isr(wo, 0);
|
||||
+
|
||||
+ intr = mtk_wed_wo_get_isr(wo);
|
||||
+ intr &= wo->mmio.irq_mask;
|
||||
+ mask = intr & (MTK_WED_WO_RXCH_INT_MASK | MTK_WED_WO_EXCEPTION_INT_MASK);
|
||||
+ mtk_wed_wo_irq_disable(wo, mask);
|
||||
+
|
||||
+ if (intr & MTK_WED_WO_RXCH_INT_MASK) {
|
||||
+ mtk_wed_wo_rx_run_queue(wo, &wo->q_rx);
|
||||
+ mtk_wed_wo_rx_complete(wo);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+/* mtk wed wo hw queues */
|
||||
+
|
||||
+static int
|
||||
+mtk_wed_wo_queue_alloc(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q,
|
||||
+ int n_desc, int buf_size, int index,
|
||||
+ struct mtk_wed_wo_queue_regs *regs)
|
||||
+{
|
||||
+ spin_lock_init(&q->lock);
|
||||
+ q->regs = *regs;
|
||||
+ q->n_desc = n_desc;
|
||||
+ q->buf_size = buf_size;
|
||||
+
|
||||
+ q->desc = dmam_alloc_coherent(wo->hw->dev, n_desc * sizeof(*q->desc),
|
||||
+ &q->desc_dma, GFP_KERNEL);
|
||||
+ if (!q->desc)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ q->entry = devm_kzalloc(wo->hw->dev, n_desc * sizeof(*q->entry),
|
||||
+ GFP_KERNEL);
|
||||
+ if (!q->entry)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_queue_free(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q)
|
||||
+{
|
||||
+ mtk_wed_mmio_w32(wo, q->regs.cpu_idx, 0);
|
||||
+ dma_free_coherent(wo->hw->dev, q->n_desc * sizeof(*q->desc), q->desc,
|
||||
+ q->desc_dma);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_queue_tx_clean(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q)
|
||||
+{
|
||||
+ struct page *page;
|
||||
+ int i;
|
||||
+
|
||||
+ spin_lock_bh(&q->lock);
|
||||
+ for (i = 0; i < q->n_desc; i++) {
|
||||
+ struct mtk_wed_wo_queue_entry *entry = &q->entry[i];
|
||||
+
|
||||
+ dma_unmap_single(wo->hw->dev, entry->addr, entry->len,
|
||||
+ DMA_TO_DEVICE);
|
||||
+ skb_free_frag(entry->buf);
|
||||
+ entry->buf = NULL;
|
||||
+ }
|
||||
+ spin_unlock_bh(&q->lock);
|
||||
+
|
||||
+ if (!q->cache.va)
|
||||
+ return;
|
||||
+
|
||||
+ page = virt_to_page(q->cache.va);
|
||||
+ __page_frag_cache_drain(page, q->cache.pagecnt_bias);
|
||||
+ memset(&q->cache, 0, sizeof(q->cache));
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_queue_rx_clean(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q)
|
||||
+{
|
||||
+ struct page *page;
|
||||
+
|
||||
+ spin_lock_bh(&q->lock);
|
||||
+ for (;;) {
|
||||
+ void *buf = mtk_wed_wo_dequeue(wo, q, NULL, true);
|
||||
+
|
||||
+ if (!buf)
|
||||
+ break;
|
||||
+
|
||||
+ skb_free_frag(buf);
|
||||
+ }
|
||||
+ spin_unlock_bh(&q->lock);
|
||||
+
|
||||
+ if (!q->cache.va)
|
||||
+ return;
|
||||
+
|
||||
+ page = virt_to_page(q->cache.va);
|
||||
+ __page_frag_cache_drain(page, q->cache.pagecnt_bias);
|
||||
+ memset(&q->cache, 0, sizeof(q->cache));
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_queue_reset(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q)
|
||||
+{
|
||||
+ mtk_wed_mmio_w32(wo, q->regs.cpu_idx, 0);
|
||||
+ mtk_wed_mmio_w32(wo, q->regs.desc_base, q->desc_dma);
|
||||
+ mtk_wed_mmio_w32(wo, q->regs.ring_size, q->n_desc);
|
||||
+}
|
||||
+
|
||||
+int mtk_wed_wo_queue_tx_skb(struct mtk_wed_wo *wo, struct mtk_wed_wo_queue *q,
|
||||
+ struct sk_buff *skb)
|
||||
+{
|
||||
+ struct mtk_wed_wo_queue_entry *entry;
|
||||
+ struct mtk_wed_wo_queue_desc *desc;
|
||||
+ int ret = 0, index;
|
||||
+ u32 ctrl;
|
||||
+
|
||||
+ spin_lock_bh(&q->lock);
|
||||
+
|
||||
+ q->tail = mtk_wed_mmio_r32(wo, q->regs.dma_idx);
|
||||
+ index = (q->head + 1) % q->n_desc;
|
||||
+ if (q->tail == index) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ entry = &q->entry[index];
|
||||
+ if (skb->len > entry->len) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ desc = &q->desc[index];
|
||||
+ q->head = index;
|
||||
+
|
||||
+ dma_sync_single_for_cpu(wo->hw->dev, entry->addr, skb->len,
|
||||
+ DMA_TO_DEVICE);
|
||||
+ memcpy(entry->buf, skb->data, skb->len);
|
||||
+ dma_sync_single_for_device(wo->hw->dev, entry->addr, skb->len,
|
||||
+ DMA_TO_DEVICE);
|
||||
+
|
||||
+ ctrl = FIELD_PREP(MTK_WED_WO_CTL_SD_LEN0, skb->len) |
|
||||
+ MTK_WED_WO_CTL_LAST_SEC0 | MTK_WED_WO_CTL_DMA_DONE;
|
||||
+ WRITE_ONCE(desc->buf0, cpu_to_le32(entry->addr));
|
||||
+ WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));
|
||||
+
|
||||
+ mtk_wed_wo_queue_kick(wo, q, q->head);
|
||||
+ mtk_wed_wo_kickout(wo);
|
||||
+out:
|
||||
+ spin_unlock_bh(&q->lock);
|
||||
+
|
||||
+ dev_kfree_skb(skb);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mtk_wed_wo_exception_init(struct mtk_wed_wo *wo)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+mtk_wed_wo_hardware_init(struct mtk_wed_wo *wo)
|
||||
+{
|
||||
+ struct mtk_wed_wo_queue_regs regs;
|
||||
+ struct device_node *np;
|
||||
+ int ret;
|
||||
+
|
||||
+ np = of_parse_phandle(wo->hw->node, "mediatek,wo-ccif", 0);
|
||||
+ if (!np)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ wo->mmio.regs = syscon_regmap_lookup_by_phandle(np, NULL);
|
||||
+ if (IS_ERR_OR_NULL(wo->mmio.regs))
|
||||
+ return PTR_ERR(wo->mmio.regs);
|
||||
+
|
||||
+ wo->mmio.irq = irq_of_parse_and_map(np, 0);
|
||||
+ wo->mmio.irq_mask = MTK_WED_WO_ALL_INT_MASK;
|
||||
+ spin_lock_init(&wo->mmio.lock);
|
||||
+ tasklet_setup(&wo->mmio.irq_tasklet, mtk_wed_wo_irq_tasklet);
|
||||
+
|
||||
+ ret = devm_request_irq(wo->hw->dev, wo->mmio.irq,
|
||||
+ mtk_wed_wo_irq_handler, IRQF_TRIGGER_HIGH,
|
||||
+ KBUILD_MODNAME, wo);
|
||||
+ if (ret)
|
||||
+ goto error;
|
||||
+
|
||||
+ regs.desc_base = MTK_WED_WO_CCIF_DUMMY1;
|
||||
+ regs.ring_size = MTK_WED_WO_CCIF_DUMMY2;
|
||||
+ regs.dma_idx = MTK_WED_WO_CCIF_SHADOW4;
|
||||
+ regs.cpu_idx = MTK_WED_WO_CCIF_DUMMY3;
|
||||
+
|
||||
+ ret = mtk_wed_wo_queue_alloc(wo, &wo->q_tx, MTK_WED_WO_RING_SIZE,
|
||||
+ MTK_WED_WO_CMD_LEN, MTK_WED_WO_TXCH_NUM,
|
||||
+ ®s);
|
||||
+ if (ret)
|
||||
+ goto error;
|
||||
+
|
||||
+ mtk_wed_wo_queue_refill(wo, &wo->q_tx, GFP_KERNEL, false);
|
||||
+ mtk_wed_wo_queue_reset(wo, &wo->q_tx);
|
||||
+
|
||||
+ regs.desc_base = MTK_WED_WO_CCIF_DUMMY5;
|
||||
+ regs.ring_size = MTK_WED_WO_CCIF_DUMMY6;
|
||||
+ regs.dma_idx = MTK_WED_WO_CCIF_SHADOW8;
|
||||
+ regs.cpu_idx = MTK_WED_WO_CCIF_DUMMY7;
|
||||
+
|
||||
+ ret = mtk_wed_wo_queue_alloc(wo, &wo->q_rx, MTK_WED_WO_RING_SIZE,
|
||||
+ MTK_WED_WO_CMD_LEN, MTK_WED_WO_RXCH_NUM,
|
||||
+ ®s);
|
||||
+ if (ret)
|
||||
+ goto error;
|
||||
+
|
||||
+ mtk_wed_wo_queue_refill(wo, &wo->q_rx, GFP_KERNEL, true);
|
||||
+ mtk_wed_wo_queue_reset(wo, &wo->q_rx);
|
||||
+
|
||||
+ /* rx queue irqmask */
|
||||
+ mtk_wed_wo_set_isr(wo, wo->mmio.irq_mask);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+error:
|
||||
+ devm_free_irq(wo->hw->dev, wo->mmio.irq, wo);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+mtk_wed_wo_hw_deinit(struct mtk_wed_wo *wo)
|
||||
+{
|
||||
+ /* disable interrupts */
|
||||
+ mtk_wed_wo_set_isr(wo, 0);
|
||||
+
|
||||
+ tasklet_disable(&wo->mmio.irq_tasklet);
|
||||
+
|
||||
+ disable_irq(wo->mmio.irq);
|
||||
+ devm_free_irq(wo->hw->dev, wo->mmio.irq, wo);
|
||||
+
|
||||
+ mtk_wed_wo_queue_tx_clean(wo, &wo->q_tx);
|
||||
+ mtk_wed_wo_queue_rx_clean(wo, &wo->q_rx);
|
||||
+ mtk_wed_wo_queue_free(wo, &wo->q_tx);
|
||||
+ mtk_wed_wo_queue_free(wo, &wo->q_rx);
|
||||
+}
|
||||
+
|
||||
+int mtk_wed_wo_init(struct mtk_wed_hw *hw)
|
||||
+{
|
||||
+ struct mtk_wed_wo *wo;
|
||||
+ int ret;
|
||||
+
|
||||
+ wo = devm_kzalloc(hw->dev, sizeof(*wo), GFP_KERNEL);
|
||||
+ if (!wo)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ hw->wed_wo = wo;
|
||||
+ wo->hw = hw;
|
||||
+
|
||||
+ ret = mtk_wed_wo_hardware_init(wo);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = mtk_wed_mcu_init(wo);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return mtk_wed_wo_exception_init(wo);
|
||||
+}
|
||||
+
|
||||
+void mtk_wed_wo_deinit(struct mtk_wed_hw *hw)
|
||||
+{
|
||||
+ struct mtk_wed_wo *wo = hw->wed_wo;
|
||||
+
|
||||
+ mtk_wed_wo_hw_deinit(wo);
|
||||
+}
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
|
||||
@@ -80,6 +80,54 @@ enum mtk_wed_dummy_cr_idx {
|
||||
#define MTK_WO_MCU_CFG_LS_WF_WM_WA_WM_CPU_RSTB_MASK BIT(5)
|
||||
#define MTK_WO_MCU_CFG_LS_WF_WM_WA_WA_CPU_RSTB_MASK BIT(0)
|
||||
|
||||
+#define MTK_WED_WO_RING_SIZE 256
|
||||
+#define MTK_WED_WO_CMD_LEN 1504
|
||||
+
|
||||
+#define MTK_WED_WO_TXCH_NUM 0
|
||||
+#define MTK_WED_WO_RXCH_NUM 1
|
||||
+#define MTK_WED_WO_RXCH_WO_EXCEPTION 7
|
||||
+
|
||||
+#define MTK_WED_WO_TXCH_INT_MASK BIT(0)
|
||||
+#define MTK_WED_WO_RXCH_INT_MASK BIT(1)
|
||||
+#define MTK_WED_WO_EXCEPTION_INT_MASK BIT(7)
|
||||
+#define MTK_WED_WO_ALL_INT_MASK (MTK_WED_WO_RXCH_INT_MASK | \
|
||||
+ MTK_WED_WO_EXCEPTION_INT_MASK)
|
||||
+
|
||||
+#define MTK_WED_WO_CCIF_BUSY 0x004
|
||||
+#define MTK_WED_WO_CCIF_START 0x008
|
||||
+#define MTK_WED_WO_CCIF_TCHNUM 0x00c
|
||||
+#define MTK_WED_WO_CCIF_RCHNUM 0x010
|
||||
+#define MTK_WED_WO_CCIF_RCHNUM_MASK GENMASK(7, 0)
|
||||
+
|
||||
+#define MTK_WED_WO_CCIF_ACK 0x014
|
||||
+#define MTK_WED_WO_CCIF_IRQ0_MASK 0x018
|
||||
+#define MTK_WED_WO_CCIF_IRQ1_MASK 0x01c
|
||||
+#define MTK_WED_WO_CCIF_DUMMY1 0x020
|
||||
+#define MTK_WED_WO_CCIF_DUMMY2 0x024
|
||||
+#define MTK_WED_WO_CCIF_DUMMY3 0x028
|
||||
+#define MTK_WED_WO_CCIF_DUMMY4 0x02c
|
||||
+#define MTK_WED_WO_CCIF_SHADOW1 0x030
|
||||
+#define MTK_WED_WO_CCIF_SHADOW2 0x034
|
||||
+#define MTK_WED_WO_CCIF_SHADOW3 0x038
|
||||
+#define MTK_WED_WO_CCIF_SHADOW4 0x03c
|
||||
+#define MTK_WED_WO_CCIF_DUMMY5 0x050
|
||||
+#define MTK_WED_WO_CCIF_DUMMY6 0x054
|
||||
+#define MTK_WED_WO_CCIF_DUMMY7 0x058
|
||||
+#define MTK_WED_WO_CCIF_DUMMY8 0x05c
|
||||
+#define MTK_WED_WO_CCIF_SHADOW5 0x060
|
||||
+#define MTK_WED_WO_CCIF_SHADOW6 0x064
|
||||
+#define MTK_WED_WO_CCIF_SHADOW7 0x068
|
||||
+#define MTK_WED_WO_CCIF_SHADOW8 0x06c
|
||||
+
|
||||
+#define MTK_WED_WO_CTL_SD_LEN1 GENMASK(13, 0)
|
||||
+#define MTK_WED_WO_CTL_LAST_SEC1 BIT(14)
|
||||
+#define MTK_WED_WO_CTL_BURST BIT(15)
|
||||
+#define MTK_WED_WO_CTL_SD_LEN0_SHIFT 16
|
||||
+#define MTK_WED_WO_CTL_SD_LEN0 GENMASK(29, 16)
|
||||
+#define MTK_WED_WO_CTL_LAST_SEC0 BIT(30)
|
||||
+#define MTK_WED_WO_CTL_DMA_DONE BIT(31)
|
||||
+#define MTK_WED_WO_INFO_WINFO GENMASK(15, 0)
|
||||
+
|
||||
struct mtk_wed_wo_memory_region {
|
||||
const char *name;
|
||||
void __iomem *addr;
|
||||
@@ -112,10 +160,53 @@ struct mtk_wed_fw_trailer {
|
||||
u32 crc;
|
||||
};
|
||||
|
||||
+struct mtk_wed_wo_queue_regs {
|
||||
+ u32 desc_base;
|
||||
+ u32 ring_size;
|
||||
+ u32 cpu_idx;
|
||||
+ u32 dma_idx;
|
||||
+};
|
||||
+
|
||||
+struct mtk_wed_wo_queue_desc {
|
||||
+ __le32 buf0;
|
||||
+ __le32 ctrl;
|
||||
+ __le32 buf1;
|
||||
+ __le32 info;
|
||||
+ __le32 reserved[4];
|
||||
+} __packed __aligned(32);
|
||||
+
|
||||
+struct mtk_wed_wo_queue_entry {
|
||||
+ dma_addr_t addr;
|
||||
+ void *buf;
|
||||
+ u32 len;
|
||||
+};
|
||||
+
|
||||
+struct mtk_wed_wo_queue {
|
||||
+ struct mtk_wed_wo_queue_regs regs;
|
||||
+
|
||||
+ struct page_frag_cache cache;
|
||||
+ spinlock_t lock;
|
||||
+
|
||||
+ struct mtk_wed_wo_queue_desc *desc;
|
||||
+ dma_addr_t desc_dma;
|
||||
+
|
||||
+ struct mtk_wed_wo_queue_entry *entry;
|
||||
+
|
||||
+ u16 head;
|
||||
+ u16 tail;
|
||||
+ int n_desc;
|
||||
+ int queued;
|
||||
+ int buf_size;
|
||||
+
|
||||
+};
|
||||
+
|
||||
struct mtk_wed_wo {
|
||||
struct mtk_wed_hw *hw;
|
||||
struct mtk_wed_wo_memory_region boot;
|
||||
|
||||
+ struct mtk_wed_wo_queue q_tx;
|
||||
+ struct mtk_wed_wo_queue q_rx;
|
||||
+
|
||||
struct {
|
||||
struct mutex mutex;
|
||||
int timeout;
|
||||
@@ -124,6 +215,15 @@ struct mtk_wed_wo {
|
||||
struct sk_buff_head res_q;
|
||||
wait_queue_head_t wait;
|
||||
} mcu;
|
||||
+
|
||||
+ struct {
|
||||
+ struct regmap *regs;
|
||||
+
|
||||
+ spinlock_t lock;
|
||||
+ struct tasklet_struct irq_tasklet;
|
||||
+ int irq;
|
||||
+ u32 irq_mask;
|
||||
+ } mmio;
|
||||
};
|
||||
|
||||
static inline int
|
||||
@@ -146,5 +246,9 @@ void mtk_wed_mcu_rx_unsolicited_event(st
|
||||
int mtk_wed_mcu_send_msg(struct mtk_wed_wo *wo, int id, int cmd,
|
||||
const void *data, int len, bool wait_resp);
|
||||
int mtk_wed_mcu_init(struct mtk_wed_wo *wo);
|
||||
+int mtk_wed_wo_init(struct mtk_wed_hw *hw);
|
||||
+void mtk_wed_wo_deinit(struct mtk_wed_hw *hw);
|
||||
+int mtk_wed_wo_queue_tx_skb(struct mtk_wed_wo *dev, struct mtk_wed_wo_queue *q,
|
||||
+ struct sk_buff *skb);
|
||||
|
||||
#endif /* __MTK_WED_WO_H */
|
@ -0,0 +1,79 @@
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Sat, 5 Nov 2022 23:36:20 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_wed: rename tx_wdma array in rx_wdma
|
||||
|
||||
Rename tx_wdma queue array in rx_wdma since this is rx side of wdma soc.
|
||||
Moreover rename mtk_wed_wdma_ring_setup routine in
|
||||
mtk_wed_wdma_rx_ring_setup()
|
||||
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
|
||||
@@ -253,8 +253,8 @@ mtk_wed_free_tx_rings(struct mtk_wed_dev
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev->tx_ring); i++)
|
||||
mtk_wed_free_ring(dev, &dev->tx_ring[i]);
|
||||
- for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
|
||||
- mtk_wed_free_ring(dev, &dev->tx_wdma[i]);
|
||||
+ for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
|
||||
+ mtk_wed_free_ring(dev, &dev->rx_wdma[i]);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -695,10 +695,10 @@ mtk_wed_ring_alloc(struct mtk_wed_device
|
||||
}
|
||||
|
||||
static int
|
||||
-mtk_wed_wdma_ring_setup(struct mtk_wed_device *dev, int idx, int size)
|
||||
+mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
|
||||
{
|
||||
u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
|
||||
- struct mtk_wed_ring *wdma = &dev->tx_wdma[idx];
|
||||
+ struct mtk_wed_ring *wdma = &dev->rx_wdma[idx];
|
||||
|
||||
if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size))
|
||||
return -ENOMEM;
|
||||
@@ -812,9 +812,9 @@ mtk_wed_start(struct mtk_wed_device *dev
|
||||
{
|
||||
int i;
|
||||
|
||||
- for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
|
||||
- if (!dev->tx_wdma[i].desc)
|
||||
- mtk_wed_wdma_ring_setup(dev, i, 16);
|
||||
+ for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
|
||||
+ if (!dev->rx_wdma[i].desc)
|
||||
+ mtk_wed_wdma_rx_ring_setup(dev, i, 16);
|
||||
|
||||
mtk_wed_hw_init(dev);
|
||||
mtk_wed_configure_irq(dev, irq_mask);
|
||||
@@ -923,7 +923,7 @@ mtk_wed_tx_ring_setup(struct mtk_wed_dev
|
||||
sizeof(*ring->desc)))
|
||||
return -ENOMEM;
|
||||
|
||||
- if (mtk_wed_wdma_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE))
|
||||
+ if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE))
|
||||
return -ENOMEM;
|
||||
|
||||
ring->reg_base = MTK_WED_RING_TX(idx);
|
||||
--- a/include/linux/soc/mediatek/mtk_wed.h
|
||||
+++ b/include/linux/soc/mediatek/mtk_wed.h
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <linux/pci.h>
|
||||
|
||||
#define MTK_WED_TX_QUEUES 2
|
||||
+#define MTK_WED_RX_QUEUES 2
|
||||
|
||||
struct mtk_wed_hw;
|
||||
struct mtk_wdma_desc;
|
||||
@@ -66,7 +67,7 @@ struct mtk_wed_device {
|
||||
|
||||
struct mtk_wed_ring tx_ring[MTK_WED_TX_QUEUES];
|
||||
struct mtk_wed_ring txfree_ring;
|
||||
- struct mtk_wed_ring tx_wdma[MTK_WED_TX_QUEUES];
|
||||
+ struct mtk_wed_ring rx_wdma[MTK_WED_RX_QUEUES];
|
||||
|
||||
struct {
|
||||
int size;
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,149 @@
|
||||
From: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Date: Sat, 5 Nov 2022 23:36:22 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_wed: add rx mib counters
|
||||
|
||||
Introduce WED RX MIB counters support available on MT7986a SoC.
|
||||
|
||||
Tested-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Co-developed-by: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
|
||||
Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_wed_debugfs.c
|
||||
@@ -2,6 +2,7 @@
|
||||
/* Copyright (C) 2021 Felix Fietkau <nbd@nbd.name> */
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
+#include <linux/soc/mediatek/mtk_wed.h>
|
||||
#include "mtk_wed.h"
|
||||
#include "mtk_wed_regs.h"
|
||||
|
||||
@@ -18,6 +19,8 @@ enum {
|
||||
DUMP_TYPE_WDMA,
|
||||
DUMP_TYPE_WPDMA_TX,
|
||||
DUMP_TYPE_WPDMA_TXFREE,
|
||||
+ DUMP_TYPE_WPDMA_RX,
|
||||
+ DUMP_TYPE_WED_RRO,
|
||||
};
|
||||
|
||||
#define DUMP_STR(_str) { _str, 0, DUMP_TYPE_STRING }
|
||||
@@ -36,6 +39,9 @@ enum {
|
||||
|
||||
#define DUMP_WPDMA_TX_RING(_n) DUMP_RING("WPDMA_TX" #_n, 0, DUMP_TYPE_WPDMA_TX, _n)
|
||||
#define DUMP_WPDMA_TXFREE_RING DUMP_RING("WPDMA_RX1", 0, DUMP_TYPE_WPDMA_TXFREE)
|
||||
+#define DUMP_WPDMA_RX_RING(_n) DUMP_RING("WPDMA_RX" #_n, 0, DUMP_TYPE_WPDMA_RX, _n)
|
||||
+#define DUMP_WED_RRO_RING(_base)DUMP_RING("WED_RRO_MIOD", MTK_##_base, DUMP_TYPE_WED_RRO)
|
||||
+#define DUMP_WED_RRO_FDBK(_base)DUMP_RING("WED_RRO_FDBK", MTK_##_base, DUMP_TYPE_WED_RRO)
|
||||
|
||||
static void
|
||||
print_reg_val(struct seq_file *s, const char *name, u32 val)
|
||||
@@ -57,6 +63,7 @@ dump_wed_regs(struct seq_file *s, struct
|
||||
cur > regs ? "\n" : "",
|
||||
cur->name);
|
||||
continue;
|
||||
+ case DUMP_TYPE_WED_RRO:
|
||||
case DUMP_TYPE_WED:
|
||||
val = wed_r32(dev, cur->offset);
|
||||
break;
|
||||
@@ -69,6 +76,9 @@ dump_wed_regs(struct seq_file *s, struct
|
||||
case DUMP_TYPE_WPDMA_TXFREE:
|
||||
val = wpdma_txfree_r32(dev, cur->offset);
|
||||
break;
|
||||
+ case DUMP_TYPE_WPDMA_RX:
|
||||
+ val = wpdma_rx_r32(dev, cur->base, cur->offset);
|
||||
+ break;
|
||||
}
|
||||
print_reg_val(s, cur->name, val);
|
||||
}
|
||||
@@ -132,6 +142,80 @@ wed_txinfo_show(struct seq_file *s, void
|
||||
}
|
||||
DEFINE_SHOW_ATTRIBUTE(wed_txinfo);
|
||||
|
||||
+static int
|
||||
+wed_rxinfo_show(struct seq_file *s, void *data)
|
||||
+{
|
||||
+ static const struct reg_dump regs[] = {
|
||||
+ DUMP_STR("WPDMA RX"),
|
||||
+ DUMP_WPDMA_RX_RING(0),
|
||||
+ DUMP_WPDMA_RX_RING(1),
|
||||
+
|
||||
+ DUMP_STR("WPDMA RX"),
|
||||
+ DUMP_WED(WED_WPDMA_RX_D_MIB(0)),
|
||||
+ DUMP_WED_RING(WED_WPDMA_RING_RX_DATA(0)),
|
||||
+ DUMP_WED(WED_WPDMA_RX_D_PROCESSED_MIB(0)),
|
||||
+ DUMP_WED(WED_WPDMA_RX_D_MIB(1)),
|
||||
+ DUMP_WED_RING(WED_WPDMA_RING_RX_DATA(1)),
|
||||
+ DUMP_WED(WED_WPDMA_RX_D_PROCESSED_MIB(1)),
|
||||
+ DUMP_WED(WED_WPDMA_RX_D_COHERENT_MIB),
|
||||
+
|
||||
+ DUMP_STR("WED RX"),
|
||||
+ DUMP_WED_RING(WED_RING_RX_DATA(0)),
|
||||
+ DUMP_WED_RING(WED_RING_RX_DATA(1)),
|
||||
+
|
||||
+ DUMP_STR("WED RRO"),
|
||||
+ DUMP_WED_RRO_RING(WED_RROQM_MIOD_CTRL0),
|
||||
+ DUMP_WED(WED_RROQM_MID_MIB),
|
||||
+ DUMP_WED(WED_RROQM_MOD_MIB),
|
||||
+ DUMP_WED(WED_RROQM_MOD_COHERENT_MIB),
|
||||
+ DUMP_WED_RRO_FDBK(WED_RROQM_FDBK_CTRL0),
|
||||
+ DUMP_WED(WED_RROQM_FDBK_IND_MIB),
|
||||
+ DUMP_WED(WED_RROQM_FDBK_ENQ_MIB),
|
||||
+ DUMP_WED(WED_RROQM_FDBK_ANC_MIB),
|
||||
+ DUMP_WED(WED_RROQM_FDBK_ANC2H_MIB),
|
||||
+
|
||||
+ DUMP_STR("WED Route QM"),
|
||||
+ DUMP_WED(WED_RTQM_R2H_MIB(0)),
|
||||
+ DUMP_WED(WED_RTQM_R2Q_MIB(0)),
|
||||
+ DUMP_WED(WED_RTQM_Q2H_MIB(0)),
|
||||
+ DUMP_WED(WED_RTQM_R2H_MIB(1)),
|
||||
+ DUMP_WED(WED_RTQM_R2Q_MIB(1)),
|
||||
+ DUMP_WED(WED_RTQM_Q2H_MIB(1)),
|
||||
+ DUMP_WED(WED_RTQM_Q2N_MIB),
|
||||
+ DUMP_WED(WED_RTQM_Q2B_MIB),
|
||||
+ DUMP_WED(WED_RTQM_PFDBK_MIB),
|
||||
+
|
||||
+ DUMP_STR("WED WDMA TX"),
|
||||
+ DUMP_WED(WED_WDMA_TX_MIB),
|
||||
+ DUMP_WED_RING(WED_WDMA_RING_TX),
|
||||
+
|
||||
+ DUMP_STR("WDMA TX"),
|
||||
+ DUMP_WDMA(WDMA_GLO_CFG),
|
||||
+ DUMP_WDMA_RING(WDMA_RING_TX(0)),
|
||||
+ DUMP_WDMA_RING(WDMA_RING_TX(1)),
|
||||
+
|
||||
+ DUMP_STR("WED RX BM"),
|
||||
+ DUMP_WED(WED_RX_BM_BASE),
|
||||
+ DUMP_WED(WED_RX_BM_RX_DMAD),
|
||||
+ DUMP_WED(WED_RX_BM_PTR),
|
||||
+ DUMP_WED(WED_RX_BM_TKID_MIB),
|
||||
+ DUMP_WED(WED_RX_BM_BLEN),
|
||||
+ DUMP_WED(WED_RX_BM_STS),
|
||||
+ DUMP_WED(WED_RX_BM_INTF2),
|
||||
+ DUMP_WED(WED_RX_BM_INTF),
|
||||
+ DUMP_WED(WED_RX_BM_ERR_STS),
|
||||
+ };
|
||||
+ struct mtk_wed_hw *hw = s->private;
|
||||
+ struct mtk_wed_device *dev = hw->wed_dev;
|
||||
+
|
||||
+ if (!dev)
|
||||
+ return 0;
|
||||
+
|
||||
+ dump_wed_regs(s, dev, regs, ARRAY_SIZE(regs));
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+DEFINE_SHOW_ATTRIBUTE(wed_rxinfo);
|
||||
|
||||
static int
|
||||
mtk_wed_reg_set(void *data, u64 val)
|
||||
@@ -175,4 +259,7 @@ void mtk_wed_hw_add_debugfs(struct mtk_w
|
||||
debugfs_create_u32("regidx", 0600, dir, &hw->debugfs_reg);
|
||||
debugfs_create_file_unsafe("regval", 0600, dir, hw, &fops_regval);
|
||||
debugfs_create_file_unsafe("txinfo", 0400, dir, hw, &wed_txinfo_fops);
|
||||
+ if (hw->version != 1)
|
||||
+ debugfs_create_file_unsafe("rxinfo", 0400, dir, hw,
|
||||
+ &wed_rxinfo_fops);
|
||||
}
|
Loading…
Reference in New Issue
Block a user