diff options
Diffstat (limited to 'drivers/net/ethernet/stmicro/stmmac/stmmac_main.c')
-rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 166 |
1 files changed, 159 insertions, 7 deletions
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 | ||
137 | static int eee_timer = STMMAC_DEFAULT_LPI_TIMER; | ||
138 | module_param(eee_timer, int, S_IRUGO | S_IWUSR); | ||
139 | MODULE_PARM_DESC(eee_timer, "LPI tx expiration time in msec"); | ||
140 | #define STMMAC_LPI_TIMER(x) (jiffies + msecs_to_jiffies(x)) | ||
141 | |||
136 | static irqreturn_t stmmac_interrupt(int irq, void *dev_id); | 142 | static 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 | ||
166 | static void stmmac_clk_csr_set(struct stmmac_priv *priv) | 174 | static 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 | ||
240 | static 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 | |||
248 | void 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 | */ | ||
263 | static 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 | */ | ||
280 | bool 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 | } | ||
305 | out: | ||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | static 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 | ||
1181 | open_error_lpiirq: | ||
1182 | if (priv->wol_irq != dev->irq) | ||
1183 | free_irq(priv->wol_irq, dev); | ||
1184 | |||
1071 | open_error_wolirq: | 1185 | open_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)) |