aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/powernv/opal.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms/powernv/opal.c')
-rw-r--r--arch/powerpc/platforms/powernv/opal.c92
1 files changed, 81 insertions, 11 deletions
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 18fd4e71c9c1..2241565b0739 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -23,6 +23,8 @@
23#include <linux/kobject.h> 23#include <linux/kobject.h>
24#include <linux/delay.h> 24#include <linux/delay.h>
25#include <linux/memblock.h> 25#include <linux/memblock.h>
26#include <linux/kthread.h>
27#include <linux/freezer.h>
26 28
27#include <asm/machdep.h> 29#include <asm/machdep.h>
28#include <asm/opal.h> 30#include <asm/opal.h>
@@ -58,6 +60,7 @@ static struct atomic_notifier_head opal_msg_notifier_head[OPAL_MSG_TYPE_MAX];
58static DEFINE_SPINLOCK(opal_notifier_lock); 60static DEFINE_SPINLOCK(opal_notifier_lock);
59static uint64_t last_notified_mask = 0x0ul; 61static uint64_t last_notified_mask = 0x0ul;
60static atomic_t opal_notifier_hold = ATOMIC_INIT(0); 62static atomic_t opal_notifier_hold = ATOMIC_INIT(0);
63static uint32_t opal_heartbeat;
61 64
62static void opal_reinit_cores(void) 65static void opal_reinit_cores(void)
63{ 66{
@@ -302,23 +305,26 @@ void opal_notifier_disable(void)
302 * Opal message notifier based on message type. Allow subscribers to get 305 * Opal message notifier based on message type. Allow subscribers to get
303 * notified for specific messgae type. 306 * notified for specific messgae type.
304 */ 307 */
305int opal_message_notifier_register(enum OpalMessageType msg_type, 308int opal_message_notifier_register(enum opal_msg_type msg_type,
306 struct notifier_block *nb) 309 struct notifier_block *nb)
307{ 310{
308 if (!nb) { 311 if (!nb || msg_type >= OPAL_MSG_TYPE_MAX) {
309 pr_warning("%s: Invalid argument (%p)\n", 312 pr_warning("%s: Invalid arguments, msg_type:%d\n",
310 __func__, nb);
311 return -EINVAL;
312 }
313 if (msg_type > OPAL_MSG_TYPE_MAX) {
314 pr_warning("%s: Invalid message type argument (%d)\n",
315 __func__, msg_type); 313 __func__, msg_type);
316 return -EINVAL; 314 return -EINVAL;
317 } 315 }
316
318 return atomic_notifier_chain_register( 317 return atomic_notifier_chain_register(
319 &opal_msg_notifier_head[msg_type], nb); 318 &opal_msg_notifier_head[msg_type], nb);
320} 319}
321 320
321int opal_message_notifier_unregister(enum opal_msg_type msg_type,
322 struct notifier_block *nb)
323{
324 return atomic_notifier_chain_unregister(
325 &opal_msg_notifier_head[msg_type], nb);
326}
327
322static void opal_message_do_notify(uint32_t msg_type, void *msg) 328static void opal_message_do_notify(uint32_t msg_type, void *msg)
323{ 329{
324 /* notify subscribers */ 330 /* notify subscribers */
@@ -351,7 +357,7 @@ static void opal_handle_message(void)
351 type = be32_to_cpu(msg.msg_type); 357 type = be32_to_cpu(msg.msg_type);
352 358
353 /* Sanity check */ 359 /* Sanity check */
354 if (type > OPAL_MSG_TYPE_MAX) { 360 if (type >= OPAL_MSG_TYPE_MAX) {
355 pr_warning("%s: Unknown message type: %u\n", __func__, type); 361 pr_warning("%s: Unknown message type: %u\n", __func__, type);
356 return; 362 return;
357 } 363 }
@@ -665,6 +671,9 @@ static void __init opal_dump_region_init(void)
665 uint64_t size; 671 uint64_t size;
666 int rc; 672 int rc;
667 673
674 if (!opal_check_token(OPAL_REGISTER_DUMP_REGION))
675 return;
676
668 /* Register kernel log buffer */ 677 /* Register kernel log buffer */
669 addr = log_buf_addr_get(); 678 addr = log_buf_addr_get();
670 if (addr == NULL) 679 if (addr == NULL)
@@ -684,6 +693,15 @@ static void __init opal_dump_region_init(void)
684 "rc = %d\n", rc); 693 "rc = %d\n", rc);
685} 694}
686 695
696static void opal_flash_init(struct device_node *opal_node)
697{
698 struct device_node *np;
699
700 for_each_child_of_node(opal_node, np)
701 if (of_device_is_compatible(np, "ibm,opal-flash"))
702 of_platform_device_create(np, NULL, NULL);
703}
704
687static void opal_ipmi_init(struct device_node *opal_node) 705static void opal_ipmi_init(struct device_node *opal_node)
688{ 706{
689 struct device_node *np; 707 struct device_node *np;
@@ -741,6 +759,29 @@ static void __init opal_irq_init(struct device_node *dn)
741 } 759 }
742} 760}
743 761
762static int kopald(void *unused)
763{
764 set_freezable();
765 do {
766 try_to_freeze();
767 opal_poll_events(NULL);
768 msleep_interruptible(opal_heartbeat);
769 } while (!kthread_should_stop());
770
771 return 0;
772}
773
774static void opal_init_heartbeat(void)
775{
776 /* Old firwmware, we assume the HVC heartbeat is sufficient */
777 if (of_property_read_u32(opal_node, "ibm,heartbeat-ms",
778 &opal_heartbeat) != 0)
779 opal_heartbeat = 0;
780
781 if (opal_heartbeat)
782 kthread_run(kopald, NULL, "kopald");
783}
784
744static int __init opal_init(void) 785static int __init opal_init(void)
745{ 786{
746 struct device_node *np, *consoles; 787 struct device_node *np, *consoles;
@@ -769,6 +810,9 @@ static int __init opal_init(void)
769 /* Create i2c platform devices */ 810 /* Create i2c platform devices */
770 opal_i2c_create_devs(); 811 opal_i2c_create_devs();
771 812
813 /* Setup a heatbeat thread if requested by OPAL */
814 opal_init_heartbeat();
815
772 /* Find all OPAL interrupts and request them */ 816 /* Find all OPAL interrupts and request them */
773 opal_irq_init(opal_node); 817 opal_irq_init(opal_node);
774 818
@@ -782,7 +826,7 @@ static int __init opal_init(void)
782 /* Setup error log interface */ 826 /* Setup error log interface */
783 rc = opal_elog_init(); 827 rc = opal_elog_init();
784 /* Setup code update interface */ 828 /* Setup code update interface */
785 opal_flash_init(); 829 opal_flash_update_init();
786 /* Setup platform dump extract interface */ 830 /* Setup platform dump extract interface */
787 opal_platform_dump_init(); 831 opal_platform_dump_init();
788 /* Setup system parameters interface */ 832 /* Setup system parameters interface */
@@ -791,8 +835,11 @@ static int __init opal_init(void)
791 opal_msglog_init(); 835 opal_msglog_init();
792 } 836 }
793 837
838 /* Initialize OPAL IPMI backend */
794 opal_ipmi_init(opal_node); 839 opal_ipmi_init(opal_node);
795 840
841 opal_flash_init(opal_node);
842
796 return 0; 843 return 0;
797} 844}
798machine_subsys_initcall(powernv, opal_init); 845machine_subsys_initcall(powernv, opal_init);
@@ -823,13 +870,17 @@ void opal_shutdown(void)
823 } 870 }
824 871
825 /* Unregister memory dump region */ 872 /* Unregister memory dump region */
826 opal_unregister_dump_region(OPAL_DUMP_REGION_LOG_BUF); 873 if (opal_check_token(OPAL_UNREGISTER_DUMP_REGION))
874 opal_unregister_dump_region(OPAL_DUMP_REGION_LOG_BUF);
827} 875}
828 876
829/* Export this so that test modules can use it */ 877/* Export this so that test modules can use it */
830EXPORT_SYMBOL_GPL(opal_invalid_call); 878EXPORT_SYMBOL_GPL(opal_invalid_call);
831EXPORT_SYMBOL_GPL(opal_ipmi_send); 879EXPORT_SYMBOL_GPL(opal_ipmi_send);
832EXPORT_SYMBOL_GPL(opal_ipmi_recv); 880EXPORT_SYMBOL_GPL(opal_ipmi_recv);
881EXPORT_SYMBOL_GPL(opal_flash_read);
882EXPORT_SYMBOL_GPL(opal_flash_write);
883EXPORT_SYMBOL_GPL(opal_flash_erase);
833 884
834/* Convert a region of vmalloc memory to an opal sg list */ 885/* Convert a region of vmalloc memory to an opal sg list */
835struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr, 886struct opal_sg_list *opal_vmalloc_to_sg_list(void *vmalloc_addr,
@@ -894,6 +945,25 @@ void opal_free_sg_list(struct opal_sg_list *sg)
894 } 945 }
895} 946}
896 947
948int opal_error_code(int rc)
949{
950 switch (rc) {
951 case OPAL_SUCCESS: return 0;
952
953 case OPAL_PARAMETER: return -EINVAL;
954 case OPAL_ASYNC_COMPLETION: return -EINPROGRESS;
955 case OPAL_BUSY_EVENT: return -EBUSY;
956 case OPAL_NO_MEM: return -ENOMEM;
957
958 case OPAL_UNSUPPORTED: return -EIO;
959 case OPAL_HARDWARE: return -EIO;
960 case OPAL_INTERNAL_ERROR: return -EIO;
961 default:
962 pr_err("%s: unexpected OPAL error %d\n", __func__, rc);
963 return -EIO;
964 }
965}
966
897EXPORT_SYMBOL_GPL(opal_poll_events); 967EXPORT_SYMBOL_GPL(opal_poll_events);
898EXPORT_SYMBOL_GPL(opal_rtc_read); 968EXPORT_SYMBOL_GPL(opal_rtc_read);
899EXPORT_SYMBOL_GPL(opal_rtc_write); 969EXPORT_SYMBOL_GPL(opal_rtc_write);