summaryrefslogtreecommitdiff
path: root/arch/csky/kernel/smp.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/csky/kernel/smp.c')
-rw-r--r--arch/csky/kernel/smp.c100
1 files changed, 69 insertions, 31 deletions
diff --git a/arch/csky/kernel/smp.c b/arch/csky/kernel/smp.c
index b753d382e4ce..92dbbf3e0205 100644
--- a/arch/csky/kernel/smp.c
+++ b/arch/csky/kernel/smp.c
@@ -12,8 +12,10 @@
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/irq.h>
+#include <linux/irq_work.h>
#include <linux/irqdomain.h>
#include <linux/of.h>
+#include <linux/seq_file.h>
#include <linux/sched/task_stack.h>
#include <linux/sched/mm.h>
#include <linux/sched/hotplug.h>
@@ -21,22 +23,28 @@
#include <asm/traps.h>
#include <asm/sections.h>
#include <asm/mmu_context.h>
-#include <asm/pgalloc.h>
-
-struct ipi_data_struct {
- unsigned long bits ____cacheline_aligned;
-};
-static DEFINE_PER_CPU(struct ipi_data_struct, ipi_data);
+#ifdef CONFIG_CPU_HAS_FPU
+#include <abi/fpu.h>
+#endif
enum ipi_message_type {
IPI_EMPTY,
IPI_RESCHEDULE,
IPI_CALL_FUNC,
+ IPI_IRQ_WORK,
IPI_MAX
};
+struct ipi_data_struct {
+ unsigned long bits ____cacheline_aligned;
+ unsigned long stats[IPI_MAX] ____cacheline_aligned;
+};
+static DEFINE_PER_CPU(struct ipi_data_struct, ipi_data);
+
static irqreturn_t handle_ipi(int irq, void *dev)
{
+ unsigned long *stats = this_cpu_ptr(&ipi_data)->stats;
+
while (true) {
unsigned long ops;
@@ -44,11 +52,20 @@ static irqreturn_t handle_ipi(int irq, void *dev)
if (ops == 0)
return IRQ_HANDLED;
- if (ops & (1 << IPI_RESCHEDULE))
+ if (ops & (1 << IPI_RESCHEDULE)) {
+ stats[IPI_RESCHEDULE]++;
scheduler_ipi();
+ }
- if (ops & (1 << IPI_CALL_FUNC))
+ if (ops & (1 << IPI_CALL_FUNC)) {
+ stats[IPI_CALL_FUNC]++;
generic_smp_call_function_interrupt();
+ }
+
+ if (ops & (1 << IPI_IRQ_WORK)) {
+ stats[IPI_IRQ_WORK]++;
+ irq_work_run();
+ }
BUG_ON((ops >> IPI_MAX) != 0);
}
@@ -80,6 +97,29 @@ send_ipi_message(const struct cpumask *to_whom, enum ipi_message_type operation)
send_arch_ipi(to_whom);
}
+static const char * const ipi_names[] = {
+ [IPI_EMPTY] = "Empty interrupts",
+ [IPI_RESCHEDULE] = "Rescheduling interrupts",
+ [IPI_CALL_FUNC] = "Function call interrupts",
+ [IPI_IRQ_WORK] = "Irq work interrupts",
+};
+
+int arch_show_interrupts(struct seq_file *p, int prec)
+{
+ unsigned int cpu, i;
+
+ for (i = 0; i < IPI_MAX; i++) {
+ seq_printf(p, "%*s%u:%s", prec - 1, "IPI", i,
+ prec >= 4 ? " " : "");
+ for_each_online_cpu(cpu)
+ seq_printf(p, "%10lu ",
+ per_cpu_ptr(&ipi_data, cpu)->stats[i]);
+ seq_printf(p, " %s\n", ipi_names[i]);
+ }
+
+ return 0;
+}
+
void arch_send_call_function_ipi_mask(struct cpumask *mask)
{
send_ipi_message(mask, IPI_CALL_FUNC);
@@ -100,14 +140,17 @@ void smp_send_stop(void)
on_each_cpu(ipi_stop, NULL, 1);
}
-void smp_send_reschedule(int cpu)
+void arch_smp_send_reschedule(int cpu)
{
send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
}
-void __init smp_prepare_boot_cpu(void)
+#ifdef CONFIG_IRQ_WORK
+void arch_irq_work_raise(void)
{
+ send_ipi_message(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
}
+#endif
void __init smp_prepare_cpus(unsigned int max_cpus)
{
@@ -120,7 +163,7 @@ void __init setup_smp_ipi(void)
int rc;
if (ipi_irq == 0)
- panic("%s IRQ mapping failed\n", __func__);
+ return;
rc = request_percpu_irq(ipi_irq, handle_ipi, "IPI Interrupt",
&ipi_dummy_dev);
@@ -133,15 +176,13 @@ void __init setup_smp_ipi(void)
void __init setup_smp(void)
{
struct device_node *node = NULL;
- int cpu;
+ unsigned int cpu;
for_each_of_cpu_node(node) {
if (!of_device_is_available(node))
continue;
- if (of_property_read_u32(node, "reg", &cpu))
- continue;
-
+ cpu = of_get_cpu_hwid(node, 0);
if (cpu >= NR_CPUS)
continue;
@@ -153,8 +194,11 @@ void __init setup_smp(void)
extern void _start_smp_secondary(void);
volatile unsigned int secondary_hint;
+volatile unsigned int secondary_hint2;
volatile unsigned int secondary_ccr;
volatile unsigned int secondary_stack;
+volatile unsigned int secondary_msa1;
+volatile unsigned int secondary_pgd;
int __cpu_up(unsigned int cpu, struct task_struct *tidle)
{
@@ -163,7 +207,10 @@ int __cpu_up(unsigned int cpu, struct task_struct *tidle)
secondary_stack =
(unsigned int) task_stack_page(tidle) + THREAD_SIZE - 8;
secondary_hint = mfcr("cr31");
+ secondary_hint2 = mfcr("cr<21, 1>");
secondary_ccr = mfcr("cr18");
+ secondary_msa1 = read_mmu_msa1();
+ secondary_pgd = mfcr("cr<29, 15>");
/*
* Because other CPUs are in reset status, we must flush data
@@ -192,25 +239,19 @@ void __init smp_cpus_done(unsigned int max_cpus)
{
}
-int setup_profiling_timer(unsigned int multiplier)
-{
- return -EINVAL;
-}
-
void csky_start_secondary(void)
{
struct mm_struct *mm = &init_mm;
unsigned int cpu = smp_processor_id();
mtcr("cr31", secondary_hint);
+ mtcr("cr<21, 1>", secondary_hint2);
mtcr("cr18", secondary_ccr);
mtcr("vbr", vec_base);
flush_tlb_all();
write_mmu_pagemask(0);
- TLBMISS_HANDLER_SETUP_PGD(swapper_pg_dir);
- TLBMISS_HANDLER_SETUP_PGD_KERNEL(swapper_pg_dir);
#ifdef CONFIG_CPU_HAS_FPU
init_fpu();
@@ -229,7 +270,6 @@ void csky_start_secondary(void)
pr_info("CPU%u Online: %s...\n", cpu, __func__);
local_irq_enable();
- preempt_disable();
cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
}
@@ -247,25 +287,21 @@ int __cpu_disable(void)
return 0;
}
-void __cpu_die(unsigned int cpu)
+void arch_cpuhp_cleanup_dead_cpu(unsigned int cpu)
{
- if (!cpu_wait_death(cpu, 5)) {
- pr_crit("CPU%u: shutdown failed\n", cpu);
- return;
- }
pr_notice("CPU%u: shutdown\n", cpu);
}
-void arch_cpu_idle_dead(void)
+void __noreturn arch_cpu_idle_dead(void)
{
idle_task_exit();
- cpu_report_death();
+ cpuhp_ap_report_dead();
while (!secondary_stack)
arch_cpu_idle();
- local_irq_disable();
+ raw_local_irq_disable();
asm volatile(
"mov sp, %0\n"
@@ -273,5 +309,7 @@ void arch_cpu_idle_dead(void)
"jmpi csky_start_secondary"
:
: "r" (secondary_stack));
+
+ BUG();
}
#endif