Re: OHCI shutdown problem

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Alan,

I applied it by hand to my ubuntu natty backport kernel after reverting
to the original versions.
For me it works fine and I didn't notice any problem.

Thanks for the patches.

Arno


Am 03.11.2011 21:03, schrieb Alan Stern:
> Pail, Arno, and Andre:
>
> I think I have found a permanent solution to the problem of starting up 
> and shutting down NVIDIA OHCI controllers.  In order to test over the 
> widest range of controllers, I'd appreciate it if you could all try the 
> patch below.  It's meant to apply to the 3.1 kernel, but adapting it to 
> other kernel versions should be pretty easy.  (Arno, you should first 
> revert the test patch I sent you earlier.)
>
> The patch should even fix the problem some of you have seen when you 
> unload ohci-hcd and then load it back again.
>
> Please let me know how well it works for each of you.
>
> Thanks,
>
> Alan Stern
>
>
>
> Index: usb-3.2/drivers/usb/host/pci-quirks.c
> ===================================================================
> --- usb-3.2.orig/drivers/usb/host/pci-quirks.c
> +++ usb-3.2/drivers/usb/host/pci-quirks.c
> @@ -36,6 +36,7 @@
>  #define OHCI_INTRENABLE		0x10
>  #define OHCI_INTRDISABLE	0x14
>  #define OHCI_FMINTERVAL		0x34
> +#define OHCI_HCFS		(3 << 6)	/* hc functional state */
>  #define OHCI_HCR		(1 << 0)	/* host controller reset */
>  #define OHCI_OCR		(1 << 3)	/* ownership change request */
>  #define OHCI_CTRL_RWC		(1 << 9)	/* remote wakeup connected */
> @@ -465,6 +466,8 @@ static void __devinit quirk_usb_handoff_
>  {
>  	void __iomem *base;
>  	u32 control;
> +	u32 fminterval;
> +	int cnt;
>  
>  	if (!mmio_resource_enabled(pdev, 0))
>  		return;
> @@ -497,41 +500,32 @@ static void __devinit quirk_usb_handoff_
>  	}
>  #endif
>  
> -	/* reset controller, preserving RWC (and possibly IR) */
> -	writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
> -	readl(base + OHCI_CONTROL);
> -
> -	/* Some NVIDIA controllers stop working if kept in RESET for too long */
> -	if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) {
> -		u32 fminterval;
> -		int cnt;
> +	/* disable interrupts */
> +	writel((u32) ~0, base + OHCI_INTRDISABLE);
>  
> -		/* drive reset for at least 50 ms (7.1.7.5) */
> -		msleep(50);
> +	/* Reset the USB bus, if the controller isn't already in RESET */
> +	if (control & OHCI_HCFS) {
> +		/* Go into RESET, preserving RWC (and possibly IR) */
> +		writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
> +		readl(base + OHCI_CONTROL);
>  
> -		/* software reset of the controller, preserving HcFmInterval */
> -		fminterval = readl(base + OHCI_FMINTERVAL);
> -		writel(OHCI_HCR, base + OHCI_CMDSTATUS);
> -
> -		/* reset requires max 10 us delay */
> -		for (cnt = 30; cnt > 0; --cnt) {	/* ... allow extra time */
> -			if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
> -				break;
> -			udelay(1);
> -		}
> -		writel(fminterval, base + OHCI_FMINTERVAL);
> -
> -		/* Now we're in the SUSPEND state with all devices reset
> -		 * and wakeups and interrupts disabled
> -		 */
> +		/* drive bus reset for at least 50 ms (7.1.7.5) */
> +		msleep(50);
>  	}
>  
> -	/*
> -	 * disable interrupts
> -	 */
> -	writel(~(u32)0, base + OHCI_INTRDISABLE);
> -	writel(~(u32)0, base + OHCI_INTRSTATUS);
> +	/* software reset of the controller, preserving HcFmInterval */
> +	fminterval = readl(base + OHCI_FMINTERVAL);
> +	writel(OHCI_HCR, base + OHCI_CMDSTATUS);
> +
> +	/* reset requires max 10 us delay */
> +	for (cnt = 30; cnt > 0; --cnt) {	/* ... allow extra time */
> +		if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
> +			break;
> +		udelay(1);
> +	}
> +	writel(fminterval, base + OHCI_FMINTERVAL);
>  
> +	/* Now the controller is safely in SUSPEND and nothing can wake it up */
>  	iounmap(base);
>  }
>  
> Index: usb-3.2/drivers/usb/host/ohci.h
> ===================================================================
> --- usb-3.2.orig/drivers/usb/host/ohci.h
> +++ usb-3.2/drivers/usb/host/ohci.h
> @@ -403,7 +403,6 @@ struct ohci_hcd {
>  #define	OHCI_QUIRK_HUB_POWER	0x100			/* distrust firmware power/oc setup */
>  #define	OHCI_QUIRK_AMD_PLL	0x200			/* AMD PLL quirk*/
>  #define	OHCI_QUIRK_AMD_PREFETCH	0x400			/* pre-fetch for ISO transfer */
> -#define	OHCI_QUIRK_SHUTDOWN	0x800			/* nVidia power bug */
>  	// there are also chip quirks/bugs in init logic
>  
>  	struct work_struct	nec_work;	/* Worker for NEC quirk */
> Index: usb-3.2/drivers/usb/host/ohci-pci.c
> ===================================================================
> --- usb-3.2.orig/drivers/usb/host/ohci-pci.c
> +++ usb-3.2/drivers/usb/host/ohci-pci.c
> @@ -175,28 +175,6 @@ static int ohci_quirk_amd700(struct usb_
>  	return 0;
>  }
>  
> -/* nVidia controllers continue to drive Reset signalling on the bus
> - * even after system shutdown, wasting power.  This flag tells the
> - * shutdown routine to leave the controller OPERATIONAL instead of RESET.
> - */
> -static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd)
> -{
> -	struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
> -	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
> -
> -	/* Evidently nVidia fixed their later hardware; this is a guess at
> -	 * the changeover point.
> -	 */
> -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB		0x026d
> -
> -	if (pdev->device < PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_USB) {
> -		ohci->flags |= OHCI_QUIRK_SHUTDOWN;
> -		ohci_dbg(ohci, "enabled nVidia shutdown quirk\n");
> -	}
> -
> -	return 0;
> -}
> -
>  static void sb800_prefetch(struct ohci_hcd *ohci, int on)
>  {
>  	struct pci_dev *pdev;
> @@ -260,10 +238,6 @@ static const struct pci_device_id ohci_p
>  		PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399),
>  		.driver_data = (unsigned long)ohci_quirk_amd700,
>  	},
> -	{
> -		PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
> -		.driver_data = (unsigned long) ohci_quirk_nvidia_shutdown,
> -	},
>  
>  	/* FIXME for some of the early AMD 760 southbridges, OHCI
>  	 * won't work at all.  blacklist them.
> Index: usb-3.2/drivers/usb/host/ohci-hcd.c
> ===================================================================
> --- usb-3.2.orig/drivers/usb/host/ohci-hcd.c
> +++ usb-3.2/drivers/usb/host/ohci-hcd.c
> @@ -389,17 +389,14 @@ ohci_shutdown (struct usb_hcd *hcd)
>  	struct ohci_hcd *ohci;
>  
>  	ohci = hcd_to_ohci (hcd);
> -	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
> -	ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
> +	ohci_writel(ohci, (u32) ~0, &ohci->regs->intrdisable);
>  
> -	/* If the SHUTDOWN quirk is set, don't put the controller in RESET */
> -	ohci->hc_control &= (ohci->flags & OHCI_QUIRK_SHUTDOWN ?
> -			OHCI_CTRL_RWC | OHCI_CTRL_HCFS :
> -			OHCI_CTRL_RWC);
> -	ohci_writel(ohci, ohci->hc_control, &ohci->regs->control);
> +	/* Software reset, after which the controller goes into SUSPEND */
> +	ohci_writel(ohci, OHCI_HCR, &ohci->regs->cmdstatus);
> +	ohci_readl(ohci, &ohci->regs->cmdstatus);	/* flush the writes */
> +	udelay(10);
>  
> -	/* flush the writes */
> -	(void) ohci_readl (ohci, &ohci->regs->control);
> +	ohci_writel(ohci, ohci->fminterval, &ohci->regs->fminterval);
>  }
>  
>  static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
>

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux