aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm64/kernel
diff options
context:
space:
mode:
authorSuzuki K. Poulose <suzuki.poulose@arm.com>2015-01-21 07:43:10 -0500
committerCatalin Marinas <catalin.marinas@arm.com>2015-01-23 12:11:30 -0500
commit736d474f0fafd1486f178570bc47660ee9dfdef8 (patch)
tree5d2980222088d482e73ec8047cbca23d7695ec85 /arch/arm64/kernel
parent04597a65c5efc207257a736d339c6f2f5b00250f (diff)
arm64: Consolidate hotplug notifier for instruction emulation
As of now each insn_emulation has a cpu hotplug notifier that enables/disables the CPU feature bit for the functionality. This patch re-arranges the code, such that there is only one notifier that runs through the list of registered emulation hooks and runs their corresponding set_hw_mode. We do nothing when a CPU is dying as we will set the appropriate bits as it comes back online based on the state of the hooks. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Punit Agrawal <punit.agrawal@arm.com> [catalin.marinas@arm.com: fix pr_warn compilation error] [catalin.marinas@arm.com: remove unnecessary "insn" check] Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64/kernel')
-rw-r--r--arch/arm64/kernel/armv8_deprecated.c125
1 files changed, 77 insertions, 48 deletions
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index c363671d7509..68b955e1fd99 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -19,6 +19,7 @@
19#include <asm/system_misc.h> 19#include <asm/system_misc.h>
20#include <asm/traps.h> 20#include <asm/traps.h>
21#include <asm/uaccess.h> 21#include <asm/uaccess.h>
22#include <asm/cpufeature.h>
22 23
23#define CREATE_TRACE_POINTS 24#define CREATE_TRACE_POINTS
24#include "trace-events-emulation.h" 25#include "trace-events-emulation.h"
@@ -85,6 +86,57 @@ static void remove_emulation_hooks(struct insn_emulation_ops *ops)
85 pr_notice("Removed %s emulation handler\n", ops->name); 86 pr_notice("Removed %s emulation handler\n", ops->name);
86} 87}
87 88
89static void enable_insn_hw_mode(void *data)
90{
91 struct insn_emulation *insn = (struct insn_emulation *)data;
92 if (insn->ops->set_hw_mode)
93 insn->ops->set_hw_mode(true);
94}
95
96static void disable_insn_hw_mode(void *data)
97{
98 struct insn_emulation *insn = (struct insn_emulation *)data;
99 if (insn->ops->set_hw_mode)
100 insn->ops->set_hw_mode(false);
101}
102
103/* Run set_hw_mode(mode) on all active CPUs */
104static int run_all_cpu_set_hw_mode(struct insn_emulation *insn, bool enable)
105{
106 if (!insn->ops->set_hw_mode)
107 return -EINVAL;
108 if (enable)
109 on_each_cpu(enable_insn_hw_mode, (void *)insn, true);
110 else
111 on_each_cpu(disable_insn_hw_mode, (void *)insn, true);
112 return 0;
113}
114
115/*
116 * Run set_hw_mode for all insns on a starting CPU.
117 * Returns:
118 * 0 - If all the hooks ran successfully.
119 * -EINVAL - At least one hook is not supported by the CPU.
120 */
121static int run_all_insn_set_hw_mode(unsigned long cpu)
122{
123 int rc = 0;
124 unsigned long flags;
125 struct insn_emulation *insn;
126
127 raw_spin_lock_irqsave(&insn_emulation_lock, flags);
128 list_for_each_entry(insn, &insn_emulation, node) {
129 bool enable = (insn->current_mode == INSN_HW);
130 if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(enable)) {
131 pr_warn("CPU[%ld] cannot support the emulation of %s",
132 cpu, insn->ops->name);
133 rc = -EINVAL;
134 }
135 }
136 raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
137 return rc;
138}
139
88static int update_insn_emulation_mode(struct insn_emulation *insn, 140static int update_insn_emulation_mode(struct insn_emulation *insn,
89 enum insn_emulation_mode prev) 141 enum insn_emulation_mode prev)
90{ 142{
@@ -97,10 +149,8 @@ static int update_insn_emulation_mode(struct insn_emulation *insn,
97 remove_emulation_hooks(insn->ops); 149 remove_emulation_hooks(insn->ops);
98 break; 150 break;
99 case INSN_HW: 151 case INSN_HW:
100 if (insn->ops->set_hw_mode) { 152 if (!run_all_cpu_set_hw_mode(insn, false))
101 insn->ops->set_hw_mode(false);
102 pr_notice("Disabled %s support\n", insn->ops->name); 153 pr_notice("Disabled %s support\n", insn->ops->name);
103 }
104 break; 154 break;
105 } 155 }
106 156
@@ -111,10 +161,9 @@ static int update_insn_emulation_mode(struct insn_emulation *insn,
111 register_emulation_hooks(insn->ops); 161 register_emulation_hooks(insn->ops);
112 break; 162 break;
113 case INSN_HW: 163 case INSN_HW:
114 if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(true)) 164 ret = run_all_cpu_set_hw_mode(insn, true);
165 if (!ret)
115 pr_notice("Enabled %s support\n", insn->ops->name); 166 pr_notice("Enabled %s support\n", insn->ops->name);
116 else
117 ret = -EINVAL;
118 break; 167 break;
119 } 168 }
120 169
@@ -133,6 +182,8 @@ static void register_insn_emulation(struct insn_emulation_ops *ops)
133 switch (ops->status) { 182 switch (ops->status) {
134 case INSN_DEPRECATED: 183 case INSN_DEPRECATED:
135 insn->current_mode = INSN_EMULATE; 184 insn->current_mode = INSN_EMULATE;
185 /* Disable the HW mode if it was turned on at early boot time */
186 run_all_cpu_set_hw_mode(insn, false);
136 insn->max = INSN_HW; 187 insn->max = INSN_HW;
137 break; 188 break;
138 case INSN_OBSOLETE: 189 case INSN_OBSOLETE:
@@ -453,8 +504,6 @@ ret:
453 return 0; 504 return 0;
454} 505}
455 506
456#define SCTLR_EL1_CP15BEN (1 << 5)
457
458static inline void config_sctlr_el1(u32 clear, u32 set) 507static inline void config_sctlr_el1(u32 clear, u32 set)
459{ 508{
460 u32 val; 509 u32 val;
@@ -465,48 +514,13 @@ static inline void config_sctlr_el1(u32 clear, u32 set)
465 asm volatile("msr sctlr_el1, %0" : : "r" (val)); 514 asm volatile("msr sctlr_el1, %0" : : "r" (val));
466} 515}
467 516
468static void enable_cp15_ben(void *info)
469{
470 config_sctlr_el1(0, SCTLR_EL1_CP15BEN);
471}
472
473static void disable_cp15_ben(void *info)
474{
475 config_sctlr_el1(SCTLR_EL1_CP15BEN, 0);
476}
477
478static int cpu_hotplug_notify(struct notifier_block *b,
479 unsigned long action, void *hcpu)
480{
481 switch (action) {
482 case CPU_STARTING:
483 case CPU_STARTING_FROZEN:
484 enable_cp15_ben(NULL);
485 return NOTIFY_DONE;
486 case CPU_DYING:
487 case CPU_DYING_FROZEN:
488 disable_cp15_ben(NULL);
489 return NOTIFY_DONE;
490 }
491
492 return NOTIFY_OK;
493}
494
495static struct notifier_block cpu_hotplug_notifier = {
496 .notifier_call = cpu_hotplug_notify,
497};
498
499static int cp15_barrier_set_hw_mode(bool enable) 517static int cp15_barrier_set_hw_mode(bool enable)
500{ 518{
501 if (enable) { 519 if (enable)
502 register_cpu_notifier(&cpu_hotplug_notifier); 520 config_sctlr_el1(0, SCTLR_EL1_CP15BEN);
503 on_each_cpu(enable_cp15_ben, NULL, true); 521 else
504 } else { 522 config_sctlr_el1(SCTLR_EL1_CP15BEN, 0);
505 unregister_cpu_notifier(&cpu_hotplug_notifier); 523 return 0;
506 on_each_cpu(disable_cp15_ben, NULL, true);
507 }
508
509 return true;
510} 524}
511 525
512static struct undef_hook cp15_barrier_hooks[] = { 526static struct undef_hook cp15_barrier_hooks[] = {
@@ -534,6 +548,20 @@ static struct insn_emulation_ops cp15_barrier_ops = {
534 .set_hw_mode = cp15_barrier_set_hw_mode, 548 .set_hw_mode = cp15_barrier_set_hw_mode,
535}; 549};
536 550
551static int insn_cpu_hotplug_notify(struct notifier_block *b,
552 unsigned long action, void *hcpu)
553{
554 int rc = 0;
555 if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
556 rc = run_all_insn_set_hw_mode((unsigned long)hcpu);
557
558 return notifier_from_errno(rc);
559}
560
561static struct notifier_block insn_cpu_hotplug_notifier = {
562 .notifier_call = insn_cpu_hotplug_notify,
563};
564
537/* 565/*
538 * Invoked as late_initcall, since not needed before init spawned. 566 * Invoked as late_initcall, since not needed before init spawned.
539 */ 567 */
@@ -545,6 +573,7 @@ static int __init armv8_deprecated_init(void)
545 if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION)) 573 if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
546 register_insn_emulation(&cp15_barrier_ops); 574 register_insn_emulation(&cp15_barrier_ops);
547 575
576 register_cpu_notifier(&insn_cpu_hotplug_notifier);
548 register_insn_emulation_sysctl(ctl_abi); 577 register_insn_emulation_sysctl(ctl_abi);
549 578
550 return 0; 579 return 0;