xref: /openbmc/linux/drivers/usb/host/xhci-dbgtty.c (revision 74be2d3b)
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_KERNEL);
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 			dbc_free_request(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 }
506