1 /* 2 * Copyright 2006-2008, IBM Corporation. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 */ 9 10 #undef DEBUG 11 12 #include <linux/types.h> 13 #include <linux/kernel.h> 14 #include <linux/smp.h> 15 #include <linux/reboot.h> 16 17 #include <asm/reg.h> 18 #include <asm/io.h> 19 #include <asm/prom.h> 20 #include <asm/kexec.h> 21 #include <asm/machdep.h> 22 #include <asm/rtas.h> 23 #include <asm/cell-regs.h> 24 25 #include "ras.h" 26 27 28 static void dump_fir(int cpu) 29 { 30 struct cbe_pmd_regs __iomem *pregs = cbe_get_cpu_pmd_regs(cpu); 31 struct cbe_iic_regs __iomem *iregs = cbe_get_cpu_iic_regs(cpu); 32 33 if (pregs == NULL) 34 return; 35 36 /* Todo: do some nicer parsing of bits and based on them go down 37 * to other sub-units FIRs and not only IIC 38 */ 39 printk(KERN_ERR "Global Checkstop FIR : 0x%016lx\n", 40 in_be64(&pregs->checkstop_fir)); 41 printk(KERN_ERR "Global Recoverable FIR : 0x%016lx\n", 42 in_be64(&pregs->checkstop_fir)); 43 printk(KERN_ERR "Global MachineCheck FIR : 0x%016lx\n", 44 in_be64(&pregs->spec_att_mchk_fir)); 45 46 if (iregs == NULL) 47 return; 48 printk(KERN_ERR "IOC FIR : 0x%016lx\n", 49 in_be64(&iregs->ioc_fir)); 50 51 } 52 53 void cbe_system_error_exception(struct pt_regs *regs) 54 { 55 int cpu = smp_processor_id(); 56 57 printk(KERN_ERR "System Error Interrupt on CPU %d !\n", cpu); 58 dump_fir(cpu); 59 dump_stack(); 60 } 61 62 void cbe_maintenance_exception(struct pt_regs *regs) 63 { 64 int cpu = smp_processor_id(); 65 66 /* 67 * Nothing implemented for the maintenance interrupt at this point 68 */ 69 70 printk(KERN_ERR "Unhandled Maintenance interrupt on CPU %d !\n", cpu); 71 dump_stack(); 72 } 73 74 void cbe_thermal_exception(struct pt_regs *regs) 75 { 76 int cpu = smp_processor_id(); 77 78 /* 79 * Nothing implemented for the thermal interrupt at this point 80 */ 81 82 printk(KERN_ERR "Unhandled Thermal interrupt on CPU %d !\n", cpu); 83 dump_stack(); 84 } 85 86 static int cbe_machine_check_handler(struct pt_regs *regs) 87 { 88 int cpu = smp_processor_id(); 89 90 printk(KERN_ERR "Machine Check Interrupt on CPU %d !\n", cpu); 91 dump_fir(cpu); 92 93 /* No recovery from this code now, lets continue */ 94 return 0; 95 } 96 97 struct ptcal_area { 98 struct list_head list; 99 int nid; 100 int order; 101 struct page *pages; 102 }; 103 104 static LIST_HEAD(ptcal_list); 105 106 static int ptcal_start_tok, ptcal_stop_tok; 107 108 static int __init cbe_ptcal_enable_on_node(int nid, int order) 109 { 110 struct ptcal_area *area; 111 int ret = -ENOMEM; 112 unsigned long addr; 113 114 #ifdef CONFIG_CRASH_DUMP 115 rtas_call(ptcal_stop_tok, 1, 1, NULL, nid); 116 #endif 117 118 area = kmalloc(sizeof(*area), GFP_KERNEL); 119 if (!area) 120 goto out_err; 121 122 area->nid = nid; 123 area->order = order; 124 area->pages = alloc_pages_node(area->nid, GFP_KERNEL, area->order); 125 126 if (!area->pages) 127 goto out_free_area; 128 129 addr = __pa(page_address(area->pages)); 130 131 ret = -EIO; 132 if (rtas_call(ptcal_start_tok, 3, 1, NULL, area->nid, 133 (unsigned int)(addr >> 32), 134 (unsigned int)(addr & 0xffffffff))) { 135 printk(KERN_ERR "%s: error enabling PTCAL on node %d!\n", 136 __func__, nid); 137 goto out_free_pages; 138 } 139 140 list_add(&area->list, &ptcal_list); 141 142 return 0; 143 144 out_free_pages: 145 __free_pages(area->pages, area->order); 146 out_free_area: 147 kfree(area); 148 out_err: 149 return ret; 150 } 151 152 static int __init cbe_ptcal_enable(void) 153 { 154 const u32 *size; 155 struct device_node *np; 156 int order, found_mic = 0; 157 158 np = of_find_node_by_path("/rtas"); 159 if (!np) 160 return -ENODEV; 161 162 size = of_get_property(np, "ibm,cbe-ptcal-size", NULL); 163 if (!size) 164 return -ENODEV; 165 166 pr_debug("%s: enabling PTCAL, size = 0x%x\n", __func__, *size); 167 order = get_order(*size); 168 of_node_put(np); 169 170 /* support for malta device trees, with be@/mic@ nodes */ 171 for_each_node_by_type(np, "mic-tm") { 172 cbe_ptcal_enable_on_node(of_node_to_nid(np), order); 173 found_mic = 1; 174 } 175 176 if (found_mic) 177 return 0; 178 179 /* support for older device tree - use cpu nodes */ 180 for_each_node_by_type(np, "cpu") { 181 const u32 *nid = of_get_property(np, "node-id", NULL); 182 if (!nid) { 183 printk(KERN_ERR "%s: node %s is missing node-id?\n", 184 __func__, np->full_name); 185 continue; 186 } 187 cbe_ptcal_enable_on_node(*nid, order); 188 found_mic = 1; 189 } 190 191 return found_mic ? 0 : -ENODEV; 192 } 193 194 static int cbe_ptcal_disable(void) 195 { 196 struct ptcal_area *area, *tmp; 197 int ret = 0; 198 199 pr_debug("%s: disabling PTCAL\n", __func__); 200 201 list_for_each_entry_safe(area, tmp, &ptcal_list, list) { 202 /* disable ptcal on this node */ 203 if (rtas_call(ptcal_stop_tok, 1, 1, NULL, area->nid)) { 204 printk(KERN_ERR "%s: error disabling PTCAL " 205 "on node %d!\n", __func__, 206 area->nid); 207 ret = -EIO; 208 continue; 209 } 210 211 /* ensure we can access the PTCAL area */ 212 memset(page_address(area->pages), 0, 213 1 << (area->order + PAGE_SHIFT)); 214 215 /* clean up */ 216 list_del(&area->list); 217 __free_pages(area->pages, area->order); 218 kfree(area); 219 } 220 221 return ret; 222 } 223 224 static int cbe_ptcal_notify_reboot(struct notifier_block *nb, 225 unsigned long code, void *data) 226 { 227 return cbe_ptcal_disable(); 228 } 229 230 static void cbe_ptcal_crash_shutdown(void) 231 { 232 cbe_ptcal_disable(); 233 } 234 235 static struct notifier_block cbe_ptcal_reboot_notifier = { 236 .notifier_call = cbe_ptcal_notify_reboot 237 }; 238 239 #ifdef CONFIG_PPC_IBM_CELL_RESETBUTTON 240 static int sysreset_hack; 241 242 static int __init cbe_sysreset_init(void) 243 { 244 struct cbe_pmd_regs __iomem *regs; 245 246 sysreset_hack = machine_is_compatible("IBM,CBPLUS-1.0"); 247 if (!sysreset_hack) 248 return 0; 249 250 regs = cbe_get_cpu_pmd_regs(0); 251 if (!regs) 252 return 0; 253 254 /* Enable JTAG system-reset hack */ 255 out_be32(®s->fir_mode_reg, 256 in_be32(®s->fir_mode_reg) | 257 CBE_PMD_FIR_MODE_M8); 258 259 return 0; 260 } 261 device_initcall(cbe_sysreset_init); 262 263 int cbe_sysreset_hack(void) 264 { 265 struct cbe_pmd_regs __iomem *regs; 266 267 /* 268 * The BMC can inject user triggered system reset exceptions, 269 * but cannot set the system reset reason in srr1, 270 * so check an extra register here. 271 */ 272 if (sysreset_hack && (smp_processor_id() == 0)) { 273 regs = cbe_get_cpu_pmd_regs(0); 274 if (!regs) 275 return 0; 276 if (in_be64(®s->ras_esc_0) & 0x0000ffff) { 277 out_be64(®s->ras_esc_0, 0); 278 return 0; 279 } 280 } 281 return 1; 282 } 283 #endif /* CONFIG_PPC_IBM_CELL_RESETBUTTON */ 284 285 int __init cbe_ptcal_init(void) 286 { 287 int ret; 288 ptcal_start_tok = rtas_token("ibm,cbe-start-ptcal"); 289 ptcal_stop_tok = rtas_token("ibm,cbe-stop-ptcal"); 290 291 if (ptcal_start_tok == RTAS_UNKNOWN_SERVICE 292 || ptcal_stop_tok == RTAS_UNKNOWN_SERVICE) 293 return -ENODEV; 294 295 ret = register_reboot_notifier(&cbe_ptcal_reboot_notifier); 296 if (ret) 297 goto out1; 298 299 ret = crash_shutdown_register(&cbe_ptcal_crash_shutdown); 300 if (ret) 301 goto out2; 302 303 return cbe_ptcal_enable(); 304 305 out2: 306 unregister_reboot_notifier(&cbe_ptcal_reboot_notifier); 307 out1: 308 printk(KERN_ERR "Can't disable PTCAL, so not enabling\n"); 309 return ret; 310 } 311 312 arch_initcall(cbe_ptcal_init); 313 314 void __init cbe_ras_init(void) 315 { 316 unsigned long hid0; 317 318 /* 319 * Enable System Error & thermal interrupts and wakeup conditions 320 */ 321 322 hid0 = mfspr(SPRN_HID0); 323 hid0 |= HID0_CBE_THERM_INT_EN | HID0_CBE_THERM_WAKEUP | 324 HID0_CBE_SYSERR_INT_EN | HID0_CBE_SYSERR_WAKEUP; 325 mtspr(SPRN_HID0, hid0); 326 mb(); 327 328 /* 329 * Install machine check handler. Leave setting of precise mode to 330 * what the firmware did for now 331 */ 332 ppc_md.machine_check_exception = cbe_machine_check_handler; 333 mb(); 334 335 /* 336 * For now, we assume that IOC_FIR is already set to forward some 337 * error conditions to the System Error handler. If that is not true 338 * then it will have to be fixed up here. 339 */ 340 } 341