1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * xhci-dbgtty.c - tty glue for xHCI debug capability
4 *
5 * Copyright (C) 2017 Intel Corporation
6 *
7 * Author: Lu Baolu <[email protected]>
8 */
9
10 #include <linux/slab.h>
11 #include <linux/tty.h>
12 #include <linux/tty_flip.h>
13 #include <linux/idr.h>
14
15 #include "xhci.h"
16 #include "xhci-dbgcap.h"
17
18 static struct tty_driver *dbc_tty_driver;
19 static struct idr dbc_tty_minors;
20 static DEFINE_MUTEX(dbc_tty_minors_lock);
21
dbc_to_port(struct xhci_dbc * dbc)22 static inline struct dbc_port *dbc_to_port(struct xhci_dbc *dbc)
23 {
24 return dbc->priv;
25 }
26
27 static unsigned int
dbc_kfifo_to_req(struct dbc_port * port,char * packet)28 dbc_kfifo_to_req(struct dbc_port *port, char *packet)
29 {
30 unsigned int len;
31
32 len = kfifo_len(&port->port.xmit_fifo);
33
34 if (len == 0)
35 return 0;
36
37 len = min(len, DBC_MAX_PACKET);
38
39 if (port->tx_boundary)
40 len = min(port->tx_boundary, len);
41
42 len = kfifo_out(&port->port.xmit_fifo, packet, len);
43
44 if (port->tx_boundary)
45 port->tx_boundary -= len;
46
47 return len;
48 }
49
dbc_start_tx(struct dbc_port * port)50 static int dbc_start_tx(struct dbc_port *port)
51 __releases(&port->port_lock)
52 __acquires(&port->port_lock)
53 {
54 int len;
55 struct dbc_request *req;
56 int status = 0;
57 bool do_tty_wake = false;
58 struct list_head *pool = &port->write_pool;
59
60 while (!list_empty(pool)) {
61 req = list_entry(pool->next, struct dbc_request, list_pool);
62 len = dbc_kfifo_to_req(port, req->buf);
63 if (len == 0)
64 break;
65 do_tty_wake = true;
66
67 req->length = len;
68 list_del(&req->list_pool);
69
70 spin_unlock(&port->port_lock);
71 status = dbc_ep_queue(req);
72 spin_lock(&port->port_lock);
73
74 if (status) {
75 list_add(&req->list_pool, pool);
76 break;
77 }
78 }
79
80 if (do_tty_wake && port->port.tty)
81 tty_wakeup(port->port.tty);
82
83 return status;
84 }
85
dbc_start_rx(struct dbc_port * port)86 static void dbc_start_rx(struct dbc_port *port)
87 __releases(&port->port_lock)
88 __acquires(&port->port_lock)
89 {
90 struct dbc_request *req;
91 int status;
92 struct list_head *pool = &port->read_pool;
93
94 while (!list_empty(pool)) {
95 if (!port->port.tty)
96 break;
97
98 req = list_entry(pool->next, struct dbc_request, list_pool);
99 list_del(&req->list_pool);
100 req->length = DBC_MAX_PACKET;
101
102 spin_unlock(&port->port_lock);
103 status = dbc_ep_queue(req);
104 spin_lock(&port->port_lock);
105
106 if (status) {
107 list_add(&req->list_pool, pool);
108 break;
109 }
110 }
111 }
112
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 */
dbc_rx_push_buffer(struct dbc_port * port,struct dbc_request * req)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
148 static void
dbc_read_complete(struct xhci_dbc * dbc,struct dbc_request * req)149 dbc_read_complete(struct xhci_dbc *dbc, struct dbc_request *req)
150 {
151 unsigned long flags;
152 struct dbc_port *port = dbc_to_port(dbc);
153 struct tty_struct *tty;
154 int untransferred;
155
156 tty = port->port.tty;
157
158 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 */
178 list_add_tail(&req->list_pool, &port->read_queue);
179 tasklet_schedule(&port->push);
180 out:
181 spin_unlock_irqrestore(&port->port_lock, flags);
182 }
183
dbc_write_complete(struct xhci_dbc * dbc,struct dbc_request * req)184 static void dbc_write_complete(struct xhci_dbc *dbc, struct dbc_request *req)
185 {
186 unsigned long flags;
187 struct dbc_port *port = dbc_to_port(dbc);
188
189 spin_lock_irqsave(&port->port_lock, flags);
190 list_add(&req->list_pool, &port->write_pool);
191 switch (req->status) {
192 case 0:
193 dbc_start_tx(port);
194 break;
195 case -ESHUTDOWN:
196 break;
197 default:
198 dev_warn(dbc->dev, "unexpected write complete status %d\n",
199 req->status);
200 break;
201 }
202 spin_unlock_irqrestore(&port->port_lock, flags);
203 }
204
xhci_dbc_free_req(struct dbc_request * req)205 static void xhci_dbc_free_req(struct dbc_request *req)
206 {
207 kfree(req->buf);
208 dbc_free_request(req);
209 }
210
211 static int
xhci_dbc_alloc_requests(struct xhci_dbc * dbc,unsigned int direction,struct list_head * head,void (* fn)(struct xhci_dbc *,struct dbc_request *))212 xhci_dbc_alloc_requests(struct xhci_dbc *dbc, unsigned int direction,
213 struct list_head *head,
214 void (*fn)(struct xhci_dbc *, struct dbc_request *))
215 {
216 int i;
217 struct dbc_request *req;
218
219 for (i = 0; i < DBC_QUEUE_SIZE; i++) {
220 req = dbc_alloc_request(dbc, direction, GFP_KERNEL);
221 if (!req)
222 break;
223
224 req->length = DBC_MAX_PACKET;
225 req->buf = kmalloc(req->length, GFP_KERNEL);
226 if (!req->buf) {
227 dbc_free_request(req);
228 break;
229 }
230
231 req->complete = fn;
232 list_add_tail(&req->list_pool, head);
233 }
234
235 return list_empty(head) ? -ENOMEM : 0;
236 }
237
238 static void
xhci_dbc_free_requests(struct list_head * head)239 xhci_dbc_free_requests(struct list_head *head)
240 {
241 struct dbc_request *req;
242
243 while (!list_empty(head)) {
244 req = list_entry(head->next, struct dbc_request, list_pool);
245 list_del(&req->list_pool);
246 xhci_dbc_free_req(req);
247 }
248 }
249
dbc_tty_install(struct tty_driver * driver,struct tty_struct * tty)250 static int dbc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
251 {
252 struct dbc_port *port;
253
254 mutex_lock(&dbc_tty_minors_lock);
255 port = idr_find(&dbc_tty_minors, tty->index);
256 mutex_unlock(&dbc_tty_minors_lock);
257
258 if (!port)
259 return -ENXIO;
260
261 tty->driver_data = port;
262
263 return tty_port_install(&port->port, driver, tty);
264 }
265
dbc_tty_open(struct tty_struct * tty,struct file * file)266 static int dbc_tty_open(struct tty_struct *tty, struct file *file)
267 {
268 struct dbc_port *port = tty->driver_data;
269
270 return tty_port_open(&port->port, tty, file);
271 }
272
dbc_tty_close(struct tty_struct * tty,struct file * file)273 static void dbc_tty_close(struct tty_struct *tty, struct file *file)
274 {
275 struct dbc_port *port = tty->driver_data;
276
277 tty_port_close(&port->port, tty, file);
278 }
279
dbc_tty_write(struct tty_struct * tty,const u8 * buf,size_t count)280 static ssize_t dbc_tty_write(struct tty_struct *tty, const u8 *buf,
281 size_t count)
282 {
283 struct dbc_port *port = tty->driver_data;
284 unsigned long flags;
285 unsigned int written = 0;
286
287 spin_lock_irqsave(&port->port_lock, flags);
288
289 /*
290 * Treat tty write as one usb transfer. Make sure the writes are turned
291 * into TRB request having the same size boundaries as the tty writes.
292 * Don't add data to kfifo before previous write is turned into TRBs
293 */
294 if (port->tx_boundary) {
295 spin_unlock_irqrestore(&port->port_lock, flags);
296 return 0;
297 }
298
299 if (count) {
300 written = kfifo_in(&port->port.xmit_fifo, buf, count);
301
302 if (written == count)
303 port->tx_boundary = kfifo_len(&port->port.xmit_fifo);
304
305 dbc_start_tx(port);
306 }
307
308 spin_unlock_irqrestore(&port->port_lock, flags);
309
310 return written;
311 }
312
dbc_tty_put_char(struct tty_struct * tty,u8 ch)313 static int dbc_tty_put_char(struct tty_struct *tty, u8 ch)
314 {
315 struct dbc_port *port = tty->driver_data;
316 unsigned long flags;
317 int status;
318
319 spin_lock_irqsave(&port->port_lock, flags);
320 status = kfifo_put(&port->port.xmit_fifo, ch);
321 spin_unlock_irqrestore(&port->port_lock, flags);
322
323 return status;
324 }
325
dbc_tty_flush_chars(struct tty_struct * tty)326 static void dbc_tty_flush_chars(struct tty_struct *tty)
327 {
328 struct dbc_port *port = tty->driver_data;
329 unsigned long flags;
330
331 spin_lock_irqsave(&port->port_lock, flags);
332 dbc_start_tx(port);
333 spin_unlock_irqrestore(&port->port_lock, flags);
334 }
335
dbc_tty_write_room(struct tty_struct * tty)336 static unsigned int dbc_tty_write_room(struct tty_struct *tty)
337 {
338 struct dbc_port *port = tty->driver_data;
339 unsigned long flags;
340 unsigned int room;
341
342 spin_lock_irqsave(&port->port_lock, flags);
343 room = kfifo_avail(&port->port.xmit_fifo);
344
345 if (port->tx_boundary)
346 room = 0;
347
348 spin_unlock_irqrestore(&port->port_lock, flags);
349
350 return room;
351 }
352
dbc_tty_chars_in_buffer(struct tty_struct * tty)353 static unsigned int dbc_tty_chars_in_buffer(struct tty_struct *tty)
354 {
355 struct dbc_port *port = tty->driver_data;
356 unsigned long flags;
357 unsigned int chars;
358
359 spin_lock_irqsave(&port->port_lock, flags);
360 chars = kfifo_len(&port->port.xmit_fifo);
361 spin_unlock_irqrestore(&port->port_lock, flags);
362
363 return chars;
364 }
365
dbc_tty_unthrottle(struct tty_struct * tty)366 static void dbc_tty_unthrottle(struct tty_struct *tty)
367 {
368 struct dbc_port *port = tty->driver_data;
369 unsigned long flags;
370
371 spin_lock_irqsave(&port->port_lock, flags);
372 tasklet_schedule(&port->push);
373 spin_unlock_irqrestore(&port->port_lock, flags);
374 }
375
376 static const struct tty_operations dbc_tty_ops = {
377 .install = dbc_tty_install,
378 .open = dbc_tty_open,
379 .close = dbc_tty_close,
380 .write = dbc_tty_write,
381 .put_char = dbc_tty_put_char,
382 .flush_chars = dbc_tty_flush_chars,
383 .write_room = dbc_tty_write_room,
384 .chars_in_buffer = dbc_tty_chars_in_buffer,
385 .unthrottle = dbc_tty_unthrottle,
386 };
387
dbc_rx_push(struct tasklet_struct * t)388 static void dbc_rx_push(struct tasklet_struct *t)
389 {
390 struct dbc_request *req;
391 struct tty_struct *tty;
392 unsigned long flags;
393 bool disconnect = false;
394 struct dbc_port *port = from_tasklet(port, t, push);
395 struct list_head *queue = &port->read_queue;
396 int untransferred;
397
398 spin_lock_irqsave(&port->port_lock, flags);
399 tty = port->port.tty;
400 while (!list_empty(queue)) {
401 req = list_first_entry(queue, struct dbc_request, list_pool);
402
403 if (tty && tty_throttled(tty))
404 break;
405
406 switch (req->status) {
407 case 0:
408 break;
409 case -ESHUTDOWN:
410 disconnect = true;
411 break;
412 default:
413 pr_warn("ttyDBC0: unexpected RX status %d\n",
414 req->status);
415 break;
416 }
417
418 untransferred = dbc_rx_push_buffer(port, req);
419 if (untransferred > 0)
420 break;
421
422 list_move_tail(&req->list_pool, &port->read_pool);
423 }
424
425 if (!list_empty(queue))
426 tasklet_schedule(&port->push);
427
428 if (!disconnect)
429 dbc_start_rx(port);
430
431 spin_unlock_irqrestore(&port->port_lock, flags);
432 }
433
dbc_port_activate(struct tty_port * _port,struct tty_struct * tty)434 static int dbc_port_activate(struct tty_port *_port, struct tty_struct *tty)
435 {
436 unsigned long flags;
437 struct dbc_port *port = container_of(_port, struct dbc_port, port);
438
439 spin_lock_irqsave(&port->port_lock, flags);
440 dbc_start_rx(port);
441 spin_unlock_irqrestore(&port->port_lock, flags);
442
443 return 0;
444 }
445
446 static const struct tty_port_operations dbc_port_ops = {
447 .activate = dbc_port_activate,
448 };
449
450 static void
xhci_dbc_tty_init_port(struct xhci_dbc * dbc,struct dbc_port * port)451 xhci_dbc_tty_init_port(struct xhci_dbc *dbc, struct dbc_port *port)
452 {
453 tty_port_init(&port->port);
454 spin_lock_init(&port->port_lock);
455 tasklet_setup(&port->push, dbc_rx_push);
456 INIT_LIST_HEAD(&port->read_pool);
457 INIT_LIST_HEAD(&port->read_queue);
458 INIT_LIST_HEAD(&port->write_pool);
459
460 port->port.ops = &dbc_port_ops;
461 port->n_read = 0;
462 }
463
464 static void
xhci_dbc_tty_exit_port(struct dbc_port * port)465 xhci_dbc_tty_exit_port(struct dbc_port *port)
466 {
467 tasklet_kill(&port->push);
468 tty_port_destroy(&port->port);
469 }
470
xhci_dbc_tty_register_device(struct xhci_dbc * dbc)471 static int xhci_dbc_tty_register_device(struct xhci_dbc *dbc)
472 {
473 int ret;
474 struct device *tty_dev;
475 struct dbc_port *port = dbc_to_port(dbc);
476
477 if (port->registered)
478 return -EBUSY;
479
480 xhci_dbc_tty_init_port(dbc, port);
481
482 mutex_lock(&dbc_tty_minors_lock);
483 port->minor = idr_alloc(&dbc_tty_minors, port, 0, 64, GFP_KERNEL);
484 mutex_unlock(&dbc_tty_minors_lock);
485
486 if (port->minor < 0) {
487 ret = port->minor;
488 goto err_idr;
489 }
490
491 ret = kfifo_alloc(&port->port.xmit_fifo, DBC_WRITE_BUF_SIZE,
492 GFP_KERNEL);
493 if (ret)
494 goto err_exit_port;
495
496 ret = xhci_dbc_alloc_requests(dbc, BULK_IN, &port->read_pool,
497 dbc_read_complete);
498 if (ret)
499 goto err_free_fifo;
500
501 ret = xhci_dbc_alloc_requests(dbc, BULK_OUT, &port->write_pool,
502 dbc_write_complete);
503 if (ret)
504 goto err_free_requests;
505
506 tty_dev = tty_port_register_device(&port->port,
507 dbc_tty_driver, port->minor, NULL);
508 if (IS_ERR(tty_dev)) {
509 ret = PTR_ERR(tty_dev);
510 goto err_free_requests;
511 }
512
513 port->registered = true;
514
515 return 0;
516
517 err_free_requests:
518 xhci_dbc_free_requests(&port->read_pool);
519 xhci_dbc_free_requests(&port->write_pool);
520 err_free_fifo:
521 kfifo_free(&port->port.xmit_fifo);
522 err_exit_port:
523 idr_remove(&dbc_tty_minors, port->minor);
524 err_idr:
525 xhci_dbc_tty_exit_port(port);
526
527 dev_err(dbc->dev, "can't register tty port, err %d\n", ret);
528
529 return ret;
530 }
531
xhci_dbc_tty_unregister_device(struct xhci_dbc * dbc)532 static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc)
533 {
534 struct dbc_port *port = dbc_to_port(dbc);
535
536 if (!port->registered)
537 return;
538 tty_unregister_device(dbc_tty_driver, port->minor);
539 xhci_dbc_tty_exit_port(port);
540 port->registered = false;
541
542 mutex_lock(&dbc_tty_minors_lock);
543 idr_remove(&dbc_tty_minors, port->minor);
544 mutex_unlock(&dbc_tty_minors_lock);
545
546 kfifo_free(&port->port.xmit_fifo);
547 xhci_dbc_free_requests(&port->read_pool);
548 xhci_dbc_free_requests(&port->read_queue);
549 xhci_dbc_free_requests(&port->write_pool);
550 }
551
552 static const struct dbc_driver dbc_driver = {
553 .configure = xhci_dbc_tty_register_device,
554 .disconnect = xhci_dbc_tty_unregister_device,
555 };
556
xhci_dbc_tty_probe(struct device * dev,void __iomem * base,struct xhci_hcd * xhci)557 int xhci_dbc_tty_probe(struct device *dev, void __iomem *base, struct xhci_hcd *xhci)
558 {
559 struct xhci_dbc *dbc;
560 struct dbc_port *port;
561 int status;
562
563 if (!dbc_tty_driver)
564 return -ENODEV;
565
566 port = kzalloc(sizeof(*port), GFP_KERNEL);
567 if (!port)
568 return -ENOMEM;
569
570 dbc = xhci_alloc_dbc(dev, base, &dbc_driver);
571
572 if (!dbc) {
573 status = -ENOMEM;
574 goto out2;
575 }
576
577 dbc->priv = port;
578
579 /* get rid of xhci once this is a real driver binding to a device */
580 xhci->dbc = dbc;
581
582 return 0;
583 out2:
584 kfree(port);
585
586 return status;
587 }
588
589 /*
590 * undo what probe did, assume dbc is stopped already.
591 * we also assume tty_unregister_device() is called before this
592 */
xhci_dbc_tty_remove(struct xhci_dbc * dbc)593 void xhci_dbc_tty_remove(struct xhci_dbc *dbc)
594 {
595 struct dbc_port *port = dbc_to_port(dbc);
596
597 xhci_dbc_remove(dbc);
598 kfree(port);
599 }
600
dbc_tty_init(void)601 int dbc_tty_init(void)
602 {
603 int ret;
604
605 idr_init(&dbc_tty_minors);
606
607 dbc_tty_driver = tty_alloc_driver(64, TTY_DRIVER_REAL_RAW |
608 TTY_DRIVER_DYNAMIC_DEV);
609 if (IS_ERR(dbc_tty_driver)) {
610 idr_destroy(&dbc_tty_minors);
611 return PTR_ERR(dbc_tty_driver);
612 }
613
614 dbc_tty_driver->driver_name = "dbc_serial";
615 dbc_tty_driver->name = "ttyDBC";
616
617 dbc_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
618 dbc_tty_driver->subtype = SERIAL_TYPE_NORMAL;
619 dbc_tty_driver->init_termios = tty_std_termios;
620 dbc_tty_driver->init_termios.c_cflag =
621 B9600 | CS8 | CREAD | HUPCL | CLOCAL;
622 dbc_tty_driver->init_termios.c_ispeed = 9600;
623 dbc_tty_driver->init_termios.c_ospeed = 9600;
624
625 tty_set_operations(dbc_tty_driver, &dbc_tty_ops);
626
627 ret = tty_register_driver(dbc_tty_driver);
628 if (ret) {
629 pr_err("Can't register dbc tty driver\n");
630 tty_driver_kref_put(dbc_tty_driver);
631 idr_destroy(&dbc_tty_minors);
632 }
633
634 return ret;
635 }
636
dbc_tty_exit(void)637 void dbc_tty_exit(void)
638 {
639 if (dbc_tty_driver) {
640 tty_unregister_driver(dbc_tty_driver);
641 tty_driver_kref_put(dbc_tty_driver);
642 dbc_tty_driver = NULL;
643 }
644
645 idr_destroy(&dbc_tty_minors);
646 }
647