aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorSarah Sharp <sarah.a.sharp@linux.intel.com>2011-09-13 19:41:13 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-09-20 15:33:50 -0400
commit2b69899934c63b7b9432568584fb4c4a2924f40c (patch)
treefd857f901beaf7c60b7015422aa5bc85e4a8eebe /drivers/usb
parent170c026347c867a71e27713b98c58b266146c468 (diff)
xhci: USB 3.0 BW checking.
The Intel Panther Point xHCI host tracks SuperSpeed endpoints in a different way than USB 2.0/1.1 endpoints. The bandwidth interval tables are not used, and instead the bandwidth is calculated in a very simple way. Bandwidth for SuperSpeed endpoints is tracked individually in each direction, since each direction has the full USB 3.0 bandwidth available. 10% of the bus bandwidth is reserved for non-periodic transfers. This checking would be more complex if we had USB 3.0 LPM enabled, because an additional latency for isochronous ping times need to be taken into account. However, we don't have USB 3.0 LPM support in Linux yet. 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')
-rw-r--r--drivers/usb/host/xhci.c69
-rw-r--r--drivers/usb/host/xhci.h3
2 files changed, 67 insertions, 5 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 7583b24c3387..54cb762d15c8 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -1810,6 +1810,22 @@ static int xhci_check_tt_bw_table(struct xhci_hcd *xhci,
1810 return 0; 1810 return 0;
1811} 1811}
1812 1812
1813static int xhci_check_ss_bw(struct xhci_hcd *xhci,
1814 struct xhci_virt_device *virt_dev)
1815{
1816 unsigned int bw_reserved;
1817
1818 bw_reserved = DIV_ROUND_UP(SS_BW_RESERVED*SS_BW_LIMIT_IN, 100);
1819 if (virt_dev->bw_table->ss_bw_in > (SS_BW_LIMIT_IN - bw_reserved))
1820 return -ENOMEM;
1821
1822 bw_reserved = DIV_ROUND_UP(SS_BW_RESERVED*SS_BW_LIMIT_OUT, 100);
1823 if (virt_dev->bw_table->ss_bw_out > (SS_BW_LIMIT_OUT - bw_reserved))
1824 return -ENOMEM;
1825
1826 return 0;
1827}
1828
1813/* 1829/*
1814 * This algorithm is a very conservative estimate of the worst-case scheduling 1830 * This algorithm is a very conservative estimate of the worst-case scheduling
1815 * scenario for any one interval. The hardware dynamically schedules the 1831 * scenario for any one interval. The hardware dynamically schedules the
@@ -1866,6 +1882,9 @@ static int xhci_check_bw_table(struct xhci_hcd *xhci,
1866 unsigned int packets_remaining = 0; 1882 unsigned int packets_remaining = 0;
1867 unsigned int i; 1883 unsigned int i;
1868 1884
1885 if (virt_dev->udev->speed == USB_SPEED_SUPER)
1886 return xhci_check_ss_bw(xhci, virt_dev);
1887
1869 if (virt_dev->udev->speed == USB_SPEED_HIGH) { 1888 if (virt_dev->udev->speed == USB_SPEED_HIGH) {
1870 max_bandwidth = HS_BW_LIMIT; 1889 max_bandwidth = HS_BW_LIMIT;
1871 /* Convert percent of bus BW reserved to blocks reserved */ 1890 /* Convert percent of bus BW reserved to blocks reserved */
@@ -2028,6 +2047,25 @@ static bool xhci_is_async_ep(unsigned int ep_type)
2028 ep_type != INT_IN_EP); 2047 ep_type != INT_IN_EP);
2029} 2048}
2030 2049
2050static bool xhci_is_sync_in_ep(unsigned int ep_type)
2051{
2052 return (ep_type == ISOC_IN_EP || ep_type != INT_IN_EP);
2053}
2054
2055static unsigned int xhci_get_ss_bw_consumed(struct xhci_bw_info *ep_bw)
2056{
2057 unsigned int mps = DIV_ROUND_UP(ep_bw->max_packet_size, SS_BLOCK);
2058
2059 if (ep_bw->ep_interval == 0)
2060 return SS_OVERHEAD_BURST +
2061 (ep_bw->mult * ep_bw->num_packets *
2062 (SS_OVERHEAD + mps));
2063 return DIV_ROUND_UP(ep_bw->mult * ep_bw->num_packets *
2064 (SS_OVERHEAD + mps + SS_OVERHEAD_BURST),
2065 1 << ep_bw->ep_interval);
2066
2067}
2068
2031void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci, 2069void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
2032 struct xhci_bw_info *ep_bw, 2070 struct xhci_bw_info *ep_bw,
2033 struct xhci_interval_bw_table *bw_table, 2071 struct xhci_interval_bw_table *bw_table,
@@ -2038,10 +2076,24 @@ void xhci_drop_ep_from_interval_table(struct xhci_hcd *xhci,
2038 struct xhci_interval_bw *interval_bw; 2076 struct xhci_interval_bw *interval_bw;
2039 int normalized_interval; 2077 int normalized_interval;
2040 2078
2041 if (xhci_is_async_ep(ep_bw->type) || 2079 if (xhci_is_async_ep(ep_bw->type))
2042 list_empty(&virt_ep->bw_endpoint_list))
2043 return; 2080 return;
2044 2081
2082 if (udev->speed == USB_SPEED_SUPER) {
2083 if (xhci_is_sync_in_ep(ep_bw->type))
2084 xhci->devs[udev->slot_id]->bw_table->ss_bw_in -=
2085 xhci_get_ss_bw_consumed(ep_bw);
2086 else
2087 xhci->devs[udev->slot_id]->bw_table->ss_bw_out -=
2088 xhci_get_ss_bw_consumed(ep_bw);
2089 return;
2090 }
2091
2092 /* SuperSpeed endpoints never get added to intervals in the table, so
2093 * this check is only valid for HS/FS/LS devices.
2094 */
2095 if (list_empty(&virt_ep->bw_endpoint_list))
2096 return;
2045 /* For LS/FS devices, we need to translate the interval expressed in 2097 /* For LS/FS devices, we need to translate the interval expressed in
2046 * microframes to frames. 2098 * microframes to frames.
2047 */ 2099 */
@@ -2091,6 +2143,16 @@ static void xhci_add_ep_to_interval_table(struct xhci_hcd *xhci,
2091 if (xhci_is_async_ep(ep_bw->type)) 2143 if (xhci_is_async_ep(ep_bw->type))
2092 return; 2144 return;
2093 2145
2146 if (udev->speed == USB_SPEED_SUPER) {
2147 if (xhci_is_sync_in_ep(ep_bw->type))
2148 xhci->devs[udev->slot_id]->bw_table->ss_bw_in +=
2149 xhci_get_ss_bw_consumed(ep_bw);
2150 else
2151 xhci->devs[udev->slot_id]->bw_table->ss_bw_out +=
2152 xhci_get_ss_bw_consumed(ep_bw);
2153 return;
2154 }
2155
2094 /* For LS/FS devices, we need to translate the interval expressed in 2156 /* For LS/FS devices, we need to translate the interval expressed in
2095 * microframes to frames. 2157 * microframes to frames.
2096 */ 2158 */
@@ -2169,9 +2231,6 @@ static int xhci_reserve_bandwidth(struct xhci_hcd *xhci,
2169 struct xhci_input_control_ctx *ctrl_ctx; 2231 struct xhci_input_control_ctx *ctrl_ctx;
2170 int old_active_eps = 0; 2232 int old_active_eps = 0;
2171 2233
2172 if (virt_dev->udev->speed == USB_SPEED_SUPER)
2173 return 0;
2174
2175 if (virt_dev->tt_info) 2234 if (virt_dev->tt_info)
2176 old_active_eps = virt_dev->tt_info->active_eps; 2235 old_active_eps = virt_dev->tt_info->active_eps;
2177 2236
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 752a500f8695..2882074eb2c8 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -799,6 +799,7 @@ struct xhci_bw_info {
799/* Percentage of bus bandwidth reserved for non-periodic transfers */ 799/* Percentage of bus bandwidth reserved for non-periodic transfers */
800#define FS_BW_RESERVED 10 800#define FS_BW_RESERVED 10
801#define HS_BW_RESERVED 20 801#define HS_BW_RESERVED 20
802#define SS_BW_RESERVED 10
802 803
803struct xhci_virt_ep { 804struct xhci_virt_ep {
804 struct xhci_ring *ring; 805 struct xhci_ring *ring;
@@ -869,6 +870,8 @@ struct xhci_interval_bw_table {
869 struct xhci_interval_bw interval_bw[XHCI_MAX_INTERVAL]; 870 struct xhci_interval_bw interval_bw[XHCI_MAX_INTERVAL];
870 /* Includes reserved bandwidth for async endpoints */ 871 /* Includes reserved bandwidth for async endpoints */
871 unsigned int bw_used; 872 unsigned int bw_used;
873 unsigned int ss_bw_in;
874 unsigned int ss_bw_out;
872}; 875};
873 876
874 877