aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/stmicro
diff options
context:
space:
mode:
authorGiuseppe CAVALLARO <peppe.cavallaro@st.com>2012-11-25 18:10:43 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-26 17:22:12 -0500
commit62a2ab935c8d0f8643d02d3696abc401b5da6206 (patch)
tree621848d4f395f224faa16e576d5f5b93a63f01a2 /drivers/net/ethernet/stmicro
parent9125cdd1be1199588f71c99e76e32bcda0b7d847 (diff)
stmmac: add Rx watchdog support to mitigate the DMA irqs
GMAC devices newer than databook 3.40 has an embedded timer that can be used for mitigating the number of interrupts. So this patch adds this optimizations. At any rate, the Rx watchdog can be disable (on bugged HW) by passing from the platform the riwt_off field. In this implementation the rx timer stored in the Reg9 is fixed to the max value. This will be tuned by using ethtool. V2: added a platform parameter to force to disable the rx-watchdog for example on new core where it is bugged. V3: do not disable NAPI when Rx watchdog is used. V4: a new extra statistic field has been added to show the early receive status in the interrupt handler. This patch also adds an extra check to avoid to call napi_schedule when the DMA_INTR_ENA_RIE bit is disabled in the Interrupt Mask register. Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/stmicro')
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h17
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000.h3
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h5
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c19
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c9
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c30
8 files changed, 71 insertions, 20 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index 723e9035f275..186d14806122 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -48,6 +48,10 @@
48#define CHIP_DBG(fmt, args...) do { } while (0) 48#define CHIP_DBG(fmt, args...) do { } while (0)
49#endif 49#endif
50 50
51/* Synopsys Core versions */
52#define DWMAC_CORE_3_40 0x34
53#define DWMAC_CORE_3_50 0x35
54
51#undef FRAME_FILTER_DEBUG 55#undef FRAME_FILTER_DEBUG
52/* #define FRAME_FILTER_DEBUG */ 56/* #define FRAME_FILTER_DEBUG */
53 57
@@ -81,7 +85,7 @@ struct stmmac_extra_stats {
81 unsigned long rx_missed_cntr; 85 unsigned long rx_missed_cntr;
82 unsigned long rx_overflow_cntr; 86 unsigned long rx_overflow_cntr;
83 unsigned long rx_vlan; 87 unsigned long rx_vlan;
84 /* Tx/Rx IRQ errors */ 88 /* Tx/Rx IRQ error info */
85 unsigned long tx_undeflow_irq; 89 unsigned long tx_undeflow_irq;
86 unsigned long tx_process_stopped_irq; 90 unsigned long tx_process_stopped_irq;
87 unsigned long tx_jabber_irq; 91 unsigned long tx_jabber_irq;
@@ -91,7 +95,8 @@ struct stmmac_extra_stats {
91 unsigned long rx_watchdog_irq; 95 unsigned long rx_watchdog_irq;
92 unsigned long tx_early_irq; 96 unsigned long tx_early_irq;
93 unsigned long fatal_bus_error_irq; 97 unsigned long fatal_bus_error_irq;
94 /* Extra info */ 98 /* Tx/Rx IRQ Events */
99 unsigned long rx_early_irq;
95 unsigned long threshold; 100 unsigned long threshold;
96 unsigned long tx_pkt_n; 101 unsigned long tx_pkt_n;
97 unsigned long rx_pkt_n; 102 unsigned long rx_pkt_n;
@@ -101,11 +106,12 @@ struct stmmac_extra_stats {
101 unsigned long tx_normal_irq_n; 106 unsigned long tx_normal_irq_n;
102 unsigned long tx_clean; 107 unsigned long tx_clean;
103 unsigned long tx_reset_ic_bit; 108 unsigned long tx_reset_ic_bit;
109 unsigned long irq_receive_pmt_irq_n;
110 /* MMC info */
104 unsigned long mmc_tx_irq_n; 111 unsigned long mmc_tx_irq_n;
105 unsigned long mmc_rx_irq_n; 112 unsigned long mmc_rx_irq_n;
106 unsigned long mmc_rx_csum_offload_irq_n; 113 unsigned long mmc_rx_csum_offload_irq_n;
107 /* EEE */ 114 /* EEE */
108 unsigned long irq_receive_pmt_irq_n;
109 unsigned long irq_tx_path_in_lpi_mode_n; 115 unsigned long irq_tx_path_in_lpi_mode_n;
110 unsigned long irq_tx_path_exit_lpi_mode_n; 116 unsigned long irq_tx_path_exit_lpi_mode_n;
111 unsigned long irq_rx_path_in_lpi_mode_n; 117 unsigned long irq_rx_path_in_lpi_mode_n;
@@ -165,6 +171,9 @@ struct stmmac_extra_stats {
165#define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY interface */ 171#define DMA_HW_FEAT_ACTPHYIF 0x70000000 /* Active/selected PHY interface */
166#define DEFAULT_DMA_PBL 8 172#define DEFAULT_DMA_PBL 8
167 173
174/* Max/Min RI Watchdog Timer count value */
175#define MAX_DMA_RIWT 0xff
176#define MIN_DMA_RIWT 0x20
168/* Tx coalesce parameters */ 177/* Tx coalesce parameters */
169#define STMMAC_COAL_TX_TIMER 40000 178#define STMMAC_COAL_TX_TIMER 40000
170#define STMMAC_MAX_COAL_TX_TICK 100000 179#define STMMAC_MAX_COAL_TX_TICK 100000
@@ -306,6 +315,8 @@ struct stmmac_dma_ops {
306 struct stmmac_extra_stats *x); 315 struct stmmac_extra_stats *x);
307 /* If supported then get the optional core features */ 316 /* If supported then get the optional core features */
308 unsigned int (*get_hw_feature) (void __iomem *ioaddr); 317 unsigned int (*get_hw_feature) (void __iomem *ioaddr);
318 /* Program the HW RX Watchdog */
319 void (*rx_watchdog) (void __iomem *ioaddr, u32 riwt);
309}; 320};
310 321
311struct stmmac_ops { 322struct stmmac_ops {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index 0e4cacedc1f0..7ad56afd6324 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -230,8 +230,5 @@ enum rtc_control {
230#define GMAC_MMC_TX_INTR 0x108 230#define GMAC_MMC_TX_INTR 0x108
231#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208 231#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
232 232
233/* Synopsys Core versions */
234#define DWMAC_CORE_3_40 0x34
235
236extern const struct stmmac_dma_ops dwmac1000_dma_ops; 233extern const struct stmmac_dma_ops dwmac1000_dma_ops;
237#endif /* __DWMAC1000_H__ */ 234#endif /* __DWMAC1000_H__ */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
index 033500090f55..bf83c03bfd06 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
@@ -174,6 +174,11 @@ static unsigned int dwmac1000_get_hw_feature(void __iomem *ioaddr)
174 return readl(ioaddr + DMA_HW_FEATURE); 174 return readl(ioaddr + DMA_HW_FEATURE);
175} 175}
176 176
177static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt)
178{
179 writel(riwt, ioaddr + DMA_RX_WATCHDOG);
180}
181
177const struct stmmac_dma_ops dwmac1000_dma_ops = { 182const struct stmmac_dma_ops dwmac1000_dma_ops = {
178 .init = dwmac1000_dma_init, 183 .init = dwmac1000_dma_init,
179 .dump_regs = dwmac1000_dump_dma_regs, 184 .dump_regs = dwmac1000_dump_dma_regs,
@@ -187,4 +192,5 @@ const struct stmmac_dma_ops dwmac1000_dma_ops = {
187 .stop_rx = dwmac_dma_stop_rx, 192 .stop_rx = dwmac_dma_stop_rx,
188 .dma_interrupt = dwmac_dma_interrupt, 193 .dma_interrupt = dwmac_dma_interrupt,
189 .get_hw_feature = dwmac1000_get_hw_feature, 194 .get_hw_feature = dwmac1000_get_hw_feature,
195 .rx_watchdog = dwmac1000_rx_watchdog,
190}; 196};
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
index e49c9a0fd6ff..807f30371e49 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -35,7 +35,10 @@
35#define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */ 35#define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */
36#define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */ 36#define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */
37#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */ 37#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */
38#define DMA_AXI_BUS_MODE 0x00001028 /* AXI Bus Mode */ 38/* Rx watchdog register */
39#define DMA_RX_WATCHDOG 0x00001024
40/* AXI Bus Mode */
41#define DMA_AXI_BUS_MODE 0x00001028
39#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */ 42#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */
40#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */ 43#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */
41#define DMA_HW_FEATURE 0x00001058 /* HW Feature Register */ 44#define DMA_HW_FEATURE 0x00001058 /* HW Feature Register */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
index 73766e655011..491d7e930603 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c
@@ -204,17 +204,28 @@ int dwmac_dma_interrupt(void __iomem *ioaddr,
204 } 204 }
205 } 205 }
206 /* TX/RX NORMAL interrupts */ 206 /* TX/RX NORMAL interrupts */
207 if (intr_status & DMA_STATUS_NIS) { 207 if (likely(intr_status & DMA_STATUS_NIS)) {
208 x->normal_irq_n++; 208 x->normal_irq_n++;
209 if (likely(intr_status & DMA_STATUS_RI)) 209 if (likely(intr_status & DMA_STATUS_RI)) {
210 ret |= handle_rx; 210 u32 value = readl(ioaddr + DMA_INTR_ENA);
211 if (intr_status & (DMA_STATUS_TI)) 211 /* to schedule NAPI on real RIE event. */
212 if (likely(value & DMA_INTR_ENA_RIE)) {
213 x->rx_normal_irq_n++;
214 ret |= handle_rx;
215 }
216 }
217 if (likely(intr_status & DMA_STATUS_TI)) {
218 x->tx_normal_irq_n++;
212 ret |= handle_tx; 219 ret |= handle_tx;
220 }
221 if (unlikely(intr_status & DMA_STATUS_ERI))
222 x->rx_early_irq++;
213 } 223 }
214 /* Optional hardware blocks, interrupts should be disabled */ 224 /* Optional hardware blocks, interrupts should be disabled */
215 if (unlikely(intr_status & 225 if (unlikely(intr_status &
216 (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI))) 226 (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
217 pr_info("%s: unexpected status %08x\n", __func__, intr_status); 227 pr_info("%s: unexpected status %08x\n", __func__, intr_status);
228
218 /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */ 229 /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
219 writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS); 230 writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
220 231
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 01b34517ca8e..fe0535cd86cd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -91,6 +91,8 @@ struct stmmac_priv {
91 u32 tx_count_frames; 91 u32 tx_count_frames;
92 u32 tx_coal_frames; 92 u32 tx_coal_frames;
93 u32 tx_coal_timer; 93 u32 tx_coal_timer;
94 int use_riwt;
95 u32 rx_riwt;
94}; 96};
95 97
96extern int phyaddr; 98extern int phyaddr;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 15cb6ee6ee41..7f7ccd217e4d 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -76,7 +76,7 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
76 STMMAC_STAT(rx_missed_cntr), 76 STMMAC_STAT(rx_missed_cntr),
77 STMMAC_STAT(rx_overflow_cntr), 77 STMMAC_STAT(rx_overflow_cntr),
78 STMMAC_STAT(rx_vlan), 78 STMMAC_STAT(rx_vlan),
79 /* Tx/Rx IRQ errors */ 79 /* Tx/Rx IRQ error info */
80 STMMAC_STAT(tx_undeflow_irq), 80 STMMAC_STAT(tx_undeflow_irq),
81 STMMAC_STAT(tx_process_stopped_irq), 81 STMMAC_STAT(tx_process_stopped_irq),
82 STMMAC_STAT(tx_jabber_irq), 82 STMMAC_STAT(tx_jabber_irq),
@@ -86,7 +86,8 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
86 STMMAC_STAT(rx_watchdog_irq), 86 STMMAC_STAT(rx_watchdog_irq),
87 STMMAC_STAT(tx_early_irq), 87 STMMAC_STAT(tx_early_irq),
88 STMMAC_STAT(fatal_bus_error_irq), 88 STMMAC_STAT(fatal_bus_error_irq),
89 /* Extra info */ 89 /* Tx/Rx IRQ Events */
90 STMMAC_STAT(rx_early_irq),
90 STMMAC_STAT(threshold), 91 STMMAC_STAT(threshold),
91 STMMAC_STAT(tx_pkt_n), 92 STMMAC_STAT(tx_pkt_n),
92 STMMAC_STAT(rx_pkt_n), 93 STMMAC_STAT(rx_pkt_n),
@@ -96,10 +97,12 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
96 STMMAC_STAT(tx_normal_irq_n), 97 STMMAC_STAT(tx_normal_irq_n),
97 STMMAC_STAT(tx_clean), 98 STMMAC_STAT(tx_clean),
98 STMMAC_STAT(tx_reset_ic_bit), 99 STMMAC_STAT(tx_reset_ic_bit),
100 STMMAC_STAT(irq_receive_pmt_irq_n),
101 /* MMC info */
99 STMMAC_STAT(mmc_tx_irq_n), 102 STMMAC_STAT(mmc_tx_irq_n),
100 STMMAC_STAT(mmc_rx_irq_n), 103 STMMAC_STAT(mmc_rx_irq_n),
101 STMMAC_STAT(mmc_rx_csum_offload_irq_n), 104 STMMAC_STAT(mmc_rx_csum_offload_irq_n),
102 STMMAC_STAT(irq_receive_pmt_irq_n), 105 /* EEE */
103 STMMAC_STAT(irq_tx_path_in_lpi_mode_n), 106 STMMAC_STAT(irq_tx_path_in_lpi_mode_n),
104 STMMAC_STAT(irq_tx_path_exit_lpi_mode_n), 107 STMMAC_STAT(irq_tx_path_exit_lpi_mode_n),
105 STMMAC_STAT(irq_rx_path_in_lpi_mode_n), 108 STMMAC_STAT(irq_rx_path_in_lpi_mode_n),
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index d9d68649bdaa..542edbcd92c7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -603,6 +603,8 @@ static void init_dma_desc_rings(struct net_device *dev)
603 priv->dirty_tx = 0; 603 priv->dirty_tx = 0;
604 priv->cur_tx = 0; 604 priv->cur_tx = 0;
605 605
606 if (priv->use_riwt)
607 dis_ic = 1;
606 /* Clear the Rx/Tx descriptors */ 608 /* Clear the Rx/Tx descriptors */
607 priv->hw->desc->init_rx_desc(priv->dma_rx, rxsize, dis_ic); 609 priv->hw->desc->init_rx_desc(priv->dma_rx, rxsize, dis_ic);
608 priv->hw->desc->init_tx_desc(priv->dma_tx, txsize); 610 priv->hw->desc->init_tx_desc(priv->dma_tx, txsize);
@@ -1106,6 +1108,11 @@ static int stmmac_open(struct net_device *dev)
1106 1108
1107 stmmac_init_tx_coalesce(priv); 1109 stmmac_init_tx_coalesce(priv);
1108 1110
1111 if ((priv->use_riwt) && (priv->hw->dma->rx_watchdog)) {
1112 priv->rx_riwt = MAX_DMA_RIWT;
1113 priv->hw->dma->rx_watchdog(priv->ioaddr, MAX_DMA_RIWT);
1114 }
1115
1109 napi_enable(&priv->napi); 1116 napi_enable(&priv->napi);
1110 netif_start_queue(dev); 1117 netif_start_queue(dev);
1111 1118
@@ -1423,14 +1430,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
1423#endif 1430#endif
1424 skb->protocol = eth_type_trans(skb, priv->dev); 1431 skb->protocol = eth_type_trans(skb, priv->dev);
1425 1432
1426 if (unlikely(!priv->plat->rx_coe)) { 1433 if (unlikely(!priv->plat->rx_coe))
1427 /* No RX COE for old mac10/100 devices */
1428 skb_checksum_none_assert(skb); 1434 skb_checksum_none_assert(skb);
1429 netif_receive_skb(skb); 1435 else
1430 } else {
1431 skb->ip_summed = CHECKSUM_UNNECESSARY; 1436 skb->ip_summed = CHECKSUM_UNNECESSARY;
1432 napi_gro_receive(&priv->napi, skb); 1437
1433 } 1438 napi_gro_receive(&priv->napi, skb);
1434 1439
1435 priv->dev->stats.rx_packets++; 1440 priv->dev->stats.rx_packets++;
1436 priv->dev->stats.rx_bytes += frame_len; 1441 priv->dev->stats.rx_bytes += frame_len;
@@ -2001,6 +2006,16 @@ struct stmmac_priv *stmmac_dvr_probe(struct device *device,
2001 if (flow_ctrl) 2006 if (flow_ctrl)
2002 priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */ 2007 priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */
2003 2008
2009 /* Rx Watchdog is available in the COREs newer than the 3.40.
2010 * In some case, for example on bugged HW this feature
2011 * has to be disable and this can be done by passing the
2012 * riwt_off field from the platform.
2013 */
2014 if ((priv->synopsys_id >= DWMAC_CORE_3_50) && (!priv->plat->riwt_off)) {
2015 priv->use_riwt = 1;
2016 pr_info(" Enable RX Mitigation via HW Watchdog Timer\n");
2017 }
2018
2004 netif_napi_add(ndev, &priv->napi, stmmac_poll, 64); 2019 netif_napi_add(ndev, &priv->napi, stmmac_poll, 64);
2005 2020
2006 spin_lock_init(&priv->lock); 2021 spin_lock_init(&priv->lock);
@@ -2092,6 +2107,9 @@ int stmmac_suspend(struct net_device *ndev)
2092 netif_device_detach(ndev); 2107 netif_device_detach(ndev);
2093 netif_stop_queue(ndev); 2108 netif_stop_queue(ndev);
2094 2109
2110 if (priv->use_riwt)
2111 dis_ic = 1;
2112
2095 napi_disable(&priv->napi); 2113 napi_disable(&priv->napi);
2096 2114
2097 /* Stop TX/RX DMA */ 2115 /* Stop TX/RX DMA */