.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * PowerNV OPAL high level interfaces |
---|
3 | 4 | * |
---|
4 | 5 | * 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 | 6 | */ |
---|
11 | 7 | |
---|
12 | 8 | #define pr_fmt(fmt) "opal: " fmt |
---|
.. | .. |
---|
26 | 22 | #include <linux/memblock.h> |
---|
27 | 23 | #include <linux/kthread.h> |
---|
28 | 24 | #include <linux/freezer.h> |
---|
29 | | -#include <linux/printk.h> |
---|
30 | 25 | #include <linux/kmsg_dump.h> |
---|
31 | 26 | #include <linux/console.h> |
---|
32 | 27 | #include <linux/sched/debug.h> |
---|
.. | .. |
---|
39 | 34 | #include <asm/bug.h> |
---|
40 | 35 | |
---|
41 | 36 | #include "powernv.h" |
---|
| 37 | + |
---|
| 38 | +#define OPAL_MSG_QUEUE_MAX 16 |
---|
| 39 | + |
---|
| 40 | +struct opal_msg_node { |
---|
| 41 | + struct list_head list; |
---|
| 42 | + struct opal_msg msg; |
---|
| 43 | +}; |
---|
| 44 | + |
---|
| 45 | +static DEFINE_SPINLOCK(msg_list_lock); |
---|
| 46 | +static LIST_HEAD(msg_list); |
---|
42 | 47 | |
---|
43 | 48 | /* /sys/firmware/opal */ |
---|
44 | 49 | struct kobject *opal_kobj; |
---|
.. | .. |
---|
55 | 60 | u64 recover_addr; |
---|
56 | 61 | }; |
---|
57 | 62 | |
---|
| 63 | +static int msg_list_size; |
---|
| 64 | + |
---|
58 | 65 | static struct mcheck_recoverable_range *mc_recoverable_range; |
---|
59 | 66 | static int mc_recoverable_range_len; |
---|
60 | 67 | |
---|
.. | .. |
---|
63 | 70 | static struct atomic_notifier_head opal_msg_notifier_head[OPAL_MSG_TYPE_MAX]; |
---|
64 | 71 | static uint32_t opal_heartbeat; |
---|
65 | 72 | static struct task_struct *kopald_tsk; |
---|
| 73 | +static struct opal_msg *opal_msg; |
---|
| 74 | +static u32 opal_msg_size __ro_after_init; |
---|
66 | 75 | |
---|
67 | 76 | void opal_configure_cores(void) |
---|
68 | 77 | { |
---|
.. | .. |
---|
171 | 180 | /* |
---|
172 | 181 | * Allocate a buffer to hold the MC recoverable ranges. |
---|
173 | 182 | */ |
---|
174 | | - mc_recoverable_range =__va(memblock_alloc(size, __alignof__(u64))); |
---|
175 | | - memset(mc_recoverable_range, 0, size); |
---|
| 183 | + mc_recoverable_range = memblock_alloc(size, __alignof__(u64)); |
---|
| 184 | + if (!mc_recoverable_range) |
---|
| 185 | + panic("%s: Failed to allocate %u bytes align=0x%lx\n", |
---|
| 186 | + __func__, size, __alignof__(u64)); |
---|
176 | 187 | |
---|
177 | 188 | for (i = 0; i < mc_recoverable_range_len; i++) { |
---|
178 | 189 | mc_recoverable_range[i].start_addr = |
---|
.. | .. |
---|
205 | 216 | glue = 0x7000; |
---|
206 | 217 | |
---|
207 | 218 | /* |
---|
208 | | - * Check if we are running on newer firmware that exports |
---|
209 | | - * OPAL_HANDLE_HMI token. If yes, then don't ask OPAL to patch |
---|
210 | | - * the HMI interrupt and we catch it directly in Linux. |
---|
| 219 | + * Only ancient OPAL firmware requires this. |
---|
| 220 | + * Specifically, firmware from FW810.00 (released June 2014) |
---|
| 221 | + * through FW810.20 (Released October 2014). |
---|
211 | 222 | * |
---|
212 | | - * For older firmware (i.e currently released POWER8 System Firmware |
---|
213 | | - * as of today <= SV810_087), we fallback to old behavior and let OPAL |
---|
214 | | - * patch the HMI vector and handle it inside OPAL firmware. |
---|
| 223 | + * Check if we are running on newer (post Oct 2014) firmware that |
---|
| 224 | + * exports the OPAL_HANDLE_HMI token. If yes, then don't ask OPAL to |
---|
| 225 | + * patch the HMI interrupt and we catch it directly in Linux. |
---|
215 | 226 | * |
---|
216 | | - * For newer firmware (in development/yet to be released) we will |
---|
217 | | - * start catching/handling HMI directly in Linux. |
---|
| 227 | + * For older firmware (i.e < FW810.20), we fallback to old behavior and |
---|
| 228 | + * let OPAL patch the HMI vector and handle it inside OPAL firmware. |
---|
| 229 | + * |
---|
| 230 | + * For newer firmware we catch/handle the HMI directly in Linux. |
---|
218 | 231 | */ |
---|
219 | 232 | if (!opal_check_token(OPAL_HANDLE_HMI)) { |
---|
220 | 233 | pr_info("Old firmware detected, OPAL handles HMIs.\n"); |
---|
.. | .. |
---|
224 | 237 | glue += 128; |
---|
225 | 238 | } |
---|
226 | 239 | |
---|
| 240 | + /* |
---|
| 241 | + * Only applicable to ancient firmware, all modern |
---|
| 242 | + * (post March 2015/skiboot 5.0) firmware will just return |
---|
| 243 | + * OPAL_UNSUPPORTED. |
---|
| 244 | + */ |
---|
227 | 245 | opal_register_exception_handler(OPAL_SOFTPATCH_HANDLER, 0, glue); |
---|
228 | 246 | #endif |
---|
229 | 247 | |
---|
230 | 248 | return 0; |
---|
231 | 249 | } |
---|
232 | 250 | machine_early_initcall(powernv, opal_register_exception_handlers); |
---|
| 251 | + |
---|
| 252 | +static void queue_replay_msg(void *msg) |
---|
| 253 | +{ |
---|
| 254 | + struct opal_msg_node *msg_node; |
---|
| 255 | + |
---|
| 256 | + if (msg_list_size < OPAL_MSG_QUEUE_MAX) { |
---|
| 257 | + msg_node = kzalloc(sizeof(*msg_node), GFP_ATOMIC); |
---|
| 258 | + if (msg_node) { |
---|
| 259 | + INIT_LIST_HEAD(&msg_node->list); |
---|
| 260 | + memcpy(&msg_node->msg, msg, sizeof(struct opal_msg)); |
---|
| 261 | + list_add_tail(&msg_node->list, &msg_list); |
---|
| 262 | + msg_list_size++; |
---|
| 263 | + } else |
---|
| 264 | + pr_warn_once("message queue no memory\n"); |
---|
| 265 | + |
---|
| 266 | + if (msg_list_size >= OPAL_MSG_QUEUE_MAX) |
---|
| 267 | + pr_warn_once("message queue full\n"); |
---|
| 268 | + } |
---|
| 269 | +} |
---|
| 270 | + |
---|
| 271 | +static void dequeue_replay_msg(enum opal_msg_type msg_type) |
---|
| 272 | +{ |
---|
| 273 | + struct opal_msg_node *msg_node, *tmp; |
---|
| 274 | + |
---|
| 275 | + list_for_each_entry_safe(msg_node, tmp, &msg_list, list) { |
---|
| 276 | + if (be32_to_cpu(msg_node->msg.msg_type) != msg_type) |
---|
| 277 | + continue; |
---|
| 278 | + |
---|
| 279 | + atomic_notifier_call_chain(&opal_msg_notifier_head[msg_type], |
---|
| 280 | + msg_type, |
---|
| 281 | + &msg_node->msg); |
---|
| 282 | + |
---|
| 283 | + list_del(&msg_node->list); |
---|
| 284 | + kfree(msg_node); |
---|
| 285 | + msg_list_size--; |
---|
| 286 | + } |
---|
| 287 | +} |
---|
233 | 288 | |
---|
234 | 289 | /* |
---|
235 | 290 | * Opal message notifier based on message type. Allow subscribers to get |
---|
.. | .. |
---|
238 | 293 | int opal_message_notifier_register(enum opal_msg_type msg_type, |
---|
239 | 294 | struct notifier_block *nb) |
---|
240 | 295 | { |
---|
| 296 | + int ret; |
---|
| 297 | + unsigned long flags; |
---|
| 298 | + |
---|
241 | 299 | if (!nb || msg_type >= OPAL_MSG_TYPE_MAX) { |
---|
242 | 300 | pr_warn("%s: Invalid arguments, msg_type:%d\n", |
---|
243 | 301 | __func__, msg_type); |
---|
244 | 302 | return -EINVAL; |
---|
245 | 303 | } |
---|
246 | 304 | |
---|
247 | | - return atomic_notifier_chain_register( |
---|
248 | | - &opal_msg_notifier_head[msg_type], nb); |
---|
| 305 | + spin_lock_irqsave(&msg_list_lock, flags); |
---|
| 306 | + ret = atomic_notifier_chain_register( |
---|
| 307 | + &opal_msg_notifier_head[msg_type], nb); |
---|
| 308 | + |
---|
| 309 | + /* |
---|
| 310 | + * If the registration succeeded, replay any queued messages that came |
---|
| 311 | + * in prior to the notifier chain registration. msg_list_lock held here |
---|
| 312 | + * to ensure they're delivered prior to any subsequent messages. |
---|
| 313 | + */ |
---|
| 314 | + if (ret == 0) |
---|
| 315 | + dequeue_replay_msg(msg_type); |
---|
| 316 | + |
---|
| 317 | + spin_unlock_irqrestore(&msg_list_lock, flags); |
---|
| 318 | + |
---|
| 319 | + return ret; |
---|
249 | 320 | } |
---|
250 | 321 | EXPORT_SYMBOL_GPL(opal_message_notifier_register); |
---|
251 | 322 | |
---|
.. | .. |
---|
259 | 330 | |
---|
260 | 331 | static void opal_message_do_notify(uint32_t msg_type, void *msg) |
---|
261 | 332 | { |
---|
| 333 | + unsigned long flags; |
---|
| 334 | + bool queued = false; |
---|
| 335 | + |
---|
| 336 | + spin_lock_irqsave(&msg_list_lock, flags); |
---|
| 337 | + if (opal_msg_notifier_head[msg_type].head == NULL) { |
---|
| 338 | + /* |
---|
| 339 | + * Queue up the msg since no notifiers have registered |
---|
| 340 | + * yet for this msg_type. |
---|
| 341 | + */ |
---|
| 342 | + queue_replay_msg(msg); |
---|
| 343 | + queued = true; |
---|
| 344 | + } |
---|
| 345 | + spin_unlock_irqrestore(&msg_list_lock, flags); |
---|
| 346 | + |
---|
| 347 | + if (queued) |
---|
| 348 | + return; |
---|
| 349 | + |
---|
262 | 350 | /* notify subscribers */ |
---|
263 | 351 | atomic_notifier_call_chain(&opal_msg_notifier_head[msg_type], |
---|
264 | 352 | msg_type, msg); |
---|
.. | .. |
---|
267 | 355 | static void opal_handle_message(void) |
---|
268 | 356 | { |
---|
269 | 357 | s64 ret; |
---|
270 | | - /* |
---|
271 | | - * TODO: pre-allocate a message buffer depending on opal-msg-size |
---|
272 | | - * value in /proc/device-tree. |
---|
273 | | - */ |
---|
274 | | - static struct opal_msg msg; |
---|
275 | 358 | u32 type; |
---|
276 | 359 | |
---|
277 | | - ret = opal_get_msg(__pa(&msg), sizeof(msg)); |
---|
| 360 | + ret = opal_get_msg(__pa(opal_msg), opal_msg_size); |
---|
278 | 361 | /* No opal message pending. */ |
---|
279 | 362 | if (ret == OPAL_RESOURCE) |
---|
280 | 363 | return; |
---|
.. | .. |
---|
286 | 369 | return; |
---|
287 | 370 | } |
---|
288 | 371 | |
---|
289 | | - type = be32_to_cpu(msg.msg_type); |
---|
| 372 | + type = be32_to_cpu(opal_msg->msg_type); |
---|
290 | 373 | |
---|
291 | 374 | /* Sanity check */ |
---|
292 | 375 | if (type >= OPAL_MSG_TYPE_MAX) { |
---|
293 | 376 | pr_warn_once("%s: Unknown message type: %u\n", __func__, type); |
---|
294 | 377 | return; |
---|
295 | 378 | } |
---|
296 | | - opal_message_do_notify(type, (void *)&msg); |
---|
| 379 | + opal_message_do_notify(type, (void *)opal_msg); |
---|
297 | 380 | } |
---|
298 | 381 | |
---|
299 | 382 | static irqreturn_t opal_message_notify(int irq, void *data) |
---|
.. | .. |
---|
302 | 385 | return IRQ_HANDLED; |
---|
303 | 386 | } |
---|
304 | 387 | |
---|
305 | | -static int __init opal_message_init(void) |
---|
| 388 | +static int __init opal_message_init(struct device_node *opal_node) |
---|
306 | 389 | { |
---|
307 | 390 | int ret, i, irq; |
---|
| 391 | + |
---|
| 392 | + ret = of_property_read_u32(opal_node, "opal-msg-size", &opal_msg_size); |
---|
| 393 | + if (ret) { |
---|
| 394 | + pr_notice("Failed to read opal-msg-size property\n"); |
---|
| 395 | + opal_msg_size = sizeof(struct opal_msg); |
---|
| 396 | + } |
---|
| 397 | + |
---|
| 398 | + opal_msg = kmalloc(opal_msg_size, GFP_KERNEL); |
---|
| 399 | + if (!opal_msg) { |
---|
| 400 | + opal_msg_size = sizeof(struct opal_msg); |
---|
| 401 | + /* Try to allocate fixed message size */ |
---|
| 402 | + opal_msg = kmalloc(opal_msg_size, GFP_KERNEL); |
---|
| 403 | + BUG_ON(opal_msg == NULL); |
---|
| 404 | + } |
---|
308 | 405 | |
---|
309 | 406 | for (i = 0; i < OPAL_MSG_TYPE_MAX; i++) |
---|
310 | 407 | ATOMIC_INIT_NOTIFIER_HEAD(&opal_msg_notifier_head[i]); |
---|
.. | .. |
---|
504 | 601 | recovered = 0; |
---|
505 | 602 | } |
---|
506 | 603 | |
---|
507 | | - if (!recovered && evt->severity == MCE_SEV_ERROR_SYNC) { |
---|
| 604 | + if (!recovered && evt->sync_error) { |
---|
508 | 605 | /* |
---|
509 | 606 | * Try to kill processes if we get a synchronous machine check |
---|
510 | 607 | * (e.g., one caused by execution of this instruction). This |
---|
.. | .. |
---|
535 | 632 | return recovered; |
---|
536 | 633 | } |
---|
537 | 634 | |
---|
538 | | -void pnv_platform_error_reboot(struct pt_regs *regs, const char *msg) |
---|
| 635 | +void __noreturn pnv_platform_error_reboot(struct pt_regs *regs, const char *msg) |
---|
539 | 636 | { |
---|
540 | 637 | panic_flush_kmsg_start(); |
---|
541 | 638 | |
---|
.. | .. |
---|
587 | 684 | evt.version); |
---|
588 | 685 | return 0; |
---|
589 | 686 | } |
---|
590 | | - machine_check_print_event_info(&evt, user_mode(regs)); |
---|
| 687 | + machine_check_print_event_info(&evt, user_mode(regs), false); |
---|
591 | 688 | |
---|
592 | 689 | if (opal_recover_mce(regs, &evt)) |
---|
593 | 690 | return 1; |
---|
.. | .. |
---|
613 | 710 | return 0; |
---|
614 | 711 | } |
---|
615 | 712 | |
---|
616 | | -/* HMI exception handler called in virtual mode during check_irq_replay. */ |
---|
| 713 | +int opal_hmi_exception_early2(struct pt_regs *regs) |
---|
| 714 | +{ |
---|
| 715 | + s64 rc; |
---|
| 716 | + __be64 out_flags; |
---|
| 717 | + |
---|
| 718 | + /* |
---|
| 719 | + * call opal hmi handler. |
---|
| 720 | + * Check 64-bit flag mask to find out if an event was generated, |
---|
| 721 | + * and whether TB is still valid or not etc. |
---|
| 722 | + */ |
---|
| 723 | + rc = opal_handle_hmi2(&out_flags); |
---|
| 724 | + if (rc != OPAL_SUCCESS) |
---|
| 725 | + return 0; |
---|
| 726 | + |
---|
| 727 | + if (be64_to_cpu(out_flags) & OPAL_HMI_FLAGS_NEW_EVENT) |
---|
| 728 | + local_paca->hmi_event_available = 1; |
---|
| 729 | + if (be64_to_cpu(out_flags) & OPAL_HMI_FLAGS_TOD_TB_FAIL) |
---|
| 730 | + tb_invalid = true; |
---|
| 731 | + return 1; |
---|
| 732 | +} |
---|
| 733 | + |
---|
| 734 | +/* HMI exception handler called in virtual mode when irqs are next enabled. */ |
---|
617 | 735 | int opal_handle_hmi_exception(struct pt_regs *regs) |
---|
618 | 736 | { |
---|
619 | 737 | /* |
---|
.. | .. |
---|
672 | 790 | return 0; |
---|
673 | 791 | } |
---|
674 | 792 | |
---|
675 | | -static ssize_t symbol_map_read(struct file *fp, struct kobject *kobj, |
---|
676 | | - struct bin_attribute *bin_attr, |
---|
677 | | - char *buf, loff_t off, size_t count) |
---|
678 | | -{ |
---|
679 | | - return memory_read_from_buffer(buf, count, &off, bin_attr->private, |
---|
680 | | - bin_attr->size); |
---|
681 | | -} |
---|
682 | | - |
---|
683 | | -static struct bin_attribute symbol_map_attr = { |
---|
684 | | - .attr = {.name = "symbol_map", .mode = 0400}, |
---|
685 | | - .read = symbol_map_read |
---|
686 | | -}; |
---|
687 | | - |
---|
688 | | -static void opal_export_symmap(void) |
---|
689 | | -{ |
---|
690 | | - const __be64 *syms; |
---|
691 | | - unsigned int size; |
---|
692 | | - struct device_node *fw; |
---|
693 | | - int rc; |
---|
694 | | - |
---|
695 | | - fw = of_find_node_by_path("/ibm,opal/firmware"); |
---|
696 | | - if (!fw) |
---|
697 | | - return; |
---|
698 | | - syms = of_get_property(fw, "symbol-map", &size); |
---|
699 | | - if (!syms || size != 2 * sizeof(__be64)) |
---|
700 | | - return; |
---|
701 | | - |
---|
702 | | - /* Setup attributes */ |
---|
703 | | - symbol_map_attr.private = __va(be64_to_cpu(syms[0])); |
---|
704 | | - symbol_map_attr.size = be64_to_cpu(syms[1]); |
---|
705 | | - |
---|
706 | | - rc = sysfs_create_bin_file(opal_kobj, &symbol_map_attr); |
---|
707 | | - if (rc) |
---|
708 | | - pr_warn("Error %d creating OPAL symbols file\n", rc); |
---|
709 | | -} |
---|
710 | | - |
---|
711 | 793 | static ssize_t export_attr_read(struct file *fp, struct kobject *kobj, |
---|
712 | 794 | struct bin_attribute *bin_attr, char *buf, |
---|
713 | 795 | loff_t off, size_t count) |
---|
714 | 796 | { |
---|
715 | 797 | return memory_read_from_buffer(buf, count, &off, bin_attr->private, |
---|
716 | 798 | bin_attr->size); |
---|
| 799 | +} |
---|
| 800 | + |
---|
| 801 | +static int opal_add_one_export(struct kobject *parent, const char *export_name, |
---|
| 802 | + struct device_node *np, const char *prop_name) |
---|
| 803 | +{ |
---|
| 804 | + struct bin_attribute *attr = NULL; |
---|
| 805 | + const char *name = NULL; |
---|
| 806 | + u64 vals[2]; |
---|
| 807 | + int rc; |
---|
| 808 | + |
---|
| 809 | + rc = of_property_read_u64_array(np, prop_name, &vals[0], 2); |
---|
| 810 | + if (rc) |
---|
| 811 | + goto out; |
---|
| 812 | + |
---|
| 813 | + attr = kzalloc(sizeof(*attr), GFP_KERNEL); |
---|
| 814 | + if (!attr) { |
---|
| 815 | + rc = -ENOMEM; |
---|
| 816 | + goto out; |
---|
| 817 | + } |
---|
| 818 | + name = kstrdup(export_name, GFP_KERNEL); |
---|
| 819 | + if (!name) { |
---|
| 820 | + rc = -ENOMEM; |
---|
| 821 | + goto out; |
---|
| 822 | + } |
---|
| 823 | + |
---|
| 824 | + sysfs_bin_attr_init(attr); |
---|
| 825 | + attr->attr.name = name; |
---|
| 826 | + attr->attr.mode = 0400; |
---|
| 827 | + attr->read = export_attr_read; |
---|
| 828 | + attr->private = __va(vals[0]); |
---|
| 829 | + attr->size = vals[1]; |
---|
| 830 | + |
---|
| 831 | + rc = sysfs_create_bin_file(parent, attr); |
---|
| 832 | +out: |
---|
| 833 | + if (rc) { |
---|
| 834 | + kfree(name); |
---|
| 835 | + kfree(attr); |
---|
| 836 | + } |
---|
| 837 | + |
---|
| 838 | + return rc; |
---|
| 839 | +} |
---|
| 840 | + |
---|
| 841 | +static void opal_add_exported_attrs(struct device_node *np, |
---|
| 842 | + struct kobject *kobj) |
---|
| 843 | +{ |
---|
| 844 | + struct device_node *child; |
---|
| 845 | + struct property *prop; |
---|
| 846 | + |
---|
| 847 | + for_each_property_of_node(np, prop) { |
---|
| 848 | + int rc; |
---|
| 849 | + |
---|
| 850 | + if (!strcmp(prop->name, "name") || |
---|
| 851 | + !strcmp(prop->name, "phandle")) |
---|
| 852 | + continue; |
---|
| 853 | + |
---|
| 854 | + rc = opal_add_one_export(kobj, prop->name, np, prop->name); |
---|
| 855 | + if (rc) { |
---|
| 856 | + pr_warn("Unable to add export %pOF/%s, rc = %d!\n", |
---|
| 857 | + np, prop->name, rc); |
---|
| 858 | + } |
---|
| 859 | + } |
---|
| 860 | + |
---|
| 861 | + for_each_child_of_node(np, child) { |
---|
| 862 | + struct kobject *child_kobj; |
---|
| 863 | + |
---|
| 864 | + child_kobj = kobject_create_and_add(child->name, kobj); |
---|
| 865 | + if (!child_kobj) { |
---|
| 866 | + pr_err("Unable to create export dir for %pOF\n", child); |
---|
| 867 | + continue; |
---|
| 868 | + } |
---|
| 869 | + |
---|
| 870 | + opal_add_exported_attrs(child, child_kobj); |
---|
| 871 | + } |
---|
717 | 872 | } |
---|
718 | 873 | |
---|
719 | 874 | /* |
---|
.. | .. |
---|
725 | 880 | */ |
---|
726 | 881 | static void opal_export_attrs(void) |
---|
727 | 882 | { |
---|
728 | | - struct bin_attribute *attr; |
---|
729 | 883 | struct device_node *np; |
---|
730 | | - struct property *prop; |
---|
731 | 884 | struct kobject *kobj; |
---|
732 | | - u64 vals[2]; |
---|
733 | 885 | int rc; |
---|
734 | 886 | |
---|
735 | 887 | np = of_find_node_by_path("/ibm,opal/firmware/exports"); |
---|
.. | .. |
---|
740 | 892 | kobj = kobject_create_and_add("exports", opal_kobj); |
---|
741 | 893 | if (!kobj) { |
---|
742 | 894 | pr_warn("kobject_create_and_add() of exports failed\n"); |
---|
| 895 | + of_node_put(np); |
---|
743 | 896 | return; |
---|
744 | 897 | } |
---|
745 | 898 | |
---|
746 | | - for_each_property_of_node(np, prop) { |
---|
747 | | - if (!strcmp(prop->name, "name") || !strcmp(prop->name, "phandle")) |
---|
748 | | - continue; |
---|
| 899 | + opal_add_exported_attrs(np, kobj); |
---|
749 | 900 | |
---|
750 | | - if (of_property_read_u64_array(np, prop->name, &vals[0], 2)) |
---|
751 | | - continue; |
---|
752 | | - |
---|
753 | | - attr = kzalloc(sizeof(*attr), GFP_KERNEL); |
---|
754 | | - |
---|
755 | | - if (attr == NULL) { |
---|
756 | | - pr_warn("Failed kmalloc for bin_attribute!"); |
---|
757 | | - continue; |
---|
758 | | - } |
---|
759 | | - |
---|
760 | | - sysfs_bin_attr_init(attr); |
---|
761 | | - attr->attr.name = kstrdup(prop->name, GFP_KERNEL); |
---|
762 | | - attr->attr.mode = 0400; |
---|
763 | | - attr->read = export_attr_read; |
---|
764 | | - attr->private = __va(vals[0]); |
---|
765 | | - attr->size = vals[1]; |
---|
766 | | - |
---|
767 | | - if (attr->attr.name == NULL) { |
---|
768 | | - pr_warn("Failed kstrdup for bin_attribute attr.name"); |
---|
769 | | - kfree(attr); |
---|
770 | | - continue; |
---|
771 | | - } |
---|
772 | | - |
---|
773 | | - rc = sysfs_create_bin_file(kobj, attr); |
---|
774 | | - if (rc) { |
---|
775 | | - pr_warn("Error %d creating OPAL sysfs exports/%s file\n", |
---|
776 | | - rc, prop->name); |
---|
777 | | - kfree(attr->attr.name); |
---|
778 | | - kfree(attr); |
---|
779 | | - } |
---|
780 | | - } |
---|
| 901 | + /* |
---|
| 902 | + * NB: symbol_map existed before the generic export interface so it |
---|
| 903 | + * lives under the top level opal_kobj. |
---|
| 904 | + */ |
---|
| 905 | + rc = opal_add_one_export(opal_kobj, "symbol_map", |
---|
| 906 | + np->parent, "symbol-map"); |
---|
| 907 | + if (rc) |
---|
| 908 | + pr_warn("Error %d creating OPAL symbols file\n", rc); |
---|
781 | 909 | |
---|
782 | 910 | of_node_put(np); |
---|
783 | 911 | } |
---|
.. | .. |
---|
880 | 1008 | consoles = of_find_node_by_path("/ibm,opal/consoles"); |
---|
881 | 1009 | if (consoles) { |
---|
882 | 1010 | for_each_child_of_node(consoles, np) { |
---|
883 | | - if (strcmp(np->name, "serial")) |
---|
| 1011 | + if (!of_node_name_eq(np, "serial")) |
---|
884 | 1012 | continue; |
---|
885 | 1013 | of_platform_device_create(np, NULL, NULL); |
---|
886 | 1014 | } |
---|
.. | .. |
---|
888 | 1016 | } |
---|
889 | 1017 | |
---|
890 | 1018 | /* Initialise OPAL messaging system */ |
---|
891 | | - opal_message_init(); |
---|
| 1019 | + opal_message_init(opal_node); |
---|
892 | 1020 | |
---|
893 | 1021 | /* Initialise OPAL asynchronous completion interface */ |
---|
894 | 1022 | opal_async_comp_init(); |
---|
.. | .. |
---|
924 | 1052 | /* Create "opal" kobject under /sys/firmware */ |
---|
925 | 1053 | rc = opal_sysfs_init(); |
---|
926 | 1054 | if (rc == 0) { |
---|
927 | | - /* Export symbol map to userspace */ |
---|
928 | | - opal_export_symmap(); |
---|
929 | 1055 | /* Setup dump region interface */ |
---|
930 | 1056 | opal_dump_region_init(); |
---|
931 | 1057 | /* Setup error log interface */ |
---|
.. | .. |
---|
938 | 1064 | opal_sys_param_init(); |
---|
939 | 1065 | /* Setup message log sysfs interface. */ |
---|
940 | 1066 | opal_msglog_sysfs_init(); |
---|
| 1067 | + /* Add all export properties*/ |
---|
| 1068 | + opal_export_attrs(); |
---|
941 | 1069 | } |
---|
942 | | - |
---|
943 | | - /* Export all properties */ |
---|
944 | | - opal_export_attrs(); |
---|
945 | 1070 | |
---|
946 | 1071 | /* Initialize platform devices: IPMI backend, PRD & flash interface */ |
---|
947 | 1072 | opal_pdev_init("ibm,opal-ipmi"); |
---|
.. | .. |
---|
963 | 1088 | /* Initialise OPAL sensor groups */ |
---|
964 | 1089 | opal_sensor_groups_init(); |
---|
965 | 1090 | |
---|
| 1091 | + /* Initialise OPAL Power control interface */ |
---|
| 1092 | + opal_power_control_init(); |
---|
| 1093 | + |
---|
| 1094 | + /* Initialize OPAL secure variables */ |
---|
| 1095 | + opal_pdev_init("ibm,secvar-backend"); |
---|
| 1096 | + |
---|
966 | 1097 | return 0; |
---|
967 | 1098 | } |
---|
968 | 1099 | machine_subsys_initcall(powernv, opal_init); |
---|