aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2010-10-28 18:40:26 -0400
committerSarah Sharp <sarah.a.sharp@linux.intel.com>2011-03-13 21:23:06 -0400
commitc56354378426e550aaf6ddf3983f502a8fddeab5 (patch)
tree35464da7692b5ac096bc05841b2dc4761e711117 /drivers/usb/core
parent83de4b2b90887b5b317d8313864fe4cc5db35280 (diff)
usb: Make core allocate resources per PCI-device.
Introduce the notion of a PCI device that may be associated with more than one USB host controller driver (struct usb_hcd). This patch is the start of the work to separate the xHCI host controller into two roothubs: a USB 3.0 roothub with SuperSpeed-only ports, and a USB 2.0 roothub with HS/FS/LS ports. One usb_hcd structure is designated to be the "primary HCD", and a pointer is added to the usb_hcd structure to keep track of that. A new function call, usb_hcd_is_primary_hcd() is added to check whether the USB hcd is marked as the primary HCD (or if it is not part of a roothub pair). To allow the USB core and xHCI driver to access either roothub in a pair, a "shared_hcd" pointer is added to the usb_hcd structure. Add a new function, usb_create_shared_hcd(), that does roothub allocation for paired roothubs. It will act just like usb_create_hcd() did if the primary_hcd pointer argument is NULL. If it is passed a non-NULL primary_hcd pointer, it sets usb_hcd->shared_hcd and usb_hcd->primary_hcd fields. It will also skip the bandwidth_mutex allocation, and set the secondary hcd's bandwidth_mutex pointer to the primary HCD's mutex. IRQs are only allocated once for the primary roothub. Introduce a new usb_hcd driver flag that indicates the host controller driver wants to create two roothubs. If the HCD_SHARED flag is set, then the USB core PCI probe methods will allocate a second roothub, and make sure that second roothub gets freed during rmmod and in initialization error paths. When usb_hc_died() is called with the primary HCD, make sure that any roothubs that share that host controller are also marked as being dead. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/hcd.c108
1 files changed, 89 insertions, 19 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index a0adcac3da0..ba15eeab824 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2143,7 +2143,9 @@ EXPORT_SYMBOL_GPL(usb_hcd_irq);
2143 * 2143 *
2144 * This is called by bus glue to report a USB host controller that died 2144 * This is called by bus glue to report a USB host controller that died
2145 * while operations may still have been pending. It's called automatically 2145 * while operations may still have been pending. It's called automatically
2146 * by the PCI glue, so only glue for non-PCI busses should need to call it. 2146 * by the PCI glue, so only glue for non-PCI busses should need to call it.
2147 *
2148 * Only call this function with the primary HCD.
2147 */ 2149 */
2148void usb_hc_died (struct usb_hcd *hcd) 2150void usb_hc_died (struct usb_hcd *hcd)
2149{ 2151{
@@ -2162,17 +2164,31 @@ void usb_hc_died (struct usb_hcd *hcd)
2162 USB_STATE_NOTATTACHED); 2164 USB_STATE_NOTATTACHED);
2163 usb_kick_khubd (hcd->self.root_hub); 2165 usb_kick_khubd (hcd->self.root_hub);
2164 } 2166 }
2167 if (usb_hcd_is_primary_hcd(hcd) && hcd->shared_hcd) {
2168 hcd = hcd->shared_hcd;
2169 if (hcd->rh_registered) {
2170 clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
2171
2172 /* make khubd clean up old urbs and devices */
2173 usb_set_device_state(hcd->self.root_hub,
2174 USB_STATE_NOTATTACHED);
2175 usb_kick_khubd(hcd->self.root_hub);
2176 }
2177 }
2165 spin_unlock_irqrestore (&hcd_root_hub_lock, flags); 2178 spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
2179 /* Make sure that the other roothub is also deallocated. */
2166} 2180}
2167EXPORT_SYMBOL_GPL (usb_hc_died); 2181EXPORT_SYMBOL_GPL (usb_hc_died);
2168 2182
2169/*-------------------------------------------------------------------------*/ 2183/*-------------------------------------------------------------------------*/
2170 2184
2171/** 2185/**
2172 * usb_create_hcd - create and initialize an HCD structure 2186 * usb_create_shared_hcd - create and initialize an HCD structure
2173 * @driver: HC driver that will use this hcd 2187 * @driver: HC driver that will use this hcd
2174 * @dev: device for this HC, stored in hcd->self.controller 2188 * @dev: device for this HC, stored in hcd->self.controller
2175 * @bus_name: value to store in hcd->self.bus_name 2189 * @bus_name: value to store in hcd->self.bus_name
2190 * @primary_hcd: a pointer to the usb_hcd structure that is sharing the
2191 * PCI device. Only allocate certain resources for the primary HCD
2176 * Context: !in_interrupt() 2192 * Context: !in_interrupt()
2177 * 2193 *
2178 * Allocate a struct usb_hcd, with extra space at the end for the 2194 * Allocate a struct usb_hcd, with extra space at the end for the
@@ -2181,8 +2197,9 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
2181 * 2197 *
2182 * If memory is unavailable, returns NULL. 2198 * If memory is unavailable, returns NULL.
2183 */ 2199 */
2184struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, 2200struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
2185 struct device *dev, const char *bus_name) 2201 struct device *dev, const char *bus_name,
2202 struct usb_hcd *primary_hcd)
2186{ 2203{
2187 struct usb_hcd *hcd; 2204 struct usb_hcd *hcd;
2188 2205
@@ -2191,16 +2208,24 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
2191 dev_dbg (dev, "hcd alloc failed\n"); 2208 dev_dbg (dev, "hcd alloc failed\n");
2192 return NULL; 2209 return NULL;
2193 } 2210 }
2194 hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex), 2211 if (primary_hcd == NULL) {
2195 GFP_KERNEL); 2212 hcd->bandwidth_mutex = kmalloc(sizeof(*hcd->bandwidth_mutex),
2196 if (!hcd->bandwidth_mutex) { 2213 GFP_KERNEL);
2197 kfree(hcd); 2214 if (!hcd->bandwidth_mutex) {
2198 dev_dbg(dev, "hcd bandwidth mutex alloc failed\n"); 2215 kfree(hcd);
2199 return NULL; 2216 dev_dbg(dev, "hcd bandwidth mutex alloc failed\n");
2217 return NULL;
2218 }
2219 mutex_init(hcd->bandwidth_mutex);
2220 dev_set_drvdata(dev, hcd);
2221 } else {
2222 hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
2223 hcd->primary_hcd = primary_hcd;
2224 primary_hcd->primary_hcd = primary_hcd;
2225 hcd->shared_hcd = primary_hcd;
2226 primary_hcd->shared_hcd = hcd;
2200 } 2227 }
2201 mutex_init(hcd->bandwidth_mutex);
2202 2228
2203 dev_set_drvdata(dev, hcd);
2204 kref_init(&hcd->kref); 2229 kref_init(&hcd->kref);
2205 2230
2206 usb_bus_init(&hcd->self); 2231 usb_bus_init(&hcd->self);
@@ -2221,13 +2246,46 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
2221 "USB Host Controller"; 2246 "USB Host Controller";
2222 return hcd; 2247 return hcd;
2223} 2248}
2249EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
2250
2251/**
2252 * usb_create_hcd - create and initialize an HCD structure
2253 * @driver: HC driver that will use this hcd
2254 * @dev: device for this HC, stored in hcd->self.controller
2255 * @bus_name: value to store in hcd->self.bus_name
2256 * Context: !in_interrupt()
2257 *
2258 * Allocate a struct usb_hcd, with extra space at the end for the
2259 * HC driver's private data. Initialize the generic members of the
2260 * hcd structure.
2261 *
2262 * If memory is unavailable, returns NULL.
2263 */
2264struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
2265 struct device *dev, const char *bus_name)
2266{
2267 return usb_create_shared_hcd(driver, dev, bus_name, NULL);
2268}
2224EXPORT_SYMBOL_GPL(usb_create_hcd); 2269EXPORT_SYMBOL_GPL(usb_create_hcd);
2225 2270
2271/*
2272 * Roothubs that share one PCI device must also share the bandwidth mutex.
2273 * Don't deallocate the bandwidth_mutex until the last shared usb_hcd is
2274 * deallocated.
2275 *
2276 * Make sure to only deallocate the bandwidth_mutex when the primary HCD is
2277 * freed. When hcd_release() is called for the non-primary HCD, set the
2278 * primary_hcd's shared_hcd pointer to null (since the non-primary HCD will be
2279 * freed shortly).
2280 */
2226static void hcd_release (struct kref *kref) 2281static void hcd_release (struct kref *kref)
2227{ 2282{
2228 struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); 2283 struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
2229 2284
2230 kfree(hcd->bandwidth_mutex); 2285 if (usb_hcd_is_primary_hcd(hcd))
2286 kfree(hcd->bandwidth_mutex);
2287 else
2288 hcd->shared_hcd->shared_hcd = NULL;
2231 kfree(hcd); 2289 kfree(hcd);
2232} 2290}
2233 2291
@@ -2246,6 +2304,14 @@ void usb_put_hcd (struct usb_hcd *hcd)
2246} 2304}
2247EXPORT_SYMBOL_GPL(usb_put_hcd); 2305EXPORT_SYMBOL_GPL(usb_put_hcd);
2248 2306
2307int usb_hcd_is_primary_hcd(struct usb_hcd *hcd)
2308{
2309 if (!hcd->primary_hcd)
2310 return 1;
2311 return hcd == hcd->primary_hcd;
2312}
2313EXPORT_SYMBOL_GPL(usb_hcd_is_primary_hcd);
2314
2249static int usb_hcd_request_irqs(struct usb_hcd *hcd, 2315static int usb_hcd_request_irqs(struct usb_hcd *hcd,
2250 unsigned int irqnum, unsigned long irqflags) 2316 unsigned int irqnum, unsigned long irqflags)
2251{ 2317{
@@ -2367,9 +2433,11 @@ int usb_add_hcd(struct usb_hcd *hcd,
2367 dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); 2433 dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
2368 2434
2369 /* enable irqs just before we start the controller */ 2435 /* enable irqs just before we start the controller */
2370 retval = usb_hcd_request_irqs(hcd, irqnum, irqflags); 2436 if (usb_hcd_is_primary_hcd(hcd)) {
2371 if (retval) 2437 retval = usb_hcd_request_irqs(hcd, irqnum, irqflags);
2372 goto err_request_irq; 2438 if (retval)
2439 goto err_request_irq;
2440 }
2373 2441
2374 hcd->state = HC_STATE_RUNNING; 2442 hcd->state = HC_STATE_RUNNING;
2375 retval = hcd->driver->start(hcd); 2443 retval = hcd->driver->start(hcd);
@@ -2416,7 +2484,7 @@ err_register_root_hub:
2416 clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); 2484 clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
2417 del_timer_sync(&hcd->rh_timer); 2485 del_timer_sync(&hcd->rh_timer);
2418err_hcd_driver_start: 2486err_hcd_driver_start:
2419 if (hcd->irq >= 0) 2487 if (usb_hcd_is_primary_hcd(hcd) && hcd->irq >= 0)
2420 free_irq(irqnum, hcd); 2488 free_irq(irqnum, hcd);
2421err_request_irq: 2489err_request_irq:
2422err_hcd_driver_setup: 2490err_hcd_driver_setup:
@@ -2480,8 +2548,10 @@ void usb_remove_hcd(struct usb_hcd *hcd)
2480 clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); 2548 clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
2481 del_timer_sync(&hcd->rh_timer); 2549 del_timer_sync(&hcd->rh_timer);
2482 2550
2483 if (hcd->irq >= 0) 2551 if (usb_hcd_is_primary_hcd(hcd)) {
2484 free_irq(hcd->irq, hcd); 2552 if (hcd->irq >= 0)
2553 free_irq(hcd->irq, hcd);
2554 }
2485 2555
2486 usb_put_dev(hcd->self.root_hub); 2556 usb_put_dev(hcd->self.root_hub);
2487 usb_deregister_bus(&hcd->self); 2557 usb_deregister_bus(&hcd->self);