Commit ba750502 authored by Paul Burton's avatar Paul Burton Committed by Ralf Baechle

MIPS: pm-cps: Generate idle state entry code when CPUs are onlined

The MIPS Coherent Processing System (CPS) power management code has
previously generated code used to enter low power idle states once
during boot for all CPUs. This has the drawback that if a CPU is present
in the system but not being used (for example due to the maxcpus kernel
parameter) then we encounter problems due to not having probed that CPU
for information about its type & properties. The result of this is that
we generate entry code which is both unused, potentially entirely
invalid & likely to be unsuitable for the CPU in question anyway.

Avoid this by generating idle state entry code only when a CPU is
brought online. This way we only ever generate code for CPUs that we
know we've probed the properties of, and that will actually be used.

[ralf@linux-mips.org: Resolve merge conflict.]
Signed-off-by: default avatarPaul Burton <paul.burton@imgtec.com>
Cc: Adam Buchbinder <adam.buchbinder@gmail.com>
Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
Cc: Markos Chandras <markos.chandras@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: linux-kernel@vger.kernel.org
Patchwork: https://patchwork.linux-mips.org/patch/14259/Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent cd14c92b
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* option) any later version. * option) any later version.
*/ */
#include <linux/cpuhotplug.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -70,8 +71,8 @@ static DEFINE_PER_CPU_ALIGNED(atomic_t, pm_barrier); ...@@ -70,8 +71,8 @@ static DEFINE_PER_CPU_ALIGNED(atomic_t, pm_barrier);
DEFINE_PER_CPU_ALIGNED(struct mips_static_suspend_state, cps_cpu_state); DEFINE_PER_CPU_ALIGNED(struct mips_static_suspend_state, cps_cpu_state);
/* A somewhat arbitrary number of labels & relocs for uasm */ /* A somewhat arbitrary number of labels & relocs for uasm */
static struct uasm_label labels[32] __initdata; static struct uasm_label labels[32];
static struct uasm_reloc relocs[32] __initdata; static struct uasm_reloc relocs[32];
enum mips_reg { enum mips_reg {
zero, at, v0, v1, a0, a1, a2, a3, zero, at, v0, v1, a0, a1, a2, a3,
...@@ -193,7 +194,7 @@ int cps_pm_enter_state(enum cps_pm_state state) ...@@ -193,7 +194,7 @@ int cps_pm_enter_state(enum cps_pm_state state)
return 0; return 0;
} }
static void __init cps_gen_cache_routine(u32 **pp, struct uasm_label **pl, static void cps_gen_cache_routine(u32 **pp, struct uasm_label **pl,
struct uasm_reloc **pr, struct uasm_reloc **pr,
const struct cache_desc *cache, const struct cache_desc *cache,
unsigned op, int lbl) unsigned op, int lbl)
...@@ -237,7 +238,7 @@ static void __init cps_gen_cache_routine(u32 **pp, struct uasm_label **pl, ...@@ -237,7 +238,7 @@ static void __init cps_gen_cache_routine(u32 **pp, struct uasm_label **pl,
uasm_i_nop(pp); uasm_i_nop(pp);
} }
static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, static int cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl,
struct uasm_reloc **pr, struct uasm_reloc **pr,
const struct cpuinfo_mips *cpu_info, const struct cpuinfo_mips *cpu_info,
int lbl) int lbl)
...@@ -330,7 +331,7 @@ static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, ...@@ -330,7 +331,7 @@ static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl,
return 0; return 0;
} }
static void __init cps_gen_set_top_bit(u32 **pp, struct uasm_label **pl, static void cps_gen_set_top_bit(u32 **pp, struct uasm_label **pl,
struct uasm_reloc **pr, struct uasm_reloc **pr,
unsigned r_addr, int lbl) unsigned r_addr, int lbl)
{ {
...@@ -343,7 +344,7 @@ static void __init cps_gen_set_top_bit(u32 **pp, struct uasm_label **pl, ...@@ -343,7 +344,7 @@ static void __init cps_gen_set_top_bit(u32 **pp, struct uasm_label **pl,
uasm_i_nop(pp); uasm_i_nop(pp);
} }
static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) static void *cps_gen_entry_code(unsigned cpu, enum cps_pm_state state)
{ {
struct uasm_label *l = labels; struct uasm_label *l = labels;
struct uasm_reloc *r = relocs; struct uasm_reloc *r = relocs;
...@@ -637,7 +638,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state) ...@@ -637,7 +638,7 @@ static void * __init cps_gen_entry_code(unsigned cpu, enum cps_pm_state state)
return NULL; return NULL;
} }
static int __init cps_gen_core_entries(unsigned cpu) static int cps_pm_online_cpu(unsigned int cpu)
{ {
enum cps_pm_state state; enum cps_pm_state state;
unsigned core = cpu_data[cpu].core; unsigned core = cpu_data[cpu].core;
...@@ -679,13 +680,10 @@ static int __init cps_gen_core_entries(unsigned cpu) ...@@ -679,13 +680,10 @@ static int __init cps_gen_core_entries(unsigned cpu)
static int __init cps_pm_init(void) static int __init cps_pm_init(void)
{ {
unsigned cpu;
int err;
/* A CM is required for all non-coherent states */ /* A CM is required for all non-coherent states */
if (!mips_cm_present()) { if (!mips_cm_present()) {
pr_warn("pm-cps: no CM, non-coherent states unavailable\n"); pr_warn("pm-cps: no CM, non-coherent states unavailable\n");
goto out; return 0;
} }
/* /*
...@@ -715,12 +713,7 @@ static int __init cps_pm_init(void) ...@@ -715,12 +713,7 @@ static int __init cps_pm_init(void)
pr_warn("pm-cps: no CPC, clock & power gating unavailable\n"); pr_warn("pm-cps: no CPC, clock & power gating unavailable\n");
} }
for_each_present_cpu(cpu) { return cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "AP_PM_CPS_CPU_ONLINE",
err = cps_gen_core_entries(cpu); cps_pm_online_cpu, NULL);
if (err)
return err;
}
out:
return 0;
} }
arch_initcall(cps_pm_init); arch_initcall(cps_pm_init);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment