firmware/psci: Expose PSCI conduit
authorMarc Zyngier <marc.zyngier@arm.com>
Tue, 6 Feb 2018 17:56:16 +0000 (17:56 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 16 Feb 2018 19:22:56 +0000 (20:22 +0100)
Commit 09a8d6d48499 upstream.

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>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
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 6306ab10af182141ef3568ba0665b2bcc4fea9a7..66ff54787d3e9588ffc7738ab9afdc9daa0f8d0e 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;