summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/freescale
diff options
context:
space:
mode:
authorShawn Guo <shawn.guo@freescale.com>2014-09-15 11:20:58 +0800
committerOctavian Purdila <octavian.purdila@nxp.com>2017-02-23 14:21:42 +0200
commitd40b0ffbda7b80a71bb222c405946a3922f2f689 (patch)
tree8c8a442e5053153058504f15a24405087e462ce1 /drivers/net/ethernet/freescale
parent6f70ef55178c9b9ec4147cf0b1de0fcd450bb878 (diff)
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 <shawn.guo@freescale.com> (cherry-pick and merge from commit: 4f406fae257cc7945a0e3a425213440bb12ba345)
Diffstat (limited to 'drivers/net/ethernet/freescale')
-rw-r--r--drivers/net/ethernet/freescale/fec.h8
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c31
2 files changed, 38 insertions, 1 deletions
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 <linux/clocksource.h>
#include <linux/net_tstamp.h>
+#include <linux/pm_qos.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/timecounter.h>
@@ -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 12aef1b15356..348882efa9da 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,
@@ -2820,10 +2820,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);
@@ -2858,6 +2877,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);