tty: n_smux: Add support for ldisc removal during SSR
If subsystem restart (SSR) is in progress and the line discipline is
removed, then the platform devices may get removed twice leading to a
kernel panic.
Add conditional logic to properly handle platform device removal if line
discipline is removed while a subsystem restart is in progress.
CRs-Fixed: 386491
Change-Id: I1ddc89175509e333098f849b0f76e09660644573
Signed-off-by: Eric Holmberg <eholmber@codeaurora.org>
diff --git a/drivers/tty/n_smux.c b/drivers/tty/n_smux.c
index 32e52d0..1385e08 100644
--- a/drivers/tty/n_smux.c
+++ b/drivers/tty/n_smux.c
@@ -274,6 +274,7 @@
struct mutex mutex_lha0;
int is_initialized;
+ int platform_devs_registered;
int in_reset;
int ld_open_count;
struct tty_struct *tty;
@@ -3377,14 +3378,18 @@
/* re-register platform devices */
SMUX_DBG("%s: ssr - after power-up\n", __func__);
mutex_lock(&smux.mutex_lha0);
- for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
- SMUX_DBG("%s: register pdev '%s'\n",
+ if (smux.ld_open_count > 0
+ && !smux.platform_devs_registered) {
+ for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+ SMUX_DBG("%s: register pdev '%s'\n",
__func__, smux_devs[i].name);
- smux_devs[i].dev.release = smux_pdev_release;
- tmp = platform_device_register(&smux_devs[i]);
- if (tmp)
- pr_err("%s: error %d registering device %s\n",
+ smux_devs[i].dev.release = smux_pdev_release;
+ tmp = platform_device_register(&smux_devs[i]);
+ if (tmp)
+ pr_err("%s: error %d registering device %s\n",
__func__, tmp, smux_devs[i].name);
+ }
+ smux.platform_devs_registered = 1;
}
mutex_unlock(&smux.mutex_lha0);
return NOTIFY_DONE;
@@ -3396,30 +3401,34 @@
/* Cleanup channels */
smux_flush_workqueues();
mutex_lock(&smux.mutex_lha0);
- smux_lch_purge();
- if (smux.tty)
- tty_driver_flush_buffer(smux.tty);
+ if (smux.ld_open_count > 0) {
+ smux_lch_purge();
+ if (smux.tty)
+ tty_driver_flush_buffer(smux.tty);
- /* Unregister platform devices */
- for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
- SMUX_DBG("%s: unregister pdev '%s'\n",
- __func__, smux_devs[i].name);
- platform_device_unregister(&smux_devs[i]);
+ /* Unregister platform devices */
+ if (smux.platform_devs_registered) {
+ for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+ SMUX_DBG("%s: unregister pdev '%s'\n",
+ __func__, smux_devs[i].name);
+ platform_device_unregister(&smux_devs[i]);
+ }
+ smux.platform_devs_registered = 0;
+ }
+
+ /* Power-down UART */
+ spin_lock_irqsave(&smux.tx_lock_lha2, flags);
+ if (smux.power_state != SMUX_PWR_OFF) {
+ SMUX_PWR("%s: SSR - turning off UART\n", __func__);
+ smux.power_state = SMUX_PWR_OFF;
+ power_off_uart = 1;
+ }
+ smux.powerdown_enabled = 0;
+ spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
+
+ if (power_off_uart)
+ smux_uart_power_off_atomic();
}
-
- /* Power-down UART */
- spin_lock_irqsave(&smux.tx_lock_lha2, flags);
- if (smux.power_state != SMUX_PWR_OFF) {
- SMUX_PWR("%s: SSR - turning off UART\n", __func__);
- smux.power_state = SMUX_PWR_OFF;
- power_off_uart = 1;
- }
- smux.powerdown_enabled = 0;
- spin_unlock_irqrestore(&smux.tx_lock_lha2, flags);
-
- if (power_off_uart)
- smux_uart_power_off_atomic();
-
smux.tx_activity_flag = 0;
smux.rx_activity_flag = 0;
smux.rx_state = SMUX_RX_IDLE;
@@ -3493,6 +3502,7 @@
pr_err("%s: error %d registering device %s\n",
__func__, tmp, smux_devs[i].name);
}
+ smux.platform_devs_registered = 1;
mutex_unlock(&smux.mutex_lha0);
return 0;
}
@@ -3519,10 +3529,13 @@
smux_lch_purge();
/* Unregister platform devices */
- for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
- SMUX_DBG("%s: unregister pdev '%s'\n",
- __func__, smux_devs[i].name);
- platform_device_unregister(&smux_devs[i]);
+ if (smux.platform_devs_registered) {
+ for (i = 0; i < ARRAY_SIZE(smux_devs); ++i) {
+ SMUX_DBG("%s: unregister pdev '%s'\n",
+ __func__, smux_devs[i].name);
+ platform_device_unregister(&smux_devs[i]);
+ }
+ smux.platform_devs_registered = 0;
}
/* Schedule UART power-up if it's down */
@@ -3668,6 +3681,7 @@
smux.ld_open_count = 0;
smux.in_reset = 0;
smux.is_initialized = 1;
+ smux.platform_devs_registered = 0;
smux_byte_loopback = 0;
spin_lock_init(&smux.tx_lock_lha2);