|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH v2 20/22] ARM: vGIC: move virtual IRQ enable bit from rank to pending_irq
The enabled bits for a group of IRQs are still stored in the irq_rank
structure, although we already have the same information in pending_irq,
in the GIC_IRQ_GUEST_ENABLED bit of the "status" field.
Remove the storage from the irq_rank and just utilize the existing
wrappers to cover enabling/disabling of multiple IRQs.
This also marks the removal of the last member of struct vgic_irq_rank.
Signed-off-by: Andre Przywara <andre.przywara@xxxxxxx>
---
xen/arch/arm/vgic-v2.c | 41 +++------
xen/arch/arm/vgic-v3.c | 41 +++------
xen/arch/arm/vgic.c | 201 +++++++++++++++++++++++++++------------------
xen/include/asm-arm/vgic.h | 10 +--
4 files changed, 152 insertions(+), 141 deletions(-)
diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
index c7ed3ce..3320642 100644
--- a/xen/arch/arm/vgic-v2.c
+++ b/xen/arch/arm/vgic-v2.c
@@ -166,9 +166,7 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v,
mmio_info_t *info,
register_t *r, void *priv)
{
struct hsr_dabt dabt = info->dabt;
- struct vgic_irq_rank *rank;
int gicd_reg = (int)(info->gpa - v->domain->arch.vgic.dbase);
- unsigned long flags;
unsigned int irq;
perfc_incr(vgicd_reads);
@@ -222,20 +220,16 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v,
mmio_info_t *info,
case VRANGE32(GICD_ISENABLER, GICD_ISENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ISENABLER, DABT_WORD);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank, flags);
- *r = vreg_reg32_extract(rank->ienable, info);
- vgic_unlock_rank(v, rank, flags);
+ irq = (gicd_reg - GICD_ISENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto read_as_zero;
+ *r = vgic_fetch_irq_enabled(v, irq);
return 1;
case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ICENABLER, DABT_WORD);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank, flags);
- *r = vreg_reg32_extract(rank->ienable, info);
- vgic_unlock_rank(v, rank, flags);
+ irq = (gicd_reg - GICD_ICENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto read_as_zero;
+ *r = vgic_fetch_irq_enabled(v, irq);
return 1;
/* Read the pending status of an IRQ via GICD is not supported */
@@ -386,10 +380,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
mmio_info_t *info,
register_t r, void *priv)
{
struct hsr_dabt dabt = info->dabt;
- struct vgic_irq_rank *rank;
int gicd_reg = (int)(info->gpa - v->domain->arch.vgic.dbase);
- uint32_t tr;
- unsigned long flags;
unsigned int irq;
perfc_incr(vgicd_writes);
@@ -426,24 +417,16 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
mmio_info_t *info,
case VRANGE32(GICD_ISENABLER, GICD_ISENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ISENABLER, DABT_WORD);
- if ( rank == NULL) goto write_ignore;
- vgic_lock_rank(v, rank, flags);
- tr = rank->ienable;
- vreg_reg32_setbits(&rank->ienable, r, info);
- vgic_enable_irqs(v, (rank->ienable) & (~tr), rank->index);
- vgic_unlock_rank(v, rank, flags);
+ irq = (gicd_reg - GICD_ISENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto write_ignore;
+ vgic_store_irq_enable(v, irq, r);
return 1;
case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, gicd_reg - GICD_ICENABLER, DABT_WORD);
- if ( rank == NULL) goto write_ignore;
- vgic_lock_rank(v, rank, flags);
- tr = rank->ienable;
- vreg_reg32_clearbits(&rank->ienable, r, info);
- vgic_disable_irqs(v, (~rank->ienable) & tr, rank->index);
- vgic_unlock_rank(v, rank, flags);
+ irq = (gicd_reg - GICD_ICENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto write_ignore;
+ vgic_store_irq_disable(v, irq, r);
return 1;
case VRANGE32(GICD_ISPENDR, GICD_ISPENDRN):
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
index e9d46af..00cc1e5 100644
--- a/xen/arch/arm/vgic-v3.c
+++ b/xen/arch/arm/vgic-v3.c
@@ -676,8 +676,6 @@ static int __vgic_v3_distr_common_mmio_read(const char
*name, struct vcpu *v,
register_t *r)
{
struct hsr_dabt dabt = info->dabt;
- struct vgic_irq_rank *rank;
- unsigned long flags;
unsigned int irq;
switch ( reg )
@@ -689,20 +687,16 @@ static int __vgic_v3_distr_common_mmio_read(const char
*name, struct vcpu *v,
case VRANGE32(GICD_ISENABLER, GICD_ISENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, reg - GICD_ISENABLER, DABT_WORD);
- if ( rank == NULL ) goto read_as_zero;
- vgic_lock_rank(v, rank, flags);
- *r = vreg_reg32_extract(rank->ienable, info);
- vgic_unlock_rank(v, rank, flags);
+ irq = (reg - GICD_ISENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto read_as_zero;
+ *r = vgic_fetch_irq_enabled(v, irq);
return 1;
case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, reg - GICD_ICENABLER, DABT_WORD);
- if ( rank == NULL ) goto read_as_zero;
- vgic_lock_rank(v, rank, flags);
- *r = vreg_reg32_extract(rank->ienable, info);
- vgic_unlock_rank(v, rank, flags);
+ irq = (reg - GICD_ICENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto read_as_zero;
+ *r = vgic_fetch_irq_enabled(v, irq);
return 1;
/* Read the pending status of an IRQ via GICD/GICR is not supported */
@@ -752,9 +746,6 @@ static int __vgic_v3_distr_common_mmio_write(const char
*name, struct vcpu *v,
register_t r)
{
struct hsr_dabt dabt = info->dabt;
- struct vgic_irq_rank *rank;
- uint32_t tr;
- unsigned long flags;
unsigned int irq;
switch ( reg )
@@ -765,24 +756,16 @@ static int __vgic_v3_distr_common_mmio_write(const char
*name, struct vcpu *v,
case VRANGE32(GICD_ISENABLER, GICD_ISENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, reg - GICD_ISENABLER, DABT_WORD);
- if ( rank == NULL ) goto write_ignore;
- vgic_lock_rank(v, rank, flags);
- tr = rank->ienable;
- vreg_reg32_setbits(&rank->ienable, r, info);
- vgic_enable_irqs(v, (rank->ienable) & (~tr), rank->index);
- vgic_unlock_rank(v, rank, flags);
+ irq = (reg - GICD_ISENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto write_ignore;
+ vgic_store_irq_enable(v, irq, r);
return 1;
case VRANGE32(GICD_ICENABLER, GICD_ICENABLERN):
if ( dabt.size != DABT_WORD ) goto bad_width;
- rank = vgic_rank_offset(v, 1, reg - GICD_ICENABLER, DABT_WORD);
- if ( rank == NULL ) goto write_ignore;
- vgic_lock_rank(v, rank, flags);
- tr = rank->ienable;
- vreg_reg32_clearbits(&rank->ienable, r, info);
- vgic_disable_irqs(v, (~rank->ienable) & tr, rank->index);
- vgic_unlock_rank(v, rank, flags);
+ irq = (reg - GICD_ICENABLER) * 8;
+ if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto write_ignore;
+ vgic_store_irq_disable(v, irq, r);
return 1;
case VRANGE32(GICD_ISPENDR, GICD_ISPENDRN):
diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
index a49fcde..dd969e2 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -261,6 +261,60 @@ struct vcpu *vgic_get_target_vcpu(struct domain *d, struct
pending_irq *p)
return d->vcpu[p->vcpu_id];
}
+/* Takes a locked pending_irq and enables the interrupt, also unlocking it. */
+static void vgic_enable_irq_unlock(struct domain *d, struct pending_irq *p)
+{
+ struct vcpu *v_target;
+ unsigned long flags;
+ struct irq_desc *desc;
+
+ v_target = vgic_lock_vcpu_irq(d, p, &flags);
+
+ clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
+ gic_remove_from_lr_pending(v_target, p);
+ desc = p->desc;
+ spin_unlock(&p->lock);
+ spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
+
+ if ( desc != NULL )
+ {
+ spin_lock_irqsave(&desc->lock, flags);
+ desc->handler->disable(desc);
+ spin_unlock_irqrestore(&desc->lock, flags);
+ }
+}
+
+/* Takes a locked pending_irq and disables the interrupt, also unlocking it. */
+static void vgic_disable_irq_unlock(struct domain *d, struct pending_irq *p)
+{
+ struct vcpu *v_target;
+ unsigned long flags;
+ struct irq_desc *desc;
+ int int_type;
+
+ v_target = vgic_lock_vcpu_irq(d, p, &flags);
+
+ set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
+ int_type = test_bit(GIC_IRQ_GUEST_LEVEL, &p->status) ? IRQ_TYPE_LEVEL_HIGH
:
+
IRQ_TYPE_EDGE_RISING;
+ if ( !list_empty(&p->inflight) &&
+ !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) )
+ gic_raise_guest_irq(v_target, p->irq, p->cur_priority);
+ desc = p->desc;
+ spin_unlock(&p->lock);
+ spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
+
+ if ( desc != NULL )
+ {
+ spin_lock_irqsave(&desc->lock, flags);
+ irq_set_affinity(desc, cpumask_of(v_target->processor));
+ if ( irq_type_set_by_domain(d) )
+ gic_set_irq_type(desc, int_type);
+ desc->handler->enable(desc);
+ spin_unlock_irqrestore(&desc->lock, flags);
+ }
+}
+
#define MAX_IRQS_PER_IPRIORITYR 4
uint32_t vgic_fetch_irq_priority(struct vcpu *v, unsigned int nrirqs,
unsigned int first_irq)
@@ -347,6 +401,75 @@ void vgic_store_irq_config(struct vcpu *v, unsigned int
first_irq,
local_irq_restore(flags);
}
+#define IRQS_PER_ENABLER 32
+/**
+ * vgic_fetch_irq_enabled: assemble the enabled bits for a group of 32 IRQs
+ * @v: the VCPU for private IRQs, any VCPU of a domain for SPIs
+ * @first_irq: the first IRQ to be queried, must be aligned to 32
+ */
+uint32_t vgic_fetch_irq_enabled(struct vcpu *v, unsigned int first_irq)
+{
+ struct pending_irq *pirqs[IRQS_PER_ENABLER];
+ unsigned long flags;
+ uint32_t reg = 0;
+ unsigned int i;
+
+ local_irq_save(flags);
+ vgic_lock_irqs(v, IRQS_PER_ENABLER, first_irq, pirqs);
+
+ for ( i = 0; i < 32; i++ )
+ if ( test_bit(GIC_IRQ_GUEST_ENABLED, &pirqs[i]->status) )
+ reg |= BIT(i);
+
+ vgic_unlock_irqs(pirqs, IRQS_PER_ENABLER);
+ local_irq_restore(flags);
+
+ return reg;
+}
+
+void vgic_store_irq_enable(struct vcpu *v, unsigned int first_irq,
+ uint32_t value)
+{
+ struct pending_irq *pirqs[IRQS_PER_ENABLER];
+ unsigned long flags;
+ int i;
+
+ local_irq_save(flags);
+ vgic_lock_irqs(v, IRQS_PER_ENABLER, first_irq, pirqs);
+
+ /* This goes backwards, as it unlocks the IRQs during the process */
+ for ( i = IRQS_PER_ENABLER - 1; i >= 0; i-- )
+ {
+ if ( !test_bit(GIC_IRQ_GUEST_ENABLED, &pirqs[i]->status) &&
+ (value & BIT(i)) )
+ vgic_enable_irq_unlock(v->domain, pirqs[i]);
+ else
+ spin_unlock(&pirqs[i]->lock);
+ }
+ local_irq_restore(flags);
+}
+
+void vgic_store_irq_disable(struct vcpu *v, unsigned int first_irq,
+ uint32_t value)
+{
+ struct pending_irq *pirqs[IRQS_PER_ENABLER];
+ unsigned long flags;
+ int i;
+
+ local_irq_save(flags);
+ vgic_lock_irqs(v, IRQS_PER_ENABLER, first_irq, pirqs);
+
+ /* This goes backwards, as it unlocks the IRQs during the process */
+ for ( i = 31; i >= 0; i-- )
+ {
+ if ( test_bit(GIC_IRQ_GUEST_ENABLED, &pirqs[i]->status) &&
+ (value & BIT(i)) )
+ vgic_disable_irq_unlock(v->domain, pirqs[i]);
+ else
+ spin_unlock(&pirqs[i]->lock);
+ }
+}
+
bool vgic_migrate_irq(struct pending_irq *p, unsigned long *flags,
struct vcpu *new)
{
@@ -437,40 +560,6 @@ void arch_move_irqs(struct vcpu *v)
}
}
-void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
-{
- const unsigned long mask = r;
- struct pending_irq *p;
- struct irq_desc *desc;
- unsigned int irq;
- unsigned long flags;
- int i = 0;
- struct vcpu *v_target;
-
- /* LPIs will never be disabled via this function. */
- ASSERT(!is_lpi(32 * n + 31));
-
- while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
- irq = i + (32 * n);
- p = irq_to_pending(v, irq);
- v_target = vgic_get_target_vcpu(v->domain, p);
-
- spin_lock_irqsave(&v_target->arch.vgic.lock, flags);
- clear_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
- gic_remove_from_lr_pending(v_target, p);
- desc = p->desc;
- spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags);
-
- if ( desc != NULL )
- {
- spin_lock_irqsave(&desc->lock, flags);
- desc->handler->disable(desc);
- spin_unlock_irqrestore(&desc->lock, flags);
- }
- i++;
- }
-}
-
void vgic_lock_irqs(struct vcpu *v, unsigned int nrirqs,
unsigned int first_irq, struct pending_irq **pirqs)
{
@@ -491,50 +580,6 @@ void vgic_unlock_irqs(struct pending_irq **pirqs, unsigned
int nrirqs)
spin_unlock(&pirqs[i]->lock);
}
-void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
-{
- const unsigned long mask = r;
- struct pending_irq *p;
- unsigned int irq, int_type;
- unsigned long flags, vcpu_flags;
- int i = 0;
- struct vcpu *v_target;
- struct domain *d = v->domain;
-
- /* LPIs will never be enabled via this function. */
- ASSERT(!is_lpi(32 * n + 31));
-
- while ( (i = find_next_bit(&mask, 32, i)) < 32 ) {
- irq = i + (32 * n);
- p = irq_to_pending(v, irq);
- v_target = vgic_get_target_vcpu(v->domain, p);
- spin_lock_irqsave(&v_target->arch.vgic.lock, vcpu_flags);
- vgic_irq_lock(p, flags);
- set_bit(GIC_IRQ_GUEST_ENABLED, &p->status);
- int_type = test_bit(GIC_IRQ_GUEST_LEVEL, &p->status) ?
- IRQ_TYPE_LEVEL_HIGH : IRQ_TYPE_EDGE_RISING;
- if ( !list_empty(&p->inflight) && !test_bit(GIC_IRQ_GUEST_VISIBLE,
&p->status) )
- gic_raise_guest_irq(v_target, irq, p->cur_priority);
- vgic_irq_unlock(p, flags);
- spin_unlock_irqrestore(&v_target->arch.vgic.lock, vcpu_flags);
- if ( p->desc != NULL )
- {
- spin_lock_irqsave(&p->desc->lock, flags);
- irq_set_affinity(p->desc, cpumask_of(v_target->processor));
- /*
- * The irq cannot be a PPI, we only support delivery of SPIs
- * to guests.
- */
- ASSERT(irq >= 32);
- if ( irq_type_set_by_domain(d) )
- gic_set_irq_type(p->desc, int_type);
- p->desc->handler->enable(p->desc);
- spin_unlock_irqrestore(&p->desc->lock, flags);
- }
- i++;
- }
-}
-
bool vgic_to_sgi(struct vcpu *v, register_t sgir, enum gic_sgi_mode irqmode,
int virq, const struct sgi_target *target)
{
diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
index fe4d53d..233ff1f 100644
--- a/xen/include/asm-arm/vgic.h
+++ b/xen/include/asm-arm/vgic.h
@@ -109,9 +109,6 @@ struct vgic_irq_rank {
spinlock_t lock; /* Covers access to all other members of this struct */
uint8_t index;
-
- uint32_t ienable;
-
};
struct sgi_target {
@@ -187,6 +184,11 @@ void vgic_store_irq_priority(struct vcpu *v, unsigned int
nrirqs,
uint32_t vgic_fetch_irq_config(struct vcpu *v, unsigned int first_irq);
void vgic_store_irq_config(struct vcpu *v, unsigned int first_irq,
uint32_t reg);
+uint32_t vgic_fetch_irq_enabled(struct vcpu *v, unsigned int first_irq);
+void vgic_store_irq_enable(struct vcpu *v, unsigned int first_irq,
+ uint32_t value);
+void vgic_store_irq_disable(struct vcpu *v, unsigned int first_irq,
+ uint32_t value);
enum gic_sgi_mode;
@@ -218,8 +220,6 @@ extern struct pending_irq *spi_to_pending(struct domain *d,
unsigned int irq);
extern struct vgic_irq_rank *vgic_rank_offset(struct vcpu *v, int b, int n,
int s);
extern struct vgic_irq_rank *vgic_rank_irq(struct vcpu *v, unsigned int irq);
extern bool vgic_emulate(struct cpu_user_regs *regs, union hsr hsr);
-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 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);
--
2.9.0
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |