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>
This commit is contained in:
Родитель
8d8479db3d
Коммит
430ee58e03
|
@ -2506,7 +2506,6 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* starting here, usbcore will pay attention to this root hub */
|
/* starting here, usbcore will pay attention to this root hub */
|
||||||
rhdev->bus_mA = min(500u, hcd->power_budget);
|
|
||||||
if ((retval = register_root_hub(hcd)) != 0)
|
if ((retval = register_root_hub(hcd)) != 0)
|
||||||
goto err_register_root_hub;
|
goto err_register_root_hub;
|
||||||
|
|
||||||
|
|
|
@ -1351,6 +1351,8 @@ static int hub_configure(struct usb_hub *hub,
|
||||||
unsigned int pipe;
|
unsigned int pipe;
|
||||||
int maxp, ret, i;
|
int maxp, ret, i;
|
||||||
char *message = "out of memory";
|
char *message = "out of memory";
|
||||||
|
unsigned unit_load;
|
||||||
|
unsigned full_load;
|
||||||
|
|
||||||
hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
|
hub->buffer = kmalloc(sizeof(*hub->buffer), GFP_KERNEL);
|
||||||
if (!hub->buffer) {
|
if (!hub->buffer) {
|
||||||
|
@ -1397,6 +1399,13 @@ static int hub_configure(struct usb_hub *hub,
|
||||||
}
|
}
|
||||||
|
|
||||||
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
|
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
|
||||||
|
if (hub_is_superspeed(hdev)) {
|
||||||
|
unit_load = 150;
|
||||||
|
full_load = 900;
|
||||||
|
} else {
|
||||||
|
unit_load = 100;
|
||||||
|
full_load = 500;
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME for USB 3.0, skip for now */
|
/* FIXME for USB 3.0, skip for now */
|
||||||
if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
|
if ((wHubCharacteristics & HUB_CHAR_COMPOUND) &&
|
||||||
|
@ -1516,40 +1525,44 @@ static int hub_configure(struct usb_hub *hub,
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
le16_to_cpus(&hubstatus);
|
le16_to_cpus(&hubstatus);
|
||||||
|
hcd = bus_to_hcd(hdev->bus);
|
||||||
if (hdev == hdev->bus->root_hub) {
|
if (hdev == hdev->bus->root_hub) {
|
||||||
if (hdev->bus_mA == 0 || hdev->bus_mA >= 500)
|
if (hcd->power_budget > 0)
|
||||||
hub->mA_per_port = 500;
|
hdev->bus_mA = hcd->power_budget;
|
||||||
|
else
|
||||||
|
hdev->bus_mA = full_load * hdev->maxchild;
|
||||||
|
if (hdev->bus_mA >= full_load)
|
||||||
|
hub->mA_per_port = full_load;
|
||||||
else {
|
else {
|
||||||
hub->mA_per_port = hdev->bus_mA;
|
hub->mA_per_port = hdev->bus_mA;
|
||||||
hub->limited_power = 1;
|
hub->limited_power = 1;
|
||||||
}
|
}
|
||||||
} else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
|
} else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
|
||||||
|
int remaining = hdev->bus_mA -
|
||||||
|
hub->descriptor->bHubContrCurrent;
|
||||||
|
|
||||||
dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
|
dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
|
||||||
hub->descriptor->bHubContrCurrent);
|
hub->descriptor->bHubContrCurrent);
|
||||||
hub->limited_power = 1;
|
hub->limited_power = 1;
|
||||||
if (hdev->maxchild > 0) {
|
|
||||||
int remaining = hdev->bus_mA -
|
|
||||||
hub->descriptor->bHubContrCurrent;
|
|
||||||
|
|
||||||
if (remaining < hdev->maxchild * 100)
|
if (remaining < hdev->maxchild * unit_load)
|
||||||
dev_warn(hub_dev,
|
dev_warn(hub_dev,
|
||||||
"insufficient power available "
|
"insufficient power available "
|
||||||
"to use all downstream ports\n");
|
"to use all downstream ports\n");
|
||||||
hub->mA_per_port = 100; /* 7.2.1.1 */
|
hub->mA_per_port = unit_load; /* 7.2.1 */
|
||||||
}
|
|
||||||
} else { /* Self-powered external hub */
|
} else { /* Self-powered external hub */
|
||||||
/* FIXME: What about battery-powered external hubs that
|
/* FIXME: What about battery-powered external hubs that
|
||||||
* provide less current per port? */
|
* provide less current per port? */
|
||||||
hub->mA_per_port = 500;
|
hub->mA_per_port = full_load;
|
||||||
}
|
}
|
||||||
if (hub->mA_per_port < 500)
|
if (hub->mA_per_port < full_load)
|
||||||
dev_dbg(hub_dev, "%umA bus power budget for each child\n",
|
dev_dbg(hub_dev, "%umA bus power budget for each child\n",
|
||||||
hub->mA_per_port);
|
hub->mA_per_port);
|
||||||
|
|
||||||
/* Update the HCD's internal representation of this hub before khubd
|
/* Update the HCD's internal representation of this hub before khubd
|
||||||
* starts getting port status changes for devices under the hub.
|
* starts getting port status changes for devices under the hub.
|
||||||
*/
|
*/
|
||||||
hcd = bus_to_hcd(hdev->bus);
|
|
||||||
if (hcd->driver->update_hub_device) {
|
if (hcd->driver->update_hub_device) {
|
||||||
ret = hcd->driver->update_hub_device(hcd, hdev,
|
ret = hcd->driver->update_hub_device(hcd, hdev,
|
||||||
&hub->tt, GFP_KERNEL);
|
&hub->tt, GFP_KERNEL);
|
||||||
|
@ -4204,16 +4217,23 @@ hub_power_remaining (struct usb_hub *hub)
|
||||||
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
|
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
|
||||||
struct usb_device *udev = hub->ports[port1 - 1]->child;
|
struct usb_device *udev = hub->ports[port1 - 1]->child;
|
||||||
int delta;
|
int delta;
|
||||||
|
unsigned unit_load;
|
||||||
|
|
||||||
if (!udev)
|
if (!udev)
|
||||||
continue;
|
continue;
|
||||||
|
if (hub_is_superspeed(udev))
|
||||||
|
unit_load = 150;
|
||||||
|
else
|
||||||
|
unit_load = 100;
|
||||||
|
|
||||||
/* Unconfigured devices may not use more than 100mA,
|
/*
|
||||||
* or 8mA for OTG ports */
|
* Unconfigured devices may not use more than one unit load,
|
||||||
|
* or 8mA for OTG ports
|
||||||
|
*/
|
||||||
if (udev->actconfig)
|
if (udev->actconfig)
|
||||||
delta = usb_get_max_power(udev, udev->actconfig);
|
delta = usb_get_max_power(udev, udev->actconfig);
|
||||||
else if (port1 != udev->bus->otg_port || hdev->parent)
|
else if (port1 != udev->bus->otg_port || hdev->parent)
|
||||||
delta = 100;
|
delta = unit_load;
|
||||||
else
|
else
|
||||||
delta = 8;
|
delta = 8;
|
||||||
if (delta > hub->mA_per_port)
|
if (delta > hub->mA_per_port)
|
||||||
|
@ -4248,6 +4268,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||||
le16_to_cpu(hub->descriptor->wHubCharacteristics);
|
le16_to_cpu(hub->descriptor->wHubCharacteristics);
|
||||||
struct usb_device *udev;
|
struct usb_device *udev;
|
||||||
int status, i;
|
int status, i;
|
||||||
|
unsigned unit_load;
|
||||||
|
|
||||||
dev_dbg (hub_dev,
|
dev_dbg (hub_dev,
|
||||||
"port %d, status %04x, change %04x, %s\n",
|
"port %d, status %04x, change %04x, %s\n",
|
||||||
|
@ -4337,6 +4358,10 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||||
goto done;
|
goto done;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (hub_is_superspeed(hub->hdev))
|
||||||
|
unit_load = 150;
|
||||||
|
else
|
||||||
|
unit_load = 100;
|
||||||
|
|
||||||
for (i = 0; i < SET_CONFIG_TRIES; i++) {
|
for (i = 0; i < SET_CONFIG_TRIES; i++) {
|
||||||
|
|
||||||
|
@ -4384,7 +4409,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||||
* on the parent.
|
* on the parent.
|
||||||
*/
|
*/
|
||||||
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
|
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
|
||||||
&& udev->bus_mA <= 100) {
|
&& udev->bus_mA <= unit_load) {
|
||||||
u16 devstat;
|
u16 devstat;
|
||||||
|
|
||||||
status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
|
status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче