Skip to content

Commit

Permalink
arm, arm64: Factor out handle_irq_target irqchip callback
Browse files Browse the repository at this point in the history
As we run the GICv3 only in affinity mode, access to ITARGETSR can be
ignored, and the existing handle_irq_target can become GICv2-only.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
  • Loading branch information
jan-kiszka committed Dec 5, 2016
1 parent 6a98d45 commit faa98cc
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 75 deletions.
74 changes: 2 additions & 72 deletions hypervisor/arch/arm-common/gic-common.c
Expand Up @@ -24,7 +24,7 @@
#define REG_RANGE(base, n, size) \
(base) ... ((base) + (n - 1) * (size))

static DEFINE_SPINLOCK(dist_lock);
DEFINE_SPINLOCK(dist_lock);

/* The GICv2 interface numbering does not necessarily match the logical map */
u8 gicv2_target_cpu_map[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
Expand Down Expand Up @@ -103,76 +103,6 @@ restrict_bitmask_access(struct mmio_access *mmio, unsigned int reg_index,
return MMIO_HANDLED;
}

/*
* GICv2 uses 8bit values for each IRQ in the ITARGETRs registers
*/
static enum mmio_result handle_irq_target(struct mmio_access *mmio,
unsigned int irq)
{
/*
* ITARGETSR contain one byte per IRQ, so the first one affected by this
* access corresponds to the reg index
*/
unsigned int irq_base = irq & ~0x3;
struct cell *cell = this_cell();
unsigned int offset;
u32 access_mask = 0;
unsigned int n;
u8 targets;

/*
* Let the guest freely access its SGIs and PPIs, which may be used to
* fill its CPU interface map.
*/
if (!is_spi(irq)) {
mmio_perform_access(gicd_base, mmio);
return MMIO_HANDLED;
}

/*
* The registers are byte-accessible, but we always do word accesses.
*/
offset = irq % 4;
mmio->address &= ~0x3;
mmio->value <<= 8 * offset;
mmio->size = 4;

for (n = 0; n < 4; n++) {
if (irqchip_irq_in_cell(cell, irq_base + n))
access_mask |= 0xff << (8 * n);
else
continue;

if (!mmio->is_write)
continue;

targets = (mmio->value >> (8 * n)) & 0xff;

if (!gic_targets_in_cell(cell, targets)) {
printk("Attempt to route IRQ%d outside of cell\n",
irq_base + n);
return MMIO_ERROR;
}
}

if (mmio->is_write) {
spin_lock(&dist_lock);
u32 itargetsr =
mmio_read32(gicd_base + GICD_ITARGETSR + irq_base);
mmio->value &= access_mask;
/* Combine with external SPIs */
mmio->value |= (itargetsr & ~access_mask);
/* And do the access */
mmio_perform_access(gicd_base, mmio);
spin_unlock(&dist_lock);
} else {
mmio_perform_access(gicd_base, mmio);
mmio->value &= access_mask;
}

return MMIO_HANDLED;
}

static enum mmio_result handle_sgir_access(struct mmio_access *mmio)
{
struct sgi sgi;
Expand Down Expand Up @@ -269,7 +199,7 @@ enum mmio_result gic_handle_dist_access(void *arg, struct mmio_access *mmio)
break;

case REG_RANGE(GICD_ITARGETSR, 1024, 1):
ret = handle_irq_target(mmio, reg - GICD_ITARGETSR);
ret = irqchip.handle_irq_target(mmio, reg - GICD_ITARGETSR);
break;

case REG_RANGE(GICD_ICENABLER, 32, 4):
Expand Down
74 changes: 73 additions & 1 deletion hypervisor/arch/arm-common/gic-v2.c
Expand Up @@ -11,7 +11,7 @@
*/

#include <jailhouse/control.h>
#include <jailhouse/mmio.h>
#include <jailhouse/printk.h>
#include <asm/gic.h>
#include <asm/irqchip.h>
#include <asm/setup.h>
Expand Down Expand Up @@ -291,6 +291,76 @@ enum mmio_result gic_handle_irq_route(struct mmio_access *mmio,
return MMIO_HANDLED;
}

/*
* GICv2 uses 8bit values for each IRQ in the ITARGETSR registers
*/
static enum mmio_result gic_handle_irq_target(struct mmio_access *mmio,
unsigned int irq)
{
/*
* ITARGETSR contain one byte per IRQ, so the first one affected by this
* access corresponds to the reg index
*/
unsigned int irq_base = irq & ~0x3;
struct cell *cell = this_cell();
unsigned int offset;
u32 access_mask = 0;
unsigned int n;
u8 targets;

/*
* Let the guest freely access its SGIs and PPIs, which may be used to
* fill its CPU interface map.
*/
if (!is_spi(irq)) {
mmio_perform_access(gicd_base, mmio);
return MMIO_HANDLED;
}

/*
* The registers are byte-accessible, but we always do word accesses.
*/
offset = irq % 4;
mmio->address &= ~0x3;
mmio->value <<= 8 * offset;
mmio->size = 4;

for (n = 0; n < 4; n++) {
if (irqchip_irq_in_cell(cell, irq_base + n))
access_mask |= 0xff << (8 * n);
else
continue;

if (!mmio->is_write)
continue;

targets = (mmio->value >> (8 * n)) & 0xff;

if (!gic_targets_in_cell(cell, targets)) {
printk("Attempt to route IRQ%d outside of cell\n",
irq_base + n);
return MMIO_ERROR;
}
}

if (mmio->is_write) {
spin_lock(&dist_lock);
u32 itargetsr =
mmio_read32(gicd_base + GICD_ITARGETSR + irq_base);
mmio->value &= access_mask;
/* Combine with external SPIs */
mmio->value |= (itargetsr & ~access_mask);
/* And do the access */
mmio_perform_access(gicd_base, mmio);
spin_unlock(&dist_lock);
} else {
mmio_perform_access(gicd_base, mmio);
mmio->value &= access_mask;
}

return MMIO_HANDLED;
}

unsigned int irqchip_mmio_count_regions(struct cell *cell)
{
return 1;
Expand All @@ -309,4 +379,6 @@ struct irqchip_ops irqchip = {
.enable_maint_irq = gic_enable_maint_irq,
.has_pending_irqs = gic_has_pending_irqs,
.eoi_irq = gic_eoi_irq,

.handle_irq_target = gic_handle_irq_target,
};
3 changes: 3 additions & 0 deletions hypervisor/arch/arm-common/include/asm/gic.h
Expand Up @@ -47,9 +47,12 @@
#define is_spi(irqn) ((irqn) > 31 && (irqn) < 1020)

#ifndef __ASSEMBLY__
extern struct irqchip_ops irqchip;

extern u8 gicv2_target_cpu_map[8];

extern void *gicd_base;
extern spinlock_t dist_lock;

int gic_probe_cpu_id(unsigned int cpu);
enum mmio_result gic_handle_dist_access(void *arg, struct mmio_access *mmio);
Expand Down
3 changes: 3 additions & 0 deletions hypervisor/arch/arm-common/include/asm/irqchip.h
Expand Up @@ -52,6 +52,9 @@ struct irqchip_ops {
int (*inject_irq)(struct per_cpu *cpu_data, u16 irq_id);
void (*enable_maint_irq)(bool enable);
bool (*has_pending_irqs)(void);

enum mmio_result (*handle_irq_target)(struct mmio_access *mmio,
unsigned int irq);
};

unsigned int irqchip_mmio_count_regions(struct cell *cell);
Expand Down
2 changes: 0 additions & 2 deletions hypervisor/arch/arm-common/irqchip.c
Expand Up @@ -32,8 +32,6 @@
(counter) < (config)->num_irqchips; \
(chip)++, (counter)++)

extern struct irqchip_ops irqchip;

void *gicd_base;

/*
Expand Down
8 changes: 8 additions & 0 deletions hypervisor/arch/arm/gic-v3.c
Expand Up @@ -432,6 +432,13 @@ static bool gicv3_has_pending_irqs(void)
return false;
}

static enum mmio_result gicv3_handle_irq_target(struct mmio_access *mmio,
unsigned int irq)
{
/* ignore writes, we are in affinity routing mode */
return MMIO_HANDLED;
}

unsigned int irqchip_mmio_count_regions(struct cell *cell)
{
return 2;
Expand All @@ -448,4 +455,5 @@ struct irqchip_ops irqchip = {
.enable_maint_irq = gicv3_enable_maint_irq,
.has_pending_irqs = gicv3_has_pending_irqs,
.eoi_irq = gic_eoi_irq,
.handle_irq_target = gicv3_handle_irq_target,
};

0 comments on commit faa98cc

Please sign in to comment.