Skip to content
Permalink
Browse files
RISC-V: Move to IPI domain APIs
DO NOT UPSTREAM !!!!!

Signed-off-by: Anup Patel <anup.patel@wdc.com>
  • Loading branch information
avpatel committed Jun 16, 2021
1 parent a83554d commit fc99da1943417514801d7a190ca8b1bf1be5bd13
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 81 deletions.
@@ -50,6 +50,7 @@ config RISCV
select GENERIC_EARLY_IOREMAP
select GENERIC_GETTIMEOFDAY if HAVE_GENERIC_VDSO
select GENERIC_IOREMAP
select GENERIC_IRQ_IPI
select GENERIC_IRQ_MULTI_HANDLER
select GENERIC_IRQ_SHOW
select GENERIC_LIB_DEVMEM_IS_ALLOWED
@@ -15,11 +15,6 @@
struct seq_file;
extern unsigned long boot_cpu_hartid;

struct riscv_ipi_ops {
void (*ipi_inject)(const struct cpumask *target);
void (*ipi_clear)(void);
};

#ifdef CONFIG_SMP
/*
* Mapping between linux logical cpu index and hartid.
@@ -33,9 +28,6 @@ void show_ipi_stats(struct seq_file *p, int prec);
/* SMP initialization hook for setup_arch */
void __init setup_smp(void);

/* Called from C code, this handles an IPI. */
void handle_IPI(struct pt_regs *regs);

/* Hook for the generic smp_call_function_many() routine. */
void arch_send_call_function_ipi_mask(struct cpumask *mask);

@@ -45,11 +37,17 @@ void arch_send_call_function_single_ipi(int cpu);
int riscv_hartid_to_cpuid(int hartid);
void riscv_cpuid_to_hartid_mask(const struct cpumask *in, struct cpumask *out);

/* Set custom IPI operations */
void riscv_set_ipi_ops(const struct riscv_ipi_ops *ops);
/* Enable IPI for CPU hotplug */
void riscv_ipi_enable(void);

/* Disable IPI for CPU hotplug */
void riscv_ipi_disable(void);

/* Setup IPI for boot CPU */
void riscv_ipi_setup(void);

/* Clear IPI for current CPU */
void riscv_clear_ipi(void);
/* Set the IPI interrupt number for arch (called by irqchip drivers) */
void riscv_ipi_set_virq(int virq);

/* Secondary hart entry */
asmlinkage void smp_callin(void);
@@ -92,11 +90,11 @@ static inline void riscv_cpuid_to_hartid_mask(const struct cpumask *in,
cpumask_set_cpu(boot_cpu_hartid, out);
}

static inline void riscv_set_ipi_ops(const struct riscv_ipi_ops *ops)
void riscv_ipi_setup(void)
{
}

static inline void riscv_clear_ipi(void)
static inline void riscv_ipi_set_virq(int virq)
{
}

@@ -13,6 +13,7 @@
#include <asm/irq.h>
#include <asm/cpu_ops.h>
#include <asm/sbi.h>
#include <asm/smp.h>

void cpu_stop(void);
void arch_cpu_idle_dead(void)
@@ -47,6 +48,7 @@ int __cpu_disable(void)

remove_cpu_topology(cpu);
set_cpu_online(cpu, false);
riscv_ipi_disable();
irq_migrate_all_off_this_cpu();

return ret;
@@ -21,4 +21,5 @@ void __init init_IRQ(void)
irqchip_init();
if (!handle_arch_irq)
panic("No interrupt controller found.");
riscv_ipi_setup();
}
@@ -8,6 +8,7 @@
#include <linux/init.h>
#include <linux/pm.h>
#include <linux/reboot.h>
#include <linux/irqchip/irq-riscv-intc.h>
#include <asm/sbi.h>
#include <asm/smp.h>

@@ -603,7 +604,7 @@ static void sbi_ipi_clear(void)
csr_clear(CSR_IP, IE_SIE);
}

static const struct riscv_ipi_ops sbi_ipi_ops = {
static const struct riscv_intc_ipi_ops sbi_ipi_ops = {
.ipi_inject = sbi_send_cpumask_ipi,
.ipi_clear = sbi_ipi_clear
};
@@ -655,5 +656,5 @@ void __init sbi_init(void)
__sbi_rfence = __sbi_rfence_v01;
}

riscv_set_ipi_ops(&sbi_ipi_ops);
riscv_intc_set_ipi_ops(&sbi_ipi_ops);
}
@@ -18,6 +18,7 @@
#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/irq_work.h>

#include <asm/sbi.h>
@@ -48,6 +49,9 @@ static struct {
unsigned long bits ____cacheline_aligned;
} ipi_data[NR_CPUS] __cacheline_aligned;

static int ipi_virq __ro_after_init;
static struct irq_desc *ipi_desc __ro_after_init;

int riscv_hartid_to_cpuid(int hartid)
{
int i;
@@ -88,21 +92,6 @@ static void ipi_stop(void)
wait_for_interrupt();
}

static const struct riscv_ipi_ops *ipi_ops __ro_after_init;

void riscv_set_ipi_ops(const struct riscv_ipi_ops *ops)
{
ipi_ops = ops;
}
EXPORT_SYMBOL_GPL(riscv_set_ipi_ops);

void riscv_clear_ipi(void)
{
if (ipi_ops && ipi_ops->ipi_clear)
ipi_ops->ipi_clear();
}
EXPORT_SYMBOL_GPL(riscv_clear_ipi);

static void send_ipi_mask(const struct cpumask *mask, enum ipi_message_type op)
{
int cpu;
@@ -112,10 +101,7 @@ static void send_ipi_mask(const struct cpumask *mask, enum ipi_message_type op)
set_bit(op, &ipi_data[cpu].bits);
smp_mb__after_atomic();

if (ipi_ops && ipi_ops->ipi_inject)
ipi_ops->ipi_inject(mask);
else
pr_warn("IPI inject method not available\n");
__ipi_send_mask(ipi_desc, mask);
}

static void send_ipi_single(int cpu, enum ipi_message_type op)
@@ -124,10 +110,7 @@ static void send_ipi_single(int cpu, enum ipi_message_type op)
set_bit(op, &ipi_data[cpu].bits);
smp_mb__after_atomic();

if (ipi_ops && ipi_ops->ipi_inject)
ipi_ops->ipi_inject(cpumask_of(cpu));
else
pr_warn("IPI inject method not available\n");
__ipi_send_mask(ipi_desc, cpumask_of(cpu));
}

#ifdef CONFIG_IRQ_WORK
@@ -137,16 +120,11 @@ void arch_irq_work_raise(void)
}
#endif

void handle_IPI(struct pt_regs *regs)
static irqreturn_t handle_IPI(int irq, void *data)
{
struct pt_regs *old_regs = set_irq_regs(regs);
unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
unsigned long *stats = ipi_data[smp_processor_id()].stats;

irq_enter();

riscv_clear_ipi();

while (true) {
unsigned long ops;

@@ -190,9 +168,43 @@ void handle_IPI(struct pt_regs *regs)
}

done:
irq_exit();
set_irq_regs(old_regs);
return IRQ_HANDLED;
}

void riscv_ipi_enable(void)
{
if (WARN_ON_ONCE(!ipi_virq))
return;

enable_percpu_irq(ipi_virq, 0);
}

void riscv_ipi_disable(void)
{
if (WARN_ON_ONCE(!ipi_virq))
return;

disable_percpu_irq(ipi_virq);
}

void riscv_ipi_setup(void)
{
int err;

err = request_percpu_irq(ipi_virq, handle_IPI, "IPI", NULL);
WARN_ON(err);

ipi_desc = irq_to_desc(ipi_virq);
irq_set_status_flags(ipi_virq, IRQ_HIDDEN);

riscv_ipi_enable();
}

void riscv_ipi_set_virq(int virq)
{
ipi_virq = virq;
}
EXPORT_SYMBOL_GPL(riscv_ipi_set_virq);

static const char * const ipi_names[] = {
[IPI_RESCHEDULE] = "Rescheduling interrupts",
@@ -159,12 +159,12 @@ asmlinkage __visible void smp_callin(void)
struct mm_struct *mm = &init_mm;
unsigned int curr_cpuid = smp_processor_id();

riscv_clear_ipi();

/* All kernel threads share the same mm context. */
mmgrab(mm);
current->active_mm = mm;

riscv_ipi_enable();

notify_cpu_starting(curr_cpuid);
numa_add_cpu(curr_cpuid);
update_siblings_masks(curr_cpuid);
@@ -16,6 +16,7 @@
#include <linux/of_address.h>
#include <linux/sched_clock.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/irqchip/irq-riscv-intc.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/smp.h>
@@ -54,7 +55,7 @@ static void clint_clear_ipi(void)
writel(0, clint_ipi_base + cpuid_to_hartid_map(smp_processor_id()));
}

static struct riscv_ipi_ops clint_ipi_ops = {
static struct riscv_intc_ipi_ops clint_ipi_ops = {
.ipi_inject = clint_send_ipi,
.ipi_clear = clint_clear_ipi,
};
@@ -228,7 +229,7 @@ static int __init clint_timer_init_dt(struct device_node *np)
goto fail_free_irq;
}

riscv_set_ipi_ops(&clint_ipi_ops);
riscv_intc_set_ipi_ops(&clint_ipi_ops);
clint_clear_ipi();

return 0;

0 comments on commit fc99da1

Please sign in to comment.