[PATCH v2] powerpc/usb: fix bug of CPU hang when missing USB PHY clock

Kumar Gala galak at kernel.crashing.org
Tue Sep 18 15:35:09 EST 2012


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.
> 
> Signed-off-by: Shengzhou Liu <Shengzhou.Liu at freescale.com>
> ---
> 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?

- k

> 
> 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
> 



More information about the Linuxppc-dev mailing list