static void fpga_irq_unmask(struct vmm_host_irq *irq) { struct fpga_irq_data *f = vmm_host_irq_get_chip_data(irq); u32 mask = 1 << fpga_irq(irq); vmm_writel(mask, f->base + IRQ_ENABLE_SET); }
static void gic_eoi_irq(struct vmm_host_irq *d) { struct gic_chip_data *gic = vmm_host_irq_get_chip_data(d); gic_write(d->hwirq, gic->cpu_base + GICC_EOI); if (gic->eoimode && !vmm_host_irq_is_routed(d)) { gic_write(d->hwirq, gic->cpu2_base + GICC2_DIR); } }
static void gic_eoi_irq(struct vmm_host_irq *irq) { struct gic_chip_data *gic = vmm_host_irq_get_chip_data(irq); u32 irq_no = gic_irq(gic, irq); gic_write(irq_no, gic->cpu_base + GIC_CPU_EOI); if (gic->eoimode && !vmm_host_irq_is_routed(irq)) { gic_write(irq_no, gic->cpu2_base + GIC_CPU2_DIR); } }
static void gic_irq_set_routed_state(struct vmm_host_irq *d, u32 val, u32 mask) { struct gic_chip_data *gic = vmm_host_irq_get_chip_data(d); if (mask & VMM_ROUTED_IRQ_STATE_PENDING) gic_poke_irq(gic, d, (val & VMM_ROUTED_IRQ_STATE_PENDING) ? GICD_ENABLE_SET : GICD_ENABLE_CLEAR); if (mask & VMM_ROUTED_IRQ_STATE_ACTIVE) gic_poke_irq(gic, d, (val & VMM_ROUTED_IRQ_STATE_ACTIVE) ? GICD_ACTIVE_SET : GICD_ACTIVE_CLEAR); if (mask & VMM_ROUTED_IRQ_STATE_MASKED) gic_poke_irq(gic, d, (val & VMM_ROUTED_IRQ_STATE_MASKED) ? GICD_ENABLE_CLEAR : GICD_ENABLE_SET); }
static u32 gic_irq_get_routed_state(struct vmm_host_irq *d, u32 mask) { u32 val = 0; struct gic_chip_data *gic = vmm_host_irq_get_chip_data(d); if ((mask & VMM_ROUTED_IRQ_STATE_PENDING) && gic_peek_irq(gic, d, GICD_ENABLE_SET)) val |= VMM_ROUTED_IRQ_STATE_PENDING; if ((mask & VMM_ROUTED_IRQ_STATE_ACTIVE) && gic_peek_irq(gic, d, GICD_ACTIVE_SET)) val |= VMM_ROUTED_IRQ_STATE_ACTIVE; if ((mask & VMM_ROUTED_IRQ_STATE_MASKED) && !gic_peek_irq(gic, d, GICD_ENABLE_SET)) val |= VMM_ROUTED_IRQ_STATE_MASKED; return val; }
static int gic_set_type(struct vmm_host_irq *irq, u32 type) { struct gic_chip_data *gic = vmm_host_irq_get_chip_data(irq); virtual_addr_t base = gic->dist_base; u32 irq_no = gic_irq(gic, irq); u32 enablemask = 1 << (irq_no % 32); u32 enableoff = (irq_no / 32) * 4; u32 confmask = 0x2 << ((irq_no % 16) * 2); u32 confoff = (irq_no / 16) * 4; bool enabled = FALSE; u32 val; /* Interrupt configuration for SGIs can't be changed */ if (irq_no < 16) { return VMM_EINVALID; } if (type != VMM_IRQ_TYPE_LEVEL_HIGH && type != VMM_IRQ_TYPE_EDGE_RISING) { return VMM_EINVALID; } val = gic_read(base + GIC_DIST_CONFIG + confoff); if (type == VMM_IRQ_TYPE_LEVEL_HIGH) { val &= ~confmask; } else if (type == VMM_IRQ_TYPE_EDGE_RISING) { val |= confmask; } /* * As recommended by the spec, disable the interrupt before changing * the configuration */ if (gic_read(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) { gic_write(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff); enabled = TRUE; } gic_write(val, base + GIC_DIST_CONFIG + confoff); if (enabled) { gic_write(enablemask, base + GIC_DIST_ENABLE_SET + enableoff); } return 0; }
static int gic_set_affinity(struct vmm_host_irq *d, const struct vmm_cpumask *mask_val, bool force) { virtual_addr_t reg; u32 shift = (d->hwirq % 4) * 8; u32 cpu = vmm_cpumask_first(mask_val); u32 val, mask, bit; struct gic_chip_data *gic = vmm_host_irq_get_chip_data(d); if (cpu >= 8) return VMM_EINVALID; reg = gic->dist_base + GICD_TARGET + (d->hwirq & ~3); mask = 0xff << shift; bit = 1 << (cpu + shift); val = gic_read(reg) & ~mask; gic_write(val | bit, reg); return 0; }
static void gic_unmask_irq(struct vmm_host_irq *d) { gic_poke_irq(vmm_host_irq_get_chip_data(d), d, GICD_ENABLE_SET); }
static inline u32 gic_irq(struct vmm_host_irq *irq) { struct gic_chip_data *gic_data = vmm_host_irq_get_chip_data(irq); return irq->num - gic_data->irq_offset; }
static inline virtual_addr_t gic_cpu_base(struct vmm_host_irq *irq) { struct gic_chip_data *gic_data = vmm_host_irq_get_chip_data(irq); return gic_data->cpu_base; }
static inline u32 fpga_irq(struct vmm_host_irq *irq) { struct fpga_irq_data *f = vmm_host_irq_get_chip_data(irq); return irq->num - f->irq_start; }
static void gic_unmask_irq(struct vmm_host_irq *irq) { gic_poke_irq(vmm_host_irq_get_chip_data(irq), irq, GIC_DIST_ENABLE_SET); }
static void gic_mask_irq(struct vmm_host_irq *d) { gic_poke_irq(vmm_host_irq_get_chip_data(d), d, GIC_DIST_ENABLE_CLEAR); }