root/drivers/firmware/psci/psci.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. psci_tos_resident_on
  2. psci_has_ext_power_state
  3. psci_has_osi_support
  4. psci_power_state_loses_context
  5. psci_power_state_is_valid
  6. __invoke_psci_fn_hvc
  7. __invoke_psci_fn_smc
  8. psci_to_linux_errno
  9. psci_get_version
  10. psci_cpu_suspend
  11. psci_cpu_off
  12. psci_cpu_on
  13. psci_migrate
  14. psci_affinity_info
  15. psci_migrate_info_type
  16. psci_migrate_info_up_cpu
  17. set_conduit
  18. get_set_conduit_method
  19. psci_sys_reset
  20. psci_sys_poweroff
  21. psci_features
  22. psci_suspend_finisher
  23. psci_cpu_suspend_enter
  24. psci_system_suspend
  25. psci_system_suspend_enter
  26. psci_init_system_reset2
  27. psci_init_system_suspend
  28. psci_init_cpu_suspend
  29. psci_init_migrate
  30. psci_init_smccc
  31. psci_0_2_set_functions
  32. psci_probe
  33. psci_0_2_init
  34. psci_0_1_init
  35. psci_1_0_init
  36. psci_dt_init
  37. psci_acpi_init

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  *
   4  * Copyright (C) 2015 ARM Limited
   5  */
   6 
   7 #define pr_fmt(fmt) "psci: " fmt
   8 
   9 #include <linux/acpi.h>
  10 #include <linux/arm-smccc.h>
  11 #include <linux/cpuidle.h>
  12 #include <linux/errno.h>
  13 #include <linux/linkage.h>
  14 #include <linux/of.h>
  15 #include <linux/pm.h>
  16 #include <linux/printk.h>
  17 #include <linux/psci.h>
  18 #include <linux/reboot.h>
  19 #include <linux/slab.h>
  20 #include <linux/suspend.h>
  21 
  22 #include <uapi/linux/psci.h>
  23 
  24 #include <asm/cpuidle.h>
  25 #include <asm/cputype.h>
  26 #include <asm/system_misc.h>
  27 #include <asm/smp_plat.h>
  28 #include <asm/suspend.h>
  29 
  30 /*
  31  * While a 64-bit OS can make calls with SMC32 calling conventions, for some
  32  * calls it is necessary to use SMC64 to pass or return 64-bit values.
  33  * For such calls PSCI_FN_NATIVE(version, name) will choose the appropriate
  34  * (native-width) function ID.
  35  */
  36 #ifdef CONFIG_64BIT
  37 #define PSCI_FN_NATIVE(version, name)   PSCI_##version##_FN64_##name
  38 #else
  39 #define PSCI_FN_NATIVE(version, name)   PSCI_##version##_FN_##name
  40 #endif
  41 
  42 /*
  43  * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF
  44  * calls to its resident CPU, so we must avoid issuing those. We never migrate
  45  * a Trusted OS even if it claims to be capable of migration -- doing so will
  46  * require cooperation with a Trusted OS driver.
  47  */
  48 static int resident_cpu = -1;
  49 
  50 bool psci_tos_resident_on(int cpu)
  51 {
  52         return cpu == resident_cpu;
  53 }
  54 
  55 struct psci_operations psci_ops = {
  56         .conduit = PSCI_CONDUIT_NONE,
  57         .smccc_version = SMCCC_VERSION_1_0,
  58 };
  59 
  60 typedef unsigned long (psci_fn)(unsigned long, unsigned long,
  61                                 unsigned long, unsigned long);
  62 static psci_fn *invoke_psci_fn;
  63 
  64 enum psci_function {
  65         PSCI_FN_CPU_SUSPEND,
  66         PSCI_FN_CPU_ON,
  67         PSCI_FN_CPU_OFF,
  68         PSCI_FN_MIGRATE,
  69         PSCI_FN_MAX,
  70 };
  71 
  72 static u32 psci_function_id[PSCI_FN_MAX];
  73 
  74 #define PSCI_0_2_POWER_STATE_MASK               \
  75                                 (PSCI_0_2_POWER_STATE_ID_MASK | \
  76                                 PSCI_0_2_POWER_STATE_TYPE_MASK | \
  77                                 PSCI_0_2_POWER_STATE_AFFL_MASK)
  78 
  79 #define PSCI_1_0_EXT_POWER_STATE_MASK           \
  80                                 (PSCI_1_0_EXT_POWER_STATE_ID_MASK | \
  81                                 PSCI_1_0_EXT_POWER_STATE_TYPE_MASK)
  82 
  83 static u32 psci_cpu_suspend_feature;
  84 static bool psci_system_reset2_supported;
  85 
  86 static inline bool psci_has_ext_power_state(void)
  87 {
  88         return psci_cpu_suspend_feature &
  89                                 PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK;
  90 }
  91 
  92 static inline bool psci_has_osi_support(void)
  93 {
  94         return psci_cpu_suspend_feature & PSCI_1_0_OS_INITIATED;
  95 }
  96 
  97 static inline bool psci_power_state_loses_context(u32 state)
  98 {
  99         const u32 mask = psci_has_ext_power_state() ?
 100                                         PSCI_1_0_EXT_POWER_STATE_TYPE_MASK :
 101                                         PSCI_0_2_POWER_STATE_TYPE_MASK;
 102 
 103         return state & mask;
 104 }
 105 
 106 bool psci_power_state_is_valid(u32 state)
 107 {
 108         const u32 valid_mask = psci_has_ext_power_state() ?
 109                                PSCI_1_0_EXT_POWER_STATE_MASK :
 110                                PSCI_0_2_POWER_STATE_MASK;
 111 
 112         return !(state & ~valid_mask);
 113 }
 114 
 115 static unsigned long __invoke_psci_fn_hvc(unsigned long function_id,
 116                         unsigned long arg0, unsigned long arg1,
 117                         unsigned long arg2)
 118 {
 119         struct arm_smccc_res res;
 120 
 121         arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
 122         return res.a0;
 123 }
 124 
 125 static unsigned long __invoke_psci_fn_smc(unsigned long function_id,
 126                         unsigned long arg0, unsigned long arg1,
 127                         unsigned long arg2)
 128 {
 129         struct arm_smccc_res res;
 130 
 131         arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
 132         return res.a0;
 133 }
 134 
 135 static int psci_to_linux_errno(int errno)
 136 {
 137         switch (errno) {
 138         case PSCI_RET_SUCCESS:
 139                 return 0;
 140         case PSCI_RET_NOT_SUPPORTED:
 141                 return -EOPNOTSUPP;
 142         case PSCI_RET_INVALID_PARAMS:
 143         case PSCI_RET_INVALID_ADDRESS:
 144                 return -EINVAL;
 145         case PSCI_RET_DENIED:
 146                 return -EPERM;
 147         };
 148 
 149         return -EINVAL;
 150 }
 151 
 152 static u32 psci_get_version(void)
 153 {
 154         return invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
 155 }
 156 
 157 static int psci_cpu_suspend(u32 state, unsigned long entry_point)
 158 {
 159         int err;
 160         u32 fn;
 161 
 162         fn = psci_function_id[PSCI_FN_CPU_SUSPEND];
 163         err = invoke_psci_fn(fn, state, entry_point, 0);
 164         return psci_to_linux_errno(err);
 165 }
 166 
 167 static int psci_cpu_off(u32 state)
 168 {
 169         int err;
 170         u32 fn;
 171 
 172         fn = psci_function_id[PSCI_FN_CPU_OFF];
 173         err = invoke_psci_fn(fn, state, 0, 0);
 174         return psci_to_linux_errno(err);
 175 }
 176 
 177 static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point)
 178 {
 179         int err;
 180         u32 fn;
 181 
 182         fn = psci_function_id[PSCI_FN_CPU_ON];
 183         err = invoke_psci_fn(fn, cpuid, entry_point, 0);
 184         return psci_to_linux_errno(err);
 185 }
 186 
 187 static int psci_migrate(unsigned long cpuid)
 188 {
 189         int err;
 190         u32 fn;
 191 
 192         fn = psci_function_id[PSCI_FN_MIGRATE];
 193         err = invoke_psci_fn(fn, cpuid, 0, 0);
 194         return psci_to_linux_errno(err);
 195 }
 196 
 197 static int psci_affinity_info(unsigned long target_affinity,
 198                 unsigned long lowest_affinity_level)
 199 {
 200         return invoke_psci_fn(PSCI_FN_NATIVE(0_2, AFFINITY_INFO),
 201                               target_affinity, lowest_affinity_level, 0);
 202 }
 203 
 204 static int psci_migrate_info_type(void)
 205 {
 206         return invoke_psci_fn(PSCI_0_2_FN_MIGRATE_INFO_TYPE, 0, 0, 0);
 207 }
 208 
 209 static unsigned long psci_migrate_info_up_cpu(void)
 210 {
 211         return invoke_psci_fn(PSCI_FN_NATIVE(0_2, MIGRATE_INFO_UP_CPU),
 212                               0, 0, 0);
 213 }
 214 
 215 static void set_conduit(enum psci_conduit conduit)
 216 {
 217         switch (conduit) {
 218         case PSCI_CONDUIT_HVC:
 219                 invoke_psci_fn = __invoke_psci_fn_hvc;
 220                 break;
 221         case PSCI_CONDUIT_SMC:
 222                 invoke_psci_fn = __invoke_psci_fn_smc;
 223                 break;
 224         default:
 225                 WARN(1, "Unexpected PSCI conduit %d\n", conduit);
 226         }
 227 
 228         psci_ops.conduit = conduit;
 229 }
 230 
 231 static int get_set_conduit_method(struct device_node *np)
 232 {
 233         const char *method;
 234 
 235         pr_info("probing for conduit method from DT.\n");
 236 
 237         if (of_property_read_string(np, "method", &method)) {
 238                 pr_warn("missing \"method\" property\n");
 239                 return -ENXIO;
 240         }
 241 
 242         if (!strcmp("hvc", method)) {
 243                 set_conduit(PSCI_CONDUIT_HVC);
 244         } else if (!strcmp("smc", method)) {
 245                 set_conduit(PSCI_CONDUIT_SMC);
 246         } else {
 247                 pr_warn("invalid \"method\" property: %s\n", method);
 248                 return -EINVAL;
 249         }
 250         return 0;
 251 }
 252 
 253 static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd)
 254 {
 255         if ((reboot_mode == REBOOT_WARM || reboot_mode == REBOOT_SOFT) &&
 256             psci_system_reset2_supported) {
 257                 /*
 258                  * reset_type[31] = 0 (architectural)
 259                  * reset_type[30:0] = 0 (SYSTEM_WARM_RESET)
 260                  * cookie = 0 (ignored by the implementation)
 261                  */
 262                 invoke_psci_fn(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2), 0, 0, 0);
 263         } else {
 264                 invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
 265         }
 266 }
 267 
 268 static void psci_sys_poweroff(void)
 269 {
 270         invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
 271 }
 272 
 273 static int __init psci_features(u32 psci_func_id)
 274 {
 275         return invoke_psci_fn(PSCI_1_0_FN_PSCI_FEATURES,
 276                               psci_func_id, 0, 0);
 277 }
 278 
 279 #ifdef CONFIG_CPU_IDLE
 280 static int psci_suspend_finisher(unsigned long state)
 281 {
 282         u32 power_state = state;
 283 
 284         return psci_ops.cpu_suspend(power_state, __pa_symbol(cpu_resume));
 285 }
 286 
 287 int psci_cpu_suspend_enter(u32 state)
 288 {
 289         int ret;
 290 
 291         if (!psci_power_state_loses_context(state))
 292                 ret = psci_ops.cpu_suspend(state, 0);
 293         else
 294                 ret = cpu_suspend(state, psci_suspend_finisher);
 295 
 296         return ret;
 297 }
 298 #endif
 299 
 300 static int psci_system_suspend(unsigned long unused)
 301 {
 302         return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND),
 303                               __pa_symbol(cpu_resume), 0, 0);
 304 }
 305 
 306 static int psci_system_suspend_enter(suspend_state_t state)
 307 {
 308         return cpu_suspend(0, psci_system_suspend);
 309 }
 310 
 311 static const struct platform_suspend_ops psci_suspend_ops = {
 312         .valid          = suspend_valid_only_mem,
 313         .enter          = psci_system_suspend_enter,
 314 };
 315 
 316 static void __init psci_init_system_reset2(void)
 317 {
 318         int ret;
 319 
 320         ret = psci_features(PSCI_FN_NATIVE(1_1, SYSTEM_RESET2));
 321 
 322         if (ret != PSCI_RET_NOT_SUPPORTED)
 323                 psci_system_reset2_supported = true;
 324 }
 325 
 326 static void __init psci_init_system_suspend(void)
 327 {
 328         int ret;
 329 
 330         if (!IS_ENABLED(CONFIG_SUSPEND))
 331                 return;
 332 
 333         ret = psci_features(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND));
 334 
 335         if (ret != PSCI_RET_NOT_SUPPORTED)
 336                 suspend_set_ops(&psci_suspend_ops);
 337 }
 338 
 339 static void __init psci_init_cpu_suspend(void)
 340 {
 341         int feature = psci_features(psci_function_id[PSCI_FN_CPU_SUSPEND]);
 342 
 343         if (feature != PSCI_RET_NOT_SUPPORTED)
 344                 psci_cpu_suspend_feature = feature;
 345 }
 346 
 347 /*
 348  * Detect the presence of a resident Trusted OS which may cause CPU_OFF to
 349  * return DENIED (which would be fatal).
 350  */
 351 static void __init psci_init_migrate(void)
 352 {
 353         unsigned long cpuid;
 354         int type, cpu = -1;
 355 
 356         type = psci_ops.migrate_info_type();
 357 
 358         if (type == PSCI_0_2_TOS_MP) {
 359                 pr_info("Trusted OS migration not required\n");
 360                 return;
 361         }
 362 
 363         if (type == PSCI_RET_NOT_SUPPORTED) {
 364                 pr_info("MIGRATE_INFO_TYPE not supported.\n");
 365                 return;
 366         }
 367 
 368         if (type != PSCI_0_2_TOS_UP_MIGRATE &&
 369             type != PSCI_0_2_TOS_UP_NO_MIGRATE) {
 370                 pr_err("MIGRATE_INFO_TYPE returned unknown type (%d)\n", type);
 371                 return;
 372         }
 373 
 374         cpuid = psci_migrate_info_up_cpu();
 375         if (cpuid & ~MPIDR_HWID_BITMASK) {
 376                 pr_warn("MIGRATE_INFO_UP_CPU reported invalid physical ID (0x%lx)\n",
 377                         cpuid);
 378                 return;
 379         }
 380 
 381         cpu = get_logical_index(cpuid);
 382         resident_cpu = cpu >= 0 ? cpu : -1;
 383 
 384         pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
 385 }
 386 
 387 static void __init psci_init_smccc(void)
 388 {
 389         u32 ver = ARM_SMCCC_VERSION_1_0;
 390         int feature;
 391 
 392         feature = psci_features(ARM_SMCCC_VERSION_FUNC_ID);
 393 
 394         if (feature != PSCI_RET_NOT_SUPPORTED) {
 395                 u32 ret;
 396                 ret = invoke_psci_fn(ARM_SMCCC_VERSION_FUNC_ID, 0, 0, 0);
 397                 if (ret == ARM_SMCCC_VERSION_1_1) {
 398                         psci_ops.smccc_version = SMCCC_VERSION_1_1;
 399                         ver = ret;
 400                 }
 401         }
 402 
 403         /*
 404          * Conveniently, the SMCCC and PSCI versions are encoded the
 405          * same way. No, this isn't accidental.
 406          */
 407         pr_info("SMC Calling Convention v%d.%d\n",
 408                 PSCI_VERSION_MAJOR(ver), PSCI_VERSION_MINOR(ver));
 409 
 410 }
 411 
 412 static void __init psci_0_2_set_functions(void)
 413 {
 414         pr_info("Using standard PSCI v0.2 function IDs\n");
 415         psci_ops.get_version = psci_get_version;
 416 
 417         psci_function_id[PSCI_FN_CPU_SUSPEND] =
 418                                         PSCI_FN_NATIVE(0_2, CPU_SUSPEND);
 419         psci_ops.cpu_suspend = psci_cpu_suspend;
 420 
 421         psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
 422         psci_ops.cpu_off = psci_cpu_off;
 423 
 424         psci_function_id[PSCI_FN_CPU_ON] = PSCI_FN_NATIVE(0_2, CPU_ON);
 425         psci_ops.cpu_on = psci_cpu_on;
 426 
 427         psci_function_id[PSCI_FN_MIGRATE] = PSCI_FN_NATIVE(0_2, MIGRATE);
 428         psci_ops.migrate = psci_migrate;
 429 
 430         psci_ops.affinity_info = psci_affinity_info;
 431 
 432         psci_ops.migrate_info_type = psci_migrate_info_type;
 433 
 434         arm_pm_restart = psci_sys_reset;
 435 
 436         pm_power_off = psci_sys_poweroff;
 437 }
 438 
 439 /*
 440  * Probe function for PSCI firmware versions >= 0.2
 441  */
 442 static int __init psci_probe(void)
 443 {
 444         u32 ver = psci_get_version();
 445 
 446         pr_info("PSCIv%d.%d detected in firmware.\n",
 447                         PSCI_VERSION_MAJOR(ver),
 448                         PSCI_VERSION_MINOR(ver));
 449 
 450         if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) {
 451                 pr_err("Conflicting PSCI version detected.\n");
 452                 return -EINVAL;
 453         }
 454 
 455         psci_0_2_set_functions();
 456 
 457         psci_init_migrate();
 458 
 459         if (PSCI_VERSION_MAJOR(ver) >= 1) {
 460                 psci_init_smccc();
 461                 psci_init_cpu_suspend();
 462                 psci_init_system_suspend();
 463                 psci_init_system_reset2();
 464         }
 465 
 466         return 0;
 467 }
 468 
 469 typedef int (*psci_initcall_t)(const struct device_node *);
 470 
 471 /*
 472  * PSCI init function for PSCI versions >=0.2
 473  *
 474  * Probe based on PSCI PSCI_VERSION function
 475  */
 476 static int __init psci_0_2_init(struct device_node *np)
 477 {
 478         int err;
 479 
 480         err = get_set_conduit_method(np);
 481         if (err)
 482                 return err;
 483 
 484         /*
 485          * Starting with v0.2, the PSCI specification introduced a call
 486          * (PSCI_VERSION) that allows probing the firmware version, so
 487          * that PSCI function IDs and version specific initialization
 488          * can be carried out according to the specific version reported
 489          * by firmware
 490          */
 491         return psci_probe();
 492 }
 493 
 494 /*
 495  * PSCI < v0.2 get PSCI Function IDs via DT.
 496  */
 497 static int __init psci_0_1_init(struct device_node *np)
 498 {
 499         u32 id;
 500         int err;
 501 
 502         err = get_set_conduit_method(np);
 503         if (err)
 504                 return err;
 505 
 506         pr_info("Using PSCI v0.1 Function IDs from DT\n");
 507 
 508         if (!of_property_read_u32(np, "cpu_suspend", &id)) {
 509                 psci_function_id[PSCI_FN_CPU_SUSPEND] = id;
 510                 psci_ops.cpu_suspend = psci_cpu_suspend;
 511         }
 512 
 513         if (!of_property_read_u32(np, "cpu_off", &id)) {
 514                 psci_function_id[PSCI_FN_CPU_OFF] = id;
 515                 psci_ops.cpu_off = psci_cpu_off;
 516         }
 517 
 518         if (!of_property_read_u32(np, "cpu_on", &id)) {
 519                 psci_function_id[PSCI_FN_CPU_ON] = id;
 520                 psci_ops.cpu_on = psci_cpu_on;
 521         }
 522 
 523         if (!of_property_read_u32(np, "migrate", &id)) {
 524                 psci_function_id[PSCI_FN_MIGRATE] = id;
 525                 psci_ops.migrate = psci_migrate;
 526         }
 527 
 528         return 0;
 529 }
 530 
 531 static int __init psci_1_0_init(struct device_node *np)
 532 {
 533         int err;
 534 
 535         err = psci_0_2_init(np);
 536         if (err)
 537                 return err;
 538 
 539         if (psci_has_osi_support())
 540                 pr_info("OSI mode supported.\n");
 541 
 542         return 0;
 543 }
 544 
 545 static const struct of_device_id psci_of_match[] __initconst = {
 546         { .compatible = "arm,psci",     .data = psci_0_1_init},
 547         { .compatible = "arm,psci-0.2", .data = psci_0_2_init},
 548         { .compatible = "arm,psci-1.0", .data = psci_1_0_init},
 549         {},
 550 };
 551 
 552 int __init psci_dt_init(void)
 553 {
 554         struct device_node *np;
 555         const struct of_device_id *matched_np;
 556         psci_initcall_t init_fn;
 557         int ret;
 558 
 559         np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np);
 560 
 561         if (!np || !of_device_is_available(np))
 562                 return -ENODEV;
 563 
 564         init_fn = (psci_initcall_t)matched_np->data;
 565         ret = init_fn(np);
 566 
 567         of_node_put(np);
 568         return ret;
 569 }
 570 
 571 #ifdef CONFIG_ACPI
 572 /*
 573  * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's
 574  * explicitly clarified in SBBR
 575  */
 576 int __init psci_acpi_init(void)
 577 {
 578         if (!acpi_psci_present()) {
 579                 pr_info("is not implemented in ACPI.\n");
 580                 return -EOPNOTSUPP;
 581         }
 582 
 583         pr_info("probing for conduit method from ACPI.\n");
 584 
 585         if (acpi_psci_use_hvc())
 586                 set_conduit(PSCI_CONDUIT_HVC);
 587         else
 588                 set_conduit(PSCI_CONDUIT_SMC);
 589 
 590         return psci_probe();
 591 }
 592 #endif

/* [<][>][^][v][top][bottom][index][help] */