diff options
Diffstat (limited to 'drivers/net/ethernet/freescale/fec_main.c')
-rw-r--r-- | drivers/net/ethernet/freescale/fec_main.c | 145 |
1 files changed, 119 insertions, 26 deletions
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index bba87775419d..9bb6220663b2 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c | |||
@@ -188,6 +188,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); | |||
188 | #define FEC_MMFR_RA(v) ((v & 0x1f) << 18) | 188 | #define FEC_MMFR_RA(v) ((v & 0x1f) << 18) |
189 | #define FEC_MMFR_TA (2 << 16) | 189 | #define FEC_MMFR_TA (2 << 16) |
190 | #define FEC_MMFR_DATA(v) (v & 0xffff) | 190 | #define FEC_MMFR_DATA(v) (v & 0xffff) |
191 | /* FEC ECR bits definition */ | ||
192 | #define FEC_ECR_MAGICEN (1 << 2) | ||
193 | #define FEC_ECR_SLEEP (1 << 3) | ||
191 | 194 | ||
192 | #define FEC_MII_TIMEOUT 30000 /* us */ | 195 | #define FEC_MII_TIMEOUT 30000 /* us */ |
193 | 196 | ||
@@ -196,6 +199,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); | |||
196 | 199 | ||
197 | #define FEC_PAUSE_FLAG_AUTONEG 0x1 | 200 | #define FEC_PAUSE_FLAG_AUTONEG 0x1 |
198 | #define FEC_PAUSE_FLAG_ENABLE 0x2 | 201 | #define FEC_PAUSE_FLAG_ENABLE 0x2 |
202 | #define FEC_WOL_HAS_MAGIC_PACKET (0x1 << 0) | ||
203 | #define FEC_WOL_FLAG_ENABLE (0x1 << 1) | ||
204 | #define FEC_WOL_FLAG_SLEEP_ON (0x1 << 2) | ||
199 | 205 | ||
200 | #define COPYBREAK_DEFAULT 256 | 206 | #define COPYBREAK_DEFAULT 256 |
201 | 207 | ||
@@ -1090,7 +1096,9 @@ static void | |||
1090 | fec_stop(struct net_device *ndev) | 1096 | fec_stop(struct net_device *ndev) |
1091 | { | 1097 | { |
1092 | struct fec_enet_private *fep = netdev_priv(ndev); | 1098 | struct fec_enet_private *fep = netdev_priv(ndev); |
1099 | struct fec_platform_data *pdata = fep->pdev->dev.platform_data; | ||
1093 | u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); | 1100 | u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); |
1101 | u32 val; | ||
1094 | 1102 | ||
1095 | /* We cannot expect a graceful transmit stop without link !!! */ | 1103 | /* We cannot expect a graceful transmit stop without link !!! */ |
1096 | if (fep->link) { | 1104 | if (fep->link) { |
@@ -1104,17 +1112,28 @@ fec_stop(struct net_device *ndev) | |||
1104 | * For i.MX6SX SOC, enet use AXI bus, we use disable MAC | 1112 | * For i.MX6SX SOC, enet use AXI bus, we use disable MAC |
1105 | * instead of reset MAC itself. | 1113 | * instead of reset MAC itself. |
1106 | */ | 1114 | */ |
1107 | if (fep->quirks & FEC_QUIRK_HAS_AVB) { | 1115 | if (!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { |
1108 | writel(0, fep->hwp + FEC_ECNTRL); | 1116 | if (fep->quirks & FEC_QUIRK_HAS_AVB) { |
1117 | writel(0, fep->hwp + FEC_ECNTRL); | ||
1118 | } else { | ||
1119 | writel(1, fep->hwp + FEC_ECNTRL); | ||
1120 | udelay(10); | ||
1121 | } | ||
1122 | writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); | ||
1109 | } else { | 1123 | } else { |
1110 | writel(1, fep->hwp + FEC_ECNTRL); | 1124 | writel(FEC_DEFAULT_IMASK | FEC_ENET_WAKEUP, fep->hwp + FEC_IMASK); |
1111 | udelay(10); | 1125 | val = readl(fep->hwp + FEC_ECNTRL); |
1126 | val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP); | ||
1127 | writel(val, fep->hwp + FEC_ECNTRL); | ||
1128 | |||
1129 | if (pdata && pdata->sleep_mode_enable) | ||
1130 | pdata->sleep_mode_enable(true); | ||
1112 | } | 1131 | } |
1113 | writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); | 1132 | writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); |
1114 | writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); | ||
1115 | 1133 | ||
1116 | /* We have to keep ENET enabled to have MII interrupt stay working */ | 1134 | /* We have to keep ENET enabled to have MII interrupt stay working */ |
1117 | if (fep->quirks & FEC_QUIRK_ENET_MAC) { | 1135 | if (fep->quirks & FEC_QUIRK_ENET_MAC && |
1136 | !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) { | ||
1118 | writel(2, fep->hwp + FEC_ECNTRL); | 1137 | writel(2, fep->hwp + FEC_ECNTRL); |
1119 | writel(rmii_mode, fep->hwp + FEC_R_CNTRL); | 1138 | writel(rmii_mode, fep->hwp + FEC_R_CNTRL); |
1120 | } | 1139 | } |
@@ -1170,12 +1189,13 @@ static void | |||
1170 | fec_enet_tx_queue(struct net_device *ndev, u16 queue_id) | 1189 | fec_enet_tx_queue(struct net_device *ndev, u16 queue_id) |
1171 | { | 1190 | { |
1172 | struct fec_enet_private *fep; | 1191 | struct fec_enet_private *fep; |
1173 | struct bufdesc *bdp; | 1192 | struct bufdesc *bdp, *bdp_t; |
1174 | unsigned short status; | 1193 | unsigned short status; |
1175 | struct sk_buff *skb; | 1194 | struct sk_buff *skb; |
1176 | struct fec_enet_priv_tx_q *txq; | 1195 | struct fec_enet_priv_tx_q *txq; |
1177 | struct netdev_queue *nq; | 1196 | struct netdev_queue *nq; |
1178 | int index = 0; | 1197 | int index = 0; |
1198 | int i, bdnum; | ||
1179 | int entries_free; | 1199 | int entries_free; |
1180 | 1200 | ||
1181 | fep = netdev_priv(ndev); | 1201 | fep = netdev_priv(ndev); |
@@ -1196,18 +1216,29 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id) | |||
1196 | if (bdp == txq->cur_tx) | 1216 | if (bdp == txq->cur_tx) |
1197 | break; | 1217 | break; |
1198 | 1218 | ||
1199 | index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep); | 1219 | bdp_t = bdp; |
1200 | 1220 | bdnum = 1; | |
1221 | index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep); | ||
1201 | skb = txq->tx_skbuff[index]; | 1222 | skb = txq->tx_skbuff[index]; |
1202 | txq->tx_skbuff[index] = NULL; | 1223 | while (!skb) { |
1203 | if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr)) | 1224 | bdp_t = fec_enet_get_nextdesc(bdp_t, fep, queue_id); |
1204 | dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, | 1225 | index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep); |
1205 | bdp->cbd_datlen, DMA_TO_DEVICE); | 1226 | skb = txq->tx_skbuff[index]; |
1206 | bdp->cbd_bufaddr = 0; | 1227 | bdnum++; |
1207 | if (!skb) { | ||
1208 | bdp = fec_enet_get_nextdesc(bdp, fep, queue_id); | ||
1209 | continue; | ||
1210 | } | 1228 | } |
1229 | if (skb_shinfo(skb)->nr_frags && | ||
1230 | (status = bdp_t->cbd_sc) & BD_ENET_TX_READY) | ||
1231 | break; | ||
1232 | |||
1233 | for (i = 0; i < bdnum; i++) { | ||
1234 | if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr)) | ||
1235 | dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, | ||
1236 | bdp->cbd_datlen, DMA_TO_DEVICE); | ||
1237 | bdp->cbd_bufaddr = 0; | ||
1238 | if (i < bdnum - 1) | ||
1239 | bdp = fec_enet_get_nextdesc(bdp, fep, queue_id); | ||
1240 | } | ||
1241 | txq->tx_skbuff[index] = NULL; | ||
1211 | 1242 | ||
1212 | /* Check for errors. */ | 1243 | /* Check for errors. */ |
1213 | if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | | 1244 | if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | |
@@ -2428,6 +2459,44 @@ static int fec_enet_set_tunable(struct net_device *netdev, | |||
2428 | return ret; | 2459 | return ret; |
2429 | } | 2460 | } |
2430 | 2461 | ||
2462 | static void | ||
2463 | fec_enet_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) | ||
2464 | { | ||
2465 | struct fec_enet_private *fep = netdev_priv(ndev); | ||
2466 | |||
2467 | if (fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET) { | ||
2468 | wol->supported = WAKE_MAGIC; | ||
2469 | wol->wolopts = fep->wol_flag & FEC_WOL_FLAG_ENABLE ? WAKE_MAGIC : 0; | ||
2470 | } else { | ||
2471 | wol->supported = wol->wolopts = 0; | ||
2472 | } | ||
2473 | } | ||
2474 | |||
2475 | static int | ||
2476 | fec_enet_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol) | ||
2477 | { | ||
2478 | struct fec_enet_private *fep = netdev_priv(ndev); | ||
2479 | |||
2480 | if (!(fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET)) | ||
2481 | return -EINVAL; | ||
2482 | |||
2483 | if (wol->wolopts & ~WAKE_MAGIC) | ||
2484 | return -EINVAL; | ||
2485 | |||
2486 | device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC); | ||
2487 | if (device_may_wakeup(&ndev->dev)) { | ||
2488 | fep->wol_flag |= FEC_WOL_FLAG_ENABLE; | ||
2489 | if (fep->irq[0] > 0) | ||
2490 | enable_irq_wake(fep->irq[0]); | ||
2491 | } else { | ||
2492 | fep->wol_flag &= (~FEC_WOL_FLAG_ENABLE); | ||
2493 | if (fep->irq[0] > 0) | ||
2494 | disable_irq_wake(fep->irq[0]); | ||
2495 | } | ||
2496 | |||
2497 | return 0; | ||
2498 | } | ||
2499 | |||
2431 | static const struct ethtool_ops fec_enet_ethtool_ops = { | 2500 | static const struct ethtool_ops fec_enet_ethtool_ops = { |
2432 | .get_settings = fec_enet_get_settings, | 2501 | .get_settings = fec_enet_get_settings, |
2433 | .set_settings = fec_enet_set_settings, | 2502 | .set_settings = fec_enet_set_settings, |
@@ -2446,6 +2515,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = { | |||
2446 | .get_ts_info = fec_enet_get_ts_info, | 2515 | .get_ts_info = fec_enet_get_ts_info, |
2447 | .get_tunable = fec_enet_get_tunable, | 2516 | .get_tunable = fec_enet_get_tunable, |
2448 | .set_tunable = fec_enet_set_tunable, | 2517 | .set_tunable = fec_enet_set_tunable, |
2518 | .get_wol = fec_enet_get_wol, | ||
2519 | .set_wol = fec_enet_set_wol, | ||
2449 | }; | 2520 | }; |
2450 | 2521 | ||
2451 | static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) | 2522 | static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) |
@@ -2525,12 +2596,9 @@ static void fec_enet_free_queue(struct net_device *ndev) | |||
2525 | } | 2596 | } |
2526 | 2597 | ||
2527 | for (i = 0; i < fep->num_rx_queues; i++) | 2598 | for (i = 0; i < fep->num_rx_queues; i++) |
2528 | if (fep->rx_queue[i]) | 2599 | kfree(fep->rx_queue[i]); |
2529 | kfree(fep->rx_queue[i]); | ||
2530 | |||
2531 | for (i = 0; i < fep->num_tx_queues; i++) | 2600 | for (i = 0; i < fep->num_tx_queues; i++) |
2532 | if (fep->tx_queue[i]) | 2601 | kfree(fep->tx_queue[i]); |
2533 | kfree(fep->tx_queue[i]); | ||
2534 | } | 2602 | } |
2535 | 2603 | ||
2536 | static int fec_enet_alloc_queue(struct net_device *ndev) | 2604 | static int fec_enet_alloc_queue(struct net_device *ndev) |
@@ -2706,6 +2774,9 @@ fec_enet_open(struct net_device *ndev) | |||
2706 | phy_start(fep->phy_dev); | 2774 | phy_start(fep->phy_dev); |
2707 | netif_tx_start_all_queues(ndev); | 2775 | netif_tx_start_all_queues(ndev); |
2708 | 2776 | ||
2777 | device_set_wakeup_enable(&ndev->dev, fep->wol_flag & | ||
2778 | FEC_WOL_FLAG_ENABLE); | ||
2779 | |||
2709 | return 0; | 2780 | return 0; |
2710 | 2781 | ||
2711 | err_enet_mii_probe: | 2782 | err_enet_mii_probe: |
@@ -3155,6 +3226,9 @@ fec_probe(struct platform_device *pdev) | |||
3155 | 3226 | ||
3156 | platform_set_drvdata(pdev, ndev); | 3227 | platform_set_drvdata(pdev, ndev); |
3157 | 3228 | ||
3229 | if (of_get_property(np, "fsl,magic-packet", NULL)) | ||
3230 | fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET; | ||
3231 | |||
3158 | phy_node = of_parse_phandle(np, "phy-handle", 0); | 3232 | phy_node = of_parse_phandle(np, "phy-handle", 0); |
3159 | if (!phy_node && of_phy_is_fixed_link(np)) { | 3233 | if (!phy_node && of_phy_is_fixed_link(np)) { |
3160 | ret = of_phy_register_fixed_link(np); | 3234 | ret = of_phy_register_fixed_link(np); |
@@ -3249,6 +3323,8 @@ fec_probe(struct platform_device *pdev) | |||
3249 | 0, pdev->name, ndev); | 3323 | 0, pdev->name, ndev); |
3250 | if (ret) | 3324 | if (ret) |
3251 | goto failed_irq; | 3325 | goto failed_irq; |
3326 | |||
3327 | fep->irq[i] = irq; | ||
3252 | } | 3328 | } |
3253 | 3329 | ||
3254 | init_completion(&fep->mdio_done); | 3330 | init_completion(&fep->mdio_done); |
@@ -3265,6 +3341,9 @@ fec_probe(struct platform_device *pdev) | |||
3265 | if (ret) | 3341 | if (ret) |
3266 | goto failed_register; | 3342 | goto failed_register; |
3267 | 3343 | ||
3344 | device_init_wakeup(&ndev->dev, fep->wol_flag & | ||
3345 | FEC_WOL_HAS_MAGIC_PACKET); | ||
3346 | |||
3268 | if (fep->bufdesc_ex && fep->ptp_clock) | 3347 | if (fep->bufdesc_ex && fep->ptp_clock) |
3269 | netdev_info(ndev, "registered PHC device %d\n", fep->dev_id); | 3348 | netdev_info(ndev, "registered PHC device %d\n", fep->dev_id); |
3270 | 3349 | ||
@@ -3318,6 +3397,8 @@ static int __maybe_unused fec_suspend(struct device *dev) | |||
3318 | 3397 | ||
3319 | rtnl_lock(); | 3398 | rtnl_lock(); |
3320 | if (netif_running(ndev)) { | 3399 | if (netif_running(ndev)) { |
3400 | if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) | ||
3401 | fep->wol_flag |= FEC_WOL_FLAG_SLEEP_ON; | ||
3321 | phy_stop(fep->phy_dev); | 3402 | phy_stop(fep->phy_dev); |
3322 | napi_disable(&fep->napi); | 3403 | napi_disable(&fep->napi); |
3323 | netif_tx_lock_bh(ndev); | 3404 | netif_tx_lock_bh(ndev); |
@@ -3325,11 +3406,12 @@ static int __maybe_unused fec_suspend(struct device *dev) | |||
3325 | netif_tx_unlock_bh(ndev); | 3406 | netif_tx_unlock_bh(ndev); |
3326 | fec_stop(ndev); | 3407 | fec_stop(ndev); |
3327 | fec_enet_clk_enable(ndev, false); | 3408 | fec_enet_clk_enable(ndev, false); |
3328 | pinctrl_pm_select_sleep_state(&fep->pdev->dev); | 3409 | if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) |
3410 | pinctrl_pm_select_sleep_state(&fep->pdev->dev); | ||
3329 | } | 3411 | } |
3330 | rtnl_unlock(); | 3412 | rtnl_unlock(); |
3331 | 3413 | ||
3332 | if (fep->reg_phy) | 3414 | if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) |
3333 | regulator_disable(fep->reg_phy); | 3415 | regulator_disable(fep->reg_phy); |
3334 | 3416 | ||
3335 | /* SOC supply clock to phy, when clock is disabled, phy link down | 3417 | /* SOC supply clock to phy, when clock is disabled, phy link down |
@@ -3345,9 +3427,11 @@ static int __maybe_unused fec_resume(struct device *dev) | |||
3345 | { | 3427 | { |
3346 | struct net_device *ndev = dev_get_drvdata(dev); | 3428 | struct net_device *ndev = dev_get_drvdata(dev); |
3347 | struct fec_enet_private *fep = netdev_priv(ndev); | 3429 | struct fec_enet_private *fep = netdev_priv(ndev); |
3430 | struct fec_platform_data *pdata = fep->pdev->dev.platform_data; | ||
3348 | int ret; | 3431 | int ret; |
3432 | int val; | ||
3349 | 3433 | ||
3350 | if (fep->reg_phy) { | 3434 | if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) { |
3351 | ret = regulator_enable(fep->reg_phy); | 3435 | ret = regulator_enable(fep->reg_phy); |
3352 | if (ret) | 3436 | if (ret) |
3353 | return ret; | 3437 | return ret; |
@@ -3355,12 +3439,21 @@ static int __maybe_unused fec_resume(struct device *dev) | |||
3355 | 3439 | ||
3356 | rtnl_lock(); | 3440 | rtnl_lock(); |
3357 | if (netif_running(ndev)) { | 3441 | if (netif_running(ndev)) { |
3358 | pinctrl_pm_select_default_state(&fep->pdev->dev); | ||
3359 | ret = fec_enet_clk_enable(ndev, true); | 3442 | ret = fec_enet_clk_enable(ndev, true); |
3360 | if (ret) { | 3443 | if (ret) { |
3361 | rtnl_unlock(); | 3444 | rtnl_unlock(); |
3362 | goto failed_clk; | 3445 | goto failed_clk; |
3363 | } | 3446 | } |
3447 | if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) { | ||
3448 | if (pdata && pdata->sleep_mode_enable) | ||
3449 | pdata->sleep_mode_enable(false); | ||
3450 | val = readl(fep->hwp + FEC_ECNTRL); | ||
3451 | val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP); | ||
3452 | writel(val, fep->hwp + FEC_ECNTRL); | ||
3453 | fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON; | ||
3454 | } else { | ||
3455 | pinctrl_pm_select_default_state(&fep->pdev->dev); | ||
3456 | } | ||
3364 | fec_restart(ndev); | 3457 | fec_restart(ndev); |
3365 | netif_tx_lock_bh(ndev); | 3458 | netif_tx_lock_bh(ndev); |
3366 | netif_device_attach(ndev); | 3459 | netif_device_attach(ndev); |