Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb/core: consider link speed while looking at bMaxPower

The USB 2.0 specification says that bMaxPower is the maximum power
consumption expressed in 2 mA units and the USB 3.0 specification says
that it is expressed in 8 mA units.
This patch adds a helper function usb_get_max_power() which computes the
value based on config & usb_device's speed value. The the device descriptor
dump computes the value on its own.

Cc: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Sebastian Andrzej Siewior and committed by
Greg Kroah-Hartman
8d8479db ece1d77e

+44 -15
+10 -3
drivers/usb/core/devices.c
··· 316 316 */ 317 317 static char *usb_dump_config_descriptor(char *start, char *end, 318 318 const struct usb_config_descriptor *desc, 319 - int active) 319 + int active, int speed) 320 320 { 321 + int mul; 322 + 321 323 if (start > end) 322 324 return start; 325 + if (speed == USB_SPEED_SUPER) 326 + mul = 8; 327 + else 328 + mul = 2; 323 329 start += sprintf(start, format_config, 324 330 /* mark active/actual/current cfg. */ 325 331 active ? '*' : ' ', 326 332 desc->bNumInterfaces, 327 333 desc->bConfigurationValue, 328 334 desc->bmAttributes, 329 - desc->bMaxPower * 2); 335 + desc->bMaxPower * mul); 330 336 return start; 331 337 } 332 338 ··· 348 342 if (!config) 349 343 /* getting these some in 2.3.7; none in 2.3.6 */ 350 344 return start + sprintf(start, "(null Cfg. desc.)\n"); 351 - start = usb_dump_config_descriptor(start, end, &config->desc, active); 345 + start = usb_dump_config_descriptor(start, end, &config->desc, active, 346 + speed); 352 347 for (i = 0; i < USB_MAXIADS; i++) { 353 348 if (config->intf_assoc[i] == NULL) 354 349 break;
+1 -1
drivers/usb/core/generic.c
··· 100 100 */ 101 101 102 102 /* Rule out configs that draw too much bus current */ 103 - if (c->desc.bMaxPower * 2 > udev->bus_mA) { 103 + if (usb_get_max_power(udev, c) > udev->bus_mA) { 104 104 insufficient_power++; 105 105 continue; 106 106 }
+1 -1
drivers/usb/core/hub.c
··· 4211 4211 /* Unconfigured devices may not use more than 100mA, 4212 4212 * or 8mA for OTG ports */ 4213 4213 if (udev->actconfig) 4214 - delta = udev->actconfig->desc.bMaxPower * 2; 4214 + delta = usb_get_max_power(udev, udev->actconfig); 4215 4215 else if (port1 != udev->bus->otg_port || hdev->parent) 4216 4216 delta = 100; 4217 4217 else
+1 -1
drivers/usb/core/message.c
··· 1751 1751 } 1752 1752 } 1753 1753 1754 - i = dev->bus_mA - cp->desc.bMaxPower * 2; 1754 + i = dev->bus_mA - usb_get_max_power(dev, cp); 1755 1755 if (i < 0) 1756 1756 dev_warn(&dev->dev, "new config #%d exceeds power " 1757 1757 "limit by %dmA\n",
+22 -9
drivers/usb/core/sysfs.c
··· 17 17 #include "usb.h" 18 18 19 19 /* Active configuration fields */ 20 - #define usb_actconfig_show(field, multiplier, format_string) \ 20 + #define usb_actconfig_show(field, format_string) \ 21 21 static ssize_t show_##field(struct device *dev, \ 22 22 struct device_attribute *attr, char *buf) \ 23 23 { \ ··· 28 28 actconfig = udev->actconfig; \ 29 29 if (actconfig) \ 30 30 return sprintf(buf, format_string, \ 31 - actconfig->desc.field * multiplier); \ 31 + actconfig->desc.field); \ 32 32 else \ 33 33 return 0; \ 34 34 } \ 35 35 36 - #define usb_actconfig_attr(field, multiplier, format_string) \ 37 - usb_actconfig_show(field, multiplier, format_string) \ 38 - static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); 36 + #define usb_actconfig_attr(field, format_string) \ 37 + usb_actconfig_show(field, format_string) \ 38 + static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL); 39 39 40 - usb_actconfig_attr(bNumInterfaces, 1, "%2d\n") 41 - usb_actconfig_attr(bmAttributes, 1, "%2x\n") 42 - usb_actconfig_attr(bMaxPower, 2, "%3dmA\n") 40 + usb_actconfig_attr(bNumInterfaces, "%2d\n") 41 + usb_actconfig_attr(bmAttributes, "%2x\n") 42 + 43 + static ssize_t show_bMaxPower(struct device *dev, 44 + struct device_attribute *attr, char *buf) 45 + { 46 + struct usb_device *udev; 47 + struct usb_host_config *actconfig; 48 + 49 + udev = to_usb_device(dev); 50 + actconfig = udev->actconfig; 51 + if (!actconfig) 52 + return 0; 53 + return sprintf(buf, "%dmA\n", usb_get_max_power(udev, actconfig)); 54 + } 55 + static DEVICE_ATTR(bMaxPower, S_IRUGO, show_bMaxPower, NULL); 43 56 44 57 static ssize_t show_configuration_string(struct device *dev, 45 58 struct device_attribute *attr, char *buf) ··· 69 56 static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL); 70 57 71 58 /* configuration value is always present, and r/w */ 72 - usb_actconfig_show(bConfigurationValue, 1, "%u\n"); 59 + usb_actconfig_show(bConfigurationValue, "%u\n"); 73 60 74 61 static ssize_t 75 62 set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
+9
drivers/usb/core/usb.h
··· 38 38 extern int usb_set_configuration(struct usb_device *dev, int configuration); 39 39 extern int usb_choose_configuration(struct usb_device *udev); 40 40 41 + static inline unsigned usb_get_max_power(struct usb_device *udev, 42 + struct usb_host_config *c) 43 + { 44 + /* SuperSpeed power is in 8 mA units; others are in 2 mA units */ 45 + unsigned mul = (udev->speed == USB_SPEED_SUPER ? 8 : 2); 46 + 47 + return c->desc.bMaxPower * mul; 48 + } 49 + 41 50 extern void usb_kick_khubd(struct usb_device *dev); 42 51 extern int usb_match_one_id_intf(struct usb_device *dev, 43 52 struct usb_host_interface *intf,