diff options
Diffstat (limited to 'drivers/usb/host/ehci-hcd.c')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 99 |
1 files changed, 57 insertions, 42 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index d9d53f289ca..4725d15d096 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -24,6 +24,7 @@ #include <linux/ioport.h> #include <linux/sched.h> #include <linux/slab.h> +#include <linux/vmalloc.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/timer.h> @@ -59,7 +60,6 @@ * providing early devices for those host controllers to talk to! */ -#define DRIVER_VERSION "10 Dec 2004" #define DRIVER_AUTHOR "David Brownell" #define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver" @@ -145,16 +145,6 @@ static int handshake (struct ehci_hcd *ehci, void __iomem *ptr, return -ETIMEDOUT; } -static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr, - u32 mask, u32 done, int usec) -{ - int error = handshake(ehci, ptr, mask, done, usec); - if (error) - ehci_to_hcd(ehci)->state = HC_STATE_HALT; - - return error; -} - /* force HC to halt state from unknown (EHCI spec section 2.3) */ static int ehci_halt (struct ehci_hcd *ehci) { @@ -173,6 +163,22 @@ static int ehci_halt (struct ehci_hcd *ehci) STS_HALT, STS_HALT, 16 * 125); } +static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr, + u32 mask, u32 done, int usec) +{ + int error; + + error = handshake(ehci, ptr, mask, done, usec); + if (error) { + ehci_halt(ehci); + ehci_to_hcd(ehci)->state = HC_STATE_HALT; + ehci_err(ehci, "force halt; handhake %p %08x %08x -> %d\n", + ptr, mask, done, error); + } + + return error; +} + /* put TDI/ARC silicon into EHCI mode */ static void tdi_reset (struct ehci_hcd *ehci) { @@ -614,9 +620,9 @@ static int ehci_run (struct usb_hcd *hcd) temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci_info (ehci, - "USB %x.%x started, EHCI %x.%02x, driver %s%s\n", + "USB %x.%x started, EHCI %x.%02x%s\n", ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), - temp >> 8, temp & 0xff, DRIVER_VERSION, + temp >> 8, temp & 0xff, ignore_oc ? ", overcurrent ignored" : ""); ehci_writel(ehci, INTR_MASK, @@ -637,7 +643,7 @@ static int ehci_run (struct usb_hcd *hcd) static irqreturn_t ehci_irq (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); - u32 status, pcd_status = 0, cmd; + u32 status, masked_status, pcd_status = 0, cmd; int bh; spin_lock (&ehci->lock); @@ -650,14 +656,14 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) goto dead; } - status &= INTR_MASK; - if (!status) { /* irq sharing? */ + masked_status = status & INTR_MASK; + if (!masked_status) { /* irq sharing? */ spin_unlock(&ehci->lock); return IRQ_NONE; } /* clear (just) interrupts */ - ehci_writel(ehci, status, &ehci->regs->status); + ehci_writel(ehci, masked_status, &ehci->regs->status); cmd = ehci_readl(ehci, &ehci->regs->command); bh = 0; @@ -700,7 +706,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) pcd_status = status; /* resume root hub? */ - if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN)) + if (!(cmd & CMD_RUN)) usb_hcd_resume_root_hub(hcd); while (i--) { @@ -709,8 +715,11 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) if (pstatus & PORT_OWNER) continue; - if (!(pstatus & PORT_RESUME) - || ehci->reset_done [i] != 0) + if (!(test_bit(i, &ehci->suspended_ports) && + ((pstatus & PORT_RESUME) || + !(pstatus & PORT_SUSPEND)) && + (pstatus & PORT_PE) && + ehci->reset_done[i] == 0)) continue; /* start 20 msec resume signaling from this port, @@ -725,19 +734,17 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* PCI errors [4.15.2.4] */ if (unlikely ((status & STS_FATAL) != 0)) { - dbg_cmd (ehci, "fatal", ehci_readl(ehci, - &ehci->regs->command)); - dbg_status (ehci, "fatal", status); - if (status & STS_HALT) { - ehci_err (ehci, "fatal error\n"); + ehci_err(ehci, "fatal error\n"); + dbg_cmd(ehci, "fatal", cmd); + dbg_status(ehci, "fatal", status); + ehci_halt(ehci); dead: - ehci_reset (ehci); - ehci_writel(ehci, 0, &ehci->regs->configured_flag); - /* generic layer kills/unlinks all urbs, then - * uses ehci_stop to clean up the rest - */ - bh = 1; - } + ehci_reset(ehci); + ehci_writel(ehci, 0, &ehci->regs->configured_flag); + /* generic layer kills/unlinks all urbs, then + * uses ehci_stop to clean up the rest + */ + bh = 1; } if (bh) @@ -988,9 +995,7 @@ static int ehci_get_frame (struct usb_hcd *hcd) /*-------------------------------------------------------------------------*/ -#define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC - -MODULE_DESCRIPTION (DRIVER_INFO); +MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR (DRIVER_AUTHOR); MODULE_LICENSE ("GPL"); @@ -1014,11 +1019,6 @@ MODULE_LICENSE ("GPL"); #define PS3_SYSTEM_BUS_DRIVER ps3_ehci_driver #endif -#if defined(CONFIG_440EPX) && !defined(CONFIG_PPC_MERGE) -#include "ehci-ppc-soc.c" -#define PLATFORM_DRIVER ehci_ppc_soc_driver -#endif - #ifdef CONFIG_USB_EHCI_HCD_PPC_OF #include "ehci-ppc-of.c" #define OF_PLATFORM_DRIVER ehci_hcd_ppc_of_driver @@ -1043,6 +1043,16 @@ static int __init ehci_hcd_init(void) { int retval = 0; + if (usb_disabled()) + return -ENODEV; + + printk(KERN_INFO "%s: " DRIVER_DESC "\n", hcd_name); + set_bit(USB_EHCI_LOADED, &usb_hcds_loaded); + if (test_bit(USB_UHCI_LOADED, &usb_hcds_loaded) || + test_bit(USB_OHCI_LOADED, &usb_hcds_loaded)) + printk(KERN_WARNING "Warning! ehci_hcd should always be loaded" + " before uhci_hcd and ohci_hcd, not after\n"); + pr_debug("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n", hcd_name, sizeof(struct ehci_qh), sizeof(struct ehci_qtd), @@ -1050,8 +1060,10 @@ static int __init ehci_hcd_init(void) #ifdef DEBUG ehci_debug_root = debugfs_create_dir("ehci", NULL); - if (!ehci_debug_root) - return -ENOENT; + if (!ehci_debug_root) { + retval = -ENOENT; + goto err_debug; + } #endif #ifdef PLATFORM_DRIVER @@ -1098,7 +1110,9 @@ clean0: #ifdef DEBUG debugfs_remove(ehci_debug_root); ehci_debug_root = NULL; +err_debug: #endif + clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); return retval; } module_init(ehci_hcd_init); @@ -1120,6 +1134,7 @@ static void __exit ehci_hcd_cleanup(void) #ifdef DEBUG debugfs_remove(ehci_debug_root); #endif + clear_bit(USB_EHCI_LOADED, &usb_hcds_loaded); } module_exit(ehci_hcd_cleanup); |