static DEFINE_SPINLOCK(dist_lock);
/* The GIC interface numbering does not necessarily match the logical map */
-static u8 target_cpu_map[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+u8 target_cpu_map[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
/* Check that the targeted interface belongs to the cell */
bool gic_targets_in_cell(struct cell *cell, u8 targets)
irqchip_eoi_irq(irq_id, handled);
}
}
-
-void gic_target_spis(struct cell *config_cell, struct cell *dest_cell)
-{
- unsigned int i, first_cpu, cpu_itf;
- unsigned int shift = 0;
- void *itargetsr = gicd_base + GICD_ITARGETSR;
- u32 targets;
- u32 mask = 0;
- u32 bits = 0;
-
- /* Always route to the first logical CPU on reset */
- for_each_cpu(first_cpu, dest_cell->cpu_set)
- break;
-
- cpu_itf = target_cpu_map[first_cpu];
-
- /* ITARGETSR0-7 contain the PPIs and SGIs, and are read-only. */
- itargetsr += 4 * 8;
-
- for (i = 0; i < 64; i++, shift = (shift + 8) % 32) {
- if (irqchip_irq_in_cell(config_cell, 32 + i)) {
- mask |= (0xff << shift);
- bits |= (cpu_itf << shift);
- }
-
- /* ITARGETRs have 4 IRQ per register */
- if ((i + 1) % 4 == 0) {
- targets = mmio_read32(itargetsr);
- targets &= ~mask;
- targets |= bits;
- mmio_write32(itargetsr, targets);
- itargetsr += 4;
- mask = 0;
- bits = 0;
- }
- }
-}
{
int err;
- /*
- * target_cpu_map has not been populated by all available CPUs when the
- * setup code initialises the root cell. It is assumed that the kernel
- * already has configured all its SPIs anyway, and that it will redirect
- * them when unplugging a CPU.
- */
- if (cell != &root_cell)
- gic_target_spis(cell, cell);
-
/*
* Let the guest access the virtual CPU interface instead of the
* physical one.
PAGING_NON_COHERENT);
}
+static void gic_adjust_irq_target(struct cell *cell, u16 irq_id)
+{
+ void *itargetsr = gicd_base + GICD_ITARGETSR + (irq_id & ~0x3);
+ u32 targets = mmio_read32(itargetsr);
+ unsigned int shift = irq_id % 4;
+
+ if (gic_targets_in_cell(cell, (u8)(targets >> shift)))
+ return;
+
+ targets &= ~(0xff << shift);
+ targets |= target_cpu_map[first_cpu(cell->cpu_set)] << shift;
+
+ mmio_write32(itargetsr, targets);
+}
+
static int gic_send_sgi(struct sgi *sgi)
{
u32 val;
.cpu_reset = gic_cpu_reset,
.cell_init = gic_cell_init,
.cell_exit = gic_cell_exit,
+ .adjust_irq_target = gic_adjust_irq_target,
.send_sgi = gic_send_sgi,
.handle_irq = gic_handle_irq,
return 0;
}
-static void gic_route_spis(struct cell *config_cell, struct cell *dest_cell)
+static void gic_adjust_irq_target(struct cell *cell, u16 irq_id)
{
- int i;
- void *irouter = gicd_base + GICD_IROUTER;
- unsigned int first_cpu;
-
- /* Use the core functions to retrieve the first physical id */
- for_each_cpu(first_cpu, dest_cell->cpu_set)
- break;
+ void *irouter = gicd_base + GICD_IROUTER + irq_id;
+ u32 route = mmio_read32(irouter);
- for (i = 0; i < 64; i++, irouter += 8)
- if (irqchip_irq_in_cell(config_cell, 32 + i))
- mmio_write64(irouter, first_cpu);
+ if (!cell_owns_cpu(cell, route))
+ mmio_write32(irouter, first_cpu(cell->cpu_set));
}
static enum mmio_result gic_handle_redist_access(void *arg,
static int gic_cell_init(struct cell *cell)
{
- gic_route_spis(cell, cell);
-
mmio_region_register(cell, (unsigned long)gicd_base, gicd_size,
gic_handle_dist_access, NULL);
mmio_region_register(cell, (unsigned long)gicr_base, gicr_size,
.cpu_init = gic_cpu_init,
.cpu_reset = gic_cpu_reset,
.cell_init = gic_cell_init,
+ .adjust_irq_target = gic_adjust_irq_target,
.send_sgi = gic_send_sgi,
.handle_irq = gic_handle_irq,
.inject_irq = gic_inject_irq,
#include <jailhouse/types.h>
#define GICD_CTLR 0x0000
+# define GICD_CTLR_ARE_NS (1 << 4)
#define GICD_TYPER 0x0004
#define GICD_IIDR 0x0008
#define GICD_IGROUPR 0x0080
struct per_cpu;
struct sgi;
+extern u8 target_cpu_map[];
+
int gic_probe_cpu_id(unsigned int cpu);
enum mmio_result gic_handle_dist_access(void *arg, struct mmio_access *mmio);
enum mmio_result gic_handle_irq_route(struct mmio_access *mmio,
unsigned int irq);
void gic_handle_sgir_write(struct sgi *sgi, bool virt_input);
void gic_handle_irq(struct per_cpu *cpu_data);
-void gic_target_spis(struct cell *config_cell, struct cell *dest_cell);
bool gic_targets_in_cell(struct cell *cell, u8 targets);
#endif /* !__ASSEMBLY__ */
int (*cell_init)(struct cell *cell);
void (*cell_exit)(struct cell *cell);
int (*cpu_reset)(struct per_cpu *cpu_data, bool is_shutdown);
+ void (*adjust_irq_target)(struct cell *cell, u16 irq_id);
int (*send_sgi)(struct sgi *sgi);
void (*handle_irq)(struct per_cpu *cpu_data);
if (err)
return err;
- if (cell != &root_cell)
+ if (cell != &root_cell) {
for_each_irqchip(chip, cell->config, n) {
if (chip->address != (unsigned long)gicd_base)
continue;
~chip->pin_bitmap[pos];
}
+ for (n = 32; n < sizeof(cell->arch.irq_bitmap) * 8; n++) {
+ if (irqchip_irq_in_cell(cell, n))
+ irqchip.adjust_irq_target(cell, n);
+ if (irqchip_irq_in_cell(&root_cell, n))
+ irqchip.adjust_irq_target(&root_cell, n);
+ }
+ }
+
return 0;
}