|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v10 4/7] xen/arm: Add virtual GICv3 support
On Tue, 9 Sep 2014, vijay.kilari@xxxxxxxxx wrote:
> From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
>
> Add virtual GICv3 driver support.
> Also, with this patch vgic_irq_rank structure is modified to
> hold GICv2 GICD_TARGET and GICv3 GICD_ROUTER registers under
> union.
>
> This patch adds only basic GICv3 support.
> Does not support Interrupt Translation support (ITS)
>
> Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
> ---
> v10:- Implement callbacks get_target_vcpu and get_irq_priority
> for vgic-v3
> - Fix REG_RANK_NR for 64 bit
> v9: - Use 128K mask to compute GICR register offset if stride
> is not set
> - Fix alignment errors in vgic-v.c
> - Updated vgic_{lock,unlock}_rank
> v8: - Fixed printk coding styles
> - Moved GICD_PIDRn and GICR_PIDRn macros to vgic-v3.c
> from header file
> - Check is made on return value of vgic_v3_init()
> v7: Fixed coding style.
> v6: Removed byte read access for IROUTERN register.
> ---
> xen/arch/arm/Makefile | 1 +
> xen/arch/arm/vgic-v2.c | 23 +-
> xen/arch/arm/vgic-v3.c | 954
> ++++++++++++++++++++++++++++++++++++++++++++
> xen/arch/arm/vgic.c | 6 +
> xen/include/asm-arm/vgic.h | 18 +-
> 5 files changed, 989 insertions(+), 13 deletions(-)
>
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index 33765f6..e557cac 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -29,6 +29,7 @@ obj-y += smp.o
> obj-y += shutdown.o
> obj-y += traps.o
> obj-y += vgic.o vgic-v2.o
> +obj-$(CONFIG_ARM_64) += vgic-v3.o
> obj-y += vtimer.o
> obj-y += vuart.o
> obj-y += hvm.o
> diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c
> index ef18804..d10e139 100644
> --- a/xen/arch/arm/vgic-v2.c
> +++ b/xen/arch/arm/vgic-v2.c
> @@ -132,10 +132,9 @@ static int vgic_v2_distr_mmio_read(struct vcpu *v,
> mmio_info_t *info)
> if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto
> bad_width;
> rank = vgic_rank_offset(v, 8, gicd_reg - GICD_ITARGETSR, DABT_WORD);
> if ( rank == NULL) goto read_as_zero;
> -
> vgic_lock_rank(v, rank, flags);
> - *r = rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR,
> - DABT_WORD)];
> + *r = rank->v2.itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR,
> + DABT_WORD)];
> if ( dabt.size == DABT_BYTE )
> *r = vgic_byte_read(*r, dabt.sign, gicd_reg);
> vgic_unlock_rank(v, rank, flags);
> @@ -390,7 +389,7 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
> mmio_info_t *info)
> struct vcpu *v_target, *v_old;
>
> new_target = i % 8;
> - old_target_mask = vgic_byte_read(rank->itargets[REG_RANK_INDEX(8,
> + old_target_mask =
> vgic_byte_read(rank->v2.itargets[REG_RANK_INDEX(8,
> gicd_reg - GICD_ITARGETSR,
> DABT_WORD)], 0, i/8);
> old_target = find_first_bit(&old_target_mask, 8);
>
> @@ -404,11 +403,11 @@ static int vgic_v2_distr_mmio_write(struct vcpu *v,
> mmio_info_t *info)
> i += 8 - new_target;
> }
> if ( dabt.size == DABT_WORD )
> - rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR,
> - DABT_WORD)] = target;
> + rank->v2.itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR,
> + DABT_WORD)] = target;
> else
> - vgic_byte_write(&rank->itargets[REG_RANK_INDEX(8,
> - gicd_reg - GICD_ITARGETSR, DABT_WORD)], target,
> gicd_reg);
> + vgic_byte_write(&rank->v2.itargets[REG_RANK_INDEX(8,
> + gicd_reg - GICD_ITARGETSR, DABT_WORD)], target,
> gicd_reg);
> vgic_unlock_rank(v, rank, flags);
> return 1;
> }
> @@ -511,7 +510,7 @@ static struct vcpu *vgic_v2_get_target_vcpu(struct vcpu
> *v, unsigned int irq)
> struct vgic_irq_rank *rank = vgic_rank_irq(v, irq);
> ASSERT(spin_is_locked(&rank->lock));
>
> - target = vgic_byte_read(rank->itargets[(irq%32)/4], 0, irq % 4);
> + target = vgic_byte_read(rank->v2.itargets[(irq%32)/4], 0, irq % 4);
> /* 1-N SPI should be delivered as pending to all the vcpus in the
> * mask, but here we just return the first vcpu for simplicity and
> * because it would be too slow to do otherwise. */
> @@ -541,7 +540,7 @@ static int vgic_v2_vcpu_init(struct vcpu *v)
>
> /* For SGI and PPI the target is always this CPU */
> for ( i = 0 ; i < 8 ; i++ )
> - v->arch.vgic.private_irqs->itargets[i] =
> + v->arch.vgic.private_irqs->v2.itargets[i] =
> (1<<(v->vcpu_id+0))
> | (1<<(v->vcpu_id+8))
> | (1<<(v->vcpu_id+16))
> @@ -556,8 +555,8 @@ static int vgic_v2_domain_init(struct domain *d)
>
> /* By default deliver to CPU0 */
> for ( i = 0; i < DOMAIN_NR_RANKS(d); i++ )
> - memset(d->arch.vgic.shared_irqs[i].itargets, 0x1,
> - sizeof(d->arch.vgic.shared_irqs[i].itargets));
> + memset(d->arch.vgic.shared_irqs[i].v2.itargets, 0x1,
> + sizeof(d->arch.vgic.shared_irqs[i].v2.itargets));
>
> /* We rely on gicv_setup() to initialize dbase(vGIC distributor base) */
> register_mmio_handler(d, &vgic_v2_distr_mmio_handler, d->arch.vgic.dbase,
> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> new file mode 100644
> index 0000000..374a226
> --- /dev/null
> +++ b/xen/arch/arm/vgic-v3.c
> @@ -0,0 +1,954 @@
> +/*
> + * xen/arch/arm/vgic-v3.c
> + *
> + * ARM Virtual Generic Interrupt Controller v3 support
> + * based on xen/arch/arm/vgic.c
> + *
> + * Vijaya Kumar K <vijaya.kumar@xxxxxxxxxxxxxxxxxx>
> + * Copyright (c) 2014 Cavium Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <xen/bitops.h>
> +#include <xen/config.h>
> +#include <xen/lib.h>
> +#include <xen/init.h>
> +#include <xen/softirq.h>
> +#include <xen/irq.h>
> +#include <xen/sched.h>
> +#include <xen/sizes.h>
> +#include <asm/current.h>
> +#include <asm/device.h>
> +#include <asm/mmio.h>
> +#include <asm/gic_v3_defs.h>
> +#include <asm/gic.h>
> +#include <asm/vgic.h>
> +
> +/* GICD_PIDRn register values for ARM implementations */
> +#define GICV3_GICD_PIDR0 0x92
> +#define GICV3_GICD_PIDR1 0xb4
> +#define GICV3_GICD_PIDR2 0x3b
> +#define GICV3_GICD_PIDR4 0x04
> +
> +/* GICR_PIDRn register values for ARM implementations */
> +#define GICV3_GICR_PIDR0 0x93
> +#define GICV3_GICR_PIDR1 GICV3_GICD_PIDR1
> +#define GICV3_GICR_PIDR2 GICV3_GICD_PIDR2
> +#define GICV3_GICR_PIDR4 GICV3_GICD_PIDR4
> +
> +static struct vcpu *vgicv3_get_target_vcpu(struct vcpu *v, unsigned int irq)
> +{
> + /* TODO: Return vcpu0 always */
> + return v->domain->vcpu[0];
> +}
> +
> +static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu *v, mmio_info_t *info,
> + uint32_t gicr_reg)
> +{
> + struct hsr_dabt dabt = info->dabt;
> + struct cpu_user_regs *regs = guest_cpu_user_regs();
> + register_t *r = select_user_reg(regs, dabt.reg);
> + uint64_t aff;
> +
> + switch ( gicr_reg )
> + {
> + case GICR_CTLR:
> + /* We have not implemented LPI's, read zero */
> + goto read_as_zero;
> + case GICR_IIDR:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = GICV3_GICR_IIDR_VAL;
> + return 1;
> + case GICR_TYPER:
> + if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> + /* TBD: Update processor id in [23:8] when ITS support is added */
> + aff = (MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 3) << 56 |
> + MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 2) << 48 |
> + MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 1) << 40 |
> + MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 0) << 32);
> + *r = aff;
> + return 1;
> + case GICR_STATUSR:
> + /* Not implemented */
> + goto read_as_zero;
> + case GICR_WAKER:
> + /* Power management is not implemented */
> + goto read_as_zero;
> + case GICR_SETLPIR:
> + /* WO. Read as zero */
> + goto read_as_zero_64;
> + case GICR_CLRLPIR:
> + /* WO. Read as zero */
> + goto read_as_zero_64;
> + case GICR_PROPBASER:
> + /* LPI's not implemented */
> + goto read_as_zero_64;
> + case GICR_PENDBASER:
> + /* LPI's not implemented */
> + goto read_as_zero_64;
> + case GICR_INVLPIR:
> + /* WO. Read as zero */
> + goto read_as_zero_64;
> + case GICR_INVALLR:
> + /* WO. Read as zero */
> + goto read_as_zero_64;
> + return 0;
> + case GICR_SYNCR:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + /* RO . But when read it always returns busy bito bit[0] */
> + *r = GICR_SYNCR_NOT_BUSY;
> + return 1;
> + case GICR_MOVLPIR:
> + /* WO Read as zero */
> + goto read_as_zero_64;
> + case GICR_MOVALLR:
> + /* WO Read as zero */
> + goto read_as_zero_64;
> + case GICR_PIDR0:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = GICV3_GICR_PIDR0;
> + return 1;
> + case GICR_PIDR1:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = GICV3_GICR_PIDR1;
> + return 1;
> + case GICR_PIDR2:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = GICV3_GICR_PIDR2;
> + return 1;
> + case GICR_PIDR3:
> + /* Manufacture/customer defined */
> + goto read_as_zero;
> + case GICR_PIDR4:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = GICV3_GICR_PIDR4;
> + return 1;
> + case GICR_PIDR5 ... GICR_PIDR7:
> + /* Reserved0 */
> + goto read_as_zero;
> + default:
> + printk("vGICv3: vGICR: read r%d offset %#08x\n not found",
> + dabt.reg, gicr_reg);
> + return 0;
> + }
> +bad_width:
> + printk("vGICv3: vGICR: bad read width %d r%d offset %#08x\n",
> + dabt.size, dabt.reg, gicr_reg);
> + domain_crash_synchronous();
> + return 0;
> +
> +read_as_zero_64:
> + if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> + *r = 0;
> + return 1;
> +
> +read_as_zero:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = 0;
> + return 1;
> +}
> +
> +static int __vgic_v3_rdistr_rd_mmio_write(struct vcpu *v, mmio_info_t *info,
> + uint32_t gicr_reg)
> +{
> + struct hsr_dabt dabt = info->dabt;
> + struct cpu_user_regs *regs = guest_cpu_user_regs();
> + register_t *r = select_user_reg(regs, dabt.reg);
> +
> + switch ( gicr_reg )
> + {
> + case GICR_CTLR:
> + /* LPI's not implemented */
> + goto write_ignore;
> + case GICR_IIDR:
> + /* RO */
> + goto write_ignore;
> + case GICR_TYPER:
> + /* RO */
> + goto write_ignore_64;
> + case GICR_STATUSR:
> + /* Not implemented */
> + goto write_ignore;
> + case GICR_WAKER:
> + /* Power mgmt not implemented */
> + goto write_ignore;
> + case GICR_SETLPIR:
> + /* LPI is not implemented */
> + goto write_ignore_64;
> + case GICR_CLRLPIR:
> + /* LPI is not implemented */
> + goto write_ignore_64;
> + case GICR_PROPBASER:
> + /* LPI is not implemented */
> + goto write_ignore_64;
> + case GICR_PENDBASER:
> + /* LPI is not implemented */
> + goto write_ignore_64;
> + case GICR_INVLPIR:
> + /* LPI is not implemented */
> + goto write_ignore_64;
> + case GICR_INVALLR:
> + /* LPI is not implemented */
> + goto write_ignore_64;
> + case GICR_SYNCR:
> + /* RO */
> + goto write_ignore;
> + case GICR_MOVLPIR:
> + /* LPI is not implemented */
> + goto write_ignore_64;
> + case GICR_MOVALLR:
> + /* LPI is not implemented */
> + goto write_ignore_64;
> + case GICR_PIDR7... GICR_PIDR0:
> + /* RO */
> + goto write_ignore;
> + default:
> + printk("vGICR: write r%d offset %#08x\n not found", dabt.reg,
> gicr_reg);
> + return 0;
> + }
> +bad_width:
> + printk("vGICR: bad write width %d r%d=%"PRIregister" offset %#08x\n",
> + dabt.size, dabt.reg, *r, gicr_reg);
> + domain_crash_synchronous();
> + return 0;
> +
> +write_ignore_64:
> + if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> + return 1;
> +
> +write_ignore:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + return 1;
> +}
> +
> +static int __vgic_v3_distr_common_mmio_read(struct vcpu *v, mmio_info_t
> *info,
> + uint32_t reg)
> +{
> + struct hsr_dabt dabt = info->dabt;
> + struct cpu_user_regs *regs = guest_cpu_user_regs();
> + register_t *r = select_user_reg(regs, dabt.reg);
> + struct vgic_irq_rank *rank;
> + unsigned long flags;
> +
> + switch ( reg )
> + {
> + case GICD_IGROUPR ... GICD_IGROUPRN:
> + /* We do not implement security extensions for guests, read zero */
> + goto read_as_zero;
> + case 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 = rank->ienable;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case 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 = rank->ienable;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_ISPENDR ... GICD_ISPENDRN:
> + if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto
> bad_width;
> + rank = vgic_rank_offset(v, 1, reg - GICD_ISPENDR, DABT_WORD);
> + if ( rank == NULL ) goto read_as_zero;
> + vgic_lock_rank(v, rank, flags);
> + *r = vgic_byte_read(rank->ipend, dabt.sign, reg);
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_ICPENDR ... GICD_ICPENDRN:
> + if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto
> bad_width;
> + rank = vgic_rank_offset(v, 1, reg - GICD_ICPENDR, DABT_WORD);
> + if ( rank == NULL) goto read_as_zero;
> + vgic_lock_rank(v, rank, flags);
> + *r = vgic_byte_read(rank->ipend, dabt.sign, reg);
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_ISACTIVER ... GICD_ISACTIVERN:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + rank = vgic_rank_offset(v, 1, reg - GICD_ISACTIVER, DABT_WORD);
> + if ( rank == NULL) goto read_as_zero;
> + vgic_lock_rank(v, rank, flags);
> + *r = rank->iactive;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_ICACTIVER ... GICD_ICACTIVERN:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + rank = vgic_rank_offset(v, 1, reg - GICD_ICACTIVER, DABT_WORD);
> + if ( rank == NULL) goto read_as_zero;
> + vgic_lock_rank(v, rank, flags);
> + *r = rank->iactive;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
> + if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto
> bad_width;
> + rank = vgic_rank_offset(v, 8, reg - GICD_IPRIORITYR, DABT_WORD);
> + if ( rank == NULL) goto read_as_zero;
> +
> + vgic_lock_rank(v, rank, flags);
> + *r = rank->ipriority[REG_RANK_INDEX(8, reg - GICD_IPRIORITYR,
> + DABT_WORD)];
> + if ( dabt.size == DABT_BYTE )
> + *r = vgic_byte_read(*r, dabt.sign, reg);
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_ICFGR ... GICD_ICFGRN:
> + 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);
> + *r = rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR, DABT_WORD)];
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + default:
> + printk("vGICv3: vGICD/vGICR: unhandled read r%d offset %#08x\n",
> + dabt.reg, reg);
> + return 0;
> + }
> +
> +bad_width:
> + dprintk(XENLOG_ERR,
> + "vGICv3: vGICD/vGICR: bad read width %d r%d offset %#08x\n",
> + dabt.size, dabt.reg, reg);
> + domain_crash_synchronous();
> + return 0;
> +
> +read_as_zero:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = 0;
> + return 1;
> +}
> +
> +static int __vgic_v3_distr_common_mmio_write(struct vcpu *v, mmio_info_t
> *info,
> + uint32_t reg)
> +{
> + struct hsr_dabt dabt = info->dabt;
> + struct cpu_user_regs *regs = guest_cpu_user_regs();
> + register_t *r = select_user_reg(regs, dabt.reg);
> + struct vgic_irq_rank *rank;
> + uint32_t tr;
> + unsigned long flags;
> +
> + switch ( reg )
> + {
> + case GICD_IGROUPR ... GICD_IGROUPRN:
> + /* We do not implement security extensions for guests, write ignore
> */
> + goto write_ignore;
> + case 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;
> + rank->ienable |= *r;
> + vgic_unlock_rank(v, rank, flags);
> + /* The irq number is extracted from offset. so shift by register
> size */
> + vgic_enable_irqs(v, (*r) & (~tr), (reg - GICD_ISENABLER) >>
> DABT_WORD);
> + return 1;
> + case 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;
> + rank->ienable &= ~*r;
> + vgic_unlock_rank(v, rank, flags);
> + /* The irq number is extracted from offset. so shift by register
> size */
> + vgic_disable_irqs(v, (*r) & tr, (reg - GICD_ICENABLER) >> DABT_WORD);
> + return 1;
> + case GICD_ISPENDR ... GICD_ISPENDRN:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + rank = vgic_rank_offset(v, 1, reg - GICD_ISPENDR, DABT_WORD);
> + if ( rank == NULL ) goto write_ignore;
> + vgic_lock_rank(v, rank, flags);
> + rank->ipend = *r;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_ICPENDR ... GICD_ICPENDRN:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + rank = vgic_rank_offset(v, 1, reg - GICD_ICPENDR, DABT_WORD);
> + if ( rank == NULL ) goto write_ignore;
> + vgic_lock_rank(v, rank, flags);
> + rank->ipend &= ~*r;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_ISACTIVER ... GICD_ISACTIVERN:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + rank = vgic_rank_offset(v, 1, reg - GICD_ISACTIVER, DABT_WORD);
> + if ( rank == NULL) goto write_ignore;
> + vgic_lock_rank(v, rank, flags);
> + rank->iactive &= ~*r;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_ICACTIVER ... GICD_ICACTIVERN:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + rank = vgic_rank_offset(v, 1, reg - GICD_ICACTIVER, DABT_WORD);
> + if ( rank == NULL) goto write_ignore;
> + vgic_lock_rank(v, rank, flags);
> + rank->iactive &= ~*r;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
> + if ( dabt.size != DABT_BYTE && dabt.size != DABT_WORD ) goto
> bad_width;
> + rank = vgic_rank_offset(v, 8, reg - GICD_IPRIORITYR, DABT_WORD);
> + if ( rank == NULL) goto write_ignore;
> + vgic_lock_rank(v, rank, flags);
> + if ( dabt.size == DABT_WORD )
> + rank->ipriority[REG_RANK_INDEX(8, reg - GICD_IPRIORITYR,
> + DABT_WORD)] = *r;
> + else
> + vgic_byte_write(&rank->ipriority[REG_RANK_INDEX(8,
> + reg - GICD_IPRIORITYR, DABT_WORD)], *r, reg);
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_ICFGR: /* Restricted to configure SGIs */
> + goto write_ignore;
> + case GICD_ICFGR + 4 ... GICD_ICFGRN: /* PPI + SPIs */
> + /* 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);
> + rank->icfg[REG_RANK_INDEX(2, reg - GICD_ICFGR, DABT_WORD)] = *r;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + default:
> + printk("vGICv3: vGICD/vGICR: unhandled write r%d "
> + "=%"PRIregister" offset %#08x\n", dabt.reg, *r, reg);
> + return 0;
> + }
> +
> +bad_width:
> + dprintk(XENLOG_ERR,
> + "vGICv3: vGICD/vGICR: bad write width %d r%d=%"PRIregister" "
> + "offset %#08x\n", dabt.size, dabt.reg, *r, reg);
> + domain_crash_synchronous();
> + return 0;
> +
> +write_ignore:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + return 1;
> +}
> +
> +static int vgic_v3_rdistr_sgi_mmio_read(struct vcpu *v, mmio_info_t *info,
> + uint32_t gicr_reg)
> +{
> + struct hsr_dabt dabt = info->dabt;
> + struct cpu_user_regs *regs = guest_cpu_user_regs();
> + register_t *r = select_user_reg(regs, dabt.reg);
> + struct vgic_irq_rank *rank;
> + unsigned long flags;
> +
> + switch ( gicr_reg )
> + {
> + case GICR_IGRPMODR0:
> + /* We do not implement security extensions for guests, read zero */
> + goto read_as_zero;
> + case GICR_IGROUPR0:
> + case GICR_ISENABLER0:
> + case GICR_ICENABLER0:
> + case GICR_ISACTIVER0:
> + case GICR_ICACTIVER0:
> + case GICR_IPRIORITYR0...GICR_IPRIORITYR7:
> + case GICR_ICFGR0... GICR_ICFGR1:
> + /*
> + * Above registers offset are common with GICD.
> + * So handle in common with GICD handling
> + */
> + return __vgic_v3_distr_common_mmio_read(v, info, gicr_reg);
> + case GICR_ISPENDR0:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + rank = vgic_rank_offset(v, 1, gicr_reg - GICR_ISPENDR0, DABT_WORD);
> + if ( rank == NULL ) goto read_as_zero;
> + vgic_lock_rank(v, rank, flags);
> + *r = rank->pendsgi;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICR_ICPENDR0:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + rank = vgic_rank_offset(v, 1, gicr_reg - GICR_ICPENDR0, DABT_WORD);
> + if ( rank == NULL ) goto read_as_zero;
> + vgic_lock_rank(v, rank, flags);
> + *r = rank->pendsgi;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICR_NSACR:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + return 1;
> + default:
> + printk("vGICv3: vGICR: read r%d offset %#08x\n not found",
> + dabt.reg, gicr_reg);
> + return 0;
> + }
> +bad_width:
> + printk("vGICv3: vGICR: bad read width %d r%d offset %#08x\n",
> + dabt.size, dabt.reg, gicr_reg);
> + domain_crash_synchronous();
> + return 0;
> +
> +read_as_zero:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = 0;
> + return 1;
> +}
> +
> +static int vgic_v3_rdistr_sgi_mmio_write(struct vcpu *v, mmio_info_t *info,
> + uint32_t gicr_reg)
> +{
> + struct hsr_dabt dabt = info->dabt;
> + struct cpu_user_regs *regs = guest_cpu_user_regs();
> + register_t *r = select_user_reg(regs, dabt.reg);
> + struct vgic_irq_rank *rank;
> + unsigned long flags;
> +
> + switch ( gicr_reg )
> + {
> + case GICR_IGRPMODR0:
> + /* We do not implement security extensions for guests, write ignore
> */
> + goto write_ignore;
> + case GICR_IGROUPR0:
> + case GICR_ISENABLER0:
> + case GICR_ICENABLER0:
> + case GICR_ISACTIVER0:
> + case GICR_ICACTIVER0:
> + case GICR_ICFGR1:
> + case GICR_IPRIORITYR0...GICR_IPRIORITYR7:
> + /*
> + * Above registers offset are common with GICD.
> + * So handle common with GICD handling
> + */
> + return __vgic_v3_distr_common_mmio_write(v, info, gicr_reg);
> + case GICR_ISPENDR0:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + rank = vgic_rank_offset(v, 1, gicr_reg - GICR_ISACTIVER0, DABT_WORD);
> + if ( rank == NULL ) goto write_ignore;
> + vgic_lock_rank(v, rank, flags);
> + /* TODO: we just store the SGI pending status. Handle it properly */
> + rank->pendsgi |= *r;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICR_ICPENDR0:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + rank = vgic_rank_offset(v, 1, gicr_reg - GICR_ISACTIVER0, DABT_WORD);
> + if ( rank == NULL ) goto write_ignore;
> + vgic_lock_rank(v, rank, flags);
> + /* TODO: we just store the SGI pending status. Handle it properly */
> + rank->pendsgi &= ~*r;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICR_NSACR:
> + /* We do not implement security extensions for guests, write ignore
> */
> + goto write_ignore;
> + default:
> + printk("vGICv3: vGICR SGI: write r%d offset %#08x\n not found",
> + dabt.reg, gicr_reg);
> + return 0;
> + }
> +
> +bad_width:
> + printk("vGICR SGI: bad write width %d r%d=%"PRIregister" offset %#08x\n",
> + dabt.size, dabt.reg, *r, gicr_reg);
> + domain_crash_synchronous();
> + return 0;
> +
> +write_ignore:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + return 1;
> +}
> +
> +static int vgic_v3_rdistr_mmio_read(struct vcpu *v, mmio_info_t *info)
> +{
> + uint32_t offset;
> +
> + if ( v->domain->arch.vgic.rdist_stride != 0 )
> + offset = info->gpa & (v->domain->arch.vgic.rdist_stride - 1);
> + else
> + /* If stride is not set. Default 128K */
> + offset = info->gpa & (SZ_128K - 1);
> +
> + if ( offset < SZ_64K )
> + return __vgic_v3_rdistr_rd_mmio_read(v, info, offset);
> + else if ( (offset >= SZ_64K) && (offset < 2 * SZ_64K) )
> + return vgic_v3_rdistr_sgi_mmio_read(v, info, (offset - SZ_64K));
> + else
> + gdprintk(XENLOG_WARNING,
> + "vGICv3: vGICR: unknown gpa read address %"PRIpaddr"\n",
> + info->gpa);
> +
> + return 0;
> +}
> +
> +static int vgic_v3_rdistr_mmio_write(struct vcpu *v, mmio_info_t *info)
> +{
> + uint32_t offset;
> +
> + if ( v->domain->arch.vgic.rdist_stride != 0 )
> + offset = info->gpa & (v->domain->arch.vgic.rdist_stride - 1);
> + else
> + /* If stride is not set. Default 128K */
> + offset = info->gpa & (SZ_128K - 1);
> +
> + if ( offset < SZ_64K )
> + return __vgic_v3_rdistr_rd_mmio_write(v, info, offset);
> + else if ( (offset >= SZ_64K) && (offset < 2 * SZ_64K) )
> + return vgic_v3_rdistr_sgi_mmio_write(v, info, (offset - SZ_64K));
> + else
> + gdprintk(XENLOG_WARNING,
> + "vGICV3: vGICR: unknown gpa write address %"PRIpaddr"\n",
> + info->gpa);
> +
> + return 0;
> +}
> +
> +static int vgic_v3_distr_mmio_read(struct vcpu *v, mmio_info_t *info)
> +{
> + struct hsr_dabt dabt = info->dabt;
> + struct cpu_user_regs *regs = guest_cpu_user_regs();
> + register_t *r = select_user_reg(regs, dabt.reg);
> + struct vgic_irq_rank *rank;
> + unsigned long flags;
> + int gicd_reg = (int)(info->gpa - v->domain->arch.vgic.dbase);
> +
> + switch ( gicd_reg )
> + {
> + case GICD_CTLR:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + vgic_lock(v);
> + *r = v->domain->arch.vgic.ctlr;
> + vgic_unlock(v);
> + return 1;
> + case GICD_TYPER:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + /* No secure world support for guests. */
> + *r = (((v->domain->max_vcpus << 5) & GICD_TYPE_CPUS ) |
> + ((v->domain->arch.vgic.nr_lines / 32) & GICD_TYPE_LINES));
> + return 1;
> + case GICD_STATUSR:
> + /*
> + * Optional, Not implemented for now.
> + * Update to support guest debugging.
> + */
> + goto read_as_zero;
> + case GICD_IIDR:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = GICV3_GICD_IIDR_VAL;
> + return 1;
> + case 0x020 ... 0x03c:
> + case 0xc000 ... 0xffcc:
> + /* Implementation defined -- read as zero */
> + goto read_as_zero;
> + case GICD_IGROUPR ... GICD_IGROUPRN:
> + case GICD_ISENABLER ... GICD_ISENABLERN:
> + case GICD_ICENABLER ... GICD_ICENABLERN:
> + case GICD_ISPENDR ... GICD_ISPENDRN:
> + case GICD_ICPENDR ... GICD_ICPENDRN:
> + case GICD_ISACTIVER ... GICD_ISACTIVERN:
> + case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
> + case GICD_ICFGR ... GICD_ICFGRN:
> + /*
> + * Above all register are common with GICR and GICD
> + * Manage in common
> + */
> + return __vgic_v3_distr_common_mmio_read(v, info, gicd_reg);
> + case GICD_IROUTER ... GICD_IROUTER31:
> + /* SGI/PPI is RES0 */
> + goto read_as_zero_64;
> + case GICD_IROUTER32 ... GICD_IROUTERN:
> + if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> + rank = vgic_rank_offset(v, 64, gicd_reg - GICD_IROUTER,
> DABT_DOUBLE_WORD);
> + if ( rank == NULL) goto read_as_zero;
> + vgic_lock_rank(v, rank, flags);
> + /* IROUTER is 64 bit so, to make it byte size right shift by 3.
> + Here once. macro REG_RANK_INDEX will do it twice */
This comment is not correct, is it?
> + *r = rank->v3.irouter[REG_RANK_INDEX(64,
> + (gicd_reg - GICD_IROUTER), DABT_DOUBLE_WORD)];
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_NSACR ... GICD_NSACRN:
> + /* We do not implement security extensions for guests, read zero */
> + goto read_as_zero;
> + case GICD_SGIR:
> + /* Read as ICH_SGIR system register with SRE set. So ignore */
> + goto read_as_zero;
> + case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
> + /* Replaced with GICR_ICPENDR0. So ignore write */
> + goto read_as_zero;
> + case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
> + /* Replaced with GICR_ISPENDR0. So ignore write */
> + goto read_as_zero;
> + case GICD_PIDR0:
> + /* GICv3 identification value */
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = GICV3_GICD_PIDR0;
> + return 1;
> + case GICD_PIDR1:
> + /* GICv3 identification value */
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = GICV3_GICD_PIDR1;
> + return 1;
> + case GICD_PIDR2:
> + /* GICv3 identification value */
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = GICV3_GICD_PIDR2;
> + return 1;
> + case GICD_PIDR3:
> + /* GICv3 identification value. Manufacturer/Customer defined */
> + goto read_as_zero;
> + case GICD_PIDR4:
> + /* GICv3 identification value */
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = GICV3_GICD_PIDR4;
> + return 1;
> + case GICD_PIDR5 ... GICD_PIDR7:
> + /* Reserved0 */
> + goto read_as_zero;
> + case 0x00c:
> + case 0x044:
> + case 0x04c:
> + case 0x05c ... 0x07c:
> + case 0xf30 ... 0x5fcc:
> + case 0x8000 ... 0xbfcc:
> + /* These are reserved register addresses */
> + printk("vGICv3: vGICD: read unknown 0x00c .. 0xfcc r%d offset
> %#08x\n",
> + dabt.reg, gicd_reg);
> + goto read_as_zero;
> + default:
> + printk("vGICv3: vGICD: unhandled read r%d offset %#08x\n",
> + dabt.reg, gicd_reg);
> + return 0;
> + }
> +
> +bad_width:
> + dprintk(XENLOG_ERR, "vGICv3: vGICD: bad read width %d r%d offset
> %#08x\n",
> + dabt.size, dabt.reg, gicd_reg);
> + domain_crash_synchronous();
> + return 0;
> +
> +read_as_zero_64:
> + if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> + *r = 0;
> + return 1;
> +
> +read_as_zero:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + *r = 0;
> + return 1;
> +}
> +
> +static int vgic_v3_distr_mmio_write(struct vcpu *v, mmio_info_t *info)
> +{
> + struct hsr_dabt dabt = info->dabt;
> + struct cpu_user_regs *regs = guest_cpu_user_regs();
> + register_t *r = select_user_reg(regs, dabt.reg);
> + struct vgic_irq_rank *rank;
> + unsigned long flags;
> + int gicd_reg = (int)(info->gpa - v->domain->arch.vgic.dbase);
> +
> + switch ( gicd_reg )
> + {
> + case GICD_CTLR:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + /* Ignore all but the enable bit */
> + v->domain->arch.vgic.ctlr = (*r) & GICD_CTL_ENABLE;
> + return 1;
> + case GICD_TYPER:
> + /* RO -- write ignored */
> + goto write_ignore;
> + case GICD_IIDR:
> + /* RO -- write ignored */
> + goto write_ignore;
> + case GICD_STATUSR:
> + /* RO -- write ignored */
> + goto write_ignore;
> + case GICD_SETSPI_NSR:
> + /* Message based SPI is not implemented */
> + goto write_ignore;
> + case GICD_CLRSPI_NSR:
> + /* Message based SPI is not implemented */
> + goto write_ignore;
> + case GICD_SETSPI_SR:
> + /* Message based SPI is not implemented */
> + goto write_ignore;
> + case GICD_CLRSPI_SR:
> + /* Message based SPI is not implemented */
> + goto write_ignore;
> + case 0x020 ... 0x03c:
> + case 0xc000 ... 0xffcc:
> + /* Implementation defined -- write ignored */
> + printk("vGICv3: vGICD: write unknown 0x020 - 0x03c r%d offset
> %#08x\n",
> + dabt.reg, gicd_reg);
> + goto write_ignore;
> + case GICD_IGROUPR ... GICD_IGROUPRN:
> + case GICD_ISENABLER ... GICD_ISENABLERN:
> + case GICD_ICENABLER ... GICD_ICENABLERN:
> + case GICD_ISPENDR ... GICD_ISPENDRN:
> + case GICD_ICPENDR ... GICD_ICPENDRN:
> + case GICD_ISACTIVER ... GICD_ISACTIVERN:
> + case GICD_ICACTIVER ... GICD_ICACTIVERN:
> + case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
> + case GICD_ICFGR ... GICD_ICFGRN:
> + /* Above registers are common with GICR and GICD
> + * Manage in common */
> + return __vgic_v3_distr_common_mmio_write(v, info, gicd_reg);
> + case GICD_IROUTER ... GICD_IROUTER31:
> + /* SGI/PPI is RES0 */
> + goto write_ignore_64;
> + case GICD_IROUTER32 ... GICD_IROUTERN:
> + if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> + rank = vgic_rank_offset(v, 64, gicd_reg - GICD_IROUTER,
> DABT_DOUBLE_WORD);
> + if ( rank == NULL) goto write_ignore_64;
> + if ( *r )
> + {
> + /* TODO: Ignored. We don't support irq delivery for vcpu != 0 */
> + gdprintk(XENLOG_DEBUG,
> + "SPI delivery to secondary cpus not supported\n");
> + goto write_ignore_64;
> + }
> + vgic_lock_rank(v, rank, flags);
> + rank->v3.irouter[REG_RANK_INDEX(64,
> + (gicd_reg - GICD_IROUTER), DABT_DOUBLE_WORD)] = *r;
> + vgic_unlock_rank(v, rank, flags);
> + return 1;
> + case GICD_NSACR ... GICD_NSACRN:
> + /* We do not implement security extensions for guests, write ignore
> */
> + goto write_ignore;
> + case GICD_SGIR:
> + /* it is accessed as system register in GICv3 */
> + goto write_ignore;
> + case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
> + /* Replaced with GICR_ICPENDR0. So ignore write */
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + return 0;
> + case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
> + /* Replaced with GICR_ISPENDR0. So ignore write */
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + return 0;
> + case GICD_PIDR7... GICD_PIDR0:
> + /* RO -- write ignore */
> + goto write_ignore;
> + case 0x00c:
> + case 0x044:
> + case 0x04c:
> + case 0x05c ... 0x07c:
> + case 0xf30 ... 0x5fcc:
> + case 0x8000 ... 0xbfcc:
> + /* Reserved register addresses */
> + printk("vGICv3: vGICD: write unknown 0x00c 0xfcc r%d offset
> %#08x\n",
> + dabt.reg, gicd_reg);
> + goto write_ignore;
> + default:
> + printk("vGICv3: vGICD: unhandled write r%d=%"PRIregister" "
> + "offset %#08x\n", dabt.reg, *r, gicd_reg);
> + return 0;
> + }
> +
> +bad_width:
> + dprintk(XENLOG_ERR,
> + "VGICv3: vGICD: bad write width %d r%d=%"PRIregister" "
> + "offset %#08x\n", dabt.size, dabt.reg, *r, gicd_reg);
> + domain_crash_synchronous();
> + return 0;
> +
> +write_ignore:
> + if ( dabt.size != DABT_WORD ) goto bad_width;
> + return 1;
> +
> +write_ignore_64:
> + if ( dabt.size != DABT_DOUBLE_WORD ) goto bad_width;
> + return 1;
> +}
> +
> +static const struct mmio_handler_ops vgic_rdistr_mmio_handler = {
> + .read_handler = vgic_v3_rdistr_mmio_read,
> + .write_handler = vgic_v3_rdistr_mmio_write,
> +};
> +
> +static const struct mmio_handler_ops vgic_distr_mmio_handler = {
> + .read_handler = vgic_v3_distr_mmio_read,
> + .write_handler = vgic_v3_distr_mmio_write,
> +};
> +
> +static int vgicv3_get_irq_priority(struct vcpu *v, unsigned int irq)
> +{
> + int priority;
> + struct vgic_irq_rank *rank;
> +
> + rank = vgic_rank_offset(v, 8, (irq / 4) * 4, DABT_WORD);
Call vgic_rank_irq instead.
You could also add an assert about the rank being locked like in the v2
case.
> + priority = vgic_byte_read(rank->ipriority[REG_RANK_INDEX(8,
> + irq, DABT_WORD)], 0, irq &
> 0x3);
> +
> + return priority;
> +}
> +
> +static int vgicv3_vcpu_init(struct vcpu *v)
> +{
> + int i;
> + uint64_t affinity;
> +
> + /* For SGI and PPI the target is always this CPU */
> + affinity = (MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 3) << 32 |
> + MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 2) << 16 |
> + MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 1) << 8 |
> + MPIDR_AFFINITY_LEVEL(v->arch.vmpidr, 0));
> +
> + for ( i = 0 ; i < 32 ; i++ )
> + v->arch.vgic.private_irqs->v3.irouter[i] = affinity;
> +
> + return 0;
> +}
> +
> +static int vgicv3_domain_init(struct domain *d)
> +{
> + int i;
> +
> + /* We rely on gicv init to get dbase and size */
> + register_mmio_handler(d, &vgic_distr_mmio_handler, d->arch.vgic.dbase,
> + d->arch.vgic.dbase_size);
> +
> + /*
> + * Register mmio handler per redistributor region but not for
> + * every sgi rdist region which is per core.
> + * The redistributor region encompasses per core sgi region.
> + */
> + for ( i = 0; i < d->arch.vgic.rdist_count; i++ )
> + register_mmio_handler(d, &vgic_rdistr_mmio_handler,
> + d->arch.vgic.rbase[i], d->arch.vgic.rbase_size[i]);
> +
> + return 0;
> +}
> +
> +static const struct vgic_ops v3_ops = {
> + .vcpu_init = vgicv3_vcpu_init,
> + .domain_init = vgicv3_domain_init,
> + .get_irq_priority = vgicv3_get_irq_priority,
> + .get_target_vcpu = vgicv3_get_target_vcpu,
> +};
> +
> +int vgic_v3_init(struct domain *d)
> +{
> + register_vgic_ops(d, &v3_ops);
> +
> + return 0;
> +}
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/arch/arm/vgic.c b/xen/arch/arm/vgic.c
> index 30faefe..fc7c6a5 100644
> --- a/xen/arch/arm/vgic.c
> +++ b/xen/arch/arm/vgic.c
> @@ -76,6 +76,12 @@ int domain_vgic_init(struct domain *d)
>
> switch ( gic_hw_version() )
> {
> +#ifdef CONFIG_ARM_64
> + case GIC_V3:
> + if ( vgic_v3_init(d) )
> + return -ENODEV;
> + break;
> +#endif
> case GIC_V2:
> if ( vgic_v2_init(d) )
> return -ENODEV;
> diff --git a/xen/include/asm-arm/vgic.h b/xen/include/asm-arm/vgic.h
> index a9f1943..60651cc 100644
> --- a/xen/include/asm-arm/vgic.h
> +++ b/xen/include/asm-arm/vgic.h
> @@ -88,7 +88,14 @@ struct vgic_irq_rank {
> uint32_t ienable, iactive, ipend, pendsgi;
> uint32_t icfg[2];
> uint32_t ipriority[8];
> - uint32_t itargets[8];
> + union {
> + struct {
> + uint32_t itargets[8];
> + }v2;
> + struct {
> + uint64_t irouter[32];
> + }v3;
> + };
> };
>
> struct vgic_ops {
> @@ -120,6 +127,14 @@ static inline int REG_RANK_NR(int b, uint32_t n)
> {
> switch ( b )
> {
> + /*
> + * IRQ ranks are of size 32. So n cannot be shifter beyond 5 for 32
^shifted
> + * and above. For 64-bit n is already shifted DBAT_DOUBLE_WORD
> + * by the caller
> + */
> + case 64:
> + case 32: return n >> 5;
> + case 16: return n >> 4;
> case 8: return n >> 3;
> case 4: return n >> 2;
> case 2: return n >> 1;
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |