aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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