use the platform_device which was added to xhci.c to decouple PCI from xhci core driver. Signed-off-by: Felipe Balbi <balbi@xxxxxx> --- drivers/usb/host/Makefile | 7 +- drivers/usb/host/xhci-pci.c | 351 ++++++++++--------------------------------- drivers/usb/host/xhci.c | 27 ++-- drivers/usb/host/xhci.h | 11 +- 4 files changed, 106 insertions(+), 290 deletions(-) diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 624a362..92357af 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -11,7 +11,7 @@ fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o -xhci-hcd-y := xhci.o xhci-mem.o xhci-pci.o +xhci-hcd-y := xhci.o xhci-mem.o xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o obj-$(CONFIG_USB_WHCI_HCD) += whci/ @@ -26,6 +26,11 @@ obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o obj-$(CONFIG_USB_FHCI_HCD) += fhci.o obj-$(CONFIG_USB_XHCI_HCD) += xhci-hcd.o + +ifneq ($(CONFIG_PCI),) + obj-$(CONFIG_USB_XHCI_HCD) += xhci-pci.o +endif + obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index e11900e..c0df79a 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -22,6 +22,7 @@ #include <linux/pci.h> #include <linux/slab.h> +#include <linux/platform_device.h> #include "xhci.h" @@ -32,306 +33,114 @@ #define PCI_VENDOR_ID_ETRON 0x1b6f #define PCI_DEVICE_ID_ASROCK_P67 0x7023 -struct xhci_pci_data { - unsigned int limit_active_eps; - unsigned int quirks; +struct xhci_pci { + struct device *dev; + struct platform_device *xhci; }; -static const char hcd_name[] = "xhci_hcd"; - -/* called after powerup, by probe or system-pm "wakeup" */ -static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) +static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { - /* - * TODO: Implement finding debug ports later. - * TODO: see if there are any quirks that need to be added to handle - * new extended capabilities. - */ + struct xhci_platform_data *data; + struct xhci_pci *glue; + struct platform_device *xhci; + struct resource res[2]; - /* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */ - if (!pci_set_mwi(pdev)) - xhci_dbg(xhci, "MWI active\n"); + int ret = -ENOMEM; - xhci_dbg(xhci, "Finished xhci_pci_reinit\n"); - return 0; -} + data = (struct xhci_platform_data *) id->driver_data; -/* called during probe() after chip reset completes */ -static int xhci_pci_setup(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci; - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - int retval; - u32 temp; - - hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; - - if (usb_hcd_is_primary_hcd(hcd)) { - xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL); - if (!xhci) - return -ENOMEM; - *((struct xhci_hcd **) hcd->hcd_priv) = xhci; - xhci->main_hcd = hcd; - /* Mark the first roothub as being USB 2.0. - * The xHCI driver will register the USB 3.0 roothub. - */ - hcd->speed = HCD_USB2; - hcd->self.root_hub->speed = USB_SPEED_HIGH; - /* - * USB 2.0 roothub under xHCI has an integrated TT, - * (rate matching hub) as opposed to having an OHCI/UHCI - * companion controller. - */ - hcd->has_tt = 1; - } else { - /* xHCI private pointer was set in xhci_pci_probe for the second - * registered roothub. - */ - xhci = hcd_to_xhci(hcd); - temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); - if (HCC_64BIT_ADDR(temp)) { - xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); - dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64)); - } else { - dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32)); - } - return 0; + glue = kzalloc(sizeof(*glue), GFP_KERNEL); + if (!glue) { + dev_err(&dev->dev, "failed to allocate glue\n"); + goto err0; } - xhci->cap_regs = hcd->regs; - xhci->op_regs = hcd->regs + - HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); - xhci->run_regs = hcd->regs + - (xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK); - /* Cache read-only capability registers */ - xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); - xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); - xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); - xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); - xhci->hci_version = HC_VERSION(xhci->hcc_params); - xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params); - xhci_print_registers(xhci); - - /* Make sure the HC is halted. */ - retval = xhci_halt(xhci); - if (retval) - goto error; - - xhci_dbg(xhci, "Resetting HCD\n"); - /* Reset the internal HC memory state and registers. */ - retval = xhci_reset(xhci); - if (retval) - goto error; - xhci_dbg(xhci, "Reset complete\n"); - - temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); - if (HCC_64BIT_ADDR(temp)) { - xhci_dbg(xhci, "Enabling 64-bit DMA addresses.\n"); - dma_set_mask(hcd->self.controller, DMA_BIT_MASK(64)); - } else { - dma_set_mask(hcd->self.controller, DMA_BIT_MASK(32)); + ret = pci_enable_device(dev); + if (ret) { + dev_err(&dev->dev, "failed to enable pci device\n"); + goto err1; } - xhci_dbg(xhci, "Calling HCD init\n"); - /* Initialize HCD and host controller data structures. */ - retval = xhci_init(hcd); - if (retval) - goto error; - xhci_dbg(xhci, "Called HCD init\n"); - - pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn); - xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); + /* Quirk on revision 0 of Fresco Logic's PDK */ + if (dev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && + dev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK) { + if (dev->revision == 0x0) + data->quirks |= XHCI_RESET_EP_QUIRK; + } - /* Find any debug ports */ - retval = xhci_pci_reinit(xhci, pdev); - if (!retval) - return retval; + pci_set_power_state(dev, PCI_D0); + pci_set_master(dev); -error: - kfree(xhci); - return retval; -} + xhci = platform_device_alloc("xhci-pci", -1); + if (!xhci) { + dev_err(&dev->dev, "couldn't allocate xhci device\n"); + goto err2; + } -static const struct hc_driver xhci_pci_hc_driver; + pci_set_drvdata(dev, glue); -/* - * We need to register our own PCI probe function (instead of the USB core's - * function) in order to create a second roothub under xHCI. - */ -static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) -{ - int retval; - struct xhci_hcd *xhci; - const struct hc_driver *driver; - struct usb_hcd *hcd; - struct xhci_pci_data *data = (struct xhci_pci_data *) id->driver_data; + memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); - driver = &xhci_pci_hc_driver; + res[0].start = pci_resource_start(dev, 0); + res[0].end = pci_resource_end(dev, 0); + res[0].name = "xhci"; + res[0].flags = IORESOURCE_MEM; - /* Register the USB 2.0 roothub. - * FIXME: USB core must know to register the USB 2.0 roothub first. - * This is sort of silly, because we could just set the HCD driver flags - * to say USB 2.0, but I'm not sure what the implications would be in - * the other parts of the HCD code. - */ - retval = usb_hcd_pci_probe(dev, id); + res[1].start = dev->irq; + res[1].name = "xhci"; + res[1].flags = IORESOURCE_IRQ; - if (retval) - return retval; + ret = platform_device_add_resources(xhci, res, ARRAY_SIZE(res)); + if (ret) { + dev_err(&dev->dev, "couldn't add resources to xhci device\n"); + goto err3; + } - /* USB 2.0 roothub is stored in the PCI device now. */ - hcd = dev_get_drvdata(&dev->dev); - xhci = hcd_to_xhci(hcd); + dma_set_coherent_mask(&xhci->dev, dev->dev.coherent_dma_mask); - xhci->quirks = data->quirks; - xhci->limit_active_eps = data->limit_active_eps; + xhci->dev.dma_mask = dev->dev.dma_mask; + xhci->dev.dma_parms = dev->dev.dma_parms; + xhci->dev.parent = &dev->dev; + glue->dev = &dev->dev; + glue->xhci = xhci; - /* Quirk on revision 0 of Fresco Logic's PDK */ - if (dev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && - dev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK) { - if (dev->revision == 0x0) { - xhci->quirks |= XHCI_RESET_EP_QUIRK; - xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" - " endpoint cmd after reset endpoint\n"); - } + ret = platform_device_add_data(xhci, data, sizeof(*data)); + if (ret) { + dev_err(&dev->dev, "failed to add platform data\n"); + goto err3; } - xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev, - pci_name(dev), hcd); - if (!xhci->shared_hcd) { - retval = -ENOMEM; - goto dealloc_usb2_hcd; + ret = platform_device_add(xhci); + if (ret) { + dev_err(&dev->dev, "failed to register xhci device\n"); + goto err3; } - /* Set the xHCI pointer before xhci_pci_setup() (aka hcd_driver.reset) - * is called by usb_add_hcd(). - */ - *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci; - - retval = usb_add_hcd(xhci->shared_hcd, dev->irq, - IRQF_DISABLED | IRQF_SHARED); - if (retval) - goto put_usb3_hcd; - /* Roothub already marked as USB 3.0 speed */ return 0; -put_usb3_hcd: - usb_put_hcd(xhci->shared_hcd); -dealloc_usb2_hcd: - usb_hcd_pci_remove(dev); - return retval; -} +err3: + pci_set_drvdata(dev, NULL); + platform_device_put(xhci); -static void xhci_pci_remove(struct pci_dev *dev) -{ - struct xhci_hcd *xhci; +err2: + pci_disable_device(dev); - xhci = hcd_to_xhci(pci_get_drvdata(dev)); - if (xhci->shared_hcd) { - usb_remove_hcd(xhci->shared_hcd); - usb_put_hcd(xhci->shared_hcd); - } - usb_hcd_pci_remove(dev); - kfree(xhci); -} +err1: + kfree(glue); -#ifdef CONFIG_PM -static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - int retval = 0; - - if (hcd->state != HC_STATE_SUSPENDED || - xhci->shared_hcd->state != HC_STATE_SUSPENDED) - return -EINVAL; - - retval = xhci_suspend(xhci); - - return retval; +err0: + return ret; } -static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) +static void xhci_pci_remove(struct pci_dev *dev) { - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - int retval = 0; - - /* The BIOS on systems with the Intel Panther Point chipset may or may - * not support xHCI natively. That means that during system resume, it - * may switch the ports back to EHCI so that users can use their - * keyboard to select a kernel from GRUB after resume from hibernate. - * - * The BIOS is supposed to remember whether the OS had xHCI ports - * enabled before resume, and switch the ports back to xHCI when the - * BIOS/OS semaphore is written, but we all know we can't trust BIOS - * writers. - * - * Unconditionally switch the ports back to xHCI after a system resume. - * We can't tell whether the EHCI or xHCI controller will be resumed - * first, so we have to do the port switchover in both drivers. Writing - * a '1' to the port switchover registers should have no effect if the - * port was already switched over. - */ - if (usb_is_intel_switchable_xhci(pdev)) - usb_enable_xhci_ports(pdev); - - retval = xhci_resume(xhci, hibernated); - return retval; + struct xhci_pci *glue = pci_get_drvdata(dev); + + platform_device_unregister(glue->xhci); + pci_set_drvdata(dev, NULL); + pci_disable_device(dev); + kfree(glue); } -#endif /* CONFIG_PM */ - -static const struct hc_driver xhci_pci_hc_driver = { - .description = hcd_name, - .product_desc = "xHCI Host Controller", - .hcd_priv_size = sizeof(struct xhci_hcd *), - - /* - * generic hardware linkage - */ - .irq = xhci_irq, - .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED, - - /* - * basic lifecycle operations - */ - .reset = xhci_pci_setup, - .start = xhci_run, -#ifdef CONFIG_PM - .pci_suspend = xhci_pci_suspend, - .pci_resume = xhci_pci_resume, -#endif - .stop = xhci_stop, - .shutdown = xhci_shutdown, - - /* - * managing i/o requests and associated device resources - */ - .urb_enqueue = xhci_urb_enqueue, - .urb_dequeue = xhci_urb_dequeue, - .alloc_dev = xhci_alloc_dev, - .free_dev = xhci_free_dev, - .alloc_streams = xhci_alloc_streams, - .free_streams = xhci_free_streams, - .add_endpoint = xhci_add_endpoint, - .drop_endpoint = xhci_drop_endpoint, - .endpoint_reset = xhci_endpoint_reset, - .check_bandwidth = xhci_check_bandwidth, - .reset_bandwidth = xhci_reset_bandwidth, - .address_device = xhci_address_device, - .update_hub_device = xhci_update_hub_device, - .reset_device = xhci_discover_or_reset_device, - - /* - * scheduling support - */ - .get_frame_number = xhci_get_frame, - - /* Root hub support */ - .hub_control = xhci_hub_control, - .hub_status_data = xhci_hub_status_data, - .bus_suspend = xhci_bus_suspend, - .bus_resume = xhci_bus_resume, -}; /*-------------------------------------------------------------------------*/ @@ -401,7 +210,7 @@ MODULE_DEVICE_TABLE(pci, pci_ids); /* pci driver glue; this is a "new style" PCI driver module */ static struct pci_driver xhci_pci_driver = { - .name = (char *) hcd_name, + .name = "xhci-pci", .id_table = pci_ids, .probe = xhci_pci_probe, @@ -416,12 +225,14 @@ static struct pci_driver xhci_pci_driver = { #endif }; -int xhci_register_pci(void) +static int xhci_register_pci(void) { return pci_register_driver(&xhci_pci_driver); } +module_init(xhci_register_pci); -void xhci_unregister_pci(void) +static void xhci_unregister_pci(void) { pci_unregister_driver(&xhci_pci_driver); } +module_exit(xhci_unregister_pci); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 608f919..abc46ae 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3087,6 +3087,7 @@ static const struct hc_driver xhci_hc_driver = { static int xhci_probe(struct platform_device *pdev) { + struct xhci_platform_data *data = pdev->dev.platform_data; struct usb_hcd *hcd; struct xhci_hcd *xhci; struct resource *res; @@ -3143,6 +3144,10 @@ static int xhci_probe(struct platform_device *pdev) } xhci = hcd_to_xhci(hcd); + + xhci->quirks = data->quirks; + xhci->limit_active_eps = data->limit_active_eps; + xhci->shared_hcd = usb_create_shared_hcd(&xhci_hc_driver, &pdev->dev, dev_name(&pdev->dev), hcd); if (!xhci->shared_hcd) { @@ -3195,26 +3200,25 @@ static int __devexit xhci_remove(struct platform_device *pdev) return 0; } +static const struct platform_device_id xhci_id_table[] __devinitconst = { + { + .name = "xhci-pci", + }, + { }, /* Terminating Entry */ +}; +MODULE_DEVICE_TABLE(platform, xhci_id_table); + static struct platform_driver xhci_driver = { .probe = xhci_probe, .remove = __devexit_p(xhci_remove), .driver = { .name = "xhci", }, + .id_table = xhci_id_table, }; static int __init xhci_hcd_init(void) { -#ifdef CONFIG_PCI - int retval = 0; - - retval = xhci_register_pci(); - - if (retval < 0) { - printk(KERN_DEBUG "Problem registering PCI driver."); - return retval; - } -#endif /* * Check the compiler generated sizes of structures that must be laid * out in specific ways for hardware access. @@ -3240,9 +3244,6 @@ module_init(xhci_hcd_init); static void __exit xhci_hcd_cleanup(void) { -#ifdef CONFIG_PCI - xhci_unregister_pci(); -#endif platform_driver_unregister(&xhci_driver); } module_exit(xhci_hcd_cleanup); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index d8bbf5c..b854e73 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -40,6 +40,11 @@ /* Section 5.3.3 - MaxPorts */ #define MAX_HC_PORTS 127 +struct xhci_platform_data { + unsigned int limit_active_eps; + unsigned int quirks; +}; + /* * xHCI register interface. * This corresponds to the eXtensible Host Controller Interface (xHCI) @@ -1472,12 +1477,6 @@ void xhci_urb_free_priv(struct xhci_hcd *xhci, struct urb_priv *urb_priv); void xhci_free_command(struct xhci_hcd *xhci, struct xhci_command *command); -#ifdef CONFIG_PCI -/* xHCI PCI glue */ -int xhci_register_pci(void); -void xhci_unregister_pci(void); -#endif - /* xHCI host controller glue */ void xhci_quiesce(struct xhci_hcd *xhci); int xhci_halt(struct xhci_hcd *xhci); -- 1.7.6 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html