aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/port.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/port.c')
-rw-r--r--drivers/usb/core/port.c89
1 files changed, 65 insertions, 24 deletions
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 62036faf56c0..fe1b6d0967e3 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -21,6 +21,8 @@
21 21
22#include "hub.h" 22#include "hub.h"
23 23
24static int usb_port_block_power_off;
25
24static const struct attribute_group *port_dev_group[]; 26static const struct attribute_group *port_dev_group[];
25 27
26static ssize_t connect_type_show(struct device *dev, 28static ssize_t connect_type_show(struct device *dev,
@@ -66,6 +68,7 @@ static void usb_port_device_release(struct device *dev)
66{ 68{
67 struct usb_port *port_dev = to_usb_port(dev); 69 struct usb_port *port_dev = to_usb_port(dev);
68 70
71 kfree(port_dev->req);
69 kfree(port_dev); 72 kfree(port_dev);
70} 73}
71 74
@@ -142,6 +145,9 @@ static int usb_port_runtime_suspend(struct device *dev)
142 == PM_QOS_FLAGS_ALL) 145 == PM_QOS_FLAGS_ALL)
143 return -EAGAIN; 146 return -EAGAIN;
144 147
148 if (usb_port_block_power_off)
149 return -EBUSY;
150
145 usb_autopm_get_interface(intf); 151 usb_autopm_get_interface(intf);
146 retval = usb_hub_set_port_power(hdev, hub, port1, false); 152 retval = usb_hub_set_port_power(hdev, hub, port1, false);
147 usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION); 153 usb_clear_port_feature(hdev, port1, USB_PORT_FEAT_C_CONNECTION);
@@ -190,11 +196,19 @@ static int link_peers(struct usb_port *left, struct usb_port *right)
190 if (left->peer || right->peer) { 196 if (left->peer || right->peer) {
191 struct usb_port *lpeer = left->peer; 197 struct usb_port *lpeer = left->peer;
192 struct usb_port *rpeer = right->peer; 198 struct usb_port *rpeer = right->peer;
193 199 char *method;
194 WARN(1, "failed to peer %s and %s (%s -> %p) (%s -> %p)\n", 200
195 dev_name(&left->dev), dev_name(&right->dev), 201 if (left->location && left->location == right->location)
196 dev_name(&left->dev), lpeer, 202 method = "location";
197 dev_name(&right->dev), rpeer); 203 else
204 method = "default";
205
206 pr_warn("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n",
207 dev_name(&left->dev), dev_name(&right->dev), method,
208 dev_name(&left->dev),
209 lpeer ? dev_name(&lpeer->dev) : "none",
210 dev_name(&right->dev),
211 rpeer ? dev_name(&rpeer->dev) : "none");
198 return -EBUSY; 212 return -EBUSY;
199 } 213 }
200 214
@@ -251,6 +265,7 @@ static void link_peers_report(struct usb_port *left, struct usb_port *right)
251 dev_warn(&left->dev, "failed to peer to %s (%d)\n", 265 dev_warn(&left->dev, "failed to peer to %s (%d)\n",
252 dev_name(&right->dev), rc); 266 dev_name(&right->dev), rc);
253 pr_warn_once("usb: port power management may be unreliable\n"); 267 pr_warn_once("usb: port power management may be unreliable\n");
268 usb_port_block_power_off = 1;
254 } 269 }
255} 270}
256 271
@@ -386,9 +401,13 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
386 int retval; 401 int retval;
387 402
388 port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL); 403 port_dev = kzalloc(sizeof(*port_dev), GFP_KERNEL);
389 if (!port_dev) { 404 if (!port_dev)
390 retval = -ENOMEM; 405 return -ENOMEM;
391 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;
392 } 411 }
393 412
394 hub->ports[port1 - 1] = port_dev; 413 hub->ports[port1 - 1] = port_dev;
@@ -404,31 +423,53 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1)
404 port1); 423 port1);
405 mutex_init(&port_dev->status_lock); 424 mutex_init(&port_dev->status_lock);
406 retval = device_register(&port_dev->dev); 425 retval = device_register(&port_dev->dev);
407 if (retval) 426 if (retval) {
408 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 }
409 438
410 find_and_link_peer(hub, port1); 439 find_and_link_peer(hub, port1);
411 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 */
412 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);
413 450
414 /* 451 /*
415 * Do not enable port runtime pm if the hub does not support 452 * Keep hidden the ability to enable port-poweroff if the hub
416 * power switching. Also, userspace must have final say of 453 * does not support power switching.
417 * whether a port is permitted to power-off. Do not enable
418 * runtime pm if we fail to expose pm_qos_no_power_off.
419 */ 454 */
420 if (hub_is_port_power_switchable(hub) 455 if (!hub_is_port_power_switchable(hub))
421 && dev_pm_qos_expose_flags(&port_dev->dev, 456 return 0;
422 PM_QOS_FLAG_NO_POWER_OFF) == 0)
423 pm_runtime_enable(&port_dev->dev);
424 457
425 device_enable_async_suspend(&port_dev->dev); 458 /* Attempt to let userspace take over the policy. */
426 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 }
427 465
428error_register: 466 /* Userspace owns the policy, drop the kernel 'no_poweroff' request. */
429 put_device(&port_dev->dev); 467 retval = dev_pm_qos_remove_request(port_dev->req);
430exit: 468 if (retval >= 0) {
431 return retval; 469 kfree(port_dev->req);
470 port_dev->req = NULL;
471 }
472 return 0;
432} 473}
433 474
434void usb_hub_remove_port_device(struct usb_hub *hub, int port1) 475void usb_hub_remove_port_device(struct usb_hub *hub, int port1)