linux/arch/arm64/kernel/psci.c
<<
>>
Prefs
   1/*
   2 * This program is free software; you can redistribute it and/or modify
   3 * it under the terms of the GNU General Public License version 2 as
   4 * published by the Free Software Foundation.
   5 *
   6 * This program is distributed in the hope that it will be useful,
   7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   9 * GNU General Public License for more details.
  10 *
  11 * Copyright (C) 2013 ARM Limited
  12 *
  13 * Author: Will Deacon <will.deacon@arm.com>
  14 */
  15
  16#define pr_fmt(fmt) "psci: " fmt
  17
  18#include <linux/init.h>
  19#include <linux/of.h>
  20#include <linux/smp.h>
  21#include <linux/reboot.h>
  22#include <linux/pm.h>
  23#include <linux/delay.h>
  24#include <linux/slab.h>
  25#include <uapi/linux/psci.h>
  26
  27#include <asm/compiler.h>
  28#include <asm/cpu_ops.h>
  29#include <asm/errno.h>
  30#include <asm/psci.h>
  31#include <asm/smp_plat.h>
  32#include <asm/suspend.h>
  33#include <asm/system_misc.h>
  34
  35#define PSCI_POWER_STATE_TYPE_STANDBY           0
  36#define PSCI_POWER_STATE_TYPE_POWER_DOWN        1
  37
  38struct psci_power_state {
  39        u16     id;
  40        u8      type;
  41        u8      affinity_level;
  42};
  43
  44struct psci_operations {
  45        int (*cpu_suspend)(struct psci_power_state state,
  46                           unsigned long entry_point);
  47        int (*cpu_off)(struct psci_power_state state);
  48        int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
  49        int (*migrate)(unsigned long cpuid);
  50        int (*affinity_info)(unsigned long target_affinity,
  51                        unsigned long lowest_affinity_level);
  52        int (*migrate_info_type)(void);
  53};
  54
  55static struct psci_operations psci_ops;
  56
  57static int (*invoke_psci_fn)(u64, u64, u64, u64);
  58typedef int (*psci_initcall_t)(const struct device_node *);
  59
  60asmlinkage int __invoke_psci_fn_hvc(u64, u64, u64, u64);
  61asmlinkage int __invoke_psci_fn_smc(u64, u64, u64, u64);
  62
  63enum psci_function {
  64        PSCI_FN_CPU_SUSPEND,
  65        PSCI_FN_CPU_ON,
  66        PSCI_FN_CPU_OFF,
  67        PSCI_FN_MIGRATE,
  68        PSCI_FN_AFFINITY_INFO,
  69        PSCI_FN_MIGRATE_INFO_TYPE,
  70        PSCI_FN_MAX,
  71};
  72
  73static DEFINE_PER_CPU_READ_MOSTLY(struct psci_power_state *, psci_power_state);
  74
  75static u32 psci_function_id[PSCI_FN_MAX];
  76
  77static int psci_to_linux_errno(int errno)
  78{
  79        switch (errno) {
  80        case PSCI_RET_SUCCESS:
  81                return 0;
  82        case PSCI_RET_NOT_SUPPORTED:
  83                return -EOPNOTSUPP;
  84        case PSCI_RET_INVALID_PARAMS:
  85                return -EINVAL;
  86        case PSCI_RET_DENIED:
  87                return -EPERM;
  88        };
  89
  90        return -EINVAL;
  91}
  92
  93static u32 psci_power_state_pack(struct psci_power_state state)
  94{
  95        return ((state.id << PSCI_0_2_POWER_STATE_ID_SHIFT)
  96                        & PSCI_0_2_POWER_STATE_ID_MASK) |
  97                ((state.type << PSCI_0_2_POWER_STATE_TYPE_SHIFT)
  98                 & PSCI_0_2_POWER_STATE_TYPE_MASK) |
  99                ((state.affinity_level << PSCI_0_2_POWER_STATE_AFFL_SHIFT)
 100                 & PSCI_0_2_POWER_STATE_AFFL_MASK);
 101}
 102
 103static void psci_power_state_unpack(u32 power_state,
 104                                    struct psci_power_state *state)
 105{
 106        state->id = (power_state & PSCI_0_2_POWER_STATE_ID_MASK) >>
 107                        PSCI_0_2_POWER_STATE_ID_SHIFT;
 108        state->type = (power_state & PSCI_0_2_POWER_STATE_TYPE_MASK) >>
 109                        PSCI_0_2_POWER_STATE_TYPE_SHIFT;
 110        state->affinity_level =
 111                        (power_state & PSCI_0_2_POWER_STATE_AFFL_MASK) >>
 112                        PSCI_0_2_POWER_STATE_AFFL_SHIFT;
 113}
 114
 115static int psci_get_version(void)
 116{
 117        int err;
 118
 119        err = invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
 120        return err;
 121}
 122
 123static int psci_cpu_suspend(struct psci_power_state state,
 124                            unsigned long entry_point)
 125{
 126        int err;
 127        u32 fn, power_state;
 128
 129        fn = psci_function_id[PSCI_FN_CPU_SUSPEND];
 130        power_state = psci_power_state_pack(state);
 131        err = invoke_psci_fn(fn, power_state, entry_point, 0);
 132        return psci_to_linux_errno(err);
 133}
 134
 135static int psci_cpu_off(struct psci_power_state state)
 136{
 137        int err;
 138        u32 fn, power_state;
 139
 140        fn = psci_function_id[PSCI_FN_CPU_OFF];
 141        power_state = psci_power_state_pack(state);
 142        err = invoke_psci_fn(fn, power_state, 0, 0);
 143        return psci_to_linux_errno(err);
 144}
 145
 146static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point)
 147{
 148        int err;
 149        u32 fn;
 150
 151        fn = psci_function_id[PSCI_FN_CPU_ON];
 152        err = invoke_psci_fn(fn, cpuid, entry_point, 0);
 153        return psci_to_linux_errno(err);
 154}
 155
 156static int psci_migrate(unsigned long cpuid)
 157{
 158        int err;
 159        u32 fn;
 160
 161        fn = psci_function_id[PSCI_FN_MIGRATE];
 162        err = invoke_psci_fn(fn, cpuid, 0, 0);
 163        return psci_to_linux_errno(err);
 164}
 165
 166static int psci_affinity_info(unsigned long target_affinity,
 167                unsigned long lowest_affinity_level)
 168{
 169        int err;
 170        u32 fn;
 171
 172        fn = psci_function_id[PSCI_FN_AFFINITY_INFO];
 173        err = invoke_psci_fn(fn, target_affinity, lowest_affinity_level, 0);
 174        return err;
 175}
 176
 177static int psci_migrate_info_type(void)
 178{
 179        int err;
 180        u32 fn;
 181
 182        fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE];
 183        err = invoke_psci_fn(fn, 0, 0, 0);
 184        return err;
 185}
 186
 187static int __maybe_unused cpu_psci_cpu_init_idle(struct device_node *cpu_node,
 188                                                 unsigned int cpu)
 189{
 190        int i, ret, count = 0;
 191        struct psci_power_state *psci_states;
 192        struct device_node *state_node;
 193
 194        /*
 195         * If the PSCI cpu_suspend function hook has not been initialized
 196         * idle states must not be enabled, so bail out
 197         */
 198        if (!psci_ops.cpu_suspend)
 199                return -EOPNOTSUPP;
 200
 201        /* Count idle states */
 202        while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states",
 203                                              count))) {
 204                count++;
 205                of_node_put(state_node);
 206        }
 207
 208        if (!count)
 209                return -ENODEV;
 210
 211        psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
 212        if (!psci_states)
 213                return -ENOMEM;
 214
 215        for (i = 0; i < count; i++) {
 216                u32 psci_power_state;
 217
 218                state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
 219
 220                ret = of_property_read_u32(state_node,
 221                                           "arm,psci-suspend-param",
 222                                           &psci_power_state);
 223                if (ret) {
 224                        pr_warn(" * %s missing arm,psci-suspend-param property\n",
 225                                state_node->full_name);
 226                        of_node_put(state_node);
 227                        goto free_mem;
 228                }
 229
 230                of_node_put(state_node);
 231                pr_debug("psci-power-state %#x index %d\n", psci_power_state,
 232                                                            i);
 233                psci_power_state_unpack(psci_power_state, &psci_states[i]);
 234        }
 235        /* Idle states parsed correctly, initialize per-cpu pointer */
 236        per_cpu(psci_power_state, cpu) = psci_states;
 237        return 0;
 238
 239free_mem:
 240        kfree(psci_states);
 241        return ret;
 242}
 243
 244static int get_set_conduit_method(struct device_node *np)
 245{
 246        const char *method;
 247
 248        pr_info("probing for conduit method from DT.\n");
 249
 250        if (of_property_read_string(np, "method", &method)) {
 251                pr_warn("missing \"method\" property\n");
 252                return -ENXIO;
 253        }
 254
 255        if (!strcmp("hvc", method)) {
 256                invoke_psci_fn = __invoke_psci_fn_hvc;
 257        } else if (!strcmp("smc", method)) {
 258                invoke_psci_fn = __invoke_psci_fn_smc;
 259        } else {
 260                pr_warn("invalid \"method\" property: %s\n", method);
 261                return -EINVAL;
 262        }
 263        return 0;
 264}
 265
 266static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd)
 267{
 268        invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
 269}
 270
 271static void psci_sys_poweroff(void)
 272{
 273        invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
 274}
 275
 276/*
 277 * PSCI Function IDs for v0.2+ are well defined so use
 278 * standard values.
 279 */
 280static int __init psci_0_2_init(struct device_node *np)
 281{
 282        int err, ver;
 283
 284        err = get_set_conduit_method(np);
 285
 286        if (err)
 287                goto out_put_node;
 288
 289        ver = psci_get_version();
 290
 291        if (ver == PSCI_RET_NOT_SUPPORTED) {
 292                /* PSCI v0.2 mandates implementation of PSCI_ID_VERSION. */
 293                pr_err("PSCI firmware does not comply with the v0.2 spec.\n");
 294                err = -EOPNOTSUPP;
 295                goto out_put_node;
 296        } else {
 297                pr_info("PSCIv%d.%d detected in firmware.\n",
 298                                PSCI_VERSION_MAJOR(ver),
 299                                PSCI_VERSION_MINOR(ver));
 300
 301                if (PSCI_VERSION_MAJOR(ver) == 0 &&
 302                                PSCI_VERSION_MINOR(ver) < 2) {
 303                        err = -EINVAL;
 304                        pr_err("Conflicting PSCI version detected.\n");
 305                        goto out_put_node;
 306                }
 307        }
 308
 309        pr_info("Using standard PSCI v0.2 function IDs\n");
 310        psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN64_CPU_SUSPEND;
 311        psci_ops.cpu_suspend = psci_cpu_suspend;
 312
 313        psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
 314        psci_ops.cpu_off = psci_cpu_off;
 315
 316        psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN64_CPU_ON;
 317        psci_ops.cpu_on = psci_cpu_on;
 318
 319        psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_MIGRATE;
 320        psci_ops.migrate = psci_migrate;
 321
 322        psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN64_AFFINITY_INFO;
 323        psci_ops.affinity_info = psci_affinity_info;
 324
 325        psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] =
 326                PSCI_0_2_FN_MIGRATE_INFO_TYPE;
 327        psci_ops.migrate_info_type = psci_migrate_info_type;
 328
 329        arm_pm_restart = psci_sys_reset;
 330
 331        pm_power_off = psci_sys_poweroff;
 332
 333out_put_node:
 334        of_node_put(np);
 335        return err;
 336}
 337
 338/*
 339 * PSCI < v0.2 get PSCI Function IDs via DT.
 340 */
 341static int __init psci_0_1_init(struct device_node *np)
 342{
 343        u32 id;
 344        int err;
 345
 346        err = get_set_conduit_method(np);
 347
 348        if (err)
 349                goto out_put_node;
 350
 351        pr_info("Using PSCI v0.1 Function IDs from DT\n");
 352
 353        if (!of_property_read_u32(np, "cpu_suspend", &id)) {
 354                psci_function_id[PSCI_FN_CPU_SUSPEND] = id;
 355                psci_ops.cpu_suspend = psci_cpu_suspend;
 356        }
 357
 358        if (!of_property_read_u32(np, "cpu_off", &id)) {
 359                psci_function_id[PSCI_FN_CPU_OFF] = id;
 360                psci_ops.cpu_off = psci_cpu_off;
 361        }
 362
 363        if (!of_property_read_u32(np, "cpu_on", &id)) {
 364                psci_function_id[PSCI_FN_CPU_ON] = id;
 365                psci_ops.cpu_on = psci_cpu_on;
 366        }
 367
 368        if (!of_property_read_u32(np, "migrate", &id)) {
 369                psci_function_id[PSCI_FN_MIGRATE] = id;
 370                psci_ops.migrate = psci_migrate;
 371        }
 372
 373out_put_node:
 374        of_node_put(np);
 375        return err;
 376}
 377
 378static const struct of_device_id psci_of_match[] __initconst = {
 379        { .compatible = "arm,psci",     .data = psci_0_1_init},
 380        { .compatible = "arm,psci-0.2", .data = psci_0_2_init},
 381        {},
 382};
 383
 384int __init psci_init(void)
 385{
 386        struct device_node *np;
 387        const struct of_device_id *matched_np;
 388        psci_initcall_t init_fn;
 389
 390        np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np);
 391
 392        if (!np)
 393                return -ENODEV;
 394
 395        init_fn = (psci_initcall_t)matched_np->data;
 396        return init_fn(np);
 397}
 398
 399#ifdef CONFIG_SMP
 400
 401static int __init cpu_psci_cpu_init(struct device_node *dn, unsigned int cpu)
 402{
 403        return 0;
 404}
 405
 406static int __init cpu_psci_cpu_prepare(unsigned int cpu)
 407{
 408        if (!psci_ops.cpu_on) {
 409                pr_err("no cpu_on method, not booting CPU%d\n", cpu);
 410                return -ENODEV;
 411        }
 412
 413        return 0;
 414}
 415
 416static int cpu_psci_cpu_boot(unsigned int cpu)
 417{
 418        int err = psci_ops.cpu_on(cpu_logical_map(cpu), __pa(secondary_entry));
 419        if (err)
 420                pr_err("failed to boot CPU%d (%d)\n", cpu, err);
 421
 422        return err;
 423}
 424
 425#ifdef CONFIG_HOTPLUG_CPU
 426static int cpu_psci_cpu_disable(unsigned int cpu)
 427{
 428        /* Fail early if we don't have CPU_OFF support */
 429        if (!psci_ops.cpu_off)
 430                return -EOPNOTSUPP;
 431        return 0;
 432}
 433
 434static void cpu_psci_cpu_die(unsigned int cpu)
 435{
 436        int ret;
 437        /*
 438         * There are no known implementations of PSCI actually using the
 439         * power state field, pass a sensible default for now.
 440         */
 441        struct psci_power_state state = {
 442                .type = PSCI_POWER_STATE_TYPE_POWER_DOWN,
 443        };
 444
 445        ret = psci_ops.cpu_off(state);
 446
 447        pr_crit("unable to power off CPU%u (%d)\n", cpu, ret);
 448}
 449
 450static int cpu_psci_cpu_kill(unsigned int cpu)
 451{
 452        int err, i;
 453
 454        if (!psci_ops.affinity_info)
 455                return 1;
 456        /*
 457         * cpu_kill could race with cpu_die and we can
 458         * potentially end up declaring this cpu undead
 459         * while it is dying. So, try again a few times.
 460         */
 461
 462        for (i = 0; i < 10; i++) {
 463                err = psci_ops.affinity_info(cpu_logical_map(cpu), 0);
 464                if (err == PSCI_0_2_AFFINITY_LEVEL_OFF) {
 465                        pr_info("CPU%d killed.\n", cpu);
 466                        return 1;
 467                }
 468
 469                msleep(10);
 470                pr_info("Retrying again to check for CPU kill\n");
 471        }
 472
 473        pr_warn("CPU%d may not have shut down cleanly (AFFINITY_INFO reports %d)\n",
 474                        cpu, err);
 475        /* Make op_cpu_kill() fail. */
 476        return 0;
 477}
 478#endif
 479#endif
 480
 481static int psci_suspend_finisher(unsigned long index)
 482{
 483        struct psci_power_state *state = __this_cpu_read(psci_power_state);
 484
 485        return psci_ops.cpu_suspend(state[index - 1],
 486                                    virt_to_phys(cpu_resume));
 487}
 488
 489static int __maybe_unused cpu_psci_cpu_suspend(unsigned long index)
 490{
 491        int ret;
 492        struct psci_power_state *state = __this_cpu_read(psci_power_state);
 493        /*
 494         * idle state index 0 corresponds to wfi, should never be called
 495         * from the cpu_suspend operations
 496         */
 497        if (WARN_ON_ONCE(!index))
 498                return -EINVAL;
 499
 500        if (state[index - 1].type == PSCI_POWER_STATE_TYPE_STANDBY)
 501                ret = psci_ops.cpu_suspend(state[index - 1], 0);
 502        else
 503                ret = __cpu_suspend(index, psci_suspend_finisher);
 504
 505        return ret;
 506}
 507
 508const struct cpu_operations cpu_psci_ops = {
 509        .name           = "psci",
 510#ifdef CONFIG_CPU_IDLE
 511        .cpu_init_idle  = cpu_psci_cpu_init_idle,
 512        .cpu_suspend    = cpu_psci_cpu_suspend,
 513#endif
 514#ifdef CONFIG_SMP
 515        .cpu_init       = cpu_psci_cpu_init,
 516        .cpu_prepare    = cpu_psci_cpu_prepare,
 517        .cpu_boot       = cpu_psci_cpu_boot,
 518#ifdef CONFIG_HOTPLUG_CPU
 519        .cpu_disable    = cpu_psci_cpu_disable,
 520        .cpu_die        = cpu_psci_cpu_die,
 521        .cpu_kill       = cpu_psci_cpu_kill,
 522#endif
 523#endif
 524};
 525
 526