aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/include/asm/opal.h2
-rw-r--r--arch/powerpc/include/asm/paca.h8
-rw-r--r--arch/powerpc/kernel/asm-offsets.c10
-rw-r--r--arch/powerpc/kernel/exceptions-64s.S27
-rw-r--r--arch/powerpc/platforms/powernv/opal.c130
-rw-r--r--arch/powerpc/platforms/powernv/setup.c1
6 files changed, 174 insertions, 4 deletions
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 77ebe50020a2..2893e8f5406d 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -436,6 +436,8 @@ extern void opal_get_rtc_time(struct rtc_time *tm);
436extern unsigned long opal_get_boot_time(void); 436extern unsigned long opal_get_boot_time(void);
437extern void opal_nvram_init(void); 437extern void opal_nvram_init(void);
438 438
439extern int opal_machine_check(struct pt_regs *regs);
440
439#endif /* __ASSEMBLY__ */ 441#endif /* __ASSEMBLY__ */
440 442
441#endif /* __OPAL_H */ 443#endif /* __OPAL_H */
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index 516bfb3f47d9..17722c73ba2e 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -43,6 +43,7 @@ extern unsigned int debug_smp_processor_id(void); /* from linux/smp.h */
43#define get_slb_shadow() (get_paca()->slb_shadow_ptr) 43#define get_slb_shadow() (get_paca()->slb_shadow_ptr)
44 44
45struct task_struct; 45struct task_struct;
46struct opal_machine_check_event;
46 47
47/* 48/*
48 * Defines the layout of the paca. 49 * Defines the layout of the paca.
@@ -135,6 +136,13 @@ struct paca_struct {
135 u8 io_sync; /* writel() needs spin_unlock sync */ 136 u8 io_sync; /* writel() needs spin_unlock sync */
136 u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */ 137 u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */
137 138
139#ifdef CONFIG_PPC_POWERNV
140 /* Pointer to OPAL machine check event structure set by the
141 * early exception handler for use by high level C handler
142 */
143 struct opal_machine_check_event *opal_mc_evt;
144#endif
145
138 /* Stuff for accurate time accounting */ 146 /* Stuff for accurate time accounting */
139 u64 user_time; /* accumulated usermode TB ticks */ 147 u64 user_time; /* accumulated usermode TB ticks */
140 u64 system_time; /* accumulated system TB ticks */ 148 u64 system_time; /* accumulated system TB ticks */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 5f078bc2063e..536ffa897c6c 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -48,6 +48,9 @@
48#ifdef CONFIG_PPC_ISERIES 48#ifdef CONFIG_PPC_ISERIES
49#include <asm/iseries/alpaca.h> 49#include <asm/iseries/alpaca.h>
50#endif 50#endif
51#ifdef CONFIG_PPC_POWERNV
52#include <asm/opal.h>
53#endif
51#if defined(CONFIG_KVM) || defined(CONFIG_KVM_GUEST) 54#if defined(CONFIG_KVM) || defined(CONFIG_KVM_GUEST)
52#include <linux/kvm_host.h> 55#include <linux/kvm_host.h>
53#endif 56#endif
@@ -609,5 +612,12 @@ int main(void)
609 arch.timing_last_enter.tv32.tbl)); 612 arch.timing_last_enter.tv32.tbl));
610#endif 613#endif
611 614
615#ifdef CONFIG_PPC_POWERNV
616 DEFINE(OPAL_MC_GPR3, offsetof(struct opal_machine_check_event, gpr3));
617 DEFINE(OPAL_MC_SRR0, offsetof(struct opal_machine_check_event, srr0));
618 DEFINE(OPAL_MC_SRR1, offsetof(struct opal_machine_check_event, srr1));
619 DEFINE(PACA_OPAL_MC_EVT, offsetof(struct paca_struct, opal_mc_evt));
620#endif
621
612 return 0; 622 return 0;
613} 623}
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 41b02c792aa3..d51458fa8dee 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -1143,7 +1143,7 @@ _GLOBAL(do_stab_bolted)
1143 rfid 1143 rfid
1144 b . /* prevent speculative execution */ 1144 b . /* prevent speculative execution */
1145 1145
1146#ifdef CONFIG_PPC_PSERIES 1146#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
1147/* 1147/*
1148 * Data area reserved for FWNMI option. 1148 * Data area reserved for FWNMI option.
1149 * This address (0x7000) is fixed by the RPA. 1149 * This address (0x7000) is fixed by the RPA.
@@ -1151,7 +1151,7 @@ _GLOBAL(do_stab_bolted)
1151 .= 0x7000 1151 .= 0x7000
1152 .globl fwnmi_data_area 1152 .globl fwnmi_data_area
1153fwnmi_data_area: 1153fwnmi_data_area:
1154#endif /* CONFIG_PPC_PSERIES */ 1154#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */
1155 1155
1156 /* iSeries does not use the FWNMI stuff, so it is safe to put 1156 /* iSeries does not use the FWNMI stuff, so it is safe to put
1157 * this here, even if we later allow kernels that will boot on 1157 * this here, even if we later allow kernels that will boot on
@@ -1176,9 +1176,12 @@ xLparMap:
1176 1176
1177#endif /* CONFIG_PPC_ISERIES */ 1177#endif /* CONFIG_PPC_ISERIES */
1178 1178
1179#ifdef CONFIG_PPC_PSERIES 1179#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
1180 /* pseries and powernv need to keep the whole page from
1181 * 0x7000 to 0x8000 free for use by the firmware
1182 */
1180 . = 0x8000 1183 . = 0x8000
1181#endif /* CONFIG_PPC_PSERIES */ 1184#endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */
1182 1185
1183/* 1186/*
1184 * Space for CPU0's segment table. 1187 * Space for CPU0's segment table.
@@ -1193,3 +1196,19 @@ xLparMap:
1193 .globl initial_stab 1196 .globl initial_stab
1194initial_stab: 1197initial_stab:
1195 .space 4096 1198 .space 4096
1199#ifdef CONFIG_PPC_POWERNV
1200_GLOBAL(opal_mc_secondary_handler)
1201 HMT_MEDIUM
1202 SET_SCRATCH0(r13)
1203 GET_PACA(r13)
1204 clrldi r3,r3,2
1205 tovirt(r3,r3)
1206 std r3,PACA_OPAL_MC_EVT(r13)
1207 ld r13,OPAL_MC_SRR0(r3)
1208 mtspr SPRN_SRR0,r13
1209 ld r13,OPAL_MC_SRR1(r3)
1210 mtspr SPRN_SRR1,r13
1211 ld r3,OPAL_MC_GPR3(r3)
1212 GET_SCRATCH0(r13)
1213 b machine_check_pSeries
1214#endif /* CONFIG_PPC_POWERNV */
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 5a598caefcba..aaa0dba49471 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -27,12 +27,14 @@ struct opal {
27 27
28static struct device_node *opal_node; 28static struct device_node *opal_node;
29static DEFINE_SPINLOCK(opal_write_lock); 29static DEFINE_SPINLOCK(opal_write_lock);
30extern u64 opal_mc_secondary_handler[];
30 31
31int __init early_init_dt_scan_opal(unsigned long node, 32int __init early_init_dt_scan_opal(unsigned long node,
32 const char *uname, int depth, void *data) 33 const char *uname, int depth, void *data)
33{ 34{
34 const void *basep, *entryp; 35 const void *basep, *entryp;
35 unsigned long basesz, entrysz; 36 unsigned long basesz, entrysz;
37 u64 glue;
36 38
37 if (depth != 1 || strcmp(uname, "ibm,opal") != 0) 39 if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
38 return 0; 40 return 0;
@@ -59,6 +61,19 @@ int __init early_init_dt_scan_opal(unsigned long node,
59 printk("OPAL V1 detected !\n"); 61 printk("OPAL V1 detected !\n");
60 } 62 }
61 63
64 /* Hookup some exception handlers. We use the fwnmi area at 0x7000
65 * to provide the glue space to OPAL
66 */
67 glue = 0x7000;
68 opal_register_exception_handler(OPAL_MACHINE_CHECK_HANDLER,
69 __pa(opal_mc_secondary_handler[0]),
70 glue);
71 glue += 128;
72 opal_register_exception_handler(OPAL_HYPERVISOR_MAINTENANCE_HANDLER,
73 0, glue);
74 glue += 128;
75 opal_register_exception_handler(OPAL_SOFTPATCH_HANDLER, 0, glue);
76
62 return 1; 77 return 1;
63} 78}
64 79
@@ -136,6 +151,121 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
136 return written; 151 return written;
137} 152}
138 153
154int opal_machine_check(struct pt_regs *regs)
155{
156 struct opal_machine_check_event *opal_evt = get_paca()->opal_mc_evt;
157 struct opal_machine_check_event evt;
158 const char *level, *sevstr, *subtype;
159 static const char *opal_mc_ue_types[] = {
160 "Indeterminate",
161 "Instruction fetch",
162 "Page table walk ifetch",
163 "Load/Store",
164 "Page table walk Load/Store",
165 };
166 static const char *opal_mc_slb_types[] = {
167 "Indeterminate",
168 "Parity",
169 "Multihit",
170 };
171 static const char *opal_mc_erat_types[] = {
172 "Indeterminate",
173 "Parity",
174 "Multihit",
175 };
176 static const char *opal_mc_tlb_types[] = {
177 "Indeterminate",
178 "Parity",
179 "Multihit",
180 };
181
182 /* Copy the event structure and release the original */
183 evt = *opal_evt;
184 opal_evt->in_use = 0;
185
186 /* Print things out */
187 if (evt.version != OpalMCE_V1) {
188 pr_err("Machine Check Exception, Unknown event version %d !\n",
189 evt.version);
190 return 0;
191 }
192 switch(evt.severity) {
193 case OpalMCE_SEV_NO_ERROR:
194 level = KERN_INFO;
195 sevstr = "Harmless";
196 break;
197 case OpalMCE_SEV_WARNING:
198 level = KERN_WARNING;
199 sevstr = "";
200 break;
201 case OpalMCE_SEV_ERROR_SYNC:
202 level = KERN_ERR;
203 sevstr = "Severe";
204 break;
205 case OpalMCE_SEV_FATAL:
206 default:
207 level = KERN_ERR;
208 sevstr = "Fatal";
209 break;
210 }
211
212 printk("%s%s Machine check interrupt [%s]\n", level, sevstr,
213 evt.disposition == OpalMCE_DISPOSITION_RECOVERED ?
214 "Recovered" : "[Not recovered");
215 printk("%s Initiator: %s\n", level,
216 evt.initiator == OpalMCE_INITIATOR_CPU ? "CPU" : "Unknown");
217 switch(evt.error_type) {
218 case OpalMCE_ERROR_TYPE_UE:
219 subtype = evt.u.ue_error.ue_error_type <
220 ARRAY_SIZE(opal_mc_ue_types) ?
221 opal_mc_ue_types[evt.u.ue_error.ue_error_type]
222 : "Unknown";
223 printk("%s Error type: UE [%s]\n", level, subtype);
224 if (evt.u.ue_error.effective_address_provided)
225 printk("%s Effective address: %016llx\n",
226 level, evt.u.ue_error.effective_address);
227 if (evt.u.ue_error.physical_address_provided)
228 printk("%s Physial address: %016llx\n",
229 level, evt.u.ue_error.physical_address);
230 break;
231 case OpalMCE_ERROR_TYPE_SLB:
232 subtype = evt.u.slb_error.slb_error_type <
233 ARRAY_SIZE(opal_mc_slb_types) ?
234 opal_mc_slb_types[evt.u.slb_error.slb_error_type]
235 : "Unknown";
236 printk("%s Error type: SLB [%s]\n", level, subtype);
237 if (evt.u.slb_error.effective_address_provided)
238 printk("%s Effective address: %016llx\n",
239 level, evt.u.slb_error.effective_address);
240 break;
241 case OpalMCE_ERROR_TYPE_ERAT:
242 subtype = evt.u.erat_error.erat_error_type <
243 ARRAY_SIZE(opal_mc_erat_types) ?
244 opal_mc_erat_types[evt.u.erat_error.erat_error_type]
245 : "Unknown";
246 printk("%s Error type: ERAT [%s]\n", level, subtype);
247 if (evt.u.erat_error.effective_address_provided)
248 printk("%s Effective address: %016llx\n",
249 level, evt.u.erat_error.effective_address);
250 break;
251 case OpalMCE_ERROR_TYPE_TLB:
252 subtype = evt.u.tlb_error.tlb_error_type <
253 ARRAY_SIZE(opal_mc_tlb_types) ?
254 opal_mc_tlb_types[evt.u.tlb_error.tlb_error_type]
255 : "Unknown";
256 printk("%s Error type: TLB [%s]\n", level, subtype);
257 if (evt.u.tlb_error.effective_address_provided)
258 printk("%s Effective address: %016llx\n",
259 level, evt.u.tlb_error.effective_address);
260 break;
261 default:
262 case OpalMCE_ERROR_TYPE_UNKNOWN:
263 printk("%s Error type: Unknown\n", level);
264 break;
265 }
266 return evt.severity == OpalMCE_SEV_FATAL ? 0 : 1;
267}
268
139static irqreturn_t opal_interrupt(int irq, void *data) 269static irqreturn_t opal_interrupt(int irq, void *data)
140{ 270{
141 uint64_t events; 271 uint64_t events;
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c
index 4a2b2e279593..f0242f3fd3e6 100644
--- a/arch/powerpc/platforms/powernv/setup.c
+++ b/arch/powerpc/platforms/powernv/setup.c
@@ -141,6 +141,7 @@ static void __init pnv_setup_machdep_opal(void)
141 ppc_md.restart = pnv_restart; 141 ppc_md.restart = pnv_restart;
142 ppc_md.power_off = pnv_power_off; 142 ppc_md.power_off = pnv_power_off;
143 ppc_md.halt = pnv_halt; 143 ppc_md.halt = pnv_halt;
144 ppc_md.machine_check_exception = opal_machine_check;
144} 145}
145 146
146#ifdef CONFIG_PPC_POWERNV_RTAS 147#ifdef CONFIG_PPC_POWERNV_RTAS