[PATCH 052/149] USB: Fix NEC OHCI chip silicon bug

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Greg Kroah-Hartman
Date: Thursday, July 12, 2007 - 4:41 pm

From: Michael Hanselmann <linux-kernel@hansmi.ch>

This patch fixes a silicon bug in some NEC OHCI chips. The bug appears
at random times and is very, very difficult to reproduce. Without the
following patch, Linux would shut the chip and its associated devices
down. In Apple PowerBooks this leads to an unusable keyboard and mouse
(SSH still working). The idea of restarting the chip is taken from
public Darwin code.

Signed-off-by: Michael Hanselmann <linux-kernel@hansmi.ch>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/usb/host/ohci-hcd.c |   51 ++++++++++++++++++++++++++++++++----------
 drivers/usb/host/ohci-hub.c |    5 ++-
 drivers/usb/host/ohci-mem.c |    1 +
 drivers/usb/host/ohci-pci.c |   16 +++++++++++++
 drivers/usb/host/ohci.h     |    2 +
 5 files changed, 61 insertions(+), 14 deletions(-)

diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index ce05e5f..44717fa 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -35,6 +35,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/reboot.h>
+#include <linux/workqueue.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -82,6 +83,8 @@ static const char	hcd_name [] = "ohci_hcd";
 static void ohci_dump (struct ohci_hcd *ohci, int verbose);
 static int ohci_init (struct ohci_hcd *ohci);
 static void ohci_stop (struct usb_hcd *hcd);
+static int ohci_restart (struct ohci_hcd *ohci);
+static void ohci_quirk_nec_worker (struct work_struct *work);
 
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
@@ -651,9 +654,20 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 	}
 
 	if (ints & OHCI_INTR_UE) {
-		disable (ohci);
-		ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
 		// e.g. due to PCI Master/Target Abort
+		if (ohci->flags & OHCI_QUIRK_NEC) {
+			/* Workaround for a silicon bug in some NEC chips used
+			 * in Apple's PowerBooks. Adapted from Darwin code.
+			 */
+			ohci_err (ohci, "OHCI Unrecoverable Error, scheduling NEC chip restart\n");
+
+			ohci_writel (ohci, OHCI_INTR_UE, &regs->intrdisable);
+
+			schedule_work (&ohci->nec_work);
+		} else {
+			disable (ohci);
+			ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
+		}
 
 		ohci_dump (ohci, 1);
 		ohci_usb_reset (ohci);
@@ -755,23 +769,16 @@ static void ohci_stop (struct usb_hcd *hcd)
 /*-------------------------------------------------------------------------*/
 
 /* must not be called from interrupt context */
-
-#ifdef	CONFIG_PM
-
 static int ohci_restart (struct ohci_hcd *ohci)
 {
 	int temp;
 	int i;
 	struct urb_priv *priv;
 
-	/* mark any devices gone, so they do nothing till khubd disconnects.
-	 * recycle any "live" eds/tds (and urbs) right away.
-	 * later, khubd disconnect processing will recycle the other state,
-	 * (either as disconnect/reconnect, or maybe someday as a reset).
-	 */
 	spin_lock_irq(&ohci->lock);
 	disable (ohci);
-	usb_root_hub_lost_power(ohci_to_hcd(ohci)->self.root_hub);
+
+	/* Recycle any "live" eds/tds (and urbs). */
 	if (!list_empty (&ohci->pending))
 		ohci_dbg(ohci, "abort schedule...\n");
 	list_for_each_entry (priv, &ohci->pending, pending) {
@@ -822,7 +829,27 @@ static int ohci_restart (struct ohci_hcd *ohci)
 	ohci_dbg(ohci, "restart complete\n");
 	return 0;
 }
-#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* NEC workaround */
+static void ohci_quirk_nec_worker(struct work_struct *work)
+{
+	struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
+	int status;
+
+	status = ohci_init(ohci);
+	if (status != 0) {
+		ohci_err(ohci, "Restarting NEC controller failed "
+			 "in ohci_init, %d\n", status);
+		return;
+	}
+
+	status = ohci_restart(ohci);
+	if (status != 0)
+		ohci_err(ohci, "Restarting NEC controller failed "
+			 "in ohci_restart, %d\n", status);
+}
 
 /*-------------------------------------------------------------------------*/
 
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index bb9cc59..48e4b11 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -55,8 +55,6 @@ static void dl_done_list (struct ohci_hcd *);
 static void finish_unlinks (struct ohci_hcd *, u16);
 
 #ifdef	CONFIG_PM
-static int ohci_restart(struct ohci_hcd *ohci);
-
 static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop)
 __releases(ohci->lock)
 __acquires(ohci->lock)
@@ -191,6 +189,9 @@ __acquires(ohci->lock)
 			spin_unlock_irq (&ohci->lock);
 			(void) ohci_init (ohci);
 			status = ohci_restart (ohci);
+
+			usb_root_hub_lost_power(hcd->self.root_hub);
+
 			spin_lock_irq (&ohci->lock);
 		}
 		return status;
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index 2f20d3d..450c7b4 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -28,6 +28,7 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
 	ohci->next_statechange = jiffies;
 	spin_lock_init (&ohci->lock);
 	INIT_LIST_HEAD (&ohci->pending);
+	INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
 }
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 15013f4..a5e2eb8 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -111,6 +111,18 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
 #endif
 }
 
+/* Check for NEC chip and apply quirk for allegedly lost interrupts.
+ */
+static int ohci_quirk_nec(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+	ohci->flags |= OHCI_QUIRK_NEC;
+	ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
+
+	return 0;
+}
+
 /* List of quirks for OHCI */
 static const struct pci_device_id ohci_pci_quirks[] = {
 	{
@@ -134,6 +146,10 @@ static const struct pci_device_id ohci_pci_quirks[] = {
 		.driver_data = (unsigned long)ohci_quirk_toshiba_scc,
 	},
 	{
+		PCI_DEVICE(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB),
+		.driver_data = (unsigned long)ohci_quirk_nec,
+	},
+	{
 		/* Toshiba portege 4000 */
 		.vendor		= PCI_VENDOR_ID_AL,
 		.device		= 0x5237,
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index c2b5ecf..4ada43c 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -397,8 +397,10 @@ struct ohci_hcd {
 #define	OHCI_QUIRK_BE_DESC	0x08			/* BE descriptors */
 #define	OHCI_QUIRK_BE_MMIO	0x10			/* BE registers */
 #define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
+#define	OHCI_QUIRK_NEC		0x40			/* lost interrupts */
 	// there are also chip quirks/bugs in init logic
 
+	struct work_struct	nec_work;	/* Worker for NEC quirk */
 };
 
 /* convert between an hcd pointer and the corresponding ohci_hcd */
-- 
1.5.2.2


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[PATCH 029/149] USB: usb gadget, dead config cleanup, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 030/149] USB: add USB_DEVICE_AND_INTERFACE_INFO for ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 031/149] USB: hub.c loops forever on resume from ra ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 032/149] USB: prevent char device open/deregister race, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 033/149] USB: rework C++-style comments, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 034/149] USB: ftdi_sio.c: Allow setting latency tim ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 035/149] USB: EHCI big endian data structures suppo ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 036/149] USB: Set CONFIG_USB_EHCI_BIG_ENDIAN_MMIO/_ ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 037/149] USB: ehci_fsl update for MPC831x support, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 038/149] USB: use function attribute __maybe_unused, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 040/149] USB: visor driver adapted to new tty buffering, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 041/149] USB: Digi AccelePort adapted to new tty bu ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 042/149] USB: generic usb serial to new buffering s ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 043/149] USB: flow control fix for pl2303, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 044/149] USB: usb serial gadget, sparse fixes, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 045/149] USB Core: hub.c: prevent re-enumeration on HNP, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 046/149] USB: introduce usb_anchor, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 047/149] USB: usb-skeleton: usb anchor to implement ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 048/149] USB: whiteheat driver update, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 049/149] USB: digi_acceleport further buffer clean up, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 050/149] USB: EHCI: Safe endianness for transfer bu ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 051/149] USB: Disable file_storage USB_CONFIG_ATT_W ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 052/149] USB: Fix NEC OHCI chip silicon bug, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 053/149] USB: remove __usb_port_suspend, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 054/149] USB: separate root and non-root suspend/resume, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 055/149] USB: remove excess code from hub.c, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 056/149] USB: add reset_resume method, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 057/149] USB: unify reset_resume and normal resume, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 058/149] USB: add power/persist device attribute, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 059/149] USB: fsl_usb2_udc: replace deprecated irq flag, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 060/149] USB: fsl_usb2_udc: Get max ep number from ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 061/149] USB: option: fix usage of urb-&gt;status abuse, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 062/149] USB: PS3: USB system-bus rework, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 063/149] USB Gadget driver for Samsung s3c2410 ARM SoC, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 064/149] USB: usb-storage: use kthread_stop() for t ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 065/149] USB: usb host side can be configured given ..., Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
[PATCH 066/149] ehci-hub: improved over-current recovery, Greg Kroah-Hartman, (Thu Jul 12, 4:41 pm)
Re: [PATCH 033/149] USB: rework C++-style comments, David Brownell, (Thu Jul 12, 8:27 pm)
Re: [PATCH 048/149] USB: whiteheat driver update, Ragner Magalhaes, (Fri Jul 13, 12:50 pm)
Re: [PATCH 048/149] USB: whiteheat driver update, Felipe Balbi, (Fri Jul 13, 12:53 pm)