Skip to content

Commit 6aaff44

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 62c156b commit 6aaff44

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
@@ -1964,6 +1964,16 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev,
19641964
return ret;
19651965
}
19661966

1967+
void usb_hcd_fixup_endpoint(struct usb_device *udev,
1968+
struct usb_host_endpoint *ep, int interval)
1969+
{
1970+
struct usb_hcd *hcd;
1971+
1972+
hcd = bus_to_hcd(udev->bus);
1973+
if (hcd->driver->fixup_endpoint)
1974+
hcd->driver->fixup_endpoint(hcd, udev, ep, interval);
1975+
}
1976+
19671977
/* Disables the endpoint: synchronizes with the hcd to make sure all
19681978
* endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
19691979
* 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
@@ -1890,6 +1890,8 @@ extern int usb_clear_halt(struct usb_device *dev, int pipe);
18901890
extern int usb_reset_configuration(struct usb_device *dev);
18911891
extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
18921892
extern void usb_reset_endpoint(struct usb_device *dev, unsigned int epaddr);
1893+
extern void usb_fixup_endpoint(struct usb_device *dev, int epaddr,
1894+
int interval);
18931895

18941896
/* this request isn't really synchronous, but it belongs with the others */
18951897
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)