X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fusb%2Fhost%2Fehci-hcd.c;h=e25adf501967c50c357081c8c6c3fffe18bb801f;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=08fb7643be42ffc2fc07f6e3da37a0d635431043;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 08fb7643b..e25adf501 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -155,7 +155,7 @@ MODULE_PARM_DESC (log2_irq_thresh, "log2 IRQ latency, 1-64 microframes"); * before driver shutdown. But it also seems to be caused by bugs in cardbus * bridge shutdown: shutting down the bridge before the devices using it. */ -static int handshake (u32 *ptr, u32 mask, u32 done, int usec) +static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; @@ -289,22 +289,26 @@ static void ehci_watchdog (unsigned long param) static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap) { if (cap & (1 << 16)) { - int msec = 500; + int msec = 5000; + struct pci_dev *pdev = to_pci_dev(ehci->hcd.self.controller); /* request handoff to OS */ - cap &= 1 << 24; - pci_write_config_dword (to_pci_dev(ehci->hcd.self.controller), where, cap); + cap |= 1 << 24; + pci_write_config_dword(pdev, where, cap); /* and wait a while for it to happen */ do { msleep(10); msec -= 10; - pci_read_config_dword (to_pci_dev(ehci->hcd.self.controller), where, &cap); + pci_read_config_dword(pdev, where, &cap); } while ((cap & (1 << 16)) && msec); if (cap & (1 << 16)) { ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n", where, cap); - return 1; + // some BIOS versions seem buggy... + // return 1; + ehci_warn (ehci, "continuing after BIOS bug...\n"); + return 0; } ehci_dbg (ehci, "BIOS handoff succeeded\n"); } @@ -336,8 +340,8 @@ static int ehci_hc_reset (struct usb_hcd *hcd) spin_lock_init (&ehci->lock); - ehci->caps = (struct ehci_caps *) hcd->regs; - ehci->regs = (struct ehci_regs *) (hcd->regs + + ehci->caps = hcd->regs; + ehci->regs = (hcd->regs + HC_LENGTH (readl (&ehci->caps->hc_capbase))); dbg_hcs_params (ehci, "reset"); dbg_hcc_params (ehci, "reset"); @@ -414,7 +418,7 @@ static int ehci_start (struct usb_hcd *hcd) else // N microframes cached ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params); - ehci->reclaim = 0; + ehci->reclaim = NULL; ehci->next_uframe = -1; /* controller state: unknown --> reset */ @@ -424,7 +428,6 @@ static int ehci_start (struct usb_hcd *hcd) ehci_mem_cleanup (ehci); return retval; } - writel (INTR_MASK, &ehci->regs->intr_enable); writel (ehci->periodic_dma, &ehci->regs->frame_list); #ifdef CONFIG_PCI @@ -462,7 +465,7 @@ static int ehci_start (struct usb_hcd *hcd) * its dummy is used in hw_alt_next of many tds, to prevent the qh * from automatically advancing to the next td after short reads. */ - ehci->async->qh_next.qh = 0; + ehci->async->qh_next.qh = NULL; ehci->async->hw_next = QH_NEXT (ehci->async->qh_dma); ehci->async->hw_info1 = cpu_to_le32 (QH_HEAD); ehci->async->hw_token = cpu_to_le32 (QTD_STS_HALT); @@ -520,7 +523,7 @@ static int ehci_start (struct usb_hcd *hcd) /* wire up the root hub */ bus = hcd_to_bus (hcd); - bus->root_hub = udev = usb_alloc_dev (NULL, bus, 0); + udev = usb_alloc_dev (NULL, bus, 0); if (!udev) { done2: ehci_mem_cleanup (ehci); @@ -530,7 +533,8 @@ done2: /* * Start, enabling full USB 2.0 functionality ... usb 1.1 devices * are explicitly handed to companion controller(s), so no TT is - * involved with the root hub. + * involved with the root hub. (Except where one is integrated, + * and there's no companion controller unless maybe for USB OTG.) */ ehci->reboot_notifier.notifier_call = ehci_reboot; register_reboot_notifier (&ehci->reboot_notifier); @@ -553,16 +557,17 @@ done2: * and device drivers may start it running. */ udev->speed = USB_SPEED_HIGH; - if (hcd_register_root (hcd) != 0) { + if (hcd_register_root (udev, hcd) != 0) { if (hcd->state == USB_STATE_RUNNING) ehci_ready (ehci); ehci_reset (ehci); - bus->root_hub = 0; usb_put_dev (udev); retval = -ENODEV; goto done2; } + writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ + create_debug_files (ehci); return 0; @@ -573,6 +578,7 @@ done2: static void ehci_stop (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); + u8 rh_ports, port; ehci_dbg (ehci, "stop\n"); @@ -584,7 +590,16 @@ static void ehci_stop (struct usb_hcd *hcd) return; } del_timer_sync (&ehci->watchdog); + + /* Turn off port power on all root hub ports. */ + rh_ports = HCS_N_PORTS (ehci->hcs_params); + for (port = 1; port <= rh_ports; port++) { + ehci_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, + port, NULL, 0); + } + ehci_reset (ehci); + writel (0, &ehci->regs->intr_enable); /* let companion controllers work when we aren't */ writel (0, &ehci->regs->configured_flag); @@ -635,7 +650,7 @@ static int ehci_suspend (struct usb_hcd *hcd, u32 state) msleep (100); #ifdef CONFIG_USB_SUSPEND - (void) usb_suspend_device (hcd->self.root_hub); + (void) usb_suspend_device (hcd->self.root_hub, state); #else /* FIXME lock root hub */ (void) ehci_hub_suspend (hcd); @@ -680,9 +695,18 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs) timer_action_done (ehci, TIMER_IO_WATCHDOG); if (ehci->reclaim_ready) end_unlink_async (ehci, regs); + + /* another CPU may drop ehci->lock during a schedule scan while + * it reports urb completions. this flag guards against bogus + * attempts at re-entrant schedule scanning. + */ + if (ehci->scanning) + return; + ehci->scanning = 1; scan_async (ehci, regs); if (ehci->next_uframe != -1) scan_periodic (ehci, regs); + ehci->scanning = 0; /* the IO watchdog guards against hardware or driver bugs that * misplace IRQs, and should let us run completely without IRQs. @@ -704,12 +728,6 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) status = readl (&ehci->regs->status); - /* shared irq */ - if (status == 0) { - spin_unlock (&ehci->lock); - return IRQ_NONE; - } - /* e.g. cardbus physical eject */ if (status == ~(u32) 0) { ehci_dbg (ehci, "device removed\n"); @@ -717,8 +735,10 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs) } status &= INTR_MASK; - if (!status) /* irq sharing? */ - goto done; + if (!status) { /* irq sharing? */ + spin_unlock(&ehci->lock); + return IRQ_NONE; + } /* clear (just) interrupts */ writel (status, &ehci->regs->status); @@ -789,7 +809,6 @@ dead: if (bh) ehci_work (ehci, regs); -done: spin_unlock (&ehci->lock); return IRQ_HANDLED; } @@ -978,7 +997,7 @@ idle_timeout: list_empty (&qh->qtd_list) ? "" : "(has tds)"); break; } - dev->ep [epnum] = 0; + dev->ep[epnum] = NULL; done: spin_unlock_irqrestore (&ehci->lock, flags); return; @@ -1029,6 +1048,8 @@ static const struct hc_driver ehci_driver = { */ .hub_status_data = ehci_hub_status_data, .hub_control = ehci_hub_control, + .hub_suspend = ehci_hub_suspend, + .hub_resume = ehci_hub_resume, }; /*-------------------------------------------------------------------------*/