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

xhci: dbgtty: use IDR to support several dbc instances.

To support systems with several xhci controllers with active
dbc on each xhci we need to use IDR to identify and give
an index to each port.

Avoid using global struct tty_driver.driver_state for storing
dbc port pointer as it won't work with several dbc ports

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20220216095153.1303105-6-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Mathias Nyman and committed by
Greg Kroah-Hartman
e1ec140f 6aec5000

+40 -7
+1
drivers/usb/host/xhci-dbgcap.h
··· 100 100 struct dbc_port { 101 101 struct tty_port port; 102 102 spinlock_t port_lock; /* port access */ 103 + int minor; 103 104 104 105 struct list_head read_pool; 105 106 struct list_head read_queue;
+39 -7
drivers/usb/host/xhci-dbgtty.c
··· 10 10 #include <linux/slab.h> 11 11 #include <linux/tty.h> 12 12 #include <linux/tty_flip.h> 13 + #include <linux/idr.h> 13 14 14 15 #include "xhci.h" 15 16 #include "xhci-dbgcap.h" 16 17 17 18 static struct tty_driver *dbc_tty_driver; 19 + static struct idr dbc_tty_minors; 20 + static DEFINE_MUTEX(dbc_tty_minors_lock); 18 21 19 22 static inline struct dbc_port *dbc_to_port(struct xhci_dbc *dbc) 20 23 { ··· 180 177 181 178 static int dbc_tty_install(struct tty_driver *driver, struct tty_struct *tty) 182 179 { 183 - struct dbc_port *port = driver->driver_state; 180 + struct dbc_port *port; 181 + 182 + mutex_lock(&dbc_tty_minors_lock); 183 + port = idr_find(&dbc_tty_minors, tty->index); 184 + mutex_unlock(&dbc_tty_minors_lock); 185 + 186 + if (!port) 187 + return -ENXIO; 184 188 185 189 tty->driver_data = port; 186 190 ··· 416 406 417 407 xhci_dbc_tty_init_port(dbc, port); 418 408 409 + mutex_lock(&dbc_tty_minors_lock); 410 + port->minor = idr_alloc(&dbc_tty_minors, port, 0, 64, GFP_KERNEL); 411 + mutex_unlock(&dbc_tty_minors_lock); 412 + 413 + if (port->minor < 0) { 414 + ret = port->minor; 415 + goto err_idr; 416 + } 417 + 419 418 ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL); 420 419 if (ret) 421 420 goto err_exit_port; ··· 440 421 goto err_free_requests; 441 422 442 423 tty_dev = tty_port_register_device(&port->port, 443 - dbc_tty_driver, 0, NULL); 424 + dbc_tty_driver, port->minor, NULL); 444 425 if (IS_ERR(tty_dev)) { 445 426 ret = PTR_ERR(tty_dev); 446 427 goto err_free_requests; ··· 456 437 err_free_fifo: 457 438 kfifo_free(&port->write_fifo); 458 439 err_exit_port: 440 + idr_remove(&dbc_tty_minors, port->minor); 441 + err_idr: 459 442 xhci_dbc_tty_exit_port(port); 460 443 461 444 dev_err(dbc->dev, "can't register tty port, err %d\n", ret); ··· 471 450 472 451 if (!port->registered) 473 452 return; 474 - tty_unregister_device(dbc_tty_driver, 0); 453 + tty_unregister_device(dbc_tty_driver, port->minor); 475 454 xhci_dbc_tty_exit_port(port); 476 455 port->registered = false; 456 + 457 + mutex_lock(&dbc_tty_minors_lock); 458 + idr_remove(&dbc_tty_minors, port->minor); 459 + mutex_unlock(&dbc_tty_minors_lock); 477 460 478 461 kfifo_free(&port->write_fifo); 479 462 xhci_dbc_free_requests(&port->read_pool); ··· 503 478 if (!port) 504 479 return -ENOMEM; 505 480 506 - dbc_tty_driver->driver_state = port; 507 - 508 481 dbc = xhci_alloc_dbc(dev, base, &dbc_driver); 482 + 509 483 if (!dbc) { 510 484 status = -ENOMEM; 511 485 goto out2; ··· 538 514 { 539 515 int ret; 540 516 541 - dbc_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW | 517 + idr_init(&dbc_tty_minors); 518 + 519 + dbc_tty_driver = tty_alloc_driver(64, TTY_DRIVER_REAL_RAW | 542 520 TTY_DRIVER_DYNAMIC_DEV); 543 - if (IS_ERR(dbc_tty_driver)) 521 + if (IS_ERR(dbc_tty_driver)) { 522 + idr_destroy(&dbc_tty_minors); 544 523 return PTR_ERR(dbc_tty_driver); 524 + } 545 525 546 526 dbc_tty_driver->driver_name = "dbc_serial"; 547 527 dbc_tty_driver->name = "ttyDBC"; ··· 564 536 if (ret) { 565 537 pr_err("Can't register dbc tty driver\n"); 566 538 tty_driver_kref_put(dbc_tty_driver); 539 + idr_destroy(&dbc_tty_minors); 567 540 } 541 + 568 542 return ret; 569 543 } 570 544 ··· 577 547 tty_driver_kref_put(dbc_tty_driver); 578 548 dbc_tty_driver = NULL; 579 549 } 550 + 551 + idr_destroy(&dbc_tty_minors); 580 552 }