Skip to content

Commit 868b460

Browse files
Jonathan Bellpopcornmix
authored andcommitted
usb: add plumbing for updating interrupt endpoint interval state
xHCI caches device and endpoint data after the interface is configured, so an explicit command needs to be issued for any device driver wanting to alter the polling interval of an endpoint. Add usb_fixup_endpoint() to allow drivers to do this. The fixup must be called after calculating endpoint bandwidth requirements but before any URBs are submitted. If polling intervals are shortened, any bandwidth reservations are no longer valid but in practice polling intervals are only ever relaxed. Limit the scope to interrupt transfers for now. Signed-off-by: Jonathan Bell <[email protected]>
1 parent 24f127f commit 868b460

File tree

4 files changed

+34
-0
lines changed

4 files changed

+34
-0
lines changed

drivers/usb/core/hcd.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1953,6 +1953,16 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev,
19531953
return ret;
19541954
}
19551955

1956+
void usb_hcd_fixup_endpoint(struct usb_device *udev,
1957+
struct usb_host_endpoint *ep, int interval)
1958+
{
1959+
struct usb_hcd *hcd;
1960+
1961+
hcd = bus_to_hcd(udev->bus);
1962+
if (hcd->driver->fixup_endpoint)
1963+
hcd->driver->fixup_endpoint(hcd, udev, ep, interval);
1964+
}
1965+
19561966
/* Disables the endpoint: synchronizes with the hcd to make sure all
19571967
* endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
19581968
* have been called previously. Use for set_configuration, set_interface,

drivers/usb/core/message.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,21 @@ static void remove_intf_ep_devs(struct usb_interface *intf)
12671267
intf->ep_devs_created = 0;
12681268
}
12691269

1270+
void usb_fixup_endpoint(struct usb_device *dev, int epaddr, int interval)
1271+
{
1272+
unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
1273+
struct usb_host_endpoint *ep;
1274+
1275+
if (usb_endpoint_out(epaddr))
1276+
ep = dev->ep_out[epnum];
1277+
else
1278+
ep = dev->ep_in[epnum];
1279+
1280+
if (ep && usb_endpoint_xfer_int(&ep->desc))
1281+
usb_hcd_fixup_endpoint(dev, ep, interval);
1282+
}
1283+
EXPORT_SYMBOL_GPL(usb_fixup_endpoint);
1284+
12701285
/**
12711286
* usb_disable_endpoint -- Disable an endpoint by address
12721287
* @dev: the device whose endpoint is being disabled

include/linux/usb.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1872,6 +1872,8 @@ extern int usb_clear_halt(struct usb_device *dev, int pipe);
18721872
extern int usb_reset_configuration(struct usb_device *dev);
18731873
extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
18741874
extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr);
1875+
extern void usb_fixup_endpoint(struct usb_device *dev, int epaddr,
1876+
int interval);
18751877

18761878
/* this request isn't really synchronous, but it belongs with the others */
18771879
extern int usb_driver_set_configuration(struct usb_device *udev, int config);

include/linux/usb/hcd.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,11 @@ struct hc_driver {
372372
* or bandwidth constraints.
373373
*/
374374
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
375+
/* Override the endpoint-derived interval
376+
* (if there is any cached hardware state).
377+
*/
378+
void (*fixup_endpoint)(struct usb_hcd *hcd, struct usb_device *udev,
379+
struct usb_host_endpoint *ep, int interval);
375380
/* Set the hardware-chosen device address */
376381
int (*address_device)(struct usb_hcd *, struct usb_device *udev,
377382
unsigned int timeout_ms);
@@ -437,6 +442,8 @@ extern void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *, struct urb *);
437442
extern void usb_hcd_unmap_urb_for_dma(struct usb_hcd *, struct urb *);
438443
extern void usb_hcd_flush_endpoint(struct usb_device *udev,
439444
struct usb_host_endpoint *ep);
445+
extern void usb_hcd_fixup_endpoint(struct usb_device *udev,
446+
struct usb_host_endpoint *ep, int interval);
440447
extern void usb_hcd_disable_endpoint(struct usb_device *udev,
441448
struct usb_host_endpoint *ep);
442449
extern void usb_hcd_reset_endpoint(struct usb_device *udev,

0 commit comments

Comments
 (0)