The patch below does not apply to the 5.15-stable tree. If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to stable@vger.kernel.org.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y git checkout FETCH_HEAD git cherry-pick -x 1f73b8b56cf35de29a433aee7bfff26cea98be3f # <resolve conflicts, build, test, etc.> git commit -s git send-email --to 'stable@vger.kernel.org' --in-reply-to '2025120110-deuce-arrange-e66c@gregkh' --subject-prefix 'PATCH 5.15.y' HEAD^..
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 1f73b8b56cf35de29a433aee7bfff26cea98be3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Bartosik?= ukaszb@chromium.org Date: Wed, 19 Nov 2025 21:29:09 +0000 Subject: [PATCH] xhci: dbgtty: fix device unregister MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit
When DbC is disconnected then xhci_dbc_tty_unregister_device() is called. However if there is any user space process blocked on write to DbC terminal device then it will never be signalled and thus stay blocked indifinitely.
This fix adds a tty_vhangup() call in xhci_dbc_tty_unregister_device(). The tty_vhangup() wakes up any blocked writers and causes subsequent write attempts to DbC terminal device to fail.
Cc: stable stable@kernel.org Fixes: dfba2174dc42 ("usb: xhci: Add DbC support in xHCI driver") Signed-off-by: Łukasz Bartosik ukaszb@chromium.org Link: https://patch.msgid.link/20251119212910.1245694-1-ukaszb@google.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index b7f95565524d..57cdda4e09c8 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -550,6 +550,12 @@ static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc)
if (!port->registered) return; + /* + * Hang up the TTY. This wakes up any blocked + * writers and causes subsequent writes to fail. + */ + tty_vhangup(port->port.tty); + tty_unregister_device(dbc_tty_driver, port->minor); xhci_dbc_tty_exit_port(port); port->registered = false;
From: Mathias Nyman mathias.nyman@linux.intel.com
[ Upstream commit e1ec140f273e1e30cea7e6d5f50934d877232121 ]
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... Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Stable-dep-of: 1f73b8b56cf3 ("xhci: dbgtty: fix device unregister") Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/usb/host/xhci-dbgcap.h | 1 + drivers/usb/host/xhci-dbgtty.c | 46 ++++++++++++++++++++++++++++------ 2 files changed, 40 insertions(+), 7 deletions(-)
diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h index 5109ea3c51da0..98e7331ca0951 100644 --- a/drivers/usb/host/xhci-dbgcap.h +++ b/drivers/usb/host/xhci-dbgcap.h @@ -102,6 +102,7 @@ struct dbc_ep { struct dbc_port { struct tty_port port; spinlock_t port_lock; /* port access */ + int minor;
struct list_head read_pool; struct list_head read_queue; diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index f1387161b32da..20e50e559c2a2 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -10,6 +10,7 @@ #include <linux/slab.h> #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/idr.h>
#include "xhci.h" #include "xhci-dbgcap.h" @@ -18,6 +19,8 @@ static int dbc_tty_init(void); static void dbc_tty_exit(void);
static struct tty_driver *dbc_tty_driver; +static struct idr dbc_tty_minors; +static DEFINE_MUTEX(dbc_tty_minors_lock);
static inline struct dbc_port *dbc_to_port(struct xhci_dbc *dbc) { @@ -195,7 +198,14 @@ xhci_dbc_free_requests(struct list_head *head)
static int dbc_tty_install(struct tty_driver *driver, struct tty_struct *tty) { - struct dbc_port *port = driver->driver_state; + struct dbc_port *port; + + mutex_lock(&dbc_tty_minors_lock); + port = idr_find(&dbc_tty_minors, tty->index); + mutex_unlock(&dbc_tty_minors_lock); + + if (!port) + return -ENXIO;
tty->driver_data = port;
@@ -424,6 +434,15 @@ static int xhci_dbc_tty_register_device(struct xhci_dbc *dbc)
xhci_dbc_tty_init_port(dbc, port);
+ mutex_lock(&dbc_tty_minors_lock); + port->minor = idr_alloc(&dbc_tty_minors, port, 0, 64, GFP_KERNEL); + mutex_unlock(&dbc_tty_minors_lock); + + if (port->minor < 0) { + ret = port->minor; + goto err_idr; + } + ret = kfifo_alloc(&port->write_fifo, DBC_WRITE_BUF_SIZE, GFP_KERNEL); if (ret) goto err_exit_port; @@ -439,7 +458,7 @@ static int xhci_dbc_tty_register_device(struct xhci_dbc *dbc) goto err_free_requests;
tty_dev = tty_port_register_device(&port->port, - dbc_tty_driver, 0, NULL); + dbc_tty_driver, port->minor, NULL); if (IS_ERR(tty_dev)) { ret = PTR_ERR(tty_dev); goto err_free_requests; @@ -455,6 +474,8 @@ static int xhci_dbc_tty_register_device(struct xhci_dbc *dbc) err_free_fifo: kfifo_free(&port->write_fifo); err_exit_port: + idr_remove(&dbc_tty_minors, port->minor); +err_idr: xhci_dbc_tty_exit_port(port);
dev_err(dbc->dev, "can't register tty port, err %d\n", ret); @@ -468,10 +489,14 @@ static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc)
if (!port->registered) return; - tty_unregister_device(dbc_tty_driver, 0); + tty_unregister_device(dbc_tty_driver, port->minor); xhci_dbc_tty_exit_port(port); port->registered = false;
+ mutex_lock(&dbc_tty_minors_lock); + idr_remove(&dbc_tty_minors, port->minor); + mutex_unlock(&dbc_tty_minors_lock); + kfifo_free(&port->write_fifo); xhci_dbc_free_requests(&port->read_pool); xhci_dbc_free_requests(&port->read_queue); @@ -500,9 +525,8 @@ int xhci_dbc_tty_probe(struct device *dev, void __iomem *base, struct xhci_hcd * goto out; }
- dbc_tty_driver->driver_state = port; - dbc = xhci_alloc_dbc(dev, base, &dbc_driver); + if (!dbc) { status = -ENOMEM; goto out2; @@ -541,10 +565,14 @@ static int dbc_tty_init(void) { int ret;
- dbc_tty_driver = tty_alloc_driver(1, TTY_DRIVER_REAL_RAW | + idr_init(&dbc_tty_minors); + + dbc_tty_driver = tty_alloc_driver(64, TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV); - if (IS_ERR(dbc_tty_driver)) + if (IS_ERR(dbc_tty_driver)) { + idr_destroy(&dbc_tty_minors); return PTR_ERR(dbc_tty_driver); + }
dbc_tty_driver->driver_name = "dbc_serial"; dbc_tty_driver->name = "ttyDBC"; @@ -564,7 +592,9 @@ static int dbc_tty_init(void) if (ret) { pr_err("Can't register dbc tty driver\n"); tty_driver_kref_put(dbc_tty_driver); + idr_destroy(&dbc_tty_minors); } + return ret; }
@@ -575,4 +605,6 @@ static void dbc_tty_exit(void) tty_driver_kref_put(dbc_tty_driver); dbc_tty_driver = NULL; } + + idr_destroy(&dbc_tty_minors); }
From: Łukasz Bartosik ukaszb@chromium.org
[ Upstream commit 1f73b8b56cf35de29a433aee7bfff26cea98be3f ]
When DbC is disconnected then xhci_dbc_tty_unregister_device() is called. However if there is any user space process blocked on write to DbC terminal device then it will never be signalled and thus stay blocked indifinitely.
This fix adds a tty_vhangup() call in xhci_dbc_tty_unregister_device(). The tty_vhangup() wakes up any blocked writers and causes subsequent write attempts to DbC terminal device to fail.
Cc: stable stable@kernel.org Fixes: dfba2174dc42 ("usb: xhci: Add DbC support in xHCI driver") Signed-off-by: Łukasz Bartosik ukaszb@chromium.org Link: https://patch.msgid.link/20251119212910.1245694-1-ukaszb@google.com Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/usb/host/xhci-dbgtty.c | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index 20e50e559c2a2..32f8c3d40fb0c 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -489,6 +489,12 @@ static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc)
if (!port->registered) return; + /* + * Hang up the TTY. This wakes up any blocked + * writers and causes subsequent writes to fail. + */ + tty_vhangup(port->port.tty); + tty_unregister_device(dbc_tty_driver, port->minor); xhci_dbc_tty_exit_port(port); port->registered = false;
linux-stable-mirror@lists.linaro.org