Mailing List Archive

[PATCH RFC 15/25] arm: driver for CoreLink GIC-400 Generic Interrupt Controller
From: Stefano Stabellini <stefano.stabellini@eu.citrix.com>

- GICC, GICD and GICH initialization;

- interrupts routing, acking and EOI;

- interrupt injection into guests;

- maintenance interrupt handler, that takes care of EOI physical
interrupts on behalf of the guest;

- a function to remap the virtual cpu interface into the guest address
space, where the guest expect the GICC to be.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Signed-off-by: Tim Deegan <Tim.Deegan@citrix.com>
---
xen/arch/arm/Makefile | 1 +
xen/arch/arm/domain.c | 2 +
xen/arch/arm/gic.c | 473 +++++++++++++++++++++++++++++++++++++++++++++++++
xen/arch/arm/gic.h | 151 ++++++++++++++++
4 files changed, 627 insertions(+), 0 deletions(-)
create mode 100644 xen/arch/arm/gic.c
create mode 100644 xen/arch/arm/gic.h

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 28faa73..cd196c3 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -4,6 +4,7 @@ obj-y += dummy.o
obj-y += entry.o
obj-y += domain.o
obj-y += domain_build.o
+obj-y += gic.o

#obj-bin-y += ....o

diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
index d706b5f..ecbc5b7 100644
--- a/xen/arch/arm/domain.c
+++ b/xen/arch/arm/domain.c
@@ -11,6 +11,8 @@
#include <asm/p2m.h>
#include <asm/irq.h>

+#include "gic.h"
+
DEFINE_PER_CPU(struct vcpu *, curr_vcpu);

static void continue_idle_domain(struct vcpu *v)
diff --git a/xen/arch/arm/gic.c b/xen/arch/arm/gic.c
new file mode 100644
index 0000000..9643a7d
--- /dev/null
+++ b/xen/arch/arm/gic.c
@@ -0,0 +1,473 @@
+/*
+ * xen/arch/arm/gic.c
+ *
+ * ARM Generic Interrupt Controller support
+ *
+ * Tim Deegan <tim@xen.org>
+ * 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/config.h>
+#include <xen/lib.h>
+#include <xen/init.h>
+#include <xen/mm.h>
+#include <xen/irq.h>
+#include <xen/sched.h>
+#include <xen/errno.h>
+#include <xen/softirq.h>
+#include <asm/p2m.h>
+#include <asm/domain.h>
+
+#include "gic.h"
+
+/* Access to the GIC Distributor registers through the fixmap */
+#define GICD ((volatile uint32_t *) FIXMAP_ADDR(FIXMAP_GICD))
+#define GICC ((volatile uint32_t *) (FIXMAP_ADDR(FIXMAP_GICC1) \
+ + (GIC_CR_OFFSET & 0xfff)))
+#define GICH ((volatile uint32_t *) (FIXMAP_ADDR(FIXMAP_GICH) \
+ + (GIC_HR_OFFSET & 0xfff)))
+
+/* Global state */
+static struct {
+ paddr_t dbase; /* Address of distributor registers */
+ paddr_t cbase; /* Address of CPU interface registers */
+ paddr_t hbase; /* Address of virtual interface registers */
+ unsigned int lines;
+ unsigned int cpus;
+ spinlock_t lock;
+} gic;
+
+irq_desc_t irq_desc[NR_IRQS];
+unsigned nr_lrs;
+
+static unsigned int gic_irq_startup(struct irq_desc *desc)
+{
+ uint32_t enabler;
+ int irq = desc->irq;
+
+ /* Enable routing */
+ enabler = GICD[GICD_ISENABLER + irq / 32];
+ GICD[GICD_ISENABLER + irq / 32] = enabler | (1u << (irq % 32));
+
+ return 0;
+}
+
+static void gic_irq_shutdown(struct irq_desc *desc)
+{
+ uint32_t enabler;
+ int irq = desc->irq;
+
+ /* Disable routing */
+ enabler = GICD[GICD_ICENABLER + irq / 32];
+ GICD[GICD_ICENABLER + irq / 32] = enabler | (1u << (irq % 32));
+}
+
+static void gic_irq_enable(struct irq_desc *desc)
+{
+
+}
+
+static void gic_irq_disable(struct irq_desc *desc)
+{
+
+}
+
+static void gic_irq_ack(struct irq_desc *desc)
+{
+ /* No ACK -- reading IAR has done this for us */
+}
+
+static void gic_host_irq_end(struct irq_desc *desc)
+{
+ int irq = desc->irq;
+ /* Lower the priority */
+ GICC[GICC_EOIR] = irq;
+ /* Deactivate */
+ GICC[GICC_DIR] = irq;
+}
+
+static void gic_guest_irq_end(struct irq_desc *desc)
+{
+ int irq = desc->irq;
+ /* Lower the priority of the IRQ */
+ GICC[GICC_EOIR] = irq;
+ /* Deactivation happens in maintenance interrupt / via GICV */
+}
+
+static void gic_irq_set_affinity(struct irq_desc *desc, const cpumask_t *mask)
+{
+ BUG();
+}
+
+/* XXX different for level vs edge */
+static hw_irq_controller gic_host_irq_type = {
+ .typename = "gic",
+ .startup = gic_irq_startup,
+ .shutdown = gic_irq_shutdown,
+ .enable = gic_irq_enable,
+ .disable = gic_irq_disable,
+ .ack = gic_irq_ack,
+ .end = gic_host_irq_end,
+ .set_affinity = gic_irq_set_affinity,
+};
+static hw_irq_controller gic_guest_irq_type = {
+ .typename = "gic",
+ .startup = gic_irq_startup,
+ .shutdown = gic_irq_shutdown,
+ .enable = gic_irq_enable,
+ .disable = gic_irq_disable,
+ .ack = gic_irq_ack,
+ .end = gic_guest_irq_end,
+ .set_affinity = gic_irq_set_affinity,
+};
+
+/* Program the GIC to route an interrupt */
+static int gic_route_irq(unsigned int irq, bool_t level,
+ unsigned int cpu_mask, unsigned int priority)
+{
+ volatile unsigned char *bytereg;
+ uint32_t cfg, edgebit;
+ struct irq_desc *desc = irq_to_desc(irq);
+ unsigned long flags;
+
+ ASSERT(!(cpu_mask & ~0xff)); /* Targets bitmap only supports 8 CPUs */
+ ASSERT(priority <= 0xff); /* Only 8 bits of priority */
+ ASSERT(irq < gic.lines + 32); /* Can't route interrupts that don't exist */
+
+ spin_lock_irqsave(&desc->lock, flags);
+ spin_lock(&gic.lock);
+
+ if ( desc->action != NULL )
+ {
+ spin_unlock(&desc->lock);
+ return -EBUSY;
+ }
+
+ desc->handler = &gic_host_irq_type;
+
+ /* Disable interrupt */
+ desc->handler->shutdown(desc);
+
+ /* Set edge / level */
+ cfg = GICD[GICD_ICFGR + irq / 16];
+ edgebit = 2u << (2 * (irq % 16));
+ if ( level )
+ cfg &= ~edgebit;
+ else
+ cfg |= edgebit;
+ GICD[GICD_ICFGR + irq / 16] = cfg;
+
+ /* Set target CPU mask (RAZ/WI on uniprocessor) */
+ bytereg = (unsigned char *) (GICD + GICD_ITARGETSR);
+ bytereg[irq] = cpu_mask;
+
+ /* Set priority */
+ bytereg = (unsigned char *) (GICD + GICD_IPRIORITYR);
+ bytereg[irq] = priority;
+
+ spin_unlock(&gic.lock);
+ spin_unlock_irqrestore(&desc->lock, flags);
+ return 0;
+}
+
+static void __init gic_dist_init(void)
+{
+ uint32_t type;
+ uint32_t cpumask = 1 << smp_processor_id();
+ int i;
+
+ cpumask |= cpumask << 8;
+ cpumask |= cpumask << 16;
+
+ /* Disable the distributor */
+ GICD[GICD_CTLR] = 0;
+
+ type = GICD[GICD_TYPER];
+ gic.lines = 32 * (type & GICD_TYPE_LINES);
+ gic.cpus = 1 + ((type & GICD_TYPE_CPUS) >> 5);
+ printk("GIC: %d lines, %d cpu%s%s (IID %8.8x).\n",
+ gic.lines, gic.cpus, (gic.cpus == 1) ? "" : "s",
+ (type & GICD_TYPE_SEC) ? ", secure" : "",
+ GICD[GICD_IIDR]);
+
+ /* Default all global IRQs to level, active low */
+ for ( i = 32; i < gic.lines; i += 16 )
+ GICD[GICD_ICFGR + i / 16] = 0x0;
+
+ /* Route all global IRQs to this CPU */
+ for ( i = 32; i < gic.lines; i += 4 )
+ GICD[GICD_ICFGR + i / 4] = cpumask;
+
+ /* Default priority for global interrupts */
+ for ( i = 32; i < gic.lines; i += 4 )
+ GICD[GICD_IPRIORITYR + i / 4] = 0xa0a0a0a0;
+
+ /* Disable all global interrupts */
+ for ( i = 32; i < gic.lines; i += 32 )
+ GICD[GICD_ICENABLER + i / 32] = ~0ul;
+
+ /* Turn on the distributor */
+ GICD[GICD_CTLR] = GICD_CTL_ENABLE;
+}
+
+static void __cpuinit gic_cpu_init(void)
+{
+ int i;
+
+ /* Disable all PPI and enable all SGI */
+ GICD[GICD_ICENABLER] = 0xffff0000; /* Disable all PPI */
+ GICD[GICD_ISENABLER] = 0x0000ffff; /* Enable all SGI */
+ /* Set PPI and SGI priorities */
+ for (i = 0; i < 32; i += 4)
+ GICD[GICD_IPRIORITYR + i / 4] = 0xa0a0a0a0;
+
+ /* Local settings: interface controller */
+ GICC[GICC_PMR] = 0xff; /* Don't mask by priority */
+ GICC[GICC_BPR] = 0; /* Finest granularity of priority */
+ GICC[GICC_CTLR] = GICC_CTL_ENABLE|GICC_CTL_EOI; /* Turn on delivery */
+}
+
+static void __cpuinit gic_hyp_init(void)
+{
+ uint32_t vtr;
+
+ vtr = GICH[GICH_VTR];
+ nr_lrs = (vtr & GICH_VTR_NRLRGS) + 1;
+ printk("GICH: %d list registers available\n", nr_lrs);
+
+ GICH[GICH_HCR] = GICH_HCR_EN;
+ GICH[GICH_MISR] = GICH_MISR_EOI;
+}
+
+/* Set up the GIC */
+void gic_init(void)
+{
+ /* XXX FIXME get this from devicetree */
+ gic.dbase = GIC_BASE_ADDRESS + GIC_DR_OFFSET;
+ gic.cbase = GIC_BASE_ADDRESS + GIC_CR_OFFSET;
+ gic.hbase = GIC_BASE_ADDRESS + GIC_HR_OFFSET;
+ set_fixmap(FIXMAP_GICD, gic.dbase >> PAGE_SHIFT, DEV_SHARED);
+ BUILD_BUG_ON(FIXMAP_ADDR(FIXMAP_GICC1) !=
+ FIXMAP_ADDR(FIXMAP_GICC2)-PAGE_SIZE);
+ set_fixmap(FIXMAP_GICC1, gic.cbase >> PAGE_SHIFT, DEV_SHARED);
+ set_fixmap(FIXMAP_GICC2, (gic.cbase >> PAGE_SHIFT) + 1, DEV_SHARED);
+ set_fixmap(FIXMAP_GICH, gic.hbase >> PAGE_SHIFT, DEV_SHARED);
+
+ /* Global settings: interrupt distributor */
+ spin_lock_init(&gic.lock);
+ spin_lock(&gic.lock);
+
+ gic_dist_init();
+ gic_cpu_init();
+ gic_hyp_init();
+
+ spin_unlock(&gic.lock);
+}
+
+void gic_route_irqs(void)
+{
+ /* XXX should get these from DT */
+ /* GIC maintenance */
+ gic_route_irq(25, 1, 1u << smp_processor_id(), 0xa0);
+ /* Hypervisor Timer */
+ gic_route_irq(26, 1, 1u << smp_processor_id(), 0xa0);
+ /* Timer */
+ gic_route_irq(30, 1, 1u << smp_processor_id(), 0xa0);
+ /* UART */
+ gic_route_irq(37, 0, 1u << smp_processor_id(), 0xa0);
+}
+
+void __init release_irq(unsigned int irq)
+{
+ struct irq_desc *desc;
+ unsigned long flags;
+ struct irqaction *action;
+
+ desc = irq_to_desc(irq);
+
+ spin_lock_irqsave(&desc->lock,flags);
+ action = desc->action;
+ desc->action = NULL;
+ desc->status |= IRQ_DISABLED;
+
+ spin_lock(&gic.lock);
+ desc->handler->shutdown(desc);
+ spin_unlock(&gic.lock);
+
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+ /* Wait to make sure it's not being used on another CPU */
+ do { smp_mb(); } while ( desc->status & IRQ_INPROGRESS );
+
+ if (action && action->free_on_release)
+ xfree(action);
+}
+
+static int __setup_irq(struct irq_desc *desc, unsigned int irq,
+ struct irqaction *new)
+{
+ if ( desc->action != NULL )
+ return -EBUSY;
+
+ desc->action = new;
+ desc->status &= ~IRQ_DISABLED;
+ dsb();
+
+ desc->handler->startup(desc);
+
+ return 0;
+}
+
+int __init setup_irq(unsigned int irq, struct irqaction *new)
+{
+ int rc;
+ unsigned long flags;
+ struct irq_desc *desc;
+
+ desc = irq_to_desc(irq);
+
+ spin_lock_irqsave(&desc->lock, flags);
+
+ rc = __setup_irq(desc, irq, new);
+
+ spin_unlock_irqrestore(&desc->lock,flags);
+
+ return rc;
+}
+
+void gic_set_guest_irq(unsigned int virtual_irq,
+ unsigned int state, unsigned int priority)
+{
+ BUG_ON(virtual_irq > nr_lrs);
+ GICH[GICH_LR + virtual_irq] = state |
+ GICH_LR_MAINTENANCE_IRQ |
+ ((priority >> 3) << GICH_LR_PRIORITY_SHIFT) |
+ ((virtual_irq & GICH_LR_VIRTUAL_MASK) << GICH_LR_VIRTUAL_SHIFT);
+}
+
+void gic_inject_irq_start(void)
+{
+ uint32_t hcr;
+ hcr = READ_CP32(HCR);
+ WRITE_CP32(hcr | HCR_VI, HCR);
+ isb();
+}
+
+void gic_inject_irq_stop(void)
+{
+ uint32_t hcr;
+ hcr = READ_CP32(HCR);
+ if (hcr & HCR_VI) {
+ WRITE_CP32(hcr & ~HCR_VI, HCR);
+ isb();
+ }
+}
+
+int gic_route_irq_to_guest(struct domain *d, unsigned int irq,
+ const char * devname)
+{
+ struct irqaction *action;
+ struct irq_desc *desc = irq_to_desc(irq);
+ unsigned long flags;
+ int retval;
+
+ action = xmalloc(struct irqaction);
+ if (!action)
+ return -ENOMEM;
+
+ action->dev_id = d;
+ action->name = devname;
+
+ spin_lock_irqsave(&desc->lock, flags);
+
+ desc->handler = &gic_guest_irq_type;
+ desc->status |= IRQ_GUEST;
+
+ retval = __setup_irq(desc, irq, action);
+ if (retval) {
+ xfree(action);
+ goto out;
+ }
+
+out:
+ spin_unlock_irqrestore(&desc->lock, flags);
+ return retval;
+}
+
+/* Accept an interrupt from the GIC and dispatch its handler */
+void gic_interrupt(struct cpu_user_regs *regs, int is_fiq)
+{
+ uint32_t intack = GICC[GICC_IAR];
+ unsigned int irq = intack & GICC_IA_IRQ;
+
+ if ( irq == 1023 )
+ /* Spurious interrupt */
+ return;
+
+ do_IRQ(regs, irq, is_fiq);
+}
+
+void gicv_setup(struct domain *d)
+{
+ /* map the gic virtual cpu interface in the gic cpu interface region of
+ * the guest */
+ printk("mapping GICC at %#"PRIx32" to %#"PRIx32"\n",
+ GIC_BASE_ADDRESS + GIC_CR_OFFSET,
+ GIC_BASE_ADDRESS + GIC_VR_OFFSET);
+ map_mmio_regions(d, GIC_BASE_ADDRESS + GIC_CR_OFFSET,
+ GIC_BASE_ADDRESS + GIC_CR_OFFSET + (2 * PAGE_SIZE) - 1,
+ GIC_BASE_ADDRESS + GIC_VR_OFFSET);
+}
+
+static void maintenance_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
+{
+ int i, virq;
+ uint32_t lr;
+ uint64_t eisr = GICH[GICH_EISR0] | (((uint64_t) GICH[GICH_EISR1]) << 32);
+
+ for ( i = 0; i < 64; i++ ) {
+ if ( eisr & ((uint64_t)1 << i) ) {
+ struct pending_irq *p;
+
+ lr = GICH[GICH_LR + i];
+ virq = lr & GICH_LR_VIRTUAL_MASK;
+ GICH[GICH_LR + i] = 0;
+
+ spin_lock(&current->arch.vgic.lock);
+ p = irq_to_pending(current, virq);
+ if ( p->desc != NULL ) {
+ p->desc->status &= ~IRQ_INPROGRESS;
+ GICC[GICC_DIR] = virq;
+ }
+ gic_inject_irq_stop();
+ list_del(&p->link);
+ INIT_LIST_HEAD(&p->link);
+ cpu_raise_softirq(current->processor, VGIC_SOFTIRQ);
+ spin_unlock(&current->arch.vgic.lock);
+ }
+ }
+}
+
+void __cpuinit init_maintenance_interrupt(void)
+{
+ request_irq(25, maintenance_interrupt, 0, "irq-maintenance", NULL);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/gic.h b/xen/arch/arm/gic.h
new file mode 100644
index 0000000..63b6648
--- /dev/null
+++ b/xen/arch/arm/gic.h
@@ -0,0 +1,151 @@
+/*
+ * xen/arch/arm/gic.h
+ *
+ * ARM Generic Interrupt Controller support
+ *
+ * Tim Deegan <tim@xen.org>
+ * 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.
+ */
+
+#ifndef __ARCH_ARM_GIC_H__
+#define __ARCH_ARM_GIC_H__
+
+#define GICD_CTLR (0x000/4)
+#define GICD_TYPER (0x004/4)
+#define GICD_IIDR (0x008/4)
+#define GICD_IGROUPR (0x080/4)
+#define GICD_IGROUPRN (0x0FC/4)
+#define GICD_ISENABLER (0x100/4)
+#define GICD_ISENABLERN (0x17C/4)
+#define GICD_ICENABLER (0x180/4)
+#define GICD_ICENABLERN (0x1fC/4)
+#define GICD_ISPENDR (0x200/4)
+#define GICD_ISPENDRN (0x27C/4)
+#define GICD_ICPENDR (0x280/4)
+#define GICD_ICPENDRN (0x2FC/4)
+#define GICD_ISACTIVER (0x300/4)
+#define GICD_ISACTIVERN (0x37C/4)
+#define GICD_ICACTIVER (0x380/4)
+#define GICD_ICACTIVERN (0x3FC/4)
+#define GICD_IPRIORITYR (0x400/4)
+#define GICD_IPRIORITYRN (0x7F8/4)
+#define GICD_ITARGETSR (0x800/4)
+#define GICD_ITARGETSRN (0xBF8/4)
+#define GICD_ICFGR (0xC00/4)
+#define GICD_ICFGRN (0xCFC/4)
+#define GICD_NSACR (0xE00/4)
+#define GICD_NSACRN (0xEFC/4)
+#define GICD_ICPIDR2 (0xFE8/4)
+#define GICD_SGIR (0xF00/4)
+#define GICD_CPENDSGIR (0xF10/4)
+#define GICD_CPENDSGIRN (0xF1C/4)
+#define GICD_SPENDSGIR (0xF20/4)
+#define GICD_SPENDSGIRN (0xF2C/4)
+#define GICD_ICPIDR2 (0xFE8/4)
+
+#define GICC_CTLR (0x0000/4)
+#define GICC_PMR (0x0004/4)
+#define GICC_BPR (0x0008/4)
+#define GICC_IAR (0x000C/4)
+#define GICC_EOIR (0x0010/4)
+#define GICC_RPR (0x0014/4)
+#define GICC_HPPIR (0x0018/4)
+#define GICC_APR (0x00D0/4)
+#define GICC_NSAPR (0x00E0/4)
+#define GICC_DIR (0x1000/4)
+
+#define GICH_HCR (0x00/4)
+#define GICH_VTR (0x04/4)
+#define GICH_VMCR (0x08/4)
+#define GICH_MISR (0x10/4)
+#define GICH_EISR0 (0x20/4)
+#define GICH_EISR1 (0x24/4)
+#define GICH_ELRSR0 (0x30/4)
+#define GICH_ELRSR1 (0x34/4)
+#define GICH_APR (0xF0/4)
+#define GICH_LR (0x100/4)
+
+/* Register bits */
+#define GICD_CTL_ENABLE 0x1
+
+#define GICD_TYPE_LINES 0x01f
+#define GICD_TYPE_CPUS 0x0e0
+#define GICD_TYPE_SEC 0x400
+
+#define GICC_CTL_ENABLE 0x1
+#define GICC_CTL_EOI (0x1 << 9)
+
+#define GICC_IA_IRQ 0x03ff
+#define GICC_IA_CPU 0x1c00
+
+#define GICH_HCR_EN (1 << 0)
+#define GICH_HCR_UIE (1 << 1)
+#define GICH_HCR_LRENPIE (1 << 2)
+#define GICH_HCR_NPIE (1 << 3)
+#define GICH_HCR_VGRP0EIE (1 << 4)
+#define GICH_HCR_VGRP0DIE (1 << 5)
+#define GICH_HCR_VGRP1EIE (1 << 6)
+#define GICH_HCR_VGRP1DIE (1 << 7)
+
+#define GICH_MISR_EOI (1 << 0)
+#define GICH_MISR_U (1 << 1)
+#define GICH_MISR_LRENP (1 << 2)
+#define GICH_MISR_NP (1 << 3)
+#define GICH_MISR_VGRP0E (1 << 4)
+#define GICH_MISR_VGRP0D (1 << 5)
+#define GICH_MISR_VGRP1E (1 << 6)
+#define GICH_MISR_VGRP1D (1 << 7)
+
+#define GICH_LR_VIRTUAL_MASK 0x3ff
+#define GICH_LR_VIRTUAL_SHIFT 0
+#define GICH_LR_PHYSICAL_MASK 0x3ff
+#define GICH_LR_PHYSICAL_SHIFT 10
+#define GICH_LR_STATE_MASK 0x3
+#define GICH_LR_STATE_SHIFT 28
+#define GICH_LR_PRIORITY_SHIFT 23
+#define GICH_LR_MAINTENANCE_IRQ (1<<19)
+#define GICH_LR_PENDING (1<<28)
+#define GICH_LR_ACTIVE (1<<29)
+#define GICH_LR_GRP1 (1<<30)
+#define GICH_LR_HW (1<<31)
+#define GICH_LR_CPUID_SHIFT 9
+#define GICH_VTR_NRLRGS 0x3f
+
+extern struct pending_irq *irq_to_pending(struct vcpu *v, unsigned int irq);
+
+extern void gic_route_irqs(void);
+
+extern void __cpuinit init_maintenance_interrupt(void);
+extern void gic_set_guest_irq(unsigned int irq,
+ unsigned int state, unsigned int priority);
+extern void gic_inject_irq_start(void);
+extern void gic_inject_irq_stop(void);
+extern int gic_route_irq_to_guest(struct domain *d, unsigned int irq,
+ const char * devname);
+
+/* Accept an interrupt from the GIC and dispatch its handler */
+extern void gic_interrupt(struct cpu_user_regs *regs, int is_fiq);
+/* Bring up the interrupt controller */
+extern void gic_init(void);
+/* setup the gic virtual interface for a guest */
+extern void gicv_setup(struct domain *d);
+#endif
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--
1.7.2.5


_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel