Instead of allocating space for the whole xhci_hcd structure at the end of usb_hcd, make the USB core allocate enough space for a pointer to the xhci_hcd structure. This will make it easy to share the xhci_hcd structure across the two roothubs (the USB 3.0 usb_hcd and the USB 2.0 usb_hcd). Deallocate the xhci_hcd at PCI remove time, so the hcd_priv will be deallocated after the usb_hcd is deallocated. We do this by registering a different PCI remove function that calls the usb_hcd_pci_remove() function, and then frees the xhci_hcd. usb_hcd_pci_remove() calls kput() on the usb_hcd structure, which will deallocate the memory that contains the hcd_priv pointer, but not the memory it points to. Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx> --- drivers/usb/host/xhci-pci.c | 33 +++++++++++++++++++++++++++------ drivers/usb/host/xhci.h | 5 +++-- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index bb668a8..0090828 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -57,6 +57,12 @@ static int xhci_pci_setup(struct usb_hcd *hcd) hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; + xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL); + if (!xhci) + return -ENOMEM; + *((struct xhci_hcd **) hcd->hcd_priv) = xhci; + xhci->main_hcd = hcd; + xhci->cap_regs = hcd->regs; xhci->op_regs = hcd->regs + HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); @@ -85,13 +91,13 @@ static int xhci_pci_setup(struct usb_hcd *hcd) /* Make sure the HC is halted. */ retval = xhci_halt(xhci); if (retval) - return retval; + goto error; xhci_dbg(xhci, "Resetting HCD\n"); /* Reset the internal HC memory state and registers. */ retval = xhci_reset(xhci); if (retval) - return retval; + goto error; xhci_dbg(xhci, "Reset complete\n"); temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); @@ -106,14 +112,29 @@ static int xhci_pci_setup(struct usb_hcd *hcd) /* Initialize HCD and host controller data structures. */ retval = xhci_init(hcd); if (retval) - return 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); /* Find any debug ports */ - return xhci_pci_reinit(xhci, pdev); + retval = xhci_pci_reinit(xhci, pdev); + if (!retval) + return retval; + +error: + kfree(xhci); + return retval; +} + +static void xhci_pci_remove(struct pci_dev *dev) +{ + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(pci_get_drvdata(dev)); + usb_hcd_pci_remove(dev); + kfree(xhci); } #ifdef CONFIG_PM @@ -143,7 +164,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) static const struct hc_driver xhci_pci_hc_driver = { .description = hcd_name, .product_desc = "xHCI Host Controller", - .hcd_priv_size = sizeof(struct xhci_hcd), + .hcd_priv_size = sizeof(struct xhci_hcd *), /* * generic hardware linkage @@ -211,7 +232,7 @@ static struct pci_driver xhci_pci_driver = { .id_table = pci_ids, .probe = usb_hcd_pci_probe, - .remove = usb_hcd_pci_remove, + .remove = xhci_pci_remove, /* suspend and resume implemented later */ .shutdown = usb_hcd_pci_shutdown, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 3cc4ebc..243d8d9 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1167,6 +1167,7 @@ struct s3_save { /* There is one ehci_hci structure per controller */ struct xhci_hcd { + struct usb_hcd *main_hcd; /* glue to PCI and HCD framework */ struct xhci_cap_regs __iomem *cap_regs; struct xhci_op_regs __iomem *op_regs; @@ -1270,12 +1271,12 @@ struct xhci_hcd { /* convert between an HCD pointer and the corresponding EHCI_HCD */ static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd) { - return (struct xhci_hcd *) (hcd->hcd_priv); + return *((struct xhci_hcd **) (hcd->hcd_priv)); } static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci) { - return container_of((void *) xhci, struct usb_hcd, hcd_priv); + return xhci->main_hcd; } #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING -- 1.6.3.3 -- 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