Message ID | 20170504153123.1204-7-andre.przywara@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi Andre, On 04/05/17 16:31, Andre Przywara wrote: > Currently we store the interrupt type configuration (level or edge > triggered) in the rank structure. Move this value into struct pending_irq. > We just need one bit (edge or level), so use one of the status bits. > > Signed-off-by: Andre Przywara <andre.przywara@arm.com> > --- > xen/arch/arm/vgic-v2.c | 29 ++++++++++------------------- > xen/arch/arm/vgic-v3.c | 31 ++++++++++++------------------- > xen/arch/arm/vgic.c | 39 ++++++++++++++++++++------------------- > xen/include/asm-arm/vgic.h | 7 ++++++- > 4 files changed, 48 insertions(+), 58 deletions(-) > > diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c > index 5c59fb4..795173c 100644 > --- a/xen/arch/arm/vgic-v2.c > +++ b/xen/arch/arm/vgic-v2.c > @@ -278,20 +278,10 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info, > goto read_reserved; > > case VRANGE32(GICD_ICFGR, GICD_ICFGRN): > - { > - uint32_t icfgr; > - > if ( dabt.size != DABT_WORD ) goto bad_width; > - rank = vgic_rank_offset(v, 2, gicd_reg - GICD_ICFGR, DABT_WORD); > - if ( rank == NULL) goto read_as_zero; > - vgic_lock_rank(v, rank, flags); > - icfgr = rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR, DABT_WORD)]; > - vgic_unlock_rank(v, rank, flags); > - > - *r = vgic_reg32_extract(icfgr, info); > - > + irq = (gicd_reg - GICD_ICFGR) * 4; This would be nicer to have that handle directly in gather_irq_info_config rather than open-coding everywhere. Also it avoids this confusion of what irq actually meaning in this context. I was also expecting some check on whether the interrupts is valid for the vGIC. > + *r = vgic_reg32_extract(gather_irq_info_config(v, irq), info); > return 1; > - } > > case VRANGE32(0xD00, 0xDFC): > goto read_impl_defined; > @@ -534,15 +524,16 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info, > goto write_ignore_32; > > case VRANGE32(GICD_ICFGR2, GICD_ICFGRN): /* SPIs */ > + { > + uint32_t icfgr; > + > if ( dabt.size != DABT_WORD ) goto bad_width; > - rank = vgic_rank_offset(v, 2, gicd_reg - GICD_ICFGR, DABT_WORD); > - if ( rank == NULL) goto write_ignore; > - vgic_lock_rank(v, rank, flags); > - vgic_reg32_update(&rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR, > - DABT_WORD)], > - r, info); > - vgic_unlock_rank(v, rank, flags); > + irq = (gicd_reg - GICD_ICFGR) * 4; Ditto for the irq and the check. > + icfgr = gather_irq_info_config(v, irq); > + vgic_reg32_update(&icfgr, r, info); > + scatter_irq_info_config(v, irq, icfgr); > return 1; > + } > > case VRANGE32(0xD00, 0xDFC): > goto write_impl_defined; > diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c > index 10db939..7989989 100644 > --- a/xen/arch/arm/vgic-v3.c > +++ b/xen/arch/arm/vgic-v3.c > @@ -521,20 +521,11 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v, > return 1; > > case VRANGE32(GICD_ICFGR, GICD_ICFGRN): > - { > - uint32_t icfgr; > - > if ( dabt.size != DABT_WORD ) goto bad_width; > - rank = vgic_rank_offset(v, 2, reg - GICD_ICFGR, DABT_WORD); > - if ( rank == NULL ) goto read_as_zero; > - vgic_lock_rank(v, rank, flags); > - icfgr = rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR, DABT_WORD)]; > - vgic_unlock_rank(v, rank, flags); > - > - *r = vgic_reg32_extract(icfgr, info); > - > + irq = (reg - GICD_IPRIORITYR) * 4; > + if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto read_as_zero; This should really be an helper. > + *r = vgic_reg32_extract(gather_irq_info_config(v, irq), info); > return 1; > - } > > default: > printk(XENLOG_G_ERR > @@ -636,17 +627,19 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v, > goto write_ignore_32; > > case VRANGE32(GICD_ICFGR + 4, GICD_ICFGRN): /* PPI + SPIs */ > + { > + uint32_t icfgr; > + > /* ICFGR1 for PPI's, which is implementation defined > if ICFGR1 is programmable or not. We chose to program */ > if ( dabt.size != DABT_WORD ) goto bad_width; > - rank = vgic_rank_offset(v, 2, reg - GICD_ICFGR, DABT_WORD); > - if ( rank == NULL ) goto write_ignore; > - vgic_lock_rank(v, rank, flags); > - vgic_reg32_update(&rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR, > - DABT_WORD)], > - r, info); > - vgic_unlock_rank(v, rank, flags); > + irq = (reg - GICD_ICFGR) * 4; > + if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto write_ignore; > + icfgr = gather_irq_info_config(v, irq); > + vgic_reg32_update(&icfgr, r, info); > + scatter_irq_info_config(v, irq, icfgr); > return 1; > + } > > default: > printk(XENLOG_G_ERR > diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c > index 68eef47..02c1d12 100644 > --- a/xen/arch/arm/vgic.c > +++ b/xen/arch/arm/vgic.c > @@ -235,6 +235,19 @@ static void set_priority(struct pending_irq *p, uint8_t prio) > p->new_priority = prio; > } > > +unsigned int extract_config(struct pending_irq *p) Why this is exported? Also naming. > +{ > + return test_bit(GIC_IRQ_GUEST_EDGE, &p->status) ? 2 : 0; Please document 0, 2. Likely with a some define. > +} > + > +static void set_config(struct pending_irq *p, unsigned int config) Naming. > +{ > + if ( config < 2 ) Ditto. > + clear_bit(GIC_IRQ_GUEST_EDGE, &p->status); > + else > + set_bit(GIC_IRQ_GUEST_EDGE, &p->status); > +} > + > > #define DEFINE_GATHER_IRQ_INFO(name, get_val, shift) \ > uint32_t gather_irq_info_##name(struct vcpu *v, unsigned int irq) \ > @@ -267,6 +280,8 @@ void scatter_irq_info_##name(struct vcpu *v, unsigned int irq, \ > /* grep fodder: gather_irq_info_priority, scatter_irq_info_priority below */ > DEFINE_GATHER_IRQ_INFO(priority, extract_priority, 8) > DEFINE_SCATTER_IRQ_INFO(priority, set_priority, 8) > +DEFINE_GATHER_IRQ_INFO(config, extract_config, 2) > +DEFINE_SCATTER_IRQ_INFO(config, set_config, 2) > > bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq) > { > @@ -357,27 +372,11 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n) > } > } > > -#define VGIC_ICFG_MASK(intr) (1 << ((2 * ((intr) % 16)) + 1)) > - > -/* The function should be called with the rank lock taken */ > -static inline unsigned int vgic_get_virq_type(struct vcpu *v, int n, int index) > -{ > - struct vgic_irq_rank *r = vgic_get_rank(v, n); > - uint32_t tr = r->icfg[index >> 4]; > - > - ASSERT(spin_is_locked(&r->lock)); > - > - if ( tr & VGIC_ICFG_MASK(index) ) > - return IRQ_TYPE_EDGE_RISING; > - else > - return IRQ_TYPE_LEVEL_HIGH; > -} > - > void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n) > { > const unsigned long mask = r; > struct pending_irq *p; > - unsigned int irq; > + unsigned int irq, int_type; > unsigned long flags; > int i = 0; > struct vcpu *v_target; > @@ -392,6 +391,8 @@ void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n) > spin_lock(&p->lock); > > set_bit(GIC_IRQ_GUEST_ENABLED, &p->status); > + int_type = test_bit(GIC_IRQ_GUEST_EDGE, &p->status) ? > + IRQ_TYPE_EDGE_RISING : IRQ_TYPE_LEVEL_HIGH; > > if ( !list_empty(&p->inflight) && !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) ) > gic_raise_guest_irq(v_target, p); > @@ -399,15 +400,15 @@ void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n) > spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags); > if ( p->desc != NULL ) > { > - irq_set_affinity(p->desc, cpumask_of(v_target->processor)); > 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, vgic_get_virq_type(v, n, i)); > + gic_set_irq_type(p->desc, int_type); > p->desc->handler->enable(p->desc); > spin_unlock_irqrestore(&p->desc->lock, flags); > } > diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h > index 38a5e76..931a672 100644 > --- a/xen/include/asm-arm/vgic.h > +++ b/xen/include/asm-arm/vgic.h > @@ -60,12 +60,15 @@ struct pending_irq > * vcpu while it is still inflight and on an GICH_LR register on the > * old vcpu. > * > + * GIC_IRQ_GUEST_EDGE: the IRQ is an edge triggered interrupt. Also, explain that by default the interrupt will be level. > + * > */ > #define GIC_IRQ_GUEST_QUEUED 0 > #define GIC_IRQ_GUEST_ACTIVE 1 > #define GIC_IRQ_GUEST_VISIBLE 2 > #define GIC_IRQ_GUEST_ENABLED 3 > #define GIC_IRQ_GUEST_MIGRATING 4 > +#define GIC_IRQ_GUEST_EDGE 5 > unsigned long status; > struct irq_desc *desc; /* only set it the irq corresponds to a physical irq */ > unsigned int irq; > @@ -102,7 +105,6 @@ struct vgic_irq_rank { > uint8_t index; > > uint32_t ienable; > - uint32_t icfg[2]; > > /* > * It's more convenient to store a target VCPU per vIRQ > @@ -173,6 +175,9 @@ static inline int REG_RANK_NR(int b, uint32_t n) > uint32_t gather_irq_info_priority(struct vcpu *v, unsigned int irq); > void scatter_irq_info_priority(struct vcpu *v, unsigned int irq, > unsigned int value); > +uint32_t gather_irq_info_config(struct vcpu *v, unsigned int irq); > +void scatter_irq_info_config(struct vcpu *v, unsigned int irq, > + unsigned int value); > > #define VGIC_REG_MASK(size) ((~0UL) >> (BITS_PER_LONG - ((1 << (size)) * 8))) > > Cheers,
diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index 5c59fb4..795173c 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -278,20 +278,10 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v, mmio_info_t *info, goto read_reserved; case VRANGE32(GICD_ICFGR, GICD_ICFGRN): - { - uint32_t icfgr; - if ( dabt.size != DABT_WORD ) goto bad_width; - rank = vgic_rank_offset(v, 2, gicd_reg - GICD_ICFGR, DABT_WORD); - if ( rank == NULL) goto read_as_zero; - vgic_lock_rank(v, rank, flags); - icfgr = rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR, DABT_WORD)]; - vgic_unlock_rank(v, rank, flags); - - *r = vgic_reg32_extract(icfgr, info); - + irq = (gicd_reg - GICD_ICFGR) * 4; + *r = vgic_reg32_extract(gather_irq_info_config(v, irq), info); return 1; - } case VRANGE32(0xD00, 0xDFC): goto read_impl_defined; @@ -534,15 +524,16 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v, mmio_info_t *info, goto write_ignore_32; case VRANGE32(GICD_ICFGR2, GICD_ICFGRN): /* SPIs */ + { + uint32_t icfgr; + if ( dabt.size != DABT_WORD ) goto bad_width; - rank = vgic_rank_offset(v, 2, gicd_reg - GICD_ICFGR, DABT_WORD); - if ( rank == NULL) goto write_ignore; - vgic_lock_rank(v, rank, flags); - vgic_reg32_update(&rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR, - DABT_WORD)], - r, info); - vgic_unlock_rank(v, rank, flags); + irq = (gicd_reg - GICD_ICFGR) * 4; + icfgr = gather_irq_info_config(v, irq); + vgic_reg32_update(&icfgr, r, info); + scatter_irq_info_config(v, irq, icfgr); return 1; + } case VRANGE32(0xD00, 0xDFC): goto write_impl_defined; diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c index 10db939..7989989 100644 --- a/xen/arch/arm/vgic-v3.c +++ b/xen/arch/arm/vgic-v3.c @@ -521,20 +521,11 @@ static int __vgic_v3_distr_common_mmio_read(const char *name, struct vcpu *v, return 1; case VRANGE32(GICD_ICFGR, GICD_ICFGRN): - { - uint32_t icfgr; - if ( dabt.size != DABT_WORD ) goto bad_width; - rank = vgic_rank_offset(v, 2, reg - GICD_ICFGR, DABT_WORD); - if ( rank == NULL ) goto read_as_zero; - vgic_lock_rank(v, rank, flags); - icfgr = rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR, DABT_WORD)]; - vgic_unlock_rank(v, rank, flags); - - *r = vgic_reg32_extract(icfgr, info); - + irq = (reg - GICD_IPRIORITYR) * 4; + if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto read_as_zero; + *r = vgic_reg32_extract(gather_irq_info_config(v, irq), info); return 1; - } default: printk(XENLOG_G_ERR @@ -636,17 +627,19 @@ static int __vgic_v3_distr_common_mmio_write(const char *name, struct vcpu *v, goto write_ignore_32; case VRANGE32(GICD_ICFGR + 4, GICD_ICFGRN): /* PPI + SPIs */ + { + uint32_t icfgr; + /* ICFGR1 for PPI's, which is implementation defined if ICFGR1 is programmable or not. We chose to program */ if ( dabt.size != DABT_WORD ) goto bad_width; - rank = vgic_rank_offset(v, 2, reg - GICD_ICFGR, DABT_WORD); - if ( rank == NULL ) goto write_ignore; - vgic_lock_rank(v, rank, flags); - vgic_reg32_update(&rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR, - DABT_WORD)], - r, info); - vgic_unlock_rank(v, rank, flags); + irq = (reg - GICD_ICFGR) * 4; + if ( irq >= v->domain->arch.vgic.nr_spis + 32 ) goto write_ignore; + icfgr = gather_irq_info_config(v, irq); + vgic_reg32_update(&icfgr, r, info); + scatter_irq_info_config(v, irq, icfgr); return 1; + } default: printk(XENLOG_G_ERR diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c index 68eef47..02c1d12 100644 --- a/xen/arch/arm/vgic.c +++ b/xen/arch/arm/vgic.c @@ -235,6 +235,19 @@ static void set_priority(struct pending_irq *p, uint8_t prio) p->new_priority = prio; } +unsigned int extract_config(struct pending_irq *p) +{ + return test_bit(GIC_IRQ_GUEST_EDGE, &p->status) ? 2 : 0; +} + +static void set_config(struct pending_irq *p, unsigned int config) +{ + if ( config < 2 ) + clear_bit(GIC_IRQ_GUEST_EDGE, &p->status); + else + set_bit(GIC_IRQ_GUEST_EDGE, &p->status); +} + #define DEFINE_GATHER_IRQ_INFO(name, get_val, shift) \ uint32_t gather_irq_info_##name(struct vcpu *v, unsigned int irq) \ @@ -267,6 +280,8 @@ void scatter_irq_info_##name(struct vcpu *v, unsigned int irq, \ /* grep fodder: gather_irq_info_priority, scatter_irq_info_priority below */ DEFINE_GATHER_IRQ_INFO(priority, extract_priority, 8) DEFINE_SCATTER_IRQ_INFO(priority, set_priority, 8) +DEFINE_GATHER_IRQ_INFO(config, extract_config, 2) +DEFINE_SCATTER_IRQ_INFO(config, set_config, 2) bool vgic_migrate_irq(struct vcpu *old, struct vcpu *new, unsigned int irq) { @@ -357,27 +372,11 @@ void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n) } } -#define VGIC_ICFG_MASK(intr) (1 << ((2 * ((intr) % 16)) + 1)) - -/* The function should be called with the rank lock taken */ -static inline unsigned int vgic_get_virq_type(struct vcpu *v, int n, int index) -{ - struct vgic_irq_rank *r = vgic_get_rank(v, n); - uint32_t tr = r->icfg[index >> 4]; - - ASSERT(spin_is_locked(&r->lock)); - - if ( tr & VGIC_ICFG_MASK(index) ) - return IRQ_TYPE_EDGE_RISING; - else - return IRQ_TYPE_LEVEL_HIGH; -} - void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n) { const unsigned long mask = r; struct pending_irq *p; - unsigned int irq; + unsigned int irq, int_type; unsigned long flags; int i = 0; struct vcpu *v_target; @@ -392,6 +391,8 @@ void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n) spin_lock(&p->lock); set_bit(GIC_IRQ_GUEST_ENABLED, &p->status); + int_type = test_bit(GIC_IRQ_GUEST_EDGE, &p->status) ? + IRQ_TYPE_EDGE_RISING : IRQ_TYPE_LEVEL_HIGH; if ( !list_empty(&p->inflight) && !test_bit(GIC_IRQ_GUEST_VISIBLE, &p->status) ) gic_raise_guest_irq(v_target, p); @@ -399,15 +400,15 @@ void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n) spin_unlock_irqrestore(&v_target->arch.vgic.lock, flags); if ( p->desc != NULL ) { - irq_set_affinity(p->desc, cpumask_of(v_target->processor)); 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, vgic_get_virq_type(v, n, i)); + gic_set_irq_type(p->desc, int_type); p->desc->handler->enable(p->desc); spin_unlock_irqrestore(&p->desc->lock, flags); } diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h index 38a5e76..931a672 100644 --- a/xen/include/asm-arm/vgic.h +++ b/xen/include/asm-arm/vgic.h @@ -60,12 +60,15 @@ struct pending_irq * vcpu while it is still inflight and on an GICH_LR register on the * old vcpu. * + * GIC_IRQ_GUEST_EDGE: the IRQ is an edge triggered interrupt. + * */ #define GIC_IRQ_GUEST_QUEUED 0 #define GIC_IRQ_GUEST_ACTIVE 1 #define GIC_IRQ_GUEST_VISIBLE 2 #define GIC_IRQ_GUEST_ENABLED 3 #define GIC_IRQ_GUEST_MIGRATING 4 +#define GIC_IRQ_GUEST_EDGE 5 unsigned long status; struct irq_desc *desc; /* only set it the irq corresponds to a physical irq */ unsigned int irq; @@ -102,7 +105,6 @@ struct vgic_irq_rank { uint8_t index; uint32_t ienable; - uint32_t icfg[2]; /* * It's more convenient to store a target VCPU per vIRQ @@ -173,6 +175,9 @@ static inline int REG_RANK_NR(int b, uint32_t n) uint32_t gather_irq_info_priority(struct vcpu *v, unsigned int irq); void scatter_irq_info_priority(struct vcpu *v, unsigned int irq, unsigned int value); +uint32_t gather_irq_info_config(struct vcpu *v, unsigned int irq); +void scatter_irq_info_config(struct vcpu *v, unsigned int irq, + unsigned int value); #define VGIC_REG_MASK(size) ((~0UL) >> (BITS_PER_LONG - ((1 << (size)) * 8)))
Currently we store the interrupt type configuration (level or edge triggered) in the rank structure. Move this value into struct pending_irq. We just need one bit (edge or level), so use one of the status bits. Signed-off-by: Andre Przywara <andre.przywara@arm.com> --- xen/arch/arm/vgic-v2.c | 29 ++++++++++------------------- xen/arch/arm/vgic-v3.c | 31 ++++++++++++------------------- xen/arch/arm/vgic.c | 39 ++++++++++++++++++++------------------- xen/include/asm-arm/vgic.h | 7 ++++++- 4 files changed, 48 insertions(+), 58 deletions(-)