diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-02-16 00:56:49 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-03-20 04:13:10 -0500 |
commit | db33f9bc09aaf68db7866374f9219c676787b4a2 (patch) | |
tree | 4b3bb99778f65966dd1d40122a3fcb2f1f07741c | |
parent | c7f81d42d3d07115a7b92e36ade0f3167f75bc55 (diff) |
[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 <davem@davemloft.net>
-rw-r--r-- | drivers/serial/sunhv.c | 52 |
1 files changed, 36 insertions, 16 deletions
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index cc46206a1065..7f73907db7b6 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 * | |||
136 | 136 | ||
137 | static void transmit_chars(struct uart_port *port) | 137 | static void transmit_chars(struct uart_port *port) |
138 | { | 138 | { |
139 | struct circ_buf *xmit = &port->info->xmit; | 139 | struct circ_buf *xmit; |
140 | |||
141 | if (!port->info) | ||
142 | return; | ||
140 | 143 | ||
144 | xmit = &port->info->xmit; | ||
141 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) | 145 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) |
142 | return; | 146 | return; |
143 | 147 | ||
@@ -452,8 +456,6 @@ static unsigned int __init get_interrupt(void) | |||
452 | return sun4v_vdev_device_interrupt(node); | 456 | return sun4v_vdev_device_interrupt(node); |
453 | } | 457 | } |
454 | 458 | ||
455 | static u32 sunhv_irq; | ||
456 | |||
457 | static int __init sunhv_init(void) | 459 | static int __init sunhv_init(void) |
458 | { | 460 | { |
459 | struct uart_port *port; | 461 | struct uart_port *port; |
@@ -462,35 +464,33 @@ static int __init sunhv_init(void) | |||
462 | if (tlb_type != hypervisor) | 464 | if (tlb_type != hypervisor) |
463 | return -ENODEV; | 465 | return -ENODEV; |
464 | 466 | ||
465 | sunhv_irq = get_interrupt(); | ||
466 | if (!sunhv_irq) | ||
467 | return -ENODEV; | ||
468 | |||
469 | port = kmalloc(sizeof(struct uart_port), GFP_KERNEL); | 467 | port = kmalloc(sizeof(struct uart_port), GFP_KERNEL); |
470 | if (unlikely(!port)) | 468 | if (unlikely(!port)) |
471 | return -ENOMEM; | 469 | return -ENOMEM; |
472 | 470 | ||
471 | memset(port, 0, sizeof(struct uart_port)); | ||
472 | |||
473 | port->line = 0; | 473 | port->line = 0; |
474 | port->ops = &sunhv_pops; | 474 | port->ops = &sunhv_pops; |
475 | port->type = PORT_SUNHV; | 475 | port->type = PORT_SUNHV; |
476 | port->uartclk = ( 29491200 / 16 ); /* arbitrary */ | 476 | port->uartclk = ( 29491200 / 16 ); /* arbitrary */ |
477 | 477 | ||
478 | if (request_irq(sunhv_irq, sunhv_interrupt, | 478 | /* Set this just to make uart_configure_port() happy. */ |
479 | SA_SHIRQ, "serial(sunhv)", port)) { | 479 | port->membase = (unsigned char __iomem *) __pa(port); |
480 | printk("sunhv: Cannot get IRQ %x\n", sunhv_irq); | 480 | |
481 | port->irq = get_interrupt(); | ||
482 | if (!port->irq) { | ||
481 | kfree(port); | 483 | kfree(port); |
482 | return -ENODEV; | 484 | return -ENODEV; |
483 | } | 485 | } |
484 | 486 | ||
485 | printk("SUNHV: SUN4V virtual console, IRQ %s\n", | ||
486 | __irq_itoa(sunhv_irq)); | ||
487 | |||
488 | sunhv_reg.minor = sunserial_current_minor; | 487 | sunhv_reg.minor = sunserial_current_minor; |
489 | sunhv_reg.nr = 1; | 488 | sunhv_reg.nr = 1; |
490 | 489 | ||
491 | ret = uart_register_driver(&sunhv_reg); | 490 | ret = uart_register_driver(&sunhv_reg); |
492 | if (ret < 0) { | 491 | if (ret < 0) { |
493 | free_irq(sunhv_irq, up); | 492 | printk(KERN_ERR "SUNHV: uart_register_driver() failed %d\n", |
493 | ret); | ||
494 | kfree(port); | 494 | kfree(port); |
495 | 495 | ||
496 | return ret; | 496 | return ret; |
@@ -502,7 +502,26 @@ static int __init sunhv_init(void) | |||
502 | 502 | ||
503 | sunhv_port = port; | 503 | sunhv_port = port; |
504 | 504 | ||
505 | uart_add_one_port(&sunhv_reg, port); | 505 | ret = uart_add_one_port(&sunhv_reg, port); |
506 | if (ret < 0) { | ||
507 | printk(KERN_ERR "SUNHV: uart_add_one_port() failed %d\n", ret); | ||
508 | sunserial_current_minor -= 1; | ||
509 | uart_unregister_driver(&sunhv_reg); | ||
510 | kfree(port); | ||
511 | sunhv_port = NULL; | ||
512 | return -ENODEV; | ||
513 | } | ||
514 | |||
515 | if (request_irq(port->irq, sunhv_interrupt, | ||
516 | SA_SHIRQ, "serial(sunhv)", port)) { | ||
517 | printk(KERN_ERR "sunhv: Cannot register IRQ\n"); | ||
518 | uart_remove_one_port(&sunhv_reg, port); | ||
519 | sunserial_current_minor -= 1; | ||
520 | uart_unregister_driver(&sunhv_reg); | ||
521 | kfree(port); | ||
522 | sunhv_port = NULL; | ||
523 | return -ENODEV; | ||
524 | } | ||
506 | 525 | ||
507 | return 0; | 526 | return 0; |
508 | } | 527 | } |
@@ -513,8 +532,9 @@ static void __exit sunhv_exit(void) | |||
513 | 532 | ||
514 | BUG_ON(!port); | 533 | BUG_ON(!port); |
515 | 534 | ||
535 | free_irq(port->irq, port); | ||
536 | |||
516 | uart_remove_one_port(&sunhv_reg, port); | 537 | uart_remove_one_port(&sunhv_reg, port); |
517 | free_irq(sunhv_irq, port); | ||
518 | sunserial_current_minor -= 1; | 538 | sunserial_current_minor -= 1; |
519 | 539 | ||
520 | uart_unregister_driver(&sunhv_reg); | 540 | uart_unregister_driver(&sunhv_reg); |