diff options
Diffstat (limited to 'arch/powerpc/platforms/powernv/opal.c')
-rw-r--r-- | arch/powerpc/platforms/powernv/opal.c | 72 |
1 files changed, 50 insertions, 22 deletions
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c index f10b9ec8c1f5..18fd4e71c9c1 100644 --- a/arch/powerpc/platforms/powernv/opal.c +++ b/arch/powerpc/platforms/powernv/opal.c | |||
@@ -208,7 +208,7 @@ static int __init opal_register_exception_handlers(void) | |||
208 | * start catching/handling HMI directly in Linux. | 208 | * start catching/handling HMI directly in Linux. |
209 | */ | 209 | */ |
210 | if (!opal_check_token(OPAL_HANDLE_HMI)) { | 210 | if (!opal_check_token(OPAL_HANDLE_HMI)) { |
211 | pr_info("opal: Old firmware detected, OPAL handles HMIs.\n"); | 211 | pr_info("Old firmware detected, OPAL handles HMIs.\n"); |
212 | opal_register_exception_handler( | 212 | opal_register_exception_handler( |
213 | OPAL_HYPERVISOR_MAINTENANCE_HANDLER, | 213 | OPAL_HYPERVISOR_MAINTENANCE_HANDLER, |
214 | 0, glue); | 214 | 0, glue); |
@@ -667,7 +667,13 @@ static void __init opal_dump_region_init(void) | |||
667 | 667 | ||
668 | /* Register kernel log buffer */ | 668 | /* Register kernel log buffer */ |
669 | addr = log_buf_addr_get(); | 669 | addr = log_buf_addr_get(); |
670 | if (addr == NULL) | ||
671 | return; | ||
672 | |||
670 | size = log_buf_len_get(); | 673 | size = log_buf_len_get(); |
674 | if (size == 0) | ||
675 | return; | ||
676 | |||
671 | rc = opal_register_dump_region(OPAL_DUMP_REGION_LOG_BUF, | 677 | rc = opal_register_dump_region(OPAL_DUMP_REGION_LOG_BUF, |
672 | __pa(addr), size); | 678 | __pa(addr), size); |
673 | /* Don't warn if this is just an older OPAL that doesn't | 679 | /* Don't warn if this is just an older OPAL that doesn't |
@@ -695,15 +701,54 @@ static void opal_i2c_create_devs(void) | |||
695 | of_platform_device_create(np, NULL, NULL); | 701 | of_platform_device_create(np, NULL, NULL); |
696 | } | 702 | } |
697 | 703 | ||
704 | static void __init opal_irq_init(struct device_node *dn) | ||
705 | { | ||
706 | const __be32 *irqs; | ||
707 | int i, irqlen; | ||
708 | |||
709 | /* Get interrupt property */ | ||
710 | irqs = of_get_property(opal_node, "opal-interrupts", &irqlen); | ||
711 | opal_irq_count = irqs ? (irqlen / 4) : 0; | ||
712 | pr_debug("Found %d interrupts reserved for OPAL\n", opal_irq_count); | ||
713 | if (!opal_irq_count) | ||
714 | return; | ||
715 | |||
716 | /* Install interrupt handlers */ | ||
717 | opal_irqs = kzalloc(opal_irq_count * sizeof(unsigned int), GFP_KERNEL); | ||
718 | for (i = 0; irqs && i < opal_irq_count; i++, irqs++) { | ||
719 | unsigned int irq, virq; | ||
720 | int rc; | ||
721 | |||
722 | /* Get hardware and virtual IRQ */ | ||
723 | irq = be32_to_cpup(irqs); | ||
724 | virq = irq_create_mapping(NULL, irq); | ||
725 | if (virq == NO_IRQ) { | ||
726 | pr_warn("Failed to map irq 0x%x\n", irq); | ||
727 | continue; | ||
728 | } | ||
729 | |||
730 | /* Install interrupt handler */ | ||
731 | rc = request_irq(virq, opal_interrupt, 0, "opal", NULL); | ||
732 | if (rc) { | ||
733 | irq_dispose_mapping(virq); | ||
734 | pr_warn("Error %d requesting irq %d (0x%x)\n", | ||
735 | rc, virq, irq); | ||
736 | continue; | ||
737 | } | ||
738 | |||
739 | /* Cache IRQ */ | ||
740 | opal_irqs[i] = virq; | ||
741 | } | ||
742 | } | ||
743 | |||
698 | static int __init opal_init(void) | 744 | static int __init opal_init(void) |
699 | { | 745 | { |
700 | struct device_node *np, *consoles; | 746 | struct device_node *np, *consoles; |
701 | const __be32 *irqs; | 747 | int rc; |
702 | int rc, i, irqlen; | ||
703 | 748 | ||
704 | opal_node = of_find_node_by_path("/ibm,opal"); | 749 | opal_node = of_find_node_by_path("/ibm,opal"); |
705 | if (!opal_node) { | 750 | if (!opal_node) { |
706 | pr_warn("opal: Node not found\n"); | 751 | pr_warn("Device node not found\n"); |
707 | return -ENODEV; | 752 | return -ENODEV; |
708 | } | 753 | } |
709 | 754 | ||
@@ -725,24 +770,7 @@ static int __init opal_init(void) | |||
725 | opal_i2c_create_devs(); | 770 | opal_i2c_create_devs(); |
726 | 771 | ||
727 | /* Find all OPAL interrupts and request them */ | 772 | /* Find all OPAL interrupts and request them */ |
728 | irqs = of_get_property(opal_node, "opal-interrupts", &irqlen); | 773 | opal_irq_init(opal_node); |
729 | pr_debug("opal: Found %d interrupts reserved for OPAL\n", | ||
730 | irqs ? (irqlen / 4) : 0); | ||
731 | opal_irq_count = irqlen / 4; | ||
732 | opal_irqs = kzalloc(opal_irq_count * sizeof(unsigned int), GFP_KERNEL); | ||
733 | for (i = 0; irqs && i < (irqlen / 4); i++, irqs++) { | ||
734 | unsigned int hwirq = be32_to_cpup(irqs); | ||
735 | unsigned int irq = irq_create_mapping(NULL, hwirq); | ||
736 | if (irq == NO_IRQ) { | ||
737 | pr_warning("opal: Failed to map irq 0x%x\n", hwirq); | ||
738 | continue; | ||
739 | } | ||
740 | rc = request_irq(irq, opal_interrupt, 0, "opal", NULL); | ||
741 | if (rc) | ||
742 | pr_warning("opal: Error %d requesting irq %d" | ||
743 | " (0x%x)\n", rc, irq, hwirq); | ||
744 | opal_irqs[i] = irq; | ||
745 | } | ||
746 | 774 | ||
747 | /* Create "opal" kobject under /sys/firmware */ | 775 | /* Create "opal" kobject under /sys/firmware */ |
748 | rc = opal_sysfs_init(); | 776 | rc = opal_sysfs_init(); |