aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-03-30 12:32:00 -0400
committerDavid S. Miller <davem@davemloft.net>2018-03-30 12:32:00 -0400
commit8bafb83eeee2efb8b9b4e9dfd9fb90debe4a2417 (patch)
treea4a5452905bc802e15bb730470bc2b0cfb0b5dab
parent02281a3525c9f1c07d792d64b079a2d677ed0ea5 (diff)
parent8bf993a5877e8a0a2f6338085f2dee7c23f524a3 (diff)
Merge branch 'stmmac-DWMAC5'
Jose Abreu says: ==================== Fix TX Timeout and implement Safety Features Fix the TX Timeout handler to correctly reconfigure the whole system and start implementing features for DWMAC5 cores, specifically the Safety Features. Changes since v1: - Display error stats in ethtool ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h22
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4.h4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c39
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac5.c298
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac5.h52
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h12
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c39
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c101
10 files changed, 567 insertions, 8 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index ff3f83b86d10..972e4ef6d414 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -4,7 +4,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
4 chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \ 4 chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \
5 dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \ 5 dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
6 mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o \ 6 mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o dwmac4_descs.o \
7 dwmac4_dma.o dwmac4_lib.o dwmac4_core.o $(stmmac-y) 7 dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o $(stmmac-y)
8 8
9# Ordering matters. Generic driver must be last. 9# Ordering matters. Generic driver must be last.
10obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o 10obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 2ffe76c0ff74..ad2388aee463 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -38,6 +38,8 @@
38#define DWMAC_CORE_3_40 0x34 38#define DWMAC_CORE_3_40 0x34
39#define DWMAC_CORE_3_50 0x35 39#define DWMAC_CORE_3_50 0x35
40#define DWMAC_CORE_4_00 0x40 40#define DWMAC_CORE_4_00 0x40
41#define DWMAC_CORE_5_00 0x50
42#define DWMAC_CORE_5_10 0x51
41#define STMMAC_CHAN0 0 /* Always supported and default for all chips */ 43#define STMMAC_CHAN0 0 /* Always supported and default for all chips */
42 44
43/* These need to be power of two, and >= 4 */ 45/* These need to be power of two, and >= 4 */
@@ -174,6 +176,17 @@ struct stmmac_extra_stats {
174 unsigned long tx_tso_nfrags; 176 unsigned long tx_tso_nfrags;
175}; 177};
176 178
179/* Safety Feature statistics exposed by ethtool */
180struct stmmac_safety_stats {
181 unsigned long mac_errors[32];
182 unsigned long mtl_errors[32];
183 unsigned long dma_errors[32];
184};
185
186/* Number of fields in Safety Stats */
187#define STMMAC_SAFETY_FEAT_SIZE \
188 (sizeof(struct stmmac_safety_stats) / sizeof(unsigned long))
189
177/* CSR Frequency Access Defines*/ 190/* CSR Frequency Access Defines*/
178#define CSR_F_35M 35000000 191#define CSR_F_35M 35000000
179#define CSR_F_60M 60000000 192#define CSR_F_60M 60000000
@@ -336,6 +349,8 @@ struct dma_features {
336 /* TX and RX FIFO sizes */ 349 /* TX and RX FIFO sizes */
337 unsigned int tx_fifo_size; 350 unsigned int tx_fifo_size;
338 unsigned int rx_fifo_size; 351 unsigned int rx_fifo_size;
352 /* Automotive Safety Package */
353 unsigned int asp;
339}; 354};
340 355
341/* GMAC TX FIFO is 8K, Rx FIFO is 16K */ 356/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
@@ -532,6 +547,13 @@ struct stmmac_ops {
532 bool loopback); 547 bool loopback);
533 void (*pcs_rane)(void __iomem *ioaddr, bool restart); 548 void (*pcs_rane)(void __iomem *ioaddr, bool restart);
534 void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv *adv); 549 void (*pcs_get_adv_lp)(void __iomem *ioaddr, struct rgmii_adv *adv);
550 /* Safety Features */
551 int (*safety_feat_config)(void __iomem *ioaddr, unsigned int asp);
552 bool (*safety_feat_irq_status)(struct net_device *ndev,
553 void __iomem *ioaddr, unsigned int asp,
554 struct stmmac_safety_stats *stats);
555 const char *(*safety_feat_dump)(struct stmmac_safety_stats *stats,
556 int index, unsigned long *count);
535}; 557};
536 558
537/* PTP and HW Timer helpers */ 559/* PTP and HW Timer helpers */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 7761a26ec9c5..c7bff596c665 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -39,6 +39,7 @@
39#define GMAC_HW_FEATURE0 0x0000011c 39#define GMAC_HW_FEATURE0 0x0000011c
40#define GMAC_HW_FEATURE1 0x00000120 40#define GMAC_HW_FEATURE1 0x00000120
41#define GMAC_HW_FEATURE2 0x00000124 41#define GMAC_HW_FEATURE2 0x00000124
42#define GMAC_HW_FEATURE3 0x00000128
42#define GMAC_MDIO_ADDR 0x00000200 43#define GMAC_MDIO_ADDR 0x00000200
43#define GMAC_MDIO_DATA 0x00000204 44#define GMAC_MDIO_DATA 0x00000204
44#define GMAC_ADDR_HIGH(reg) (0x300 + reg * 8) 45#define GMAC_ADDR_HIGH(reg) (0x300 + reg * 8)
@@ -192,6 +193,9 @@ enum power_event {
192#define GMAC_HW_FEAT_TXQCNT GENMASK(9, 6) 193#define GMAC_HW_FEAT_TXQCNT GENMASK(9, 6)
193#define GMAC_HW_FEAT_RXQCNT GENMASK(3, 0) 194#define GMAC_HW_FEAT_RXQCNT GENMASK(3, 0)
194 195
196/* MAC HW features3 bitmap */
197#define GMAC_HW_FEAT_ASP GENMASK(29, 28)
198
195/* MAC HW ADDR regs */ 199/* MAC HW ADDR regs */
196#define GMAC_HI_DCS GENMASK(18, 16) 200#define GMAC_HI_DCS GENMASK(18, 16)
197#define GMAC_HI_DCS_SHIFT 16 201#define GMAC_HI_DCS_SHIFT 16
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index 46b9ae20ff6c..a3af92ebbca8 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -20,6 +20,7 @@
20#include <net/dsa.h> 20#include <net/dsa.h>
21#include "stmmac_pcs.h" 21#include "stmmac_pcs.h"
22#include "dwmac4.h" 22#include "dwmac4.h"
23#include "dwmac5.h"
23 24
24static void dwmac4_core_init(struct mac_device_info *hw, 25static void dwmac4_core_init(struct mac_device_info *hw,
25 struct net_device *dev) 26 struct net_device *dev)
@@ -768,6 +769,40 @@ static const struct stmmac_ops dwmac410_ops = {
768 .set_filter = dwmac4_set_filter, 769 .set_filter = dwmac4_set_filter,
769}; 770};
770 771
772static const struct stmmac_ops dwmac510_ops = {
773 .core_init = dwmac4_core_init,
774 .set_mac = stmmac_dwmac4_set_mac,
775 .rx_ipc = dwmac4_rx_ipc_enable,
776 .rx_queue_enable = dwmac4_rx_queue_enable,
777 .rx_queue_prio = dwmac4_rx_queue_priority,
778 .tx_queue_prio = dwmac4_tx_queue_priority,
779 .rx_queue_routing = dwmac4_rx_queue_routing,
780 .prog_mtl_rx_algorithms = dwmac4_prog_mtl_rx_algorithms,
781 .prog_mtl_tx_algorithms = dwmac4_prog_mtl_tx_algorithms,
782 .set_mtl_tx_queue_weight = dwmac4_set_mtl_tx_queue_weight,
783 .map_mtl_to_dma = dwmac4_map_mtl_dma,
784 .config_cbs = dwmac4_config_cbs,
785 .dump_regs = dwmac4_dump_regs,
786 .host_irq_status = dwmac4_irq_status,
787 .host_mtl_irq_status = dwmac4_irq_mtl_status,
788 .flow_ctrl = dwmac4_flow_ctrl,
789 .pmt = dwmac4_pmt,
790 .set_umac_addr = dwmac4_set_umac_addr,
791 .get_umac_addr = dwmac4_get_umac_addr,
792 .set_eee_mode = dwmac4_set_eee_mode,
793 .reset_eee_mode = dwmac4_reset_eee_mode,
794 .set_eee_timer = dwmac4_set_eee_timer,
795 .set_eee_pls = dwmac4_set_eee_pls,
796 .pcs_ctrl_ane = dwmac4_ctrl_ane,
797 .pcs_rane = dwmac4_rane,
798 .pcs_get_adv_lp = dwmac4_get_adv_lp,
799 .debug = dwmac4_debug,
800 .set_filter = dwmac4_set_filter,
801 .safety_feat_config = dwmac5_safety_feat_config,
802 .safety_feat_irq_status = dwmac5_safety_feat_irq_status,
803 .safety_feat_dump = dwmac5_safety_feat_dump,
804};
805
771struct mac_device_info *dwmac4_setup(void __iomem *ioaddr, int mcbins, 806struct mac_device_info *dwmac4_setup(void __iomem *ioaddr, int mcbins,
772 int perfect_uc_entries, int *synopsys_id) 807 int perfect_uc_entries, int *synopsys_id)
773{ 808{
@@ -808,7 +843,9 @@ struct mac_device_info *dwmac4_setup(void __iomem *ioaddr, int mcbins,
808 else 843 else
809 mac->dma = &dwmac4_dma_ops; 844 mac->dma = &dwmac4_dma_ops;
810 845
811 if (*synopsys_id >= DWMAC_CORE_4_00) 846 if (*synopsys_id >= DWMAC_CORE_5_10)
847 mac->mac = &dwmac510_ops;
848 else if (*synopsys_id >= DWMAC_CORE_4_00)
812 mac->mac = &dwmac410_ops; 849 mac->mac = &dwmac410_ops;
813 else 850 else
814 mac->mac = &dwmac4_ops; 851 mac->mac = &dwmac4_ops;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index c110f6850ffa..d37d457306d1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -373,6 +373,12 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr,
373 373
374 /* IEEE 1588-2002 */ 374 /* IEEE 1588-2002 */
375 dma_cap->time_stamp = 0; 375 dma_cap->time_stamp = 0;
376
377 /* MAC HW feature3 */
378 hw_cap = readl(ioaddr + GMAC_HW_FEATURE3);
379
380 /* 5.10 Features */
381 dma_cap->asp = (hw_cap & GMAC_HW_FEAT_ASP) >> 28;
376} 382}
377 383
378/* Enable/disable TSO feature and set MSS */ 384/* Enable/disable TSO feature and set MSS */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.c b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
new file mode 100644
index 000000000000..860de39999c7
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.c
@@ -0,0 +1,298 @@
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
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)
18
19static void dwmac5_log_error(struct net_device *ndev, u32 value, bool corr,
20 const char *module_name, const struct dwmac5_error_desc *desc,
21 unsigned long field_offset, struct stmmac_safety_stats *stats)
22{
23 unsigned long loc, mask;
24 u8 *bptr = (u8 *)stats;
25 unsigned long *ptr;
26
27 ptr = (unsigned long *)(bptr + field_offset);
28
29 mask = value;
30 for_each_set_bit(loc, &mask, 32) {
31 netdev_err(ndev, "Found %s error in %s: '%s: %s'\n", corr ?
32 "correctable" : "uncorrectable", module_name,
33 desc[loc].desc, desc[loc].detailed_desc);
34
35 /* Update counters */
36 ptr[loc]++;
37 }
38}
39
40static const struct dwmac5_error_desc dwmac5_mac_errors[32]= {
41 { true, "ATPES", "Application Transmit Interface Parity Check Error" },
42 { true, "TPES", "TSO Data Path Parity Check Error" },
43 { true, "RDPES", "Read Descriptor Parity Check Error" },
44 { true, "MPES", "MTL Data Path Parity Check Error" },
45 { true, "MTSPES", "MTL TX Status Data Path Parity Check Error" },
46 { true, "ARPES", "Application Receive Interface Data Path Parity Check Error" },
47 { true, "CWPES", "CSR Write Data Path Parity Check Error" },
48 { true, "ASRPES", "AXI Slave Read Data Path Parity Check Error" },
49 { true, "TTES", "TX FSM Timeout Error" },
50 { true, "RTES", "RX FSM Timeout Error" },
51 { true, "CTES", "CSR FSM Timeout Error" },
52 { true, "ATES", "APP FSM Timeout Error" },
53 { true, "PTES", "PTP FSM Timeout Error" },
54 { true, "T125ES", "TX125 FSM Timeout Error" },
55 { true, "R125ES", "RX125 FSM Timeout Error" },
56 { true, "RVCTES", "REV MDC FSM Timeout Error" },
57 { true, "MSTTES", "Master Read/Write Timeout Error" },
58 { true, "SLVTES", "Slave Read/Write Timeout Error" },
59 { true, "ATITES", "Application Timeout on ATI Interface Error" },
60 { true, "ARITES", "Application Timeout on ARI Interface Error" },
61 { false, "UNKNOWN", "Unknown Error" }, /* 20 */
62 { false, "UNKNOWN", "Unknown Error" }, /* 21 */
63 { false, "UNKNOWN", "Unknown Error" }, /* 22 */
64 { false, "UNKNOWN", "Unknown Error" }, /* 23 */
65 { true, "FSMPES", "FSM State Parity Error" },
66 { false, "UNKNOWN", "Unknown Error" }, /* 25 */
67 { false, "UNKNOWN", "Unknown Error" }, /* 26 */
68 { false, "UNKNOWN", "Unknown Error" }, /* 27 */
69 { false, "UNKNOWN", "Unknown Error" }, /* 28 */
70 { false, "UNKNOWN", "Unknown Error" }, /* 29 */
71 { false, "UNKNOWN", "Unknown Error" }, /* 30 */
72 { false, "UNKNOWN", "Unknown Error" }, /* 31 */
73};
74
75static void dwmac5_handle_mac_err(struct net_device *ndev,
76 void __iomem *ioaddr, bool correctable,
77 struct stmmac_safety_stats *stats)
78{
79 u32 value;
80
81 value = readl(ioaddr + MAC_DPP_FSM_INT_STATUS);
82 writel(value, ioaddr + MAC_DPP_FSM_INT_STATUS);
83
84 dwmac5_log_error(ndev, value, correctable, "MAC", dwmac5_mac_errors,
85 STAT_OFF(mac_errors), stats);
86}
87
88static const struct dwmac5_error_desc dwmac5_mtl_errors[32]= {
89 { true, "TXCES", "MTL TX Memory Error" },
90 { true, "TXAMS", "MTL TX Memory Address Mismatch Error" },
91 { true, "TXUES", "MTL TX Memory Error" },
92 { false, "UNKNOWN", "Unknown Error" }, /* 3 */
93 { true, "RXCES", "MTL RX Memory Error" },
94 { true, "RXAMS", "MTL RX Memory Address Mismatch Error" },
95 { true, "RXUES", "MTL RX Memory Error" },
96 { false, "UNKNOWN", "Unknown Error" }, /* 7 */
97 { true, "ECES", "MTL EST Memory Error" },
98 { true, "EAMS", "MTL EST Memory Address Mismatch Error" },
99 { true, "EUES", "MTL EST Memory Error" },
100 { false, "UNKNOWN", "Unknown Error" }, /* 11 */
101 { true, "RPCES", "MTL RX Parser Memory Error" },
102 { true, "RPAMS", "MTL RX Parser Memory Address Mismatch Error" },
103 { true, "RPUES", "MTL RX Parser Memory Error" },
104 { false, "UNKNOWN", "Unknown Error" }, /* 15 */
105 { false, "UNKNOWN", "Unknown Error" }, /* 16 */
106 { false, "UNKNOWN", "Unknown Error" }, /* 17 */
107 { false, "UNKNOWN", "Unknown Error" }, /* 18 */
108 { false, "UNKNOWN", "Unknown Error" }, /* 19 */
109 { false, "UNKNOWN", "Unknown Error" }, /* 20 */
110 { false, "UNKNOWN", "Unknown Error" }, /* 21 */
111 { false, "UNKNOWN", "Unknown Error" }, /* 22 */
112 { false, "UNKNOWN", "Unknown Error" }, /* 23 */
113 { false, "UNKNOWN", "Unknown Error" }, /* 24 */
114 { false, "UNKNOWN", "Unknown Error" }, /* 25 */
115 { false, "UNKNOWN", "Unknown Error" }, /* 26 */
116 { false, "UNKNOWN", "Unknown Error" }, /* 27 */
117 { false, "UNKNOWN", "Unknown Error" }, /* 28 */
118 { false, "UNKNOWN", "Unknown Error" }, /* 29 */
119 { false, "UNKNOWN", "Unknown Error" }, /* 30 */
120 { false, "UNKNOWN", "Unknown Error" }, /* 31 */
121};
122
123static void dwmac5_handle_mtl_err(struct net_device *ndev,
124 void __iomem *ioaddr, bool correctable,
125 struct stmmac_safety_stats *stats)
126{
127 u32 value;
128
129 value = readl(ioaddr + MTL_ECC_INT_STATUS);
130 writel(value, ioaddr + MTL_ECC_INT_STATUS);
131
132 dwmac5_log_error(ndev, value, correctable, "MTL", dwmac5_mtl_errors,
133 STAT_OFF(mtl_errors), stats);
134}
135
136static const struct dwmac5_error_desc dwmac5_dma_errors[32]= {
137 { true, "TCES", "DMA TSO Memory Error" },
138 { true, "TAMS", "DMA TSO Memory Address Mismatch Error" },
139 { true, "TUES", "DMA TSO Memory Error" },
140 { false, "UNKNOWN", "Unknown Error" }, /* 3 */
141 { false, "UNKNOWN", "Unknown Error" }, /* 4 */
142 { false, "UNKNOWN", "Unknown Error" }, /* 5 */
143 { false, "UNKNOWN", "Unknown Error" }, /* 6 */
144 { false, "UNKNOWN", "Unknown Error" }, /* 7 */
145 { false, "UNKNOWN", "Unknown Error" }, /* 8 */
146 { false, "UNKNOWN", "Unknown Error" }, /* 9 */
147 { false, "UNKNOWN", "Unknown Error" }, /* 10 */
148 { false, "UNKNOWN", "Unknown Error" }, /* 11 */
149 { false, "UNKNOWN", "Unknown Error" }, /* 12 */
150 { false, "UNKNOWN", "Unknown Error" }, /* 13 */
151 { false, "UNKNOWN", "Unknown Error" }, /* 14 */
152 { false, "UNKNOWN", "Unknown Error" }, /* 15 */
153 { false, "UNKNOWN", "Unknown Error" }, /* 16 */
154 { false, "UNKNOWN", "Unknown Error" }, /* 17 */
155 { false, "UNKNOWN", "Unknown Error" }, /* 18 */
156 { false, "UNKNOWN", "Unknown Error" }, /* 19 */
157 { false, "UNKNOWN", "Unknown Error" }, /* 20 */
158 { false, "UNKNOWN", "Unknown Error" }, /* 21 */
159 { false, "UNKNOWN", "Unknown Error" }, /* 22 */
160 { false, "UNKNOWN", "Unknown Error" }, /* 23 */
161 { false, "UNKNOWN", "Unknown Error" }, /* 24 */
162 { false, "UNKNOWN", "Unknown Error" }, /* 25 */
163 { false, "UNKNOWN", "Unknown Error" }, /* 26 */
164 { false, "UNKNOWN", "Unknown Error" }, /* 27 */
165 { false, "UNKNOWN", "Unknown Error" }, /* 28 */
166 { false, "UNKNOWN", "Unknown Error" }, /* 29 */
167 { false, "UNKNOWN", "Unknown Error" }, /* 30 */
168 { false, "UNKNOWN", "Unknown Error" }, /* 31 */
169};
170
171static void dwmac5_handle_dma_err(struct net_device *ndev,
172 void __iomem *ioaddr, bool correctable,
173 struct stmmac_safety_stats *stats)
174{
175 u32 value;
176
177 value = readl(ioaddr + DMA_ECC_INT_STATUS);
178 writel(value, ioaddr + DMA_ECC_INT_STATUS);
179
180 dwmac5_log_error(ndev, value, correctable, "DMA", dwmac5_dma_errors,
181 STAT_OFF(dma_errors), stats);
182}
183
184int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp)
185{
186 u32 value;
187
188 if (!asp)
189 return -EINVAL;
190
191 /* 1. Enable Safety Features */
192 value = readl(ioaddr + MTL_ECC_CONTROL);
193 value |= TSOEE; /* TSO ECC */
194 value |= MRXPEE; /* MTL RX Parser ECC */
195 value |= MESTEE; /* MTL EST ECC */
196 value |= MRXEE; /* MTL RX FIFO ECC */
197 value |= MTXEE; /* MTL TX FIFO ECC */
198 writel(value, ioaddr + MTL_ECC_CONTROL);
199
200 /* 2. Enable MTL Safety Interrupts */
201 value = readl(ioaddr + MTL_ECC_INT_ENABLE);
202 value |= RPCEIE; /* RX Parser Memory Correctable Error */
203 value |= ECEIE; /* EST Memory Correctable Error */
204 value |= RXCEIE; /* RX Memory Correctable Error */
205 value |= TXCEIE; /* TX Memory Correctable Error */
206 writel(value, ioaddr + MTL_ECC_INT_ENABLE);
207
208 /* 3. Enable DMA Safety Interrupts */
209 value = readl(ioaddr + DMA_ECC_INT_ENABLE);
210 value |= TCEIE; /* TSO Memory Correctable Error */
211 writel(value, ioaddr + DMA_ECC_INT_ENABLE);
212
213 /* Only ECC Protection for External Memory feature is selected */
214 if (asp <= 0x1)
215 return 0;
216
217 /* 5. Enable Parity and Timeout for FSM */
218 value = readl(ioaddr + MAC_FSM_CONTROL);
219 value |= PRTYEN; /* FSM Parity Feature */
220 value |= TMOUTEN; /* FSM Timeout Feature */
221 writel(value, ioaddr + MAC_FSM_CONTROL);
222
223 /* 4. Enable Data Parity Protection */
224 value = readl(ioaddr + MTL_DPP_CONTROL);
225 value |= EDPP;
226 writel(value, ioaddr + MTL_DPP_CONTROL);
227
228 /*
229 * All the Automotive Safety features are selected without the "Parity
230 * Port Enable for external interface" feature.
231 */
232 if (asp <= 0x2)
233 return 0;
234
235 value |= EPSI;
236 writel(value, ioaddr + MTL_DPP_CONTROL);
237 return 0;
238}
239
240bool dwmac5_safety_feat_irq_status(struct net_device *ndev,
241 void __iomem *ioaddr, unsigned int asp,
242 struct stmmac_safety_stats *stats)
243{
244 bool ret = false, err, corr;
245 u32 mtl, dma;
246
247 if (!asp)
248 return false;
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);
257 ret |= !corr;
258 }
259
260 err = (mtl & (MEUIS | MECIS)) || (dma & (MSUIS | MSCIS));
261 corr = (mtl & MECIS) || (dma & MSCIS);
262 if (err) {
263 dwmac5_handle_mtl_err(ndev, ioaddr, corr, stats);
264 ret |= !corr;
265 }
266
267 err = dma & (DEUIS | DECIS);
268 corr = dma & DECIS;
269 if (err) {
270 dwmac5_handle_dma_err(ndev, ioaddr, corr, stats);
271 ret |= !corr;
272 }
273
274 return ret;
275}
276
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
285const char *dwmac5_safety_feat_dump(struct stmmac_safety_stats *stats,
286 int index, unsigned long *count)
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))
292 return NULL;
293 if (!dwmac5_all_errors[module].desc[offset].valid)
294 return NULL;
295 if (count)
296 *count = *(ptr + index);
297 return dwmac5_all_errors[module].desc[offset].desc;
298}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac5.h b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
new file mode 100644
index 000000000000..a0d2c44711b9
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac5.h
@@ -0,0 +1,52 @@
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#ifndef __DWMAC5_H__
6#define __DWMAC5_H__
7
8#define MAC_DPP_FSM_INT_STATUS 0x00000140
9#define MAC_AXI_SLV_DPE_ADDR_STATUS 0x00000144
10#define MAC_FSM_CONTROL 0x00000148
11#define PRTYEN BIT(1)
12#define TMOUTEN BIT(0)
13
14#define MTL_ECC_CONTROL 0x00000cc0
15#define TSOEE BIT(4)
16#define MRXPEE BIT(3)
17#define MESTEE BIT(2)
18#define MRXEE BIT(1)
19#define MTXEE BIT(0)
20
21#define MTL_SAFETY_INT_STATUS 0x00000cc4
22#define MCSIS BIT(31)
23#define MEUIS BIT(1)
24#define MECIS BIT(0)
25#define MTL_ECC_INT_ENABLE 0x00000cc8
26#define RPCEIE BIT(12)
27#define ECEIE BIT(8)
28#define RXCEIE BIT(4)
29#define TXCEIE BIT(0)
30#define MTL_ECC_INT_STATUS 0x00000ccc
31#define MTL_DPP_CONTROL 0x00000ce0
32#define EPSI BIT(2)
33#define OPE BIT(1)
34#define EDPP BIT(0)
35
36#define DMA_SAFETY_INT_STATUS 0x00001080
37#define MSUIS BIT(29)
38#define MSCIS BIT(28)
39#define DEUIS BIT(1)
40#define DECIS BIT(0)
41#define DMA_ECC_INT_ENABLE 0x00001084
42#define TCEIE BIT(0)
43#define DMA_ECC_INT_STATUS 0x00001088
44
45int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp);
46bool dwmac5_safety_feat_irq_status(struct net_device *ndev,
47 void __iomem *ioaddr, unsigned int asp,
48 struct stmmac_safety_stats *stats);
49const char *dwmac5_safety_feat_dump(struct stmmac_safety_stats *stats,
50 int index, unsigned long *count);
51
52#endif /* __DWMAC5_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 75161e1b7e55..da50451f8999 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -114,6 +114,7 @@ struct stmmac_priv {
114 int mii_irq[PHY_MAX_ADDR]; 114 int mii_irq[PHY_MAX_ADDR];
115 115
116 struct stmmac_extra_stats xstats ____cacheline_aligned_in_smp; 116 struct stmmac_extra_stats xstats ____cacheline_aligned_in_smp;
117 struct stmmac_safety_stats sstats;
117 struct plat_stmmacenet_data *plat; 118 struct plat_stmmacenet_data *plat;
118 struct dma_features dma_cap; 119 struct dma_features dma_cap;
119 struct stmmac_counters mmc; 120 struct stmmac_counters mmc;
@@ -145,6 +146,17 @@ struct stmmac_priv {
145 struct dentry *dbgfs_rings_status; 146 struct dentry *dbgfs_rings_status;
146 struct dentry *dbgfs_dma_cap; 147 struct dentry *dbgfs_dma_cap;
147#endif 148#endif
149
150 unsigned long state;
151 struct workqueue_struct *wq;
152 struct work_struct service_task;
153};
154
155enum stmmac_state {
156 STMMAC_DOWN,
157 STMMAC_RESET_REQUESTED,
158 STMMAC_RESETING,
159 STMMAC_SERVICE_SCHED,
148}; 160};
149 161
150int stmmac_mdio_unregister(struct net_device *ndev); 162int stmmac_mdio_unregister(struct net_device *ndev);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index af30b4857c3b..2c6ed47704fc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -523,11 +523,23 @@ stmmac_set_pauseparam(struct net_device *netdev,
523static void stmmac_get_ethtool_stats(struct net_device *dev, 523static void stmmac_get_ethtool_stats(struct net_device *dev,
524 struct ethtool_stats *dummy, u64 *data) 524 struct ethtool_stats *dummy, u64 *data)
525{ 525{
526 const char *(*dump)(struct stmmac_safety_stats *stats, int index,
527 unsigned long *count);
526 struct stmmac_priv *priv = netdev_priv(dev); 528 struct stmmac_priv *priv = netdev_priv(dev);
527 u32 rx_queues_count = priv->plat->rx_queues_to_use; 529 u32 rx_queues_count = priv->plat->rx_queues_to_use;
528 u32 tx_queues_count = priv->plat->tx_queues_to_use; 530 u32 tx_queues_count = priv->plat->tx_queues_to_use;
531 unsigned long count;
529 int i, j = 0; 532 int i, j = 0;
530 533
534 if (priv->dma_cap.asp && priv->hw->mac->safety_feat_dump) {
535 dump = priv->hw->mac->safety_feat_dump;
536
537 for (i = 0; i < STMMAC_SAFETY_FEAT_SIZE; i++) {
538 if (dump(&priv->sstats, i, &count))
539 data[j++] = count;
540 }
541 }
542
531 /* Update the DMA HW counters for dwmac10/100 */ 543 /* Update the DMA HW counters for dwmac10/100 */
532 if (priv->hw->dma->dma_diagnostic_fr) 544 if (priv->hw->dma->dma_diagnostic_fr)
533 priv->hw->dma->dma_diagnostic_fr(&dev->stats, 545 priv->hw->dma->dma_diagnostic_fr(&dev->stats,
@@ -569,7 +581,9 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
569static int stmmac_get_sset_count(struct net_device *netdev, int sset) 581static int stmmac_get_sset_count(struct net_device *netdev, int sset)
570{ 582{
571 struct stmmac_priv *priv = netdev_priv(netdev); 583 struct stmmac_priv *priv = netdev_priv(netdev);
572 int len; 584 const char *(*dump)(struct stmmac_safety_stats *stats, int index,
585 unsigned long *count);
586 int i, len, safety_len = 0;
573 587
574 switch (sset) { 588 switch (sset) {
575 case ETH_SS_STATS: 589 case ETH_SS_STATS:
@@ -577,6 +591,16 @@ static int stmmac_get_sset_count(struct net_device *netdev, int sset)
577 591
578 if (priv->dma_cap.rmon) 592 if (priv->dma_cap.rmon)
579 len += STMMAC_MMC_STATS_LEN; 593 len += STMMAC_MMC_STATS_LEN;
594 if (priv->dma_cap.asp && priv->hw->mac->safety_feat_dump) {
595 dump = priv->hw->mac->safety_feat_dump;
596
597 for (i = 0; i < STMMAC_SAFETY_FEAT_SIZE; i++) {
598 if (dump(&priv->sstats, i, NULL))
599 safety_len++;
600 }
601
602 len += safety_len;
603 }
580 604
581 return len; 605 return len;
582 default: 606 default:
@@ -589,9 +613,22 @@ static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
589 int i; 613 int i;
590 u8 *p = data; 614 u8 *p = data;
591 struct stmmac_priv *priv = netdev_priv(dev); 615 struct stmmac_priv *priv = netdev_priv(dev);
616 const char *(*dump)(struct stmmac_safety_stats *stats, int index,
617 unsigned long *count);
592 618
593 switch (stringset) { 619 switch (stringset) {
594 case ETH_SS_STATS: 620 case ETH_SS_STATS:
621 if (priv->dma_cap.asp && priv->hw->mac->safety_feat_dump) {
622 dump = priv->hw->mac->safety_feat_dump;
623 for (i = 0; i < STMMAC_SAFETY_FEAT_SIZE; i++) {
624 const char *desc = dump(&priv->sstats, i, NULL);
625
626 if (desc) {
627 memcpy(p, desc, ETH_GSTRING_LEN);
628 p += ETH_GSTRING_LEN;
629 }
630 }
631 }
595 if (priv->dma_cap.rmon) 632 if (priv->dma_cap.rmon)
596 for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) { 633 for (i = 0; i < STMMAC_MMC_STATS_LEN; i++) {
597 memcpy(p, stmmac_mmc[i].stat_string, 634 memcpy(p, stmmac_mmc[i].stat_string,
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 9f983dd069d5..9a16931ce39d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -196,6 +196,20 @@ static void stmmac_start_all_queues(struct stmmac_priv *priv)
196 netif_tx_start_queue(netdev_get_tx_queue(priv->dev, queue)); 196 netif_tx_start_queue(netdev_get_tx_queue(priv->dev, queue));
197} 197}
198 198
199static void stmmac_service_event_schedule(struct stmmac_priv *priv)
200{
201 if (!test_bit(STMMAC_DOWN, &priv->state) &&
202 !test_and_set_bit(STMMAC_SERVICE_SCHED, &priv->state))
203 queue_work(priv->wq, &priv->service_task);
204}
205
206static void stmmac_global_err(struct stmmac_priv *priv)
207{
208 netif_carrier_off(priv->dev);
209 set_bit(STMMAC_RESET_REQUESTED, &priv->state);
210 stmmac_service_event_schedule(priv);
211}
212
199/** 213/**
200 * stmmac_clk_csr_set - dynamically set the MDC clock 214 * stmmac_clk_csr_set - dynamically set the MDC clock
201 * @priv: driver private structure 215 * @priv: driver private structure
@@ -2000,6 +2014,22 @@ static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode,
2000 } 2014 }
2001} 2015}
2002 2016
2017static bool stmmac_safety_feat_interrupt(struct stmmac_priv *priv)
2018{
2019 bool ret = false;
2020
2021 /* Safety features are only available in cores >= 5.10 */
2022 if (priv->synopsys_id < DWMAC_CORE_5_10)
2023 return ret;
2024 if (priv->hw->mac->safety_feat_irq_status)
2025 ret = priv->hw->mac->safety_feat_irq_status(priv->dev,
2026 priv->ioaddr, priv->dma_cap.asp, &priv->sstats);
2027
2028 if (ret)
2029 stmmac_global_err(priv);
2030 return ret;
2031}
2032
2003/** 2033/**
2004 * stmmac_dma_interrupt - DMA ISR 2034 * stmmac_dma_interrupt - DMA ISR
2005 * @priv: driver private structure 2035 * @priv: driver private structure
@@ -2489,6 +2519,17 @@ static void stmmac_mtl_configuration(struct stmmac_priv *priv)
2489 stmmac_mac_config_rx_queues_routing(priv); 2519 stmmac_mac_config_rx_queues_routing(priv);
2490} 2520}
2491 2521
2522static void stmmac_safety_feat_configuration(struct stmmac_priv *priv)
2523{
2524 if (priv->hw->mac->safety_feat_config && priv->dma_cap.asp) {
2525 netdev_info(priv->dev, "Enabling Safety Features\n");
2526 priv->hw->mac->safety_feat_config(priv->ioaddr,
2527 priv->dma_cap.asp);
2528 } else {
2529 netdev_info(priv->dev, "No Safety Features support found\n");
2530 }
2531}
2532
2492/** 2533/**
2493 * stmmac_hw_setup - setup mac in a usable state. 2534 * stmmac_hw_setup - setup mac in a usable state.
2494 * @dev : pointer to the device structure. 2535 * @dev : pointer to the device structure.
@@ -2540,6 +2581,10 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
2540 if (priv->synopsys_id >= DWMAC_CORE_4_00) 2581 if (priv->synopsys_id >= DWMAC_CORE_4_00)
2541 stmmac_mtl_configuration(priv); 2582 stmmac_mtl_configuration(priv);
2542 2583
2584 /* Initialize Safety Features */
2585 if (priv->synopsys_id >= DWMAC_CORE_5_10)
2586 stmmac_safety_feat_configuration(priv);
2587
2543 ret = priv->hw->mac->rx_ipc(priv->hw); 2588 ret = priv->hw->mac->rx_ipc(priv->hw);
2544 if (!ret) { 2589 if (!ret) {
2545 netdev_warn(priv->dev, "RX IPC Checksum Offload disabled\n"); 2590 netdev_warn(priv->dev, "RX IPC Checksum Offload disabled\n");
@@ -3587,12 +3632,8 @@ static int stmmac_poll(struct napi_struct *napi, int budget)
3587static void stmmac_tx_timeout(struct net_device *dev) 3632static void stmmac_tx_timeout(struct net_device *dev)
3588{ 3633{
3589 struct stmmac_priv *priv = netdev_priv(dev); 3634 struct stmmac_priv *priv = netdev_priv(dev);
3590 u32 tx_count = priv->plat->tx_queues_to_use;
3591 u32 chan;
3592 3635
3593 /* Clear Tx resources and restart transmitting again */ 3636 stmmac_global_err(priv);
3594 for (chan = 0; chan < tx_count; chan++)
3595 stmmac_tx_err(priv, chan);
3596} 3637}
3597 3638
3598/** 3639/**
@@ -3716,6 +3757,13 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
3716 return IRQ_NONE; 3757 return IRQ_NONE;
3717 } 3758 }
3718 3759
3760 /* Check if adapter is up */
3761 if (test_bit(STMMAC_DOWN, &priv->state))
3762 return IRQ_HANDLED;
3763 /* Check if a fatal error happened */
3764 if (stmmac_safety_feat_interrupt(priv))
3765 return IRQ_HANDLED;
3766
3719 /* To handle GMAC own interrupts */ 3767 /* To handle GMAC own interrupts */
3720 if ((priv->plat->has_gmac) || (priv->plat->has_gmac4)) { 3768 if ((priv->plat->has_gmac) || (priv->plat->has_gmac4)) {
3721 int status = priv->hw->mac->host_irq_status(priv->hw, 3769 int status = priv->hw->mac->host_irq_status(priv->hw,
@@ -4051,6 +4099,37 @@ static const struct net_device_ops stmmac_netdev_ops = {
4051 .ndo_set_mac_address = stmmac_set_mac_address, 4099 .ndo_set_mac_address = stmmac_set_mac_address,
4052}; 4100};
4053 4101
4102static void stmmac_reset_subtask(struct stmmac_priv *priv)
4103{
4104 if (!test_and_clear_bit(STMMAC_RESET_REQUESTED, &priv->state))
4105 return;
4106 if (test_bit(STMMAC_DOWN, &priv->state))
4107 return;
4108
4109 netdev_err(priv->dev, "Reset adapter.\n");
4110
4111 rtnl_lock();
4112 netif_trans_update(priv->dev);
4113 while (test_and_set_bit(STMMAC_RESETING, &priv->state))
4114 usleep_range(1000, 2000);
4115
4116 set_bit(STMMAC_DOWN, &priv->state);
4117 dev_close(priv->dev);
4118 dev_open(priv->dev);
4119 clear_bit(STMMAC_DOWN, &priv->state);
4120 clear_bit(STMMAC_RESETING, &priv->state);
4121 rtnl_unlock();
4122}
4123
4124static void stmmac_service_task(struct work_struct *work)
4125{
4126 struct stmmac_priv *priv = container_of(work, struct stmmac_priv,
4127 service_task);
4128
4129 stmmac_reset_subtask(priv);
4130 clear_bit(STMMAC_SERVICE_SCHED, &priv->state);
4131}
4132
4054/** 4133/**
4055 * stmmac_hw_init - Init the MAC device 4134 * stmmac_hw_init - Init the MAC device
4056 * @priv: driver private structure 4135 * @priv: driver private structure
@@ -4212,6 +4291,15 @@ int stmmac_dvr_probe(struct device *device,
4212 /* Verify driver arguments */ 4291 /* Verify driver arguments */
4213 stmmac_verify_args(); 4292 stmmac_verify_args();
4214 4293
4294 /* Allocate workqueue */
4295 priv->wq = create_singlethread_workqueue("stmmac_wq");
4296 if (!priv->wq) {
4297 dev_err(priv->device, "failed to create workqueue\n");
4298 goto error_wq;
4299 }
4300
4301 INIT_WORK(&priv->service_task, stmmac_service_task);
4302
4215 /* Override with kernel parameters if supplied XXX CRS XXX 4303 /* Override with kernel parameters if supplied XXX CRS XXX
4216 * this needs to have multiple instances 4304 * this needs to have multiple instances
4217 */ 4305 */
@@ -4342,6 +4430,8 @@ error_mdio_register:
4342 netif_napi_del(&rx_q->napi); 4430 netif_napi_del(&rx_q->napi);
4343 } 4431 }
4344error_hw_init: 4432error_hw_init:
4433 destroy_workqueue(priv->wq);
4434error_wq:
4345 free_netdev(ndev); 4435 free_netdev(ndev);
4346 4436
4347 return ret; 4437 return ret;
@@ -4374,6 +4464,7 @@ int stmmac_dvr_remove(struct device *dev)
4374 priv->hw->pcs != STMMAC_PCS_TBI && 4464 priv->hw->pcs != STMMAC_PCS_TBI &&
4375 priv->hw->pcs != STMMAC_PCS_RTBI) 4465 priv->hw->pcs != STMMAC_PCS_RTBI)
4376 stmmac_mdio_unregister(ndev); 4466 stmmac_mdio_unregister(ndev);
4467 destroy_workqueue(priv->wq);
4377 free_netdev(ndev); 4468 free_netdev(ndev);
4378 4469
4379 return 0; 4470 return 0;