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

usb: gadget: f_midi: pre-allocate IN requests

This patch introduces pre-allocation of IN endpoint USB requests. This
improves on latency (requires no usb request allocation on transmit) and avoid
several potential probles on allocating too many usb requests (which involves
DMA pool allocation problems).

This implementation also handles better multiple MIDI Gadget ports, always
processing the last processed MIDI substream if the last USB request wasn't
enought to handle the whole stream.

Signed-off-by: Felipe F. Tonello <eu@felipetonello.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>

authored by

Felipe F. Tonello and committed by
Felipe Balbi
e1e3d7ec f0f1b8ca

+129 -39
+128 -38
drivers/usb/gadget/function/f_midi.c
··· 23 23 #include <linux/module.h> 24 24 #include <linux/slab.h> 25 25 #include <linux/device.h> 26 + #include <linux/kfifo.h> 26 27 27 28 #include <sound/core.h> 28 29 #include <sound/initval.h> ··· 89 88 int index; 90 89 char *id; 91 90 unsigned int buflen, qlen; 91 + /* This fifo is used as a buffer ring for pre-allocated IN usb_requests */ 92 + DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *); 93 + unsigned int in_last_port; 92 94 }; 93 95 94 96 static inline struct f_midi *func_to_midi(struct usb_function *f) ··· 99 95 return container_of(f, struct f_midi, func); 100 96 } 101 97 102 - static void f_midi_transmit(struct f_midi *midi, struct usb_request *req); 98 + static void f_midi_transmit(struct f_midi *midi); 103 99 104 100 DECLARE_UAC_AC_HEADER_DESCRIPTOR(1); 105 101 DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); ··· 257 253 } else if (ep == midi->in_ep) { 258 254 /* Our transmit completed. See if there's more to go. 259 255 * f_midi_transmit eats req, don't queue it again. */ 260 - f_midi_transmit(midi, req); 256 + req->length = 0; 257 + f_midi_transmit(midi); 261 258 return; 262 259 } 263 260 break; ··· 269 264 case -ESHUTDOWN: /* disconnect from host */ 270 265 VDBG(cdev, "%s gone (%d), %d/%d\n", ep->name, status, 271 266 req->actual, req->length); 272 - if (ep == midi->out_ep) 267 + if (ep == midi->out_ep) { 273 268 f_midi_handle_out_data(ep, req); 274 - 275 - free_ep_req(ep, req); 269 + /* We don't need to free IN requests because it's handled 270 + * by the midi->in_req_fifo. */ 271 + free_ep_req(ep, req); 272 + } 276 273 return; 277 274 278 275 case -EOVERFLOW: /* buffer overrun on read means that ··· 341 334 if (err) 342 335 return err; 343 336 337 + /* pre-allocate write usb requests to use on f_midi_transmit. */ 338 + while (kfifo_avail(&midi->in_req_fifo)) { 339 + struct usb_request *req = 340 + midi_alloc_ep_req(midi->in_ep, midi->buflen); 341 + 342 + if (req == NULL) 343 + return -ENOMEM; 344 + 345 + req->length = 0; 346 + req->complete = f_midi_complete; 347 + 348 + kfifo_put(&midi->in_req_fifo, req); 349 + } 350 + 344 351 /* allocate a bunch of read buffers and queue them all at once. */ 345 352 for (i = 0; i < midi->qlen && err == 0; i++) { 346 353 struct usb_request *req = ··· 379 358 { 380 359 struct f_midi *midi = func_to_midi(f); 381 360 struct usb_composite_dev *cdev = f->config->cdev; 361 + struct usb_request *req = NULL; 382 362 383 363 DBG(cdev, "disable\n"); 384 364 ··· 389 367 */ 390 368 usb_ep_disable(midi->in_ep); 391 369 usb_ep_disable(midi->out_ep); 370 + 371 + /* release IN requests */ 372 + while (kfifo_get(&midi->in_req_fifo, &req)) 373 + free_ep_req(midi->in_ep, req); 392 374 } 393 375 394 376 static int f_midi_snd_free(struct snd_device *device) ··· 514 488 } 515 489 } 516 490 517 - static void f_midi_transmit(struct f_midi *midi, struct usb_request *req) 491 + static void f_midi_drop_out_substreams(struct f_midi *midi) 518 492 { 519 - struct usb_ep *ep = midi->in_ep; 520 - int i; 521 - 522 - if (!ep) 523 - return; 524 - 525 - if (!req) 526 - req = midi_alloc_ep_req(ep, midi->buflen); 527 - 528 - if (!req) { 529 - ERROR(midi, "%s: alloc_ep_request failed\n", __func__); 530 - return; 531 - } 532 - req->length = 0; 533 - req->complete = f_midi_complete; 493 + unsigned int i; 534 494 535 495 for (i = 0; i < MAX_PORTS; i++) { 536 496 struct gmidi_in_port *port = midi->in_port[i]; 537 497 struct snd_rawmidi_substream *substream = midi->in_substream[i]; 538 498 539 - if (!port || !port->active || !substream) 499 + if (!port) 500 + break; 501 + 502 + if (!port->active || !substream) 540 503 continue; 541 504 542 - while (req->length + 3 < midi->buflen) { 543 - uint8_t b; 544 - if (snd_rawmidi_transmit(substream, &b, 1) != 1) { 545 - port->active = 0; 505 + snd_rawmidi_drop_output(substream); 506 + } 507 + } 508 + 509 + static void f_midi_transmit(struct f_midi *midi) 510 + { 511 + struct usb_ep *ep = midi->in_ep; 512 + bool active; 513 + 514 + /* We only care about USB requests if IN endpoint is enabled */ 515 + if (!ep || !ep->enabled) 516 + goto drop_out; 517 + 518 + do { 519 + struct usb_request *req = NULL; 520 + unsigned int len, i; 521 + 522 + active = false; 523 + 524 + /* We peek the request in order to reuse it if it fails 525 + * to enqueue on its endpoint */ 526 + len = kfifo_peek(&midi->in_req_fifo, &req); 527 + if (len != 1) { 528 + ERROR(midi, "%s: Couldn't get usb request\n", __func__); 529 + goto drop_out; 530 + } 531 + 532 + /* If buffer overrun, then we ignore this transmission. 533 + * IMPORTANT: This will cause the user-space rawmidi device to block until a) usb 534 + * requests have been completed or b) snd_rawmidi_write() times out. */ 535 + if (req->length > 0) 536 + return; 537 + 538 + for (i = midi->in_last_port; i < MAX_PORTS; i++) { 539 + struct gmidi_in_port *port = midi->in_port[i]; 540 + struct snd_rawmidi_substream *substream = midi->in_substream[i]; 541 + 542 + if (!port) { 543 + /* Reset counter when we reach the last available port */ 544 + midi->in_last_port = 0; 546 545 break; 547 546 } 548 - f_midi_transmit_byte(req, port, b); 547 + 548 + if (!port->active || !substream) 549 + continue; 550 + 551 + while (req->length + 3 < midi->buflen) { 552 + uint8_t b; 553 + 554 + if (snd_rawmidi_transmit(substream, &b, 1) != 1) { 555 + port->active = 0; 556 + break; 557 + } 558 + f_midi_transmit_byte(req, port, b); 559 + } 560 + 561 + active = !!port->active; 562 + /* Check if last port is still active, which means that 563 + * there is still data on that substream but this current 564 + * request run out of space. */ 565 + if (active) { 566 + midi->in_last_port = i; 567 + /* There is no need to re-iterate though midi ports. */ 568 + break; 569 + } 549 570 } 550 - } 551 571 552 - if (req->length > 0 && ep->enabled) { 553 - int err; 572 + if (req->length > 0) { 573 + int err; 554 574 555 - err = usb_ep_queue(ep, req, GFP_ATOMIC); 556 - if (err < 0) 557 - ERROR(midi, "%s queue req: %d\n", 558 - midi->in_ep->name, err); 559 - } else { 560 - free_ep_req(ep, req); 561 - } 575 + err = usb_ep_queue(ep, req, GFP_ATOMIC); 576 + if (err < 0) { 577 + ERROR(midi, "%s failed to queue req: %d\n", 578 + midi->in_ep->name, err); 579 + req->length = 0; /* Re-use request next time. */ 580 + } else { 581 + /* Upon success, put request at the back of the queue. */ 582 + kfifo_skip(&midi->in_req_fifo); 583 + kfifo_put(&midi->in_req_fifo, req); 584 + } 585 + } 586 + } while (active); 587 + 588 + return; 589 + 590 + drop_out: 591 + f_midi_drop_out_substreams(midi); 562 592 } 563 593 564 594 static void f_midi_in_tasklet(unsigned long data) 565 595 { 566 596 struct f_midi *midi = (struct f_midi *) data; 567 - f_midi_transmit(midi, NULL); 597 + f_midi_transmit(midi); 568 598 } 569 599 570 600 static int f_midi_in_open(struct snd_rawmidi_substream *substream) ··· 746 664 goto fail; 747 665 } 748 666 midi->rmidi = rmidi; 667 + midi->in_last_port = 0; 749 668 strcpy(rmidi->name, card->shortname); 750 669 rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | 751 670 SNDRV_RAWMIDI_INFO_INPUT | ··· 1136 1053 mutex_lock(&opts->lock); 1137 1054 for (i = opts->in_ports - 1; i >= 0; --i) 1138 1055 kfree(midi->in_port[i]); 1056 + kfifo_free(&midi->in_req_fifo); 1139 1057 kfree(midi); 1140 1058 --opts->refcnt; 1141 1059 mutex_unlock(&opts->lock); ··· 1210 1126 midi->index = opts->index; 1211 1127 midi->buflen = opts->buflen; 1212 1128 midi->qlen = opts->qlen; 1129 + midi->in_last_port = 0; 1130 + 1131 + status = kfifo_alloc(&midi->in_req_fifo, midi->qlen, GFP_KERNEL); 1132 + if (status) 1133 + goto setup_fail; 1134 + 1213 1135 ++opts->refcnt; 1214 1136 mutex_unlock(&opts->lock); 1215 1137
+1 -1
drivers/usb/gadget/legacy/gmidi.c
··· 53 53 54 54 static unsigned int qlen = 32; 55 55 module_param(qlen, uint, S_IRUGO); 56 - MODULE_PARM_DESC(qlen, "USB read request queue length"); 56 + MODULE_PARM_DESC(qlen, "USB read and write request queue length"); 57 57 58 58 static unsigned int in_ports = 1; 59 59 module_param(in_ports, uint, S_IRUGO);