aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-hcd.c
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2009-12-03 12:44:29 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-12-11 14:55:27 -0500
commit74f9fe21e0440066eb337b9f644238cb3050b91c (patch)
treeb4ab839ba1a02cf2e6834ae3013b24e59e1e76c4 /drivers/usb/host/xhci-hcd.c
parent3342ecda3ffb059f2ffd765a71d9579f0aa036eb (diff)
USB: xhci: Make reverting an alt setting "unfailable".
When a driver wants to switch to a different alternate setting for an interface, the USB core will (soon) check whether there is enough bandwidth. Once the new alternate setting is installed in the xHCI hardware, the USB core will send a USB_REQ_SET_INTERFACE control message. That can fail in various ways, and the USB core needs to be able to reinstate the old alternate setting. With the old code, reinstating the old alt setting could fail if the there's not enough memory to allocate new endpoint rings. Keep around a cache of (at most 31) endpoint rings for this case. When we successfully switch the xHCI hardware to the new alt setting, the old alt setting's rings will be stored in the cache. Therefore we'll always have enough rings to satisfy a conversion back to a previous device setting. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/xhci-hcd.c')
-rw-r--r--drivers/usb/host/xhci-hcd.c32
1 files changed, 27 insertions, 5 deletions
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 0d5a8564ed17..5e92c72df642 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -1262,13 +1262,35 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
1262 LAST_CTX_TO_EP_NUM(slot_ctx->dev_info)); 1262 LAST_CTX_TO_EP_NUM(slot_ctx->dev_info));
1263 1263
1264 xhci_zero_in_ctx(xhci, virt_dev); 1264 xhci_zero_in_ctx(xhci, virt_dev);
1265 /* Free any old rings */ 1265 /* Install new rings and free or cache any old rings */
1266 for (i = 1; i < 31; ++i) { 1266 for (i = 1; i < 31; ++i) {
1267 if (virt_dev->eps[i].new_ring) { 1267 int rings_cached;
1268 xhci_ring_free(xhci, virt_dev->eps[i].ring); 1268
1269 virt_dev->eps[i].ring = virt_dev->eps[i].new_ring; 1269 if (!virt_dev->eps[i].new_ring)
1270 virt_dev->eps[i].new_ring = NULL; 1270 continue;
1271 /* Only cache or free the old ring if it exists.
1272 * It may not if this is the first add of an endpoint.
1273 */
1274 if (virt_dev->eps[i].ring) {
1275 rings_cached = virt_dev->num_rings_cached;
1276 if (rings_cached < XHCI_MAX_RINGS_CACHED) {
1277 virt_dev->num_rings_cached++;
1278 rings_cached = virt_dev->num_rings_cached;
1279 virt_dev->ring_cache[rings_cached] =
1280 virt_dev->eps[i].ring;
1281 xhci_dbg(xhci, "Cached old ring, "
1282 "%d ring%s cached\n",
1283 rings_cached,
1284 (rings_cached > 1) ? "s" : "");
1285 } else {
1286 xhci_ring_free(xhci, virt_dev->eps[i].ring);
1287 xhci_dbg(xhci, "Ring cache full (%d rings), "
1288 "freeing ring\n",
1289 virt_dev->num_rings_cached);
1290 }
1271 } 1291 }
1292 virt_dev->eps[i].ring = virt_dev->eps[i].new_ring;
1293 virt_dev->eps[i].new_ring = NULL;
1272 } 1294 }
1273 1295
1274 return ret; 1296 return ret;