diff --git a/sys/dev/psci/psci.h b/sys/dev/psci/psci.h --- a/sys/dev/psci/psci.h +++ b/sys/dev/psci/psci.h @@ -31,6 +31,12 @@ #include #ifdef _KERNEL +typedef enum { + PSCI_METHOD_UNKNOWN, + PSCI_METHOD_HVC, + PSCI_METHOD_SMC, +} psci_method_t; + typedef int (*psci_initfn_t)(device_t dev, int default_version); typedef int (*psci_callfn_t)(register_t, register_t, register_t, register_t, register_t, register_t, register_t, register_t, @@ -42,6 +48,7 @@ void psci_reset(void); int32_t psci_features(uint32_t); int psci_get_version(void); +psci_method_t psci_get_method(void); /* Handler to let us call into the PSCI/SMCCC firmware */ extern psci_callfn_t psci_callfn; diff --git a/sys/dev/psci/psci.c b/sys/dev/psci/psci.c --- a/sys/dev/psci/psci.c +++ b/sys/dev/psci/psci.c @@ -126,24 +126,31 @@ static int psci_attach(device_t, psci_initfn_t, int); -static int psci_find_callfn(psci_callfn_t *); +static void psci_find_method(void); static int psci_def_callfn(register_t, register_t, register_t, register_t, register_t, register_t, register_t, register_t, struct arm_smccc_res *res); +static psci_method_t psci_method = PSCI_METHOD_UNKNOWN; psci_callfn_t psci_callfn = psci_def_callfn; static void psci_init(void *dummy) { - psci_callfn_t new_callfn; - - if (psci_find_callfn(&new_callfn) != PSCI_RETVAL_SUCCESS) { - printf("No PSCI/SMCCC call function found\n"); + psci_find_method(); + switch (psci_method) { + case PSCI_METHOD_UNKNOWN: + default: + printf("No PSCI/SMCCC call method found\n"); return; + case PSCI_METHOD_HVC: + psci_callfn = arm_smccc_hvc; + break; + case PSCI_METHOD_SMC: + psci_callfn = arm_smccc_smc; + break; } - psci_callfn = new_callfn; psci_present = true; } /* This needs to be before cpu_mp at SI_SUB_CPU, SI_ORDER_THIRD */ @@ -182,24 +189,6 @@ EARLY_DRIVER_MODULE(psci, ofwbus, psci_fdt_driver, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_FIRST); -static psci_callfn_t -psci_fdt_get_callfn(phandle_t node) -{ - char method[16]; - - if ((OF_getprop(node, "method", method, sizeof(method))) > 0) { - if (strcmp(method, "hvc") == 0) - return (arm_smccc_hvc); - else if (strcmp(method, "smc") == 0) - return (arm_smccc_smc); - else - printf("psci: PSCI conduit \"%s\" invalid\n", method); - } else - printf("psci: PSCI conduit not supplied in the device tree\n"); - - return (NULL); -} - static int psci_fdt_probe(device_t dev) { @@ -277,22 +266,6 @@ return (flags); } -static psci_callfn_t -psci_acpi_get_callfn(int flags) -{ - - if ((flags & ACPI_FADT_PSCI_COMPLIANT) != 0) { - if ((flags & ACPI_FADT_PSCI_USE_HVC) != 0) - return (arm_smccc_hvc); - else - return (arm_smccc_smc); - } else { - printf("psci: PSCI conduit not supplied in the device tree\n"); - } - - return (NULL); -} - static void psci_acpi_identify(driver_t *driver, device_t parent) { @@ -379,9 +352,10 @@ } #ifdef FDT -static int -psci_fdt_callfn(psci_callfn_t *callfn) +static void +psci_find_fdt_method(void) { + char method[16]; phandle_t node; /* XXX: This is suboptimal, we should walk the tree & check each @@ -395,56 +369,61 @@ break; } if (node == 0) - return (PSCI_MISSING); + return; if (!ofw_bus_node_status_okay(node)) - return (PSCI_MISSING); + return; - *callfn = psci_fdt_get_callfn(node); - return (0); + if ((OF_getprop(node, "method", method, sizeof(method))) > 0) { + if (strcmp(method, "hvc") == 0) + psci_method = PSCI_METHOD_HVC; + else if (strcmp(method, "smc") == 0) + psci_method = PSCI_METHOD_SMC; + else + printf("psci: PSCI conduit \"%s\" invalid\n", method); + } else + printf("psci: PSCI conduit not supplied in the device tree\n"); } #endif #ifdef DEV_ACPI -static int -psci_acpi_callfn(psci_callfn_t *callfn) +static void +psci_find_acpi_method(void) { int flags; flags = psci_acpi_bootflags(); if ((flags & ACPI_FADT_PSCI_COMPLIANT) == 0) - return (PSCI_MISSING); + return; - *callfn = psci_acpi_get_callfn(flags); - return (0); + if ((flags & ACPI_FADT_PSCI_USE_HVC) != 0) + psci_method = PSCI_METHOD_HVC; + else + psci_method = PSCI_METHOD_SMC; } #endif -static int -psci_find_callfn(psci_callfn_t *callfn) +static void +psci_find_method(void) { - int error; - - *callfn = NULL; #ifdef FDT if (USE_FDT) { - error = psci_fdt_callfn(callfn); - if (error != 0) - return (error); + psci_find_fdt_method(); + return; } #endif #ifdef DEV_ACPI - if (*callfn == NULL && USE_ACPI) { - error = psci_acpi_callfn(callfn); - if (error != 0) - return (error); + if (USE_ACPI) { + psci_find_acpi_method(); + return; } #endif +} - if (*callfn == NULL) - return (PSCI_MISSING); - - return (PSCI_RETVAL_SUCCESS); +psci_method_t +psci_get_method(void) +{ + return (psci_method); } int32_t