Commit b02d0ed6 authored by Sarah Sharp's avatar Sarah Sharp

xhci: Change hcd_priv into a pointer.

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: default avatarSarah Sharp <sarah.a.sharp@linux.intel.com>
parent 214f76f7
...@@ -57,6 +57,12 @@ static int xhci_pci_setup(struct usb_hcd *hcd) ...@@ -57,6 +57,12 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; 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->cap_regs = hcd->regs;
xhci->op_regs = hcd->regs + xhci->op_regs = hcd->regs +
HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase));
...@@ -85,13 +91,13 @@ static int xhci_pci_setup(struct usb_hcd *hcd) ...@@ -85,13 +91,13 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
/* Make sure the HC is halted. */ /* Make sure the HC is halted. */
retval = xhci_halt(xhci); retval = xhci_halt(xhci);
if (retval) if (retval)
return retval; goto error;
xhci_dbg(xhci, "Resetting HCD\n"); xhci_dbg(xhci, "Resetting HCD\n");
/* Reset the internal HC memory state and registers. */ /* Reset the internal HC memory state and registers. */
retval = xhci_reset(xhci); retval = xhci_reset(xhci);
if (retval) if (retval)
return retval; goto error;
xhci_dbg(xhci, "Reset complete\n"); xhci_dbg(xhci, "Reset complete\n");
temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
...@@ -106,14 +112,29 @@ static int xhci_pci_setup(struct usb_hcd *hcd) ...@@ -106,14 +112,29 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
/* Initialize HCD and host controller data structures. */ /* Initialize HCD and host controller data structures. */
retval = xhci_init(hcd); retval = xhci_init(hcd);
if (retval) if (retval)
return retval; goto error;
xhci_dbg(xhci, "Called HCD init\n"); xhci_dbg(xhci, "Called HCD init\n");
pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn); pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn);
/* Find any debug ports */ /* 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 #ifdef CONFIG_PM
...@@ -143,7 +164,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) ...@@ -143,7 +164,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
static const struct hc_driver xhci_pci_hc_driver = { static const struct hc_driver xhci_pci_hc_driver = {
.description = hcd_name, .description = hcd_name,
.product_desc = "xHCI Host Controller", .product_desc = "xHCI Host Controller",
.hcd_priv_size = sizeof(struct xhci_hcd), .hcd_priv_size = sizeof(struct xhci_hcd *),
/* /*
* generic hardware linkage * generic hardware linkage
...@@ -211,7 +232,7 @@ static struct pci_driver xhci_pci_driver = { ...@@ -211,7 +232,7 @@ static struct pci_driver xhci_pci_driver = {
.id_table = pci_ids, .id_table = pci_ids,
.probe = usb_hcd_pci_probe, .probe = usb_hcd_pci_probe,
.remove = usb_hcd_pci_remove, .remove = xhci_pci_remove,
/* suspend and resume implemented later */ /* suspend and resume implemented later */
.shutdown = usb_hcd_pci_shutdown, .shutdown = usb_hcd_pci_shutdown,
......
...@@ -1163,6 +1163,7 @@ struct s3_save { ...@@ -1163,6 +1163,7 @@ struct s3_save {
/* There is one ehci_hci structure per controller */ /* There is one ehci_hci structure per controller */
struct xhci_hcd { struct xhci_hcd {
struct usb_hcd *main_hcd;
/* glue to PCI and HCD framework */ /* glue to PCI and HCD framework */
struct xhci_cap_regs __iomem *cap_regs; struct xhci_cap_regs __iomem *cap_regs;
struct xhci_op_regs __iomem *op_regs; struct xhci_op_regs __iomem *op_regs;
...@@ -1266,12 +1267,12 @@ struct xhci_hcd { ...@@ -1266,12 +1267,12 @@ struct xhci_hcd {
/* convert between an HCD pointer and the corresponding EHCI_HCD */ /* convert between an HCD pointer and the corresponding EHCI_HCD */
static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *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) 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 #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment