| From f013f2facbbfaac10b5b792a3c28df009aa8388b Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 30 Jan 2020 19:10:36 -0800 |
| Subject: usb: gadget: composite: Support more than 500mA MaxPower |
| |
| From: Jack Pham <jackp@codeaurora.org> |
| |
| [ Upstream commit a2035411fa1d1206cea7d5dfe833e78481844a76 ] |
| |
| USB 3.x SuperSpeed peripherals can draw up to 900mA of VBUS power |
| when in configured state. However, if a configuration wanting to |
| take advantage of this is added with MaxPower greater than 500 |
| (currently possible if using a ConfigFS gadget) the composite |
| driver fails to accommodate this for a couple reasons: |
| |
| - usb_gadget_vbus_draw() when called from set_config() and |
| composite_resume() will be passed the MaxPower value without |
| regard for the current connection speed, resulting in a |
| violation for USB 2.0 since the max is 500mA. |
| |
| - the bMaxPower of the configuration descriptor would be |
| incorrectly encoded, again if the connection speed is only |
| at USB 2.0 or below, likely wrapping around U8_MAX since |
| the 2mA multiplier corresponds to a maximum of 510mA. |
| |
| Fix these by adding checks against the current gadget->speed |
| when the c->MaxPower value is used (set_config() and |
| composite_resume()) and appropriately limit based on whether |
| it is currently at a low-/full-/high- or super-speed connection. |
| |
| Because 900 is not divisible by 8, with the round-up division |
| currently used in encode_bMaxPower() a MaxPower of 900mA will |
| result in an encoded value of 0x71. When a host stack (including |
| Linux and Windows) enumerates this on a single port root hub, it |
| reads this value back and decodes (multiplies by 8) to get 904mA |
| which is strictly greater than 900mA that is typically budgeted |
| for that port, causing it to reject the configuration. Instead, |
| we should be using the round-down behavior of normal integral |
| division so that 900 / 8 -> 0x70 or 896mA to stay within range. |
| And we might as well change it for the high/full/low case as well |
| for consistency. |
| |
| N.B. USB 3.2 Gen N x 2 allows for up to 1500mA but there doesn't |
| seem to be any any peripheral controller supported by Linux that |
| does two lane operation, so for now keeping the clamp at 900 |
| should be fine. |
| |
| Signed-off-by: Jack Pham <jackp@codeaurora.org> |
| Signed-off-by: Felipe Balbi <balbi@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/usb/gadget/composite.c | 24 ++++++++++++++++++------ |
| 1 file changed, 18 insertions(+), 6 deletions(-) |
| |
| diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c |
| index cd303a3ea6802..223f72d4d9edd 100644 |
| --- a/drivers/usb/gadget/composite.c |
| +++ b/drivers/usb/gadget/composite.c |
| @@ -438,9 +438,13 @@ static u8 encode_bMaxPower(enum usb_device_speed speed, |
| if (!val) |
| return 0; |
| if (speed < USB_SPEED_SUPER) |
| - return DIV_ROUND_UP(val, 2); |
| + return min(val, 500U) / 2; |
| else |
| - return DIV_ROUND_UP(val, 8); |
| + /* |
| + * USB 3.x supports up to 900mA, but since 900 isn't divisible |
| + * by 8 the integral division will effectively cap to 896mA. |
| + */ |
| + return min(val, 900U) / 8; |
| } |
| |
| static int config_buf(struct usb_configuration *config, |
| @@ -852,6 +856,10 @@ static int set_config(struct usb_composite_dev *cdev, |
| |
| /* when we return, be sure our power usage is valid */ |
| power = c->MaxPower ? c->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW; |
| + if (gadget->speed < USB_SPEED_SUPER) |
| + power = min(power, 500U); |
| + else |
| + power = min(power, 900U); |
| done: |
| usb_gadget_vbus_draw(gadget, power); |
| if (result >= 0 && cdev->delayed_status) |
| @@ -2278,7 +2286,7 @@ void composite_resume(struct usb_gadget *gadget) |
| { |
| struct usb_composite_dev *cdev = get_gadget_data(gadget); |
| struct usb_function *f; |
| - u16 maxpower; |
| + unsigned maxpower; |
| |
| /* REVISIT: should we have config level |
| * suspend/resume callbacks? |
| @@ -2292,10 +2300,14 @@ void composite_resume(struct usb_gadget *gadget) |
| f->resume(f); |
| } |
| |
| - maxpower = cdev->config->MaxPower; |
| + maxpower = cdev->config->MaxPower ? |
| + cdev->config->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW; |
| + if (gadget->speed < USB_SPEED_SUPER) |
| + maxpower = min(maxpower, 500U); |
| + else |
| + maxpower = min(maxpower, 900U); |
| |
| - usb_gadget_vbus_draw(gadget, maxpower ? |
| - maxpower : CONFIG_USB_GADGET_VBUS_DRAW); |
| + usb_gadget_vbus_draw(gadget, maxpower); |
| } |
| |
| cdev->suspended = 0; |
| -- |
| 2.20.1 |
| |