aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/hub.c6
-rw-r--r--drivers/usb/core/hub.h2
-rw-r--r--drivers/usb/core/port.c65
3 files changed, 54 insertions, 19 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 78c3cd20d7ae..21b99b4b4082 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1577,6 +1577,12 @@ static int hub_configure(struct usb_hub *hub,
1577 } 1577 }
1578 } 1578 }
1579 hdev->maxchild = i; 1579 hdev->maxchild = i;
1580 for (i = 0; i < hdev->maxchild; i++) {
1581 struct usb_port *port_dev = hub->ports[i];
1582
1583 pm_runtime_put(&port_dev->dev);
1584 }
1585
1580 mutex_unlock(&usb_port_peer_mutex); 1586 mutex_unlock(&usb_port_peer_mutex);
1581 if (ret < 0) 1587 if (ret < 0)
1582 goto fail; 1588 goto fail;
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index 0a7cdc0ef0a9..326308e53961 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -84,6 +84,7 @@ struct usb_hub {
84 * @dev: generic device interface 84 * @dev: generic device interface
85 * @port_owner: port's owner 85 * @port_owner: port's owner
86 * @peer: related usb2 and usb3 ports (share the same connector) 86 * @peer: related usb2 and usb3 ports (share the same connector)
87 * @req: default pm qos request for hubs without port power control
87 * @connect_type: port's connect type 88 * @connect_type: port's connect type
88 * @location: opaque representation of platform connector location 89 * @location: opaque representation of platform connector location
89 * @status_lock: synchronize port_event() vs usb_port_{suspend|resume} 90 * @status_lock: synchronize port_event() vs usb_port_{suspend|resume}
@@ -95,6 +96,7 @@ struct usb_port {
95 struct device dev; 96 struct device dev;
96 struct usb_dev_state *port_owner; 97 struct usb_dev_state *port_owner;
97 struct usb_port *peer; 98 struct usb_port *peer;
99 struct dev_pm_qos_request *req;
98 enum usb_port_connect_type connect_type; 100 enum usb_port_connect_type connect_type;
99 usb_port_location_t location; 101 usb_port_location_t location;
100 struct mutex status_lock; 102 struct mutex status_lock;
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 9347ade7d5fe..fe1b6d0967e3 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -68,6 +68,7 @@ static void usb_port_device_release(struct device *dev)
68{ 68{
69 struct usb_port *port_dev = to_usb_port(dev); 69 struct usb_port *port_dev = to_usb_port(dev);
70 70
71 kfree(port_dev->req);
71 kfree(port_dev); 72 kfree(port_dev);
72} 73}
73 74
@@ -400,9 +401,13 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
400 int retval; 401 int retval;
401 402
402 port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); 403 port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
403 if (!port_dev) { 404 if (!port_dev)
404 retval = -ENOMEM; 405 return -ENOMEM;
405 goto exit; 406
407 port_dev->req = kzalloc(sizeof(*(port_dev->req)), GFP_KERNEL);
408 if (!port_dev->req) {
409 kfree(port_dev);
410 return -ENOMEM;
406 } 411 }
407 412
408 hub->ports[port1 - 1] = port_dev; 413 hub->ports[port1 - 1] = port_dev;
@@ -418,31 +423,53 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
418 port1); 423 port1);
419 mutex_init(&port_dev->status_lock); 424 mutex_init(&port_dev->status_lock);
420 retval = device_register(&port_dev->dev); 425 retval = device_register(&port_dev->dev);
421 if (retval) 426 if (retval) {
422 goto error_register; 427 put_device(&port_dev->dev);
428 return retval;
429 }
430
431 /* Set default policy of port-poweroff disabled. */
432 retval = dev_pm_qos_add_request(&port_dev->dev, port_dev->req,
433 DEV_PM_QOS_FLAGS, PM_QOS_FLAG_NO_POWER_OFF);
434 if (retval < 0) {
435 device_unregister(&port_dev->dev);
436 return retval;
437 }
423 438
424 find_and_link_peer(hub, port1); 439 find_and_link_peer(hub, port1);
425 440
441 /*
442 * Enable runtime pm and hold a refernce that hub_configure()
443 * will drop once the PM_QOS_NO_POWER_OFF flag state has been set
444 * and the hub has been fully registered (hdev->maxchild set).
445 */
426 pm_runtime_set_active(&port_dev->dev); 446 pm_runtime_set_active(&port_dev->dev);
447 pm_runtime_get_noresume(&port_dev->dev);
448 pm_runtime_enable(&port_dev->dev);
449 device_enable_async_suspend(&port_dev->dev);
427 450
428 /* 451 /*
429 * Do not enable port runtime pm if the hub does not support 452 * Keep hidden the ability to enable port-poweroff if the hub
430 * power switching. Also, userspace must have final say of 453 * does not support power switching.
431 * whether a port is permitted to power-off. Do not enable
432 * runtime pm if we fail to expose pm_qos_no_power_off.
433 */ 454 */
434 if (hub_is_port_power_switchable(hub) 455 if (!hub_is_port_power_switchable(hub))
435 && dev_pm_qos_expose_flags(&port_dev->dev, 456 return 0;
436 PM_QOS_FLAG_NO_POWER_OFF) == 0)
437 pm_runtime_enable(&port_dev->dev);
438 457
439 device_enable_async_suspend(&port_dev->dev); 458 /* Attempt to let userspace take over the policy. */
440 return 0; 459 retval = dev_pm_qos_expose_flags(&port_dev->dev,
460 PM_QOS_FLAG_NO_POWER_OFF);
461 if (retval < 0) {
462 dev_warn(&port_dev->dev, "failed to expose pm_qos_no_poweroff\n");
463 return 0;
464 }
441 465
442error_register: 466 /* Userspace owns the policy, drop the kernel 'no_poweroff' request. */
443 put_device(&port_dev->dev); 467 retval = dev_pm_qos_remove_request(port_dev->req);
444exit: 468 if (retval >= 0) {
445 return retval; 469 kfree(port_dev->req);
470 port_dev->req = NULL;
471 }
472 return 0;
446} 473}
447 474
448void usb_hub_remove_port_device(struct usb_hub *hub, int port1) 475void usb_hub_remove_port_device(struct usb_hub *hub, int port1)