Commit ffe59ee3 authored by Huacai Chen's avatar Huacai Chen Committed by Paul Burton

MIPS: Loongson-3: Add CSR IPI support

CSR IPI and legacy MMIO use the same infrastructure, but CSR IPI is
faster than legacy MMIO IPI. This patch enable CSR IPI if possible
(except for MailBox, because CSR IPI is too complicated for MailBox).
Signed-off-by: default avatarHuacai Chen <chenhc@lemote.com>
Signed-off-by: default avatarPaul Burton <paul.burton@mips.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: James Hogan <jhogan@kernel.org>
Cc: linux-mips@linux-mips.org
Cc: linux-mips@vger.kernel.org
Cc: Fuxin Zhang <zhangfx@lemote.com>
Cc: Zhangjin Wu <wuzhangjin@gmail.com>
Cc: Huacai Chen <chenhuacai@gmail.com>
parent 7507445b
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <asm/tlbflush.h> #include <asm/tlbflush.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <loongson.h> #include <loongson.h>
#include <loongson_regs.h>
#include <workarounds.h> #include <workarounds.h>
#include "smp.h" #include "smp.h"
...@@ -48,6 +49,62 @@ static uint32_t core0_c0count[NR_CPUS]; ...@@ -48,6 +49,62 @@ static uint32_t core0_c0count[NR_CPUS];
__wbflush(); \ __wbflush(); \
} while (0) } while (0)
u32 (*ipi_read_clear)(int cpu);
void (*ipi_write_action)(int cpu, u32 action);
static u32 csr_ipi_read_clear(int cpu)
{
u32 action;
/* Load the ipi register to figure out what we're supposed to do */
action = csr_readl(LOONGSON_CSR_IPI_STATUS);
/* Clear the ipi register to clear the interrupt */
csr_writel(action, LOONGSON_CSR_IPI_CLEAR);
return action;
}
static void csr_ipi_write_action(int cpu, u32 action)
{
unsigned int irq = 0;
while ((irq = ffs(action))) {
uint32_t val = CSR_IPI_SEND_BLOCK;
val |= (irq - 1);
val |= (cpu << CSR_IPI_SEND_CPU_SHIFT);
csr_writel(val, LOONGSON_CSR_IPI_SEND);
action &= ~BIT(irq - 1);
}
}
static u32 legacy_ipi_read_clear(int cpu)
{
u32 action;
/* Load the ipi register to figure out what we're supposed to do */
action = loongson3_ipi_read32(ipi_status0_regs[cpu_logical_map(cpu)]);
/* Clear the ipi register to clear the interrupt */
loongson3_ipi_write32(action, ipi_clear0_regs[cpu_logical_map(cpu)]);
return action;
}
static void legacy_ipi_write_action(int cpu, u32 action)
{
loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu]);
}
static void csr_ipi_probe(void)
{
if (cpu_has_csr() && csr_readl(LOONGSON_CSR_FEATURES) & LOONGSON_CSRF_IPI) {
ipi_read_clear = csr_ipi_read_clear;
ipi_write_action = csr_ipi_write_action;
} else {
ipi_read_clear = legacy_ipi_read_clear;
ipi_write_action = legacy_ipi_write_action;
}
}
static void ipi_set0_regs_init(void) static void ipi_set0_regs_init(void)
{ {
ipi_set0_regs[0] = (void *) ipi_set0_regs[0] = (void *)
...@@ -233,7 +290,7 @@ static void ipi_mailbox_buf_init(void) ...@@ -233,7 +290,7 @@ static void ipi_mailbox_buf_init(void)
*/ */
static void loongson3_send_ipi_single(int cpu, unsigned int action) static void loongson3_send_ipi_single(int cpu, unsigned int action)
{ {
loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu_logical_map(cpu)]); ipi_write_action(cpu_logical_map(cpu), (u32)action);
} }
static void static void
...@@ -242,14 +299,14 @@ loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action) ...@@ -242,14 +299,14 @@ loongson3_send_ipi_mask(const struct cpumask *mask, unsigned int action)
unsigned int i; unsigned int i;
for_each_cpu(i, mask) for_each_cpu(i, mask)
loongson3_ipi_write32((u32)action, ipi_set0_regs[cpu_logical_map(i)]); ipi_write_action(cpu_logical_map(i), (u32)action);
} }
#define IPI_IRQ_OFFSET 6 #define IPI_IRQ_OFFSET 6
void loongson3_send_irq_by_ipi(int cpu, int irqs) void loongson3_send_irq_by_ipi(int cpu, int irqs)
{ {
loongson3_ipi_write32(irqs << IPI_IRQ_OFFSET, ipi_set0_regs[cpu_logical_map(cpu)]); ipi_write_action(cpu_logical_map(cpu), irqs << IPI_IRQ_OFFSET);
} }
void loongson3_ipi_interrupt(struct pt_regs *regs) void loongson3_ipi_interrupt(struct pt_regs *regs)
...@@ -257,13 +314,9 @@ void loongson3_ipi_interrupt(struct pt_regs *regs) ...@@ -257,13 +314,9 @@ void loongson3_ipi_interrupt(struct pt_regs *regs)
int i, cpu = smp_processor_id(); int i, cpu = smp_processor_id();
unsigned int action, c0count, irqs; unsigned int action, c0count, irqs;
/* Load the ipi register to figure out what we're supposed to do */ action = ipi_read_clear(cpu);
action = loongson3_ipi_read32(ipi_status0_regs[cpu_logical_map(cpu)]);
irqs = action >> IPI_IRQ_OFFSET; irqs = action >> IPI_IRQ_OFFSET;
/* Clear the ipi register to clear the interrupt */
loongson3_ipi_write32((u32)action, ipi_clear0_regs[cpu_logical_map(cpu)]);
if (action & SMP_RESCHEDULE_YOURSELF) if (action & SMP_RESCHEDULE_YOURSELF)
scheduler_ipi(); scheduler_ipi();
...@@ -372,6 +425,7 @@ static void __init loongson3_smp_setup(void) ...@@ -372,6 +425,7 @@ static void __init loongson3_smp_setup(void)
num++; num++;
} }
csr_ipi_probe();
ipi_set0_regs_init(); ipi_set0_regs_init();
ipi_clear0_regs_init(); ipi_clear0_regs_init();
ipi_status0_regs_init(); ipi_status0_regs_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