summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2014-05-28 23:51:13 +0300
committerBen Hutchings <ben@decadent.org.uk>2014-07-11 13:33:44 +0100
commit28170033c7ccff7c8ebcf1e648e26f1801e8f198 (patch)
tree0ee582190177f3efd8fab620f410ccd09f97066d
parentd70ca1085a097b191679d6c146b0887d2f5ca3c4 (diff)
downloadlwn-28170033c7ccff7c8ebcf1e648e26f1801e8f198.tar.gz
lwn-28170033c7ccff7c8ebcf1e648e26f1801e8f198.zip
xhci: delete endpoints from bandwidth list before freeing whole device
commit 5dc2808c4729bf080487e61b80ee04e0fdb12a37 upstream. Lists of endpoints are stored for bandwidth calculation for roothub ports. Make sure we remove all endpoints from the list before the whole device, containing its endpoints list_head stuctures, is freed. This used to be done in the wrong order in xhci_mem_cleanup(), and triggered an oops in resume from S4 (hibernate). Tested-by: Ville Syrjälä <ville.syrjala@linux.intel.com> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r--drivers/usb/host/xhci-mem.c20
1 files changed, 10 insertions, 10 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index ec735410e715..74922b9808d8 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1722,6 +1722,16 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
kfree(cur_cd);
}
+ num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
+ for (i = 0; i < num_ports; i++) {
+ struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table;
+ for (j = 0; j < XHCI_MAX_INTERVAL; j++) {
+ struct list_head *ep = &bwt->interval_bw[j].endpoints;
+ while (!list_empty(ep))
+ list_del_init(ep->next);
+ }
+ }
+
for (i = 1; i < MAX_HC_SLOTS; ++i)
xhci_free_virt_device(xhci, i);
@@ -1762,16 +1772,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
if (!xhci->rh_bw)
goto no_bw;
- num_ports = HCS_MAX_PORTS(xhci->hcs_params1);
- for (i = 0; i < num_ports; i++) {
- struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table;
- for (j = 0; j < XHCI_MAX_INTERVAL; j++) {
- struct list_head *ep = &bwt->interval_bw[j].endpoints;
- while (!list_empty(ep))
- list_del_init(ep->next);
- }
- }
-
for (i = 0; i < num_ports; i++) {
struct xhci_tt_bw_info *tt, *n;
list_for_each_entry_safe(tt, n, &xhci->rh_bw[i].tts, tt_list) {