Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

firmware/psci: Expose SMCCC version through psci_ops

Since PSCI 1.0 allows the SMCCC version to be (indirectly) probed,
let's do that at boot time, and expose the version of the calling
convention as part of the psci_ops structure.

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>

authored by

Marc Zyngier and committed by
Catalin Marinas
e78eef55 09a8d6d4

+33
+27
drivers/firmware/psci.c
··· 61 61 62 62 struct psci_operations psci_ops = { 63 63 .conduit = PSCI_CONDUIT_NONE, 64 + .smccc_version = SMCCC_VERSION_1_0, 64 65 }; 65 66 66 67 typedef unsigned long (psci_fn)(unsigned long, unsigned long, ··· 512 511 pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid); 513 512 } 514 513 514 + static void __init psci_init_smccc(void) 515 + { 516 + u32 ver = ARM_SMCCC_VERSION_1_0; 517 + int feature; 518 + 519 + feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID); 520 + 521 + if (feature != PSCI_RET_NOT_SUPPORTED) { 522 + u32 ret; 523 + ret = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0); 524 + if (ret == ARM_SMCCC_VERSION_1_1) { 525 + psci_ops.smccc_version = SMCCC_VERSION_1_1; 526 + ver = ret; 527 + } 528 + } 529 + 530 + /* 531 + * Conveniently, the SMCCC and PSCI versions are encoded the 532 + * same way. No, this isn't accidental. 533 + */ 534 + pr_info("SMC Calling Convention v%d.%d\n", 535 + PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver)); 536 + 537 + } 538 + 515 539 static void __init psci_0_2_set_functions(void) 516 540 { 517 541 pr_info("Using standard PSCI v0.2 function IDs\n"); ··· 585 559 psci_init_migrate(); 586 560 587 561 if (PSCI_VERSION_MAJOR(ver) >= 1) { 562 + psci_init_smccc(); 588 563 psci_init_cpu_suspend(); 589 564 psci_init_system_suspend(); 590 565 }
+6
include/linux/psci.h
··· 31 31 PSCI_CONDUIT_HVC, 32 32 }; 33 33 34 + enum smccc_version { 35 + SMCCC_VERSION_1_0, 36 + SMCCC_VERSION_1_1, 37 + }; 38 + 34 39 struct psci_operations { 35 40 u32 (*get_version)(void); 36 41 int (*cpu_suspend)(u32 state, unsigned long entry_point); ··· 46 41 unsigned long lowest_affinity_level); 47 42 int (*migrate_info_type)(void); 48 43 enum psci_conduit conduit; 44 + enum smccc_version smccc_version; 49 45 }; 50 46 51 47 extern struct psci_operations psci_ops;