* 2001-June Works with usb-storage and NEC EHCI on 2.4
*/
-#define DRIVER_VERSION "26 Oct 2004"
+#define DRIVER_VERSION "2004-May-10"
#define DRIVER_AUTHOR "David Brownell"
#define DRIVER_DESC "USB 2.0 'Enhanced' Host Controller (EHCI) Driver"
* 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 (void __iomem *ptr, u32 mask, u32 done, int usec)
+static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec)
{
u32 result;
return -ETIMEDOUT;
}
+/*
+ * hc states include: unknown, halted, ready, running
+ * transitional states are messy just now
+ * trying to avoid "running" unless urbs are active
+ * a "ready" hc can be finishing prefetched work
+ */
+
/* force HC to halt state from unknown (EHCI spec section 2.3) */
static int ehci_halt (struct ehci_hcd *ehci)
{
}
/* idle the controller (from running) */
-static void ehci_quiesce (struct ehci_hcd *ehci)
+static void ehci_ready (struct ehci_hcd *ehci)
{
u32 temp;
#endif
/* wait for any schedule enables/disables to take effect */
- temp = readl (&ehci->regs->command) << 10;
- temp &= STS_ASS | STS_PSS;
+ temp = 0;
+ if (ehci->async->qh_next.qh)
+ temp = STS_ASS;
+ if (ehci->next_uframe != -1)
+ temp |= STS_PSS;
if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
temp, 16 * 125) != 0) {
ehci->hcd.state = USB_STATE_HALT;
spin_lock_init (&ehci->lock);
ehci->caps = hcd->regs;
- ehci->regs = hcd->regs + HC_LENGTH (readl (&ehci->caps->hc_capbase));
+ ehci->regs = (hcd->regs +
+ HC_LENGTH (readl (&ehci->caps->hc_capbase)));
dbg_hcs_params (ehci, "reset");
dbg_hcc_params (ehci, "reset");
#ifdef CONFIG_PCI
writel(0, &ehci->regs->intr_enable);
/* EHCI 0.96 and later may have "extended capabilities" */
- if (hcd->self.controller->bus == &pci_bus_type) {
- struct pci_dev *pdev = to_pci_dev(ehci->hcd.self.controller);
-
- /* AMD8111 EHCI doesn't work, according to AMD errata */
- if ((pdev->vendor == PCI_VENDOR_ID_AMD)
- && (pdev->device == 0x7463)) {
- ehci_info (ehci, "ignoring AMD8111 (errata)\n");
- return -EIO;
- }
-
+ if (hcd->self.controller->bus == &pci_bus_type)
temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
- } else
+ else
temp = 0;
while (temp && count--) {
u32 cap;
if (bios_handoff (ehci, temp, cap) != 0)
return -EOPNOTSUPP;
break;
+ case 0x0a: /* appendix C */
+ ehci_dbg (ehci, "debug registers, BAR %d offset %d\n",
+ (cap >> 29) & 0x07, (cap >> 16) & 0x0fff);
+ break;
case 0: /* illegal reserved capability */
ehci_warn (ehci, "illegal capability!\n");
cap = 0;
/* cache this readonly data; minimize PCI reads */
ehci->hcs_params = readl (&ehci->caps->hcs_params);
- /* at least the Genesys GL880S needs fixup here */
- temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
- temp &= 0x0f;
- if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) {
- temp |= (ehci->hcs_params & ~0xf);
- ehci->hcs_params = temp;
- }
-
/* force HC to halt state */
return ehci_halt (ehci);
}
int retval;
u32 hcc_params;
u8 sbrn = 0;
- int first;
-
- /* skip some things on restart paths */
- first = (ehci->watchdog.data == 0);
- if (first) {
- init_timer (&ehci->watchdog);
- ehci->watchdog.function = ehci_watchdog;
- ehci->watchdog.data = (unsigned long) ehci;
- }
+
+ init_timer (&ehci->watchdog);
+ ehci->watchdog.function = ehci_watchdog;
+ ehci->watchdog.data = (unsigned long) ehci;
/*
* hw default: 1K periodic list heads, one per frame.
* periodic_size can shrink by USBCMD update if hcc_params allows.
*/
ehci->periodic_size = DEFAULT_I_TDPS;
- if (first && (retval = ehci_mem_init (ehci, GFP_KERNEL)) < 0)
+ if ((retval = ehci_mem_init (ehci, GFP_KERNEL)) < 0)
return retval;
/* controllers may cache some of the periodic schedule ... */
ehci->i_thresh = 2 + HCC_ISOC_THRES (hcc_params);
ehci->reclaim = NULL;
- ehci->reclaim_ready = 0;
ehci->next_uframe = -1;
/* controller state: unknown --> reset */
* 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.
*/
- if (first) {
- 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);
- ehci->async->hw_qtd_next = EHCI_LIST_END;
- ehci->async->qh_state = QH_STATE_LINKED;
- ehci->async->hw_alt_next = QTD_NEXT (ehci->async->dummy->qtd_dma);
- }
+ 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);
+ ehci->async->hw_qtd_next = EHCI_LIST_END;
+ ehci->async->qh_state = QH_STATE_LINKED;
+ ehci->async->hw_alt_next = QTD_NEXT (ehci->async->dummy->qtd_dma);
writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
/*
/* wire up the root hub */
bus = hcd_to_bus (hcd);
- udev = first ? usb_alloc_dev (NULL, bus, 0) : bus->root_hub;
+ udev = usb_alloc_dev (NULL, bus, 0);
if (!udev) {
done2:
ehci_mem_cleanup (ehci);
return -ENOMEM;
}
- udev->speed = USB_SPEED_HIGH;
- udev->state = first ? USB_STATE_ATTACHED : USB_STATE_CONFIGURED;
/*
* Start, enabling full USB 2.0 functionality ... usb 1.1 devices
* involved with the root hub. (Except where one is integrated,
* and there's no companion controller unless maybe for USB OTG.)
*/
- if (first) {
- ehci->reboot_notifier.notifier_call = ehci_reboot;
- register_reboot_notifier (&ehci->reboot_notifier);
- }
+ ehci->reboot_notifier.notifier_call = ehci_reboot;
+ register_reboot_notifier (&ehci->reboot_notifier);
ehci->hcd.state = USB_STATE_RUNNING;
writel (FLAG_CF, &ehci->regs->configured_flag);
temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
ehci_info (ehci,
- "USB %x.%x %s, EHCI %x.%02x, driver %s\n",
+ "USB %x.%x enabled, EHCI %x.%02x, driver %s\n",
((sbrn & 0xf0)>>4), (sbrn & 0x0f),
- first ? "initialized" : "restarted",
temp >> 8, temp & 0xff, DRIVER_VERSION);
/*
* From here on, khubd concurrently accesses the root
* hub; drivers will be talking to enumerated devices.
- * (On restart paths, khubd already knows about the root
- * hub and could find work as soon as we wrote FLAG_CF.)
*
* Before this point the HC was idle/ready. After, khubd
* and device drivers may start it running.
*/
- if (first && hcd_register_root (udev, hcd) != 0) {
+ udev->speed = USB_SPEED_HIGH;
+ if (hcd_register_root (udev, hcd) != 0) {
if (hcd->state == USB_STATE_RUNNING)
- ehci_quiesce (ehci);
+ ehci_ready (ehci);
ehci_reset (ehci);
usb_put_dev (udev);
retval = -ENODEV;
writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
- if (first)
- create_debug_files (ehci);
+ create_debug_files (ehci);
return 0;
}
ehci_dbg (ehci, "stop\n");
- /* Turn off port power on all root hub ports. */
- rh_ports = HCS_N_PORTS (ehci->hcs_params);
- for (port = 1; port <= rh_ports; port++)
- (void) ehci_hub_control(hcd,
- ClearPortFeature, USB_PORT_FEAT_POWER,
- port, NULL, 0);
-
/* no more interrupts ... */
+ if (hcd->state == USB_STATE_RUNNING)
+ ehci_ready (ehci);
+ if (in_interrupt ()) { /* must not happen!! */
+ ehci_err (ehci, "stopped in_interrupt!\n");
+ return;
+ }
del_timer_sync (&ehci->watchdog);
- spin_lock_irq(&ehci->lock);
- if (HCD_IS_RUNNING (ehci->hcd.state))
- ehci_quiesce (ehci);
+ /* 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);
- spin_unlock_irq(&ehci->lock);
/* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag);
/* suspend/resume, section 4.3 */
-/* These routines rely on the bus (pci, platform, etc)
- * to handle powerdown and wakeup, and currently also on
+/* These routines rely on PCI to handle powerdown and wakeup, and
* transceivers that don't need any software attention to set up
* the right sort of wakeup.
*/
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- if (time_before (jiffies, ehci->next_statechange))
+ while (time_before (jiffies, ehci->next_statechange))
msleep (100);
#ifdef CONFIG_USB_SUSPEND
(void) usb_suspend_device (hcd->self.root_hub, state);
#else
- usb_lock_device (hcd->self.root_hub);
+ /* FIXME lock root hub */
(void) ehci_hub_suspend (hcd);
- usb_unlock_device (hcd->self.root_hub);
#endif
// save (PCI) FLADJ in case of Vaux power loss
- // ... we'd only use it to handle clock skew
return 0;
}
static int ehci_resume (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- unsigned port;
- struct usb_device *root = hcd->self.root_hub;
- int retval = -EINVAL;
- int powerup = 0;
+ int retval;
// maybe restore (PCI) FLADJ
- if (time_before (jiffies, ehci->next_statechange))
+ while (time_before (jiffies, ehci->next_statechange))
msleep (100);
- /* If any port is suspended, we know we can/must resume the HC. */
- for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
- u32 status;
- port--;
- status = readl (&ehci->regs->port_status [port]);
- if (status & PORT_SUSPEND) {
- down (&hcd->self.root_hub->serialize);
- retval = ehci_hub_resume (hcd);
- up (&hcd->self.root_hub->serialize);
- break;
- }
- if ((status & PORT_POWER) == 0)
- powerup = 1;
- if (!root->children [port])
- continue;
- dbg_port (ehci, __FUNCTION__, port + 1, status);
- usb_set_device_state (root->children[port],
- USB_STATE_NOTATTACHED);
- }
-
- /* Else reset, to cope with power loss or flush-to-storage
- * style "resume" having activated BIOS during reboot.
- */
- if (port == 0) {
- (void) ehci_halt (ehci);
- (void) ehci_reset (ehci);
- (void) ehci_hc_reset (hcd);
-
- /* emptying the schedule aborts any urbs */
- spin_lock_irq (&ehci->lock);
- if (ehci->reclaim)
- ehci->reclaim_ready = 1;
- ehci_work (ehci, NULL);
- spin_unlock_irq (&ehci->lock);
-
- /* restart; khubd will disconnect devices */
- retval = ehci_start (hcd);
-
- /* here we "know" root ports should always stay powered;
- * but some controllers may lost all power.
- */
- if (powerup) {
- ehci_dbg (ehci, "...powerup ports...\n");
- for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; )
- (void) ehci_hub_control(hcd,
- SetPortFeature, USB_PORT_FEAT_POWER,
- port--, NULL, 0);
- msleep(20);
- }
- }
-
+#ifdef CONFIG_USB_SUSPEND
+ retval = usb_resume_device (hcd->self.root_hub);
+#else
+ /* FIXME lock root hub */
+ retval = ehci_hub_resume (hcd);
+#endif
+ if (retval == 0)
+ hcd->self.controller->power.power_state = 0;
return retval;
}
* misplace IRQs, and should let us run completely without IRQs.
* such lossage has been observed on both VT6202 and VT8235.
*/
- if (HCD_IS_RUNNING (ehci->hcd.state) && (ehci->async->qh_next.ptr != 0
- || ehci->periodic_sched != 0))
+ if ((ehci->async->qh_next.ptr != 0) || (ehci->periodic_sched != 0))
timer_action (ehci, TIMER_IO_WATCHDOG);
}
}
}
-static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
-{
- /* if we need to use IAA and it's busy, defer */
- if (qh->qh_state == QH_STATE_LINKED
- && ehci->reclaim
- && HCD_IS_RUNNING (ehci->hcd.state)) {
- struct ehci_qh *last;
-
- for (last = ehci->reclaim;
- last->reclaim;
- last = last->reclaim)
- continue;
- qh->qh_state = QH_STATE_UNLINK_WAIT;
- last->reclaim = qh;
-
- /* bypass IAA if the hc can't care */
- } else if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim)
- end_unlink_async (ehci, NULL);
-
- /* something else might have unlinked the qh by now */
- if (qh->qh_state == QH_STATE_LINKED)
- start_unlink_async (ehci, qh);
-}
-
/* remove from hardware lists
* completions normally happen asynchronously
*/
qh = (struct ehci_qh *) urb->hcpriv;
if (!qh)
break;
- unlink_async (ehci, qh);
+
+ /* if we need to use IAA and it's busy, defer */
+ if (qh->qh_state == QH_STATE_LINKED
+ && ehci->reclaim
+ && HCD_IS_RUNNING (ehci->hcd.state)
+ ) {
+ struct ehci_qh *last;
+
+ for (last = ehci->reclaim;
+ last->reclaim;
+ last = last->reclaim)
+ continue;
+ qh->qh_state = QH_STATE_UNLINK_WAIT;
+ last->reclaim = qh;
+
+ /* bypass IAA if the hc can't care */
+ } else if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim)
+ end_unlink_async (ehci, NULL);
+
+ /* something else might have unlinked the qh by now */
+ if (qh->qh_state == QH_STATE_LINKED)
+ start_unlink_async (ehci, qh);
break;
case PIPE_INTERRUPT:
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
int epnum;
unsigned long flags;
- struct ehci_qh *qh, *tmp;
+ struct ehci_qh *qh;
/* ASSERT: any requests/urbs are being unlinked */
/* ASSERT: nobody can be submitting urbs for this any more */
if (!HCD_IS_RUNNING (ehci->hcd.state))
qh->qh_state = QH_STATE_IDLE;
switch (qh->qh_state) {
- case QH_STATE_LINKED:
- for (tmp = ehci->async->qh_next.qh;
- tmp && tmp != qh;
- tmp = tmp->qh_next.qh)
- continue;
- /* periodic qh self-unlinks on empty */
- if (!tmp)
- goto nogood;
- unlink_async (ehci, qh);
- /* FALL THROUGH */
case QH_STATE_UNLINK: /* wait for hw to finish? */
idle_timeout:
spin_unlock_irqrestore (&ehci->lock, flags);
}
/* else FALL THROUGH */
default:
-nogood:
/* caller was supposed to have unlinked any requests;
* that's not our job. just leak this memory.
*/
* memory lifecycle (except per-request)
*/
.hcd_alloc = ehci_hcd_alloc,
+ .hcd_free = ehci_hcd_free,
/*
* managing i/o requests and associated device resources
sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
- return pci_register_driver (&ehci_pci_driver);
+ return pci_module_init (&ehci_pci_driver);
}
module_init (init);