dwmac5.c (53f071e19d566e7d0a4eada1bd8313a4cdb660a4) dwmac5.c (4dbbe8dde8485b89bce8bbbe7564337fd7eed69f)
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
2// Copyright (c) 2017 Synopsys, Inc. and/or its affiliates.
3// stmmac Support for 5.xx Ethernet QoS cores
4
5#include <linux/bitops.h>
6#include <linux/iopoll.h>
7#include "common.h"
8#include "dwmac4.h"
9#include "dwmac5.h"
1// SPDX-License-Identifier: (GPL-2.0 OR MIT)
2// Copyright (c) 2017 Synopsys, Inc. and/or its affiliates.
3// stmmac Support for 5.xx Ethernet QoS cores
4
5#include <linux/bitops.h>
6#include <linux/iopoll.h>
7#include "common.h"
8#include "dwmac4.h"
9#include "dwmac5.h"
10#include "stmmac.h"
10
11struct dwmac5_error_desc {
12 bool valid;
13 const char *desc;
14 const char *detailed_desc;
15};
16
17#define STAT_OFF(field) offsetof(struct stmmac_safety_stats, field)

--- 214 unchanged lines hidden (view full) ---

232 if (asp <= 0x2)
233 return 0;
234
235 value |= EPSI;
236 writel(value, ioaddr + MTL_DPP_CONTROL);
237 return 0;
238}
239
11
12struct dwmac5_error_desc {
13 bool valid;
14 const char *desc;
15 const char *detailed_desc;
16};
17
18#define STAT_OFF(field) offsetof(struct stmmac_safety_stats, field)

--- 214 unchanged lines hidden (view full) ---

233 if (asp <= 0x2)
234 return 0;
235
236 value |= EPSI;
237 writel(value, ioaddr + MTL_DPP_CONTROL);
238 return 0;
239}
240
240bool dwmac5_safety_feat_irq_status(struct net_device *ndev,
241int dwmac5_safety_feat_irq_status(struct net_device *ndev,
241 void __iomem *ioaddr, unsigned int asp,
242 struct stmmac_safety_stats *stats)
243{
242 void __iomem *ioaddr, unsigned int asp,
243 struct stmmac_safety_stats *stats)
244{
244 bool ret = false, err, corr;
245 bool err, corr;
245 u32 mtl, dma;
246 u32 mtl, dma;
247 int ret = 0;
246
247 if (!asp)
248
249 if (!asp)
248 return false;
250 return -EINVAL;
249
250 mtl = readl(ioaddr + MTL_SAFETY_INT_STATUS);
251 dma = readl(ioaddr + DMA_SAFETY_INT_STATUS);
252
253 err = (mtl & MCSIS) || (dma & MCSIS);
254 corr = false;
255 if (err) {
256 dwmac5_handle_mac_err(ndev, ioaddr, corr, stats);

--- 20 unchanged lines hidden (view full) ---

277static const struct dwmac5_error {
278 const struct dwmac5_error_desc *desc;
279} dwmac5_all_errors[] = {
280 { dwmac5_mac_errors },
281 { dwmac5_mtl_errors },
282 { dwmac5_dma_errors },
283};
284
251
252 mtl = readl(ioaddr + MTL_SAFETY_INT_STATUS);
253 dma = readl(ioaddr + DMA_SAFETY_INT_STATUS);
254
255 err = (mtl & MCSIS) || (dma & MCSIS);
256 corr = false;
257 if (err) {
258 dwmac5_handle_mac_err(ndev, ioaddr, corr, stats);

--- 20 unchanged lines hidden (view full) ---

279static const struct dwmac5_error {
280 const struct dwmac5_error_desc *desc;
281} dwmac5_all_errors[] = {
282 { dwmac5_mac_errors },
283 { dwmac5_mtl_errors },
284 { dwmac5_dma_errors },
285};
286
285const char *dwmac5_safety_feat_dump(struct stmmac_safety_stats *stats,
286 int index, unsigned long *count)
287int dwmac5_safety_feat_dump(struct stmmac_safety_stats *stats,
288 int index, unsigned long *count, const char **desc)
287{
288 int module = index / 32, offset = index % 32;
289 unsigned long *ptr = (unsigned long *)stats;
290
291 if (module >= ARRAY_SIZE(dwmac5_all_errors))
289{
290 int module = index / 32, offset = index % 32;
291 unsigned long *ptr = (unsigned long *)stats;
292
293 if (module >= ARRAY_SIZE(dwmac5_all_errors))
292 return NULL;
294 return -EINVAL;
293 if (!dwmac5_all_errors[module].desc[offset].valid)
295 if (!dwmac5_all_errors[module].desc[offset].valid)
294 return NULL;
296 return -EINVAL;
295 if (count)
296 *count = *(ptr + index);
297 if (count)
298 *count = *(ptr + index);
297 return dwmac5_all_errors[module].desc[offset].desc;
299 if (desc)
300 *desc = dwmac5_all_errors[module].desc[offset].desc;
301 return 0;
298}
302}
303
304static int dwmac5_rxp_disable(void __iomem *ioaddr)
305{
306 u32 val;
307 int ret;
308
309 val = readl(ioaddr + MTL_OPERATION_MODE);
310 val &= ~MTL_FRPE;
311 writel(val, ioaddr + MTL_OPERATION_MODE);
312
313 ret = readl_poll_timeout(ioaddr + MTL_RXP_CONTROL_STATUS, val,
314 val & RXPI, 1, 10000);
315 if (ret)
316 return ret;
317 return 0;
318}
319
320static void dwmac5_rxp_enable(void __iomem *ioaddr)
321{
322 u32 val;
323
324 val = readl(ioaddr + MTL_OPERATION_MODE);
325 val |= MTL_FRPE;
326 writel(val, ioaddr + MTL_OPERATION_MODE);
327}
328
329static int dwmac5_rxp_update_single_entry(void __iomem *ioaddr,
330 struct stmmac_tc_entry *entry,
331 int pos)
332{
333 int ret, i;
334
335 for (i = 0; i < (sizeof(entry->val) / sizeof(u32)); i++) {
336 int real_pos = pos * (sizeof(entry->val) / sizeof(u32)) + i;
337 u32 val;
338
339 /* Wait for ready */
340 ret = readl_poll_timeout(ioaddr + MTL_RXP_IACC_CTRL_STATUS,
341 val, !(val & STARTBUSY), 1, 10000);
342 if (ret)
343 return ret;
344
345 /* Write data */
346 val = *((u32 *)&entry->val + i);
347 writel(val, ioaddr + MTL_RXP_IACC_DATA);
348
349 /* Write pos */
350 val = real_pos & ADDR;
351 writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
352
353 /* Write OP */
354 val |= WRRDN;
355 writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
356
357 /* Start Write */
358 val |= STARTBUSY;
359 writel(val, ioaddr + MTL_RXP_IACC_CTRL_STATUS);
360
361 /* Wait for done */
362 ret = readl_poll_timeout(ioaddr + MTL_RXP_IACC_CTRL_STATUS,
363 val, !(val & STARTBUSY), 1, 10000);
364 if (ret)
365 return ret;
366 }
367
368 return 0;
369}
370
371static struct stmmac_tc_entry *
372dwmac5_rxp_get_next_entry(struct stmmac_tc_entry *entries, unsigned int count,
373 u32 curr_prio)
374{
375 struct stmmac_tc_entry *entry;
376 u32 min_prio = ~0x0;
377 int i, min_prio_idx;
378 bool found = false;
379
380 for (i = count - 1; i >= 0; i--) {
381 entry = &entries[i];
382
383 /* Do not update unused entries */
384 if (!entry->in_use)
385 continue;
386 /* Do not update already updated entries (i.e. fragments) */
387 if (entry->in_hw)
388 continue;
389 /* Let last entry be updated last */
390 if (entry->is_last)
391 continue;
392 /* Do not return fragments */
393 if (entry->is_frag)
394 continue;
395 /* Check if we already checked this prio */
396 if (entry->prio < curr_prio)
397 continue;
398 /* Check if this is the minimum prio */
399 if (entry->prio < min_prio) {
400 min_prio = entry->prio;
401 min_prio_idx = i;
402 found = true;
403 }
404 }
405
406 if (found)
407 return &entries[min_prio_idx];
408 return NULL;
409}
410
411int dwmac5_rxp_config(void __iomem *ioaddr, struct stmmac_tc_entry *entries,
412 unsigned int count)
413{
414 struct stmmac_tc_entry *entry, *frag;
415 int i, ret, nve = 0;
416 u32 curr_prio = 0;
417 u32 old_val, val;
418
419 /* Force disable RX */
420 old_val = readl(ioaddr + GMAC_CONFIG);
421 val = old_val & ~GMAC_CONFIG_RE;
422 writel(val, ioaddr + GMAC_CONFIG);
423
424 /* Disable RX Parser */
425 ret = dwmac5_rxp_disable(ioaddr);
426 if (ret)
427 goto re_enable;
428
429 /* Set all entries as NOT in HW */
430 for (i = 0; i < count; i++) {
431 entry = &entries[i];
432 entry->in_hw = false;
433 }
434
435 /* Update entries by reverse order */
436 while (1) {
437 entry = dwmac5_rxp_get_next_entry(entries, count, curr_prio);
438 if (!entry)
439 break;
440
441 curr_prio = entry->prio;
442 frag = entry->frag_ptr;
443
444 /* Set special fragment requirements */
445 if (frag) {
446 entry->val.af = 0;
447 entry->val.rf = 0;
448 entry->val.nc = 1;
449 entry->val.ok_index = nve + 2;
450 }
451
452 ret = dwmac5_rxp_update_single_entry(ioaddr, entry, nve);
453 if (ret)
454 goto re_enable;
455
456 entry->table_pos = nve++;
457 entry->in_hw = true;
458
459 if (frag && !frag->in_hw) {
460 ret = dwmac5_rxp_update_single_entry(ioaddr, frag, nve);
461 if (ret)
462 goto re_enable;
463 frag->table_pos = nve++;
464 frag->in_hw = true;
465 }
466 }
467
468 if (!nve)
469 goto re_enable;
470
471 /* Update all pass entry */
472 for (i = 0; i < count; i++) {
473 entry = &entries[i];
474 if (!entry->is_last)
475 continue;
476
477 ret = dwmac5_rxp_update_single_entry(ioaddr, entry, nve);
478 if (ret)
479 goto re_enable;
480
481 entry->table_pos = nve++;
482 }
483
484 /* Assume n. of parsable entries == n. of valid entries */
485 val = (nve << 16) & NPE;
486 val |= nve & NVE;
487 writel(val, ioaddr + MTL_RXP_CONTROL_STATUS);
488
489 /* Enable RX Parser */
490 dwmac5_rxp_enable(ioaddr);
491
492re_enable:
493 /* Re-enable RX */
494 writel(old_val, ioaddr + GMAC_CONFIG);
495 return ret;
496}