aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2011-09-02 14:05:47 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-09-09 18:52:53 -0400
commit839c817ce67178ca3c7c7ad534c571bba1e69ebe (patch)
treedcf27811dfebe7fcad0a91885744552d0065cdb2 /drivers/usb/host
parent66381755442189bbeb15f1a51b1e0059327d84ed (diff)
xhci: Store information about roothubs and TTs.
For upcoming patches, we need to keep information about the bandwidth domains under the xHCI host. Each root port is a separate primary bandwidth domain, and each high speed hub's TT (and potentially each port on a multi-TT hub) is a secondary bandwidth domain. If the table were in text form, it would look a bit like this: EP Interval Sum of Number Largest Max Max Packet of Packets Packet Size Overhead 0 N mps overhead ... 15 N mps overhead Overhead is the maximum packet overhead (for bit stuffing, CRC, protocol overhead, etc) for all the endpoints in this interval. Devices with different speeds have different max packet overhead. For example, if there is a low speed and a full speed endpoint that both have an interval of 3, we would use the higher overhead (the low speed overhead). Interval 0 is a bit special, since we really just want to know the sum of the max ESIT payloads instead of the largest max packet size. That's stored in the interval0_esit_payload variable. For root ports, we also need to keep track of the number of active TTs. For each root port, and each TT under a root port, store some information about the bandwidth consumption. Dynamically allocate an array of root port bandwidth information for the number of root ports on the xHCI host. Each root port stores a list of TTs under the root port. A single TT hub only has one entry in the list, but a multi-TT hub will have an entry per port. When the USB core says that a USB device is a hub, create one or more entries in the root port TT list for the hub. When a device is deleted, and it is a hub, search through the root port TT list and delete all TT entries for the hub. Keep track of which TT entry is associated with a device under a TT. LS/FS devices attached directly to the root port will have usb_device->tt set to the roothub. Ignore that, and treat it like a primary bandwidth domain, since there isn't really a high speed bus between the roothub and the host. 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')
-rw-r--r--drivers/usb/host/xhci-mem.c132
-rw-r--r--drivers/usb/host/xhci.c8
-rw-r--r--drivers/usb/host/xhci.h50
3 files changed, 189 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 */ 690static 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
739int 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
771free_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 */
691void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) 782void 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.
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 7da3b139c8dd..1657041c19cf 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -2990,6 +2990,14 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
2990 } 2990 }
2991 2991
2992 spin_lock_irqsave(&xhci->lock, flags); 2992 spin_lock_irqsave(&xhci->lock, flags);
2993 if (hdev->speed == USB_SPEED_HIGH &&
2994 xhci_alloc_tt_info(xhci, vdev, hdev, tt, GFP_ATOMIC)) {
2995 xhci_dbg(xhci, "Could not allocate xHCI TT structure.\n");
2996 xhci_free_command(xhci, config_cmd);
2997 spin_unlock_irqrestore(&xhci->lock, flags);
2998 return -ENOMEM;
2999 }
3000
2993 xhci_slot_copy(xhci, config_cmd->in_ctx, vdev->out_ctx); 3001 xhci_slot_copy(xhci, config_cmd->in_ctx, vdev->out_ctx);
2994 ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx); 3002 ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx);
2995 ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); 3003 ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index ec4817003a56..eee47c8a6ee8 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -774,6 +774,26 @@ struct xhci_virt_ep {
774 bool skip; 774 bool skip;
775}; 775};
776 776
777enum xhci_overhead_type {
778 LS_OVERHEAD_TYPE = 0,
779 FS_OVERHEAD_TYPE,
780 HS_OVERHEAD_TYPE,
781};
782
783struct xhci_interval_bw {
784 unsigned int num_packets;
785 /* How many endpoints of each speed are present. */
786 unsigned int overhead[3];
787};
788
789#define XHCI_MAX_INTERVAL 16
790
791struct xhci_interval_bw_table {
792 unsigned int interval0_esit_payload;
793 struct xhci_interval_bw interval_bw[XHCI_MAX_INTERVAL];
794};
795
796
777struct xhci_virt_device { 797struct xhci_virt_device {
778 struct usb_device *udev; 798 struct usb_device *udev;
779 /* 799 /*
@@ -800,6 +820,30 @@ struct xhci_virt_device {
800 struct list_head cmd_list; 820 struct list_head cmd_list;
801 u8 fake_port; 821 u8 fake_port;
802 u8 real_port; 822 u8 real_port;
823 struct xhci_interval_bw_table *bw_table;
824 struct xhci_tt_bw_info *tt_info;
825};
826
827/*
828 * For each roothub, keep track of the bandwidth information for each periodic
829 * interval.
830 *
831 * If a high speed hub is attached to the roothub, each TT associated with that
832 * hub is a separate bandwidth domain. The interval information for the
833 * endpoints on the devices under that TT will appear in the TT structure.
834 */
835struct xhci_root_port_bw_info {
836 struct list_head tts;
837 unsigned int num_active_tts;
838 struct xhci_interval_bw_table bw_table;
839};
840
841struct xhci_tt_bw_info {
842 struct list_head tt_list;
843 int slot_id;
844 int ttport;
845 struct xhci_interval_bw_table bw_table;
846 int active_eps;
803}; 847};
804 848
805 849
@@ -1268,6 +1312,8 @@ struct xhci_hcd {
1268 int slot_id; 1312 int slot_id;
1269 /* Internal mirror of the HW's dcbaa */ 1313 /* Internal mirror of the HW's dcbaa */
1270 struct xhci_virt_device *devs[MAX_HC_SLOTS]; 1314 struct xhci_virt_device *devs[MAX_HC_SLOTS];
1315 /* For keeping track of bandwidth domains per roothub. */
1316 struct xhci_root_port_bw_info *rh_bw;
1271 1317
1272 /* DMA pools */ 1318 /* DMA pools */
1273 struct dma_pool *device_pool; 1319 struct dma_pool *device_pool;
@@ -1508,6 +1554,10 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd);
1508irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd); 1554irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd);
1509int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev); 1555int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev);
1510void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev); 1556void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev);
1557int xhci_alloc_tt_info(struct xhci_hcd *xhci,
1558 struct xhci_virt_device *virt_dev,
1559 struct usb_device *hdev,
1560 struct usb_tt *tt, gfp_t mem_flags);
1511int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev, 1561int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
1512 struct usb_host_endpoint **eps, unsigned int num_eps, 1562 struct usb_host_endpoint **eps, unsigned int num_eps,
1513 unsigned int num_streams, gfp_t mem_flags); 1563 unsigned int num_streams, gfp_t mem_flags);