|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC PATCH v1 07/10] xen/arm: split vgic into generic and GIC v2 specific drivers
From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
vgic driver contains both generic and GIC v2 specific
funtionality together. Segregate vgic driver into generic
code into vgic.c and GIC v2 specific functionality into
vgic-v2.c files. This helps to and GIC v3 specific funtionality.
Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
---
xen/arch/arm/Makefile | 2 +-
xen/arch/arm/vgic-v2.c | 636 ++++++++++++++++++++++++++++++++++++++++++++
xen/arch/arm/vgic.c | 640 ++++-----------------------------------------
xen/include/asm-arm/gic.h | 9 +
4 files changed, 695 insertions(+), 592 deletions(-)
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 969ee52..20f59f4 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -26,7 +26,7 @@ obj-y += smpboot.o
obj-y += smp.o
obj-y += shutdown.o
obj-y += traps.o
-obj-y += vgic.o
+obj-y += vgic.o vgic-v2.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
new file mode 100644
index 0000000..1e69763
--- /dev/null
+++ b/xen/arch/arm/vgic-v2.c
@@ -0,0 +1,636 @@
+/*
+ * xen/arch/arm/vgic-v2.c
+ *
+ * ARM Virtual Generic Interrupt Controller support v2
+ *
+ * Ian Campbell <ian.campbell@xxxxxxxxxx>
+ * Copyright (c) 2011 Citrix Systems.
+ *
+ * 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 <asm/current.h>
+
+#include "io.h"
+#include <asm/gic_v2_defs.h>
+#include <asm/gic.h>
+
+struct vgic_irq_rank {
+ spinlock_t lock; /* Covers access to all other members of this struct */
+ uint32_t ienable, iactive, ipend, pendsgi;
+ uint32_t icfg[2];
+ uint32_t ipriority[8];
+ uint32_t itargets[8];
+};
+
+#define REG(n) (n/4)
+
+/* Number of ranks of interrupt registers for a domain */
+#define DOMAIN_NR_RANKS(d) (((d)->arch.vgic.nr_lines+31)/32)
+
+/*
+ * Rank containing GICD_<FOO><n> for GICD_<FOO> with
+ * <b>-bits-per-interrupt
+ */
+static inline int REG_RANK_NR(int b, uint32_t n)
+{
+ switch ( b )
+ {
+ case 8: return n >> 3;
+ case 4: return n >> 2;
+ case 2: return n >> 1;
+ case 1: return n;
+ default: BUG();
+ }
+}
+
+/*
+ * Offset of GICD_<FOO><n> with its rank, for GICD_<FOO> with
+ * <b>-bits-per-interrupt.
+ */
+#define REG_RANK_INDEX(b, n) ((n) & ((b)-1))
+
+/*
+ * Returns rank corresponding to a GICD_<FOO><n> register for
+ * GICD_<FOO> with <b>-bits-per-interrupt.
+ */
+static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
+{
+ int rank = REG_RANK_NR(b, n);
+
+ if ( rank == 0 )
+ return (struct vgic_irq_rank *)v->arch.vgic.private_irqs;
+ else if ( rank <= DOMAIN_NR_RANKS(v->domain) )
+ return (struct vgic_irq_rank *)((unsigned char
*)(v->domain->arch.vgic.shared_irqs)
+ + (sizeof(struct vgic_irq_rank) *(rank - 1)));
+ else
+ return NULL;
+}
+
+static uint32_t byte_read(uint32_t val, int sign, int offset)
+{
+ int byte = offset & 0x3;
+
+ val = val >> (8*byte);
+ if ( sign && (val & 0x80) )
+ val |= 0xffffff00;
+ else
+ val &= 0x000000ff;
+ return val;
+}
+
+static void byte_write(uint32_t *reg, uint32_t var, int offset)
+{
+ int byte = offset & 0x3;
+
+ var &= (0xff << (8*byte));
+
+ *reg &= ~(0xff << (8*byte));
+ *reg |= var;
+}
+
+static int vgic_read_priority(struct vcpu *v, int irq)
+{
+ int idx = irq >> 2;
+ struct vgic_irq_rank *rank = vgic_irq_rank(v, 8, idx);
+ return byte_read(rank->ipriority[REG_RANK_INDEX(8, idx)], 0, irq & 0x3);
+}
+
+static int vgic_vcpu_init(struct vcpu *v)
+{
+ int i;
+ struct vgic_irq_rank *vir;
+
+ vir = xzalloc(struct vgic_irq_rank);
+ memset(vir, 0, sizeof(struct vgic_irq_rank));
+
+ spin_lock_init(&vir->lock);
+
+ /* For SGI and PPI the target is always this CPU */
+ for ( i = 0 ; i < 8 ; i++ )
+ vir->itargets[i] =
+ (1<<(v->vcpu_id+0))
+ | (1<<(v->vcpu_id+8))
+ | (1<<(v->vcpu_id+16))
+ | (1<<(v->vcpu_id+24));
+
+ v->arch.vgic.private_irqs = (struct vgic_irq_irank *)vir;
+ return 0;
+}
+
+static struct vgic_ops ops = {
+ .vgic_vcpu_init = vgic_vcpu_init,
+ .read_priority = vgic_read_priority,
+};
+
+#define vgic_lock(v) spin_lock_irq(&(v)->domain->arch.vgic.lock)
+#define vgic_unlock(v) spin_unlock_irq(&(v)->domain->arch.vgic.lock)
+
+#define vgic_lock_rank(v, r) spin_lock(&(r)->lock)
+#define vgic_unlock_rank(v, r) spin_unlock(&(r)->lock)
+
+static int vgic_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;
+ int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
+ int gicd_reg = REG(offset);
+
+ switch ( gicd_reg )
+ {
+ case GICD_CTLR:
+ if ( dabt.size != 2 ) goto bad_width;
+ vgic_lock(v);
+ *r = v->domain->arch.vgic.ctlr;
+ vgic_unlock(v);
+ return 1;
+ case GICD_TYPER:
+ if ( dabt.size != 2 ) goto bad_width;
+ /* No secure world support for guests. */
+ vgic_lock(v);
+ *r = ( (v->domain->max_vcpus<<5) & GICD_TYPE_CPUS )
+ |( ((v->domain->arch.vgic.nr_lines/32)) & GICD_TYPE_LINES );
+ vgic_unlock(v);
+ return 1;
+ case GICD_IIDR:
+ if ( dabt.size != 2 ) goto bad_width;
+ /*
+ * XXX Do we need a JEP106 manufacturer ID?
+ * Just use the physical h/w value for now
+ */
+ *r = 0x0000043b;
+ return 1;
+
+ /* Implementation defined -- read as zero */
+ case REG(0x020) ... REG(0x03c):
+ goto read_as_zero;
+
+ 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 != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER);
+ if ( rank == NULL) goto read_as_zero;
+ vgic_lock_rank(v, rank);
+ *r = rank->ienable;
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_ICENABLER ... GICD_ICENABLERN:
+ if ( dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER);
+ if ( rank == NULL) goto read_as_zero;
+ vgic_lock_rank(v, rank);
+ *r = rank->ienable;
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_ISPENDR ... GICD_ISPENDRN:
+ if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISPENDR);
+ if ( rank == NULL) goto read_as_zero;
+ vgic_lock_rank(v, rank);
+ *r = byte_read(rank->ipend, dabt.sign, offset);
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_ICPENDR ... GICD_ICPENDRN:
+ if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICPENDR);
+ if ( rank == NULL) goto read_as_zero;
+ vgic_lock_rank(v, rank);
+ *r = byte_read(rank->ipend, dabt.sign, offset);
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_ISACTIVER ... GICD_ISACTIVERN:
+ if ( dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER);
+ if ( rank == NULL) goto read_as_zero;
+ vgic_lock_rank(v, rank);
+ *r = rank->iactive;
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_ICACTIVER ... GICD_ICACTIVERN:
+ if ( dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER);
+ if ( rank == NULL) goto read_as_zero;
+ vgic_lock_rank(v, rank);
+ *r = rank->iactive;
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_ITARGETSR ... GICD_ITARGETSRN:
+ if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 8, gicd_reg - GICD_ITARGETSR);
+ if ( rank == NULL) goto read_as_zero;
+
+ vgic_lock_rank(v, rank);
+ *r = rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)];
+ if ( dabt.size == 0 )
+ *r = byte_read(*r, dabt.sign, offset);
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
+ if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR);
+ if ( rank == NULL) goto read_as_zero;
+
+ vgic_lock_rank(v, rank);
+ *r = rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)];
+ if ( dabt.size == 0 )
+ *r = byte_read(*r, dabt.sign, offset);
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_ICFGR ... GICD_ICFGRN:
+ if ( dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR);
+ if ( rank == NULL) goto read_as_zero;
+ vgic_lock_rank(v, rank);
+ *r = rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)];
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_NSACR ... GICD_NSACRN:
+ /* We do not implement security extensions for guests, read zero */
+ goto read_as_zero;
+
+ case GICD_SGIR:
+ if ( dabt.size != 2 ) goto bad_width;
+ /* Write only -- read unknown */
+ *r = 0xdeadbeef;
+ return 1;
+
+ case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
+ if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 1, gicd_reg - GICD_CPENDSGIR);
+ if ( rank == NULL) goto read_as_zero;
+ vgic_lock_rank(v, rank);
+ *r = byte_read(rank->pendsgi, dabt.sign, offset);
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
+ if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 1, gicd_reg - GICD_SPENDSGIR);
+ if ( rank == NULL) goto read_as_zero;
+ vgic_lock_rank(v, rank);
+ *r = byte_read(rank->pendsgi, dabt.sign, offset);
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ /* Implementation defined -- read as zero */
+ case REG(0xfd0) ... REG(0xfe4):
+ goto read_as_zero;
+
+ case GICD_ICPIDR2:
+ if ( dabt.size != 2 ) goto bad_width;
+ printk("vGICD: unhandled read from ICPIDR2\n");
+ return 0;
+
+ /* Implementation defined -- read as zero */
+ case REG(0xfec) ... REG(0xffc):
+ goto read_as_zero;
+
+ /* Reserved -- read as zero */
+ case REG(0x00c) ... REG(0x01c):
+ case REG(0x040) ... REG(0x07c):
+ case REG(0x7fc):
+ case REG(0xbfc):
+ case REG(0xf04) ... REG(0xf0c):
+ case REG(0xf30) ... REG(0xfcc):
+ goto read_as_zero;
+
+ default:
+ printk("vGICD: unhandled read r%d offset %#08x\n",
+ dabt.reg, offset);
+ return 0;
+ }
+
+bad_width:
+ printk("vGICD: bad read width %d r%d offset %#08x\n",
+ dabt.size, dabt.reg, offset);
+ domain_crash_synchronous();
+ return 0;
+
+read_as_zero:
+ if ( dabt.size != 2 ) goto bad_width;
+ *r = 0;
+ return 1;
+}
+
+static inline int is_vcpu_running(struct domain *d, int vcpuid)
+{
+ struct vcpu *v;
+
+ if ( vcpuid >= d->max_vcpus )
+ return 0;
+
+ v = d->vcpu[vcpuid];
+ if ( v == NULL )
+ return 0;
+ if (test_bit(_VPF_down, &v->pause_flags) )
+ return 0;
+
+ return 1;
+}
+
+static int vgic_to_sgi(struct vcpu *v, register_t sgir)
+{
+ struct domain *d = v->domain;
+ int virtual_irq;
+ int filter;
+ int vcpuid;
+ int i;
+ unsigned long vcpu_mask = 0;
+
+ ASSERT(d->max_vcpus < 8*sizeof(vcpu_mask));
+
+ filter = (sgir & GICD_SGI_TARGET_LIST_MASK);
+ virtual_irq = (sgir & GICD_SGI_INTID_MASK);
+ ASSERT( virtual_irq < 16 );
+
+ switch ( filter )
+ {
+ case GICD_SGI_TARGET_LIST:
+ vcpu_mask = (sgir & GICD_SGI_TARGET_MASK) >> GICD_SGI_TARGET_SHIFT;
+ break;
+ case GICD_SGI_TARGET_OTHERS:
+ for ( i = 0; i < d->max_vcpus; i++ )
+ {
+ if ( i != current->vcpu_id && is_vcpu_running(d, i) )
+ set_bit(i, &vcpu_mask);
+ }
+ break;
+ case GICD_SGI_TARGET_SELF:
+ set_bit(current->vcpu_id, &vcpu_mask);
+ break;
+ default:
+ gdprintk(XENLOG_WARNING, "vGICD: unhandled GICD_SGIR write
%"PRIregister" with wrong TargetListFilter field\n",
+ sgir);
+ return 0;
+ }
+
+ for_each_set_bit( vcpuid, &vcpu_mask, d->max_vcpus )
+ {
+ if ( !is_vcpu_running(d, vcpuid) )
+ {
+ gdprintk(XENLOG_WARNING, "vGICD: GICD_SGIR write r=%"PRIregister"
vcpu_mask=%lx, wrong CPUTargetList\n",
+ sgir, vcpu_mask);
+ continue;
+ }
+ vgic_vcpu_inject_irq(d->vcpu[vcpuid], virtual_irq, 1);
+ }
+ return 1;
+}
+
+static int vgic_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;
+ int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
+ int gicd_reg = REG(offset);
+ uint32_t tr;
+
+ switch ( gicd_reg )
+ {
+ case GICD_CTLR:
+ if ( dabt.size != 2 ) goto bad_width;
+ /* Ignore all but the enable bit */
+ v->domain->arch.vgic.ctlr = (*r) & GICD_CTL_ENABLE;
+ return 1;
+
+ /* R/O -- write ignored */
+ case GICD_TYPER:
+ case GICD_IIDR:
+ goto write_ignore;
+
+ /* Implementation defined -- write ignored */
+ case REG(0x020) ... REG(0x03c):
+ goto write_ignore;
+
+ 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 != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER);
+ if ( rank == NULL) goto write_ignore;
+ vgic_lock_rank(v, rank);
+ tr = rank->ienable;
+ rank->ienable |= *r;
+ vgic_unlock_rank(v, rank);
+ vgic_enable_irqs(v, (*r) & (~tr), gicd_reg - GICD_ISENABLER);
+ return 1;
+
+ case GICD_ICENABLER ... GICD_ICENABLERN:
+ if ( dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER);
+ if ( rank == NULL) goto write_ignore;
+ vgic_lock_rank(v, rank);
+ tr = rank->ienable;
+ rank->ienable &= ~*r;
+ vgic_unlock_rank(v, rank);
+ vgic_disable_irqs(v, (*r) & tr, gicd_reg - GICD_ICENABLER);
+ return 1;
+
+ case GICD_ISPENDR ... GICD_ISPENDRN:
+ if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+ printk("vGICD: unhandled %s write %#"PRIregister" to ISPENDR%d\n",
+ dabt.size ? "word" : "byte", *r, gicd_reg - GICD_ISPENDR);
+ return 0;
+
+ case GICD_ICPENDR ... GICD_ICPENDRN:
+ if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+ printk("vGICD: unhandled %s write %#"PRIregister" to ICPENDR%d\n",
+ dabt.size ? "word" : "byte", *r, gicd_reg - GICD_ICPENDR);
+ return 0;
+
+ case GICD_ISACTIVER ... GICD_ISACTIVERN:
+ if ( dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER);
+ if ( rank == NULL) goto write_ignore;
+ vgic_lock_rank(v, rank);
+ rank->iactive &= ~*r;
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_ICACTIVER ... GICD_ICACTIVERN:
+ if ( dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER);
+ if ( rank == NULL) goto write_ignore;
+ vgic_lock_rank(v, rank);
+ rank->iactive &= ~*r;
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_ITARGETSR ... GICD_ITARGETSR + 7:
+ /* SGI/PPI target is read only */
+ goto write_ignore;
+
+ case GICD_ITARGETSR + 8 ... GICD_ITARGETSRN:
+ if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 8, gicd_reg - GICD_ITARGETSR);
+ if ( rank == NULL) goto write_ignore;
+ vgic_lock_rank(v, rank);
+ if ( dabt.size == 2 )
+ rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)] = *r;
+ else
+ byte_write(&rank->itargets[REG_RANK_INDEX(8, gicd_reg -
GICD_ITARGETSR)],
+ *r, offset);
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
+ if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR);
+ if ( rank == NULL) goto write_ignore;
+ vgic_lock_rank(v, rank);
+ if ( dabt.size == 2 )
+ rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)] =
*r;
+ else
+ byte_write(&rank->ipriority[REG_RANK_INDEX(8, gicd_reg -
GICD_IPRIORITYR)],
+ *r, offset);
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_ICFGR: /* SGIs */
+ goto write_ignore;
+ case GICD_ICFGR + 1: /* PPIs */
+ /* It is implementation defined if these are writeable. We chose not */
+ goto write_ignore;
+ case GICD_ICFGR + 2 ... GICD_ICFGRN: /* SPIs */
+ if ( dabt.size != 2 ) goto bad_width;
+ rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR);
+ vgic_lock_rank(v, rank);
+ if ( rank == NULL) goto write_ignore;
+ rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)] = *r;
+ vgic_unlock_rank(v, rank);
+ return 1;
+
+ case GICD_NSACR ... GICD_NSACRN:
+ /* We do not implement security extensions for guests, write ignore */
+ goto write_ignore;
+
+ case GICD_SGIR:
+ if ( dabt.size != 2 )
+ goto bad_width;
+ return vgic_to_sgi(v, *r);
+
+ case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
+ if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+ printk("vGICD: unhandled %s write %#"PRIregister" to ICPENDSGIR%d\n",
+ dabt.size ? "word" : "byte", *r, gicd_reg - GICD_CPENDSGIR);
+ return 0;
+
+ case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
+ if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+ printk("vGICD: unhandled %s write %#"PRIregister" to ISPENDSGIR%d\n",
+ dabt.size ? "word" : "byte", *r, gicd_reg - GICD_SPENDSGIR);
+ return 0;
+
+ /* Implementation defined -- write ignored */
+ case REG(0xfd0) ... REG(0xfe4):
+ goto write_ignore;
+
+ /* R/O -- write ignore */
+ case GICD_ICPIDR2:
+ goto write_ignore;
+
+ /* Implementation defined -- write ignored */
+ case REG(0xfec) ... REG(0xffc):
+ goto write_ignore;
+
+ /* Reserved -- write ignored */
+ case REG(0x00c) ... REG(0x01c):
+ case REG(0x040) ... REG(0x07c):
+ case REG(0x7fc):
+ case REG(0xbfc):
+ case REG(0xf04) ... REG(0xf0c):
+ case REG(0xf30) ... REG(0xfcc):
+ goto write_ignore;
+
+ default:
+ printk("vGICD: unhandled write r%d=%"PRIregister" offset %#08x\n",
+ dabt.reg, *r, offset);
+ return 0;
+ }
+
+bad_width:
+ printk("vGICD: bad write width %d r%d=%"PRIregister" offset %#08x\n",
+ dabt.size, dabt.reg, *r, offset);
+ domain_crash_synchronous();
+ return 0;
+
+write_ignore:
+ if ( dabt.size != 2 ) goto bad_width;
+ return 1;
+}
+
+static int vgic_distr_mmio_check(struct vcpu *v, paddr_t addr)
+{
+ struct domain *d = v->domain;
+
+ return (addr >= (d->arch.vgic.dbase)) && (addr < (d->arch.vgic.dbase +
PAGE_SIZE));
+}
+
+static struct mmio_handler vgic_distr_mmio_handler = {
+ .check_handler = vgic_distr_mmio_check,
+ .read_handler = vgic_distr_mmio_read,
+ .write_handler = vgic_distr_mmio_write,
+};
+
+int vgic_v2_init(struct domain *d)
+{
+ int i;
+ struct vgic_irq_rank *r;
+
+ d->arch.vgic.shared_irqs =
+ (struct vgic_irq_rank *)xzalloc_array(struct vgic_irq_rank,
DOMAIN_NR_RANKS(d));
+
+ for (i=0; i<DOMAIN_NR_RANKS(d); i++) {
+ r = (struct vgic_irq_rank *)((unsigned char
*)(d->arch.vgic.shared_irqs)
+ + sizeof(struct vgic_irq_rank) * i);
+ spin_lock_init(&r->lock);
+ }
+ register_vgic_ops(&ops);
+
+ register_mmio_handler(&vgic_distr_mmio_handler);
+ 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 9c907b5..b60f012 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -31,57 +31,53 @@
#include <asm/gic_v2_defs.h>
#include <asm/gic.h>
-#define REG(n) (n/4)
-/* Number of ranks of interrupt registers for a domain */
-#define DOMAIN_NR_RANKS(d) (((d)->arch.vgic.nr_lines+31)/32)
+static struct vgic_ops *vgic_ops;
-/* Represents state corresponding to a block of 32 interrupts */
-struct vgic_irq_rank {
- spinlock_t lock; /* Covers access to all other members of this struct */
- uint32_t ienable, iactive, ipend, pendsgi;
- uint32_t icfg[2];
- uint32_t ipriority[8];
- uint32_t itargets[8];
-};
-
-/*
- * Rank containing GICD_<FOO><n> for GICD_<FOO> with
- * <b>-bits-per-interrupt
- */
-static inline int REG_RANK_NR(int b, uint32_t n)
+void register_vgic_ops(struct vgic_ops *ops)
{
- switch ( b )
- {
- case 8: return n >> 3;
- case 4: return n >> 2;
- case 2: return n >> 1;
- case 1: return n;
- default: BUG();
- }
+ vgic_ops = ops;
}
-/*
- * Offset of GICD_<FOO><n> with its rank, for GICD_<FOO> with
- * <b>-bits-per-interrupt.
- */
-#define REG_RANK_INDEX(b, n) ((n) & ((b)-1))
-
-/*
- * Returns rank corresponding to a GICD_<FOO><n> register for
- * GICD_<FOO> with <b>-bits-per-interrupt.
- */
-static struct vgic_irq_rank *vgic_irq_rank(struct vcpu *v, int b, int n)
+int domain_vgic_init(struct domain *d)
{
- int rank = REG_RANK_NR(b, n);
+ int i;
+
+ static const struct dt_device_match gicv2_ids[] __initconst =
+ {
+ DT_MATCH_GIC,
+ { /* sentinel */ },
+ };
+ struct dt_device_node *node;
+
+ d->arch.vgic.ctlr = 0;
- if ( rank == 0 )
- return (struct vgic_irq_rank *)v->arch.vgic.private_irqs;
- else if ( rank <= DOMAIN_NR_RANKS(v->domain) )
- return (struct vgic_irq_rank *)((unsigned char
*)(v->domain->arch.vgic.shared_irqs)
- + (sizeof(struct vgic_irq_rank) *(rank - 1)));
+ /* Currently nr_lines in vgic and gic doesn't have the same meanings
+ * Here nr_lines = number of SPIs
+ */
+ if ( d->domain_id == 0 )
+ d->arch.vgic.nr_lines = gic_number_lines() - 32;
else
- return NULL;
+ d->arch.vgic.nr_lines = 0; /* We don't need SPIs for the guest */
+
+ node = dt_find_interrupt_controller(gicv2_ids);
+ if ( node )
+ {
+ if (vgic_v2_init(d))
+ panic("vgic v2 initialization failed");
+ goto out;
+ }
+ if ( !node )
+ panic("Unable to find compatible vGIC");
+out:
+ d->arch.vgic.pending_irqs =
+ xzalloc_array(struct pending_irq, d->arch.vgic.nr_lines);
+ for (i=0; i<d->arch.vgic.nr_lines; i++)
+ {
+ INIT_LIST_HEAD(&d->arch.vgic.pending_irqs[i].inflight);
+ INIT_LIST_HEAD(&d->arch.vgic.pending_irqs[i].lr_queue);
+ }
+ return 0;
}
void domain_vgic_free(struct domain *d)
@@ -93,11 +89,11 @@ void domain_vgic_free(struct domain *d)
int vcpu_vgic_init(struct vcpu *v)
{
int i;
- struct vgic_irq_rank *vir;
- vir = xzalloc(struct vgic_irq_rank);
- memset(vir, 0, sizeof(struct vgic_irq_rank));
- spin_lock_init(&vir->lock);
+ if (vgic_ops)
+ vgic_ops->vgic_vcpu_init(v);
+ else
+ panic("No VGIC ops found\n");
memset(&v->arch.vgic.pending_irqs, 0, sizeof(v->arch.vgic.pending_irqs));
for (i = 0; i < 32; i++)
@@ -106,16 +102,6 @@ int vcpu_vgic_init(struct vcpu *v)
INIT_LIST_HEAD(&v->arch.vgic.pending_irqs[i].lr_queue);
}
- /* For SGI and PPI the target is always this CPU */
- for ( i = 0 ; i < 8 ; i++ )
- vir->itargets[i] =
- (1<<(v->vcpu_id+0))
- | (1<<(v->vcpu_id+8))
- | (1<<(v->vcpu_id+16))
- | (1<<(v->vcpu_id+24));
-
- v->arch.vgic.private_irqs = (struct vgic_irq_irank *)vir;
-
INIT_LIST_HEAD(&v->arch.vgic.inflight_irqs);
INIT_LIST_HEAD(&v->arch.vgic.lr_pending);
spin_lock_init(&v->arch.vgic.lock);
@@ -123,232 +109,7 @@ int vcpu_vgic_init(struct vcpu *v)
return 0;
}
-#define vgic_lock(v) spin_lock_irq(&(v)->domain->arch.vgic.lock)
-#define vgic_unlock(v) spin_unlock_irq(&(v)->domain->arch.vgic.lock)
-
-#define vgic_lock_rank(v, r) spin_lock(&(r)->lock)
-#define vgic_unlock_rank(v, r) spin_unlock(&(r)->lock)
-
-static uint32_t byte_read(uint32_t val, int sign, int offset)
-{
- int byte = offset & 0x3;
-
- val = val >> (8*byte);
- if ( sign && (val & 0x80) )
- val |= 0xffffff00;
- else
- val &= 0x000000ff;
- return val;
-}
-
-static void byte_write(uint32_t *reg, uint32_t var, int offset)
-{
- int byte = offset & 0x3;
-
- var &= (0xff << (8*byte));
-
- *reg &= ~(0xff << (8*byte));
- *reg |= var;
-}
-
-static int vgic_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;
- int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
- int gicd_reg = REG(offset);
-
- switch ( gicd_reg )
- {
- case GICD_CTLR:
- if ( dabt.size != 2 ) goto bad_width;
- vgic_lock(v);
- *r = v->domain->arch.vgic.ctlr;
- vgic_unlock(v);
- return 1;
- case GICD_TYPER:
- if ( dabt.size != 2 ) goto bad_width;
- /* No secure world support for guests. */
- vgic_lock(v);
- *r = ( (v->domain->max_vcpus<<5) & GICD_TYPE_CPUS )
- |( ((v->domain->arch.vgic.nr_lines/32)) & GICD_TYPE_LINES );
- vgic_unlock(v);
- return 1;
- case GICD_IIDR:
- if ( dabt.size != 2 ) goto bad_width;
- /*
- * XXX Do we need a JEP106 manufacturer ID?
- * Just use the physical h/w value for now
- */
- *r = 0x0000043b;
- return 1;
-
- /* Implementation defined -- read as zero */
- case REG(0x020) ... REG(0x03c):
- goto read_as_zero;
-
- 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 != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank);
- *r = rank->ienable;
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_ICENABLER ... GICD_ICENABLERN:
- if ( dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank);
- *r = rank->ienable;
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_ISPENDR ... GICD_ISPENDRN:
- if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISPENDR);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank);
- *r = byte_read(rank->ipend, dabt.sign, offset);
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_ICPENDR ... GICD_ICPENDRN:
- if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICPENDR);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank);
- *r = byte_read(rank->ipend, dabt.sign, offset);
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_ISACTIVER ... GICD_ISACTIVERN:
- if ( dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank);
- *r = rank->iactive;
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_ICACTIVER ... GICD_ICACTIVERN:
- if ( dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank);
- *r = rank->iactive;
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_ITARGETSR ... GICD_ITARGETSRN:
- if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 8, gicd_reg - GICD_ITARGETSR);
- if ( rank == NULL) goto read_as_zero;
-
- vgic_lock_rank(v, rank);
- *r = rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)];
- if ( dabt.size == 0 )
- *r = byte_read(*r, dabt.sign, offset);
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
- if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR);
- if ( rank == NULL) goto read_as_zero;
-
- vgic_lock_rank(v, rank);
- *r = rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)];
- if ( dabt.size == 0 )
- *r = byte_read(*r, dabt.sign, offset);
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_ICFGR ... GICD_ICFGRN:
- if ( dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank);
- *r = rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)];
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_NSACR ... GICD_NSACRN:
- /* We do not implement security extensions for guests, read zero */
- goto read_as_zero;
-
- case GICD_SGIR:
- if ( dabt.size != 2 ) goto bad_width;
- /* Write only -- read unknown */
- *r = 0xdeadbeef;
- return 1;
-
- case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
- if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 1, gicd_reg - GICD_CPENDSGIR);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank);
- *r = byte_read(rank->pendsgi, dabt.sign, offset);
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
- if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 1, gicd_reg - GICD_SPENDSGIR);
- if ( rank == NULL) goto read_as_zero;
- vgic_lock_rank(v, rank);
- *r = byte_read(rank->pendsgi, dabt.sign, offset);
- vgic_unlock_rank(v, rank);
- return 1;
-
- /* Implementation defined -- read as zero */
- case REG(0xfd0) ... REG(0xfe4):
- goto read_as_zero;
-
- case GICD_ICPIDR2:
- if ( dabt.size != 2 ) goto bad_width;
- printk("vGICD: unhandled read from ICPIDR2\n");
- return 0;
-
- /* Implementation defined -- read as zero */
- case REG(0xfec) ... REG(0xffc):
- goto read_as_zero;
-
- /* Reserved -- read as zero */
- case REG(0x00c) ... REG(0x01c):
- case REG(0x040) ... REG(0x07c):
- case REG(0x7fc):
- case REG(0xbfc):
- case REG(0xf04) ... REG(0xf0c):
- case REG(0xf30) ... REG(0xfcc):
- goto read_as_zero;
-
- default:
- printk("vGICD: unhandled read r%d offset %#08x\n",
- dabt.reg, offset);
- return 0;
- }
-
-bad_width:
- printk("vGICD: bad read width %d r%d offset %#08x\n",
- dabt.size, dabt.reg, offset);
- domain_crash_synchronous();
- return 0;
-
-read_as_zero:
- if ( dabt.size != 2 ) goto bad_width;
- *r = 0;
- return 1;
-}
-
-static void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
+void vgic_disable_irqs(struct vcpu *v, uint32_t r, int n)
{
const unsigned long mask = r;
struct pending_irq *p;
@@ -366,7 +127,7 @@ static void vgic_disable_irqs(struct vcpu *v, uint32_t r,
int n)
}
}
-static void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
+void vgic_enable_irqs(struct vcpu *v, uint32_t r, int n)
{
const unsigned long mask = r;
struct pending_irq *p;
@@ -382,310 +143,9 @@ static void vgic_enable_irqs(struct vcpu *v, uint32_t r,
int n)
if ( p->desc != NULL )
p->desc->handler->enable(p->desc);
i++;
- }
+ }
}
-static inline int is_vcpu_running(struct domain *d, int vcpuid)
-{
- struct vcpu *v;
-
- if ( vcpuid >= d->max_vcpus )
- return 0;
-
- v = d->vcpu[vcpuid];
- if ( v == NULL )
- return 0;
- if (test_bit(_VPF_down, &v->pause_flags) )
- return 0;
-
- return 1;
-}
-
-static int vgic_to_sgi(struct vcpu *v, register_t sgir)
-{
- struct domain *d = v->domain;
- int virtual_irq;
- int filter;
- int vcpuid;
- int i;
- unsigned long vcpu_mask = 0;
-
- ASSERT(d->max_vcpus < 8*sizeof(vcpu_mask));
-
- filter = (sgir & GICD_SGI_TARGET_LIST_MASK);
- virtual_irq = (sgir & GICD_SGI_INTID_MASK);
- ASSERT( virtual_irq < 16 );
-
- switch ( filter )
- {
- case GICD_SGI_TARGET_LIST:
- vcpu_mask = (sgir & GICD_SGI_TARGET_MASK) >> GICD_SGI_TARGET_SHIFT;
- break;
- case GICD_SGI_TARGET_OTHERS:
- for ( i = 0; i < d->max_vcpus; i++ )
- {
- if ( i != current->vcpu_id && is_vcpu_running(d, i) )
- set_bit(i, &vcpu_mask);
- }
- break;
- case GICD_SGI_TARGET_SELF:
- set_bit(current->vcpu_id, &vcpu_mask);
- break;
- default:
- gdprintk(XENLOG_WARNING, "vGICD: unhandled GICD_SGIR write
%"PRIregister" with wrong TargetListFilter field\n",
- sgir);
- return 0;
- }
-
- for_each_set_bit( vcpuid, &vcpu_mask, d->max_vcpus )
- {
- if ( !is_vcpu_running(d, vcpuid) )
- {
- gdprintk(XENLOG_WARNING, "vGICD: GICD_SGIR write r=%"PRIregister"
vcpu_mask=%lx, wrong CPUTargetList\n",
- sgir, vcpu_mask);
- continue;
- }
- vgic_vcpu_inject_irq(d->vcpu[vcpuid], virtual_irq, 1);
- }
- return 1;
-}
-
-static int vgic_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;
- int offset = (int)(info->gpa - v->domain->arch.vgic.dbase);
- int gicd_reg = REG(offset);
- uint32_t tr;
-
- switch ( gicd_reg )
- {
- case GICD_CTLR:
- if ( dabt.size != 2 ) goto bad_width;
- /* Ignore all but the enable bit */
- v->domain->arch.vgic.ctlr = (*r) & GICD_CTL_ENABLE;
- return 1;
-
- /* R/O -- write ignored */
- case GICD_TYPER:
- case GICD_IIDR:
- goto write_ignore;
-
- /* Implementation defined -- write ignored */
- case REG(0x020) ... REG(0x03c):
- goto write_ignore;
-
- 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 != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISENABLER);
- if ( rank == NULL) goto write_ignore;
- vgic_lock_rank(v, rank);
- tr = rank->ienable;
- rank->ienable |= *r;
- vgic_unlock_rank(v, rank);
- vgic_enable_irqs(v, (*r) & (~tr), gicd_reg - GICD_ISENABLER);
- return 1;
-
- case GICD_ICENABLER ... GICD_ICENABLERN:
- if ( dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICENABLER);
- if ( rank == NULL) goto write_ignore;
- vgic_lock_rank(v, rank);
- tr = rank->ienable;
- rank->ienable &= ~*r;
- vgic_unlock_rank(v, rank);
- vgic_disable_irqs(v, (*r) & tr, gicd_reg - GICD_ICENABLER);
- return 1;
-
- case GICD_ISPENDR ... GICD_ISPENDRN:
- if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
- printk("vGICD: unhandled %s write %#"PRIregister" to ISPENDR%d\n",
- dabt.size ? "word" : "byte", *r, gicd_reg - GICD_ISPENDR);
- return 0;
-
- case GICD_ICPENDR ... GICD_ICPENDRN:
- if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
- printk("vGICD: unhandled %s write %#"PRIregister" to ICPENDR%d\n",
- dabt.size ? "word" : "byte", *r, gicd_reg - GICD_ICPENDR);
- return 0;
-
- case GICD_ISACTIVER ... GICD_ISACTIVERN:
- if ( dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ISACTIVER);
- if ( rank == NULL) goto write_ignore;
- vgic_lock_rank(v, rank);
- rank->iactive &= ~*r;
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_ICACTIVER ... GICD_ICACTIVERN:
- if ( dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 1, gicd_reg - GICD_ICACTIVER);
- if ( rank == NULL) goto write_ignore;
- vgic_lock_rank(v, rank);
- rank->iactive &= ~*r;
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_ITARGETSR ... GICD_ITARGETSR + 7:
- /* SGI/PPI target is read only */
- goto write_ignore;
-
- case GICD_ITARGETSR + 8 ... GICD_ITARGETSRN:
- if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 8, gicd_reg - GICD_ITARGETSR);
- if ( rank == NULL) goto write_ignore;
- vgic_lock_rank(v, rank);
- if ( dabt.size == 2 )
- rank->itargets[REG_RANK_INDEX(8, gicd_reg - GICD_ITARGETSR)] = *r;
- else
- byte_write(&rank->itargets[REG_RANK_INDEX(8, gicd_reg -
GICD_ITARGETSR)],
- *r, offset);
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_IPRIORITYR ... GICD_IPRIORITYRN:
- if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 8, gicd_reg - GICD_IPRIORITYR);
- if ( rank == NULL) goto write_ignore;
- vgic_lock_rank(v, rank);
- if ( dabt.size == 2 )
- rank->ipriority[REG_RANK_INDEX(8, gicd_reg - GICD_IPRIORITYR)] =
*r;
- else
- byte_write(&rank->ipriority[REG_RANK_INDEX(8, gicd_reg -
GICD_IPRIORITYR)],
- *r, offset);
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_ICFGR: /* SGIs */
- goto write_ignore;
- case GICD_ICFGR + 1: /* PPIs */
- /* It is implementation defined if these are writeable. We chose not */
- goto write_ignore;
- case GICD_ICFGR + 2 ... GICD_ICFGRN: /* SPIs */
- if ( dabt.size != 2 ) goto bad_width;
- rank = vgic_irq_rank(v, 2, gicd_reg - GICD_ICFGR);
- vgic_lock_rank(v, rank);
- if ( rank == NULL) goto write_ignore;
- rank->icfg[REG_RANK_INDEX(2, gicd_reg - GICD_ICFGR)] = *r;
- vgic_unlock_rank(v, rank);
- return 1;
-
- case GICD_NSACR ... GICD_NSACRN:
- /* We do not implement security extensions for guests, write ignore */
- goto write_ignore;
-
- case GICD_SGIR:
- if ( dabt.size != 2 )
- goto bad_width;
- return vgic_to_sgi(v, *r);
-
- case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
- if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
- printk("vGICD: unhandled %s write %#"PRIregister" to ICPENDSGIR%d\n",
- dabt.size ? "word" : "byte", *r, gicd_reg - GICD_CPENDSGIR);
- return 0;
-
- case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
- if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
- printk("vGICD: unhandled %s write %#"PRIregister" to ISPENDSGIR%d\n",
- dabt.size ? "word" : "byte", *r, gicd_reg - GICD_SPENDSGIR);
- return 0;
-
- /* Implementation defined -- write ignored */
- case REG(0xfd0) ... REG(0xfe4):
- goto write_ignore;
-
- /* R/O -- write ignore */
- case GICD_ICPIDR2:
- goto write_ignore;
-
- /* Implementation defined -- write ignored */
- case REG(0xfec) ... REG(0xffc):
- goto write_ignore;
-
- /* Reserved -- write ignored */
- case REG(0x00c) ... REG(0x01c):
- case REG(0x040) ... REG(0x07c):
- case REG(0x7fc):
- case REG(0xbfc):
- case REG(0xf04) ... REG(0xf0c):
- case REG(0xf30) ... REG(0xfcc):
- goto write_ignore;
-
- default:
- printk("vGICD: unhandled write r%d=%"PRIregister" offset %#08x\n",
- dabt.reg, *r, offset);
- return 0;
- }
-
-bad_width:
- printk("vGICD: bad write width %d r%d=%"PRIregister" offset %#08x\n",
- dabt.size, dabt.reg, *r, offset);
- domain_crash_synchronous();
- return 0;
-
-write_ignore:
- if ( dabt.size != 2 ) goto bad_width;
- return 1;
-}
-
-static int vgic_distr_mmio_check(struct vcpu *v, paddr_t addr)
-{
- struct domain *d = v->domain;
-
- return (addr >= (d->arch.vgic.dbase)) && (addr < (d->arch.vgic.dbase +
PAGE_SIZE));
-}
-
-static struct mmio_handler vgic_distr_mmio_handler = {
- .check_handler = vgic_distr_mmio_check,
- .read_handler = vgic_distr_mmio_read,
- .write_handler = vgic_distr_mmio_write,
-};
-
-int domain_vgic_init(struct domain *d)
-{
- int i;
- struct vgic_irq_rank *r;
-
- d->arch.vgic.ctlr = 0;
-
- /* Currently nr_lines in vgic and gic doesn't have the same meanings
- * Here nr_lines = number of SPIs
- */
- if ( d->domain_id == 0 )
- d->arch.vgic.nr_lines = gic_number_lines() - 32;
- else
- d->arch.vgic.nr_lines = 0; /* We don't need SPIs for the guest */
-
- d->arch.vgic.shared_irqs =
- (struct vgic_irq_rank *)xzalloc_array(struct vgic_irq_rank,
DOMAIN_NR_RANKS(d));
-
- d->arch.vgic.pending_irqs =
- xzalloc_array(struct pending_irq, d->arch.vgic.nr_lines);
- for (i=0; i<d->arch.vgic.nr_lines; i++)
- {
- INIT_LIST_HEAD(&d->arch.vgic.pending_irqs[i].inflight);
- INIT_LIST_HEAD(&d->arch.vgic.pending_irqs[i].lr_queue);
- }
- for (i=0; i<DOMAIN_NR_RANKS(d); i++)
- {
- r = (struct vgic_irq_rank *)((unsigned char
*)(d->arch.vgic.shared_irqs)
- + sizeof(struct vgic_irq_rank) * i);
- spin_lock_init(&r->lock);
- }
-
- register_mmio_handler(&vgic_distr_mmio_handler);
- return 0;
-}
-
-
struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq)
{
struct pending_irq *n;
@@ -712,15 +172,13 @@ void vgic_clear_pending_irqs(struct vcpu *v)
void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq, int virtual)
{
- int idx = irq >> 2, byte = irq & 0x3;
uint8_t priority;
- struct vgic_irq_rank *rank = vgic_irq_rank(v, 8, idx);
- struct pending_irq *iter, *n = irq_to_pending(v, irq);
+ struct pending_irq *iter;
+ struct pending_irq *n = irq_to_pending(v, irq);
unsigned long flags;
bool_t running;
spin_lock_irqsave(&v->arch.vgic.lock, flags);
-
if ( !list_empty(&n->inflight) )
{
if ( (irq != current->domain->arch.evtchn_irq) ||
@@ -737,7 +195,7 @@ void vgic_vcpu_inject_irq(struct vcpu *v, unsigned int irq,
int virtual)
return;
}
- priority = byte_read(rank->ipriority[REG_RANK_INDEX(8, idx)], 0, byte);
+ priority = vgic_ops->read_priority(v, irq);
n->irq = irq;
set_bit(GIC_IRQ_GUEST_PENDING, &n->status);
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index 4244491..2de6c6a 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -54,6 +54,9 @@ extern void domain_vgic_free(struct domain *d);
extern int vcpu_vgic_init(struct vcpu *v);
extern int vcpu_gic_init(struct vcpu *v);
+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 int vgic_v2_init(struct domain *d);
extern void gicv2_init(void);
@@ -130,7 +133,13 @@ struct gic_hw_operations {
unsigned long (*read_cpu_sgi_rbase)(void);
};
+struct vgic_ops {
+ int (*vgic_vcpu_init)(struct vcpu *v);
+ int (*read_priority)(struct vcpu *v, int irq);
+};
+
extern void register_gic_ops(struct gic_hw_operations *);
+extern void register_vgic_ops(struct vgic_ops *ops);
extern void update_cpu_lr_mask(void);
extern void send_SGI_mask(const cpumask_t *cpumask, enum gic_sgi sgi);
--
1.7.9.5
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |