[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC PATCH v1 09/10] xen/arm: Add vgic support for GIC v3



From: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>

Add vgic driver support for GIC v3 version.

Signed-off-by: Vijaya Kumar K <Vijaya.Kumar@xxxxxxxxxxxxxxxxxx>
---
 xen/arch/arm/Makefile     |    2 +-
 xen/arch/arm/vgic-v3.c    |  927 +++++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/vgic.c       |   12 +
 xen/include/asm-arm/gic.h |    1 +
 4 files changed, 941 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index a11c699..5a6cb07 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 vgic-v2.o
+obj-y += vgic.o vgic-v2.o vgic-v3.o
 obj-y += vtimer.o
 obj-y += vuart.o
 obj-y += hvm.o
diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
new file mode 100644
index 0000000..b5c1d1e
--- /dev/null
+++ b/xen/arch/arm/vgic-v3.c
@@ -0,0 +1,927 @@
+/*
+ * 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 <asm/current.h>
+
+#include "io.h"
+#include <asm/gic-v3.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];
+    uint64_t irouter[32];
+};
+
+#define REG(n) (n)
+
+/* 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 64: return n >> 6;
+        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;
+        case 1: return n;
+        default: BUG();
+    }
+}
+
+/*
+ * Offset of GICD_<FOO><n> with its rank, for GICD_<FOO> with
+ * <b>-bits-per-interrupt.
+ */
+/* Shift n >> 2 to make it byte register diff */
+#define REG_RANK_INDEX(b, n) (((n) >> 2) & ((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;
+
+    n = n >> 2;
+    rank  = REG_RANK_NR(b, n);
+
+    if ( rank == 0 ) /* Rank 0 is nothing but GICR registers in GICv3 */
+        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;
+}
+
+#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_read_priority(struct vcpu *v, int irq)
+{
+   struct vgic_irq_rank *rank = vgic_irq_rank(v, 8, irq);
+   return byte_read(rank->ipriority[REG_RANK_INDEX(8, irq)], 0, irq & 0x3);
+}
+ 
+static int __vgic_rdistr_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);
+    int offset = (int)(info->gpa - gic_data_rdist_rd_base());
+    int gicr_reg = REG(offset);
+    u64 mpidr;
+    u64 aff;
+
+    switch ( gicr_reg )
+    {
+    case GICR_CTLR:
+        /* We have implemented LPI's, read zero */
+        goto read_as_zero;
+    case GICR_IIDR:
+        *r = 0x34;
+        return 1;
+    case GICR_TYPER:
+        if(((info->gpa) & (~((SZ_64K * 2 * smp_processor_id()) - 1))) ==
+            (gic_data_rdist_rd_base() & (~((SZ_64K * 2 * smp_processor_id()) - 
1))) )
+        {
+            mpidr = cpu_logical_map(smp_processor_id());
+            aff  = mpidr & ((1 << 24) - 1);
+            aff |= (mpidr >> 8) & (0xffUL << 24);
+            aff = aff << 32;
+            aff = (aff | ((u64)smp_processor_id() << 8));
+            aff = (aff | (0x9UL << 0));
+            *r = aff;
+            return 1;
+        }
+        *r = 0;
+        return 0;
+    case GICR_STATUSR:
+        /* Not implemented */
+        goto read_as_zero;
+    case GICR_WAKER:
+        /* Not implemented */
+        goto read_as_zero;
+    case GICR_SETLPIR:
+    case GICR_CLRLPIR:
+        /* WO */
+        return 0;
+    case GICR_PROPBASER:
+        /* LPI's not implemented */
+        goto read_as_zero;
+    case GICR_PENDBASER:
+        /* LPI's not implemented */
+        goto read_as_zero;
+    case GICR_INVLPIR:
+    case GICR_INVALLR:
+        /* WO */
+        return 0;
+    case GICR_SYNCR:
+        if ( dabt.size != 2 ) goto bad_width;
+        /* RO */
+        /* Return as not busy */
+        *r = 1;
+        return 1;
+    case GICR_MOVLPIR:
+    case GICR_MOVALLR:
+        /* WO */
+        return 0;
+    case GICR_PIDR7... GICR_PIDR0:
+        *r = 0x93;
+         return 1;
+    default:
+        printk("vGICR: read r%d offset %#08x\n not found", dabt.reg, offset);
+       
+    }
+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 int __vgic_rdistr_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);
+    int offset = (int)(info->gpa - gic_data_rdist_rd_base());
+    int gicr_reg = REG(offset);
+
+    switch ( gicr_reg )
+    {
+    case GICR_CTLR:
+        /* We do not implement LPI's, read zero */
+        goto write_ignore;
+    case GICR_IIDR:
+    case GICR_TYPER:
+        /* RO */
+        goto write_ignore;
+    case GICR_STATUSR:
+        /* Not implemented */
+        goto write_ignore;
+    case GICR_WAKER:
+        /* Not implemented */
+        goto write_ignore;
+    case GICR_SETLPIR:
+        return 1;
+    case GICR_CLRLPIR:
+        return 1;
+    case GICR_PROPBASER:
+        /* LPI is not implemented */
+        goto write_ignore;
+    case GICR_PENDBASER:
+        /* LPI is not implemented */
+        goto write_ignore;
+    case GICR_INVLPIR:
+        return 1;
+    case GICR_INVALLR:
+        return 1;
+    case GICR_SYNCR:
+        /* RO */
+        goto write_ignore;
+    case GICR_MOVLPIR:
+        return 1;
+    case GICR_MOVALLR:
+        return 1;
+    case GICR_PIDR7... GICR_PIDR0:
+        /* RO */
+        goto write_ignore;
+    default:
+        printk("vGICR: write r%d offset %#08x\n not found", dabt.reg, offset);
+    }
+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_rdistr_sgi_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 - gic_data_rdist_sgi_base());
+    int gicr_reg = REG(offset);
+
+    switch ( gicr_reg )
+    {
+    case GICR_IGROUPR0:
+        /* We do not implement security extensions for guests, read zero */
+        goto read_as_zero;
+    case GICR_IGRPMODR0:
+        /* We do not implement security extensions for guests, read zero */
+        goto read_as_zero;
+    case GICR_ISENABLER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ISENABLER0);
+        if ( rank == NULL ) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->ienable;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ICENABLER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ICENABLER0);
+        if ( rank == NULL ) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->ienable;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ISPENDR0:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ISPENDR0);
+        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 GICR_ICPENDR0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ICPENDR0);
+        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 GICR_ISACTIVER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ISACTIVER0);
+        if ( rank == NULL ) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->iactive;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ICACTIVER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ICACTIVER0);
+        if ( rank == NULL ) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->iactive;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_IPRIORITYR0...GICR_IPRIORITYR7:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 8, gicr_reg - GICR_IPRIORITYR0);
+        if ( rank == NULL ) goto read_as_zero;
+
+        vgic_lock_rank(v, rank);
+        *r = rank->ipriority[REG_RANK_INDEX(8, gicr_reg - GICR_IPRIORITYR0)];
+        if ( dabt.size == 0 )
+            *r = byte_read(*r, dabt.sign, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ICFGR0... GICR_ICFGR1:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 2, gicr_reg - GICR_ICFGR0);
+        if ( rank == NULL) goto read_as_zero;
+        vgic_lock_rank(v, rank);
+        *r = rank->icfg[REG_RANK_INDEX(2, gicr_reg - GICR_ICFGR0)];
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_NSACR:
+        if ( dabt.size != 2 ) goto bad_width;
+        return 1;
+    default:
+        printk("vGICR: read r%d offset %#08x\n not found", dabt.reg, offset);
+       
+    }
+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 int vgic_rdistr_sgi_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 - gic_data_rdist_sgi_base());
+    int gicr_reg = REG(offset);
+    uint32_t tr;
+
+    switch ( gicr_reg )
+    {
+    case GICR_IGROUPR0:
+        /* We do not implement security extensions for guests, write ignore */
+        goto write_ignore;
+    case GICR_IGRPMODR0:
+        /* We do not implement security extensions for guests, write ignore */
+        goto write_ignore;
+    case GICR_ISENABLER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ISENABLER0);
+        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), (gicr_reg - GICR_ISENABLER0) >> 2);
+        return 1;
+    case GICR_ICENABLER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ICENABLER0);
+        if ( rank == NULL ) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        rank->ienable &= ~*r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ISPENDR0:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        return 0;
+    case GICR_ICPENDR0:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        return 0;
+    case GICR_ISACTIVER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ISACTIVER0);
+        if ( rank == NULL ) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        rank->iactive &= ~*r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ICACTIVER0:
+        if ( dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 1, gicr_reg - GICR_ICACTIVER0);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        rank->iactive &= ~*r;
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_IPRIORITYR0...GICR_IPRIORITYR7:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        rank = vgic_irq_rank(v, 8, gicr_reg - GICR_IPRIORITYR0);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        if ( dabt.size == 2 )
+            rank->ipriority[REG_RANK_INDEX(8, gicr_reg - GICR_IPRIORITYR0)] = 
*r;
+        else
+            byte_write(&rank->ipriority[REG_RANK_INDEX(8, gicr_reg - 
GICR_IPRIORITYR0)],
+                       *r, offset);
+        vgic_unlock_rank(v, rank);
+        return 1;
+    case GICR_ICFGR0:
+        /* RO */
+    case GICR_ICFGR1:
+        goto write_ignore;
+    case GICR_NSACR:
+        /* We do not implement security extensions for guests, write ignore */
+        goto write_ignore;
+    default:
+        printk("vGICR: write r%d offset %#08x\n not found", dabt.reg, offset);
+    }
+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_rdistr_mmio_read(struct vcpu *v, mmio_info_t *info)
+{
+    uint32_t offset = info->gpa - gic_data_rdist_rd_base();
+    uint32_t sgi_offset = info->gpa - gic_data_rdist_sgi_base();
+
+    if ( offset < SZ_64K)
+       return __vgic_rdistr_mmio_read(v, info);
+    else if (sgi_offset < SZ_64K)
+       return vgic_rdistr_sgi_mmio_read(v, info);
+    else 
+       printk("vGICR: wrong gpa read %"PRIpaddr"\n",info->gpa);
+    return 0;
+}
+      
+static int vgic_rdistr_mmio_write(struct vcpu *v, mmio_info_t *info)
+{
+    uint32_t offset = info->gpa - gic_data_rdist_rd_base();
+    uint32_t sgi_offset = info->gpa - gic_data_rdist_sgi_base();
+
+    if (offset < SZ_64K)
+       return __vgic_rdistr_mmio_write(v, info);
+    else if (sgi_offset < SZ_64K)
+       return vgic_rdistr_sgi_mmio_write(v, info);
+    else
+       printk("vGICR: wrong gpa write %"PRIpaddr"\n",info->gpa);
+    return 0;
+}
+
+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_STATUSR:
+        /* Not implemented */
+        goto read_as_zero;
+    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 = 0x0000034c;
+        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_IROUTER ... GICD_IROUTERN:
+        rank = vgic_irq_rank(v, 64, gicd_reg - GICD_IROUTERN);
+        if ( rank == NULL) goto read_as_zero;
+
+        vgic_lock_rank(v, rank);
+        /* IROUTER is 64 bit so, to make it byte size right shift by 3. 
+           Here once. macro REG_RANK_INDEX will do it twice */
+        *r = rank->irouter[REG_RANK_INDEX(64, (gicd_reg - GICD_IROUTER)>>1)];
+        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;
+    case GICD_PIDR7... GICD_PIDR0:
+        /* GICv3 identification value */
+        *r = 0x92;
+        return 1;
+    case REG(0x00c):
+    case REG(0x044):
+    case REG(0x04c):
+    case REG(0x05c) ... REG(0x07c):
+    case REG(0xf30) ... REG(0x5fcc):
+    case REG(0x8000) ... REG(0xbfcc):
+    case REG(0xc000) ... REG(0xffcc):
+       printk("vGICD: read unknown 0x00c .. 0xfcc r%d offset %#08x\n", 
dabt.reg, offset);
+        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:
+    printk("vGICD: read as zero %d r%d offset %#08x\n",
+           dabt.size, dabt.reg, offset);
+    if ( dabt.size != 2 ) goto bad_width;
+    *r = 0;
+    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;
+
+    case GICD_STATUSR:
+        goto write_ignore;
+    case GICD_SETSPI_NSR:
+        goto write_ignore;
+    case GICD_CLRSPI_NSR:
+        goto write_ignore;
+    case GICD_SETSPI_SR:
+        goto write_ignore;
+    case GICD_CLRSPI_SR:
+        goto write_ignore;
+    /* Implementation defined -- write ignored */
+    case REG(0x020) ... REG(0x03c):
+       printk("vGICD: write unknown 0x020 - 0x03c r%d offset %#08x\n", 
dabt.reg, offset);
+        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) >> 2);
+        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;
+        return 0;
+
+    case GICD_ICPENDR ... GICD_ICPENDRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        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_IROUTER ... GICD_IROUTER + 8*7:
+        /* SGI/PPI target is read only */
+        goto write_ignore;
+
+    case GICD_IROUTER + 8*8 ... GICD_IROUTERN:
+        rank = vgic_irq_rank(v, 64, gicd_reg - GICD_IROUTER);
+        if ( rank == NULL) goto write_ignore;
+        vgic_lock_rank(v, rank);
+        rank->irouter[REG_RANK_INDEX(64, (gicd_reg - GICD_IROUTER)>>1)] = *r;
+        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 + 4: /* PPIs */
+        /* It is implementation defined if these are writeable. We chose not */
+        goto write_ignore;
+    case GICD_ICFGR + 8 ... 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:
+        /* it is accessed as system register */
+        goto write_ignore;
+
+    case GICD_CPENDSGIR ... GICD_CPENDSGIRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        return 0;
+
+    case GICD_SPENDSGIR ... GICD_SPENDSGIRN:
+        if ( dabt.size != 0 && dabt.size != 2 ) goto bad_width;
+        return 0;
+
+    case REG(0x00c):
+    case REG(0x044):
+    case REG(0x04c):
+    case REG(0x05c) ... REG(0x07c):
+    case REG(0xf30) ... REG(0x5fcc):
+    case REG(0x8000) ... REG(0xbfcc):
+    case REG(0xc000) ... REG(0xffcc):
+       printk("vGICD: write unknown 0x00c 0xfcc  r%d offset %#08x\n", 
dabt.reg, offset);
+        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_rdistr_mmio_check(struct vcpu *v, paddr_t addr)
+{
+    struct domain *d = v->domain;
+
+    /* Compare with global rdist base. the addr should fall in this region */
+    return (addr >= (d->arch.vgic.rbase)) && (addr < (d->arch.vgic.rbase + 
d->arch.vgic.rbase_size));
+}
+
+static struct mmio_handler vgic_rdistr_mmio_handler = {
+    .check_handler = vgic_rdistr_mmio_check,
+    .read_handler  = vgic_rdistr_mmio_read,
+    .write_handler = vgic_rdistr_mmio_write,
+};
+
+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 + 
d->arch.vgic.dbase_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,
+};
+
+
+static int vgic_vcpu_init(struct vcpu *v)
+{
+    int i;
+    u64 affinity;
+    struct vgic_irq_rank *vir;
+
+    vir =  xzalloc(struct vgic_irq_rank);
+
+    memset(vir, 0, sizeof(struct vgic_irq_rank));
+
+    spin_lock_init(&vir->lock);
+
+    v->arch.vgic.private_irqs = (struct vgic_irq_irank *)vir;
+
+    /* For SGI and PPI the target is always this CPU */
+    affinity = cpu_logical_map(v->vcpu_id);
+    for ( i = 0 ; i < 32 ; i++ )
+        ((struct vgic_irq_rank *)(v->arch.vgic.private_irqs))->irouter[i] = 
affinity;
+    return 0;
+}
+
+static struct vgic_ops ops = {
+    .vgic_vcpu_init   = vgic_vcpu_init,
+    .read_priority = vgic_read_priority,
+};
+
+int vgic_v3_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);
+    register_mmio_handler(&vgic_rdistr_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 b60f012..79b9587 100644
--- a/xen/arch/arm/vgic.c
+++ b/xen/arch/arm/vgic.c
@@ -43,6 +43,11 @@ int domain_vgic_init(struct domain *d)
 {
     int i;
 
+    static const struct dt_device_match gicv3_ids[] __initconst =
+    {
+        DT_MATCH_GIC_V3,
+        { /* sentinel */ },
+    };
     static const struct dt_device_match gicv2_ids[] __initconst =
     {
         DT_MATCH_GIC,
@@ -60,6 +65,13 @@ int domain_vgic_init(struct domain *d)
     else
         d->arch.vgic.nr_lines = 0; /* We don't need SPIs for the guest */
 
+    node = dt_find_interrupt_controller(gicv3_ids);
+    if ( node )
+    {
+        if (vgic_v3_init(d))
+            panic("vgic v3 initialization failed");
+        goto out;
+    }
     node = dt_find_interrupt_controller(gicv2_ids);
     if ( node )
     {
diff --git a/xen/include/asm-arm/gic.h b/xen/include/asm-arm/gic.h
index b6fbd5e..0bce7f5 100644
--- a/xen/include/asm-arm/gic.h
+++ b/xen/include/asm-arm/gic.h
@@ -60,6 +60,7 @@ 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_v3_init(struct domain *d);
 extern int vgic_v2_init(struct domain *d);
 
 extern void gicv3_init(void);
-- 
1.7.9.5


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.