This patch starts decoupling xhci core from PCI. Although we still have a lot to do, this shows how things will look like after the conversion is finished. [bigeasy@xxxxxxxxxxxxx: - add module license, use bitmap for unique ids, tmp pdev workaround] Signed-off-by: Felipe Balbi <balbi@xxxxxx> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> --- drivers/usb/host/Makefile | 7 +- drivers/usb/host/xhci-mem.c | 20 ++-- drivers/usb/host/xhci-pci.c | 225 +++++++++++++++++++++++++------------------ drivers/usb/host/xhci.c | 85 ++++++++++------ drivers/usb/host/xhci.h | 6 - 5 files changed, 200 insertions(+), 143 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-mem.c b/drivers/usb/host/xhci-mem.c index 586aac7..c9ff110 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -312,10 +312,10 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci, unsigned int num_stream_ctxs, struct xhci_stream_ctx *stream_ctx, dma_addr_t dma) { - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct device *dev = xhci_to_hcd(xhci)->self.controller; if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE) - dma_free_coherent(&pdev->dev, + dma_free_coherent(dev, sizeof(struct xhci_stream_ctx)*num_stream_ctxs, stream_ctx, dma); else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE) @@ -340,10 +340,10 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci, unsigned int num_stream_ctxs, dma_addr_t *dma, gfp_t mem_flags) { - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct device *dev = xhci_to_hcd(xhci)->self.controller; if (num_stream_ctxs > MEDIUM_STREAM_ARRAY_SIZE) - return dma_alloc_coherent(&pdev->dev, + return dma_alloc_coherent(dev, sizeof(struct xhci_stream_ctx)*num_stream_ctxs, dma, mem_flags); else if (num_stream_ctxs <= SMALL_STREAM_ARRAY_SIZE) @@ -1403,7 +1403,7 @@ static void scratchpad_free(struct xhci_hcd *xhci) { int num_sp; int i; - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct device *dev = xhci_to_hcd(xhci)->self.controller; if (!xhci->scratchpad) return; @@ -1411,13 +1411,13 @@ static void scratchpad_free(struct xhci_hcd *xhci) num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2); for (i = 0; i < num_sp; i++) { - dma_free_coherent(&pdev->dev, xhci->page_size, + dma_free_coherent(dev, xhci->page_size, xhci->scratchpad->sp_buffers[i], xhci->scratchpad->sp_dma_buffers[i]); } kfree(xhci->scratchpad->sp_dma_buffers); kfree(xhci->scratchpad->sp_buffers); - dma_free_coherent(&pdev->dev, num_sp * sizeof(u64), + dma_free_coherent(dev, num_sp * sizeof(u64), xhci->scratchpad->sp_array, xhci->scratchpad->sp_dma); kfree(xhci->scratchpad); @@ -1487,7 +1487,7 @@ void xhci_free_command(struct xhci_hcd *xhci, void xhci_mem_cleanup(struct xhci_hcd *xhci) { - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct device *dev = xhci_to_hcd(xhci)->self.controller; int size; int i; @@ -1499,7 +1499,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) } size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries); if (xhci->erst.entries) - dma_free_coherent(&pdev->dev, size, + dma_free_coherent(dev, size, xhci->erst.entries, xhci->erst.erst_dma_addr); xhci->erst.entries = NULL; xhci_dbg(xhci, "Freed ERST\n"); @@ -1539,7 +1539,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr); if (xhci->dcbaa) - dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa), + dma_free_coherent(dev, sizeof(*xhci->dcbaa), xhci->dcbaa, xhci->dcbaa->dma); xhci->dcbaa = NULL; diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 7006600..b01c021 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,7 +33,6 @@ #define PCI_VENDOR_ID_ETRON 0x1b6f #define PCI_DEVICE_ID_ASROCK_P67 0x7023 -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) @@ -58,6 +58,12 @@ static int xhci_pci_setup(struct usb_hcd *hcd) struct pci_dev *pdev = to_pci_dev(hcd->self.controller); int retval; u32 temp; + struct platform_device *plat_dev; + struct xhci_platform_data *data; + + plat_dev = to_platform_device(hcd->self.controller); + data = plat_dev->dev.platform_data; + pdev = to_pci_dev(plat_dev->dev.parent); hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; @@ -107,41 +113,8 @@ static int xhci_pci_setup(struct usb_hcd *hcd) xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params); xhci_print_registers(xhci); - /* Look for vendor-specific quirks */ - if (pdev->vendor == PCI_VENDOR_ID_FRESCO_LOGIC && - pdev->device == PCI_DEVICE_ID_FRESCO_LOGIC_PDK) { - if (pdev->revision == 0x0) { - xhci->quirks |= XHCI_RESET_EP_QUIRK; - xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" - " endpoint cmd after reset endpoint\n"); - } - /* Fresco Logic confirms: all revisions of this chip do not - * support MSI, even though some of them claim to in their PCI - * capabilities. - */ - xhci->quirks |= XHCI_BROKEN_MSI; - xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u " - "has broken MSI implementation\n", - pdev->revision); - } - - if (pdev->vendor == PCI_VENDOR_ID_NEC) - xhci->quirks |= XHCI_NEC_HOST; - - /* AMD PLL quirk */ - if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) - xhci->quirks |= XHCI_AMD_PLL_FIX; - if (pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) { - xhci->quirks |= XHCI_SPURIOUS_SUCCESS; - xhci->quirks |= XHCI_EP_LIMIT_QUIRK; - xhci->limit_active_eps = 64; - } - if (pdev->vendor == PCI_VENDOR_ID_ETRON && - pdev->device == PCI_DEVICE_ID_ASROCK_P67) { - xhci->quirks |= XHCI_RESET_ON_RESUME; - xhci_dbg(xhci, "QUIRK: Resetting on resume\n"); - } + xhci->quirks = data->quirks; + xhci->limit_active_eps = data->limit_active_eps; /* Make sure the HC is halted. */ retval = xhci_halt(xhci); @@ -183,79 +156,132 @@ error: return retval; } -static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +#define XHCI_PCI_DEVS_POSSIBLE 32 +static DECLARE_BITMAP(xhci_pci_devs, XHCI_PCI_DEVS_POSSIBLE); + +static int xhci_get_unique_id(void) { - int retval; - struct xhci_hcd *xhci; - const struct hc_driver *driver; - struct usb_hcd *hcd; - struct xhci_platform_data *data; + int id; +again: + id = find_first_zero_bit(xhci_pci_devs, XHCI_PCI_DEVS_POSSIBLE); + if (id < XHCI_PCI_DEVS_POSSIBLE) { + int old; + + old = test_and_set_bit(id, xhci_pci_devs); + if (old) + goto again; + } else { + id = -ENOMEM; + } + return id; +} - data = (struct xhci_platform_data *) id->driver_data; - driver = data->driver; +static void xhci_put_unique_id(int id) +{ + if (id < 0) + return; + WARN_ON(!test_bit(id, xhci_pci_devs)); + clear_bit(id, xhci_pci_devs); +} - /* 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); +static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + struct xhci_platform_data *data; + struct platform_device *xhci_pdev; + struct resource res[2]; + int dev_id; + int ret; - if (retval) - return retval; + data = (struct xhci_platform_data *) id->driver_data; - /* USB 2.0 roothub is stored in the PCI device now. */ - hcd = dev_get_drvdata(&dev->dev); - xhci = hcd_to_xhci(hcd); + ret = pci_enable_device(dev); + if (ret) { + dev_err(&dev->dev, "failed to enable pci device\n"); + goto err1; + } /* 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) { + if (dev->revision == 0x0) data->quirks |= XHCI_RESET_EP_QUIRK; - xhci_dbg(xhci, "QUIRK: Fresco Logic xHC needs configure" - " endpoint cmd after reset endpoint\n"); - } } - xhci->shared_hcd = usb_create_shared_hcd(driver, &dev->dev, - pci_name(dev), hcd); - if (!xhci->shared_hcd) { - retval = -ENOMEM; - goto dealloc_usb2_hcd; + pci_set_power_state(dev, PCI_D0); + pci_set_master(dev); + + dev_id = xhci_get_unique_id(); + if (dev_id < 0) { + dev_err(&dev->dev, "Too many xhci controller in system\n"); + goto err2; + } + xhci_pdev = platform_device_alloc("usb-xhci-pci", dev_id); + if (!xhci_pdev) { + dev_err(&dev->dev, "couldn't allocate xhci device\n"); + goto err2_5; } - /* 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; + pci_set_drvdata(dev, xhci_pdev); + + memset(res, 0x00, sizeof(res)); + + 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; + res[1].start = dev->irq; + res[1].name = "xhci"; + res[1].flags = IORESOURCE_IRQ; + + ret = platform_device_add_resources(xhci_pdev, res, ARRAY_SIZE(res)); + if (ret) { + dev_err(&dev->dev, "couldn't add resources to xhci device\n"); + goto err3; + } + + dma_set_coherent_mask(&xhci_pdev->dev, dev->dev.coherent_dma_mask); + + xhci_pdev->dev.dma_mask = dev->dev.dma_mask; + xhci_pdev->dev.dma_parms = dev->dev.dma_parms; + xhci_pdev->dev.parent = &dev->dev; + + ret = platform_device_add_data(xhci_pdev, data, sizeof(*data)); + if (ret) { + dev_err(&dev->dev, "failed to add platform data\n"); + goto err3; + } + + ret = platform_device_add(xhci_pdev); + if (ret) { + dev_err(&dev->dev, "failed to register xhci device\n"); + goto err3; + } - 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_pdev); + +err2_5: + xhci_put_unique_id(dev_id); +err2: + pci_disable_device(dev); + +err1: + return ret; } static void xhci_pci_remove(struct pci_dev *dev) { - struct xhci_hcd *xhci; - - 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); + struct platform_device *xhci_pdev = pci_get_drvdata(dev); + int id; + + id = xhci_pdev->id; + pci_set_drvdata(dev, NULL); + platform_device_unregister(xhci_pdev); + xhci_put_unique_id(id); + pci_disable_device(dev); } #ifdef CONFIG_PM @@ -304,7 +330,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) #endif /* CONFIG_PM */ static const struct hc_driver xhci_pci_hc_driver = { - .description = hcd_name, + .description = "xhci-pci", .product_desc = "xHCI Host Controller", .hcd_priv_size = sizeof(struct xhci_hcd *), @@ -424,29 +450,38 @@ static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { }; MODULE_DEVICE_TABLE(pci, pci_ids); +static void usb_xhci_pci_shutdown(struct pci_dev *dev) +{ + pci_disable_device(dev); +} + /* 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, - .remove = xhci_pci_remove, + .remove = __devexit_p(xhci_pci_remove), /* suspend and resume implemented later */ - .shutdown = usb_hcd_pci_shutdown, + .shutdown = usb_xhci_pci_shutdown, #ifdef CONFIG_PM_SLEEP .driver = { - .pm = &usb_hcd_pci_pm_ops + .pm = &usb_hcd_plat_pci_pm_ops, }, #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); +MODULE_DESCRIPTION("PCI glue code for the XHCI controller"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 203114d..55a963c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -198,20 +198,24 @@ static int xhci_free_msi(struct xhci_hcd *xhci) */ static int xhci_setup_msi(struct xhci_hcd *xhci) { - int ret; - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + struct platform_device *plat_dev; + struct pci_dev *pci_dev; + int ret; + + plat_dev = to_platform_device(xhci_to_hcd(xhci)->self.controller); + pci_dev = to_pci_dev(plat_dev->dev.parent); - ret = pci_enable_msi(pdev); + ret = pci_enable_msi(pci_dev); if (ret) { xhci_err(xhci, "failed to allocate MSI entry\n"); return ret; } - ret = request_irq(pdev->irq, (irq_handler_t)xhci_msi_irq, + ret = request_irq(pci_dev->irq, (irq_handler_t)xhci_msi_irq, 0, "xhci_hcd", xhci_to_hcd(xhci)); if (ret) { xhci_err(xhci, "disable MSI interrupt\n"); - pci_disable_msi(pdev); + pci_disable_msi(pci_dev); } return ret; @@ -223,9 +227,12 @@ static int xhci_setup_msi(struct xhci_hcd *xhci) */ static void xhci_free_irq(struct xhci_hcd *xhci) { - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - int ret; + struct platform_device *plat_dev; + struct pci_dev *pci_dev; + int ret; + plat_dev = to_platform_device(xhci_to_hcd(xhci)->self.controller); + pci_dev = to_pci_dev(plat_dev->dev.parent); /* return if using legacy interrupt */ if (xhci_to_hcd(xhci)->irq >= 0) return; @@ -233,8 +240,8 @@ static void xhci_free_irq(struct xhci_hcd *xhci) ret = xhci_free_msi(xhci); if (!ret) return; - if (pdev->irq >= 0) - free_irq(pdev->irq, xhci_to_hcd(xhci)); + if (pci_dev->irq >= 0) + free_irq(pci_dev->irq, xhci_to_hcd(xhci)); return; } @@ -246,7 +253,11 @@ static int xhci_setup_msix(struct xhci_hcd *xhci) { int i, ret = 0; struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + struct platform_device *plat_dev; + struct pci_dev *pci_dev; + + plat_dev = to_platform_device(hcd->self.controller); + pci_dev = to_pci_dev(plat_dev->dev.parent); /* * calculate number of msi-x vectors supported. @@ -271,7 +282,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci) xhci->msix_entries[i].vector = 0; } - ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count); + ret = pci_enable_msix(pci_dev, xhci->msix_entries, xhci->msix_count); if (ret) { xhci_err(xhci, "Failed to enable MSI-X\n"); goto free_entries; @@ -291,7 +302,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci) disable_msix: xhci_err(xhci, "disable MSI-X interrupt\n"); xhci_free_irq(xhci); - pci_disable_msix(pdev); + pci_disable_msix(pci_dev); free_entries: kfree(xhci->msix_entries); xhci->msix_entries = NULL; @@ -302,16 +313,20 @@ free_entries: static void xhci_cleanup_msix(struct xhci_hcd *xhci) { struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + struct platform_device *plat_dev; + struct pci_dev *pci_dev; + + plat_dev = to_platform_device(hcd->self.controller); + pci_dev = to_pci_dev(plat_dev->dev.parent); xhci_free_irq(xhci); if (xhci->msix_entries) { - pci_disable_msix(pdev); + pci_disable_msix(pci_dev); kfree(xhci->msix_entries); xhci->msix_entries = NULL; } else { - pci_disable_msi(pdev); + pci_disable_msi(pci_dev); } hcd->msix_enabled = 0; @@ -3130,8 +3145,6 @@ static int xhci_probe(struct platform_device *pdev) goto err0; } - platform_set_drvdata(pdev, hcd); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "missing memory resource\n"); @@ -3211,29 +3224,42 @@ static int __devexit xhci_remove(struct platform_device *pdev) iounmap(hcd->regs); release_mem_region(hcd->rsrc_start, hcd->rsrc_len); usb_put_hcd(hcd); + platform_set_drvdata(pdev, NULL); return 0; } +static void xhci_plat_shutdown(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + if (!hcd) + return; + if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && + hcd->driver->shutdown) + hcd->driver->shutdown(hcd); +} + +static const struct platform_device_id xhci_id_table[] __devinitconst = { + { + .name = "usb-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), + .shutdown = xhci_plat_shutdown, .driver = { - .name = "xhci", + .name = "xhci-core", + .owner = THIS_MODULE, }, + .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. @@ -3259,9 +3285,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 1f0021c..3f82ad2 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1488,12 +1488,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.4.4 -- 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