+static void xhci_free_tt_info(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ int slot_id)
+{
+ struct list_head *tt;
+ struct list_head *tt_list_head;
+ struct list_head *tt_next;
+ struct xhci_tt_bw_info *tt_info;
+
+ /* If the device never made it past the Set Address stage,
+ * it may not have the real_port set correctly.
+ */
+ if (virt_dev->real_port == 0 ||
+ virt_dev->real_port > HCS_MAX_PORTS(xhci->hcs_params1)) {
+ xhci_dbg(xhci, "Bad real port.\n");
+ return;
+ }
+
+ tt_list_head = &(xhci->rh_bw[virt_dev->real_port - 1].tts);
+ if (list_empty(tt_list_head))
+ return;
+
+ list_for_each(tt, tt_list_head) {
+ tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list);
+ if (tt_info->slot_id == slot_id)
+ break;
+ }
+ /* Cautionary measure in case the hub was disconnected before we
+ * stored the TT information.
+ */
+ if (tt_info->slot_id != slot_id)
+ return;
+
+ tt_next = tt->next;
+ tt_info = list_entry(tt, struct xhci_tt_bw_info,
+ tt_list);
+ /* Multi-TT hubs will have more than one entry */
+ do {
+ list_del(tt);
+ kfree(tt_info);
+ tt = tt_next;
+ if (list_empty(tt_list_head))
+ break;
+ tt_next = tt->next;
+ tt_info = list_entry(tt, struct xhci_tt_bw_info,
+ tt_list);
+ } while (tt_info->slot_id == slot_id);
+}
+
+int xhci_alloc_tt_info(struct xhci_hcd *xhci,
+ struct xhci_virt_device *virt_dev,
+ struct usb_device *hdev,
+ struct usb_tt *tt, gfp_t mem_flags)
+{
+ struct xhci_tt_bw_info *tt_info;
+ unsigned int num_ports;
+ int i, j;
+
+ if (!tt->multi)
+ num_ports = 1;
+ else
+ num_ports = hdev->maxchild;
+
+ for (i = 0; i < num_ports; i++, tt_info++) {
+ struct xhci_interval_bw_table *bw_table;
+
+ tt_info = kzalloc(sizeof(*tt_info), mem_flags);
+ if (!tt_info)
+ goto free_tts;
+ INIT_LIST_HEAD(&tt_info->tt_list);
+ list_add(&tt_info->tt_list,
+ &xhci->rh_bw[virt_dev->real_port - 1].tts);
+ tt_info->slot_id = virt_dev->udev->slot_id;
+ if (tt->multi)
+ tt_info->ttport = i+1;
+ bw_table = &tt_info->bw_table;
+ for (j = 0; j < XHCI_MAX_INTERVAL; j++)
+ INIT_LIST_HEAD(&bw_table->interval_bw[j].endpoints);
+ }
+ return 0;
+
+free_tts:
+ xhci_free_tt_info(xhci, virt_dev, virt_dev->udev->slot_id);
+ return -ENOMEM;
+}
+
+
+/* All the xhci_tds in the ring's TD list should be freed at this point.
+ * Should be called with xhci->lock held if there is any chance the TT lists
+ * will be manipulated by the configure endpoint, allocate device, or update
+ * hub functions while this function is removing the TT entries from the list.
+ */