1 /* 2 * PowerNV OPAL high level interfaces 3 * 4 * Copyright 2011 IBM Corp. 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * as published by the Free Software Foundation; either version 9 * 2 of the License, or (at your option) any later version. 10 */ 11 12 #undef DEBUG 13 14 #include <linux/types.h> 15 #include <linux/of.h> 16 #include <linux/of_platform.h> 17 #include <linux/interrupt.h> 18 #include <asm/opal.h> 19 #include <asm/firmware.h> 20 21 #include "powernv.h" 22 23 struct opal { 24 u64 base; 25 u64 entry; 26 } opal; 27 28 static struct device_node *opal_node; 29 static DEFINE_SPINLOCK(opal_write_lock); 30 extern u64 opal_mc_secondary_handler[]; 31 32 int __init early_init_dt_scan_opal(unsigned long node, 33 const char *uname, int depth, void *data) 34 { 35 const void *basep, *entryp; 36 unsigned long basesz, entrysz; 37 38 if (depth != 1 || strcmp(uname, "ibm,opal") != 0) 39 return 0; 40 41 basep = of_get_flat_dt_prop(node, "opal-base-address", &basesz); 42 entryp = of_get_flat_dt_prop(node, "opal-entry-address", &entrysz); 43 44 if (!basep || !entryp) 45 return 1; 46 47 opal.base = of_read_number(basep, basesz/4); 48 opal.entry = of_read_number(entryp, entrysz/4); 49 50 pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%ld)\n", 51 opal.base, basep, basesz); 52 pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%ld)\n", 53 opal.entry, entryp, entrysz); 54 55 powerpc_firmware_features |= FW_FEATURE_OPAL; 56 if (of_flat_dt_is_compatible(node, "ibm,opal-v2")) { 57 powerpc_firmware_features |= FW_FEATURE_OPALv2; 58 printk("OPAL V2 detected !\n"); 59 } else { 60 printk("OPAL V1 detected !\n"); 61 } 62 63 return 1; 64 } 65 66 static int __init opal_register_exception_handlers(void) 67 { 68 u64 glue; 69 70 if (!(powerpc_firmware_features & FW_FEATURE_OPAL)) 71 return -ENODEV; 72 73 /* Hookup some exception handlers. We use the fwnmi area at 0x7000 74 * to provide the glue space to OPAL 75 */ 76 glue = 0x7000; 77 opal_register_exception_handler(OPAL_MACHINE_CHECK_HANDLER, 78 __pa(opal_mc_secondary_handler[0]), 79 glue); 80 glue += 128; 81 opal_register_exception_handler(OPAL_HYPERVISOR_MAINTENANCE_HANDLER, 82 0, glue); 83 glue += 128; 84 opal_register_exception_handler(OPAL_SOFTPATCH_HANDLER, 0, glue); 85 86 return 0; 87 } 88 89 early_initcall(opal_register_exception_handlers); 90 91 int opal_get_chars(uint32_t vtermno, char *buf, int count) 92 { 93 s64 len, rc; 94 u64 evt; 95 96 if (!opal.entry) 97 return -ENODEV; 98 opal_poll_events(&evt); 99 if ((evt & OPAL_EVENT_CONSOLE_INPUT) == 0) 100 return 0; 101 len = count; 102 rc = opal_console_read(vtermno, &len, buf); 103 if (rc == OPAL_SUCCESS) 104 return len; 105 return 0; 106 } 107 108 int opal_put_chars(uint32_t vtermno, const char *data, int total_len) 109 { 110 int written = 0; 111 s64 len, rc; 112 unsigned long flags; 113 u64 evt; 114 115 if (!opal.entry) 116 return -ENODEV; 117 118 /* We want put_chars to be atomic to avoid mangling of hvsi 119 * packets. To do that, we first test for room and return 120 * -EAGAIN if there isn't enough. 121 * 122 * Unfortunately, opal_console_write_buffer_space() doesn't 123 * appear to work on opal v1, so we just assume there is 124 * enough room and be done with it 125 */ 126 spin_lock_irqsave(&opal_write_lock, flags); 127 if (firmware_has_feature(FW_FEATURE_OPALv2)) { 128 rc = opal_console_write_buffer_space(vtermno, &len); 129 if (rc || len < total_len) { 130 spin_unlock_irqrestore(&opal_write_lock, flags); 131 /* Closed -> drop characters */ 132 if (rc) 133 return total_len; 134 opal_poll_events(&evt); 135 return -EAGAIN; 136 } 137 } 138 139 /* We still try to handle partial completions, though they 140 * should no longer happen. 141 */ 142 rc = OPAL_BUSY; 143 while(total_len > 0 && (rc == OPAL_BUSY || 144 rc == OPAL_BUSY_EVENT || rc == OPAL_SUCCESS)) { 145 len = total_len; 146 rc = opal_console_write(vtermno, &len, data); 147 148 /* Closed or other error drop */ 149 if (rc != OPAL_SUCCESS && rc != OPAL_BUSY && 150 rc != OPAL_BUSY_EVENT) { 151 written = total_len; 152 break; 153 } 154 if (rc == OPAL_SUCCESS) { 155 total_len -= len; 156 data += len; 157 written += len; 158 } 159 /* This is a bit nasty but we need that for the console to 160 * flush when there aren't any interrupts. We will clean 161 * things a bit later to limit that to synchronous path 162 * such as the kernel console and xmon/udbg 163 */ 164 do 165 opal_poll_events(&evt); 166 while(rc == OPAL_SUCCESS && (evt & OPAL_EVENT_CONSOLE_OUTPUT)); 167 } 168 spin_unlock_irqrestore(&opal_write_lock, flags); 169 return written; 170 } 171 172 int opal_machine_check(struct pt_regs *regs) 173 { 174 struct opal_machine_check_event *opal_evt = get_paca()->opal_mc_evt; 175 struct opal_machine_check_event evt; 176 const char *level, *sevstr, *subtype; 177 static const char *opal_mc_ue_types[] = { 178 "Indeterminate", 179 "Instruction fetch", 180 "Page table walk ifetch", 181 "Load/Store", 182 "Page table walk Load/Store", 183 }; 184 static const char *opal_mc_slb_types[] = { 185 "Indeterminate", 186 "Parity", 187 "Multihit", 188 }; 189 static const char *opal_mc_erat_types[] = { 190 "Indeterminate", 191 "Parity", 192 "Multihit", 193 }; 194 static const char *opal_mc_tlb_types[] = { 195 "Indeterminate", 196 "Parity", 197 "Multihit", 198 }; 199 200 /* Copy the event structure and release the original */ 201 evt = *opal_evt; 202 opal_evt->in_use = 0; 203 204 /* Print things out */ 205 if (evt.version != OpalMCE_V1) { 206 pr_err("Machine Check Exception, Unknown event version %d !\n", 207 evt.version); 208 return 0; 209 } 210 switch(evt.severity) { 211 case OpalMCE_SEV_NO_ERROR: 212 level = KERN_INFO; 213 sevstr = "Harmless"; 214 break; 215 case OpalMCE_SEV_WARNING: 216 level = KERN_WARNING; 217 sevstr = ""; 218 break; 219 case OpalMCE_SEV_ERROR_SYNC: 220 level = KERN_ERR; 221 sevstr = "Severe"; 222 break; 223 case OpalMCE_SEV_FATAL: 224 default: 225 level = KERN_ERR; 226 sevstr = "Fatal"; 227 break; 228 } 229 230 printk("%s%s Machine check interrupt [%s]\n", level, sevstr, 231 evt.disposition == OpalMCE_DISPOSITION_RECOVERED ? 232 "Recovered" : "[Not recovered"); 233 printk("%s Initiator: %s\n", level, 234 evt.initiator == OpalMCE_INITIATOR_CPU ? "CPU" : "Unknown"); 235 switch(evt.error_type) { 236 case OpalMCE_ERROR_TYPE_UE: 237 subtype = evt.u.ue_error.ue_error_type < 238 ARRAY_SIZE(opal_mc_ue_types) ? 239 opal_mc_ue_types[evt.u.ue_error.ue_error_type] 240 : "Unknown"; 241 printk("%s Error type: UE [%s]\n", level, subtype); 242 if (evt.u.ue_error.effective_address_provided) 243 printk("%s Effective address: %016llx\n", 244 level, evt.u.ue_error.effective_address); 245 if (evt.u.ue_error.physical_address_provided) 246 printk("%s Physial address: %016llx\n", 247 level, evt.u.ue_error.physical_address); 248 break; 249 case OpalMCE_ERROR_TYPE_SLB: 250 subtype = evt.u.slb_error.slb_error_type < 251 ARRAY_SIZE(opal_mc_slb_types) ? 252 opal_mc_slb_types[evt.u.slb_error.slb_error_type] 253 : "Unknown"; 254 printk("%s Error type: SLB [%s]\n", level, subtype); 255 if (evt.u.slb_error.effective_address_provided) 256 printk("%s Effective address: %016llx\n", 257 level, evt.u.slb_error.effective_address); 258 break; 259 case OpalMCE_ERROR_TYPE_ERAT: 260 subtype = evt.u.erat_error.erat_error_type < 261 ARRAY_SIZE(opal_mc_erat_types) ? 262 opal_mc_erat_types[evt.u.erat_error.erat_error_type] 263 : "Unknown"; 264 printk("%s Error type: ERAT [%s]\n", level, subtype); 265 if (evt.u.erat_error.effective_address_provided) 266 printk("%s Effective address: %016llx\n", 267 level, evt.u.erat_error.effective_address); 268 break; 269 case OpalMCE_ERROR_TYPE_TLB: 270 subtype = evt.u.tlb_error.tlb_error_type < 271 ARRAY_SIZE(opal_mc_tlb_types) ? 272 opal_mc_tlb_types[evt.u.tlb_error.tlb_error_type] 273 : "Unknown"; 274 printk("%s Error type: TLB [%s]\n", level, subtype); 275 if (evt.u.tlb_error.effective_address_provided) 276 printk("%s Effective address: %016llx\n", 277 level, evt.u.tlb_error.effective_address); 278 break; 279 default: 280 case OpalMCE_ERROR_TYPE_UNKNOWN: 281 printk("%s Error type: Unknown\n", level); 282 break; 283 } 284 return evt.severity == OpalMCE_SEV_FATAL ? 0 : 1; 285 } 286 287 static irqreturn_t opal_interrupt(int irq, void *data) 288 { 289 uint64_t events; 290 291 opal_handle_interrupt(virq_to_hw(irq), &events); 292 293 /* XXX TODO: Do something with the events */ 294 295 return IRQ_HANDLED; 296 } 297 298 static int __init opal_init(void) 299 { 300 struct device_node *np, *consoles; 301 const u32 *irqs; 302 int rc, i, irqlen; 303 304 opal_node = of_find_node_by_path("/ibm,opal"); 305 if (!opal_node) { 306 pr_warn("opal: Node not found\n"); 307 return -ENODEV; 308 } 309 if (firmware_has_feature(FW_FEATURE_OPALv2)) 310 consoles = of_find_node_by_path("/ibm,opal/consoles"); 311 else 312 consoles = of_node_get(opal_node); 313 314 /* Register serial ports */ 315 for_each_child_of_node(consoles, np) { 316 if (strcmp(np->name, "serial")) 317 continue; 318 of_platform_device_create(np, NULL, NULL); 319 } 320 of_node_put(consoles); 321 322 /* Find all OPAL interrupts and request them */ 323 irqs = of_get_property(opal_node, "opal-interrupts", &irqlen); 324 pr_debug("opal: Found %d interrupts reserved for OPAL\n", 325 irqs ? (irqlen / 4) : 0); 326 for (i = 0; irqs && i < (irqlen / 4); i++, irqs++) { 327 unsigned int hwirq = be32_to_cpup(irqs); 328 unsigned int irq = irq_create_mapping(NULL, hwirq); 329 if (irq == NO_IRQ) { 330 pr_warning("opal: Failed to map irq 0x%x\n", hwirq); 331 continue; 332 } 333 rc = request_irq(irq, opal_interrupt, 0, "opal", NULL); 334 if (rc) 335 pr_warning("opal: Error %d requesting irq %d" 336 " (0x%x)\n", rc, irq, hwirq); 337 } 338 return 0; 339 } 340 subsys_initcall(opal_init); 341