aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/host/ohci-hcd.c51
-rw-r--r--drivers/usb/host/ohci-hub.c5
-rw-r--r--drivers/usb/host/ohci-mem.c1
-rw-r--r--drivers/usb/host/ohci-pci.c16
-rw-r--r--drivers/usb/host/ohci.h2
5 files changed, 61 insertions, 14 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index ce05e5f7bed6..44717fab7435 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -35,6 +35,7 @@
35#include <linux/dma-mapping.h> 35#include <linux/dma-mapping.h>
36#include <linux/dmapool.h> 36#include <linux/dmapool.h>
37#include <linux/reboot.h> 37#include <linux/reboot.h>
38#include <linux/workqueue.h>
38 39
39#include <asm/io.h> 40#include <asm/io.h>
40#include <asm/irq.h> 41#include <asm/irq.h>
@@ -82,6 +83,8 @@ static const char hcd_name [] = "ohci_hcd";
82static void ohci_dump (struct ohci_hcd *ohci, int verbose); 83static void ohci_dump (struct ohci_hcd *ohci, int verbose);
83static int ohci_init (struct ohci_hcd *ohci); 84static int ohci_init (struct ohci_hcd *ohci);
84static void ohci_stop (struct usb_hcd *hcd); 85static void ohci_stop (struct usb_hcd *hcd);
86static int ohci_restart (struct ohci_hcd *ohci);
87static void ohci_quirk_nec_worker (struct work_struct *work);
85 88
86#include "ohci-hub.c" 89#include "ohci-hub.c"
87#include "ohci-dbg.c" 90#include "ohci-dbg.c"
@@ -651,9 +654,20 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
651 } 654 }
652 655
653 if (ints & OHCI_INTR_UE) { 656 if (ints & OHCI_INTR_UE) {
654 disable (ohci);
655 ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
656 // e.g. due to PCI Master/Target Abort 657 // e.g. due to PCI Master/Target Abort
658 if (ohci->flags & OHCI_QUIRK_NEC) {
659 /* Workaround for a silicon bug in some NEC chips used
660 * in Apple's PowerBooks. Adapted from Darwin code.
661 */
662 ohci_err (ohci, "OHCI Unrecoverable Error, scheduling NEC chip restart\n");
663
664 ohci_writel (ohci, OHCI_INTR_UE, &regs->intrdisable);
665
666 schedule_work (&ohci->nec_work);
667 } else {
668 disable (ohci);
669 ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
670 }
657 671
658 ohci_dump (ohci, 1); 672 ohci_dump (ohci, 1);
659 ohci_usb_reset (ohci); 673 ohci_usb_reset (ohci);
@@ -755,23 +769,16 @@ static void ohci_stop (struct usb_hcd *hcd)
755/*-------------------------------------------------------------------------*/ 769/*-------------------------------------------------------------------------*/
756 770
757/* must not be called from interrupt context */ 771/* must not be called from interrupt context */
758
759#ifdef CONFIG_PM
760
761static int ohci_restart (struct ohci_hcd *ohci) 772static int ohci_restart (struct ohci_hcd *ohci)
762{ 773{
763 int temp; 774 int temp;
764 int i; 775 int i;
765 struct urb_priv *priv; 776 struct urb_priv *priv;
766 777
767 /* mark any devices gone, so they do nothing till khubd disconnects.
768 * recycle any "live" eds/tds (and urbs) right away.
769 * later, khubd disconnect processing will recycle the other state,
770 * (either as disconnect/reconnect, or maybe someday as a reset).
771 */
772 spin_lock_irq(&ohci->lock); 778 spin_lock_irq(&ohci->lock);
773 disable (ohci); 779 disable (ohci);
774 usb_root_hub_lost_power(ohci_to_hcd(ohci)->self.root_hub); 780
781 /* Recycle any "live" eds/tds (and urbs). */
775 if (!list_empty (&ohci->pending)) 782 if (!list_empty (&ohci->pending))
776 ohci_dbg(ohci, "abort schedule...\n"); 783 ohci_dbg(ohci, "abort schedule...\n");
777 list_for_each_entry (priv, &ohci->pending, pending) { 784 list_for_each_entry (priv, &ohci->pending, pending) {
@@ -822,7 +829,27 @@ static int ohci_restart (struct ohci_hcd *ohci)
822 ohci_dbg(ohci, "restart complete\n"); 829 ohci_dbg(ohci, "restart complete\n");
823 return 0; 830 return 0;
824} 831}
825#endif 832
833/*-------------------------------------------------------------------------*/
834
835/* NEC workaround */
836static void ohci_quirk_nec_worker(struct work_struct *work)
837{
838 struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
839 int status;
840
841 status = ohci_init(ohci);
842 if (status != 0) {
843 ohci_err(ohci, "Restarting NEC controller failed "
844 "in ohci_init, %d\n", status);
845 return;
846 }
847
848 status = ohci_restart(ohci);
849 if (status != 0)
850 ohci_err(ohci, "Restarting NEC controller failed "
851 "in ohci_restart, %d\n", status);
852}
826 853
827/*-------------------------------------------------------------------------*/ 854/*-------------------------------------------------------------------------*/
828 855
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index bb9cc595219e..48e4b11f4d3e 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 *);
55static void finish_unlinks (struct ohci_hcd *, u16); 55static void finish_unlinks (struct ohci_hcd *, u16);
56 56
57#ifdef CONFIG_PM 57#ifdef CONFIG_PM
58static int ohci_restart(struct ohci_hcd *ohci);
59
60static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) 58static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop)
61__releases(ohci->lock) 59__releases(ohci->lock)
62__acquires(ohci->lock) 60__acquires(ohci->lock)
@@ -191,6 +189,9 @@ __acquires(ohci->lock)
191 spin_unlock_irq (&ohci->lock); 189 spin_unlock_irq (&ohci->lock);
192 (void) ohci_init (ohci); 190 (void) ohci_init (ohci);
193 status = ohci_restart (ohci); 191 status = ohci_restart (ohci);
192
193 usb_root_hub_lost_power(hcd->self.root_hub);
194
194 spin_lock_irq (&ohci->lock); 195 spin_lock_irq (&ohci->lock);
195 } 196 }
196 return status; 197 return status;
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index 2f20d3dc895b..450c7b460c5a 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)
28 ohci->next_statechange = jiffies; 28 ohci->next_statechange = jiffies;
29 spin_lock_init (&ohci->lock); 29 spin_lock_init (&ohci->lock);
30 INIT_LIST_HEAD (&ohci->pending); 30 INIT_LIST_HEAD (&ohci->pending);
31 INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
31} 32}
32 33
33/*-------------------------------------------------------------------------*/ 34/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 15013f4519ad..a5e2eb85d073 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)
111#endif 111#endif
112} 112}
113 113
114/* Check for NEC chip and apply quirk for allegedly lost interrupts.
115 */
116static int ohci_quirk_nec(struct usb_hcd *hcd)
117{
118 struct ohci_hcd *ohci = hcd_to_ohci (hcd);
119
120 ohci->flags |= OHCI_QUIRK_NEC;
121 ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
122
123 return 0;
124}
125
114/* List of quirks for OHCI */ 126/* List of quirks for OHCI */
115static const struct pci_device_id ohci_pci_quirks[] = { 127static const struct pci_device_id ohci_pci_quirks[] = {
116 { 128 {
@@ -134,6 +146,10 @@ static const struct pci_device_id ohci_pci_quirks[] = {
134 .driver_data = (unsigned long)ohci_quirk_toshiba_scc, 146 .driver_data = (unsigned long)ohci_quirk_toshiba_scc,
135 }, 147 },
136 { 148 {
149 PCI_DEVICE(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB),
150 .driver_data = (unsigned long)ohci_quirk_nec,
151 },
152 {
137 /* Toshiba portege 4000 */ 153 /* Toshiba portege 4000 */
138 .vendor = PCI_VENDOR_ID_AL, 154 .vendor = PCI_VENDOR_ID_AL,
139 .device = 0x5237, 155 .device = 0x5237,
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index c2b5ecfe5e9f..4ada43cf1387 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -397,8 +397,10 @@ struct ohci_hcd {
397#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */ 397#define OHCI_QUIRK_BE_DESC 0x08 /* BE descriptors */
398#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */ 398#define OHCI_QUIRK_BE_MMIO 0x10 /* BE registers */
399#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/ 399#define OHCI_QUIRK_ZFMICRO 0x20 /* Compaq ZFMicro chipset*/
400#define OHCI_QUIRK_NEC 0x40 /* lost interrupts */
400 // there are also chip quirks/bugs in init logic 401 // there are also chip quirks/bugs in init logic
401 402
403 struct work_struct nec_work; /* Worker for NEC quirk */
402}; 404};
403 405
404/* convert between an hcd pointer and the corresponding ohci_hcd */ 406/* convert between an hcd pointer and the corresponding ohci_hcd */