Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
opal.c
Go to the documentation of this file.
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 {
26 } opal;
27 
28 static struct device_node *opal_node;
29 static DEFINE_SPINLOCK(opal_write_lock);
31 
33  const char *uname, int depth, void *data)
34 {
35  const void *basep, *entryp;
36  unsigned long basesz, entrysz;
37  u64 glue;
38 
39  if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
40  return 0;
41 
42  basep = of_get_flat_dt_prop(node, "opal-base-address", &basesz);
43  entryp = of_get_flat_dt_prop(node, "opal-entry-address", &entrysz);
44 
45  if (!basep || !entryp)
46  return 1;
47 
48  opal.base = of_read_number(basep, basesz/4);
49  opal.entry = of_read_number(entryp, entrysz/4);
50 
51  pr_debug("OPAL Base = 0x%llx (basep=%p basesz=%ld)\n",
52  opal.base, basep, basesz);
53  pr_debug("OPAL Entry = 0x%llx (entryp=%p basesz=%ld)\n",
54  opal.entry, entryp, entrysz);
55 
56  powerpc_firmware_features |= FW_FEATURE_OPAL;
57  if (of_flat_dt_is_compatible(node, "ibm,opal-v2")) {
58  powerpc_firmware_features |= FW_FEATURE_OPALv2;
59  printk("OPAL V2 detected !\n");
60  } else {
61  printk("OPAL V1 detected !\n");
62  }
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;
70  glue);
71  glue += 128;
73  0, glue);
74  glue += 128;
76 
77  return 1;
78 }
79 
80 int opal_get_chars(uint32_t vtermno, char *buf, int count)
81 {
82  s64 len, rc;
83  u64 evt;
84 
85  if (!opal.entry)
86  return -ENODEV;
87  opal_poll_events(&evt);
88  if ((evt & OPAL_EVENT_CONSOLE_INPUT) == 0)
89  return 0;
90  len = count;
91  rc = opal_console_read(vtermno, &len, buf);
92  if (rc == OPAL_SUCCESS)
93  return len;
94  return 0;
95 }
96 
97 int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
98 {
99  int written = 0;
100  s64 len, rc;
101  unsigned long flags;
102  u64 evt;
103 
104  if (!opal.entry)
105  return -ENODEV;
106 
107  /* We want put_chars to be atomic to avoid mangling of hvsi
108  * packets. To do that, we first test for room and return
109  * -EAGAIN if there isn't enough.
110  *
111  * Unfortunately, opal_console_write_buffer_space() doesn't
112  * appear to work on opal v1, so we just assume there is
113  * enough room and be done with it
114  */
115  spin_lock_irqsave(&opal_write_lock, flags);
116  if (firmware_has_feature(FW_FEATURE_OPALv2)) {
117  rc = opal_console_write_buffer_space(vtermno, &len);
118  if (rc || len < total_len) {
119  spin_unlock_irqrestore(&opal_write_lock, flags);
120  /* Closed -> drop characters */
121  if (rc)
122  return total_len;
123  opal_poll_events(&evt);
124  return -EAGAIN;
125  }
126  }
127 
128  /* We still try to handle partial completions, though they
129  * should no longer happen.
130  */
131  rc = OPAL_BUSY;
132  while(total_len > 0 && (rc == OPAL_BUSY ||
133  rc == OPAL_BUSY_EVENT || rc == OPAL_SUCCESS)) {
134  len = total_len;
135  rc = opal_console_write(vtermno, &len, data);
136  if (rc == OPAL_SUCCESS) {
137  total_len -= len;
138  data += len;
139  written += len;
140  }
141  /* This is a bit nasty but we need that for the console to
142  * flush when there aren't any interrupts. We will clean
143  * things a bit later to limit that to synchronous path
144  * such as the kernel console and xmon/udbg
145  */
146  do
147  opal_poll_events(&evt);
148  while(rc == OPAL_SUCCESS && (evt & OPAL_EVENT_CONSOLE_OUTPUT));
149  }
150  spin_unlock_irqrestore(&opal_write_lock, flags);
151  return written;
152 }
153 
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) {
194  level = KERN_INFO;
195  sevstr = "Harmless";
196  break;
197  case OpalMCE_SEV_WARNING:
198  level = KERN_WARNING;
199  sevstr = "";
200  break;
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) {
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;
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;
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;
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:
263  printk("%s Error type: Unknown\n", level);
264  break;
265  }
266  return evt.severity == OpalMCE_SEV_FATAL ? 0 : 1;
267 }
268 
269 static irqreturn_t opal_interrupt(int irq, void *data)
270 {
272 
273  opal_handle_interrupt(virq_to_hw(irq), &events);
274 
275  /* XXX TODO: Do something with the events */
276 
277  return IRQ_HANDLED;
278 }
279 
280 static int __init opal_init(void)
281 {
282  struct device_node *np, *consoles;
283  const u32 *irqs;
284  int rc, i, irqlen;
285 
286  opal_node = of_find_node_by_path("/ibm,opal");
287  if (!opal_node) {
288  pr_warn("opal: Node not found\n");
289  return -ENODEV;
290  }
291  if (firmware_has_feature(FW_FEATURE_OPALv2))
292  consoles = of_find_node_by_path("/ibm,opal/consoles");
293  else
294  consoles = of_node_get(opal_node);
295 
296  /* Register serial ports */
297  for_each_child_of_node(consoles, np) {
298  if (strcmp(np->name, "serial"))
299  continue;
300  of_platform_device_create(np, NULL, NULL);
301  }
302  of_node_put(consoles);
303 
304  /* Find all OPAL interrupts and request them */
305  irqs = of_get_property(opal_node, "opal-interrupts", &irqlen);
306  pr_debug("opal: Found %d interrupts reserved for OPAL\n",
307  irqs ? (irqlen / 4) : 0);
308  for (i = 0; irqs && i < (irqlen / 4); i++, irqs++) {
309  unsigned int hwirq = be32_to_cpup(irqs);
310  unsigned int irq = irq_create_mapping(NULL, hwirq);
311  if (irq == NO_IRQ) {
312  pr_warning("opal: Failed to map irq 0x%x\n", hwirq);
313  continue;
314  }
315  rc = request_irq(irq, opal_interrupt, 0, "opal", NULL);
316  if (rc)
317  pr_warning("opal: Error %d requesting irq %d"
318  " (0x%x)\n", rc, irq, hwirq);
319  }
320  return 0;
321 }
322 subsys_initcall(opal_init);