RISC-V: Use atomic_cmpxchg to update PLIC bitmaps

The PLIC previously used a mutex to protect against concurrent
access to the claimed and pending bitfields. Instead of using
a mutex, we update the bitfields using atomic_cmpxchg.

Rename sifive_plic_num_irqs_pending to sifive_plic_irqs_pending
and add an early out if any interrupts are pending as the
count of pending interrupts is not used.

Cc: Sagar Karandikar <sagark@eecs.berkeley.edu>
Cc: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
Cc: Palmer Dabbelt <palmer@sifive.com>
Cc: Alistair Francis <Alistair.Francis@wdc.com>
Signed-off-by: Michael Clark <mjc@sifive.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Michael Clark 2018-04-10 20:02:46 +12:00 committed by Alistair Francis
parent c3b03e5800
commit d78940ec5d
2 changed files with 22 additions and 28 deletions

View File

@ -81,36 +81,32 @@ static void sifive_plic_print_state(SiFivePLICState *plic)
} }
} }
static static uint32_t atomic_set_masked(uint32_t *a, uint32_t mask, uint32_t value)
void sifive_plic_set_pending(SiFivePLICState *plic, int irq, bool pending)
{ {
qemu_mutex_lock(&plic->lock); uint32_t old, new, cmp = atomic_read(a);
uint32_t word = irq >> 5;
if (pending) { do {
plic->pending[word] |= (1 << (irq & 31)); old = cmp;
} else { new = (old & ~mask) | (value & mask);
plic->pending[word] &= ~(1 << (irq & 31)); cmp = atomic_cmpxchg(a, old, new);
} } while (old != cmp);
qemu_mutex_unlock(&plic->lock);
return old;
} }
static static void sifive_plic_set_pending(SiFivePLICState *plic, int irq, bool level)
void sifive_plic_set_claimed(SiFivePLICState *plic, int irq, bool claimed)
{ {
qemu_mutex_lock(&plic->lock); atomic_set_masked(&plic->pending[irq >> 5], 1 << (irq & 31), -!!level);
uint32_t word = irq >> 5;
if (claimed) {
plic->claimed[word] |= (1 << (irq & 31));
} else {
plic->claimed[word] &= ~(1 << (irq & 31));
}
qemu_mutex_unlock(&plic->lock);
} }
static static void sifive_plic_set_claimed(SiFivePLICState *plic, int irq, bool level)
int sifive_plic_num_irqs_pending(SiFivePLICState *plic, uint32_t addrid)
{ {
int i, j, count = 0; atomic_set_masked(&plic->claimed[irq >> 5], 1 << (irq & 31), -!!level);
}
static int sifive_plic_irqs_pending(SiFivePLICState *plic, uint32_t addrid)
{
int i, j;
for (i = 0; i < plic->bitfield_words; i++) { for (i = 0; i < plic->bitfield_words; i++) {
uint32_t pending_enabled_not_claimed = uint32_t pending_enabled_not_claimed =
(plic->pending[i] & ~plic->claimed[i]) & (plic->pending[i] & ~plic->claimed[i]) &
@ -123,11 +119,11 @@ int sifive_plic_num_irqs_pending(SiFivePLICState *plic, uint32_t addrid)
uint32_t prio = plic->source_priority[irq]; uint32_t prio = plic->source_priority[irq];
int enabled = pending_enabled_not_claimed & (1 << j); int enabled = pending_enabled_not_claimed & (1 << j);
if (enabled && prio > plic->target_priority[addrid]) { if (enabled && prio > plic->target_priority[addrid]) {
count++; return 1;
} }
} }
} }
return count; return 0;
} }
static void sifive_plic_update(SiFivePLICState *plic) static void sifive_plic_update(SiFivePLICState *plic)
@ -143,7 +139,7 @@ static void sifive_plic_update(SiFivePLICState *plic)
if (!env) { if (!env) {
continue; continue;
} }
int level = sifive_plic_num_irqs_pending(plic, addrid) > 0; int level = sifive_plic_irqs_pending(plic, addrid);
switch (mode) { switch (mode) {
case PLICMode_M: case PLICMode_M:
riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_MEIP, level); riscv_set_local_interrupt(RISCV_CPU(cpu), MIP_MEIP, level);
@ -439,7 +435,6 @@ static void sifive_plic_realize(DeviceState *dev, Error **errp)
memory_region_init_io(&plic->mmio, OBJECT(dev), &sifive_plic_ops, plic, memory_region_init_io(&plic->mmio, OBJECT(dev), &sifive_plic_ops, plic,
TYPE_SIFIVE_PLIC, plic->aperture_size); TYPE_SIFIVE_PLIC, plic->aperture_size);
parse_hart_config(plic); parse_hart_config(plic);
qemu_mutex_init(&plic->lock);
plic->bitfield_words = (plic->num_sources + 31) >> 5; plic->bitfield_words = (plic->num_sources + 31) >> 5;
plic->source_priority = g_new0(uint32_t, plic->num_sources); plic->source_priority = g_new0(uint32_t, plic->num_sources);
plic->target_priority = g_new(uint32_t, plic->num_addrs); plic->target_priority = g_new(uint32_t, plic->num_addrs);

View File

@ -55,7 +55,6 @@ typedef struct SiFivePLICState {
uint32_t *pending; uint32_t *pending;
uint32_t *claimed; uint32_t *claimed;
uint32_t *enable; uint32_t *enable;
QemuMutex lock;
/* config */ /* config */
char *hart_config; char *hart_config;