diff options
Diffstat (limited to 'drivers/usb/host/xhci-mem.c')
-rw-r--r-- | drivers/usb/host/xhci-mem.c | 132 |
1 files changed, 131 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 1755c668ac05..5efb0afff5f6 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c | |||
@@ -687,7 +687,98 @@ static void xhci_init_endpoint_timer(struct xhci_hcd *xhci, | |||
687 | ep->xhci = xhci; | 687 | ep->xhci = xhci; |
688 | } | 688 | } |
689 | 689 | ||
690 | /* All the xhci_tds in the ring's TD list should be freed at this point */ | 690 | static void xhci_free_tt_info(struct xhci_hcd *xhci, |
691 | struct xhci_virt_device *virt_dev, | ||
692 | int slot_id) | ||
693 | { | ||
694 | struct list_head *tt; | ||
695 | struct list_head *tt_list_head; | ||
696 | struct list_head *tt_next; | ||
697 | struct xhci_tt_bw_info *tt_info; | ||
698 | |||
699 | /* If the device never made it past the Set Address stage, | ||
700 | * it may not have the real_port set correctly. | ||
701 | */ | ||
702 | if (virt_dev->real_port == 0 || | ||
703 | virt_dev->real_port > HCS_MAX_PORTS(xhci->hcs_params1)) { | ||
704 | xhci_dbg(xhci, "Bad real port.\n"); | ||
705 | return; | ||
706 | } | ||
707 | |||
708 | tt_list_head = &(xhci->rh_bw[virt_dev->real_port - 1].tts); | ||
709 | if (list_empty(tt_list_head)) | ||
710 | return; | ||
711 | |||
712 | list_for_each(tt, tt_list_head) { | ||
713 | tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list); | ||
714 | if (tt_info->slot_id == slot_id) | ||
715 | break; | ||
716 | } | ||
717 | /* Cautionary measure in case the hub was disconnected before we | ||
718 | * stored the TT information. | ||
719 | */ | ||
720 | if (tt_info->slot_id != slot_id) | ||
721 | return; | ||
722 | |||
723 | tt_next = tt->next; | ||
724 | tt_info = list_entry(tt, struct xhci_tt_bw_info, | ||
725 | tt_list); | ||
726 | /* Multi-TT hubs will have more than one entry */ | ||
727 | do { | ||
728 | list_del(tt); | ||
729 | kfree(tt_info); | ||
730 | tt = tt_next; | ||
731 | if (list_empty(tt_list_head)) | ||
732 | break; | ||
733 | tt_next = tt->next; | ||
734 | tt_info = list_entry(tt, struct xhci_tt_bw_info, | ||
735 | tt_list); | ||
736 | } while (tt_info->slot_id == slot_id); | ||
737 | } | ||
738 | |||
739 | int xhci_alloc_tt_info(struct xhci_hcd *xhci, | ||
740 | struct xhci_virt_device *virt_dev, | ||
741 | struct usb_device *hdev, | ||
742 | struct usb_tt *tt, gfp_t mem_flags) | ||
743 | { | ||
744 | struct xhci_tt_bw_info *tt_info; | ||
745 | unsigned int num_ports; | ||
746 | int i, j; | ||
747 | |||
748 | if (!tt->multi) | ||
749 | num_ports = 1; | ||
750 | else | ||
751 | num_ports = hdev->maxchild; | ||
752 | |||
753 | for (i = 0; i < num_ports; i++, tt_info++) { | ||
754 | struct xhci_interval_bw_table *bw_table; | ||
755 | |||
756 | tt_info = kzalloc(sizeof(*tt_info), mem_flags); | ||
757 | if (!tt_info) | ||
758 | goto free_tts; | ||
759 | INIT_LIST_HEAD(&tt_info->tt_list); | ||
760 | list_add(&tt_info->tt_list, | ||
761 | &xhci->rh_bw[virt_dev->real_port - 1].tts); | ||
762 | tt_info->slot_id = virt_dev->udev->slot_id; | ||
763 | if (tt->multi) | ||
764 | tt_info->ttport = i+1; | ||
765 | bw_table = &tt_info->bw_table; | ||
766 | for (j = 0; j < XHCI_MAX_INTERVAL; j++) | ||
767 | INIT_LIST_HEAD(&bw_table->interval_bw[j].endpoints); | ||
768 | } | ||
769 | return 0; | ||
770 | |||
771 | free_tts: | ||
772 | xhci_free_tt_info(xhci, virt_dev, virt_dev->udev->slot_id); | ||
773 | return -ENOMEM; | ||
774 | } | ||
775 | |||
776 | |||
777 | /* All the xhci_tds in the ring's TD list should be freed at this point. | ||
778 | * Should be called with xhci->lock held if there is any chance the TT lists | ||
779 | * will be manipulated by the configure endpoint, allocate device, or update | ||
780 | * hub functions while this function is removing the TT entries from the list. | ||
781 | */ | ||
691 | void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) | 782 | void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) |
692 | { | 783 | { |
693 | struct xhci_virt_device *dev; | 784 | struct xhci_virt_device *dev; |
@@ -709,6 +800,8 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) | |||
709 | xhci_free_stream_info(xhci, | 800 | xhci_free_stream_info(xhci, |
710 | dev->eps[i].stream_info); | 801 | dev->eps[i].stream_info); |
711 | } | 802 | } |
803 | /* If this is a hub, free the TT(s) from the TT list */ | ||
804 | xhci_free_tt_info(xhci, dev, slot_id); | ||
712 | 805 | ||
713 | if (dev->ring_cache) { | 806 | if (dev->ring_cache) { |
714 | for (i = 0; i < dev->num_rings_cached; i++) | 807 | for (i = 0; i < dev->num_rings_cached; i++) |
@@ -926,6 +1019,36 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud | |||
926 | xhci_dbg(xhci, "Set root hub portnum to %d\n", port_num); | 1019 | xhci_dbg(xhci, "Set root hub portnum to %d\n", port_num); |
927 | xhci_dbg(xhci, "Set fake root hub portnum to %d\n", dev->fake_port); | 1020 | xhci_dbg(xhci, "Set fake root hub portnum to %d\n", dev->fake_port); |
928 | 1021 | ||
1022 | /* Find the right bandwidth table that this device will be a part of. | ||
1023 | * If this is a full speed device attached directly to a root port (or a | ||
1024 | * decendent of one), it counts as a primary bandwidth domain, not a | ||
1025 | * secondary bandwidth domain under a TT. An xhci_tt_info structure | ||
1026 | * will never be created for the HS root hub. | ||
1027 | */ | ||
1028 | if (!udev->tt || !udev->tt->hub->parent) { | ||
1029 | dev->bw_table = &xhci->rh_bw[port_num - 1].bw_table; | ||
1030 | } else { | ||
1031 | struct xhci_root_port_bw_info *rh_bw; | ||
1032 | struct xhci_tt_bw_info *tt_bw; | ||
1033 | |||
1034 | rh_bw = &xhci->rh_bw[port_num - 1]; | ||
1035 | /* Find the right TT. */ | ||
1036 | list_for_each_entry(tt_bw, &rh_bw->tts, tt_list) { | ||
1037 | if (tt_bw->slot_id != udev->tt->hub->slot_id) | ||
1038 | continue; | ||
1039 | |||
1040 | if (!dev->udev->tt->multi || | ||
1041 | (udev->tt->multi && | ||
1042 | tt_bw->ttport == dev->udev->ttport)) { | ||
1043 | dev->bw_table = &tt_bw->bw_table; | ||
1044 | dev->tt_info = tt_bw; | ||
1045 | break; | ||
1046 | } | ||
1047 | } | ||
1048 | if (!dev->tt_info) | ||
1049 | xhci_warn(xhci, "WARN: Didn't find a matching TT\n"); | ||
1050 | } | ||
1051 | |||
929 | /* Is this a LS/FS device under an external HS hub? */ | 1052 | /* Is this a LS/FS device under an external HS hub? */ |
930 | if (udev->tt && udev->tt->hub->parent) { | 1053 | if (udev->tt && udev->tt->hub->parent) { |
931 | slot_ctx->tt_info = cpu_to_le32(udev->tt->hub->slot_id | | 1054 | slot_ctx->tt_info = cpu_to_le32(udev->tt->hub->slot_id | |
@@ -1552,6 +1675,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) | |||
1552 | kfree(xhci->usb2_ports); | 1675 | kfree(xhci->usb2_ports); |
1553 | kfree(xhci->usb3_ports); | 1676 | kfree(xhci->usb3_ports); |
1554 | kfree(xhci->port_array); | 1677 | kfree(xhci->port_array); |
1678 | kfree(xhci->rh_bw); | ||
1555 | 1679 | ||
1556 | xhci->page_size = 0; | 1680 | xhci->page_size = 0; |
1557 | xhci->page_shift = 0; | 1681 | xhci->page_shift = 0; |
@@ -1822,6 +1946,12 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) | |||
1822 | if (!xhci->port_array) | 1946 | if (!xhci->port_array) |
1823 | return -ENOMEM; | 1947 | return -ENOMEM; |
1824 | 1948 | ||
1949 | xhci->rh_bw = kzalloc(sizeof(*xhci->rh_bw)*num_ports, flags); | ||
1950 | if (!xhci->rh_bw) | ||
1951 | return -ENOMEM; | ||
1952 | for (i = 0; i < num_ports; i++) | ||
1953 | INIT_LIST_HEAD(&xhci->rh_bw[i].tts); | ||
1954 | |||
1825 | /* | 1955 | /* |
1826 | * For whatever reason, the first capability offset is from the | 1956 | * For whatever reason, the first capability offset is from the |
1827 | * capability register base, not from the HCCPARAMS register. | 1957 | * capability register base, not from the HCCPARAMS register. |