* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004-2006 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
*
* Intel documents this fairly well, and as far as I know there
* are no royalties or anything like that, but even so there are
*
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/interrupt.h>
static void wakeup_rh(struct uhci_hcd *uhci);
static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
+/* If a transfer is still active after this much time, turn off FSBR */
+#define IDLE_TIMEOUT msecs_to_jiffies(50)
+#define FSBR_DELAY msecs_to_jiffies(50)
+
+/* When we timeout an idle transfer for FSBR, we'll switch it over to */
+/* depth first traversal. We'll do it in groups of this number of TDs */
+/* to make sure it doesn't hog all of the bandwidth */
+#define DEPTH_INTERVAL 5
+
#include "uhci-debug.c"
#include "uhci-q.c"
#include "uhci-hub.c"
uhci->is_stopped = UHCI_IS_STOPPED;
uhci_to_hcd(uhci)->state = HC_STATE_HALT;
uhci_to_hcd(uhci)->poll_rh = 0;
-
- uhci->dead = 0; /* Full reset resurrects the controller */
}
/*
* Last rites for a defunct/nonfunctional controller
* or one we don't want to use any more.
*/
-static void uhci_hc_died(struct uhci_hcd *uhci)
+static void hc_died(struct uhci_hcd *uhci)
{
- uhci_get_current_frame_number(uhci);
uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr);
finish_reset(uhci);
- uhci->dead = 1;
-
- /* The current frame may already be partway finished */
- ++uhci->frame_number;
+ uhci->hc_inaccessible = 1;
}
/*
- * Initialize a controller that was newly discovered or has lost power
- * or otherwise been reset while it was suspended. In none of these cases
- * can we be sure of its previous state.
+ * Initialize a controller that was newly discovered or has just been
+ * resumed. In either case we can't be sure of its previous state.
*/
static void check_and_reset_hc(struct uhci_hcd *uhci)
{
outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD);
/* Set the current frame number */
- outw(uhci->frame_number & UHCI_MAX_SOF_NUMBER,
- uhci->io_addr + USBFRNUM);
+ outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
/* Mark controller as not halted before we enable interrupts */
uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED;
int int_enable;
auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
- dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev,
- "%s%s\n", __FUNCTION__,
+ dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__,
(auto_stop ? " (auto-stop)" : ""));
/* If we get a suspend request when we're already auto-stopped
spin_unlock_irq(&uhci->lock);
msleep(1);
spin_lock_irq(&uhci->lock);
- if (uhci->dead)
+ if (uhci->hc_inaccessible) /* Died */
return;
}
if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
- dev_warn(&uhci_to_hcd(uhci)->self.root_hub->dev,
- "Controller not stopped yet!\n");
+ dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
uhci_get_current_frame_number(uhci);
+ smp_wmb();
uhci->rh_state = new_state;
uhci->is_stopped = UHCI_IS_STOPPED;
uhci_to_hcd(uhci)->poll_rh = !int_enable;
uhci_scan_schedule(uhci, NULL);
- uhci_fsbr_off(uhci);
}
static void start_rh(struct uhci_hcd *uhci)
{
uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
uhci->is_stopped = 0;
+ smp_wmb();
/* Mark it configured and running with a 64-byte max packet.
* All interrupts are enabled, even though RESUME won't do anything.
__releases(uhci->lock)
__acquires(uhci->lock)
{
- dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev,
- "%s%s\n", __FUNCTION__,
+ dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__,
uhci->rh_state == UHCI_RH_AUTO_STOPPED ?
" (auto-start)" : "");
spin_unlock_irq(&uhci->lock);
msleep(20);
spin_lock_irq(&uhci->lock);
- if (uhci->dead)
+ if (uhci->hc_inaccessible) /* Died */
return;
/* End Global Resume and wait for EOP to be sent */
errbuf, ERRBUF_LEN);
lprintk(errbuf);
}
- uhci_hc_died(uhci);
+ hc_died(uhci);
/* Force a callback in case there are
* pending unlinks */
/*
* Store the current frame number in uhci->frame_number if the controller
- * is runnning. Expand from 11 bits (of which we use only 10) to a
- * full-sized integer.
- *
- * Like many other parts of the driver, this code relies on being polled
- * more than once per second as long as the controller is running.
+ * is runnning
*/
static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
{
- if (!uhci->is_stopped) {
- unsigned delta;
-
- delta = (inw(uhci->io_addr + USBFRNUM) - uhci->frame_number) &
- (UHCI_NUMFRAMES - 1);
- uhci->frame_number += delta;
- }
+ if (!uhci->is_stopped)
+ uhci->frame_number = inw(uhci->io_addr + USBFRNUM);
}
/*
uhci->frame, uhci->frame_dma_handle);
}
-static int uhci_init(struct usb_hcd *hcd)
+static int uhci_reset(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned io_size = (unsigned) hcd->rsrc_len;
{
struct usb_hcd *hcd = (struct usb_hcd *) pci_get_drvdata(pdev);
- uhci_hc_died(hcd_to_uhci(hcd));
+ hc_died(hcd_to_uhci(hcd));
}
/*
hcd->uses_new_polling = 1;
+ uhci->fsbr = 0;
+ uhci->fsbrtimeout = 0;
+
spin_lock_init(&uhci->lock);
- setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout,
- (unsigned long) uhci);
+
+ INIT_LIST_HEAD(&uhci->td_remove_list);
INIT_LIST_HEAD(&uhci->idle_qh_list);
+
init_waitqueue_head(&uhci->waitqh);
if (DEBUG_CONFIGURED) {
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
spin_lock_irq(&uhci->lock);
- if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && !uhci->dead)
- uhci_hc_died(uhci);
+ if (!uhci->hc_inaccessible)
+ hc_died(uhci);
uhci_scan_schedule(uhci, NULL);
spin_unlock_irq(&uhci->lock);
- del_timer_sync(&uhci->fsbr_timer);
release_uhci(uhci);
}
static int uhci_rh_suspend(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- int rc = 0;
spin_lock_irq(&uhci->lock);
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
- rc = -ESHUTDOWN;
- else if (!uhci->dead)
+ if (!uhci->hc_inaccessible) /* Not dead */
suspend_rh(uhci, UHCI_RH_SUSPENDED);
spin_unlock_irq(&uhci->lock);
- return rc;
+ return 0;
}
static int uhci_rh_resume(struct usb_hcd *hcd)
int rc = 0;
spin_lock_irq(&uhci->lock);
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- dev_warn(&hcd->self.root_hub->dev, "HC isn't running!\n");
- rc = -ESHUTDOWN;
- } else if (!uhci->dead)
+ if (uhci->hc_inaccessible) {
+ if (uhci->rh_state == UHCI_RH_SUSPENDED) {
+ dev_warn(uhci_dev(uhci), "HC isn't running!\n");
+ rc = -ENODEV;
+ }
+ /* Otherwise the HC is dead */
+ } else
wakeup_rh(uhci);
spin_unlock_irq(&uhci->lock);
return rc;
dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
spin_lock_irq(&uhci->lock);
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)
- goto done_okay; /* Already suspended or dead */
+ if (uhci->hc_inaccessible) /* Dead or already suspended */
+ goto done;
if (uhci->rh_state > UHCI_RH_SUSPENDED) {
dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
*/
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
mb();
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ uhci->hc_inaccessible = 1;
hcd->poll_rh = 0;
/* FIXME: Enable non-PME# remote wakeup? */
-done_okay:
- clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
done:
spin_unlock_irq(&uhci->lock);
return rc;
dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
/* Since we aren't in D3 any more, it's safe to set this flag
- * even if the controller was dead.
+ * even if the controller was dead. It might not even be dead
+ * any more, if the firmware or quirks code has reset it.
*/
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
mb();
+ if (uhci->rh_state == UHCI_RH_RESET) /* Dead */
+ return 0;
spin_lock_irq(&uhci->lock);
/* FIXME: Disable non-PME# remote wakeup? */
- /* The firmware or a boot kernel may have changed the controller
- * settings during a system wakeup. Check it and reconfigure
- * to avoid problems.
+ uhci->hc_inaccessible = 0;
+
+ /* The BIOS may have changed the controller settings during a
+ * system wakeup. Check it and reconfigure to avoid problems.
*/
check_and_reset_hc(uhci);
-
- /* If the controller was dead before, it's back alive now */
configure_hc(uhci);
if (uhci->rh_state == UHCI_RH_RESET) {
static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- unsigned frame_number;
- unsigned delta;
+ unsigned long flags;
+ int is_stopped;
+ int frame_number;
/* Minimize latency by avoiding the spinlock */
- frame_number = uhci->frame_number;
- barrier();
- delta = (inw(uhci->io_addr + USBFRNUM) - frame_number) &
- (UHCI_NUMFRAMES - 1);
- return frame_number + delta;
+ local_irq_save(flags);
+ is_stopped = uhci->is_stopped;
+ smp_rmb();
+ frame_number = (is_stopped ? uhci->frame_number :
+ inw(uhci->io_addr + USBFRNUM));
+ local_irq_restore(flags);
+ return frame_number;
}
static const char hcd_name[] = "uhci_hcd";
.flags = HCD_USB11,
/* Basic lifecycle operations */
- .reset = uhci_init,
+ .reset = uhci_reset,
.start = uhci_start,
#ifdef CONFIG_PM
.suspend = uhci_suspend,