case VRANGE32(GICD_ISPENDR, GICD_ISPENDRN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- printk(XENLOG_G_ERR
- "%pv: vGICD: unhandled word write %#"PRIregister" to ISPENDR%d\n",
- v, r, gicd_reg - GICD_ISPENDR);
- return 0;
+ rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ISPENDR, DABT_WORD);
+ if ( rank == NULL ) goto write_ignore;
+
+ vgic_set_irqs_pending(v, r, rank->index);
+
+ return 1;
case VRANGE32(GICD_ICPENDR, GICD_ICPENDRN):
if ( dabt.size != DABT_WORD ) goto bad_width;
case VRANGE32(GICD_ISPENDR, GICD_ISPENDRN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- printk(XENLOG_G_ERR
- "%pv: %s: unhandled word write %#"PRIregister" to ISPENDR%d\n",
- v, name, r, reg - GICD_ISPENDR);
- return 0;
+ rank = vgic_rank_offset(v, 1, reg - GICD_ISPENDR, DABT_WORD);
+ if ( rank == NULL ) goto write_ignore;
+
+ vgic_set_irqs_pending(v, r, rank->index);
+
+ return 1;
case VRANGE32(GICD_ICPENDR, GICD_ICPENDRN):
if ( dabt.size != DABT_WORD ) goto bad_width;
case VREG32(GICR_ICACTIVER0):
case VREG32(GICR_ICFGR1):
case VRANGE32(GICR_IPRIORITYR0, GICR_IPRIORITYR7):
+ case VREG32(GICR_ISPENDR0):
/*
* Above registers offset are common with GICD.
* So handle common with GICD handling
return __vgic_v3_distr_common_mmio_write("vGICR: SGI", v,
info, gicr_reg, r);
- case VREG32(GICR_ISPENDR0):
- if ( dabt.size != DABT_WORD ) goto bad_width;
- printk(XENLOG_G_ERR
- "%pv: vGICR: SGI: unhandled word write %#"PRIregister" to ISPENDR0\n",
- v, r);
- return 0;
-
case VREG32(GICR_ICPENDR0):
if ( dabt.size != DABT_WORD ) goto bad_width;
printk(XENLOG_G_ERR
}
}
+void vgic_set_irqs_pending(struct vcpu *v, uint32_t r, unsigned int rank)
+{
+ const unsigned long mask = r;
+ unsigned int i;
+ /* The first rank is always per-vCPU */
+ bool private = rank == 0;
+
+ /* LPIs will never be set pending via this function */
+ ASSERT(!is_lpi(32 * rank + 31));
+
+ for_each_set_bit( i, &mask, 32 )
+ {
+ unsigned int irq = i + 32 * rank;
+
+ if ( !private )
+ {
+ struct pending_irq *p = spi_to_pending(v->domain, irq);
+
+ /*
+ * When the domain sets the pending state for a HW interrupt on
+ * the virtual distributor, we set the pending state on the
+ * physical distributor.
+ *
+ * XXX: Investigate whether we would be able to set the
+ * physical interrupt active and save an interruption. (This
+ * is what the new vGIC does).
+ */
+ if ( p->desc != NULL )
+ {
+ unsigned long flags;
+
+ spin_lock_irqsave(&p->desc->lock, flags);
+ gic_set_pending_state(p->desc, true);
+ spin_unlock_irqrestore(&p->desc->lock, flags);
+ continue;
+ }
+ }
+
+ /*
+ * If the interrupt is per-vCPU, then we want to inject the vIRQ
+ * to v, otherwise we should let the function figuring out the
+ * correct vCPU.
+ */
+ vgic_inject_irq(v->domain, private ? v : NULL, irq, true);
+ }
+}
+
bool vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode,
int virq, const struct sgi_target *target)
{
extern struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, unsigned int irq);
extern void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n);
extern void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n);
+extern void vgic_set_irqs_pending(struct vcpu *v, uint32_t r,
+ unsigned int rank);
extern void register_vgic_ops(struct domain *d, const struct vgic_ops *ops);
int vgic_v2_init(struct domain *d, int *mmio_count);
int vgic_v3_init(struct domain *d, int *mmio_count);