powerpc/usb: fix bug of CPU hang when missing USB PHY clock

Started by Shengzhou Liu on Aug 22, 2012 · 4 messages from 4 authors · Last reply Sep 18, 2012

Subsystems (3)

Maintainers (3)

STALE5166d

open the first message on its own page

Message details and related content
when missing USB PHY clock, kernel booting up will hang during USB
initialization. We should check USBGP[PHY_CLK_VALID] bit to avoid
CPU hanging in this case.

Signed-off-by: Shengzhou Liu <redacted>
---
v2 changes: use spin_event_timeout() instead.

 drivers/usb/host/ehci-fsl.c |   58 +++++++++++++++++++++++++++++-------------
 drivers/usb/host/ehci-fsl.h |    1 +
 include/linux/fsl_devices.h |    1 +
 3 files changed, 42 insertions(+), 18 deletions(-)
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index b7451b2..11ff4b4 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -210,11 +210,11 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
 	usb_put_hcd(hcd);
 }
 
-static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
+static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
 			       enum fsl_usb2_phy_modes phy_mode,
 			       unsigned int port_offset)
 {
-	u32 portsc, temp;
+	u32 portsc;
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	void __iomem *non_ehci = hcd->regs;
 	struct device *dev = hcd->self.controller;
@@ -232,9 +232,15 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
 	case FSL_USB2_PHY_ULPI:
 		if (pdata->controller_ver) {
 			/* controller version 1.6 or above */
-			temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-			out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
-				USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL);
+			setbits32(non_ehci + FSL_SOC_USB_CTRL,
+					ULPI_PHY_CLK_SEL);
+			/*
+			 * Due to controller issue of PHY_CLK_VALID in ULPI
+			 * mode, we set USB_CTRL_USB_EN before checking
+			 * PHY_CLK_VALID, otherwise PHY_CLK_VALID doesn't work.
+			 */
+			clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL,
+					UTMI_PHY_EN, USB_CTRL_USB_EN);
 		}
 		portsc |= PORT_PTS_ULPI;
 		break;
@@ -247,9 +253,7 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
 	case FSL_USB2_PHY_UTMI:
 		if (pdata->controller_ver) {
 			/* controller version 1.6 or above */
-			temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-			out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
-				UTMI_PHY_EN | USB_CTRL_USB_EN);
+			setbits32(non_ehci + FSL_SOC_USB_CTRL, UTMI_PHY_EN);
 			mdelay(FSL_UTMI_PHY_DLY);  /* Delay for UTMI PHY CLK to
 						become stable - 10ms*/
 		}
@@ -262,23 +266,34 @@ static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
 	case FSL_USB2_PHY_NONE:
 		break;
 	}
+
+	if ((pdata->controller_ver) && ((phy_mode == FSL_USB2_PHY_ULPI) ||
+			(phy_mode == FSL_USB2_PHY_UTMI))) {
+		/* check PHY_CLK_VALID to get phy clk valid */
+		if (!spin_event_timeout(in_be32(non_ehci + FSL_SOC_USB_CTRL) &
+				PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, 0)) {
+			printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n");
+			return -EINVAL;
+		}
+	}
+
 	ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
+
+	if (phy_mode != FSL_USB2_PHY_ULPI)
+		setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN);
+
+	return 0;
 }
 
-static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
+static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 {
 	struct usb_hcd *hcd = ehci_to_hcd(ehci);
 	struct fsl_usb2_platform_data *pdata;
 	void __iomem *non_ehci = hcd->regs;
-	u32 temp;
 
 	pdata = hcd->self.controller->platform_data;
 
-	/* Enable PHY interface in the control reg. */
 	if (pdata->have_sysif_regs) {
-		temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-		out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
-
 		/*
 		* Turn on cache snooping hardware, since some PowerPC platforms
 		* wholly rely on hardware to deal with cache coherent
@@ -293,7 +308,8 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 
 	if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
 			(pdata->operating_mode == FSL_USB2_DR_OTG))
-		ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
+		if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
+			return -EINVAL;
 
 	if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
 		unsigned int chip, rev, svr;
@@ -307,9 +323,12 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 			ehci->has_fsl_port_bug = 1;
 
 		if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
-			ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
+			if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
+				return -EINVAL;
+
 		if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
-			ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1);
+			if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1))
+				return -EINVAL;
 	}
 
 	if (pdata->have_sysif_regs) {
@@ -322,12 +341,15 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 #endif
 		out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
 	}
+
+	return 0;
 }
 
 /* called after powerup, by probe or system-pm "wakeup" */
 static int ehci_fsl_reinit(struct ehci_hcd *ehci)
 {
-	ehci_fsl_usb_setup(ehci);
+	if (ehci_fsl_usb_setup(ehci))
+		return -EINVAL;
 	ehci_port_power(ehci, 0);
 
 	return 0;
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index 8840368..dbd292e 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -61,4 +61,5 @@
 #define PLL_RESET               (1<<8)
 #define UTMI_PHY_EN             (1<<9)
 #define ULPI_PHY_CLK_SEL        (1<<10)
+#define PHY_CLK_VALID		(1<<17)
 #endif				/* _EHCI_FSL_H */
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 15be561..ccfc4bb 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -19,6 +19,7 @@
 
 #define FSL_UTMI_PHY_DLY	10	/*As per P1010RM, delay for UTMI
 				PHY CLK to become stable - 10ms*/
+#define FSL_USB_PHY_CLK_TIMEOUT	1000	/* uSec */
 #define FSL_USB_VER_OLD		0
 #define FSL_USB_VER_1_6		1
 #define FSL_USB_VER_2_2		2
-- 
1.6.4
Message details and related content
On Aug 22, 2012, at 5:17 AM, Shengzhou Liu wrote:
when missing USB PHY clock, kernel booting up will hang during USB
initialization. We should check USBGP[PHY_CLK_VALID] bit to avoid
CPU hanging in this case.
=20
Signed-off-by: Shengzhou Liu <redacted>
---
v2 changes: use spin_event_timeout() instead.
=20
drivers/usb/host/ehci-fsl.c |   58 =
+++++++++++++++++++++++++++++-------------
drivers/usb/host/ehci-fsl.h |    1 +
include/linux/fsl_devices.h |    1 +
3 files changed, 42 insertions(+), 18 deletions(-)
Greg,

Any issues picking this fix up for v3.6 inclusion?

- k
quoted hunk
=20
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index b7451b2..11ff4b4 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -210,11 +210,11 @@ static void usb_hcd_fsl_remove(struct usb_hcd =
*hcd,
quoted hunk
	usb_put_hcd(hcd);
}
=20
-static void ehci_fsl_setup_phy(struct usb_hcd *hcd,
+static int ehci_fsl_setup_phy(struct usb_hcd *hcd,
			       enum fsl_usb2_phy_modes phy_mode,
			       unsigned int port_offset)
{
-	u32 portsc, temp;
+	u32 portsc;
	struct ehci_hcd *ehci =3D hcd_to_ehci(hcd);
	void __iomem *non_ehci =3D hcd->regs;
	struct device *dev =3D hcd->self.controller;
@@ -232,9 +232,15 @@ static void ehci_fsl_setup_phy(struct usb_hcd =
*hcd,
	case FSL_USB2_PHY_ULPI:
		if (pdata->controller_ver) {
			/* controller version 1.6 or above */
-			temp =3D in_be32(non_ehci + FSL_SOC_USB_CTRL);
-			out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
-				USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL);
+			setbits32(non_ehci + FSL_SOC_USB_CTRL,
+					ULPI_PHY_CLK_SEL);
+			/*
+			 * Due to controller issue of PHY_CLK_VALID in =
ULPI
+			 * mode, we set USB_CTRL_USB_EN before checking
+			 * PHY_CLK_VALID, otherwise PHY_CLK_VALID =
doesn't work.
quoted hunk
+			 */
+			clrsetbits_be32(non_ehci + FSL_SOC_USB_CTRL,
+					UTMI_PHY_EN, USB_CTRL_USB_EN);
		}
		portsc |=3D PORT_PTS_ULPI;
		break;
@@ -247,9 +253,7 @@ static void ehci_fsl_setup_phy(struct usb_hcd =
*hcd,
	case FSL_USB2_PHY_UTMI:
		if (pdata->controller_ver) {
			/* controller version 1.6 or above */
-			temp =3D in_be32(non_ehci + FSL_SOC_USB_CTRL);
-			out_be32(non_ehci + FSL_SOC_USB_CTRL, temp |
-				UTMI_PHY_EN | USB_CTRL_USB_EN);
+			setbits32(non_ehci + FSL_SOC_USB_CTRL, =
UTMI_PHY_EN);
			mdelay(FSL_UTMI_PHY_DLY);  /* Delay for UTMI PHY =
CLK to
quoted hunk
						become stable - 10ms*/
		}
@@ -262,23 +266,34 @@ static void ehci_fsl_setup_phy(struct usb_hcd =
*hcd,
	case FSL_USB2_PHY_NONE:
		break;
	}
+
+	if ((pdata->controller_ver) && ((phy_mode =3D=3D =
FSL_USB2_PHY_ULPI) ||
quoted hunk
+			(phy_mode =3D=3D FSL_USB2_PHY_UTMI))) {
+		/* check PHY_CLK_VALID to get phy clk valid */
+		if (!spin_event_timeout(in_be32(non_ehci + =
FSL_SOC_USB_CTRL) &
+				PHY_CLK_VALID, FSL_USB_PHY_CLK_TIMEOUT, =
0)) {
+			printk(KERN_WARNING "fsl-ehci: USB PHY clock =
invalid\n");
+			return -EINVAL;
+		}
+	}
+
	ehci_writel(ehci, portsc, =
&ehci->regs->port_status[port_offset]);
+
+	if (phy_mode !=3D FSL_USB2_PHY_ULPI)
+		setbits32(non_ehci + FSL_SOC_USB_CTRL, USB_CTRL_USB_EN);
+
+	return 0;
}
=20
-static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
+static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
{
	struct usb_hcd *hcd =3D ehci_to_hcd(ehci);
	struct fsl_usb2_platform_data *pdata;
	void __iomem *non_ehci =3D hcd->regs;
-	u32 temp;
=20
	pdata =3D hcd->self.controller->platform_data;
=20
-	/* Enable PHY interface in the control reg. */
	if (pdata->have_sysif_regs) {
-		temp =3D in_be32(non_ehci + FSL_SOC_USB_CTRL);
-		out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | =
0x00000004);
-
		/*
		* Turn on cache snooping hardware, since some PowerPC =
platforms
quoted hunk
		* wholly rely on hardware to deal with cache coherent
@@ -293,7 +308,8 @@ static void ehci_fsl_usb_setup(struct ehci_hcd =
*ehci)
quoted hunk
=20
	if ((pdata->operating_mode =3D=3D FSL_USB2_DR_HOST) ||
			(pdata->operating_mode =3D=3D FSL_USB2_DR_OTG))
-		ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
+		if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
+			return -EINVAL;
=20
	if (pdata->operating_mode =3D=3D FSL_USB2_MPH_HOST) {
		unsigned int chip, rev, svr;
@@ -307,9 +323,12 @@ static void ehci_fsl_usb_setup(struct ehci_hcd =
*ehci)
quoted hunk
			ehci->has_fsl_port_bug =3D 1;
=20
		if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
-			ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0);
+			if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0))
+				return -EINVAL;
+
		if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
-			ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1);
+			if (ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1))
+				return -EINVAL;
	}
=20
	if (pdata->have_sysif_regs) {
@@ -322,12 +341,15 @@ static void ehci_fsl_usb_setup(struct ehci_hcd =
*ehci)
quoted hunk
#endif
		out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
	}
+
+	return 0;
}
=20
/* called after powerup, by probe or system-pm "wakeup" */
static int ehci_fsl_reinit(struct ehci_hcd *ehci)
{
-	ehci_fsl_usb_setup(ehci);
+	if (ehci_fsl_usb_setup(ehci))
+		return -EINVAL;
	ehci_port_power(ehci, 0);
=20
	return 0;
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index 8840368..dbd292e 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -61,4 +61,5 @@
#define PLL_RESET               (1<<8)
#define UTMI_PHY_EN             (1<<9)
#define ULPI_PHY_CLK_SEL        (1<<10)
+#define PHY_CLK_VALID		(1<<17)
#endif				/* _EHCI_FSL_H */
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 15be561..ccfc4bb 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -19,6 +19,7 @@
=20
#define FSL_UTMI_PHY_DLY	10	/*As per P1010RM, delay for UTMI
				PHY CLK to become stable - 10ms*/
+#define FSL_USB_PHY_CLK_TIMEOUT	1000	/* uSec */
#define FSL_USB_VER_OLD		0
#define FSL_USB_VER_1_6		1
#define FSL_USB_VER_2_2		2
--=20
1.6.4

1 more quoted lines

Message details and related content
-----Original Message-----
From: Kumar Gala [mailto:<redacted>]
Sent: Tuesday, September 18, 2012 1:35 PM
To: Greg KH
Cc: Liu Shengzhou-B36685; <redacted> list; linux-
usb@vger.kernel.org
Subject: Re: [PATCH v2] powerpc/usb: fix bug of CPU hang when missing USB
PHY clock
=20
=20
On Aug 22, 2012, at 5:17 AM, Shengzhou Liu wrote:
=20
quoted
when missing USB PHY clock, kernel booting up will hang during USB
initialization. We should check USBGP[PHY_CLK_VALID] bit to avoid CPU
hanging in this case.

Signed-off-by: Shengzhou Liu <redacted>
---
v2 changes: use spin_event_timeout() instead.

drivers/usb/host/ehci-fsl.c |   58 +++++++++++++++++++++++++++++-------
------
quoted
drivers/usb/host/ehci-fsl.h |    1 +
include/linux/fsl_devices.h |    1 +
3 files changed, 42 insertions(+), 18 deletions(-)
=20
Greg,
=20
Any issues picking this fix up for v3.6 inclusion?
=20
- k
=20
[Shengzhou] please pick the v3, thanks.
http://patchwork.ozlabs.org/patch/184666/
Message details and related content
On Tue, Sep 18, 2012 at 12:35:09AM -0500, Kumar Gala wrote:
On Aug 22, 2012, at 5:17 AM, Shengzhou Liu wrote:
quoted
when missing USB PHY clock, kernel booting up will hang during USB
initialization. We should check USBGP[PHY_CLK_VALID] bit to avoid
CPU hanging in this case.

Signed-off-by: Shengzhou Liu <redacted>
---
v2 changes: use spin_event_timeout() instead.

drivers/usb/host/ehci-fsl.c |   58 +++++++++++++++++++++++++++++-------------
drivers/usb/host/ehci-fsl.h |    1 +
include/linux/fsl_devices.h |    1 +
3 files changed, 42 insertions(+), 18 deletions(-)
Greg,

Any issues picking this fix up for v3.6 inclusion?
Yes, I will not as there is a v3 out there that I want some review on
before I can take it...

thanks,

greg k-h
Keyboard shortcuts
hback out one level
jnext message in thread / next series-diff position
kprevious message in thread / previous series-diff position
ldrill in
Escclose help / fold thread tree
?toggle this help