From db33f9bc09aaf68db7866374f9219c676787b4a2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 15 Feb 2006 21:56:49 -0800 Subject: [PATCH] [SPARC64]: Fix OOPS on sunhv interrupts. Until the uart is openned, port->info is NULL. Also, init the port->irq properly and give a non-zero port->membase so that the uart device reporting is done. Signed-off-by: David S. Miller --- drivers/serial/sunhv.c | 52 +++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index cc46206a10..7f73907db7 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -136,8 +136,12 @@ static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs * static void transmit_chars(struct uart_port *port) { - struct circ_buf *xmit = &port->info->xmit; + struct circ_buf *xmit; + + if (!port->info) + return; + xmit = &port->info->xmit; if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return; @@ -452,8 +456,6 @@ static unsigned int __init get_interrupt(void) return sun4v_vdev_device_interrupt(node); } -static u32 sunhv_irq; - static int __init sunhv_init(void) { struct uart_port *port; @@ -462,35 +464,33 @@ static int __init sunhv_init(void) if (tlb_type != hypervisor) return -ENODEV; - sunhv_irq = get_interrupt(); - if (!sunhv_irq) - return -ENODEV; - port = kmalloc(sizeof(struct uart_port), GFP_KERNEL); if (unlikely(!port)) return -ENOMEM; + memset(port, 0, sizeof(struct uart_port)); + port->line = 0; port->ops = &sunhv_pops; port->type = PORT_SUNHV; port->uartclk = ( 29491200 / 16 ); /* arbitrary */ - if (request_irq(sunhv_irq, sunhv_interrupt, - SA_SHIRQ, "serial(sunhv)", port)) { - printk("sunhv: Cannot get IRQ %x\n", sunhv_irq); + /* Set this just to make uart_configure_port() happy. */ + port->membase = (unsigned char __iomem *) __pa(port); + + port->irq = get_interrupt(); + if (!port->irq) { kfree(port); return -ENODEV; } - printk("SUNHV: SUN4V virtual console, IRQ %s\n", - __irq_itoa(sunhv_irq)); - sunhv_reg.minor = sunserial_current_minor; sunhv_reg.nr = 1; ret = uart_register_driver(&sunhv_reg); if (ret < 0) { - free_irq(sunhv_irq, up); + printk(KERN_ERR "SUNHV: uart_register_driver() failed %d\n", + ret); kfree(port); return ret; @@ -502,7 +502,26 @@ static int __init sunhv_init(void) sunhv_port = port; - uart_add_one_port(&sunhv_reg, port); + ret = uart_add_one_port(&sunhv_reg, port); + if (ret < 0) { + printk(KERN_ERR "SUNHV: uart_add_one_port() failed %d\n", ret); + sunserial_current_minor -= 1; + uart_unregister_driver(&sunhv_reg); + kfree(port); + sunhv_port = NULL; + return -ENODEV; + } + + if (request_irq(port->irq, sunhv_interrupt, + SA_SHIRQ, "serial(sunhv)", port)) { + printk(KERN_ERR "sunhv: Cannot register IRQ\n"); + uart_remove_one_port(&sunhv_reg, port); + sunserial_current_minor -= 1; + uart_unregister_driver(&sunhv_reg); + kfree(port); + sunhv_port = NULL; + return -ENODEV; + } return 0; } @@ -513,8 +532,9 @@ static void __exit sunhv_exit(void) BUG_ON(!port); + free_irq(port->irq, port); + uart_remove_one_port(&sunhv_reg, port); - free_irq(sunhv_irq, port); sunserial_current_minor -= 1; uart_unregister_driver(&sunhv_reg); -- 2.39.5