From: Linus Torvalds Date: Thu, 3 Sep 2015 23:27:01 +0000 (-0700) Subject: Merge branch 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm X-Git-Tag: firefly_0821_release~176^2~1151 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=c706c7eb0d08098f0d768aeef945d7cf1f8858b4;p=firefly-linux-kernel-4.4.55.git Merge branch 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm Pull ARM development updates from Russell King: "Included in this update: - moving PSCI code from ARM64/ARM to drivers/ - removal of some architecture internals from global kernel view - addition of software based "privileged no access" support using the old domains register to turn off the ability for kernel loads/stores to access userspace. Only the proper accessors will be usable. - addition of early fixup support for early console - re-addition (and reimplementation) of OMAP special interconnect barrier - removal of finish_arch_switch() - only expose cpuX/online in sysfs if hotpluggable - a number of code cleanups" * 'for-linus' of git://ftp.arm.linux.org.uk/~rmk/linux-arm: (41 commits) ARM: software-based priviledged-no-access support ARM: entry: provide uaccess assembly macro hooks ARM: entry: get rid of multiple macro definitions ARM: 8421/1: smp: Collapse arch_cpu_idle_dead() into cpu_die() ARM: uaccess: provide uaccess_save_and_enable() and uaccess_restore() ARM: mm: improve do_ldrd_abort macro ARM: entry: ensure that IRQs are enabled when calling syscall_trace_exit() ARM: entry: efficiency cleanups ARM: entry: get rid of asm_trace_hardirqs_on_cond ARM: uaccess: simplify user access assembly ARM: domains: remove DOMAIN_TABLE ARM: domains: keep vectors in separate domain ARM: domains: get rid of manager mode for user domain ARM: domains: move initial domain setting value to asm/domains.h ARM: domains: provide domain_mask() ARM: domains: switch to keeping domain value in register ARM: 8419/1: dma-mapping: harmonize definition of DMA_ERROR_CODE ARM: 8417/1: refactor bitops functions with BIT_MASK() and BIT_WORD() ARM: 8416/1: Feroceon: use of_iomap() to map register base ARM: 8415/1: early fixmap support for earlycon ... --- c706c7eb0d08098f0d768aeef945d7cf1f8858b4 diff --cc MAINTAINERS index 205cd5d687e4,44998e18fd22..b4c6754f3144 --- a/MAINTAINERS +++ b/MAINTAINERS @@@ -8118,8 -8065,16 +8120,17 @@@ T: git git://git.infradead.org/battery- S: Maintained F: include/linux/power_supply.h F: drivers/power/ +X: drivers/power/avs/ + POWER STATE COORDINATION INTERFACE (PSCI) + M: Mark Rutland + M: Lorenzo Pieralisi + L: linux-arm-kernel@lists.infradead.org + S: Maintained + F: drivers/firmware/psci.c + F: include/linux/psci.h + F: include/uapi/linux/psci.h + PNP SUPPORT M: "Rafael J. Wysocki" S: Maintained diff --cc arch/arm/include/asm/Kbuild index 30b3bc1666d2,517ef6dd22b9..be648eb47cd9 --- a/arch/arm/include/asm/Kbuild +++ b/arch/arm/include/asm/Kbuild @@@ -12,8 -12,6 +12,7 @@@ generic-y += irq_regs. generic-y += kdebug.h generic-y += local.h generic-y += local64.h - generic-y += mcs_spinlock.h +generic-y += mm-arch-hooks.h generic-y += msgbuf.h generic-y += param.h generic-y += parport.h diff --cc arch/arm/mach-omap2/io.c index 6a4822dbb4ea,7743e3672f98..980c9372e6fd --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@@ -359,15 -314,9 +360,16 @@@ void __init omap4_map_io(void void __init omap5_map_io(void) { iotable_init(omap54xx_io_desc, ARRAY_SIZE(omap54xx_io_desc)); + omap_barriers_init(); } #endif + +#ifdef CONFIG_SOC_DRA7XX +void __init dra7xx_map_io(void) +{ + iotable_init(dra7xx_io_desc, ARRAY_SIZE(dra7xx_io_desc)); +} +#endif /* * omap2_init_reprogram_sdrc - reprogram SDRC timing parameters * diff --cc drivers/firmware/psci.c index 000000000000,a6956007dd38..42700f09a8c5 mode 000000,100644..100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@@ -1,0 -1,382 +1,382 @@@ + /* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Copyright (C) 2015 ARM Limited + */ + + #define pr_fmt(fmt) "psci: " fmt + + #include + #include + #include + #include + #include + #include + #include + + #include + + #include + #include + #include + + /* + * While a 64-bit OS can make calls with SMC32 calling conventions, for some + * calls it is necessary to use SMC64 to pass or return 64-bit values. For such + * calls PSCI_0_2_FN_NATIVE(x) will choose the appropriate (native-width) + * function ID. + */ + #ifdef CONFIG_64BIT + #define PSCI_0_2_FN_NATIVE(name) PSCI_0_2_FN64_##name + #else + #define PSCI_0_2_FN_NATIVE(name) PSCI_0_2_FN_##name + #endif + + /* + * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF + * calls to its resident CPU, so we must avoid issuing those. We never migrate + * a Trusted OS even if it claims to be capable of migration -- doing so will + * require cooperation with a Trusted OS driver. + */ + static int resident_cpu = -1; + + bool psci_tos_resident_on(int cpu) + { + return cpu == resident_cpu; + } + + struct psci_operations psci_ops; + + typedef unsigned long (psci_fn)(unsigned long, unsigned long, + unsigned long, unsigned long); + asmlinkage psci_fn __invoke_psci_fn_hvc; + asmlinkage psci_fn __invoke_psci_fn_smc; + static psci_fn *invoke_psci_fn; + + enum psci_function { + PSCI_FN_CPU_SUSPEND, + PSCI_FN_CPU_ON, + PSCI_FN_CPU_OFF, + PSCI_FN_MIGRATE, + PSCI_FN_MAX, + }; + + static u32 psci_function_id[PSCI_FN_MAX]; + + static int psci_to_linux_errno(int errno) + { + switch (errno) { + case PSCI_RET_SUCCESS: + return 0; + case PSCI_RET_NOT_SUPPORTED: + return -EOPNOTSUPP; + case PSCI_RET_INVALID_PARAMS: + return -EINVAL; + case PSCI_RET_DENIED: + return -EPERM; + }; + + return -EINVAL; + } + + static u32 psci_get_version(void) + { + return invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0); + } + + static int psci_cpu_suspend(u32 state, unsigned long entry_point) + { + int err; + u32 fn; + + fn = psci_function_id[PSCI_FN_CPU_SUSPEND]; + err = invoke_psci_fn(fn, state, entry_point, 0); + return psci_to_linux_errno(err); + } + + static int psci_cpu_off(u32 state) + { + int err; + u32 fn; + + fn = psci_function_id[PSCI_FN_CPU_OFF]; + err = invoke_psci_fn(fn, state, 0, 0); + return psci_to_linux_errno(err); + } + + static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point) + { + int err; + u32 fn; + + fn = psci_function_id[PSCI_FN_CPU_ON]; + err = invoke_psci_fn(fn, cpuid, entry_point, 0); + return psci_to_linux_errno(err); + } + + static int psci_migrate(unsigned long cpuid) + { + int err; + u32 fn; + + fn = psci_function_id[PSCI_FN_MIGRATE]; + err = invoke_psci_fn(fn, cpuid, 0, 0); + return psci_to_linux_errno(err); + } + + static int psci_affinity_info(unsigned long target_affinity, + unsigned long lowest_affinity_level) + { + return invoke_psci_fn(PSCI_0_2_FN_NATIVE(AFFINITY_INFO), + target_affinity, lowest_affinity_level, 0); + } + + static int psci_migrate_info_type(void) + { + return invoke_psci_fn(PSCI_0_2_FN_MIGRATE_INFO_TYPE, 0, 0, 0); + } + + static unsigned long psci_migrate_info_up_cpu(void) + { + return invoke_psci_fn(PSCI_0_2_FN_NATIVE(MIGRATE_INFO_UP_CPU), + 0, 0, 0); + } + + static int get_set_conduit_method(struct device_node *np) + { + const char *method; + + pr_info("probing for conduit method from DT.\n"); + + if (of_property_read_string(np, "method", &method)) { + pr_warn("missing \"method\" property\n"); + return -ENXIO; + } + + if (!strcmp("hvc", method)) { + invoke_psci_fn = __invoke_psci_fn_hvc; + } else if (!strcmp("smc", method)) { + invoke_psci_fn = __invoke_psci_fn_smc; + } else { + pr_warn("invalid \"method\" property: %s\n", method); + return -EINVAL; + } + return 0; + } + + static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd) + { + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); + } + + static void psci_sys_poweroff(void) + { + invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); + } + + /* + * Detect the presence of a resident Trusted OS which may cause CPU_OFF to + * return DENIED (which would be fatal). + */ + static void __init psci_init_migrate(void) + { + unsigned long cpuid; + int type, cpu = -1; + + type = psci_ops.migrate_info_type(); + + if (type == PSCI_0_2_TOS_MP) { + pr_info("Trusted OS migration not required\n"); + return; + } + + if (type == PSCI_RET_NOT_SUPPORTED) { + pr_info("MIGRATE_INFO_TYPE not supported.\n"); + return; + } + + if (type != PSCI_0_2_TOS_UP_MIGRATE && + type != PSCI_0_2_TOS_UP_NO_MIGRATE) { + pr_err("MIGRATE_INFO_TYPE returned unknown type (%d)\n", type); + return; + } + + cpuid = psci_migrate_info_up_cpu(); + if (cpuid & ~MPIDR_HWID_BITMASK) { + pr_warn("MIGRATE_INFO_UP_CPU reported invalid physical ID (0x%lx)\n", + cpuid); + return; + } + + cpu = get_logical_index(cpuid); + resident_cpu = cpu >= 0 ? cpu : -1; + + pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid); + } + + static void __init psci_0_2_set_functions(void) + { + pr_info("Using standard PSCI v0.2 function IDs\n"); + psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN_NATIVE(CPU_SUSPEND); + psci_ops.cpu_suspend = psci_cpu_suspend; + + psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; + psci_ops.cpu_off = psci_cpu_off; + + psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN_NATIVE(CPU_ON); + psci_ops.cpu_on = psci_cpu_on; + + psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN_NATIVE(MIGRATE); + psci_ops.migrate = psci_migrate; + + psci_ops.affinity_info = psci_affinity_info; + + psci_ops.migrate_info_type = psci_migrate_info_type; + + arm_pm_restart = psci_sys_reset; + + pm_power_off = psci_sys_poweroff; + } + + /* + * Probe function for PSCI firmware versions >= 0.2 + */ + static int __init psci_probe(void) + { + u32 ver = psci_get_version(); + + pr_info("PSCIv%d.%d detected in firmware.\n", + PSCI_VERSION_MAJOR(ver), + PSCI_VERSION_MINOR(ver)); + + if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) { + pr_err("Conflicting PSCI version detected.\n"); + return -EINVAL; + } + + psci_0_2_set_functions(); + + psci_init_migrate(); + + return 0; + } + + typedef int (*psci_initcall_t)(const struct device_node *); + + /* + * PSCI init function for PSCI versions >=0.2 + * + * Probe based on PSCI PSCI_VERSION function + */ + static int __init psci_0_2_init(struct device_node *np) + { + int err; + + err = get_set_conduit_method(np); + + if (err) + goto out_put_node; + /* + * Starting with v0.2, the PSCI specification introduced a call + * (PSCI_VERSION) that allows probing the firmware version, so + * that PSCI function IDs and version specific initialization + * can be carried out according to the specific version reported + * by firmware + */ + err = psci_probe(); + + out_put_node: + of_node_put(np); + return err; + } + + /* + * PSCI < v0.2 get PSCI Function IDs via DT. + */ + static int __init psci_0_1_init(struct device_node *np) + { + u32 id; + int err; + + err = get_set_conduit_method(np); + + if (err) + goto out_put_node; + + pr_info("Using PSCI v0.1 Function IDs from DT\n"); + + if (!of_property_read_u32(np, "cpu_suspend", &id)) { + psci_function_id[PSCI_FN_CPU_SUSPEND] = id; + psci_ops.cpu_suspend = psci_cpu_suspend; + } + + if (!of_property_read_u32(np, "cpu_off", &id)) { + psci_function_id[PSCI_FN_CPU_OFF] = id; + psci_ops.cpu_off = psci_cpu_off; + } + + if (!of_property_read_u32(np, "cpu_on", &id)) { + psci_function_id[PSCI_FN_CPU_ON] = id; + psci_ops.cpu_on = psci_cpu_on; + } + + if (!of_property_read_u32(np, "migrate", &id)) { + psci_function_id[PSCI_FN_MIGRATE] = id; + psci_ops.migrate = psci_migrate; + } + + out_put_node: + of_node_put(np); + return err; + } + -static const struct of_device_id psci_of_match[] __initconst = { ++static const struct of_device_id const psci_of_match[] __initconst = { + { .compatible = "arm,psci", .data = psci_0_1_init}, + { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, + {}, + }; + + int __init psci_dt_init(void) + { + struct device_node *np; + const struct of_device_id *matched_np; + psci_initcall_t init_fn; + + np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np); + + if (!np) + return -ENODEV; + + init_fn = (psci_initcall_t)matched_np->data; + return init_fn(np); + } + + #ifdef CONFIG_ACPI + /* + * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's + * explicitly clarified in SBBR + */ + int __init psci_acpi_init(void) + { + if (!acpi_psci_present()) { + pr_info("is not implemented in ACPI.\n"); + return -EOPNOTSUPP; + } + + pr_info("probing for conduit method from ACPI.\n"); + + if (acpi_psci_use_hvc()) + invoke_psci_fn = __invoke_psci_fn_hvc; + else + invoke_psci_fn = __invoke_psci_fn_smc; + + return psci_probe(); + } + #endif