OSDN Git Service

Merge branch 'devel-stable' into for-linus
authorRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 3 Sep 2015 14:28:50 +0000 (15:28 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 3 Sep 2015 14:28:50 +0000 (15:28 +0100)
Conflicts:
drivers/perf/arm_pmu.c

30 files changed:
Documentation/devicetree/bindings/arm/pmu.txt
MAINTAINERS
arch/arm/Kconfig
arch/arm/include/asm/psci.h
arch/arm/kernel/Makefile
arch/arm/kernel/perf_event_v6.c
arch/arm/kernel/perf_event_v7.c
arch/arm/kernel/perf_event_xscale.c
arch/arm/kernel/psci.c [deleted file]
arch/arm/kernel/psci_smp.c
arch/arm/kernel/setup.c
arch/arm/mach-highbank/highbank.c
arch/arm/mach-highbank/pm.c
arch/arm/mach-ux500/cpu-db8500.c
arch/arm64/Kconfig
arch/arm64/include/asm/acpi.h
arch/arm64/include/asm/psci.h [deleted file]
arch/arm64/kernel/psci.c
arch/arm64/kernel/setup.c
drivers/Kconfig
drivers/Makefile
drivers/cpuidle/cpuidle-calxeda.c
drivers/firmware/Kconfig
drivers/firmware/Makefile
drivers/firmware/psci.c [new file with mode: 0644]
drivers/perf/Kconfig [new file with mode: 0644]
drivers/perf/Makefile [new file with mode: 0644]
drivers/perf/arm_pmu.c [moved from arch/arm/kernel/perf_event.c with 94% similarity]
include/linux/perf/arm_pmu.h [moved from arch/arm/include/asm/pmu.h with 98% similarity]
include/linux/psci.h [new file with mode: 0644]

index 3b5f5d1..435251f 100644 (file)
@@ -26,13 +26,19 @@ Required properties:
 
 Optional properties:
 
-- interrupt-affinity : Valid only when using SPIs, specifies a list of phandles
-                       to CPU nodes corresponding directly to the affinity of
+- interrupt-affinity : When using SPIs, specifies a list of phandles to CPU
+                       nodes corresponding directly to the affinity of
                       the SPIs listed in the interrupts property.
 
-                      This property should be present when there is more than
+                       When using a PPI, specifies a list of phandles to CPU
+                      nodes corresponding to the set of CPUs which have
+                      a PMU of this type signalling the PPI listed in the
+                      interrupts property.
+
+                       This property should be present when there is more than
                       a single SPI.
 
+
 - qcom,no-pc-write : Indicates that this PMU doesn't support the 0xc and 0xd
                      events.
 
index fd60784..44998e1 100644 (file)
@@ -799,11 +799,13 @@ F:        arch/arm/include/asm/floppy.h
 ARM PMU PROFILING AND DEBUGGING
 M:     Will Deacon <will.deacon@arm.com>
 S:     Maintained
-F:     arch/arm/kernel/perf_event*
+F:     arch/arm/kernel/perf_*
 F:     arch/arm/oprofile/common.c
-F:     arch/arm/include/asm/pmu.h
 F:     arch/arm/kernel/hw_breakpoint.c
 F:     arch/arm/include/asm/hw_breakpoint.h
+F:     arch/arm/include/asm/perf_event.h
+F:     drivers/perf/arm_pmu.c
+F:     include/linux/perf/arm_pmu.h
 
 ARM PORT
 M:     Russell King <linux@arm.linux.org.uk>
@@ -8064,6 +8066,15 @@ S:       Maintained
 F:     include/linux/power_supply.h
 F:     drivers/power/
 
+POWER STATE COORDINATION INTERFACE (PSCI)
+M:     Mark Rutland <mark.rutland@arm.com>
+M:     Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+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" <rafael.j.wysocki@intel.com>
 S:     Maintained
index 3458828..45e635b 100644 (file)
@@ -1499,6 +1499,7 @@ config HOTPLUG_CPU
 config ARM_PSCI
        bool "Support for the ARM Power State Coordination Interface (PSCI)"
        depends on CPU_V7
+       select ARM_PSCI_FW
        help
          Say Y here if you want Linux to communicate with system firmware
          implementing the PSCI specification for CPU-centric power
@@ -1719,12 +1720,8 @@ config CPU_SW_DOMAIN_PAN
          the remainder of userspace will become appropriately inaccessible.
 
 config HW_PERF_EVENTS
-       bool "Enable hardware performance counter support for perf events"
-       depends on PERF_EVENTS
-       default y
-       help
-         Enable hardware performance counter support for perf events. If
-         disabled, perf events will use software events only.
+       def_bool y
+       depends on ARM_PMU
 
 config SYS_SUPPORTS_HUGETLBFS
        def_bool y
index c25ef3e..68ee3ce 100644 (file)
 #ifndef __ASM_ARM_PSCI_H
 #define __ASM_ARM_PSCI_H
 
-#define PSCI_POWER_STATE_TYPE_STANDBY          0
-#define PSCI_POWER_STATE_TYPE_POWER_DOWN       1
-
-struct psci_power_state {
-       u16     id;
-       u8      type;
-       u8      affinity_level;
-};
-
-struct psci_operations {
-       int (*cpu_suspend)(struct psci_power_state state,
-                          unsigned long entry_point);
-       int (*cpu_off)(struct psci_power_state state);
-       int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
-       int (*migrate)(unsigned long cpuid);
-       int (*affinity_info)(unsigned long target_affinity,
-                       unsigned long lowest_affinity_level);
-       int (*migrate_info_type)(void);
-};
-
-extern struct psci_operations psci_ops;
 extern struct smp_operations psci_smp_ops;
 
 #ifdef CONFIG_ARM_PSCI
-int psci_init(void);
 bool psci_smp_available(void);
 #else
-static inline int psci_init(void) { return 0; }
 static inline bool psci_smp_available(void) { return false; }
 #endif
 
index e69f7a1..af9e59b 100644 (file)
@@ -71,8 +71,7 @@ obj-$(CONFIG_CPU_PJ4)         += pj4-cp0.o
 obj-$(CONFIG_CPU_PJ4B)         += pj4-cp0.o
 obj-$(CONFIG_IWMMXT)           += iwmmxt.o
 obj-$(CONFIG_PERF_EVENTS)      += perf_regs.o perf_callchain.o
-obj-$(CONFIG_HW_PERF_EVENTS)   += perf_event.o \
-                                  perf_event_xscale.o perf_event_v6.o \
+obj-$(CONFIG_HW_PERF_EVENTS)   += perf_event_xscale.o perf_event_v6.o \
                                   perf_event_v7.o
 CFLAGS_pj4-cp0.o               := -marm
 AFLAGS_iwmmxt.o                        := -Wa,-mcpu=iwmmxt
@@ -89,7 +88,7 @@ obj-$(CONFIG_EARLY_PRINTK)    += early_printk.o
 
 obj-$(CONFIG_ARM_VIRT_EXT)     += hyp-stub.o
 ifeq ($(CONFIG_ARM_PSCI),y)
-obj-y                          += psci.o psci-call.o
+obj-y                          += psci-call.o
 obj-$(CONFIG_SMP)              += psci_smp.o
 endif
 
index 09f83e4..09413e7 100644 (file)
@@ -34,9 +34,9 @@
 
 #include <asm/cputype.h>
 #include <asm/irq_regs.h>
-#include <asm/pmu.h>
 
 #include <linux/of.h>
+#include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
 
 enum armv6_perf_types {
index f9b37f8..126dc67 100644 (file)
 #include <asm/cp15.h>
 #include <asm/cputype.h>
 #include <asm/irq_regs.h>
-#include <asm/pmu.h>
 #include <asm/vfp.h>
 #include "../vfp/vfpinstr.h"
 
 #include <linux/of.h>
+#include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
 
 /*
index 304d056..aa0499e 100644 (file)
@@ -16,9 +16,9 @@
 
 #include <asm/cputype.h>
 #include <asm/irq_regs.h>
-#include <asm/pmu.h>
 
 #include <linux/of.h>
+#include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
 
 enum xscale_perf_types {
diff --git a/arch/arm/kernel/psci.c b/arch/arm/kernel/psci.c
deleted file mode 100644 (file)
index f90fdf4..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * 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) 2012 ARM Limited
- *
- * Author: Will Deacon <will.deacon@arm.com>
- */
-
-#define pr_fmt(fmt) "psci: " fmt
-
-#include <linux/init.h>
-#include <linux/of.h>
-#include <linux/reboot.h>
-#include <linux/pm.h>
-#include <uapi/linux/psci.h>
-
-#include <asm/compiler.h>
-#include <asm/errno.h>
-#include <asm/psci.h>
-#include <asm/system_misc.h>
-
-struct psci_operations psci_ops;
-
-static int (*invoke_psci_fn)(u32, u32, u32, u32);
-typedef int (*psci_initcall_t)(const struct device_node *);
-
-asmlinkage int __invoke_psci_fn_hvc(u32, u32, u32, u32);
-asmlinkage int __invoke_psci_fn_smc(u32, u32, u32, u32);
-
-enum psci_function {
-       PSCI_FN_CPU_SUSPEND,
-       PSCI_FN_CPU_ON,
-       PSCI_FN_CPU_OFF,
-       PSCI_FN_MIGRATE,
-       PSCI_FN_AFFINITY_INFO,
-       PSCI_FN_MIGRATE_INFO_TYPE,
-       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_power_state_pack(struct psci_power_state state)
-{
-       return ((state.id << PSCI_0_2_POWER_STATE_ID_SHIFT)
-                       & PSCI_0_2_POWER_STATE_ID_MASK) |
-               ((state.type << PSCI_0_2_POWER_STATE_TYPE_SHIFT)
-                & PSCI_0_2_POWER_STATE_TYPE_MASK) |
-               ((state.affinity_level << PSCI_0_2_POWER_STATE_AFFL_SHIFT)
-                & PSCI_0_2_POWER_STATE_AFFL_MASK);
-}
-
-static int psci_get_version(void)
-{
-       int err;
-
-       err = invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
-       return err;
-}
-
-static int psci_cpu_suspend(struct psci_power_state state,
-                           unsigned long entry_point)
-{
-       int err;
-       u32 fn, power_state;
-
-       fn = psci_function_id[PSCI_FN_CPU_SUSPEND];
-       power_state = psci_power_state_pack(state);
-       err = invoke_psci_fn(fn, power_state, entry_point, 0);
-       return psci_to_linux_errno(err);
-}
-
-static int psci_cpu_off(struct psci_power_state state)
-{
-       int err;
-       u32 fn, power_state;
-
-       fn = psci_function_id[PSCI_FN_CPU_OFF];
-       power_state = psci_power_state_pack(state);
-       err = invoke_psci_fn(fn, power_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)
-{
-       int err;
-       u32 fn;
-
-       fn = psci_function_id[PSCI_FN_AFFINITY_INFO];
-       err = invoke_psci_fn(fn, target_affinity, lowest_affinity_level, 0);
-       return err;
-}
-
-static int psci_migrate_info_type(void)
-{
-       int err;
-       u32 fn;
-
-       fn = psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE];
-       err = invoke_psci_fn(fn, 0, 0, 0);
-       return err;
-}
-
-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);
-}
-
-/*
- * PSCI Function IDs for v0.2+ are well defined so use
- * standard values.
- */
-static int psci_0_2_init(struct device_node *np)
-{
-       int err, ver;
-
-       err = get_set_conduit_method(np);
-
-       if (err)
-               goto out_put_node;
-
-       ver = psci_get_version();
-
-       if (ver == PSCI_RET_NOT_SUPPORTED) {
-               /* PSCI v0.2 mandates implementation of PSCI_ID_VERSION. */
-               pr_err("PSCI firmware does not comply with the v0.2 spec.\n");
-               err = -EOPNOTSUPP;
-               goto out_put_node;
-       } else {
-               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) {
-                       err = -EINVAL;
-                       pr_err("Conflicting PSCI version detected.\n");
-                       goto out_put_node;
-               }
-       }
-
-       pr_info("Using standard PSCI v0.2 function IDs\n");
-       psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN_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_CPU_ON;
-       psci_ops.cpu_on = psci_cpu_on;
-
-       psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN_MIGRATE;
-       psci_ops.migrate = psci_migrate;
-
-       psci_function_id[PSCI_FN_AFFINITY_INFO] = PSCI_0_2_FN_AFFINITY_INFO;
-       psci_ops.affinity_info = psci_affinity_info;
-
-       psci_function_id[PSCI_FN_MIGRATE_INFO_TYPE] =
-               PSCI_0_2_FN_MIGRATE_INFO_TYPE;
-       psci_ops.migrate_info_type = psci_migrate_info_type;
-
-       arm_pm_restart = psci_sys_reset;
-
-       pm_power_off = psci_sys_poweroff;
-
-out_put_node:
-       of_node_put(np);
-       return err;
-}
-
-/*
- * PSCI < v0.2 get PSCI Function IDs via DT.
- */
-static int 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 = {
-       { .compatible = "arm,psci", .data = psci_0_1_init},
-       { .compatible = "arm,psci-0.2", .data = psci_0_2_init},
-       {},
-};
-
-int __init psci_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);
-}
index 28a1db4..61c04b0 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/smp.h>
 #include <linux/of.h>
 #include <linux/delay.h>
+#include <linux/psci.h>
+
 #include <uapi/linux/psci.h>
 
 #include <asm/psci.h>
@@ -51,22 +53,34 @@ static int psci_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
        if (psci_ops.cpu_on)
                return psci_ops.cpu_on(cpu_logical_map(cpu),
-                                      __pa(secondary_startup));
+                                       virt_to_idmap(&secondary_startup));
        return -ENODEV;
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
+int psci_cpu_disable(unsigned int cpu)
+{
+       /* Fail early if we don't have CPU_OFF support */
+       if (!psci_ops.cpu_off)
+               return -EOPNOTSUPP;
+
+       /* Trusted OS will deny CPU_OFF */
+       if (psci_tos_resident_on(cpu))
+               return -EPERM;
+
+       return 0;
+}
+
 void __ref psci_cpu_die(unsigned int cpu)
 {
-       const struct psci_power_state ps = {
-               .type = PSCI_POWER_STATE_TYPE_POWER_DOWN,
-       };
+       u32 state = PSCI_POWER_STATE_TYPE_POWER_DOWN <<
+                   PSCI_0_2_POWER_STATE_TYPE_SHIFT;
 
-       if (psci_ops.cpu_off)
-               psci_ops.cpu_off(ps);
+       if (psci_ops.cpu_off)
+               psci_ops.cpu_off(state);
 
-       /* We should never return */
-       panic("psci: cpu %d failed to shutdown\n", cpu);
+       /* We should never return */
+       panic("psci: cpu %d failed to shutdown\n", cpu);
 }
 
 int __ref psci_cpu_kill(unsigned int cpu)
@@ -109,6 +123,7 @@ bool __init psci_smp_available(void)
 struct smp_operations __initdata psci_smp_ops = {
        .smp_boot_secondary     = psci_boot_secondary,
 #ifdef CONFIG_HOTPLUG_CPU
+       .cpu_disable            = psci_cpu_disable,
        .cpu_die                = psci_cpu_die,
        .cpu_kill               = psci_cpu_kill,
 #endif
index e2ecee6..20edd34 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/bug.h>
 #include <linux/compiler.h>
 #include <linux/sort.h>
+#include <linux/psci.h>
 
 #include <asm/unified.h>
 #include <asm/cp15.h>
@@ -976,7 +977,7 @@ void __init setup_arch(char **cmdline_p)
        unflatten_device_tree();
 
        arm_dt_init_cpu_maps();
-       psci_init();
+       psci_dt_init();
        xen_early_init();
 #ifdef CONFIG_SMP
        if (is_smp()) {
index 231fba0..6050a14 100644 (file)
@@ -28,8 +28,8 @@
 #include <linux/reboot.h>
 #include <linux/amba/bus.h>
 #include <linux/platform_device.h>
+#include <linux/psci.h>
 
-#include <asm/psci.h>
 #include <asm/hardware/cache-l2x0.h>
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
index 7f2bd85..4003116 100644 (file)
 
 #include <linux/cpu_pm.h>
 #include <linux/init.h>
+#include <linux/psci.h>
 #include <linux/suspend.h>
 
 #include <asm/suspend.h>
-#include <asm/psci.h>
+
+#include <uapi/linux/psci.h>
+
+#define HIGHBANK_SUSPEND_PARAM \
+       ((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \
+        (1 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \
+        (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT))
 
 static int highbank_suspend_finish(unsigned long val)
 {
-       const struct psci_power_state ps = {
-               .type = PSCI_POWER_STATE_TYPE_POWER_DOWN,
-               .affinity_level = 1,
-       };
-
-       return psci_ops.cpu_suspend(ps, __pa(cpu_resume));
+       return psci_ops.cpu_suspend(HIGHBANK_SUSPEND_PARAM, __pa(cpu_resume));
 }
 
 static int highbank_pm_enter(suspend_state_t state)
index 1691380..5578dc1 100644 (file)
 #include <linux/mfd/dbx500-prcmu.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
+#include <linux/perf/arm_pmu.h>
 #include <linux/regulator/machine.h>
 #include <linux/random.h>
 
-#include <asm/pmu.h>
 #include <asm/mach/map.h>
 
 #include "setup.h"
index 318175f..7c55a63 100644 (file)
@@ -20,6 +20,7 @@ config ARM64
        select ARM_GIC_V2M if PCI_MSI
        select ARM_GIC_V3
        select ARM_GIC_V3_ITS if PCI_MSI
+       select ARM_PSCI_FW
        select BUILDTIME_EXTABLE_SORT
        select CLONE_BACKWARDS
        select COMMON_CLK
index 406485e..208cec0 100644 (file)
 #ifndef _ASM_ACPI_H
 #define _ASM_ACPI_H
 
-#include <linux/mm.h>
 #include <linux/irqchip/arm-gic-acpi.h>
+#include <linux/mm.h>
+#include <linux/psci.h>
 
 #include <asm/cputype.h>
-#include <asm/psci.h>
 #include <asm/smp_plat.h>
 
 /* Macros for consistency checks of the GICC subtable of MADT */
diff --git a/arch/arm64/include/asm/psci.h b/arch/arm64/include/asm/psci.h
deleted file mode 100644 (file)
index 49d7e1a..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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) 2013 ARM Limited
- */
-
-#ifndef __ASM_PSCI_H
-#define __ASM_PSCI_H
-
-int __init psci_dt_init(void);
-
-#ifdef CONFIG_ACPI
-int __init psci_acpi_init(void);
-bool __init acpi_psci_present(void);
-bool __init acpi_psci_use_hvc(void);
-#else
-static inline int psci_acpi_init(void) { return 0; }
-static inline bool acpi_psci_present(void) { return false; }
-#endif
-
-#endif /* __ASM_PSCI_H */
index 869f202..51fd15a 100644 (file)
 #include <linux/init.h>
 #include <linux/of.h>
 #include <linux/smp.h>
-#include <linux/reboot.h>
-#include <linux/pm.h>
 #include <linux/delay.h>
+#include <linux/psci.h>
 #include <linux/slab.h>
+
 #include <uapi/linux/psci.h>
 
 #include <asm/compiler.h>
-#include <asm/cputype.h>
 #include <asm/cpu_ops.h>
 #include <asm/errno.h>
-#include <asm/psci.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
-#include <asm/system_misc.h>
-
-#define PSCI_POWER_STATE_TYPE_STANDBY          0
-#define PSCI_POWER_STATE_TYPE_POWER_DOWN       1
 
 static bool psci_power_state_loses_context(u32 state)
 {
@@ -50,122 +44,8 @@ static bool psci_power_state_is_valid(u32 state)
        return !(state & ~valid_mask);
 }
 
-/*
- * 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;
-
-struct psci_operations {
-       int (*cpu_suspend)(u32 state, unsigned long entry_point);
-       int (*cpu_off)(u32 state);
-       int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
-       int (*migrate)(unsigned long cpuid);
-       int (*affinity_info)(unsigned long target_affinity,
-                       unsigned long lowest_affinity_level);
-       int (*migrate_info_type)(void);
-};
-
-static 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 DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
 
-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_FN64_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_FN64_MIGRATE_INFO_UP_CPU, 0, 0, 0);
-}
-
 static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu)
 {
        int i, ret, count = 0;
@@ -230,238 +110,6 @@ free_mem:
        return ret;
 }
 
-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;
-
-       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_FN64_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_FN64_CPU_ON;
-       psci_ops.cpu_on = psci_cpu_on;
-
-       psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN64_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 = {
-       { .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
-
 #ifdef CONFIG_SMP
 
 static int __init cpu_psci_cpu_init(unsigned int cpu)
@@ -489,11 +137,6 @@ static int cpu_psci_cpu_boot(unsigned int cpu)
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
-static bool psci_tos_resident_on(int cpu)
-{
-       return cpu == resident_cpu;
-}
-
 static int cpu_psci_cpu_disable(unsigned int cpu)
 {
        /* Fail early if we don't have CPU_OFF support */
index f3067d4..96ce264 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/of_platform.h>
 #include <linux/efi.h>
 #include <linux/personality.h>
+#include <linux/psci.h>
 
 #include <asm/acpi.h>
 #include <asm/fixmap.h>
@@ -61,7 +62,6 @@
 #include <asm/tlbflush.h>
 #include <asm/traps.h>
 #include <asm/memblock.h>
-#include <asm/psci.h>
 #include <asm/efi.h>
 #include <asm/virt.h>
 #include <asm/xen/hypervisor.h>
index 6e973b8..3497485 100644 (file)
@@ -176,6 +176,8 @@ source "drivers/powercap/Kconfig"
 
 source "drivers/mcb/Kconfig"
 
+source "drivers/perf/Kconfig"
+
 source "drivers/ras/Kconfig"
 
 source "drivers/thunderbolt/Kconfig"
index b64b49f..f245f22 100644 (file)
@@ -161,6 +161,7 @@ obj-$(CONFIG_NTB)           += ntb/
 obj-$(CONFIG_FMC)              += fmc/
 obj-$(CONFIG_POWERCAP)         += powercap/
 obj-$(CONFIG_MCB)              += mcb/
+obj-$(CONFIG_PERF_EVENTS)      += perf/
 obj-$(CONFIG_RAS)              += ras/
 obj-$(CONFIG_THUNDERBOLT)      += thunderbolt/
 obj-$(CONFIG_CORESIGHT)                += hwtracing/coresight/
index c13feec..ea9728f 100644 (file)
 #include <linux/init.h>
 #include <linux/mm.h>
 #include <linux/platform_device.h>
+#include <linux/psci.h>
+
 #include <asm/cpuidle.h>
 #include <asm/suspend.h>
-#include <asm/psci.h>
+
+#include <uapi/linux/psci.h>
+
+#define CALXEDA_IDLE_PARAM \
+       ((0 << PSCI_0_2_POWER_STATE_ID_SHIFT) | \
+        (0 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) | \
+        (PSCI_POWER_STATE_TYPE_POWER_DOWN << PSCI_0_2_POWER_STATE_TYPE_SHIFT))
 
 static int calxeda_idle_finish(unsigned long val)
 {
-       const struct psci_power_state ps = {
-               .type = PSCI_POWER_STATE_TYPE_POWER_DOWN,
-       };
-       return psci_ops.cpu_suspend(ps, __pa(cpu_resume));
+       return psci_ops.cpu_suspend(CALXEDA_IDLE_PARAM, __pa(cpu_resume));
 }
 
 static int calxeda_pwrdown_idle(struct cpuidle_device *dev,
index 99c69a3..d8de6a8 100644 (file)
@@ -5,6 +5,9 @@
 
 menu "Firmware Drivers"
 
+config ARM_PSCI_FW
+       bool
+
 config EDD
        tristate "BIOS Enhanced Disk Drive calls determine boot disk"
        depends on X86
index 4a4b897..000830f 100644 (file)
@@ -1,6 +1,7 @@
 #
 # Makefile for the linux kernel.
 #
+obj-$(CONFIG_ARM_PSCI_FW)      += psci.o
 obj-$(CONFIG_DMI)              += dmi_scan.o
 obj-$(CONFIG_DMI_SYSFS)                += dmi-sysfs.o
 obj-$(CONFIG_EDD)              += edd.o
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
new file mode 100644 (file)
index 0000000..a695600
--- /dev/null
@@ -0,0 +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 <linux/errno.h>
+#include <linux/linkage.h>
+#include <linux/of.h>
+#include <linux/pm.h>
+#include <linux/printk.h>
+#include <linux/psci.h>
+#include <linux/reboot.h>
+
+#include <uapi/linux/psci.h>
+
+#include <asm/cputype.h>
+#include <asm/system_misc.h>
+#include <asm/smp_plat.h>
+
+/*
+ * 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 = {
+       { .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
diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
new file mode 100644 (file)
index 0000000..d9de36e
--- /dev/null
@@ -0,0 +1,15 @@
+#
+# Performance Monitor Drivers
+#
+
+menu "Performance monitor support"
+
+config ARM_PMU
+       depends on PERF_EVENTS && ARM
+       bool "ARM PMU framework"
+       default y
+       help
+         Say y if you want to use CPU performance monitors on ARM-based
+         systems.
+
+endmenu
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile
new file mode 100644 (file)
index 0000000..acd2397
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_ARM_PMU) += arm_pmu.o
similarity index 94%
rename from arch/arm/kernel/perf_event.c
rename to drivers/perf/arm_pmu.c
index 7d5379c..2365a32 100644 (file)
@@ -15,7 +15,8 @@
 #include <linux/cpumask.h>
 #include <linux/export.h>
 #include <linux/kernel.h>
-#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/perf/arm_pmu.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
@@ -24,7 +25,6 @@
 
 #include <asm/cputype.h>
 #include <asm/irq_regs.h>
-#include <asm/pmu.h>
 
 static int
 armpmu_map_cache_event(const unsigned (*cache_map)
@@ -790,54 +790,77 @@ static int probe_current_pmu(struct arm_pmu *pmu,
 
 static int of_pmu_irq_cfg(struct arm_pmu *pmu)
 {
-       int i, irq, *irqs;
+       int *irqs, i = 0;
+       bool using_spi = false;
        struct platform_device *pdev = pmu->plat_device;
 
-       /* Don't bother with PPIs; they're already affine */
-       irq = platform_get_irq(pdev, 0);
-       if (irq >= 0 && irq_is_percpu(irq)) {
-               cpumask_setall(&pmu->supported_cpus);
-               return 0;
-       }
-
        irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL);
        if (!irqs)
                return -ENOMEM;
 
-       for (i = 0; i < pdev->num_resources; ++i) {
+       do {
                struct device_node *dn;
-               int cpu;
+               int cpu, irq;
 
-               dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity",
-                                     i);
-               if (!dn) {
-                       pr_warn("Failed to parse %s/interrupt-affinity[%d]\n",
-                               of_node_full_name(pdev->dev.of_node), i);
+               /* See if we have an affinity entry */
+               dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity", i);
+               if (!dn)
                        break;
+
+               /* Check the IRQ type and prohibit a mix of PPIs and SPIs */
+               irq = platform_get_irq(pdev, i);
+               if (irq >= 0) {
+                       bool spi = !irq_is_percpu(irq);
+
+                       if (i > 0 && spi != using_spi) {
+                               pr_err("PPI/SPI IRQ type mismatch for %s!\n",
+                                       dn->name);
+                               kfree(irqs);
+                               return -EINVAL;
+                       }
+
+                       using_spi = spi;
                }
 
+               /* Now look up the logical CPU number */
                for_each_possible_cpu(cpu)
-                       if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL))
+                       if (dn == of_cpu_device_node_get(cpu))
                                break;
 
                if (cpu >= nr_cpu_ids) {
                        pr_warn("Failed to find logical CPU for %s\n",
                                dn->name);
                        of_node_put(dn);
+                       cpumask_setall(&pmu->supported_cpus);
                        break;
                }
                of_node_put(dn);
 
-               irqs[i] = cpu;
+               /* For SPIs, we need to track the affinity per IRQ */
+               if (using_spi) {
+                       if (i >= pdev->num_resources) {
+                               of_node_put(dn);
+                               break;
+                       }
+
+                       irqs[i] = cpu;
+               }
+
+               /* Keep track of the CPUs containing this PMU type */
                cpumask_set_cpu(cpu, &pmu->supported_cpus);
-       }
+               of_node_put(dn);
+               i++;
+       } while (1);
 
-       if (i == pdev->num_resources) {
+       /* If we didn't manage to parse anything, claim to support all CPUs */
+       if (cpumask_weight(&pmu->supported_cpus) == 0)
+               cpumask_setall(&pmu->supported_cpus);
+
+       /* If we matched up the IRQ affinities, use them to route the SPIs */
+       if (using_spi && i == pdev->num_resources)
                pmu->irq_affinity = irqs;
-       } else {
+       else
                kfree(irqs);
-               cpumask_setall(&pmu->supported_cpus);
-       }
 
        return 0;
 }
similarity index 98%
rename from arch/arm/include/asm/pmu.h
rename to include/linux/perf/arm_pmu.h
index 3fc87df..bfa673b 100644 (file)
@@ -30,7 +30,7 @@ struct arm_pmu_platdata {
                                  irq_handler_t pmu_handler);
 };
 
-#ifdef CONFIG_HW_PERF_EVENTS
+#ifdef CONFIG_ARM_PMU
 
 /*
  * The ARMv7 CPU PMU supports up to 32 event counters.
@@ -149,6 +149,6 @@ int arm_pmu_device_probe(struct platform_device *pdev,
                         const struct of_device_id *of_table,
                         const struct pmu_probe_info *probe_table);
 
-#endif /* CONFIG_HW_PERF_EVENTS */
+#endif /* CONFIG_ARM_PMU */
 
 #endif /* __ARM_PMU_H__ */
diff --git a/include/linux/psci.h b/include/linux/psci.h
new file mode 100644 (file)
index 0000000..a682fcc
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * 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
+ */
+
+#ifndef __LINUX_PSCI_H
+#define __LINUX_PSCI_H
+
+#include <linux/init.h>
+#include <linux/types.h>
+
+#define PSCI_POWER_STATE_TYPE_STANDBY          0
+#define PSCI_POWER_STATE_TYPE_POWER_DOWN       1
+
+bool psci_tos_resident_on(int cpu);
+
+struct psci_operations {
+       int (*cpu_suspend)(u32 state, unsigned long entry_point);
+       int (*cpu_off)(u32 state);
+       int (*cpu_on)(unsigned long cpuid, unsigned long entry_point);
+       int (*migrate)(unsigned long cpuid);
+       int (*affinity_info)(unsigned long target_affinity,
+                       unsigned long lowest_affinity_level);
+       int (*migrate_info_type)(void);
+};
+
+extern struct psci_operations psci_ops;
+
+#if defined(CONFIG_ARM_PSCI_FW)
+int __init psci_dt_init(void);
+#else
+static inline int psci_dt_init(void) { return 0; }
+#endif
+
+#if defined(CONFIG_ARM_PSCI_FW) && defined(CONFIG_ACPI)
+int __init psci_acpi_init(void);
+bool __init acpi_psci_present(void);
+bool __init acpi_psci_use_hvc(void);
+#else
+static inline int psci_acpi_init(void) { return 0; }
+static inline bool acpi_psci_present(void) { return false; }
+#endif
+
+#endif /* __LINUX_PSCI_H */