Skip to content

Commit d157a2b

Browse files
matnymangregkh
authored andcommitted
xhci: dbgtty: Improve performance by handling received data immediately.
Improve dbc transfer rate performance by copying the received data to the tty buffer directly in the request complete callback function if possible. Only defer it in case there is already pending deferred work, tty is throttled, or we fail copy the data to the tty buffer The request complete callback is already called by a workqueue. This is part 3/3 of a dbc performance improvement series that roughly triples dbc performace when using adb push and pull over dbc. Max/min push rate after patches is 210/118 MB/s, pull rate 171/133 MB/s, tested with large files (300MB-9GB) by Łukasz Bartosik Cc: Łukasz Bartosik <[email protected]> Signed-off-by: Mathias Nyman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 03e3d9c commit d157a2b

File tree

1 file changed

+65
-33
lines changed

1 file changed

+65
-33
lines changed

drivers/usb/host/xhci-dbgtty.c

Lines changed: 65 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,74 @@ static void dbc_start_rx(struct dbc_port *port)
110110
}
111111
}
112112

113+
/*
114+
* Queue received data to tty buffer and push it.
115+
*
116+
* Returns nr of remaining bytes that didn't fit tty buffer, i.e. 0 if all
117+
* bytes sucessfullt moved. In case of error returns negative errno.
118+
* Call with lock held
119+
*/
120+
static int dbc_rx_push_buffer(struct dbc_port *port, struct dbc_request *req)
121+
{
122+
char *packet = req->buf;
123+
unsigned int n, size = req->actual;
124+
int count;
125+
126+
if (!req->actual)
127+
return 0;
128+
129+
/* if n_read is set then request was partially moved to tty buffer */
130+
n = port->n_read;
131+
if (n) {
132+
packet += n;
133+
size -= n;
134+
}
135+
136+
count = tty_insert_flip_string(&port->port, packet, size);
137+
if (count)
138+
tty_flip_buffer_push(&port->port);
139+
if (count != size) {
140+
port->n_read += count;
141+
return size - count;
142+
}
143+
144+
port->n_read = 0;
145+
return 0;
146+
}
147+
113148
static void
114149
dbc_read_complete(struct xhci_dbc *dbc, struct dbc_request *req)
115150
{
116151
unsigned long flags;
117152
struct dbc_port *port = dbc_to_port(dbc);
153+
struct tty_struct *tty;
154+
int untransferred;
155+
156+
tty = port->port.tty;
118157

119158
spin_lock_irqsave(&port->port_lock, flags);
159+
160+
/*
161+
* Only defer copyig data to tty buffer in case:
162+
* - !list_empty(&port->read_queue), there are older pending data
163+
* - tty is throttled
164+
* - failed to copy all data to buffer, defer remaining part
165+
*/
166+
167+
if (list_empty(&port->read_queue) && tty && !tty_throttled(tty)) {
168+
untransferred = dbc_rx_push_buffer(port, req);
169+
if (untransferred == 0) {
170+
list_add_tail(&req->list_pool, &port->read_pool);
171+
if (req->status != -ESHUTDOWN)
172+
dbc_start_rx(port);
173+
goto out;
174+
}
175+
}
176+
177+
/* defer moving data from req to tty buffer to a tasklet */
120178
list_add_tail(&req->list_pool, &port->read_queue);
121179
tasklet_schedule(&port->push);
180+
out:
122181
spin_unlock_irqrestore(&port->port_lock, flags);
123182
}
124183

@@ -331,10 +390,10 @@ static void dbc_rx_push(struct tasklet_struct *t)
331390
struct dbc_request *req;
332391
struct tty_struct *tty;
333392
unsigned long flags;
334-
bool do_push = false;
335393
bool disconnect = false;
336394
struct dbc_port *port = from_tasklet(port, t, push);
337395
struct list_head *queue = &port->read_queue;
396+
int untransferred;
338397

339398
spin_lock_irqsave(&port->port_lock, flags);
340399
tty = port->port.tty;
@@ -356,42 +415,15 @@ static void dbc_rx_push(struct tasklet_struct *t)
356415
break;
357416
}
358417

359-
if (req->actual) {
360-
char *packet = req->buf;
361-
unsigned int n, size = req->actual;
362-
int count;
363-
364-
n = port->n_read;
365-
if (n) {
366-
packet += n;
367-
size -= n;
368-
}
369-
370-
count = tty_insert_flip_string(&port->port, packet,
371-
size);
372-
if (count)
373-
do_push = true;
374-
if (count != size) {
375-
port->n_read += count;
376-
break;
377-
}
378-
port->n_read = 0;
379-
}
418+
untransferred = dbc_rx_push_buffer(port, req);
419+
if (untransferred > 0)
420+
break;
380421

381422
list_move_tail(&req->list_pool, &port->read_pool);
382423
}
383424

384-
if (do_push)
385-
tty_flip_buffer_push(&port->port);
386-
387-
if (!list_empty(queue) && tty) {
388-
if (!tty_throttled(tty)) {
389-
if (do_push)
390-
tasklet_schedule(&port->push);
391-
else
392-
pr_warn("ttyDBC0: RX not scheduled?\n");
393-
}
394-
}
425+
if (!list_empty(queue))
426+
tasklet_schedule(&port->push);
395427

396428
if (!disconnect)
397429
dbc_start_rx(port);

0 commit comments

Comments
 (0)