d682bee89a63f25ba3164e5a13dd9bf366c16935
[openwrt/staging/blogic.git] /
1 From: Lorenzo Bianconi <lorenzo@kernel.org>
2 Date: Sat, 14 Jan 2023 18:01:31 +0100
3 Subject: [PATCH] net: ethernet: mtk_eth_soc: add dma checks to
4 mtk_hw_reset_check
5
6 Introduce mtk_hw_check_dma_hang routine to monitor possible dma hangs.
7
8 Reviewed-by: Leon Romanovsky <leonro@nvidia.com>
9 Tested-by: Daniel Golle <daniel@makrotopia.org>
10 Co-developed-by: Sujuan Chen <sujuan.chen@mediatek.com>
11 Signed-off-by: Sujuan Chen <sujuan.chen@mediatek.com>
12 Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
13 Signed-off-by: Paolo Abeni <pabeni@redhat.com>
14 ---
15
16 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
17 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
18 @@ -50,6 +50,7 @@ static const struct mtk_reg_map mtk_reg_
19 .delay_irq = 0x0a0c,
20 .irq_status = 0x0a20,
21 .irq_mask = 0x0a28,
22 + .adma_rx_dbg0 = 0x0a38,
23 .int_grp = 0x0a50,
24 },
25 .qdma = {
26 @@ -79,6 +80,8 @@ static const struct mtk_reg_map mtk_reg_
27 [0] = 0x2800,
28 [1] = 0x2c00,
29 },
30 + .pse_iq_sta = 0x0110,
31 + .pse_oq_sta = 0x0118,
32 };
33
34 static const struct mtk_reg_map mt7628_reg_map = {
35 @@ -109,6 +112,7 @@ static const struct mtk_reg_map mt7986_r
36 .delay_irq = 0x620c,
37 .irq_status = 0x6220,
38 .irq_mask = 0x6228,
39 + .adma_rx_dbg0 = 0x6238,
40 .int_grp = 0x6250,
41 },
42 .qdma = {
43 @@ -138,6 +142,8 @@ static const struct mtk_reg_map mt7986_r
44 [0] = 0x4800,
45 [1] = 0x4c00,
46 },
47 + .pse_iq_sta = 0x0180,
48 + .pse_oq_sta = 0x01a0,
49 };
50
51 /* strings used by ethtool */
52 @@ -3337,6 +3343,102 @@ static void mtk_hw_warm_reset(struct mtk
53 val, rst_mask);
54 }
55
56 +static bool mtk_hw_check_dma_hang(struct mtk_eth *eth)
57 +{
58 + const struct mtk_reg_map *reg_map = eth->soc->reg_map;
59 + bool gmac1_tx, gmac2_tx, gdm1_tx, gdm2_tx;
60 + bool oq_hang, cdm1_busy, adma_busy;
61 + bool wtx_busy, cdm_full, oq_free;
62 + u32 wdidx, val, gdm1_fc, gdm2_fc;
63 + bool qfsm_hang, qfwd_hang;
64 + bool ret = false;
65 +
66 + if (MTK_HAS_CAPS(eth->soc->caps, MTK_SOC_MT7628))
67 + return false;
68 +
69 + /* WDMA sanity checks */
70 + wdidx = mtk_r32(eth, reg_map->wdma_base[0] + 0xc);
71 +
72 + val = mtk_r32(eth, reg_map->wdma_base[0] + 0x204);
73 + wtx_busy = FIELD_GET(MTK_TX_DMA_BUSY, val);
74 +
75 + val = mtk_r32(eth, reg_map->wdma_base[0] + 0x230);
76 + cdm_full = !FIELD_GET(MTK_CDM_TXFIFO_RDY, val);
77 +
78 + oq_free = (!(mtk_r32(eth, reg_map->pse_oq_sta) & GENMASK(24, 16)) &&
79 + !(mtk_r32(eth, reg_map->pse_oq_sta + 0x4) & GENMASK(8, 0)) &&
80 + !(mtk_r32(eth, reg_map->pse_oq_sta + 0x10) & GENMASK(24, 16)));
81 +
82 + if (wdidx == eth->reset.wdidx && wtx_busy && cdm_full && oq_free) {
83 + if (++eth->reset.wdma_hang_count > 2) {
84 + eth->reset.wdma_hang_count = 0;
85 + ret = true;
86 + }
87 + goto out;
88 + }
89 +
90 + /* QDMA sanity checks */
91 + qfsm_hang = !!mtk_r32(eth, reg_map->qdma.qtx_cfg + 0x234);
92 + qfwd_hang = !mtk_r32(eth, reg_map->qdma.qtx_cfg + 0x308);
93 +
94 + gdm1_tx = FIELD_GET(GENMASK(31, 16), mtk_r32(eth, MTK_FE_GDM1_FSM)) > 0;
95 + gdm2_tx = FIELD_GET(GENMASK(31, 16), mtk_r32(eth, MTK_FE_GDM2_FSM)) > 0;
96 + gmac1_tx = FIELD_GET(GENMASK(31, 24), mtk_r32(eth, MTK_MAC_FSM(0))) != 1;
97 + gmac2_tx = FIELD_GET(GENMASK(31, 24), mtk_r32(eth, MTK_MAC_FSM(1))) != 1;
98 + gdm1_fc = mtk_r32(eth, reg_map->gdm1_cnt + 0x24);
99 + gdm2_fc = mtk_r32(eth, reg_map->gdm1_cnt + 0x64);
100 +
101 + if (qfsm_hang && qfwd_hang &&
102 + ((gdm1_tx && gmac1_tx && gdm1_fc < 1) ||
103 + (gdm2_tx && gmac2_tx && gdm2_fc < 1))) {
104 + if (++eth->reset.qdma_hang_count > 2) {
105 + eth->reset.qdma_hang_count = 0;
106 + ret = true;
107 + }
108 + goto out;
109 + }
110 +
111 + /* ADMA sanity checks */
112 + oq_hang = !!(mtk_r32(eth, reg_map->pse_oq_sta) & GENMASK(8, 0));
113 + cdm1_busy = !!(mtk_r32(eth, MTK_FE_CDM1_FSM) & GENMASK(31, 16));
114 + adma_busy = !(mtk_r32(eth, reg_map->pdma.adma_rx_dbg0) & GENMASK(4, 0)) &&
115 + !(mtk_r32(eth, reg_map->pdma.adma_rx_dbg0) & BIT(6));
116 +
117 + if (oq_hang && cdm1_busy && adma_busy) {
118 + if (++eth->reset.adma_hang_count > 2) {
119 + eth->reset.adma_hang_count = 0;
120 + ret = true;
121 + }
122 + goto out;
123 + }
124 +
125 + eth->reset.wdma_hang_count = 0;
126 + eth->reset.qdma_hang_count = 0;
127 + eth->reset.adma_hang_count = 0;
128 +out:
129 + eth->reset.wdidx = wdidx;
130 +
131 + return ret;
132 +}
133 +
134 +static void mtk_hw_reset_monitor_work(struct work_struct *work)
135 +{
136 + struct delayed_work *del_work = to_delayed_work(work);
137 + struct mtk_eth *eth = container_of(del_work, struct mtk_eth,
138 + reset.monitor_work);
139 +
140 + if (test_bit(MTK_RESETTING, &eth->state))
141 + goto out;
142 +
143 + /* DMA stuck checks */
144 + if (mtk_hw_check_dma_hang(eth))
145 + schedule_work(&eth->pending_work);
146 +
147 +out:
148 + schedule_delayed_work(&eth->reset.monitor_work,
149 + MTK_DMA_MONITOR_TIMEOUT);
150 +}
151 +
152 static int mtk_hw_init(struct mtk_eth *eth, bool reset)
153 {
154 u32 dma_mask = ETHSYS_DMA_AG_MAP_PDMA | ETHSYS_DMA_AG_MAP_QDMA |
155 @@ -3655,6 +3757,7 @@ static int mtk_cleanup(struct mtk_eth *e
156 mtk_unreg_dev(eth);
157 mtk_free_dev(eth);
158 cancel_work_sync(&eth->pending_work);
159 + cancel_delayed_work_sync(&eth->reset.monitor_work);
160
161 return 0;
162 }
163 @@ -4092,6 +4195,7 @@ static int mtk_probe(struct platform_dev
164
165 eth->rx_dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
166 INIT_WORK(&eth->rx_dim.work, mtk_dim_rx);
167 + INIT_DELAYED_WORK(&eth->reset.monitor_work, mtk_hw_reset_monitor_work);
168
169 eth->tx_dim.mode = DIM_CQ_PERIOD_MODE_START_FROM_EQE;
170 INIT_WORK(&eth->tx_dim.work, mtk_dim_tx);
171 @@ -4294,6 +4398,8 @@ static int mtk_probe(struct platform_dev
172 netif_napi_add(&eth->dummy_dev, &eth->rx_napi, mtk_napi_rx);
173
174 platform_set_drvdata(pdev, eth);
175 + schedule_delayed_work(&eth->reset.monitor_work,
176 + MTK_DMA_MONITOR_TIMEOUT);
177
178 return 0;
179
180 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
181 +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
182 @@ -257,6 +257,8 @@
183
184 #define MTK_RX_DONE_INT_V2 BIT(14)
185
186 +#define MTK_CDM_TXFIFO_RDY BIT(7)
187 +
188 /* QDMA Interrupt grouping registers */
189 #define MTK_RLS_DONE_INT BIT(0)
190
191 @@ -542,6 +544,17 @@
192 #define MT7628_SDM_RBCNT (MT7628_SDM_OFFSET + 0x10c)
193 #define MT7628_SDM_CS_ERR (MT7628_SDM_OFFSET + 0x110)
194
195 +#define MTK_FE_CDM1_FSM 0x220
196 +#define MTK_FE_CDM2_FSM 0x224
197 +#define MTK_FE_CDM3_FSM 0x238
198 +#define MTK_FE_CDM4_FSM 0x298
199 +#define MTK_FE_CDM5_FSM 0x318
200 +#define MTK_FE_CDM6_FSM 0x328
201 +#define MTK_FE_GDM1_FSM 0x228
202 +#define MTK_FE_GDM2_FSM 0x22C
203 +
204 +#define MTK_MAC_FSM(x) (0x1010C + ((x) * 0x100))
205 +
206 struct mtk_rx_dma {
207 unsigned int rxd1;
208 unsigned int rxd2;
209 @@ -938,6 +951,7 @@ struct mtk_reg_map {
210 u32 delay_irq; /* delay interrupt */
211 u32 irq_status; /* interrupt status */
212 u32 irq_mask; /* interrupt mask */
213 + u32 adma_rx_dbg0;
214 u32 int_grp;
215 } pdma;
216 struct {
217 @@ -964,6 +978,8 @@ struct mtk_reg_map {
218 u32 gdma_to_ppe;
219 u32 ppe_base;
220 u32 wdma_base[2];
221 + u32 pse_iq_sta;
222 + u32 pse_oq_sta;
223 };
224
225 /* struct mtk_eth_data - This is the structure holding all differences
226 @@ -1006,6 +1022,8 @@ struct mtk_soc_data {
227 } txrx;
228 };
229
230 +#define MTK_DMA_MONITOR_TIMEOUT msecs_to_jiffies(1000)
231 +
232 /* currently no SoC has more than 2 macs */
233 #define MTK_MAX_DEVS 2
234
235 @@ -1128,6 +1146,14 @@ struct mtk_eth {
236 struct rhashtable flow_table;
237
238 struct bpf_prog __rcu *prog;
239 +
240 + struct {
241 + struct delayed_work monitor_work;
242 + u32 wdidx;
243 + u8 wdma_hang_count;
244 + u8 qdma_hang_count;
245 + u8 adma_hang_count;
246 + } reset;
247 };
248
249 /* struct mtk_mac - the structure that holds the info about the MACs of the