aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/hcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/hcd.c')
-rw-r--r--drivers/usb/core/hcd.c49
1 files changed, 39 insertions, 10 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 9c4e2922b04d..bec31e2efb88 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -918,6 +918,7 @@ static void usb_bus_init (struct usb_bus *bus)
918 bus->bandwidth_allocated = 0; 918 bus->bandwidth_allocated = 0;
919 bus->bandwidth_int_reqs = 0; 919 bus->bandwidth_int_reqs = 0;
920 bus->bandwidth_isoc_reqs = 0; 920 bus->bandwidth_isoc_reqs = 0;
921 mutex_init(&bus->usb_address0_mutex);
921 922
922 INIT_LIST_HEAD (&bus->bus_list); 923 INIT_LIST_HEAD (&bus->bus_list);
923} 924}
@@ -1502,6 +1503,9 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
1502 ret = -EAGAIN; 1503 ret = -EAGAIN;
1503 else 1504 else
1504 urb->transfer_flags |= URB_DMA_MAP_PAGE; 1505 urb->transfer_flags |= URB_DMA_MAP_PAGE;
1506 } else if (is_vmalloc_addr(urb->transfer_buffer)) {
1507 WARN_ONCE(1, "transfer buffer not dma capable\n");
1508 ret = -EAGAIN;
1505 } else { 1509 } else {
1506 urb->transfer_dma = dma_map_single( 1510 urb->transfer_dma = dma_map_single(
1507 hcd->self.controller, 1511 hcd->self.controller,
@@ -2263,9 +2267,7 @@ static void hcd_resume_work(struct work_struct *work)
2263 struct usb_hcd *hcd = container_of(work, struct usb_hcd, wakeup_work); 2267 struct usb_hcd *hcd = container_of(work, struct usb_hcd, wakeup_work);
2264 struct usb_device *udev = hcd->self.root_hub; 2268 struct usb_device *udev = hcd->self.root_hub;
2265 2269
2266 usb_lock_device(udev);
2267 usb_remote_wakeup(udev); 2270 usb_remote_wakeup(udev);
2268 usb_unlock_device(udev);
2269} 2271}
2270 2272
2271/** 2273/**
@@ -2454,11 +2456,13 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
2454 mutex_init(hcd->bandwidth_mutex); 2456 mutex_init(hcd->bandwidth_mutex);
2455 dev_set_drvdata(dev, hcd); 2457 dev_set_drvdata(dev, hcd);
2456 } else { 2458 } else {
2459 mutex_lock(&usb_port_peer_mutex);
2457 hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex; 2460 hcd->bandwidth_mutex = primary_hcd->bandwidth_mutex;
2458 hcd->primary_hcd = primary_hcd; 2461 hcd->primary_hcd = primary_hcd;
2459 primary_hcd->primary_hcd = primary_hcd; 2462 primary_hcd->primary_hcd = primary_hcd;
2460 hcd->shared_hcd = primary_hcd; 2463 hcd->shared_hcd = primary_hcd;
2461 primary_hcd->shared_hcd = hcd; 2464 primary_hcd->shared_hcd = hcd;
2465 mutex_unlock(&usb_port_peer_mutex);
2462 } 2466 }
2463 2467
2464 kref_init(&hcd->kref); 2468 kref_init(&hcd->kref);
@@ -2510,18 +2514,25 @@ EXPORT_SYMBOL_GPL(usb_create_hcd);
2510 * deallocated. 2514 * deallocated.
2511 * 2515 *
2512 * Make sure to only deallocate the bandwidth_mutex when the primary HCD is 2516 * Make sure to only deallocate the bandwidth_mutex when the primary HCD is
2513 * freed. When hcd_release() is called for the non-primary HCD, set the 2517 * freed. When hcd_release() is called for either hcd in a peer set
2514 * primary_hcd's shared_hcd pointer to null (since the non-primary HCD will be 2518 * invalidate the peer's ->shared_hcd and ->primary_hcd pointers to
2515 * freed shortly). 2519 * block new peering attempts
2516 */ 2520 */
2517static void hcd_release (struct kref *kref) 2521static void hcd_release(struct kref *kref)
2518{ 2522{
2519 struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref); 2523 struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
2520 2524
2525 mutex_lock(&usb_port_peer_mutex);
2521 if (usb_hcd_is_primary_hcd(hcd)) 2526 if (usb_hcd_is_primary_hcd(hcd))
2522 kfree(hcd->bandwidth_mutex); 2527 kfree(hcd->bandwidth_mutex);
2523 else 2528 if (hcd->shared_hcd) {
2524 hcd->shared_hcd->shared_hcd = NULL; 2529 struct usb_hcd *peer = hcd->shared_hcd;
2530
2531 peer->shared_hcd = NULL;
2532 if (peer->primary_hcd == hcd)
2533 peer->primary_hcd = NULL;
2534 }
2535 mutex_unlock(&usb_port_peer_mutex);
2525 kfree(hcd); 2536 kfree(hcd);
2526} 2537}
2527 2538
@@ -2589,6 +2600,21 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd,
2589 return 0; 2600 return 0;
2590} 2601}
2591 2602
2603/*
2604 * Before we free this root hub, flush in-flight peering attempts
2605 * and disable peer lookups
2606 */
2607static void usb_put_invalidate_rhdev(struct usb_hcd *hcd)
2608{
2609 struct usb_device *rhdev;
2610
2611 mutex_lock(&usb_port_peer_mutex);
2612 rhdev = hcd->self.root_hub;
2613 hcd->self.root_hub = NULL;
2614 mutex_unlock(&usb_port_peer_mutex);
2615 usb_put_dev(rhdev);
2616}
2617
2592/** 2618/**
2593 * usb_add_hcd - finish generic HCD structure initialization and register 2619 * usb_add_hcd - finish generic HCD structure initialization and register
2594 * @hcd: the usb_hcd structure to initialize 2620 * @hcd: the usb_hcd structure to initialize
@@ -2649,7 +2675,9 @@ int usb_add_hcd(struct usb_hcd *hcd,
2649 retval = -ENOMEM; 2675 retval = -ENOMEM;
2650 goto err_allocate_root_hub; 2676 goto err_allocate_root_hub;
2651 } 2677 }
2678 mutex_lock(&usb_port_peer_mutex);
2652 hcd->self.root_hub = rhdev; 2679 hcd->self.root_hub = rhdev;
2680 mutex_unlock(&usb_port_peer_mutex);
2653 2681
2654 switch (hcd->speed) { 2682 switch (hcd->speed) {
2655 case HCD_USB11: 2683 case HCD_USB11:
@@ -2758,7 +2786,7 @@ err_hcd_driver_start:
2758err_request_irq: 2786err_request_irq:
2759err_hcd_driver_setup: 2787err_hcd_driver_setup:
2760err_set_rh_speed: 2788err_set_rh_speed:
2761 usb_put_dev(hcd->self.root_hub); 2789 usb_put_invalidate_rhdev(hcd);
2762err_allocate_root_hub: 2790err_allocate_root_hub:
2763 usb_deregister_bus(&hcd->self); 2791 usb_deregister_bus(&hcd->self);
2764err_register_bus: 2792err_register_bus:
@@ -2838,7 +2866,6 @@ void usb_remove_hcd(struct usb_hcd *hcd)
2838 free_irq(hcd->irq, hcd); 2866 free_irq(hcd->irq, hcd);
2839 } 2867 }
2840 2868
2841 usb_put_dev(hcd->self.root_hub);
2842 usb_deregister_bus(&hcd->self); 2869 usb_deregister_bus(&hcd->self);
2843 hcd_buffer_destroy(hcd); 2870 hcd_buffer_destroy(hcd);
2844 if (hcd->remove_phy && hcd->phy) { 2871 if (hcd->remove_phy && hcd->phy) {
@@ -2846,6 +2873,8 @@ void usb_remove_hcd(struct usb_hcd *hcd)
2846 usb_put_phy(hcd->phy); 2873 usb_put_phy(hcd->phy);
2847 hcd->phy = NULL; 2874 hcd->phy = NULL;
2848 } 2875 }
2876
2877 usb_put_invalidate_rhdev(hcd);
2849} 2878}
2850EXPORT_SYMBOL_GPL(usb_remove_hcd); 2879EXPORT_SYMBOL_GPL(usb_remove_hcd);
2851 2880