Linux-libre 4.19.123-gnu
[librecmc/linux-libre.git] / drivers / usb / host / xhci-dbgtty.c
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 <baolu.lu@linux.intel.com>
8  */
9
10 #include <linux/slab.h>
11 #include <linux/tty.h>
12 #include <linux/tty_flip.h>
13
14 #include "xhci.h"
15 #include "xhci-dbgcap.h"
16
17 static unsigned int
18 dbc_send_packet(struct dbc_port *port, char *packet, unsigned int size)
19 {
20         unsigned int            len;
21
22         len = kfifo_len(&port->write_fifo);
23         if (len < size)
24                 size = len;
25         if (size != 0)
26                 size = kfifo_out(&port->write_fifo, packet, size);
27         return size;
28 }
29
30 static int dbc_start_tx(struct dbc_port *port)
31         __releases(&port->port_lock)
32         __acquires(&port->port_lock)
33 {
34         int                     len;
35         struct dbc_request      *req;
36         int                     status = 0;
37         bool                    do_tty_wake = false;
38         struct list_head        *pool = &port->write_pool;
39
40         while (!list_empty(pool)) {
41                 req = list_entry(pool->next, struct dbc_request, list_pool);
42                 len = dbc_send_packet(port, req->buf, DBC_MAX_PACKET);
43                 if (len == 0)
44                         break;
45                 do_tty_wake = true;
46
47                 req->length = len;
48                 list_del(&req->list_pool);
49
50                 spin_unlock(&port->port_lock);
51                 status = dbc_ep_queue(port->out, req, GFP_ATOMIC);
52                 spin_lock(&port->port_lock);
53
54                 if (status) {
55                         list_add(&req->list_pool, pool);
56                         break;
57                 }
58         }
59
60         if (do_tty_wake && port->port.tty)
61                 tty_wakeup(port->port.tty);
62
63         return status;
64 }
65
66 static void dbc_start_rx(struct dbc_port *port)
67         __releases(&port->port_lock)
68         __acquires(&port->port_lock)
69 {
70         struct dbc_request      *req;
71         int                     status;
72         struct list_head        *pool = &port->read_pool;
73
74         while (!list_empty(pool)) {
75                 if (!port->port.tty)
76                         break;
77
78                 req = list_entry(pool->next, struct dbc_request, list_pool);
79                 list_del(&req->list_pool);
80                 req->length = DBC_MAX_PACKET;
81
82                 spin_unlock(&port->port_lock);
83                 status = dbc_ep_queue(port->in, req, GFP_ATOMIC);
84                 spin_lock(&port->port_lock);
85
86                 if (status) {
87                         list_add(&req->list_pool, pool);
88                         break;
89                 }
90         }
91 }
92
93 static void
94 dbc_read_complete(struct xhci_hcd *xhci, struct dbc_request *req)
95 {
96         unsigned long           flags;
97         struct xhci_dbc         *dbc = xhci->dbc;
98         struct dbc_port         *port = &dbc->port;
99
100         spin_lock_irqsave(&port->port_lock, flags);
101         list_add_tail(&req->list_pool, &port->read_queue);
102         tasklet_schedule(&port->push);
103         spin_unlock_irqrestore(&port->port_lock, flags);
104 }
105
106 static void dbc_write_complete(struct xhci_hcd *xhci, struct dbc_request *req)
107 {
108         unsigned long           flags;
109         struct xhci_dbc         *dbc = xhci->dbc;
110         struct dbc_port         *port = &dbc->port;
111
112         spin_lock_irqsave(&port->port_lock, flags);
113         list_add(&req->list_pool, &port->write_pool);
114         switch (req->status) {
115         case 0:
116                 dbc_start_tx(port);
117                 break;
118         case -ESHUTDOWN:
119                 break;
120         default:
121                 xhci_warn(xhci, "unexpected write complete status %d\n",
122                           req->status);
123                 break;
124         }
125         spin_unlock_irqrestore(&port->port_lock, flags);
126 }
127
128 static void xhci_dbc_free_req(struct dbc_ep *dep, struct dbc_request *req)
129 {
130         kfree(req->buf);
131         dbc_free_request(dep, req);
132 }
133
134 static int
135 xhci_dbc_alloc_requests(struct dbc_ep *dep, struct list_head *head,
136                         void (*fn)(struct xhci_hcd *, struct dbc_request *))
137 {
138         int                     i;
139         struct dbc_request      *req;
140
141         for (i = 0; i < DBC_QUEUE_SIZE; i++) {
142                 req = dbc_alloc_request(dep, GFP_ATOMIC);
143                 if (!req)
144                         break;
145
146                 req->length = DBC_MAX_PACKET;
147                 req->buf = kmalloc(req->length, GFP_KERNEL);
148                 if (!req->buf) {
149                         xhci_dbc_free_req(dep, req);
150                         break;
151                 }
152
153                 req->complete = fn;
154                 list_add_tail(&req->list_pool, head);
155         }
156
157         return list_empty(head) ? -ENOMEM : 0;
158 }
159
160 static void
161 xhci_dbc_free_requests(struct dbc_ep *dep, struct list_head *head)
162 {
163         struct dbc_request      *req;
164
165         while (!list_empty(head)) {
166                 req = list_entry(head->next, struct dbc_request, list_pool);
167                 list_del(&req->list_pool);
168                 xhci_dbc_free_req(dep, req);
169         }
170 }
171
172 static int dbc_tty_install(struct tty_driver *driver, struct tty_struct *tty)
173 {
174         struct dbc_port         *port = driver->driver_state;
175
176         tty->driver_data = port;
177
178         return tty_port_install(&port->port, driver, tty);
179 }
180
181 static int dbc_tty_open(struct tty_struct *tty, struct file *file)
182 {
183         struct dbc_port         *port = tty->driver_data;
184
185         return tty_port_open(&port->port, tty, file);
186 }
187
188 static void dbc_tty_close(struct tty_struct *tty, struct file *file)
189 {
190         struct dbc_port         *port = tty->driver_data;
191
192         tty_port_close(&port->port, tty, file);
193 }
194
195 static int dbc_tty_write(struct tty_struct *tty,
196                          const unsigned char *buf,
197                          int count)
198 {
199         struct dbc_port         *port = tty->driver_data;
200         unsigned long           flags;
201
202         spin_lock_irqsave(&port->port_lock, flags);
203         if (count)
204                 count = kfifo_in(&port->write_fifo, buf, count);
205         dbc_start_tx(port);
206         spin_unlock_irqrestore(&port->port_lock, flags);
207
208         return count;
209 }
210
211 static int dbc_tty_put_char(struct tty_struct *tty, unsigned char ch)
212 {
213         struct dbc_port         *port = tty->driver_data;
214         unsigned long           flags;
215         int                     status;
216
217         spin_lock_irqsave(&port->port_lock, flags);
218         status = kfifo_put(&port->write_fifo, ch);
219         spin_unlock_irqrestore(&port->port_lock, flags);
220
221         return status;
222 }
223
224 static void dbc_tty_flush_chars(struct tty_struct *tty)
225 {
226         struct dbc_port         *port = tty->driver_data;
227         unsigned long           flags;
228
229         spin_lock_irqsave(&port->port_lock, flags);
230         dbc_start_tx(port);
231         spin_unlock_irqrestore(&port->port_lock, flags);
232 }
233
234 static int dbc_tty_write_room(struct tty_struct *tty)
235 {
236         struct dbc_port         *port = tty->driver_data;
237         unsigned long           flags;
238         int                     room = 0;
239
240         spin_lock_irqsave(&port->port_lock, flags);
241         room = kfifo_avail(&port->write_fifo);
242         spin_unlock_irqrestore(&port->port_lock, flags);
243
244         return room;
245 }
246
247 static int dbc_tty_chars_in_buffer(struct tty_struct *tty)
248 {
249         struct dbc_port         *port = tty->driver_data;
250         unsigned long           flags;
251         int                     chars = 0;
252
253         spin_lock_irqsave(&port->port_lock, flags);
254         chars = kfifo_len(&port->write_fifo);
255         spin_unlock_irqrestore(&port->port_lock, flags);
256
257         return chars;
258 }
259
260 static void dbc_tty_unthrottle(struct tty_struct *tty)
261 {
262         struct dbc_port         *port = tty->driver_data;
263         unsigned long           flags;
264
265         spin_lock_irqsave(&port->port_lock, flags);
266         tasklet_schedule(&port->push);
267         spin_unlock_irqrestore(&port->port_lock, flags);
268 }
269
270 static const struct tty_operations dbc_tty_ops = {
271         .install                = dbc_tty_install,
272         .open                   = dbc_tty_open,
273         .close                  = dbc_tty_close,
274         .write                  = dbc_tty_write,
275         .put_char               = dbc_tty_put_char,
276         .flush_chars            = dbc_tty_flush_chars,
277         .write_room             = dbc_tty_write_room,
278         .chars_in_buffer        = dbc_tty_chars_in_buffer,
279         .unthrottle             = dbc_tty_unthrottle,
280 };
281
282 static struct tty_driver *dbc_tty_driver;
283
284 int xhci_dbc_tty_register_driver(struct xhci_hcd *xhci)
285 {
286         int                     status;
287         struct xhci_dbc         *dbc = xhci->dbc;
288
289         dbc_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW |
290                                           TTY_DRIVER_DYNAMIC_DEV);
291         if (IS_ERR(dbc_tty_driver)) {
292                 status = PTR_ERR(dbc_tty_driver);
293                 dbc_tty_driver = NULL;
294                 return status;
295         }
296
297         dbc_tty_driver->driver_name = "dbc_serial";
298         dbc_tty_driver->name = "ttyDBC";
299
300         dbc_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
301         dbc_tty_driver->subtype = SERIAL_TYPE_NORMAL;
302         dbc_tty_driver->init_termios = tty_std_termios;
303         dbc_tty_driver->init_termios.c_cflag =
304                         B9600 | CS8 | CREAD | HUPCL | CLOCAL;
305         dbc_tty_driver->init_termios.c_ispeed = 9600;
306         dbc_tty_driver->init_termios.c_ospeed = 9600;
307         dbc_tty_driver->driver_state = &dbc->port;
308
309         tty_set_operations(dbc_tty_driver, &dbc_tty_ops);
310
311         status = tty_register_driver(dbc_tty_driver);
312         if (status) {
313                 xhci_err(xhci,
314                          "can't register dbc tty driver, err %d\n", status);
315                 put_tty_driver(dbc_tty_driver);
316                 dbc_tty_driver = NULL;
317         }
318
319         return status;
320 }
321
322 void xhci_dbc_tty_unregister_driver(void)
323 {
324         if (dbc_tty_driver) {
325                 tty_unregister_driver(dbc_tty_driver);
326                 put_tty_driver(dbc_tty_driver);
327                 dbc_tty_driver = NULL;
328         }
329 }
330
331 static void dbc_rx_push(unsigned long _port)
332 {
333         struct dbc_request      *req;
334         struct tty_struct       *tty;
335         unsigned long           flags;
336         bool                    do_push = false;
337         bool                    disconnect = false;
338         struct dbc_port         *port = (void *)_port;
339         struct list_head        *queue = &port->read_queue;
340
341         spin_lock_irqsave(&port->port_lock, flags);
342         tty = port->port.tty;
343         while (!list_empty(queue)) {
344                 req = list_first_entry(queue, struct dbc_request, list_pool);
345
346                 if (tty && tty_throttled(tty))
347                         break;
348
349                 switch (req->status) {
350                 case 0:
351                         break;
352                 case -ESHUTDOWN:
353                         disconnect = true;
354                         break;
355                 default:
356                         pr_warn("ttyDBC0: unexpected RX status %d\n",
357                                 req->status);
358                         break;
359                 }
360
361                 if (req->actual) {
362                         char            *packet = req->buf;
363                         unsigned int    n, size = req->actual;
364                         int             count;
365
366                         n = port->n_read;
367                         if (n) {
368                                 packet += n;
369                                 size -= n;
370                         }
371
372                         count = tty_insert_flip_string(&port->port, packet,
373                                                        size);
374                         if (count)
375                                 do_push = true;
376                         if (count != size) {
377                                 port->n_read += count;
378                                 break;
379                         }
380                         port->n_read = 0;
381                 }
382
383                 list_move(&req->list_pool, &port->read_pool);
384         }
385
386         if (do_push)
387                 tty_flip_buffer_push(&port->port);
388
389         if (!list_empty(queue) && tty) {
390                 if (!tty_throttled(tty)) {
391                         if (do_push)
392                                 tasklet_schedule(&port->push);
393                         else
394                                 pr_warn("ttyDBC0: RX not scheduled?\n");
395                 }
396         }
397
398         if (!disconnect)
399                 dbc_start_rx(port);
400
401         spin_unlock_irqrestore(&port->port_lock, flags);
402 }
403
404 static int dbc_port_activate(struct tty_port *_port, struct tty_struct *tty)
405 {
406         unsigned long   flags;
407         struct dbc_port *port = container_of(_port, struct dbc_port, port);
408
409         spin_lock_irqsave(&port->port_lock, flags);
410         dbc_start_rx(port);
411         spin_unlock_irqrestore(&port->port_lock, flags);
412
413         return 0;
414 }
415
416 static const struct tty_port_operations dbc_port_ops = {
417         .activate =     dbc_port_activate,
418 };
419
420 static void
421 xhci_dbc_tty_init_port(struct xhci_hcd *xhci, struct dbc_port *port)
422 {
423         tty_port_init(&port->port);
424         spin_lock_init(&port->port_lock);
425         tasklet_init(&port->push, dbc_rx_push, (unsigned long)port);
426         INIT_LIST_HEAD(&port->read_pool);
427         INIT_LIST_HEAD(&port->read_queue);
428         INIT_LIST_HEAD(&port->write_pool);
429
430         port->in =              get_in_ep(xhci);
431         port->out =             get_out_ep(xhci);
432         port->port.ops =        &dbc_port_ops;
433         port->n_read =          0;
434 }
435
436 static void
437 xhci_dbc_tty_exit_port(struct dbc_port *port)
438 {
439         tasklet_kill(&port->push);
440         tty_port_destroy(&port->port);
441 }
442
443 int xhci_dbc_tty_register_device(struct xhci_hcd *xhci)
444 {
445         int                     ret;
446         struct device           *tty_dev;
447         struct xhci_dbc         *dbc = xhci->dbc;
448         struct dbc_port         *port = &dbc->port;
449
450         xhci_dbc_tty_init_port(xhci, port);
451         tty_dev = tty_port_register_device(&port->port,
452                                            dbc_tty_driver, 0, NULL);
453         if (IS_ERR(tty_dev)) {
454                 ret = PTR_ERR(tty_dev);
455                 goto register_fail;
456         }
457
458         ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL);
459         if (ret)
460                 goto buf_alloc_fail;
461
462         ret = xhci_dbc_alloc_requests(port->in, &port->read_pool,
463                                       dbc_read_complete);
464         if (ret)
465                 goto request_fail;
466
467         ret = xhci_dbc_alloc_requests(port->out, &port->write_pool,
468                                       dbc_write_complete);
469         if (ret)
470                 goto request_fail;
471
472         port->registered = true;
473
474         return 0;
475
476 request_fail:
477         xhci_dbc_free_requests(port->in, &port->read_pool);
478         xhci_dbc_free_requests(port->out, &port->write_pool);
479         kfifo_free(&port->write_fifo);
480
481 buf_alloc_fail:
482         tty_unregister_device(dbc_tty_driver, 0);
483
484 register_fail:
485         xhci_dbc_tty_exit_port(port);
486
487         xhci_err(xhci, "can't register tty port, err %d\n", ret);
488
489         return ret;
490 }
491
492 void xhci_dbc_tty_unregister_device(struct xhci_hcd *xhci)
493 {
494         struct xhci_dbc         *dbc = xhci->dbc;
495         struct dbc_port         *port = &dbc->port;
496
497         tty_unregister_device(dbc_tty_driver, 0);
498         xhci_dbc_tty_exit_port(port);
499         port->registered = false;
500
501         kfifo_free(&port->write_fifo);
502         xhci_dbc_free_requests(get_out_ep(xhci), &port->read_pool);
503         xhci_dbc_free_requests(get_out_ep(xhci), &port->read_queue);
504         xhci_dbc_free_requests(get_in_ep(xhci), &port->write_pool);
505 }