114a43e69SBenjamin Herrenschmidt /* 214a43e69SBenjamin Herrenschmidt * PowerNV OPAL high level interfaces 314a43e69SBenjamin Herrenschmidt * 414a43e69SBenjamin Herrenschmidt * Copyright 2011 IBM Corp. 514a43e69SBenjamin Herrenschmidt * 614a43e69SBenjamin Herrenschmidt * This program is free software; you can redistribute it and/or 714a43e69SBenjamin Herrenschmidt * modify it under the terms of the GNU General Public License 814a43e69SBenjamin Herrenschmidt * as published by the Free Software Foundation; either version 914a43e69SBenjamin Herrenschmidt * 2 of the License, or (at your option) any later version. 1014a43e69SBenjamin Herrenschmidt */ 1114a43e69SBenjamin Herrenschmidt 1214a43e69SBenjamin Herrenschmidt #undef DEBUG 1314a43e69SBenjamin Herrenschmidt 1414a43e69SBenjamin Herrenschmidt #include <linux/types.h> 1514a43e69SBenjamin Herrenschmidt #include <linux/of.h> 1626a2056eSRob Herring #include <linux/of_fdt.h> 1714a43e69SBenjamin Herrenschmidt #include <linux/of_platform.h> 18a125e092SBenjamin Herrenschmidt #include <linux/interrupt.h> 191bc98de2SGavin Shan #include <linux/notifier.h> 2073ed148aSBenjamin Herrenschmidt #include <linux/slab.h> 216f68b5e2SVasant Hegde #include <linux/kobject.h> 2214a43e69SBenjamin Herrenschmidt #include <asm/opal.h> 2314a43e69SBenjamin Herrenschmidt #include <asm/firmware.h> 2436df96f8SMahesh Salgaonkar #include <asm/mce.h> 2514a43e69SBenjamin Herrenschmidt 2614a43e69SBenjamin Herrenschmidt #include "powernv.h" 2714a43e69SBenjamin Herrenschmidt 286f68b5e2SVasant Hegde /* /sys/firmware/opal */ 296f68b5e2SVasant Hegde struct kobject *opal_kobj; 306f68b5e2SVasant Hegde 3114a43e69SBenjamin Herrenschmidt struct opal { 3214a43e69SBenjamin Herrenschmidt u64 base; 3314a43e69SBenjamin Herrenschmidt u64 entry; 3414a43e69SBenjamin Herrenschmidt } opal; 3514a43e69SBenjamin Herrenschmidt 3614a43e69SBenjamin Herrenschmidt static struct device_node *opal_node; 3714a43e69SBenjamin Herrenschmidt static DEFINE_SPINLOCK(opal_write_lock); 38ed79ba9eSBenjamin Herrenschmidt extern u64 opal_mc_secondary_handler[]; 3973ed148aSBenjamin Herrenschmidt static unsigned int *opal_irqs; 4073ed148aSBenjamin Herrenschmidt static unsigned int opal_irq_count; 411bc98de2SGavin Shan static ATOMIC_NOTIFIER_HEAD(opal_notifier_head); 421bc98de2SGavin Shan static DEFINE_SPINLOCK(opal_notifier_lock); 431bc98de2SGavin Shan static uint64_t last_notified_mask = 0x0ul; 441bc98de2SGavin Shan static atomic_t opal_notifier_hold = ATOMIC_INIT(0); 4514a43e69SBenjamin Herrenschmidt 4614a43e69SBenjamin Herrenschmidt int __init early_init_dt_scan_opal(unsigned long node, 4714a43e69SBenjamin Herrenschmidt const char *uname, int depth, void *data) 4814a43e69SBenjamin Herrenschmidt { 4914a43e69SBenjamin Herrenschmidt const void *basep, *entryp; 5014a43e69SBenjamin Herrenschmidt unsigned long basesz, entrysz; 5114a43e69SBenjamin Herrenschmidt 5214a43e69SBenjamin Herrenschmidt if (depth != 1 || strcmp(uname, "ibm,opal") != 0) 5314a43e69SBenjamin Herrenschmidt return 0; 5414a43e69SBenjamin Herrenschmidt 5514a43e69SBenjamin Herrenschmidt basep = of_get_flat_dt_prop(node, "opal-base-address", &basesz); 5614a43e69SBenjamin Herrenschmidt entryp = of_get_flat_dt_prop(node, "opal-entry-address", &entrysz); 5714a43e69SBenjamin Herrenschmidt 5814a43e69SBenjamin Herrenschmidt if (!basep || !entryp) 5914a43e69SBenjamin Herrenschmidt return 1; 6014a43e69SBenjamin Herrenschmidt 6114a43e69SBenjamin Herrenschmidt opal.base = of_read_number(basep, basesz/4); 6214a43e69SBenjamin Herrenschmidt opal.entry = of_read_number(entryp, entrysz/4); 6314a43e69SBenjamin Herrenschmidt 6414a43e69SBenjamin Herrenschmidt pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%ld)\n", 6514a43e69SBenjamin Herrenschmidt opal.base, basep, basesz); 6614a43e69SBenjamin Herrenschmidt pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%ld)\n", 6714a43e69SBenjamin Herrenschmidt opal.entry, entryp, entrysz); 6814a43e69SBenjamin Herrenschmidt 6914a43e69SBenjamin Herrenschmidt powerpc_firmware_features |= FW_FEATURE_OPAL; 7075b93da4SBenjamin Herrenschmidt if (of_flat_dt_is_compatible(node, "ibm,opal-v3")) { 7175b93da4SBenjamin Herrenschmidt powerpc_firmware_features |= FW_FEATURE_OPALv2; 7275b93da4SBenjamin Herrenschmidt powerpc_firmware_features |= FW_FEATURE_OPALv3; 7375b93da4SBenjamin Herrenschmidt printk("OPAL V3 detected !\n"); 7475b93da4SBenjamin Herrenschmidt } else if (of_flat_dt_is_compatible(node, "ibm,opal-v2")) { 7514a43e69SBenjamin Herrenschmidt powerpc_firmware_features |= FW_FEATURE_OPALv2; 7614a43e69SBenjamin Herrenschmidt printk("OPAL V2 detected !\n"); 7714a43e69SBenjamin Herrenschmidt } else { 7814a43e69SBenjamin Herrenschmidt printk("OPAL V1 detected !\n"); 7914a43e69SBenjamin Herrenschmidt } 8014a43e69SBenjamin Herrenschmidt 81c4463b37SJeremy Kerr return 1; 82c4463b37SJeremy Kerr } 83c4463b37SJeremy Kerr 84c4463b37SJeremy Kerr static int __init opal_register_exception_handlers(void) 85c4463b37SJeremy Kerr { 8629186097SBenjamin Herrenschmidt #ifdef __BIG_ENDIAN__ 87c4463b37SJeremy Kerr u64 glue; 88c4463b37SJeremy Kerr 89c4463b37SJeremy Kerr if (!(powerpc_firmware_features & FW_FEATURE_OPAL)) 90c4463b37SJeremy Kerr return -ENODEV; 91c4463b37SJeremy Kerr 9228446de2SMahesh Salgaonkar /* Hookup some exception handlers except machine check. We use the 9328446de2SMahesh Salgaonkar * fwnmi area at 0x7000 to provide the glue space to OPAL 94ed79ba9eSBenjamin Herrenschmidt */ 95ed79ba9eSBenjamin Herrenschmidt glue = 0x7000; 96ed79ba9eSBenjamin Herrenschmidt opal_register_exception_handler(OPAL_HYPERVISOR_MAINTENANCE_HANDLER, 97ed79ba9eSBenjamin Herrenschmidt 0, glue); 98ed79ba9eSBenjamin Herrenschmidt glue += 128; 99ed79ba9eSBenjamin Herrenschmidt opal_register_exception_handler(OPAL_SOFTPATCH_HANDLER, 0, glue); 10029186097SBenjamin Herrenschmidt #endif 101ed79ba9eSBenjamin Herrenschmidt 102c4463b37SJeremy Kerr return 0; 10314a43e69SBenjamin Herrenschmidt } 10414a43e69SBenjamin Herrenschmidt 105c4463b37SJeremy Kerr early_initcall(opal_register_exception_handlers); 106c4463b37SJeremy Kerr 1071bc98de2SGavin Shan int opal_notifier_register(struct notifier_block *nb) 1081bc98de2SGavin Shan { 1091bc98de2SGavin Shan if (!nb) { 1101bc98de2SGavin Shan pr_warning("%s: Invalid argument (%p)\n", 1111bc98de2SGavin Shan __func__, nb); 1121bc98de2SGavin Shan return -EINVAL; 1131bc98de2SGavin Shan } 1141bc98de2SGavin Shan 1151bc98de2SGavin Shan atomic_notifier_chain_register(&opal_notifier_head, nb); 1161bc98de2SGavin Shan return 0; 1171bc98de2SGavin Shan } 1181bc98de2SGavin Shan 1191bc98de2SGavin Shan static void opal_do_notifier(uint64_t events) 1201bc98de2SGavin Shan { 1211bc98de2SGavin Shan unsigned long flags; 1221bc98de2SGavin Shan uint64_t changed_mask; 1231bc98de2SGavin Shan 1241bc98de2SGavin Shan if (atomic_read(&opal_notifier_hold)) 1251bc98de2SGavin Shan return; 1261bc98de2SGavin Shan 1271bc98de2SGavin Shan spin_lock_irqsave(&opal_notifier_lock, flags); 1281bc98de2SGavin Shan changed_mask = last_notified_mask ^ events; 1291bc98de2SGavin Shan last_notified_mask = events; 1301bc98de2SGavin Shan spin_unlock_irqrestore(&opal_notifier_lock, flags); 1311bc98de2SGavin Shan 1321bc98de2SGavin Shan /* 1331bc98de2SGavin Shan * We feed with the event bits and changed bits for 1341bc98de2SGavin Shan * enough information to the callback. 1351bc98de2SGavin Shan */ 1361bc98de2SGavin Shan atomic_notifier_call_chain(&opal_notifier_head, 1371bc98de2SGavin Shan events, (void *)changed_mask); 1381bc98de2SGavin Shan } 1391bc98de2SGavin Shan 1401bc98de2SGavin Shan void opal_notifier_update_evt(uint64_t evt_mask, 1411bc98de2SGavin Shan uint64_t evt_val) 1421bc98de2SGavin Shan { 1431bc98de2SGavin Shan unsigned long flags; 1441bc98de2SGavin Shan 1451bc98de2SGavin Shan spin_lock_irqsave(&opal_notifier_lock, flags); 1461bc98de2SGavin Shan last_notified_mask &= ~evt_mask; 1471bc98de2SGavin Shan last_notified_mask |= evt_val; 1481bc98de2SGavin Shan spin_unlock_irqrestore(&opal_notifier_lock, flags); 1491bc98de2SGavin Shan } 1501bc98de2SGavin Shan 1511bc98de2SGavin Shan void opal_notifier_enable(void) 1521bc98de2SGavin Shan { 1531bc98de2SGavin Shan int64_t rc; 1541bc98de2SGavin Shan uint64_t evt = 0; 1551bc98de2SGavin Shan 1561bc98de2SGavin Shan atomic_set(&opal_notifier_hold, 0); 1571bc98de2SGavin Shan 1581bc98de2SGavin Shan /* Process pending events */ 1591bc98de2SGavin Shan rc = opal_poll_events(&evt); 1601bc98de2SGavin Shan if (rc == OPAL_SUCCESS && evt) 1611bc98de2SGavin Shan opal_do_notifier(evt); 1621bc98de2SGavin Shan } 1631bc98de2SGavin Shan 1641bc98de2SGavin Shan void opal_notifier_disable(void) 1651bc98de2SGavin Shan { 1661bc98de2SGavin Shan atomic_set(&opal_notifier_hold, 1); 1671bc98de2SGavin Shan } 1681bc98de2SGavin Shan 16914a43e69SBenjamin Herrenschmidt int opal_get_chars(uint32_t vtermno, char *buf, int count) 17014a43e69SBenjamin Herrenschmidt { 1714f89363bSBenjamin Herrenschmidt s64 rc; 1724f89363bSBenjamin Herrenschmidt __be64 evt, len; 17314a43e69SBenjamin Herrenschmidt 17414a43e69SBenjamin Herrenschmidt if (!opal.entry) 175daea1175SBenjamin Herrenschmidt return -ENODEV; 17614a43e69SBenjamin Herrenschmidt opal_poll_events(&evt); 1774f89363bSBenjamin Herrenschmidt if ((be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_INPUT) == 0) 17814a43e69SBenjamin Herrenschmidt return 0; 1794f89363bSBenjamin Herrenschmidt len = cpu_to_be64(count); 18014a43e69SBenjamin Herrenschmidt rc = opal_console_read(vtermno, &len, buf); 18114a43e69SBenjamin Herrenschmidt if (rc == OPAL_SUCCESS) 1824f89363bSBenjamin Herrenschmidt return be64_to_cpu(len); 18314a43e69SBenjamin Herrenschmidt return 0; 18414a43e69SBenjamin Herrenschmidt } 18514a43e69SBenjamin Herrenschmidt 18614a43e69SBenjamin Herrenschmidt int opal_put_chars(uint32_t vtermno, const char *data, int total_len) 18714a43e69SBenjamin Herrenschmidt { 18814a43e69SBenjamin Herrenschmidt int written = 0; 1894f89363bSBenjamin Herrenschmidt __be64 olen; 190daea1175SBenjamin Herrenschmidt s64 len, rc; 19114a43e69SBenjamin Herrenschmidt unsigned long flags; 1924f89363bSBenjamin Herrenschmidt __be64 evt; 19314a43e69SBenjamin Herrenschmidt 19414a43e69SBenjamin Herrenschmidt if (!opal.entry) 195daea1175SBenjamin Herrenschmidt return -ENODEV; 19614a43e69SBenjamin Herrenschmidt 19714a43e69SBenjamin Herrenschmidt /* We want put_chars to be atomic to avoid mangling of hvsi 19814a43e69SBenjamin Herrenschmidt * packets. To do that, we first test for room and return 199daea1175SBenjamin Herrenschmidt * -EAGAIN if there isn't enough. 200daea1175SBenjamin Herrenschmidt * 201daea1175SBenjamin Herrenschmidt * Unfortunately, opal_console_write_buffer_space() doesn't 202daea1175SBenjamin Herrenschmidt * appear to work on opal v1, so we just assume there is 203daea1175SBenjamin Herrenschmidt * enough room and be done with it 20414a43e69SBenjamin Herrenschmidt */ 20514a43e69SBenjamin Herrenschmidt spin_lock_irqsave(&opal_write_lock, flags); 206daea1175SBenjamin Herrenschmidt if (firmware_has_feature(FW_FEATURE_OPALv2)) { 2074f89363bSBenjamin Herrenschmidt rc = opal_console_write_buffer_space(vtermno, &olen); 2084f89363bSBenjamin Herrenschmidt len = be64_to_cpu(olen); 20914a43e69SBenjamin Herrenschmidt if (rc || len < total_len) { 21014a43e69SBenjamin Herrenschmidt spin_unlock_irqrestore(&opal_write_lock, flags); 21114a43e69SBenjamin Herrenschmidt /* Closed -> drop characters */ 21214a43e69SBenjamin Herrenschmidt if (rc) 21314a43e69SBenjamin Herrenschmidt return total_len; 2144f89363bSBenjamin Herrenschmidt opal_poll_events(NULL); 21514a43e69SBenjamin Herrenschmidt return -EAGAIN; 21614a43e69SBenjamin Herrenschmidt } 217daea1175SBenjamin Herrenschmidt } 21814a43e69SBenjamin Herrenschmidt 21914a43e69SBenjamin Herrenschmidt /* We still try to handle partial completions, though they 22014a43e69SBenjamin Herrenschmidt * should no longer happen. 22114a43e69SBenjamin Herrenschmidt */ 222daea1175SBenjamin Herrenschmidt rc = OPAL_BUSY; 22314a43e69SBenjamin Herrenschmidt while(total_len > 0 && (rc == OPAL_BUSY || 22414a43e69SBenjamin Herrenschmidt rc == OPAL_BUSY_EVENT || rc == OPAL_SUCCESS)) { 2254f89363bSBenjamin Herrenschmidt olen = cpu_to_be64(total_len); 2264f89363bSBenjamin Herrenschmidt rc = opal_console_write(vtermno, &olen, data); 2274f89363bSBenjamin Herrenschmidt len = be64_to_cpu(olen); 2281de1455fSBenjamin Herrenschmidt 2291de1455fSBenjamin Herrenschmidt /* Closed or other error drop */ 2301de1455fSBenjamin Herrenschmidt if (rc != OPAL_SUCCESS && rc != OPAL_BUSY && 2311de1455fSBenjamin Herrenschmidt rc != OPAL_BUSY_EVENT) { 2321de1455fSBenjamin Herrenschmidt written = total_len; 2331de1455fSBenjamin Herrenschmidt break; 2341de1455fSBenjamin Herrenschmidt } 23514a43e69SBenjamin Herrenschmidt if (rc == OPAL_SUCCESS) { 23614a43e69SBenjamin Herrenschmidt total_len -= len; 23714a43e69SBenjamin Herrenschmidt data += len; 23814a43e69SBenjamin Herrenschmidt written += len; 23914a43e69SBenjamin Herrenschmidt } 24014a43e69SBenjamin Herrenschmidt /* This is a bit nasty but we need that for the console to 24114a43e69SBenjamin Herrenschmidt * flush when there aren't any interrupts. We will clean 24214a43e69SBenjamin Herrenschmidt * things a bit later to limit that to synchronous path 24314a43e69SBenjamin Herrenschmidt * such as the kernel console and xmon/udbg 24414a43e69SBenjamin Herrenschmidt */ 24514a43e69SBenjamin Herrenschmidt do 24614a43e69SBenjamin Herrenschmidt opal_poll_events(&evt); 2474f89363bSBenjamin Herrenschmidt while(rc == OPAL_SUCCESS && 2484f89363bSBenjamin Herrenschmidt (be64_to_cpu(evt) & OPAL_EVENT_CONSOLE_OUTPUT)); 24914a43e69SBenjamin Herrenschmidt } 25014a43e69SBenjamin Herrenschmidt spin_unlock_irqrestore(&opal_write_lock, flags); 25114a43e69SBenjamin Herrenschmidt return written; 25214a43e69SBenjamin Herrenschmidt } 25314a43e69SBenjamin Herrenschmidt 254ed79ba9eSBenjamin Herrenschmidt int opal_machine_check(struct pt_regs *regs) 255ed79ba9eSBenjamin Herrenschmidt { 25636df96f8SMahesh Salgaonkar struct machine_check_event evt; 257ed79ba9eSBenjamin Herrenschmidt 25836df96f8SMahesh Salgaonkar if (!get_mce_event(&evt, MCE_EVENT_RELEASE)) 25936df96f8SMahesh Salgaonkar return 0; 260ed79ba9eSBenjamin Herrenschmidt 261ed79ba9eSBenjamin Herrenschmidt /* Print things out */ 26236df96f8SMahesh Salgaonkar if (evt.version != MCE_V1) { 263ed79ba9eSBenjamin Herrenschmidt pr_err("Machine Check Exception, Unknown event version %d !\n", 264ed79ba9eSBenjamin Herrenschmidt evt.version); 265ed79ba9eSBenjamin Herrenschmidt return 0; 266ed79ba9eSBenjamin Herrenschmidt } 267b5ff4211SMahesh Salgaonkar machine_check_print_event_info(&evt); 268ed79ba9eSBenjamin Herrenschmidt 26936df96f8SMahesh Salgaonkar return evt.severity == MCE_SEV_FATAL ? 0 : 1; 270ed79ba9eSBenjamin Herrenschmidt } 271ed79ba9eSBenjamin Herrenschmidt 272a125e092SBenjamin Herrenschmidt static irqreturn_t opal_interrupt(int irq, void *data) 273a125e092SBenjamin Herrenschmidt { 2745e4da530SAnton Blanchard __be64 events; 275a125e092SBenjamin Herrenschmidt 276a125e092SBenjamin Herrenschmidt opal_handle_interrupt(virq_to_hw(irq), &events); 277a125e092SBenjamin Herrenschmidt 2781bc98de2SGavin Shan opal_do_notifier(events); 279a125e092SBenjamin Herrenschmidt 280a125e092SBenjamin Herrenschmidt return IRQ_HANDLED; 281a125e092SBenjamin Herrenschmidt } 282a125e092SBenjamin Herrenschmidt 2836f68b5e2SVasant Hegde static int opal_sysfs_init(void) 2846f68b5e2SVasant Hegde { 2856f68b5e2SVasant Hegde opal_kobj = kobject_create_and_add("opal", firmware_kobj); 2866f68b5e2SVasant Hegde if (!opal_kobj) { 2876f68b5e2SVasant Hegde pr_warn("kobject_create_and_add opal failed\n"); 2886f68b5e2SVasant Hegde return -ENOMEM; 2896f68b5e2SVasant Hegde } 2906f68b5e2SVasant Hegde 2916f68b5e2SVasant Hegde return 0; 2926f68b5e2SVasant Hegde } 2936f68b5e2SVasant Hegde 29414a43e69SBenjamin Herrenschmidt static int __init opal_init(void) 29514a43e69SBenjamin Herrenschmidt { 29614a43e69SBenjamin Herrenschmidt struct device_node *np, *consoles; 2971cc79bc8SAlistair Popple const __be32 *irqs; 298a125e092SBenjamin Herrenschmidt int rc, i, irqlen; 29914a43e69SBenjamin Herrenschmidt 30014a43e69SBenjamin Herrenschmidt opal_node = of_find_node_by_path("/ibm,opal"); 30114a43e69SBenjamin Herrenschmidt if (!opal_node) { 30214a43e69SBenjamin Herrenschmidt pr_warn("opal: Node not found\n"); 30314a43e69SBenjamin Herrenschmidt return -ENODEV; 30414a43e69SBenjamin Herrenschmidt } 3052db29d28SBenjamin Herrenschmidt 3062db29d28SBenjamin Herrenschmidt /* Register OPAL consoles if any ports */ 30714a43e69SBenjamin Herrenschmidt if (firmware_has_feature(FW_FEATURE_OPALv2)) 30814a43e69SBenjamin Herrenschmidt consoles = of_find_node_by_path("/ibm,opal/consoles"); 30914a43e69SBenjamin Herrenschmidt else 31014a43e69SBenjamin Herrenschmidt consoles = of_node_get(opal_node); 3112db29d28SBenjamin Herrenschmidt if (consoles) { 31214a43e69SBenjamin Herrenschmidt for_each_child_of_node(consoles, np) { 31314a43e69SBenjamin Herrenschmidt if (strcmp(np->name, "serial")) 31414a43e69SBenjamin Herrenschmidt continue; 31514a43e69SBenjamin Herrenschmidt of_platform_device_create(np, NULL, NULL); 31614a43e69SBenjamin Herrenschmidt } 31714a43e69SBenjamin Herrenschmidt of_node_put(consoles); 3182db29d28SBenjamin Herrenschmidt } 319a125e092SBenjamin Herrenschmidt 320a125e092SBenjamin Herrenschmidt /* Find all OPAL interrupts and request them */ 321a125e092SBenjamin Herrenschmidt irqs = of_get_property(opal_node, "opal-interrupts", &irqlen); 322a125e092SBenjamin Herrenschmidt pr_debug("opal: Found %d interrupts reserved for OPAL\n", 323a125e092SBenjamin Herrenschmidt irqs ? (irqlen / 4) : 0); 32473ed148aSBenjamin Herrenschmidt opal_irq_count = irqlen / 4; 32573ed148aSBenjamin Herrenschmidt opal_irqs = kzalloc(opal_irq_count * sizeof(unsigned int), GFP_KERNEL); 326a125e092SBenjamin Herrenschmidt for (i = 0; irqs && i < (irqlen / 4); i++, irqs++) { 327a125e092SBenjamin Herrenschmidt unsigned int hwirq = be32_to_cpup(irqs); 328a125e092SBenjamin Herrenschmidt unsigned int irq = irq_create_mapping(NULL, hwirq); 329a125e092SBenjamin Herrenschmidt if (irq == NO_IRQ) { 330a125e092SBenjamin Herrenschmidt pr_warning("opal: Failed to map irq 0x%x\n", hwirq); 331a125e092SBenjamin Herrenschmidt continue; 332a125e092SBenjamin Herrenschmidt } 333a125e092SBenjamin Herrenschmidt rc = request_irq(irq, opal_interrupt, 0, "opal", NULL); 334a125e092SBenjamin Herrenschmidt if (rc) 335a125e092SBenjamin Herrenschmidt pr_warning("opal: Error %d requesting irq %d" 336a125e092SBenjamin Herrenschmidt " (0x%x)\n", rc, irq, hwirq); 33773ed148aSBenjamin Herrenschmidt opal_irqs[i] = irq; 338a125e092SBenjamin Herrenschmidt } 3396f68b5e2SVasant Hegde 3406f68b5e2SVasant Hegde /* Create "opal" kobject under /sys/firmware */ 3416f68b5e2SVasant Hegde rc = opal_sysfs_init(); 34250bd6153SVasant Hegde if (rc == 0) { 34350bd6153SVasant Hegde /* Setup code update interface */ 34450bd6153SVasant Hegde opal_flash_init(); 34550bd6153SVasant Hegde } 3466f68b5e2SVasant Hegde 34714a43e69SBenjamin Herrenschmidt return 0; 34814a43e69SBenjamin Herrenschmidt } 34914a43e69SBenjamin Herrenschmidt subsys_initcall(opal_init); 35073ed148aSBenjamin Herrenschmidt 35173ed148aSBenjamin Herrenschmidt void opal_shutdown(void) 35273ed148aSBenjamin Herrenschmidt { 35373ed148aSBenjamin Herrenschmidt unsigned int i; 35473ed148aSBenjamin Herrenschmidt 35573ed148aSBenjamin Herrenschmidt for (i = 0; i < opal_irq_count; i++) { 35673ed148aSBenjamin Herrenschmidt if (opal_irqs[i]) 357b0d436c7SAnton Blanchard free_irq(opal_irqs[i], NULL); 35873ed148aSBenjamin Herrenschmidt opal_irqs[i] = 0; 35973ed148aSBenjamin Herrenschmidt } 36073ed148aSBenjamin Herrenschmidt } 361