aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>2012-12-18 09:25:47 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-01-11 19:16:01 -0500
commit430ee58e03f1ed9c2a2b697e2f2e0bb870ce1a23 (patch)
tree637c43936871b10ab69ff15b1748c6ecd47bfcd1
parent8d8479db3dde3ef7a9bc803e565842764fa21a53 (diff)
usb/core: update power budget for SuperSpeed
Sarah pointed out that the USB3.0 spec also updates the amount of power that may be consumed by the device and quoted 9.2.5.1: |"The amount of current draw for SuperSpeed devices are increased to 150 |mA for low-power devices and 900 mA for high-power" This patch tries to update all users to use the larger values for SuperSpeed devices and use the "old" ones for everything else. While here, two other changes suggested by Alan: - the comment referering to 7.2.1.1 has been updated to 7.2.1 which is the correct source of the action. - the check for hubs with zero ports has been removed. - compute bus power by full_load * num_ports on root hubs Acked-by: Alan Stern <stern@rowland.harvard.edu> Acked-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/core/hcd.c1
-rw-r--r--drivers/usb/core/hub.c57
2 files changed, 41 insertions, 17 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 4225d5e72131..5f6da8b2d6a1 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2506,7 +2506,6 @@ int usb_add_hcd(struct usb_hcd *hcd,
2506 } 2506 }
2507 2507
2508 /* starting here, usbcore will pay attention to this root hub */ 2508 /* starting here, usbcore will pay attention to this root hub */
2509 rhdev->bus_mA = min(500u, hcd->power_budget);
2510 if ((retval = register_root_hub(hcd)) != 0) 2509 if ((retval = register_root_hub(hcd)) != 0)
2511 goto err_register_root_hub; 2510 goto err_register_root_hub;
2512 2511
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 12913306840a..0ef512aa2898 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1351,6 +1351,8 @@ static int hub_configure(struct usb_hub *hub,
1351 unsigned int pipe; 1351 unsigned int pipe;
1352 int maxp, ret, i; 1352 int maxp, ret, i;
1353 char *message = "out of memory"; 1353 char *message = "out of memory";
1354 unsigned unit_load;
1355 unsigned full_load;
1354 1356
1355 hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL); 1357 hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
1356 if (!hub->buffer) { 1358 if (!hub->buffer) {
@@ -1397,6 +1399,13 @@ static int hub_configure(struct usb_hub *hub,
1397 } 1399 }
1398 1400
1399 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics); 1401 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
1402 if (hub_is_superspeed(hdev)) {
1403 unit_load = 150;
1404 full_load = 900;
1405 } else {
1406 unit_load = 100;
1407 full_load = 500;
1408 }
1400 1409
1401 /* FIXME for USB 3.0, skip for now */ 1410 /* FIXME for USB 3.0, skip for now */
1402 if ((wHubCharacteristics & HUB_CHAR_COMPOUND) && 1411 if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
@@ -1516,40 +1525,44 @@ static int hub_configure(struct usb_hub *hub,
1516 goto fail; 1525 goto fail;
1517 } 1526 }
1518 le16_to_cpus(&hubstatus); 1527 le16_to_cpus(&hubstatus);
1528 hcd = bus_to_hcd(hdev->bus);
1519 if (hdev == hdev->bus->root_hub) { 1529 if (hdev == hdev->bus->root_hub) {
1520 if (hdev->bus_mA == 0 || hdev->bus_mA >= 500) 1530 if (hcd->power_budget > 0)
1521 hub->mA_per_port = 500; 1531 hdev->bus_mA = hcd->power_budget;
1532 else
1533 hdev->bus_mA = full_load * hdev->maxchild;
1534 if (hdev->bus_mA >= full_load)
1535 hub->mA_per_port = full_load;
1522 else { 1536 else {
1523 hub->mA_per_port = hdev->bus_mA; 1537 hub->mA_per_port = hdev->bus_mA;
1524 hub->limited_power = 1; 1538 hub->limited_power = 1;
1525 } 1539 }
1526 } else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) { 1540 } else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
1541 int remaining = hdev->bus_mA -
1542 hub->descriptor->bHubContrCurrent;
1543
1527 dev_dbg(hub_dev, "hub controller current requirement: %dmA\n", 1544 dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
1528 hub->descriptor->bHubContrCurrent); 1545 hub->descriptor->bHubContrCurrent);
1529 hub->limited_power = 1; 1546 hub->limited_power = 1;
1530 if (hdev->maxchild > 0) {
1531 int remaining = hdev->bus_mA -
1532 hub->descriptor->bHubContrCurrent;
1533 1547
1534 if (remaining < hdev->maxchild * 100) 1548 if (remaining < hdev->maxchild * unit_load)
1535 dev_warn(hub_dev, 1549 dev_warn(hub_dev,
1536 "insufficient power available " 1550 "insufficient power available "
1537 "to use all downstream ports\n"); 1551 "to use all downstream ports\n");
1538 hub->mA_per_port = 100; /* 7.2.1.1 */ 1552 hub->mA_per_port = unit_load; /* 7.2.1 */
1539 } 1553
1540 } else { /* Self-powered external hub */ 1554 } else { /* Self-powered external hub */
1541 /* FIXME: What about battery-powered external hubs that 1555 /* FIXME: What about battery-powered external hubs that
1542 * provide less current per port? */ 1556 * provide less current per port? */
1543 hub->mA_per_port = 500; 1557 hub->mA_per_port = full_load;
1544 } 1558 }
1545 if (hub->mA_per_port < 500) 1559 if (hub->mA_per_port < full_load)
1546 dev_dbg(hub_dev, "%umA bus power budget for each child\n", 1560 dev_dbg(hub_dev, "%umA bus power budget for each child\n",
1547 hub->mA_per_port); 1561 hub->mA_per_port);
1548 1562
1549 /* Update the HCD's internal representation of this hub before khubd 1563 /* Update the HCD's internal representation of this hub before khubd
1550 * starts getting port status changes for devices under the hub. 1564 * starts getting port status changes for devices under the hub.
1551 */ 1565 */
1552 hcd = bus_to_hcd(hdev->bus);
1553 if (hcd->driver->update_hub_device) { 1566 if (hcd->driver->update_hub_device) {
1554 ret = hcd->driver->update_hub_device(hcd, hdev, 1567 ret = hcd->driver->update_hub_device(hcd, hdev,
1555 &hub->tt, GFP_KERNEL); 1568 &hub->tt, GFP_KERNEL);
@@ -4204,16 +4217,23 @@ hub_power_remaining (struct usb_hub *hub)
4204 for (port1 = 1; port1 <= hdev->maxchild; ++port1) { 4217 for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
4205 struct usb_device *udev = hub->ports[port1 - 1]->child; 4218 struct usb_device *udev = hub->ports[port1 - 1]->child;
4206 int delta; 4219 int delta;
4220 unsigned unit_load;
4207 4221
4208 if (!udev) 4222 if (!udev)
4209 continue; 4223 continue;
4224 if (hub_is_superspeed(udev))
4225 unit_load = 150;
4226 else
4227 unit_load = 100;
4210 4228
4211 /* Unconfigured devices may not use more than 100mA, 4229 /*
4212 * or 8mA for OTG ports */ 4230 * Unconfigured devices may not use more than one unit load,
4231 * or 8mA for OTG ports
4232 */
4213 if (udev->actconfig) 4233 if (udev->actconfig)
4214 delta = usb_get_max_power(udev, udev->actconfig); 4234 delta = usb_get_max_power(udev, udev->actconfig);
4215 else if (port1 != udev->bus->otg_port || hdev->parent) 4235 else if (port1 != udev->bus->otg_port || hdev->parent)
4216 delta = 100; 4236 delta = unit_load;
4217 else 4237 else
4218 delta = 8; 4238 delta = 8;
4219 if (delta > hub->mA_per_port) 4239 if (delta > hub->mA_per_port)
@@ -4248,6 +4268,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
4248 le16_to_cpu(hub->descriptor->wHubCharacteristics); 4268 le16_to_cpu(hub->descriptor->wHubCharacteristics);
4249 struct usb_device *udev; 4269 struct usb_device *udev;
4250 int status, i; 4270 int status, i;
4271 unsigned unit_load;
4251 4272
4252 dev_dbg (hub_dev, 4273 dev_dbg (hub_dev,
4253 "port %d, status %04x, change %04x, %s\n", 4274 "port %d, status %04x, change %04x, %s\n",
@@ -4337,6 +4358,10 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
4337 goto done; 4358 goto done;
4338 return; 4359 return;
4339 } 4360 }
4361 if (hub_is_superspeed(hub->hdev))
4362 unit_load = 150;
4363 else
4364 unit_load = 100;
4340 4365
4341 for (i = 0; i < SET_CONFIG_TRIES; i++) { 4366 for (i = 0; i < SET_CONFIG_TRIES; i++) {
4342 4367
@@ -4384,7 +4409,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
4384 * on the parent. 4409 * on the parent.
4385 */ 4410 */
4386 if (udev->descriptor.bDeviceClass == USB_CLASS_HUB 4411 if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
4387 && udev->bus_mA <= 100) { 4412 && udev->bus_mA <= unit_load) {
4388 u16 devstat; 4413 u16 devstat;
4389 4414
4390 status = usb_get_status(udev, USB_RECIP_DEVICE, 0, 4415 status = usb_get_status(udev, USB_RECIP_DEVICE, 0,