| /** |
| * Copyright (C) ARM Limited 2013-2014. All rights reserved. |
| * |
| * 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. |
| * |
| */ |
| |
| #if GATOR_IKS_SUPPORT |
| |
| #include <linux/of.h> |
| #include <asm/bL_switcher.h> |
| #include <asm/smp_plat.h> |
| #include <trace/events/power_cpu_migrate.h> |
| |
| static bool map_cpuids; |
| static int mpidr_cpuids[NR_CPUS]; |
| static const struct gator_cpu * mpidr_cpus[NR_CPUS]; |
| static int __lcpu_to_pcpu[NR_CPUS]; |
| |
| static const struct gator_cpu *gator_find_cpu_by_dt_name(const char *const name) |
| { |
| int i; |
| |
| for (i = 0; gator_cpus[i].cpuid != 0; ++i) { |
| const struct gator_cpu *const gator_cpu = &gator_cpus[i]; |
| if (gator_cpu->dt_name != NULL && strcmp(gator_cpu->dt_name, name) == 0) { |
| return gator_cpu; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| static void calc_first_cluster_size(void) |
| { |
| int len; |
| const u32 *val; |
| const char *compatible; |
| struct device_node *cn = NULL; |
| int mpidr_cpuids_count = 0; |
| |
| // Zero is a valid cpuid, so initialize the array to 0xff's |
| memset(&mpidr_cpuids, 0xff, sizeof(mpidr_cpuids)); |
| memset(&mpidr_cpus, 0, sizeof(mpidr_cpus)); |
| |
| while ((cn = of_find_node_by_type(cn, "cpu"))) { |
| BUG_ON(mpidr_cpuids_count >= NR_CPUS); |
| |
| val = of_get_property(cn, "reg", &len); |
| if (!val || len != 4) { |
| pr_err("%s missing reg property\n", cn->full_name); |
| continue; |
| } |
| compatible = of_get_property(cn, "compatible", NULL); |
| if (compatible == NULL) { |
| pr_err("%s missing compatible property\n", cn->full_name); |
| continue; |
| } |
| |
| mpidr_cpuids[mpidr_cpuids_count] = be32_to_cpup(val); |
| mpidr_cpus[mpidr_cpuids_count] = gator_find_cpu_by_dt_name(compatible); |
| ++mpidr_cpuids_count; |
| } |
| |
| map_cpuids = (mpidr_cpuids_count == nr_cpu_ids); |
| } |
| |
| static int linearize_mpidr(int mpidr) |
| { |
| int i; |
| for (i = 0; i < nr_cpu_ids; ++i) { |
| if (mpidr_cpuids[i] == mpidr) { |
| return i; |
| } |
| } |
| |
| BUG(); |
| } |
| |
| int lcpu_to_pcpu(const int lcpu) |
| { |
| int pcpu; |
| |
| if (!map_cpuids) |
| return lcpu; |
| |
| BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0); |
| pcpu = __lcpu_to_pcpu[lcpu]; |
| BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0); |
| return pcpu; |
| } |
| |
| int pcpu_to_lcpu(const int pcpu) |
| { |
| int lcpu; |
| |
| if (!map_cpuids) |
| return pcpu; |
| |
| BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0); |
| for (lcpu = 0; lcpu < nr_cpu_ids; ++lcpu) { |
| if (__lcpu_to_pcpu[lcpu] == pcpu) { |
| BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0); |
| return lcpu; |
| } |
| } |
| BUG(); |
| } |
| |
| static void gator_update_cpu_mapping(u32 cpu_hwid) |
| { |
| int lcpu = smp_processor_id(); |
| int pcpu = linearize_mpidr(cpu_hwid & MPIDR_HWID_BITMASK); |
| BUG_ON(lcpu >= nr_cpu_ids || lcpu < 0); |
| BUG_ON(pcpu >= nr_cpu_ids || pcpu < 0); |
| __lcpu_to_pcpu[lcpu] = pcpu; |
| } |
| |
| GATOR_DEFINE_PROBE(cpu_migrate_begin, TP_PROTO(u64 timestamp, u32 cpu_hwid)) |
| { |
| const int cpu = get_physical_cpu(); |
| |
| gator_timer_offline((void *)1); |
| gator_timer_offline_dispatch(cpu, true); |
| } |
| |
| GATOR_DEFINE_PROBE(cpu_migrate_finish, TP_PROTO(u64 timestamp, u32 cpu_hwid)) |
| { |
| int cpu; |
| |
| gator_update_cpu_mapping(cpu_hwid); |
| |
| // get_physical_cpu must be called after gator_update_cpu_mapping |
| cpu = get_physical_cpu(); |
| gator_timer_online_dispatch(cpu, true); |
| gator_timer_online((void *)1); |
| } |
| |
| GATOR_DEFINE_PROBE(cpu_migrate_current, TP_PROTO(u64 timestamp, u32 cpu_hwid)) |
| { |
| gator_update_cpu_mapping(cpu_hwid); |
| } |
| |
| static void gator_send_iks_core_names(void) |
| { |
| int cpu; |
| // Send the cpu names |
| preempt_disable(); |
| for (cpu = 0; cpu < nr_cpu_ids; ++cpu) { |
| if (mpidr_cpus[cpu] != NULL) { |
| gator_send_core_name(cpu, mpidr_cpus[cpu]->cpuid, mpidr_cpus[cpu]); |
| } |
| } |
| preempt_enable(); |
| } |
| |
| static int gator_migrate_start(void) |
| { |
| int retval = 0; |
| |
| if (!map_cpuids) |
| return retval; |
| |
| if (retval == 0) |
| retval = GATOR_REGISTER_TRACE(cpu_migrate_begin); |
| if (retval == 0) |
| retval = GATOR_REGISTER_TRACE(cpu_migrate_finish); |
| if (retval == 0) |
| retval = GATOR_REGISTER_TRACE(cpu_migrate_current); |
| if (retval == 0) { |
| // Initialize the logical to physical cpu mapping |
| memset(&__lcpu_to_pcpu, 0xff, sizeof(__lcpu_to_pcpu)); |
| bL_switcher_trace_trigger(); |
| } |
| return retval; |
| } |
| |
| static void gator_migrate_stop(void) |
| { |
| if (!map_cpuids) |
| return; |
| |
| GATOR_UNREGISTER_TRACE(cpu_migrate_current); |
| GATOR_UNREGISTER_TRACE(cpu_migrate_finish); |
| GATOR_UNREGISTER_TRACE(cpu_migrate_begin); |
| } |
| |
| #else |
| |
| #define calc_first_cluster_size() |
| #define gator_send_iks_core_names() |
| #define gator_migrate_start() 0 |
| #define gator_migrate_stop() |
| |
| #endif |