From: Shawn Guo Date: Mon, 15 Sep 2014 03:20:58 +0000 (+0800) Subject: MLK-11285-01 net: fec: handle WAIT mode issue for imx6qdl X-Git-Tag: C0P2-H0.0--20200415~4793 X-Git-Url: https://git.somdevices.com/?a=commitdiff_plain;h=4020b9109e0a66f0f018ef850f2e7d6c230a4745;p=linux.git MLK-11285-01 net: fec: handle WAIT mode issue for imx6qdl This is a combination of commits 919d46e37e04 (ENGR00265935 net: fec: add pm_qos to avoid cpu enter to wait mode) and 8a12c90c9974 (ENGR00313685-14 net: fec: check workaround for FEC_QUIRK_BUG_WAITMODE) from imx_3.10.y branch. It's added for imx_3.14.y branch to work around imx6qdl issue ERR006687 (ENET: Only the ENET wake-up interrupt request can wake the system from Wait mode). Signed-off-by: Shawn Guo (cherry-pick and merge from commit: 4f406fae257cc7945a0e3a425213440bb12ba345) --- diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 5ea740b4cf14..a6a977bb1345 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -446,6 +447,12 @@ struct bufdesc_ex { #define FEC_QUIRK_HAS_COALESCE (1 << 13) /* Interrupt doesn't wake CPU from deep idle */ #define FEC_QUIRK_ERR006687 (1 << 14) +/* + * i.MX6Q/DL ENET cannot wake up system in wait mode because ENET tx & rx + * interrupt signal don't connect to GPC. So use pm qos to avoid cpu enter + * to wait mode. + */ +#define FEC_QUIRK_BUG_WAITMODE (1 << 15) struct bufdesc_prop { int qid; @@ -553,6 +560,7 @@ struct fec_enet_private { int hwts_tx_en; struct delayed_work time_keep; struct regulator *reg_phy; + struct pm_qos_request pm_qos_req; unsigned int tx_align; unsigned int rx_align; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 917091871259..c0dc643d9ad0 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -102,7 +102,7 @@ static struct platform_device_id fec_devtype[] = { .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT | FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM | FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 | - FEC_QUIRK_HAS_RACC, + FEC_QUIRK_HAS_RACC | FEC_QUIRK_BUG_WAITMODE, }, { .name = "mvf600-fec", .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC, @@ -2828,10 +2828,29 @@ static int fec_enet_alloc_buffers(struct net_device *ndev) return 0; } +static inline bool fec_enet_irq_workaround(struct fec_enet_private *fep) +{ + struct device_node *np = fep->pdev->dev.of_node; + struct device_node *intr_node; + + intr_node = of_parse_phandle(np, "interrupts-extended", 0); + if (intr_node && !strcmp(intr_node->name, "gpio")) { + /* + * If the interrupt controller is a GPIO node, it must have + * applied the workaround for WAIT mode bug. + */ + return true; + } + + return false; +} + static int fec_enet_open(struct net_device *ndev) { struct fec_enet_private *fep = netdev_priv(ndev); + const struct platform_device_id *id_entry = + platform_get_device_id(fep->pdev); int ret; ret = pm_runtime_get_sync(&fep->pdev->dev); @@ -2866,6 +2885,16 @@ fec_enet_open(struct net_device *ndev) phy_start(ndev->phydev); netif_tx_start_all_queues(ndev); + if ((id_entry->driver_data & FEC_QUIRK_BUG_WAITMODE) && + !fec_enet_irq_workaround(fep)) + pm_qos_add_request(&fep->pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, + 0); + else + pm_qos_add_request(&fep->pm_qos_req, + PM_QOS_CPU_DMA_LATENCY, + PM_QOS_DEFAULT_VALUE); + device_set_wakeup_enable(&ndev->dev, fep->wol_flag & FEC_WOL_FLAG_ENABLE);