diff options
Diffstat (limited to 'drivers/usb/host/ohci-hcd.c')
-rw-r--r-- | drivers/usb/host/ohci-hcd.c | 92 |
1 files changed, 47 insertions, 45 deletions
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index a66637e725f3..2038125b7f8c 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c | |||
@@ -35,15 +35,13 @@ | |||
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> |
41 | #include <asm/system.h> | 42 | #include <asm/system.h> |
42 | #include <asm/unaligned.h> | 43 | #include <asm/unaligned.h> |
43 | #include <asm/byteorder.h> | 44 | #include <asm/byteorder.h> |
44 | #ifdef CONFIG_PPC_PS3 | ||
45 | #include <asm/firmware.h> | ||
46 | #endif | ||
47 | 45 | ||
48 | #include "../core/hcd.h" | 46 | #include "../core/hcd.h" |
49 | 47 | ||
@@ -82,6 +80,8 @@ static const char hcd_name [] = "ohci_hcd"; | |||
82 | static void ohci_dump (struct ohci_hcd *ohci, int verbose); | 80 | static void ohci_dump (struct ohci_hcd *ohci, int verbose); |
83 | static int ohci_init (struct ohci_hcd *ohci); | 81 | static int ohci_init (struct ohci_hcd *ohci); |
84 | static void ohci_stop (struct usb_hcd *hcd); | 82 | static void ohci_stop (struct usb_hcd *hcd); |
83 | static int ohci_restart (struct ohci_hcd *ohci); | ||
84 | static void ohci_quirk_nec_worker (struct work_struct *work); | ||
85 | 85 | ||
86 | #include "ohci-hub.c" | 86 | #include "ohci-hub.c" |
87 | #include "ohci-dbg.c" | 87 | #include "ohci-dbg.c" |
@@ -510,15 +510,7 @@ static int ohci_run (struct ohci_hcd *ohci) | |||
510 | // flush the writes | 510 | // flush the writes |
511 | (void) ohci_readl (ohci, &ohci->regs->control); | 511 | (void) ohci_readl (ohci, &ohci->regs->control); |
512 | msleep(temp); | 512 | msleep(temp); |
513 | temp = roothub_a (ohci); | 513 | |
514 | if (!(temp & RH_A_NPS)) { | ||
515 | /* power down each port */ | ||
516 | for (temp = 0; temp < ohci->num_ports; temp++) | ||
517 | ohci_writel (ohci, RH_PS_LSDA, | ||
518 | &ohci->regs->roothub.portstatus [temp]); | ||
519 | } | ||
520 | // flush those writes | ||
521 | (void) ohci_readl (ohci, &ohci->regs->control); | ||
522 | memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); | 514 | memset (ohci->hcca, 0, sizeof (struct ohci_hcca)); |
523 | 515 | ||
524 | /* 2msec timelimit here means no irqs/preempt */ | 516 | /* 2msec timelimit here means no irqs/preempt */ |
@@ -659,9 +651,20 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) | |||
659 | } | 651 | } |
660 | 652 | ||
661 | if (ints & OHCI_INTR_UE) { | 653 | if (ints & OHCI_INTR_UE) { |
662 | disable (ohci); | ||
663 | ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n"); | ||
664 | // e.g. due to PCI Master/Target Abort | 654 | // e.g. due to PCI Master/Target Abort |
655 | if (ohci->flags & OHCI_QUIRK_NEC) { | ||
656 | /* Workaround for a silicon bug in some NEC chips used | ||
657 | * in Apple's PowerBooks. Adapted from Darwin code. | ||
658 | */ | ||
659 | ohci_err (ohci, "OHCI Unrecoverable Error, scheduling NEC chip restart\n"); | ||
660 | |||
661 | ohci_writel (ohci, OHCI_INTR_UE, ®s->intrdisable); | ||
662 | |||
663 | schedule_work (&ohci->nec_work); | ||
664 | } else { | ||
665 | disable (ohci); | ||
666 | ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n"); | ||
667 | } | ||
665 | 668 | ||
666 | ohci_dump (ohci, 1); | 669 | ohci_dump (ohci, 1); |
667 | ohci_usb_reset (ohci); | 670 | ohci_usb_reset (ohci); |
@@ -763,23 +766,16 @@ static void ohci_stop (struct usb_hcd *hcd) | |||
763 | /*-------------------------------------------------------------------------*/ | 766 | /*-------------------------------------------------------------------------*/ |
764 | 767 | ||
765 | /* must not be called from interrupt context */ | 768 | /* must not be called from interrupt context */ |
766 | |||
767 | #ifdef CONFIG_PM | ||
768 | |||
769 | static int ohci_restart (struct ohci_hcd *ohci) | 769 | static int ohci_restart (struct ohci_hcd *ohci) |
770 | { | 770 | { |
771 | int temp; | 771 | int temp; |
772 | int i; | 772 | int i; |
773 | struct urb_priv *priv; | 773 | struct urb_priv *priv; |
774 | 774 | ||
775 | /* mark any devices gone, so they do nothing till khubd disconnects. | ||
776 | * recycle any "live" eds/tds (and urbs) right away. | ||
777 | * later, khubd disconnect processing will recycle the other state, | ||
778 | * (either as disconnect/reconnect, or maybe someday as a reset). | ||
779 | */ | ||
780 | spin_lock_irq(&ohci->lock); | 775 | spin_lock_irq(&ohci->lock); |
781 | disable (ohci); | 776 | disable (ohci); |
782 | usb_root_hub_lost_power(ohci_to_hcd(ohci)->self.root_hub); | 777 | |
778 | /* Recycle any "live" eds/tds (and urbs). */ | ||
783 | if (!list_empty (&ohci->pending)) | 779 | if (!list_empty (&ohci->pending)) |
784 | ohci_dbg(ohci, "abort schedule...\n"); | 780 | ohci_dbg(ohci, "abort schedule...\n"); |
785 | list_for_each_entry (priv, &ohci->pending, pending) { | 781 | list_for_each_entry (priv, &ohci->pending, pending) { |
@@ -826,20 +822,31 @@ static int ohci_restart (struct ohci_hcd *ohci) | |||
826 | if ((temp = ohci_run (ohci)) < 0) { | 822 | if ((temp = ohci_run (ohci)) < 0) { |
827 | ohci_err (ohci, "can't restart, %d\n", temp); | 823 | ohci_err (ohci, "can't restart, %d\n", temp); |
828 | return temp; | 824 | return temp; |
829 | } else { | ||
830 | /* here we "know" root ports should always stay powered, | ||
831 | * and that if we try to turn them back on the root hub | ||
832 | * will respond to CSC processing. | ||
833 | */ | ||
834 | i = ohci->num_ports; | ||
835 | while (i--) | ||
836 | ohci_writel (ohci, RH_PS_PSS, | ||
837 | &ohci->regs->roothub.portstatus [i]); | ||
838 | ohci_dbg (ohci, "restart complete\n"); | ||
839 | } | 825 | } |
826 | ohci_dbg(ohci, "restart complete\n"); | ||
840 | return 0; | 827 | return 0; |
841 | } | 828 | } |
842 | #endif | 829 | |
830 | /*-------------------------------------------------------------------------*/ | ||
831 | |||
832 | /* NEC workaround */ | ||
833 | static void ohci_quirk_nec_worker(struct work_struct *work) | ||
834 | { | ||
835 | struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work); | ||
836 | int status; | ||
837 | |||
838 | status = ohci_init(ohci); | ||
839 | if (status != 0) { | ||
840 | ohci_err(ohci, "Restarting NEC controller failed " | ||
841 | "in ohci_init, %d\n", status); | ||
842 | return; | ||
843 | } | ||
844 | |||
845 | status = ohci_restart(ohci); | ||
846 | if (status != 0) | ||
847 | ohci_err(ohci, "Restarting NEC controller failed " | ||
848 | "in ohci_restart, %d\n", status); | ||
849 | } | ||
843 | 850 | ||
844 | /*-------------------------------------------------------------------------*/ | 851 | /*-------------------------------------------------------------------------*/ |
845 | 852 | ||
@@ -917,7 +924,7 @@ MODULE_LICENSE ("GPL"); | |||
917 | 924 | ||
918 | #ifdef CONFIG_PPC_PS3 | 925 | #ifdef CONFIG_PPC_PS3 |
919 | #include "ohci-ps3.c" | 926 | #include "ohci-ps3.c" |
920 | #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_sb_driver | 927 | #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver |
921 | #endif | 928 | #endif |
922 | 929 | ||
923 | #if !defined(PCI_DRIVER) && \ | 930 | #if !defined(PCI_DRIVER) && \ |
@@ -940,12 +947,9 @@ static int __init ohci_hcd_mod_init(void) | |||
940 | sizeof (struct ed), sizeof (struct td)); | 947 | sizeof (struct ed), sizeof (struct td)); |
941 | 948 | ||
942 | #ifdef PS3_SYSTEM_BUS_DRIVER | 949 | #ifdef PS3_SYSTEM_BUS_DRIVER |
943 | if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { | 950 | retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER); |
944 | retval = ps3_system_bus_driver_register( | 951 | if (retval < 0) |
945 | &PS3_SYSTEM_BUS_DRIVER); | 952 | goto error_ps3; |
946 | if (retval < 0) | ||
947 | goto error_ps3; | ||
948 | } | ||
949 | #endif | 953 | #endif |
950 | 954 | ||
951 | #ifdef PLATFORM_DRIVER | 955 | #ifdef PLATFORM_DRIVER |
@@ -991,8 +995,7 @@ static int __init ohci_hcd_mod_init(void) | |||
991 | error_platform: | 995 | error_platform: |
992 | #endif | 996 | #endif |
993 | #ifdef PS3_SYSTEM_BUS_DRIVER | 997 | #ifdef PS3_SYSTEM_BUS_DRIVER |
994 | if (firmware_has_feature(FW_FEATURE_PS3_LV1)) | 998 | ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); |
995 | ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); | ||
996 | error_ps3: | 999 | error_ps3: |
997 | #endif | 1000 | #endif |
998 | return retval; | 1001 | return retval; |
@@ -1014,8 +1017,7 @@ static void __exit ohci_hcd_mod_exit(void) | |||
1014 | platform_driver_unregister(&PLATFORM_DRIVER); | 1017 | platform_driver_unregister(&PLATFORM_DRIVER); |
1015 | #endif | 1018 | #endif |
1016 | #ifdef PS3_SYSTEM_BUS_DRIVER | 1019 | #ifdef PS3_SYSTEM_BUS_DRIVER |
1017 | if (firmware_has_feature(FW_FEATURE_PS3_LV1)) | 1020 | ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); |
1018 | ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER); | ||
1019 | #endif | 1021 | #endif |
1020 | } | 1022 | } |
1021 | module_exit(ohci_hcd_mod_exit); | 1023 | module_exit(ohci_hcd_mod_exit); |