Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 55dd23ec authored by Daniel Hellstrom's avatar Daniel Hellstrom Committed by David S. Miller
Browse files

sparc32, sun4d: Implemented SMP IPIs support for SUN4D machines



The sun4d does not seem to have a distingstion between soft and hard
IRQs. When generating IPIs the generated IRQ looks like a hard IRQ,
this patch adds a "IPI check" in the sun4d irq trap handler at a
predefined IRQ number (SUN4D_IPI_IRQ). Before generating an IPI
a per-cpu memory structure is modified for the "IPI check" to
successfully detect a IPI request to a specific processor, the check
clears the IPI work requested.

All three IPIs (resched, single and cpu-mask) use the same IRQ
number.

The IPI IRQ should preferrably be on a separate IRQ and definitly
not shared with IRQ handlers requesting IRQ with IRQF_SHARED.

Signed-off-by: default avatarDaniel Hellstrom <daniel@gaisler.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ecbc42b7
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -86,4 +86,10 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int)
#define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level)
#define set_cpu_int(cpu,level) BTFIXUP_CALL(set_cpu_int)(cpu,level)
#define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level)
#define clear_cpu_int(cpu,level) BTFIXUP_CALL(clear_cpu_int)(cpu,level)
#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)

/* All SUN4D IPIs are sent on this IRQ, may be shared with hard IRQs */
#define SUN4D_IPI_IRQ 14

extern void sun4d_ipi_interrupt(void);

#endif
#endif
+9 −0
Original line number Original line Diff line number Diff line
@@ -156,6 +156,15 @@ void sun4d_handler_irq(int pil, struct pt_regs *regs)


	cc_set_iclr(1 << pil);
	cc_set_iclr(1 << pil);


#ifdef CONFIG_SMP
	/*
	 * Check IPI data structures after IRQ has been cleared. Hard and Soft
	 * IRQ can happen at the same time, so both cases are always handled.
	 */
	if (pil == SUN4D_IPI_IRQ)
		sun4d_ipi_interrupt();
#endif

	old_regs = set_irq_regs(regs);
	old_regs = set_irq_regs(regs);
	irq_enter();
	irq_enter();
	if (sbusl == 0) {
	if (sbusl == 0) {
+79 −0
Original line number Original line Diff line number Diff line
@@ -32,6 +32,7 @@ static inline unsigned long sun4d_swap(volatile unsigned long *ptr, unsigned lon
	return val;
	return val;
}
}


static void smp4d_ipi_init(void);
static void smp_setup_percpu_timer(void);
static void smp_setup_percpu_timer(void);


static unsigned char cpu_leds[32];
static unsigned char cpu_leds[32];
@@ -118,6 +119,7 @@ void __cpuinit smp4d_callin(void)
 */
 */
void __init smp4d_boot_cpus(void)
void __init smp4d_boot_cpus(void)
{
{
	smp4d_ipi_init();
	if (boot_cpu_id)
	if (boot_cpu_id)
		current_set[0] = NULL;
		current_set[0] = NULL;
	smp_setup_percpu_timer();
	smp_setup_percpu_timer();
@@ -189,6 +191,80 @@ void __init smp4d_smp_done(void)
	sun4d_distribute_irqs();
	sun4d_distribute_irqs();
}
}


/* Memory structure giving interrupt handler information about IPI generated */
struct sun4d_ipi_work {
	int single;
	int msk;
	int resched;
};

static DEFINE_PER_CPU_SHARED_ALIGNED(struct sun4d_ipi_work, sun4d_ipi_work);

/* Initialize IPIs on the SUN4D SMP machine */
static void __init smp4d_ipi_init(void)
{
	int cpu;
	struct sun4d_ipi_work *work;

	printk(KERN_INFO "smp4d: setup IPI at IRQ %d\n", SUN4D_IPI_IRQ);

	for_each_possible_cpu(cpu) {
		work = &per_cpu(sun4d_ipi_work, cpu);
		work->single = work->msk = work->resched = 0;
	}
}

void sun4d_ipi_interrupt(void)
{
	struct sun4d_ipi_work *work = &__get_cpu_var(sun4d_ipi_work);

	if (work->single) {
		work->single = 0;
		smp_call_function_single_interrupt();
	}
	if (work->msk) {
		work->msk = 0;
		smp_call_function_interrupt();
	}
	if (work->resched) {
		work->resched = 0;
		smp_resched_interrupt();
	}
}

static void smp4d_ipi_single(int cpu)
{
	struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu);

	/* Mark work */
	work->single = 1;

	/* Generate IRQ on the CPU */
	sun4d_send_ipi(cpu, SUN4D_IPI_IRQ);
}

static void smp4d_ipi_mask_one(int cpu)
{
	struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu);

	/* Mark work */
	work->msk = 1;

	/* Generate IRQ on the CPU */
	sun4d_send_ipi(cpu, SUN4D_IPI_IRQ);
}

static void smp4d_ipi_resched(int cpu)
{
	struct sun4d_ipi_work *work = &per_cpu(sun4d_ipi_work, cpu);

	/* Mark work */
	work->resched = 1;

	/* Generate IRQ on the CPU (any IRQ will cause resched) */
	sun4d_send_ipi(cpu, SUN4D_IPI_IRQ);
}

static struct smp_funcall {
static struct smp_funcall {
	smpfunc_t func;
	smpfunc_t func;
	unsigned long arg1;
	unsigned long arg1;
@@ -354,6 +430,9 @@ void __init sun4d_init_smp(void)
	BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current);
	BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current);
	BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM);
	BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM);
	BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM);
	BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM);
	BTFIXUPSET_CALL(smp_ipi_resched, smp4d_ipi_resched, BTFIXUPCALL_NORM);
	BTFIXUPSET_CALL(smp_ipi_single, smp4d_ipi_single, BTFIXUPCALL_NORM);
	BTFIXUPSET_CALL(smp_ipi_mask_one, smp4d_ipi_mask_one, BTFIXUPCALL_NORM);


	for (i = 0; i < NR_CPUS; i++) {
	for (i = 0; i < NR_CPUS; i++) {
		ccall_info.processors_in[i] = 1;
		ccall_info.processors_in[i] = 1;