Commit 9f9ed67c authored by Russell King's avatar Russell King

[SERIAL] Fix deadlock on removal of 8250 module.

We must unregister all serial ports before driver_unregister()
can complete.  This means that we must unregister all ports in
serial8250_remove, including our legacy ISA ports.  We flag this
special cleanup operation by setting serial8250_isa_devs to NULL
and not handling our own platform device any differently from
any others.
parent 08e08e08
...@@ -2205,21 +2205,17 @@ static int __devinit serial8250_probe(struct device *dev) ...@@ -2205,21 +2205,17 @@ static int __devinit serial8250_probe(struct device *dev)
} }
/* /*
* Remove a platform device. We only remove serial ports from this * Remove serial ports registered against a platform device.
* platform device if it actually added any in the first place (iow,
* dev->platform_data is non-NULL.)
*/ */
static int __devexit serial8250_remove(struct device *dev) static int __devexit serial8250_remove(struct device *dev)
{ {
int i; int i;
if (dev->platform_data) { for (i = 0; i < UART_NR; i++) {
for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = &serial8250_ports[i];
struct uart_8250_port *up = &serial8250_ports[i];
if (up->port.dev == dev) if (up->port.dev == dev)
serial8250_unregister_port(i); serial8250_unregister_port(i);
}
} }
return 0; return 0;
} }
...@@ -2394,10 +2390,14 @@ void serial8250_unregister_port(int line) ...@@ -2394,10 +2390,14 @@ void serial8250_unregister_port(int line)
down(&serial_sem); down(&serial_sem);
uart_remove_one_port(&serial8250_reg, &uart->port); uart_remove_one_port(&serial8250_reg, &uart->port);
uart->port.flags &= ~UPF_BOOT_AUTOCONF; if (serial8250_isa_devs) {
uart->port.type = PORT_UNKNOWN; uart->port.flags &= ~UPF_BOOT_AUTOCONF;
uart->port.dev = &serial8250_isa_devs->dev; uart->port.type = PORT_UNKNOWN;
uart_add_one_port(&serial8250_reg, &uart->port); uart->port.dev = &serial8250_isa_devs->dev;
uart_add_one_port(&serial8250_reg, &uart->port);
} else {
uart->port.dev = NULL;
}
up(&serial_sem); up(&serial_sem);
} }
EXPORT_SYMBOL(serial8250_unregister_port); EXPORT_SYMBOL(serial8250_unregister_port);
...@@ -2439,17 +2439,18 @@ static int __init serial8250_init(void) ...@@ -2439,17 +2439,18 @@ static int __init serial8250_init(void)
static void __exit serial8250_exit(void) static void __exit serial8250_exit(void)
{ {
struct platform_device *isa_dev = serial8250_isa_devs;
int i; int i;
driver_unregister(&serial8250_isa_driver); /*
* This tells serial8250_unregister_port() not to re-register
for (i = 0; i < UART_NR; i++) { * the ports (thereby making serial8250_isa_driver permanently
struct uart_8250_port *up = &serial8250_ports[i]; * in use.)
if (up->port.dev == &serial8250_isa_devs->dev) */
uart_remove_one_port(&serial8250_reg, &up->port); serial8250_isa_devs = NULL;
}
platform_device_unregister(serial8250_isa_devs); driver_unregister(&serial8250_isa_driver);
platform_device_unregister(isa_dev);
uart_unregister_driver(&serial8250_reg); uart_unregister_driver(&serial8250_reg);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment