Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: gadget: dummy_hcd: complete stream support

dummy_hcd provides (alloc|free)_stream() callbacks but there are not
doing anything. The transfer side also lacks matching of streams. This
patch changes this and implements stream allocation / de-allocation
support and proper urb <=> req matching.
The UDC side exposes a limit of 16 streams. DWC3, the only USB3 UDC has
no limitations in this regard except that it _needs_ to know that
streams will be used at the ep_enable time. At the host side, there is
no real limit either: XHCI can allocate any number of streams as long as
it does not run out of memory. The UAS gadget currently requests 16
streams and the UAS host side fallbacks from the requested 256 down to
16 which is fine.
From the UASP point of view (the only specified user), the number of
used streams does not really matter. The only limitation is that the
host may not use a higher stream than the gadget requested and can deal
with.

The dummy stream support has been modelled after current UAS + XHCI +
DWC3 + UASP usage which helps me testing:
- the device announces that each ep supports 16 streams (even it could
more than that).
- the device side looks into Companion descriptor at ep_enable time and
enables them according to it.
- the host side tries to enable the requested number of streams but the
upper limit is the Comanion descriptor. None (zero streams) is an
error condition, less is okay.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Felipe Balbi <balbi@ti.com>

authored by

Sebastian Andrzej Siewior and committed by
Felipe Balbi
a54c979f 9645f7d3

+181 -16
+181 -16
drivers/usb/gadget/dummy_hcd.c
··· 88 88 unsigned wedged : 1; 89 89 unsigned already_seen : 1; 90 90 unsigned setup_stage : 1; 91 + unsigned stream_en:1; 91 92 }; 92 93 93 94 struct dummy_request { ··· 170 169 171 170 struct usb_device *udev; 172 171 struct list_head urbp_list; 172 + u32 stream_en_ep; 173 + u8 num_stream[30 / 2]; 173 174 174 175 unsigned active:1; 175 176 unsigned old_active:1; ··· 517 514 518 515 _ep->maxpacket = max; 519 516 ep->desc = desc; 517 + if (usb_ss_max_streams(_ep->comp_desc)) { 518 + if (!usb_endpoint_xfer_bulk(desc)) { 519 + dev_err(udc_dev(dum), "Can't enable stream support on " 520 + "non-bulk ep %s\n", _ep->name); 521 + return -EINVAL; 522 + } 523 + ep->stream_en = 1; 524 + } 520 525 521 - dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n", 526 + dev_dbg(udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d stream %s\n", 522 527 _ep->name, 523 528 desc->bEndpointAddress & 0x0f, 524 529 (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", ··· 545 534 val = "ctrl"; 546 535 break; 547 536 }; val; }), 548 - max); 537 + max, ep->stream_en ? "enabled" : "disabled"); 549 538 550 539 /* at this point real hardware should be NAKing transfers 551 540 * to that endpoint, until a buffer is queued to it. ··· 570 559 571 560 spin_lock_irqsave (&dum->lock, flags); 572 561 ep->desc = NULL; 562 + ep->stream_en = 0; 573 563 retval = 0; 574 564 nuke (dum, ep); 575 565 spin_unlock_irqrestore (&dum->lock, flags); ··· 1070 1058 1071 1059 /*-------------------------------------------------------------------------*/ 1072 1060 1061 + static unsigned int dummy_get_ep_idx(const struct usb_endpoint_descriptor *desc) 1062 + { 1063 + unsigned int index; 1064 + 1065 + index = usb_endpoint_num(desc) << 1; 1066 + if (usb_endpoint_dir_in(desc)) 1067 + index |= 1; 1068 + return index; 1069 + } 1070 + 1073 1071 /* MASTER/HOST SIDE DRIVER 1074 1072 * 1075 1073 * this uses the hcd framework to hook up to host side drivers. ··· 1091 1069 * the host with reads from the device, and so on, based on the 1092 1070 * usb 2.0 rules. 1093 1071 */ 1072 + 1073 + static int dummy_ep_stream_en(struct dummy_hcd *dum_hcd, struct urb *urb) 1074 + { 1075 + const struct usb_endpoint_descriptor *desc = &urb->ep->desc; 1076 + u32 index; 1077 + 1078 + if (!usb_endpoint_xfer_bulk(desc)) 1079 + return 0; 1080 + 1081 + index = dummy_get_ep_idx(desc); 1082 + return (1 << index) & dum_hcd->stream_en_ep; 1083 + } 1084 + 1085 + /* 1086 + * The max stream number is saved as a nibble so for the 30 possible endpoints 1087 + * we only 15 bytes of memory. Therefore we are limited to max 16 streams (0 1088 + * means we use only 1 stream). The maximum according to the spec is 16bit so 1089 + * if the 16 stream limit is about to go, the array size should be incremented 1090 + * to 30 elements of type u16. 1091 + */ 1092 + static int get_max_streams_for_pipe(struct dummy_hcd *dum_hcd, 1093 + unsigned int pipe) 1094 + { 1095 + int max_streams; 1096 + 1097 + max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)]; 1098 + if (usb_pipeout(pipe)) 1099 + max_streams >>= 4; 1100 + else 1101 + max_streams &= 0xf; 1102 + max_streams++; 1103 + return max_streams; 1104 + } 1105 + 1106 + static void set_max_streams_for_pipe(struct dummy_hcd *dum_hcd, 1107 + unsigned int pipe, unsigned int streams) 1108 + { 1109 + int max_streams; 1110 + 1111 + streams--; 1112 + max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)]; 1113 + if (usb_pipeout(pipe)) { 1114 + streams <<= 4; 1115 + max_streams &= 0xf; 1116 + } else { 1117 + max_streams &= 0xf0; 1118 + } 1119 + max_streams |= streams; 1120 + dum_hcd->num_stream[usb_pipeendpoint(pipe)] = max_streams; 1121 + } 1122 + 1123 + static int dummy_validate_stream(struct dummy_hcd *dum_hcd, struct urb *urb) 1124 + { 1125 + unsigned int max_streams; 1126 + int enabled; 1127 + 1128 + enabled = dummy_ep_stream_en(dum_hcd, urb); 1129 + if (!urb->stream_id) { 1130 + if (enabled) 1131 + return -EINVAL; 1132 + return 0; 1133 + } 1134 + if (!enabled) 1135 + return -EINVAL; 1136 + 1137 + max_streams = get_max_streams_for_pipe(dum_hcd, 1138 + usb_pipeendpoint(urb->pipe)); 1139 + if (urb->stream_id > max_streams) { 1140 + dev_err(dummy_dev(dum_hcd), "Stream id %d is out of range.\n", 1141 + urb->stream_id); 1142 + BUG(); 1143 + return -EINVAL; 1144 + } 1145 + return 0; 1146 + } 1094 1147 1095 1148 static int dummy_urb_enqueue ( 1096 1149 struct usb_hcd *hcd, ··· 1185 1088 1186 1089 dum_hcd = hcd_to_dummy_hcd(hcd); 1187 1090 spin_lock_irqsave(&dum_hcd->dum->lock, flags); 1091 + 1092 + rc = dummy_validate_stream(dum_hcd, urb); 1093 + if (rc) { 1094 + kfree(urbp); 1095 + goto done; 1096 + } 1097 + 1188 1098 rc = usb_hcd_link_urb_to_ep(hcd, urb); 1189 1099 if (rc) { 1190 1100 kfree(urbp); ··· 1305 1201 } 1306 1202 1307 1203 /* transfer up to a frame's worth; caller must own lock */ 1308 - static int 1309 - transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit, 1310 - int *status) 1204 + static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb, 1205 + struct dummy_ep *ep, int limit, int *status) 1311 1206 { 1207 + struct dummy *dum = dum_hcd->dum; 1312 1208 struct dummy_request *req; 1313 1209 1314 1210 top: ··· 1317 1213 unsigned host_len, dev_len, len; 1318 1214 int is_short, to_host; 1319 1215 int rescan = 0; 1216 + 1217 + if (dummy_ep_stream_en(dum_hcd, urb)) { 1218 + if ((urb->stream_id != req->req.stream_id)) 1219 + continue; 1220 + } 1320 1221 1321 1222 /* 1..N packets of ep->ep.maxpacket each ... the last one 1322 1223 * may be short (including zero length). ··· 1853 1744 default: 1854 1745 treat_control_like_bulk: 1855 1746 ep->last_io = jiffies; 1856 - total = transfer(dum, urb, ep, limit, &status); 1747 + total = transfer(dum_hcd, urb, ep, limit, &status); 1857 1748 break; 1858 1749 } 1859 1750 ··· 2310 2201 dum_hcd->timer.function = dummy_timer; 2311 2202 dum_hcd->timer.data = (unsigned long)dum_hcd; 2312 2203 dum_hcd->rh_state = DUMMY_RH_RUNNING; 2204 + dum_hcd->stream_en_ep = 0; 2313 2205 INIT_LIST_HEAD(&dum_hcd->urbp_list); 2314 2206 dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET; 2315 2207 dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING; ··· 2400 2290 struct usb_host_endpoint **eps, unsigned int num_eps, 2401 2291 unsigned int num_streams, gfp_t mem_flags) 2402 2292 { 2403 - if (hcd->speed != HCD_USB3) 2404 - dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)), 2405 - "%s() - ERROR! Not supported for USB2.0 roothub\n", 2406 - __func__); 2407 - return 0; 2293 + struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); 2294 + unsigned long flags; 2295 + int max_stream; 2296 + int ret_streams = num_streams; 2297 + unsigned int index; 2298 + unsigned int i; 2299 + 2300 + if (!num_eps) 2301 + return -EINVAL; 2302 + 2303 + spin_lock_irqsave(&dum_hcd->dum->lock, flags); 2304 + for (i = 0; i < num_eps; i++) { 2305 + index = dummy_get_ep_idx(&eps[i]->desc); 2306 + if ((1 << index) & dum_hcd->stream_en_ep) { 2307 + ret_streams = -EINVAL; 2308 + goto out; 2309 + } 2310 + max_stream = usb_ss_max_streams(&eps[i]->ss_ep_comp); 2311 + if (!max_stream) { 2312 + ret_streams = -EINVAL; 2313 + goto out; 2314 + } 2315 + if (max_stream < ret_streams) { 2316 + dev_dbg(dummy_dev(dum_hcd), "Ep 0x%x only supports %u " 2317 + "stream IDs.\n", 2318 + eps[i]->desc.bEndpointAddress, 2319 + max_stream); 2320 + ret_streams = max_stream; 2321 + } 2322 + } 2323 + 2324 + for (i = 0; i < num_eps; i++) { 2325 + index = dummy_get_ep_idx(&eps[i]->desc); 2326 + dum_hcd->stream_en_ep |= 1 << index; 2327 + set_max_streams_for_pipe(dum_hcd, 2328 + usb_endpoint_num(&eps[i]->desc), ret_streams); 2329 + } 2330 + out: 2331 + spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 2332 + return ret_streams; 2408 2333 } 2409 2334 2410 2335 /* Reverts a group of bulk endpoints back to not using stream IDs. */ ··· 2447 2302 struct usb_host_endpoint **eps, unsigned int num_eps, 2448 2303 gfp_t mem_flags) 2449 2304 { 2450 - if (hcd->speed != HCD_USB3) 2451 - dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)), 2452 - "%s() - ERROR! Not supported for USB2.0 roothub\n", 2453 - __func__); 2454 - return 0; 2305 + struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd); 2306 + unsigned long flags; 2307 + int ret; 2308 + unsigned int index; 2309 + unsigned int i; 2310 + 2311 + spin_lock_irqsave(&dum_hcd->dum->lock, flags); 2312 + for (i = 0; i < num_eps; i++) { 2313 + index = dummy_get_ep_idx(&eps[i]->desc); 2314 + if (!((1 << index) & dum_hcd->stream_en_ep)) { 2315 + ret = -EINVAL; 2316 + goto out; 2317 + } 2318 + } 2319 + 2320 + for (i = 0; i < num_eps; i++) { 2321 + index = dummy_get_ep_idx(&eps[i]->desc); 2322 + dum_hcd->stream_en_ep &= ~(1 << index); 2323 + set_max_streams_for_pipe(dum_hcd, 2324 + usb_endpoint_num(&eps[i]->desc), 0); 2325 + } 2326 + ret = 0; 2327 + out: 2328 + spin_unlock_irqrestore(&dum_hcd->dum->lock, flags); 2329 + return ret; 2455 2330 } 2456 2331 2457 2332 static struct hc_driver dummy_hcd = {