firmware/psci: Expose PSCI conduit
authorMarc Zyngier <marc.zyngier@arm.com>
Tue, 6 Feb 2018 17:56:16 +0000 (17:56 +0000)
committerCatalin Marinas <catalin.marinas@arm.com>
Tue, 6 Feb 2018 22:54:09 +0000 (22:54 +0000)
In order to call into the firmware to apply workarounds, it is
useful to find out whether we're using HVC or SMC. Let's expose
this through the psci_ops.

Acked-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
drivers/firmware/psci.c
include/linux/psci.h

index 8b25d31e84016b9977396eaab2594ff97b06d183..e9493da2b111e67ce5169bd91f031e29e0be92fc 100644 (file)
@@ -59,7 +59,9 @@ 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,
+};
 
 typedef unsigned long (psci_fn)(unsigned long, unsigned long,
                                unsigned long, unsigned long);
@@ -210,6 +212,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 +240,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;
@@ -654,9 +672,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();
 }
index f724fd8c78e82699884864c39d2a7712c5893ca7..f2679e5faa4fa705f62c8752ecce9b39524febcb 100644 (file)
@@ -25,6 +25,12 @@ bool psci_tos_resident_on(int cpu);
 int psci_cpu_init_idle(unsigned int cpu);
 int psci_cpu_suspend_enter(unsigned long index);
 
+enum psci_conduit {
+       PSCI_CONDUIT_NONE,
+       PSCI_CONDUIT_SMC,
+       PSCI_CONDUIT_HVC,
+};
+
 struct psci_operations {
        u32 (*get_version)(void);
        int (*cpu_suspend)(u32 state, unsigned long entry_point);
@@ -34,6 +40,7 @@ struct psci_operations {
        int (*affinity_info)(unsigned long target_affinity,
                        unsigned long lowest_affinity_level);
        int (*migrate_info_type)(void);
+       enum psci_conduit conduit;
 };
 
 extern struct psci_operations psci_ops;