vfs: do bulk POLL* -> EPOLL* replacement
[sfrench/cifs-2.6.git] / drivers / firmware / psci.c
index 8b25d31e84016b9977396eaab2594ff97b06d183..c80ec1d03274413863fb8e3f917f26daa8f868c2 100644 (file)
@@ -59,7 +59,10 @@ bool psci_tos_resident_on(int cpu)
        return cpu == resident_cpu;
 }
 
-struct psci_operations psci_ops;
+struct psci_operations psci_ops = {
+       .conduit = PSCI_CONDUIT_NONE,
+       .smccc_version = SMCCC_VERSION_1_0,
+};
 
 typedef unsigned long (psci_fn)(unsigned long, unsigned long,
                                unsigned long, unsigned long);
@@ -210,6 +213,22 @@ static unsigned long psci_migrate_info_up_cpu(void)
                              0, 0, 0);
 }
 
+static void set_conduit(enum psci_conduit conduit)
+{
+       switch (conduit) {
+       case PSCI_CONDUIT_HVC:
+               invoke_psci_fn = __invoke_psci_fn_hvc;
+               break;
+       case PSCI_CONDUIT_SMC:
+               invoke_psci_fn = __invoke_psci_fn_smc;
+               break;
+       default:
+               WARN(1, "Unexpected PSCI conduit %d\n", conduit);
+       }
+
+       psci_ops.conduit = conduit;
+}
+
 static int get_set_conduit_method(struct device_node *np)
 {
        const char *method;
@@ -222,9 +241,9 @@ static int get_set_conduit_method(struct device_node *np)
        }
 
        if (!strcmp("hvc", method)) {
-               invoke_psci_fn = __invoke_psci_fn_hvc;
+               set_conduit(PSCI_CONDUIT_HVC);
        } else if (!strcmp("smc", method)) {
-               invoke_psci_fn = __invoke_psci_fn_smc;
+               set_conduit(PSCI_CONDUIT_SMC);
        } else {
                pr_warn("invalid \"method\" property: %s\n", method);
                return -EINVAL;
@@ -493,6 +512,31 @@ static void __init psci_init_migrate(void)
        pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
 }
 
+static void __init psci_init_smccc(void)
+{
+       u32 ver = ARM_SMCCC_VERSION_1_0;
+       int feature;
+
+       feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
+
+       if (feature != PSCI_RET_NOT_SUPPORTED) {
+               u32 ret;
+               ret = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
+               if (ret == ARM_SMCCC_VERSION_1_1) {
+                       psci_ops.smccc_version = SMCCC_VERSION_1_1;
+                       ver = ret;
+               }
+       }
+
+       /*
+        * Conveniently, the SMCCC and PSCI versions are encoded the
+        * same way. No, this isn't accidental.
+        */
+       pr_info("SMC Calling Convention v%d.%d\n",
+               PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver));
+
+}
+
 static void __init psci_0_2_set_functions(void)
 {
        pr_info("Using standard PSCI v0.2 function IDs\n");
@@ -541,6 +585,7 @@ static int __init psci_probe(void)
        psci_init_migrate();
 
        if (PSCI_VERSION_MAJOR(ver) >= 1) {
+               psci_init_smccc();
                psci_init_cpu_suspend();
                psci_init_system_suspend();
        }
@@ -654,9 +699,9 @@ int __init psci_acpi_init(void)
        pr_info("probing for conduit method from ACPI.\n");
 
        if (acpi_psci_use_hvc())
-               invoke_psci_fn = __invoke_psci_fn_hvc;
+               set_conduit(PSCI_CONDUIT_HVC);
        else
-               invoke_psci_fn = __invoke_psci_fn_smc;
+               set_conduit(PSCI_CONDUIT_SMC);
 
        return psci_probe();
 }