diff options
author | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2010-10-26 14:03:44 -0400 |
---|---|---|
committer | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2011-03-13 21:07:13 -0400 |
commit | b02d0ed677acb3465e7600366f2353413bf24074 (patch) | |
tree | 8efdbb5ea07a387a687aa24f0bcda8ba3a454d76 | |
parent | 214f76f7d9198ddd090bd927a4bcd49391bfcd36 (diff) |
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: Sarah Sharp <sarah.a.sharp@linux.intel.com>
-rw-r--r-- | drivers/usb/host/xhci-pci.c | 33 | ||||
-rw-r--r-- | 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 bb668a894ab9..009082829364 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) | |||
57 | 57 | ||
58 | hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; | 58 | hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; |
59 | 59 | ||
60 | xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL); | ||
61 | if (!xhci) | ||
62 | return -ENOMEM; | ||
63 | *((struct xhci_hcd **) hcd->hcd_priv) = xhci; | ||
64 | xhci->main_hcd = hcd; | ||
65 | |||
60 | xhci->cap_regs = hcd->regs; | 66 | xhci->cap_regs = hcd->regs; |
61 | xhci->op_regs = hcd->regs + | 67 | xhci->op_regs = hcd->regs + |
62 | HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); | 68 | HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); |
@@ -85,13 +91,13 @@ static int xhci_pci_setup(struct usb_hcd *hcd) | |||
85 | /* Make sure the HC is halted. */ | 91 | /* Make sure the HC is halted. */ |
86 | retval = xhci_halt(xhci); | 92 | retval = xhci_halt(xhci); |
87 | if (retval) | 93 | if (retval) |
88 | return retval; | 94 | goto error; |
89 | 95 | ||
90 | xhci_dbg(xhci, "Resetting HCD\n"); | 96 | xhci_dbg(xhci, "Resetting HCD\n"); |
91 | /* Reset the internal HC memory state and registers. */ | 97 | /* Reset the internal HC memory state and registers. */ |
92 | retval = xhci_reset(xhci); | 98 | retval = xhci_reset(xhci); |
93 | if (retval) | 99 | if (retval) |
94 | return retval; | 100 | goto error; |
95 | xhci_dbg(xhci, "Reset complete\n"); | 101 | xhci_dbg(xhci, "Reset complete\n"); |
96 | 102 | ||
97 | temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); | 103 | temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); |
@@ -106,14 +112,29 @@ static int xhci_pci_setup(struct usb_hcd *hcd) | |||
106 | /* Initialize HCD and host controller data structures. */ | 112 | /* Initialize HCD and host controller data structures. */ |
107 | retval = xhci_init(hcd); | 113 | retval = xhci_init(hcd); |
108 | if (retval) | 114 | if (retval) |
109 | return retval; | 115 | goto error; |
110 | xhci_dbg(xhci, "Called HCD init\n"); | 116 | xhci_dbg(xhci, "Called HCD init\n"); |
111 | 117 | ||
112 | pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn); | 118 | pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn); |
113 | xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); | 119 | xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); |
114 | 120 | ||
115 | /* Find any debug ports */ | 121 | /* Find any debug ports */ |
116 | return xhci_pci_reinit(xhci, pdev); | 122 | retval = xhci_pci_reinit(xhci, pdev); |
123 | if (!retval) | ||
124 | return retval; | ||
125 | |||
126 | error: | ||
127 | kfree(xhci); | ||
128 | return retval; | ||
129 | } | ||
130 | |||
131 | static void xhci_pci_remove(struct pci_dev *dev) | ||
132 | { | ||
133 | struct xhci_hcd *xhci; | ||
134 | |||
135 | xhci = hcd_to_xhci(pci_get_drvdata(dev)); | ||
136 | usb_hcd_pci_remove(dev); | ||
137 | kfree(xhci); | ||
117 | } | 138 | } |
118 | 139 | ||
119 | #ifdef CONFIG_PM | 140 | #ifdef CONFIG_PM |
@@ -143,7 +164,7 @@ static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | |||
143 | static const struct hc_driver xhci_pci_hc_driver = { | 164 | static const struct hc_driver xhci_pci_hc_driver = { |
144 | .description = hcd_name, | 165 | .description = hcd_name, |
145 | .product_desc = "xHCI Host Controller", | 166 | .product_desc = "xHCI Host Controller", |
146 | .hcd_priv_size = sizeof(struct xhci_hcd), | 167 | .hcd_priv_size = sizeof(struct xhci_hcd *), |
147 | 168 | ||
148 | /* | 169 | /* |
149 | * generic hardware linkage | 170 | * generic hardware linkage |
@@ -211,7 +232,7 @@ static struct pci_driver xhci_pci_driver = { | |||
211 | .id_table = pci_ids, | 232 | .id_table = pci_ids, |
212 | 233 | ||
213 | .probe = usb_hcd_pci_probe, | 234 | .probe = usb_hcd_pci_probe, |
214 | .remove = usb_hcd_pci_remove, | 235 | .remove = xhci_pci_remove, |
215 | /* suspend and resume implemented later */ | 236 | /* suspend and resume implemented later */ |
216 | 237 | ||
217 | .shutdown = usb_hcd_pci_shutdown, | 238 | .shutdown = usb_hcd_pci_shutdown, |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index c4e70c6d809c..daa88581ad66 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -1163,6 +1163,7 @@ struct s3_save { | |||
1163 | 1163 | ||
1164 | /* There is one ehci_hci structure per controller */ | 1164 | /* There is one ehci_hci structure per controller */ |
1165 | struct xhci_hcd { | 1165 | struct xhci_hcd { |
1166 | struct usb_hcd *main_hcd; | ||
1166 | /* glue to PCI and HCD framework */ | 1167 | /* glue to PCI and HCD framework */ |
1167 | struct xhci_cap_regs __iomem *cap_regs; | 1168 | struct xhci_cap_regs __iomem *cap_regs; |
1168 | struct xhci_op_regs __iomem *op_regs; | 1169 | struct xhci_op_regs __iomem *op_regs; |
@@ -1266,12 +1267,12 @@ struct xhci_hcd { | |||
1266 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ | 1267 | /* convert between an HCD pointer and the corresponding EHCI_HCD */ |
1267 | static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd) | 1268 | static inline struct xhci_hcd *hcd_to_xhci(struct usb_hcd *hcd) |
1268 | { | 1269 | { |
1269 | return (struct xhci_hcd *) (hcd->hcd_priv); | 1270 | return *((struct xhci_hcd **) (hcd->hcd_priv)); |
1270 | } | 1271 | } |
1271 | 1272 | ||
1272 | static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci) | 1273 | static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci) |
1273 | { | 1274 | { |
1274 | return container_of((void *) xhci, struct usb_hcd, hcd_priv); | 1275 | return xhci->main_hcd; |
1275 | } | 1276 | } |
1276 | 1277 | ||
1277 | #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING | 1278 | #ifdef CONFIG_USB_XHCI_HCD_DEBUGGING |