* This file is licenced under the GPL.
*/
-#ifdef CONFIG_PMAC_PBOOK
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/pci-bridge.h>
-#include <asm/prom.h>
-#ifndef CONFIG_PM
-# define CONFIG_PM
-#endif
-#endif
-
#ifndef CONFIG_PCI
#error "This file is PCI bus glue. CONFIG_PCI must be defined."
#endif
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- ohci->regs = hcd->regs;
- ohci->next_statechange = jiffies;
- return hc_reset (ohci);
+ ohci_hcd_init (ohci);
+ return ohci_init (ohci);
}
static int __devinit
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret;
- ohci->hcca = dma_alloc_coherent (hcd->self.controller,
- sizeof *ohci->hcca, &ohci->hcca_dma, 0);
- if (!ohci->hcca)
- return -ENOMEM;
-
if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) {
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
if (pdev->vendor == PCI_VENDOR_ID_AMD
&& pdev->device == 0x740c) {
ohci->flags = OHCI_QUIRK_AMD756;
- ohci_info (ohci, "AMD756 erratum 4 workaround\n");
+ ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
+ // also somewhat erratum 10 (suspend/resume issues)
}
/* FIXME for some of the early AMD 760 southbridges, OHCI
*/
else if (pdev->vendor == PCI_VENDOR_ID_OPTI
&& pdev->device == 0xc861) {
- ohci_info (ohci,
+ ohci_dbg (ohci,
"WARNING: OPTi workarounds unavailable\n");
}
if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
&& b->vendor == PCI_VENDOR_ID_NS) {
ohci->flags |= OHCI_QUIRK_SUPERIO;
- ohci_info (ohci, "Using NSC SuperIO setup\n");
+ ohci_dbg (ohci, "Using NSC SuperIO setup\n");
}
}
-
- }
- memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
- if ((ret = ohci_mem_init (ohci)) < 0) {
- ohci_stop (hcd);
- return ret;
+ /* Check for Compaq's ZFMicro chipset, which needs short
+ * delays before control or bulk queues get re-activated
+ * in finish_unlinks()
+ */
+ else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
+ && pdev->device == 0xa0f8) {
+ ohci->flags |= OHCI_QUIRK_ZFMICRO;
+ ohci_dbg (ohci,
+ "enabled Compaq ZFMicro chipset quirk\n");
+ }
}
- if (hc_start (ohci) < 0) {
+ /* NOTE: there may have already been a first reset, to
+ * keep bios/smm irqs from making trouble
+ */
+ if ((ret = ohci_run (ohci)) < 0) {
ohci_err (ohci, "can't start\n");
ohci_stop (hcd);
- return -EBUSY;
+ return ret;
}
- create_debug_files (ohci);
-
-#ifdef DEBUG
- ohci_dump (ohci, 1);
-#endif
return 0;
}
#ifdef CONFIG_PM
-static int ohci_pci_suspend (struct usb_hcd *hcd, u32 state)
+static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
{
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
-
- /* suspend root hub, hoping it keeps power during suspend */
- while (time_before (jiffies, ohci->next_statechange))
- msleep (100);
-
-#ifdef CONFIG_USB_SUSPEND
- (void) usb_suspend_device (hcd->self.root_hub, state);
-#else
- down (&hcd->self.root_hub->serialize);
- (void) ohci_hub_suspend (hcd);
- up (&hcd->self.root_hub->serialize);
-#endif
-
- /* let things settle down a bit */
- msleep (100);
-
-#ifdef CONFIG_PMAC_PBOOK
- if (_machine == _MACH_Pmac)
- disable_irq ((to_pci_dev(hcd->self.controller))->irq);
-
- {
- struct device_node *of_node;
-
- /* Disable USB PAD & cell clock */
- of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller));
- if (of_node)
- pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ unsigned long flags;
+ int rc = 0;
+
+ /* Root hub was already suspended. Disable irq emission and
+ * mark HW unaccessible, bail out if RH has been resumed. Use
+ * the spinlock to properly synchronize with possible pending
+ * RH suspend or resume activity.
+ *
+ * This is still racy as hcd->state is manipulated outside of
+ * any locks =P But that will be a different fix.
+ */
+ spin_lock_irqsave (&ohci->lock, flags);
+ if (hcd->state != HC_STATE_SUSPENDED) {
+ rc = -EINVAL;
+ goto bail;
}
-#endif
- return 0;
+ ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+ (void)ohci_readl(ohci, &ohci->regs->intrdisable);
+ clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ bail:
+ spin_unlock_irqrestore (&ohci->lock, flags);
+
+ return rc;
}
static int ohci_pci_resume (struct usb_hcd *hcd)
{
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- int retval = 0;
-
-#ifdef CONFIG_PMAC_PBOOK
- {
- struct device_node *of_node;
-
- /* Re-enable USB PAD & cell clock */
- of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller));
- if (of_node)
- pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
- }
-#endif
-
- /* resume root hub */
- while (time_before (jiffies, ohci->next_statechange))
- msleep (100);
-#ifdef CONFIG_USB_SUSPEND
- /* get extra cleanup even if remote wakeup isn't in use */
- retval = usb_resume_device (hcd->self.root_hub);
-#else
- down (&hcd->self.root_hub->serialize);
- retval = ohci_hub_resume (hcd);
- up (&hcd->self.root_hub->serialize);
-#endif
-
- if (retval == 0) {
- hcd->self.controller->power.power_state = 0;
-#ifdef CONFIG_PMAC_PBOOK
- if (_machine == _MACH_Pmac)
- enable_irq (to_pci_dev(hcd->self.controller)->irq);
-#endif
- }
- return retval;
+ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ usb_hcd_resume_root_hub(hcd);
+ return 0;
}
#endif /* CONFIG_PM */
static const struct hc_driver ohci_pci_hc_driver = {
.description = hcd_name,
+ .product_desc = "OHCI Host Controller",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
/*
* generic hardware linkage
#endif
.stop = ohci_stop,
- /*
- * memory lifecycle (except per-request)
- */
- .hcd_alloc = ohci_hcd_alloc,
- .hcd_free = ohci_hcd_free,
-
/*
* managing i/o requests and associated device resources
*/
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
-#ifdef CONFIG_USB_SUSPEND
- .hub_suspend = ohci_hub_suspend,
- .hub_resume = ohci_hub_resume,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
#endif
+ .start_port_reset = ohci_start_port_reset,
};
/*-------------------------------------------------------------------------*/
if (usb_disabled())
return -ENODEV;
- printk (KERN_DEBUG "%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+ pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
sizeof (struct ed), sizeof (struct td));
- return pci_module_init (&ohci_pci_driver);
+ return pci_register_driver (&ohci_pci_driver);
}
module_init (ohci_hcd_pci_init);