aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/stmicro/stmmac
diff options
context:
space:
mode:
authorGiuseppe CAVALLARO <peppe.cavallaro@st.com>2012-06-27 17:14:37 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-01 06:34:50 -0400
commitd765955d2ae0b88781a0db3a5bacfe4241925e09 (patch)
treee1906652617da85d0168b5cfe84219f69403e3d0 /drivers/net/ethernet/stmicro/stmmac
parent0ec2ccd0804ebb57a860c59d056a3f420c4f8028 (diff)
stmmac: add the Energy Efficient Ethernet support
This patch adds the Energy Efficient Ethernet support to the stmmac. Please see the driver's documentation for further details about this support in the driver. Thanks also goes to Rayagond Kokatanur for his first implementation. Note: to clearly manage and expose the lpi interrupt status and eee ethtool stats I've had to do some modifications to the driver's design and I found really useful to move other parts of the code (e.g. mmc irq stat) in the main directly. So this means that some core has been reworked to introduce the EEE. v1: initial patch v2: fixed some sparse issues (typos) v3: erroneously sent the v2 renamed as v3 v4: o Fixed the return value of the stmmac_eee_init as suggested by D.Miller o Totally reviewed the ethtool support for EEE o Added a new internal parameter to tune the SW timer for TX LPI. v5: do not change any eee setting in case of the stmmac_ethtool_op_set_eee fails (it has to return -EOPNOTSUPP in that case). 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/stmmac')
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/common.h31
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000.h20
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c101
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h1
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac.h8
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c57
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c166
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c2
9 files changed, 372 insertions, 18 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index bcd54d6e94fd..e2d083228f3a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -95,6 +95,16 @@ struct stmmac_extra_stats {
95 unsigned long poll_n; 95 unsigned long poll_n;
96 unsigned long sched_timer_n; 96 unsigned long sched_timer_n;
97 unsigned long normal_irq_n; 97 unsigned long normal_irq_n;
98 unsigned long mmc_tx_irq_n;
99 unsigned long mmc_rx_irq_n;
100 unsigned long mmc_rx_csum_offload_irq_n;
101 /* EEE */
102 unsigned long irq_receive_pmt_irq_n;
103 unsigned long irq_tx_path_in_lpi_mode_n;
104 unsigned long irq_tx_path_exit_lpi_mode_n;
105 unsigned long irq_rx_path_in_lpi_mode_n;
106 unsigned long irq_rx_path_exit_lpi_mode_n;
107 unsigned long phy_eee_wakeup_error_n;
98}; 108};
99 109
100/* CSR Frequency Access Defines*/ 110/* CSR Frequency Access Defines*/
@@ -162,6 +172,17 @@ enum tx_dma_irq_status {
162 handle_tx_rx = 3, 172 handle_tx_rx = 3,
163}; 173};
164 174
175enum core_specific_irq_mask {
176 core_mmc_tx_irq = 1,
177 core_mmc_rx_irq = 2,
178 core_mmc_rx_csum_offload_irq = 4,
179 core_irq_receive_pmt_irq = 8,
180 core_irq_tx_path_in_lpi_mode = 16,
181 core_irq_tx_path_exit_lpi_mode = 32,
182 core_irq_rx_path_in_lpi_mode = 64,
183 core_irq_rx_path_exit_lpi_mode = 128,
184};
185
165/* DMA HW capabilities */ 186/* DMA HW capabilities */
166struct dma_features { 187struct dma_features {
167 unsigned int mbps_10_100; 188 unsigned int mbps_10_100;
@@ -208,6 +229,10 @@ struct dma_features {
208#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */ 229#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */
209#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */ 230#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */
210 231
232/* Default LPI timers */
233#define STMMAC_DEFAULT_LIT_LS_TIMER 0x3E8
234#define STMMAC_DEFAULT_TWT_LS_TIMER 0x0
235
211struct stmmac_desc_ops { 236struct stmmac_desc_ops {
212 /* DMA RX descriptor ring initialization */ 237 /* DMA RX descriptor ring initialization */
213 void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size, 238 void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size,
@@ -278,7 +303,7 @@ struct stmmac_ops {
278 /* Dump MAC registers */ 303 /* Dump MAC registers */
279 void (*dump_regs) (void __iomem *ioaddr); 304 void (*dump_regs) (void __iomem *ioaddr);
280 /* Handle extra events on specific interrupts hw dependent */ 305 /* Handle extra events on specific interrupts hw dependent */
281 void (*host_irq_status) (void __iomem *ioaddr); 306 int (*host_irq_status) (void __iomem *ioaddr);
282 /* Multicast filter setting */ 307 /* Multicast filter setting */
283 void (*set_filter) (struct net_device *dev, int id); 308 void (*set_filter) (struct net_device *dev, int id);
284 /* Flow control setting */ 309 /* Flow control setting */
@@ -291,6 +316,10 @@ struct stmmac_ops {
291 unsigned int reg_n); 316 unsigned int reg_n);
292 void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr, 317 void (*get_umac_addr) (void __iomem *ioaddr, unsigned char *addr,
293 unsigned int reg_n); 318 unsigned int reg_n);
319 void (*set_eee_mode) (void __iomem *ioaddr);
320 void (*reset_eee_mode) (void __iomem *ioaddr);
321 void (*set_eee_timer) (void __iomem *ioaddr, int ls, int tw);
322 void (*set_eee_pls) (void __iomem *ioaddr, int link);
294}; 323};
295 324
296struct mac_link { 325struct mac_link {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
index 23478bf4ed7a..f90fcb5f9573 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
@@ -36,6 +36,7 @@
36 36
37#define GMAC_INT_STATUS 0x00000038 /* interrupt status register */ 37#define GMAC_INT_STATUS 0x00000038 /* interrupt status register */
38enum dwmac1000_irq_status { 38enum dwmac1000_irq_status {
39 lpiis_irq = 0x400,
39 time_stamp_irq = 0x0200, 40 time_stamp_irq = 0x0200,
40 mmc_rx_csum_offload_irq = 0x0080, 41 mmc_rx_csum_offload_irq = 0x0080,
41 mmc_tx_irq = 0x0040, 42 mmc_tx_irq = 0x0040,
@@ -60,6 +61,25 @@ enum power_event {
60 power_down = 0x00000001, 61 power_down = 0x00000001,
61}; 62};
62 63
64/* Energy Efficient Ethernet (EEE)
65 *
66 * LPI status, timer and control register offset
67 */
68#define LPI_CTRL_STATUS 0x0030
69#define LPI_TIMER_CTRL 0x0034
70
71/* LPI control and status defines */
72#define LPI_CTRL_STATUS_LPITXA 0x00080000 /* Enable LPI TX Automate */
73#define LPI_CTRL_STATUS_PLSEN 0x00040000 /* Enable PHY Link Status */
74#define LPI_CTRL_STATUS_PLS 0x00020000 /* PHY Link Status */
75#define LPI_CTRL_STATUS_LPIEN 0x00010000 /* LPI Enable */
76#define LPI_CTRL_STATUS_RLPIST 0x00000200 /* Receive LPI state */
77#define LPI_CTRL_STATUS_TLPIST 0x00000100 /* Transmit LPI state */
78#define LPI_CTRL_STATUS_RLPIEX 0x00000008 /* Receive LPI Exit */
79#define LPI_CTRL_STATUS_RLPIEN 0x00000004 /* Receive LPI Entry */
80#define LPI_CTRL_STATUS_TLPIEX 0x00000002 /* Transmit LPI Exit */
81#define LPI_CTRL_STATUS_TLPIEN 0x00000001 /* Transmit LPI Entry */
82
63/* GMAC HW ADDR regs */ 83/* GMAC HW ADDR regs */
64#define GMAC_ADDR_HIGH(reg) (((reg > 15) ? 0x00000800 : 0x00000040) + \ 84#define GMAC_ADDR_HIGH(reg) (((reg > 15) ? 0x00000800 : 0x00000040) + \
65 (reg * 8)) 85 (reg * 8))
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
index b5e4d02f15c9..bfe022605498 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
@@ -194,26 +194,107 @@ static void dwmac1000_pmt(void __iomem *ioaddr, unsigned long mode)
194} 194}
195 195
196 196
197static void dwmac1000_irq_status(void __iomem *ioaddr) 197static int dwmac1000_irq_status(void __iomem *ioaddr)
198{ 198{
199 u32 intr_status = readl(ioaddr + GMAC_INT_STATUS); 199 u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
200 int status = 0;
200 201
201 /* Not used events (e.g. MMC interrupts) are not handled. */ 202 /* Not used events (e.g. MMC interrupts) are not handled. */
202 if ((intr_status & mmc_tx_irq)) 203 if ((intr_status & mmc_tx_irq)) {
203 CHIP_DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n", 204 CHIP_DBG(KERN_INFO "GMAC: MMC tx interrupt: 0x%08x\n",
204 readl(ioaddr + GMAC_MMC_TX_INTR)); 205 readl(ioaddr + GMAC_MMC_TX_INTR));
205 if (unlikely(intr_status & mmc_rx_irq)) 206 status |= core_mmc_tx_irq;
206 CHIP_DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n", 207 }
208 if (unlikely(intr_status & mmc_rx_irq)) {
209 CHIP_DBG(KERN_INFO "GMAC: MMC rx interrupt: 0x%08x\n",
207 readl(ioaddr + GMAC_MMC_RX_INTR)); 210 readl(ioaddr + GMAC_MMC_RX_INTR));
208 if (unlikely(intr_status & mmc_rx_csum_offload_irq)) 211 status |= core_mmc_rx_irq;
209 CHIP_DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n", 212 }
213 if (unlikely(intr_status & mmc_rx_csum_offload_irq)) {
214 CHIP_DBG(KERN_INFO "GMAC: MMC rx csum offload: 0x%08x\n",
210 readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD)); 215 readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
216 status |= core_mmc_rx_csum_offload_irq;
217 }
211 if (unlikely(intr_status & pmt_irq)) { 218 if (unlikely(intr_status & pmt_irq)) {
212 CHIP_DBG(KERN_DEBUG "GMAC: received Magic frame\n"); 219 CHIP_DBG(KERN_INFO "GMAC: received Magic frame\n");
213 /* clear the PMT bits 5 and 6 by reading the PMT 220 /* clear the PMT bits 5 and 6 by reading the PMT
214 * status register. */ 221 * status register. */
215 readl(ioaddr + GMAC_PMT); 222 readl(ioaddr + GMAC_PMT);
223 status |= core_irq_receive_pmt_irq;
216 } 224 }
225 /* MAC trx/rx EEE LPI entry/exit interrupts */
226 if (intr_status & lpiis_irq) {
227 /* Clean LPI interrupt by reading the Reg 12 */
228 u32 lpi_status = readl(ioaddr + LPI_CTRL_STATUS);
229
230 if (lpi_status & LPI_CTRL_STATUS_TLPIEN) {
231 CHIP_DBG(KERN_INFO "GMAC TX entered in LPI\n");
232 status |= core_irq_tx_path_in_lpi_mode;
233 }
234 if (lpi_status & LPI_CTRL_STATUS_TLPIEX) {
235 CHIP_DBG(KERN_INFO "GMAC TX exit from LPI\n");
236 status |= core_irq_tx_path_exit_lpi_mode;
237 }
238 if (lpi_status & LPI_CTRL_STATUS_RLPIEN) {
239 CHIP_DBG(KERN_INFO "GMAC RX entered in LPI\n");
240 status |= core_irq_rx_path_in_lpi_mode;
241 }
242 if (lpi_status & LPI_CTRL_STATUS_RLPIEX) {
243 CHIP_DBG(KERN_INFO "GMAC RX exit from LPI\n");
244 status |= core_irq_rx_path_exit_lpi_mode;
245 }
246 }
247
248 return status;
249}
250
251static void dwmac1000_set_eee_mode(void __iomem *ioaddr)
252{
253 u32 value;
254
255 /* Enable the link status receive on RGMII, SGMII ore SMII
256 * receive path and instruct the transmit to enter in LPI
257 * state. */
258 value = readl(ioaddr + LPI_CTRL_STATUS);
259 value |= LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA;
260 writel(value, ioaddr + LPI_CTRL_STATUS);
261}
262
263static void dwmac1000_reset_eee_mode(void __iomem *ioaddr)
264{
265 u32 value;
266
267 value = readl(ioaddr + LPI_CTRL_STATUS);
268 value &= ~(LPI_CTRL_STATUS_LPIEN | LPI_CTRL_STATUS_LPITXA);
269 writel(value, ioaddr + LPI_CTRL_STATUS);
270}
271
272static void dwmac1000_set_eee_pls(void __iomem *ioaddr, int link)
273{
274 u32 value;
275
276 value = readl(ioaddr + LPI_CTRL_STATUS);
277
278 if (link)
279 value |= LPI_CTRL_STATUS_PLS;
280 else
281 value &= ~LPI_CTRL_STATUS_PLS;
282
283 writel(value, ioaddr + LPI_CTRL_STATUS);
284}
285
286static void dwmac1000_set_eee_timer(void __iomem *ioaddr, int ls, int tw)
287{
288 int value = ((tw & 0xffff)) | ((ls & 0x7ff) << 16);
289
290 /* Program the timers in the LPI timer control register:
291 * LS: minimum time (ms) for which the link
292 * status from PHY should be ok before transmitting
293 * the LPI pattern.
294 * TW: minimum time (us) for which the core waits
295 * after it has stopped transmitting the LPI pattern.
296 */
297 writel(value, ioaddr + LPI_TIMER_CTRL);
217} 298}
218 299
219static const struct stmmac_ops dwmac1000_ops = { 300static const struct stmmac_ops dwmac1000_ops = {
@@ -226,6 +307,10 @@ static const struct stmmac_ops dwmac1000_ops = {
226 .pmt = dwmac1000_pmt, 307 .pmt = dwmac1000_pmt,
227 .set_umac_addr = dwmac1000_set_umac_addr, 308 .set_umac_addr = dwmac1000_set_umac_addr,
228 .get_umac_addr = dwmac1000_get_umac_addr, 309 .get_umac_addr = dwmac1000_get_umac_addr,
310 .set_eee_mode = dwmac1000_set_eee_mode,
311 .reset_eee_mode = dwmac1000_reset_eee_mode,
312 .set_eee_timer = dwmac1000_set_eee_timer,
313 .set_eee_pls = dwmac1000_set_eee_pls,
229}; 314};
230 315
231struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr) 316struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
index 19e0f4eed2bc..f83210e7c221 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c
@@ -72,9 +72,9 @@ static int dwmac100_rx_ipc_enable(void __iomem *ioaddr)
72 return 0; 72 return 0;
73} 73}
74 74
75static void dwmac100_irq_status(void __iomem *ioaddr) 75static int dwmac100_irq_status(void __iomem *ioaddr)
76{ 76{
77 return; 77 return 0;
78} 78}
79 79
80static void dwmac100_set_umac_addr(void __iomem *ioaddr, unsigned char *addr, 80static void dwmac100_set_umac_addr(void __iomem *ioaddr, unsigned char *addr,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
index 6e0360f9cfde..e678ce39d014 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
@@ -70,6 +70,7 @@
70#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL) 70#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
71 71
72/* DMA Status register defines */ 72/* DMA Status register defines */
73#define DMA_STATUS_GLPII 0x40000000 /* GMAC LPI interrupt */
73#define DMA_STATUS_GPI 0x10000000 /* PMT interrupt */ 74#define DMA_STATUS_GPI 0x10000000 /* PMT interrupt */
74#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */ 75#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
75#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */ 76#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int */
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index dc20c56efc9d..ab4c376cb276 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -87,6 +87,12 @@ struct stmmac_priv {
87#endif 87#endif
88 int clk_csr; 88 int clk_csr;
89 int synopsys_id; 89 int synopsys_id;
90 struct timer_list eee_ctrl_timer;
91 bool tx_path_in_lpi_mode;
92 int lpi_irq;
93 int eee_enabled;
94 int eee_active;
95 int tx_lpi_timer;
90}; 96};
91 97
92extern int phyaddr; 98extern int phyaddr;
@@ -104,6 +110,8 @@ int stmmac_dvr_remove(struct net_device *ndev);
104struct stmmac_priv *stmmac_dvr_probe(struct device *device, 110struct stmmac_priv *stmmac_dvr_probe(struct device *device,
105 struct plat_stmmacenet_data *plat_dat, 111 struct plat_stmmacenet_data *plat_dat,
106 void __iomem *addr); 112 void __iomem *addr);
113void stmmac_disable_eee_mode(struct stmmac_priv *priv);
114bool stmmac_eee_init(struct stmmac_priv *priv);
107 115
108#ifdef CONFIG_HAVE_CLK 116#ifdef CONFIG_HAVE_CLK
109static inline int stmmac_clk_enable(struct stmmac_priv *priv) 117static inline int stmmac_clk_enable(struct stmmac_priv *priv)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index ce431846fc6f..76fd61aa005f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -93,6 +93,16 @@ static const struct stmmac_stats stmmac_gstrings_stats[] = {
93 STMMAC_STAT(poll_n), 93 STMMAC_STAT(poll_n),
94 STMMAC_STAT(sched_timer_n), 94 STMMAC_STAT(sched_timer_n),
95 STMMAC_STAT(normal_irq_n), 95 STMMAC_STAT(normal_irq_n),
96 STMMAC_STAT(normal_irq_n),
97 STMMAC_STAT(mmc_tx_irq_n),
98 STMMAC_STAT(mmc_rx_irq_n),
99 STMMAC_STAT(mmc_rx_csum_offload_irq_n),
100 STMMAC_STAT(irq_receive_pmt_irq_n),
101 STMMAC_STAT(irq_tx_path_in_lpi_mode_n),
102 STMMAC_STAT(irq_tx_path_exit_lpi_mode_n),
103 STMMAC_STAT(irq_rx_path_in_lpi_mode_n),
104 STMMAC_STAT(irq_rx_path_exit_lpi_mode_n),
105 STMMAC_STAT(phy_eee_wakeup_error_n),
96}; 106};
97#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats) 107#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
98 108
@@ -366,6 +376,11 @@ static void stmmac_get_ethtool_stats(struct net_device *dev,
366 (*(u32 *)p); 376 (*(u32 *)p);
367 } 377 }
368 } 378 }
379 if (priv->eee_enabled) {
380 int val = phy_get_eee_err(priv->phydev);
381 if (val)
382 priv->xstats.phy_eee_wakeup_error_n = val;
383 }
369 } 384 }
370 for (i = 0; i < STMMAC_STATS_LEN; i++) { 385 for (i = 0; i < STMMAC_STATS_LEN; i++) {
371 char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset; 386 char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset;
@@ -464,6 +479,46 @@ static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
464 return 0; 479 return 0;
465} 480}
466 481
482static int stmmac_ethtool_op_get_eee(struct net_device *dev,
483 struct ethtool_eee *edata)
484{
485 struct stmmac_priv *priv = netdev_priv(dev);
486
487 if (!priv->dma_cap.eee)
488 return -EOPNOTSUPP;
489
490 edata->eee_enabled = priv->eee_enabled;
491 edata->eee_active = priv->eee_active;
492 edata->tx_lpi_timer = priv->tx_lpi_timer;
493
494 return phy_ethtool_get_eee(priv->phydev, edata);
495}
496
497static int stmmac_ethtool_op_set_eee(struct net_device *dev,
498 struct ethtool_eee *edata)
499{
500 struct stmmac_priv *priv = netdev_priv(dev);
501
502 priv->eee_enabled = edata->eee_enabled;
503
504 if (!priv->eee_enabled)
505 stmmac_disable_eee_mode(priv);
506 else {
507 /* We are asking for enabling the EEE but it is safe
508 * to verify all by invoking the eee_init function.
509 * In case of failure it will return an error.
510 */
511 priv->eee_enabled = stmmac_eee_init(priv);
512 if (!priv->eee_enabled)
513 return -EOPNOTSUPP;
514
515 /* Do not change tx_lpi_timer in case of failure */
516 priv->tx_lpi_timer = edata->tx_lpi_timer;
517 }
518
519 return phy_ethtool_set_eee(priv->phydev, edata);
520}
521
467static const struct ethtool_ops stmmac_ethtool_ops = { 522static const struct ethtool_ops stmmac_ethtool_ops = {
468 .begin = stmmac_check_if_running, 523 .begin = stmmac_check_if_running,
469 .get_drvinfo = stmmac_ethtool_getdrvinfo, 524 .get_drvinfo = stmmac_ethtool_getdrvinfo,
@@ -480,6 +535,8 @@ static const struct ethtool_ops stmmac_ethtool_ops = {
480 .get_strings = stmmac_get_strings, 535 .get_strings = stmmac_get_strings,
481 .get_wol = stmmac_get_wol, 536 .get_wol = stmmac_get_wol,
482 .set_wol = stmmac_set_wol, 537 .set_wol = stmmac_set_wol,
538 .get_eee = stmmac_ethtool_op_get_eee,
539 .set_eee = stmmac_ethtool_op_set_eee,
483 .get_sset_count = stmmac_get_sset_count, 540 .get_sset_count = stmmac_get_sset_count,
484 .get_ts_info = ethtool_op_get_ts_info, 541 .get_ts_info = ethtool_op_get_ts_info,
485}; 542};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index eba49cb810f9..ea3bc0963bd7 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -133,6 +133,12 @@ static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
133 NETIF_MSG_LINK | NETIF_MSG_IFUP | 133 NETIF_MSG_LINK | NETIF_MSG_IFUP |
134 NETIF_MSG_IFDOWN | NETIF_MSG_TIMER); 134 NETIF_MSG_IFDOWN | NETIF_MSG_TIMER);
135 135
136#define STMMAC_DEFAULT_LPI_TIMER 1000
137static int eee_timer = STMMAC_DEFAULT_LPI_TIMER;
138module_param(eee_timer, int, S_IRUGO | S_IWUSR);
139MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec");
140#define STMMAC_LPI_TIMER(x) (jiffies + msecs_to_jiffies(x))
141
136static irqreturn_t stmmac_interrupt(int irq, void *dev_id); 142static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
137 143
138#ifdef CONFIG_STMMAC_DEBUG_FS 144#ifdef CONFIG_STMMAC_DEBUG_FS
@@ -161,6 +167,8 @@ static void stmmac_verify_args(void)
161 flow_ctrl = FLOW_OFF; 167 flow_ctrl = FLOW_OFF;
162 if (unlikely((pause < 0) || (pause > 0xffff))) 168 if (unlikely((pause < 0) || (pause > 0xffff)))
163 pause = PAUSE_TIME; 169 pause = PAUSE_TIME;
170 if (eee_timer < 0)
171 eee_timer = STMMAC_DEFAULT_LPI_TIMER;
164} 172}
165 173
166static void stmmac_clk_csr_set(struct stmmac_priv *priv) 174static void stmmac_clk_csr_set(struct stmmac_priv *priv)
@@ -229,6 +237,85 @@ static inline void stmmac_hw_fix_mac_speed(struct stmmac_priv *priv)
229 phydev->speed); 237 phydev->speed);
230} 238}
231 239
240static void stmmac_enable_eee_mode(struct stmmac_priv *priv)
241{
242 /* Check and enter in LPI mode */
243 if ((priv->dirty_tx == priv->cur_tx) &&
244 (priv->tx_path_in_lpi_mode == false))
245 priv->hw->mac->set_eee_mode(priv->ioaddr);
246}
247
248void stmmac_disable_eee_mode(struct stmmac_priv *priv)
249{
250 /* Exit and disable EEE in case of we are are in LPI state. */
251 priv->hw->mac->reset_eee_mode(priv->ioaddr);
252 del_timer_sync(&priv->eee_ctrl_timer);
253 priv->tx_path_in_lpi_mode = false;
254}
255
256/**
257 * stmmac_eee_ctrl_timer
258 * @arg : data hook
259 * Description:
260 * If there is no data transfer and if we are not in LPI state,
261 * then MAC Transmitter can be moved to LPI state.
262 */
263static void stmmac_eee_ctrl_timer(unsigned long arg)
264{
265 struct stmmac_priv *priv = (struct stmmac_priv *)arg;
266
267 stmmac_enable_eee_mode(priv);
268 mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_TIMER(eee_timer));
269}
270
271/**
272 * stmmac_eee_init
273 * @priv: private device pointer
274 * Description:
275 * If the EEE support has been enabled while configuring the driver,
276 * if the GMAC actually supports the EEE (from the HW cap reg) and the
277 * phy can also manage EEE, so enable the LPI state and start the timer
278 * to verify if the tx path can enter in LPI state.
279 */
280bool stmmac_eee_init(struct stmmac_priv *priv)
281{
282 bool ret = false;
283
284 /* MAC core supports the EEE feature. */
285 if (priv->dma_cap.eee) {
286 /* Check if the PHY supports EEE */
287 if (phy_init_eee(priv->phydev, 1))
288 goto out;
289
290 priv->eee_active = 1;
291 init_timer(&priv->eee_ctrl_timer);
292 priv->eee_ctrl_timer.function = stmmac_eee_ctrl_timer;
293 priv->eee_ctrl_timer.data = (unsigned long)priv;
294 priv->eee_ctrl_timer.expires = STMMAC_LPI_TIMER(eee_timer);
295 add_timer(&priv->eee_ctrl_timer);
296
297 priv->hw->mac->set_eee_timer(priv->ioaddr,
298 STMMAC_DEFAULT_LIT_LS_TIMER,
299 priv->tx_lpi_timer);
300
301 pr_info("stmmac: Energy-Efficient Ethernet initialized\n");
302
303 ret = true;
304 }
305out:
306 return ret;
307}
308
309static void stmmac_eee_adjust(struct stmmac_priv *priv)
310{
311 /* When the EEE has been already initialised we have to
312 * modify the PLS bit in the LPI ctrl & status reg according
313 * to the PHY link status. For this reason.
314 */
315 if (priv->eee_enabled)
316 priv->hw->mac->set_eee_pls(priv->ioaddr, priv->phydev->link);
317}
318
232/** 319/**
233 * stmmac_adjust_link 320 * stmmac_adjust_link
234 * @dev: net device structure 321 * @dev: net device structure
@@ -249,6 +336,7 @@ static void stmmac_adjust_link(struct net_device *dev)
249 phydev->addr, phydev->link); 336 phydev->addr, phydev->link);
250 337
251 spin_lock_irqsave(&priv->lock, flags); 338 spin_lock_irqsave(&priv->lock, flags);
339
252 if (phydev->link) { 340 if (phydev->link) {
253 u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG); 341 u32 ctrl = readl(priv->ioaddr + MAC_CTRL_REG);
254 342
@@ -315,6 +403,8 @@ static void stmmac_adjust_link(struct net_device *dev)
315 if (new_state && netif_msg_link(priv)) 403 if (new_state && netif_msg_link(priv))
316 phy_print_status(phydev); 404 phy_print_status(phydev);
317 405
406 stmmac_eee_adjust(priv);
407
318 spin_unlock_irqrestore(&priv->lock, flags); 408 spin_unlock_irqrestore(&priv->lock, flags);
319 409
320 DBG(probe, DEBUG, "stmmac_adjust_link: exiting\n"); 410 DBG(probe, DEBUG, "stmmac_adjust_link: exiting\n");
@@ -332,7 +422,7 @@ static int stmmac_init_phy(struct net_device *dev)
332{ 422{
333 struct stmmac_priv *priv = netdev_priv(dev); 423 struct stmmac_priv *priv = netdev_priv(dev);
334 struct phy_device *phydev; 424 struct phy_device *phydev;
335 char phy_id[MII_BUS_ID_SIZE + 3]; 425 char phy_id_fmt[MII_BUS_ID_SIZE + 3];
336 char bus_id[MII_BUS_ID_SIZE]; 426 char bus_id[MII_BUS_ID_SIZE];
337 int interface = priv->plat->interface; 427 int interface = priv->plat->interface;
338 priv->oldlink = 0; 428 priv->oldlink = 0;
@@ -346,11 +436,12 @@ static int stmmac_init_phy(struct net_device *dev)
346 snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x", 436 snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
347 priv->plat->bus_id); 437 priv->plat->bus_id);
348 438
349 snprintf(phy_id, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id, 439 snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
350 priv->plat->phy_addr); 440 priv->plat->phy_addr);
351 pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id); 441 pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id_fmt);
352 442
353 phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0, interface); 443 phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, 0,
444 interface);
354 445
355 if (IS_ERR(phydev)) { 446 if (IS_ERR(phydev)) {
356 pr_err("%s: Could not attach to PHY\n", dev->name); 447 pr_err("%s: Could not attach to PHY\n", dev->name);
@@ -689,6 +780,11 @@ static void stmmac_tx(struct stmmac_priv *priv)
689 } 780 }
690 netif_tx_unlock(priv->dev); 781 netif_tx_unlock(priv->dev);
691 } 782 }
783
784 if ((priv->eee_enabled) && (!priv->tx_path_in_lpi_mode)) {
785 stmmac_enable_eee_mode(priv);
786 mod_timer(&priv->eee_ctrl_timer, STMMAC_LPI_TIMER(eee_timer));
787 }
692 spin_unlock(&priv->tx_lock); 788 spin_unlock(&priv->tx_lock);
693} 789}
694 790
@@ -1027,6 +1123,17 @@ static int stmmac_open(struct net_device *dev)
1027 } 1123 }
1028 } 1124 }
1029 1125
1126 /* Request the IRQ lines */
1127 if (priv->lpi_irq != -ENXIO) {
1128 ret = request_irq(priv->lpi_irq, stmmac_interrupt, IRQF_SHARED,
1129 dev->name, dev);
1130 if (unlikely(ret < 0)) {
1131 pr_err("%s: ERROR: allocating the LPI IRQ %d (%d)\n",
1132 __func__, priv->lpi_irq, ret);
1133 goto open_error_lpiirq;
1134 }
1135 }
1136
1030 /* Enable the MAC Rx/Tx */ 1137 /* Enable the MAC Rx/Tx */
1031 stmmac_set_mac(priv->ioaddr, true); 1138 stmmac_set_mac(priv->ioaddr, true);
1032 1139
@@ -1062,12 +1169,19 @@ static int stmmac_open(struct net_device *dev)
1062 if (priv->phydev) 1169 if (priv->phydev)
1063 phy_start(priv->phydev); 1170 phy_start(priv->phydev);
1064 1171
1172 priv->tx_lpi_timer = STMMAC_DEFAULT_TWT_LS_TIMER;
1173 priv->eee_enabled = stmmac_eee_init(priv);
1174
1065 napi_enable(&priv->napi); 1175 napi_enable(&priv->napi);
1066 skb_queue_head_init(&priv->rx_recycle); 1176 skb_queue_head_init(&priv->rx_recycle);
1067 netif_start_queue(dev); 1177 netif_start_queue(dev);
1068 1178
1069 return 0; 1179 return 0;
1070 1180
1181open_error_lpiirq:
1182 if (priv->wol_irq != dev->irq)
1183 free_irq(priv->wol_irq, dev);
1184
1071open_error_wolirq: 1185open_error_wolirq:
1072 free_irq(dev->irq, dev); 1186 free_irq(dev->irq, dev);
1073 1187
@@ -1093,6 +1207,9 @@ static int stmmac_release(struct net_device *dev)
1093{ 1207{
1094 struct stmmac_priv *priv = netdev_priv(dev); 1208 struct stmmac_priv *priv = netdev_priv(dev);
1095 1209
1210 if (priv->eee_enabled)
1211 del_timer_sync(&priv->eee_ctrl_timer);
1212
1096 /* Stop and disconnect the PHY */ 1213 /* Stop and disconnect the PHY */
1097 if (priv->phydev) { 1214 if (priv->phydev) {
1098 phy_stop(priv->phydev); 1215 phy_stop(priv->phydev);
@@ -1115,6 +1232,8 @@ static int stmmac_release(struct net_device *dev)
1115 free_irq(dev->irq, dev); 1232 free_irq(dev->irq, dev);
1116 if (priv->wol_irq != dev->irq) 1233 if (priv->wol_irq != dev->irq)
1117 free_irq(priv->wol_irq, dev); 1234 free_irq(priv->wol_irq, dev);
1235 if (priv->lpi_irq != -ENXIO)
1236 free_irq(priv->lpi_irq, dev);
1118 1237
1119 /* Stop TX/RX DMA and clear the descriptors */ 1238 /* Stop TX/RX DMA and clear the descriptors */
1120 priv->hw->dma->stop_tx(priv->ioaddr); 1239 priv->hw->dma->stop_tx(priv->ioaddr);
@@ -1164,6 +1283,9 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
1164 1283
1165 spin_lock(&priv->tx_lock); 1284 spin_lock(&priv->tx_lock);
1166 1285
1286 if (priv->tx_path_in_lpi_mode)
1287 stmmac_disable_eee_mode(priv);
1288
1167 entry = priv->cur_tx % txsize; 1289 entry = priv->cur_tx % txsize;
1168 1290
1169#ifdef STMMAC_XMIT_DEBUG 1291#ifdef STMMAC_XMIT_DEBUG
@@ -1540,10 +1662,37 @@ static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
1540 return IRQ_NONE; 1662 return IRQ_NONE;
1541 } 1663 }
1542 1664
1543 if (priv->plat->has_gmac) 1665 /* To handle GMAC own interrupts */
1544 /* To handle GMAC own interrupts */ 1666 if (priv->plat->has_gmac) {
1545 priv->hw->mac->host_irq_status((void __iomem *) dev->base_addr); 1667 int status = priv->hw->mac->host_irq_status((void __iomem *)
1668 dev->base_addr);
1669 if (unlikely(status)) {
1670 if (status & core_mmc_tx_irq)
1671 priv->xstats.mmc_tx_irq_n++;
1672 if (status & core_mmc_rx_irq)
1673 priv->xstats.mmc_rx_irq_n++;
1674 if (status & core_mmc_rx_csum_offload_irq)
1675 priv->xstats.mmc_rx_csum_offload_irq_n++;
1676 if (status & core_irq_receive_pmt_irq)
1677 priv->xstats.irq_receive_pmt_irq_n++;
1678
1679 /* For LPI we need to save the tx status */
1680 if (status & core_irq_tx_path_in_lpi_mode) {
1681 priv->xstats.irq_tx_path_in_lpi_mode_n++;
1682 priv->tx_path_in_lpi_mode = true;
1683 }
1684 if (status & core_irq_tx_path_exit_lpi_mode) {
1685 priv->xstats.irq_tx_path_exit_lpi_mode_n++;
1686 priv->tx_path_in_lpi_mode = false;
1687 }
1688 if (status & core_irq_rx_path_in_lpi_mode)
1689 priv->xstats.irq_rx_path_in_lpi_mode_n++;
1690 if (status & core_irq_rx_path_exit_lpi_mode)
1691 priv->xstats.irq_rx_path_exit_lpi_mode_n++;
1692 }
1693 }
1546 1694
1695 /* To handle DMA interrupts */
1547 stmmac_dma_interrupt(priv); 1696 stmmac_dma_interrupt(priv);
1548 1697
1549 return IRQ_HANDLED; 1698 return IRQ_HANDLED;
@@ -2155,6 +2304,9 @@ static int __init stmmac_cmdline_opt(char *str)
2155 } else if (!strncmp(opt, "pause:", 6)) { 2304 } else if (!strncmp(opt, "pause:", 6)) {
2156 if (kstrtoint(opt + 6, 0, &pause)) 2305 if (kstrtoint(opt + 6, 0, &pause))
2157 goto err; 2306 goto err;
2307 } else if (!strncmp(opt, "eee_timer:", 6)) {
2308 if (kstrtoint(opt + 10, 0, &eee_timer))
2309 goto err;
2158#ifdef CONFIG_STMMAC_TIMER 2310#ifdef CONFIG_STMMAC_TIMER
2159 } else if (!strncmp(opt, "tmrate:", 7)) { 2311 } else if (!strncmp(opt, "tmrate:", 7)) {
2160 if (kstrtoint(opt + 7, 0, &tmrate)) 2312 if (kstrtoint(opt + 7, 0, &tmrate))
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 20eb5026c49c..7d36163d0d23 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -156,6 +156,8 @@ static int stmmac_pltfr_probe(struct platform_device *pdev)
156 if (priv->wol_irq == -ENXIO) 156 if (priv->wol_irq == -ENXIO)
157 priv->wol_irq = priv->dev->irq; 157 priv->wol_irq = priv->dev->irq;
158 158
159 priv->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
160
159 platform_set_drvdata(pdev, priv->dev); 161 platform_set_drvdata(pdev, priv->dev);
160 162
161 pr_debug("STMMAC platform driver registration completed"); 163 pr_debug("STMMAC platform driver registration completed");