From patchwork Sat Mar 2 15:18:37 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sanjay Lal X-Patchwork-Id: 2207191 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 7681FDF230 for ; Sat, 2 Mar 2013 15:19:18 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752582Ab3CBPTK (ORCPT ); Sat, 2 Mar 2013 10:19:10 -0500 Received: from kymasys.com ([64.62.140.43]:37067 "HELO kymasys.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1752241Ab3CBPTI (ORCPT ); Sat, 2 Mar 2013 10:19:08 -0500 Received: from agni.kymasys.com ([75.40.23.192]) by kymasys.com for ; Sat, 2 Mar 2013 07:19:06 -0800 Received: by agni.kymasys.com (Postfix, from userid 500) id EBF7E63004B; Sat, 2 Mar 2013 07:18:49 -0800 (PST) From: Sanjay Lal To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org, Aurelien Jarno , Gleb Natapov , Marcelo Tosatti , Sanjay Lal Subject: [Qemu-devel][PATCH 02/12] KVM/MIPS: GIC emulation for SMP guests. Date: Sat, 2 Mar 2013 07:18:37 -0800 Message-Id: <1362237527-23678-4-git-send-email-sanjayl@kymasys.com> X-Mailer: git-send-email 1.7.11.3 In-Reply-To: <1362237527-23678-1-git-send-email-sanjayl@kymasys.com> References: <1362237527-23678-1-git-send-email-sanjayl@kymasys.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org --- hw/mips_gcmpregs.h | 122 ++++++++++++++++ hw/mips_gic.c | 418 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/mips_gic.h | 378 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 918 insertions(+) create mode 100644 hw/mips_gcmpregs.h create mode 100644 hw/mips_gic.c create mode 100644 hw/mips_gic.h diff --git a/hw/mips_gcmpregs.h b/hw/mips_gcmpregs.h new file mode 100644 index 0000000..933a5c2 --- /dev/null +++ b/hw/mips_gcmpregs.h @@ -0,0 +1,122 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000, 07 MIPS Technologies, Inc. + * + * Multiprocessor Subsystem Register Definitions + * + */ +#ifndef _ASM_GCMPREGS_H +#define _ASM_GCMPREGS_H + + +/* Offsets to major blocks within GCMP from GCMP base */ +#define GCMP_GCB_OFS 0x0000 /* Global Control Block */ +#define GCMP_CLCB_OFS 0x2000 /* Core Local Control Block */ +#define GCMP_COCB_OFS 0x4000 /* Core Other Control Block */ +#define GCMP_GDB_OFS 0x8000 /* Global Debug Block */ + +/* Offsets to individual GCMP registers from GCMP base */ +#define GCMPOFS(block, tag, reg) \ + (GCMP_##block##_OFS + GCMP_##tag##_##reg##_OFS) +#define GCMPOFSn(block, tag, reg, n) \ + (GCMP_##block##_OFS + GCMP_##tag##_##reg##_OFS(n)) + +#define GCMPGCBOFS(reg) GCMPOFS(GCB, GCB, reg) +#define GCMPGCBOFSn(reg, n) GCMPOFSn(GCB, GCB, reg, n) +#define GCMPCLCBOFS(reg) GCMPOFS(CLCB, CCB, reg) +#define GCMPCOCBOFS(reg) GCMPOFS(COCB, CCB, reg) +#define GCMPGDBOFS(reg) GCMPOFS(GDB, GDB, reg) + +/* GCMP register access */ +#define GCMPGCB(reg) REGP(_gcmp_base, GCMPGCBOFS(reg)) +#define GCMPGCBn(reg, n) REGP(_gcmp_base, GCMPGCBOFSn(reg, n)) +#define GCMPCLCB(reg) REGP(_gcmp_base, GCMPCLCBOFS(reg)) +#define GCMPCOCB(reg) REGP(_gcmp_base, GCMPCOCBOFS(reg)) +#define GCMPGDB(reg) REGP(_gcmp_base, GCMPGDBOFS(reg)) + +/* Mask generation */ +#define GCMPMSK(block, reg, bits) (MSK(bits)< +*/ + +#include "hw.h" +#include "qemu/bitmap.h" +#include "exec/memory.h" +#include "sysemu/sysemu.h" + +#ifdef CONFIG_KVM +#include "sysemu/kvm.h" +#include "kvm_mips.h" +#endif + +#include "mips_gic.h" +#include "mips_gcmpregs.h" + +//#define DEBUG + +#ifdef DEBUG +#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__) +#else +#define DPRINTF(fmt, ...) +#endif + +/* Support upto 4 VPEs */ +#define NUMVPES 4 + +/* XXXKYMA: Spoof a bit of the GCR as well, just enough to get Linux to detect it */ +typedef struct gic_t +{ + CPUMIPSState *env[NR_CPUS]; + MemoryRegion gcr_mem, gic_mem; + + qemu_irq *irqs; + + /* GCR Registers */ + uint32_t gcr_gic_base_reg; + + /* Shared Section Registers */ + uint32_t gic_gl_intr_pol_reg[8]; + uint32_t gic_gl_intr_trigtype_reg[8]; + uint32_t gic_gl_intr_pending_reg[8]; + uint32_t gic_gl_intr_mask_reg[8]; + + uint32_t gic_gl_map_pin[256]; + + /* Sparse array, need a better way */ + uint32_t gic_gl_map_vpe[0x7fa]; + + /* VPE Local Section Registers */ + /* VPE Other Section Registers, aliased to local, use the other field to access the correct instance */ + uint32_t gic_local_vpe_regs[NUMVPES][0x1000]; + + /* User Mode Visible Section Registers */ +} gic_t; + + +static uint64_t +gic_read(void *opaque, hwaddr addr, unsigned size) +{ + int reg; + gic_t *gic = (gic_t *) opaque; + + DPRINTF("addr: %#" PRIx64 ", size: %#x\n", addr, size); + + switch (addr) { + case GIC_SH_CONFIG_OFS: + return 0x8040000 | ((NUMVPES - 1) & GIC_SH_CONFIG_NUMVPES_MSK); + break; + + case GIC_SH_POL_31_0_OFS: + case GIC_SH_POL_63_32_OFS: + case GIC_SH_POL_95_64_OFS: + case GIC_SH_POL_127_96_OFS: + case GIC_SH_POL_159_128_OFS: + case GIC_SH_POL_191_160_OFS: + case GIC_SH_POL_223_192_OFS: + case GIC_SH_POL_255_224_OFS: + reg = (addr - GIC_SH_POL_31_0_OFS) / 4; + return gic->gic_gl_intr_pol_reg[reg]; + break; + + case GIC_SH_TRIG_31_0_OFS: + case GIC_SH_TRIG_63_32_OFS: + case GIC_SH_TRIG_95_64_OFS: + case GIC_SH_TRIG_127_96_OFS: + case GIC_SH_TRIG_159_128_OFS: + case GIC_SH_TRIG_191_160_OFS: + case GIC_SH_TRIG_223_192_OFS: + case GIC_SH_TRIG_255_224_OFS: + reg = (addr - GIC_SH_TRIG_31_0_OFS) / 4; + return gic->gic_gl_intr_trigtype_reg[reg]; + break; + + case GIC_SH_RMASK_31_0_OFS: + case GIC_SH_RMASK_63_32_OFS: + case GIC_SH_RMASK_95_64_OFS: + case GIC_SH_RMASK_127_96_OFS: + case GIC_SH_RMASK_159_128_OFS: + case GIC_SH_RMASK_191_160_OFS: + case GIC_SH_RMASK_223_192_OFS: + case GIC_SH_RMASK_255_224_OFS: + break; + + case GIC_SH_PEND_31_0_OFS: + case GIC_SH_PEND_63_32_OFS: + case GIC_SH_PEND_95_64_OFS: + case GIC_SH_PEND_127_96_OFS: + case GIC_SH_PEND_159_128_OFS: + case GIC_SH_PEND_191_160_OFS: + case GIC_SH_PEND_223_192_OFS: + case GIC_SH_PEND_255_224_OFS: + reg = (addr - GIC_SH_PEND_31_0_OFS) / 4; + DPRINTF("pending[%d]: %#" PRIx32 "\n", reg, gic->gic_gl_intr_pending_reg[reg]); + return gic->gic_gl_intr_pending_reg[reg]; + break; + + case GIC_SH_MASK_31_0_OFS: + case GIC_SH_MASK_63_32_OFS: + case GIC_SH_MASK_95_64_OFS: + case GIC_SH_MASK_127_96_OFS: + case GIC_SH_MASK_159_128_OFS: + case GIC_SH_MASK_191_160_OFS: + case GIC_SH_MASK_223_192_OFS: + case GIC_SH_MASK_255_224_OFS: + reg = (addr - GIC_SH_MASK_31_0_OFS) / 4; + return gic->gic_gl_intr_mask_reg[reg]; + break; + + default: + break; + } + + /* Other cases */ + if (addr >= GIC_SH_INTR_MAP_TO_PIN_BASE_OFS + && addr <= GIC_SH_MAP_TO_PIN(255)) { + reg = (addr - GIC_SH_INTR_MAP_TO_PIN_BASE_OFS) / 4; + return gic->gic_gl_map_pin[reg]; + } + + if (addr >= GIC_SH_INTR_MAP_TO_VPE_BASE_OFS + && addr <= GIC_SH_MAP_TO_VPE_REG_OFF(255, 63)) { + reg = (addr - GIC_SH_INTR_MAP_TO_VPE_BASE_OFS) / 4; + return gic->gic_gl_map_vpe[reg]; + } + + if (addr >= GIC_VPELOCAL_BASE_ADDR && addr < GIC_VPEOTHER_BASE_ADDR) { + } + + if (addr >= GIC_VPEOTHER_BASE_ADDR && addr < GIC_USERMODE_BASE_ADDR) { + } + + DPRINTF("%s: unimplemented register @ %#" PRIx64 "\n", __func__, addr); + return 0ULL; +} + +static void +gic_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) +{ + int reg, intr; + gic_t *gic = (gic_t *) opaque; + + DPRINTF("addr: %#" PRIx64 ", data: %#" PRIx64 ", size: %#x\n", addr, data, + size); + + switch (addr) { + case GIC_SH_POL_31_0_OFS: + case GIC_SH_POL_63_32_OFS: + case GIC_SH_POL_95_64_OFS: + case GIC_SH_POL_127_96_OFS: + case GIC_SH_POL_159_128_OFS: + case GIC_SH_POL_191_160_OFS: + case GIC_SH_POL_223_192_OFS: + case GIC_SH_POL_255_224_OFS: + reg = (addr - GIC_SH_POL_31_0_OFS) / 4; + gic->gic_gl_intr_pol_reg[reg] = data; + break; + + case GIC_SH_TRIG_31_0_OFS: + case GIC_SH_TRIG_63_32_OFS: + case GIC_SH_TRIG_95_64_OFS: + case GIC_SH_TRIG_127_96_OFS: + case GIC_SH_TRIG_159_128_OFS: + case GIC_SH_TRIG_191_160_OFS: + case GIC_SH_TRIG_223_192_OFS: + case GIC_SH_TRIG_255_224_OFS: + reg = (addr - GIC_SH_TRIG_31_0_OFS) / 4; + gic->gic_gl_intr_trigtype_reg[reg] = data; + break; + + case GIC_SH_RMASK_31_0_OFS: + case GIC_SH_RMASK_63_32_OFS: + case GIC_SH_RMASK_95_64_OFS: + case GIC_SH_RMASK_127_96_OFS: + case GIC_SH_RMASK_159_128_OFS: + case GIC_SH_RMASK_191_160_OFS: + case GIC_SH_RMASK_223_192_OFS: + case GIC_SH_RMASK_255_224_OFS: + reg = (addr - GIC_SH_RMASK_31_0_OFS) / 4; + gic->gic_gl_intr_mask_reg[reg] &= ~data; + break; + + case GIC_SH_WEDGE_OFS: + DPRINTF("addr: %#" PRIx64 ", data: %#" PRIx64 ", size: %#x\n", addr, + data, size); + + /* Figure out which VPE/HW Interrupt this maps to */ + intr = data & 0x7FFFFFFF; + + /* XXXSL Mask/Enabled Checks */ + if (data & 0x80000000) + qemu_set_irq(gic->irqs[intr], 1); + else + qemu_set_irq(gic->irqs[intr], 0); + + break; + + case GIC_SH_PEND_31_0_OFS: + case GIC_SH_PEND_63_32_OFS: + case GIC_SH_PEND_95_64_OFS: + case GIC_SH_PEND_127_96_OFS: + case GIC_SH_PEND_159_128_OFS: + case GIC_SH_PEND_191_160_OFS: + case GIC_SH_PEND_223_192_OFS: + case GIC_SH_PEND_255_224_OFS: + break; + + case GIC_SH_SMASK_31_0_OFS: + case GIC_SH_SMASK_63_32_OFS: + case GIC_SH_SMASK_95_64_OFS: + case GIC_SH_SMASK_127_96_OFS: + case GIC_SH_SMASK_159_128_OFS: + case GIC_SH_SMASK_191_160_OFS: + case GIC_SH_SMASK_223_192_OFS: + case GIC_SH_SMASK_255_224_OFS: + reg = (addr - GIC_SH_SMASK_31_0_OFS) / 4; + gic->gic_gl_intr_mask_reg[reg] |= data; + break; + + default: + break; + } + + /* Other cases */ + if (addr >= GIC_SH_INTR_MAP_TO_PIN_BASE_OFS + && addr <= GIC_SH_MAP_TO_PIN(255)) { + reg = (addr - GIC_SH_INTR_MAP_TO_PIN_BASE_OFS) / 4; + gic->gic_gl_map_pin[reg] = data; + } + if (addr >= GIC_SH_INTR_MAP_TO_VPE_BASE_OFS + && addr <= GIC_SH_MAP_TO_VPE_REG_OFF(255, 63)) { + reg = (addr - GIC_SH_INTR_MAP_TO_VPE_BASE_OFS) / 4; + gic->gic_gl_map_vpe[reg] = data; + } + + if (addr >= GIC_VPELOCAL_BASE_ADDR && addr < GIC_VPEOTHER_BASE_ADDR) { + } + + if (addr >= GIC_VPEOTHER_BASE_ADDR && addr < GIC_USERMODE_BASE_ADDR) { + } +} + +static uint64_t +gcr_read(void *opaque, hwaddr addr, unsigned size) +{ + gic_t *gic = (gic_t *) opaque; + + DPRINTF("addr: %#" PRIx64 ", size: %#x\n", addr, size); + + switch (addr) { + case GCMP_GCB_GC_OFS: + /* Set PCORES to # cores - 1 */ + return smp_cpus - 1; + break; + + case GCMP_GCB_GCMPB_OFS: + return GCMP_BASE_ADDR; + break; + + case GCMP_GCB_GICBA_OFS: + return gic->gcr_gic_base_reg; + break; + + default: + DPRINTF("Unsupported Reg Read @ offset %#" PRIx64 "\n", addr); + return 0; + } + + return 0ULL; +} + +static void +gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) +{ + gic_t *gic = (gic_t *) opaque; + + DPRINTF("addr: %#" PRIx64 ", data: %#" PRIx64 ", size: %#x\n", addr, data, + size); + + switch (addr) { + case GCMP_GCB_GICBA_OFS: + gic->gcr_gic_base_reg = data; + break; + + default: + break; + } +} + + + +static void +gic_set_irq(void *opaque, int n_IRQ, int level) +{ + int vpe = -1, pin = -1, i; + gic_t *gic = (gic_t *) opaque; + + pin = gic->gic_gl_map_pin[n_IRQ] & 0x7; + + for (i = 0; i < NUMVPES; i++) { + vpe = gic-> gic_gl_map_vpe[(GIC_SH_MAP_TO_VPE_REG_OFF(n_IRQ, i) - GIC_SH_INTR_MAP_TO_VPE_BASE_OFS) / 4]; + if (vpe & GIC_SH_MAP_TO_VPE_REG_BIT(i)) { + vpe = i; + break; + } + } + + if (pin >= 0 && vpe >= 0) { + int offset; + DPRINTF("[%s] INTR %d maps to PIN %d on VPE %d\n", (level ? "ASSERT" : "DEASSERT"), n_IRQ, pin, vpe); + /* Set the Global PEND register */ + offset = GIC_INTR_OFS(n_IRQ) / 4; + if (level) + gic->gic_gl_intr_pending_reg[offset] |= (1 << GIC_INTR_BIT(n_IRQ)); + else + gic->gic_gl_intr_pending_reg[offset] &= ~(1 << GIC_INTR_BIT(n_IRQ)); + +#ifdef CONFIG_KVM + if (kvm_enabled()) { + kvm_mips_set_ipi_interrupt (gic->env[vpe], pin+2, level); + } +#endif + + qemu_set_irq(gic->env[vpe]->irq[pin+2], level); + } +} + +static void +gic_reset(void *opaque) +{ + int i; + gic_t *gic = (gic_t *) opaque; + + /* Rest value is map to pin */ + for (i = 0; i < 256; i++) + gic->gic_gl_map_pin[i] = GIC_MAP_TO_PIN_MSK; + +} + +static const MemoryRegionOps gic_ops = { + .read = gic_read, + .write = gic_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const MemoryRegionOps gcr_ops = { + .read = gcr_read, + .write = gcr_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +qemu_irq * +gic_init(uint32_t ncpus, CPUMIPSState *env, MemoryRegion * address_space) +{ + CPUMIPSState *next_env; + gic_t *gic; + uint32_t x; + + if (ncpus > NUMVPES) { + fprintf(stderr, "Unable to initialize GIC - ncpus %d > NUMVPES!", ncpus); + return NULL; + } + + gic = (gic_t *) g_malloc0(sizeof(gic_t)); + + /* Register the CPU env for all cpus with the GIC */ + next_env = env; + for (x = 0; x < ncpus; x++) { + if (next_env != NULL) { + gic->env[x] = next_env; + next_env = next_env->next_cpu; + } else { + fprintf(stderr, "Unable to initialize GIC - CPUMIPSState for CPU #%d not valid!", x); + return NULL; + } + } + + /* Register GCR & GIC regions */ + memory_region_init_io(&gic->gcr_mem, &gcr_ops, gic, "GCR", + GCMP_ADDRSPACE_SZ); + memory_region_init_io(&gic->gic_mem, &gic_ops, gic, "GIC", + GIC_ADDRSPACE_SZ); + + memory_region_add_subregion(address_space, GCMP_BASE_ADDR, &gic->gcr_mem); + memory_region_add_subregion(address_space, GIC_BASE_ADDR, &gic->gic_mem); + + qemu_register_reset(gic_reset, gic); + + gic->irqs = qemu_allocate_irqs(gic_set_irq, gic, GIC_NUM_INTRS); + + return (gic->irqs); +} diff --git a/hw/mips_gic.h b/hw/mips_gic.h new file mode 100644 index 0000000..4a2c828 --- /dev/null +++ b/hw/mips_gic.h @@ -0,0 +1,378 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000, 07 MIPS Technologies, Inc. + * + * GIC Register Definitions + * + */ +#ifndef _ASM_GICREGS_H +#define _ASM_GICREGS_H + +#undef GICISBYTELITTLEENDIAN + +#define NR_CPUS 8 +/* + * GCMP Specific definitions + */ + +/* XXXKYMA: Malta Specific base address */ +#define GCMP_BASE_ADDR 0x1fbf8000ULL +#define GCMP_ADDRSPACE_SZ (256 * 1024) + +/* + * GIC Specific definitions + */ + +/* XXXKYMA: Malta Specific base address */ +#define GIC_BASE_ADDR 0x1bdc0000ULL +#define GIC_ADDRSPACE_SZ (128 * 1024) + +/* GIC Address Space Offsets */ +#define GIC_SHARED_BASE_ADDR 0x0000 +#define GIC_VPELOCAL_BASE_ADDR 0x8000 +#define GIC_VPEOTHER_BASE_ADDR 0xC000 +#define GIC_USERMODE_BASE_ADDR 0x10000 + +/* Shared Section Offsets */ +#define GIC_G_INTR_POLARITY_REG0 0x0100 +#define GIC_G_INTR_POLARITY_REG1 0x0104 +#define GIC_G_INTR_TRIGTYPE_REG0 0x0180 +#define GIC_G_INTR_TRIGTYPE_REG1 0x0184 +#define GIC_G_INTR_RESETMASK_REG0 0x0300 +#define GIC_G_INTR_RESETMASK_REG1 0x0304 +#define GIC_G_INTR_SETMASK_REG0 0x0380 + +/* + * MSC01 BIU Specific definitions + * FIXME : These should be elsewhere ? + */ +#define MSC01_BIU_REG_BASE 0x1bc80000 +#define MSC01_BIU_ADDRSPACE_SZ (256 * 1024) +#define MSC01_SC_CFG_OFS 0x0110 +#define MSC01_SC_CFG_GICPRES_MSK 0x00000004 +#define MSC01_SC_CFG_GICPRES_SHF 2 +#define MSC01_SC_CFG_GICENA_SHF 3 + +/* Constants */ +#define GIC_POL_POS 1 +#define GIC_POL_NEG 0 +#define GIC_TRIG_EDGE 1 +#define GIC_TRIG_LEVEL 0 + +#define GIC_NUM_INTRS (24 + NR_CPUS * 2) + +#define MSK(n) ((1 << (n)) - 1) +#define REG32(addr) (*(volatile unsigned int *) (addr)) +#define REG(base, offs) REG32((unsigned long)(base) + offs##_##OFS) +#define REGP(base, phys) REG32((unsigned long)(base) + (phys)) + +/* Accessors */ +#define GIC_REG(segment, offset) \ + REG32(_gic_base + segment##_##SECTION_OFS + offset##_##OFS) +#define GIC_REG_ADDR(segment, offset) \ + REG32(_gic_base + segment##_##SECTION_OFS + offset) + +#define GIC_ABS_REG(segment, offset) \ + (_gic_base + segment##_##SECTION_OFS + offset##_##OFS) +#define GIC_REG_ABS_ADDR(segment, offset) \ + (_gic_base + segment##_##SECTION_OFS + offset) + +#ifdef GICISBYTELITTLEENDIAN +#define GICREAD(reg, data) (data) = (reg), (data) = le32_to_cpu(data) +#define GICWRITE(reg, data) (reg) = cpu_to_le32(data) +#define GICBIS(reg, bits) \ + ({unsigned int data; \ + GICREAD(reg, data); \ + data |= bits; \ + GICWRITE(reg, data); \ + }) + +#else +#define GICREAD(reg, data) (data) = (reg) +#define GICWRITE(reg, data) (reg) = (data) +#define GICBIS(reg, bits) (reg) |= (bits) +#endif + + +/* GIC Address Space */ +#define SHARED_SECTION_OFS 0x0000 +#define SHARED_SECTION_SIZE 0x8000 +#define VPE_LOCAL_SECTION_OFS 0x8000 +#define VPE_LOCAL_SECTION_SIZE 0x4000 +#define VPE_OTHER_SECTION_OFS 0xc000 +#define VPE_OTHER_SECTION_SIZE 0x4000 +#define USM_VISIBLE_SECTION_OFS 0x10000 +#define USM_VISIBLE_SECTION_SIZE 0x10000 + +/* Register Map for Shared Section */ + +#define GIC_SH_CONFIG_OFS 0x0000 + +/* Shared Global Counter */ +#define GIC_SH_COUNTER_31_00_OFS 0x0010 +#define GIC_SH_COUNTER_63_32_OFS 0x0014 +#define GIC_SH_REVISIONID_OFS 0x0020 + +/* Interrupt Polarity */ +#define GIC_SH_POL_31_0_OFS 0x0100 +#define GIC_SH_POL_63_32_OFS 0x0104 +#define GIC_SH_POL_95_64_OFS 0x0108 +#define GIC_SH_POL_127_96_OFS 0x010c +#define GIC_SH_POL_159_128_OFS 0x0110 +#define GIC_SH_POL_191_160_OFS 0x0114 +#define GIC_SH_POL_223_192_OFS 0x0118 +#define GIC_SH_POL_255_224_OFS 0x011c + +/* Edge/Level Triggering */ +#define GIC_SH_TRIG_31_0_OFS 0x0180 +#define GIC_SH_TRIG_63_32_OFS 0x0184 +#define GIC_SH_TRIG_95_64_OFS 0x0188 +#define GIC_SH_TRIG_127_96_OFS 0x018c +#define GIC_SH_TRIG_159_128_OFS 0x0190 +#define GIC_SH_TRIG_191_160_OFS 0x0194 +#define GIC_SH_TRIG_223_192_OFS 0x0198 +#define GIC_SH_TRIG_255_224_OFS 0x019c + +/* Dual Edge Triggering */ +#define GIC_SH_DUAL_31_0_OFS 0x0200 +#define GIC_SH_DUAL_63_32_OFS 0x0204 +#define GIC_SH_DUAL_95_64_OFS 0x0208 +#define GIC_SH_DUAL_127_96_OFS 0x020c +#define GIC_SH_DUAL_159_128_OFS 0x0210 +#define GIC_SH_DUAL_191_160_OFS 0x0214 +#define GIC_SH_DUAL_223_192_OFS 0x0218 +#define GIC_SH_DUAL_255_224_OFS 0x021c + +/* Set/Clear corresponding bit in Edge Detect Register */ +#define GIC_SH_WEDGE_OFS 0x0280 + +/* Reset Mask - Disables Interrupt */ +#define GIC_SH_RMASK_31_0_OFS 0x0300 +#define GIC_SH_RMASK_63_32_OFS 0x0304 +#define GIC_SH_RMASK_95_64_OFS 0x0308 +#define GIC_SH_RMASK_127_96_OFS 0x030c +#define GIC_SH_RMASK_159_128_OFS 0x0310 +#define GIC_SH_RMASK_191_160_OFS 0x0314 +#define GIC_SH_RMASK_223_192_OFS 0x0318 +#define GIC_SH_RMASK_255_224_OFS 0x031c + +/* Set Mask (WO) - Enables Interrupt */ +#define GIC_SH_SMASK_31_0_OFS 0x0380 +#define GIC_SH_SMASK_63_32_OFS 0x0384 +#define GIC_SH_SMASK_95_64_OFS 0x0388 +#define GIC_SH_SMASK_127_96_OFS 0x038c +#define GIC_SH_SMASK_159_128_OFS 0x0390 +#define GIC_SH_SMASK_191_160_OFS 0x0394 +#define GIC_SH_SMASK_223_192_OFS 0x0398 +#define GIC_SH_SMASK_255_224_OFS 0x039c + +/* Global Interrupt Mask Register (RO) - Bit Set == Interrupt enabled */ +#define GIC_SH_MASK_31_0_OFS 0x0400 +#define GIC_SH_MASK_63_32_OFS 0x0404 +#define GIC_SH_MASK_95_64_OFS 0x0408 +#define GIC_SH_MASK_127_96_OFS 0x040c +#define GIC_SH_MASK_159_128_OFS 0x0410 +#define GIC_SH_MASK_191_160_OFS 0x0414 +#define GIC_SH_MASK_223_192_OFS 0x0418 +#define GIC_SH_MASK_255_224_OFS 0x041c + +/* Pending Global Interrupts (RO) */ +#define GIC_SH_PEND_31_0_OFS 0x0480 +#define GIC_SH_PEND_63_32_OFS 0x0484 +#define GIC_SH_PEND_95_64_OFS 0x0488 +#define GIC_SH_PEND_127_96_OFS 0x048c +#define GIC_SH_PEND_159_128_OFS 0x0490 +#define GIC_SH_PEND_191_160_OFS 0x0494 +#define GIC_SH_PEND_223_192_OFS 0x0498 +#define GIC_SH_PEND_255_224_OFS 0x049c + +#define GIC_SH_INTR_MAP_TO_PIN_BASE_OFS 0x0500 + +/* Maps Interrupt X to a Pin */ +#define GIC_SH_MAP_TO_PIN(intr) \ + (GIC_SH_INTR_MAP_TO_PIN_BASE_OFS + (4 * intr)) + +#define GIC_SH_INTR_MAP_TO_VPE_BASE_OFS 0x2000 + +/* Maps Interrupt X to a VPE */ +#define GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe) \ + (GIC_SH_INTR_MAP_TO_VPE_BASE_OFS + (32 * (intr)) + (((vpe) / 32) * 4)) +#define GIC_SH_MAP_TO_VPE_REG_BIT(vpe) (1 << ((vpe) % 32)) + +/* Convert an interrupt number to a byte offset/bit for multi-word registers */ +#define GIC_INTR_OFS(intr) (((intr) / 32)*4) +#define GIC_INTR_BIT(intr) ((intr) % 32) + +/* Polarity : Reset Value is always 0 */ +#define GIC_SH_SET_POLARITY_OFS 0x0100 +#define GIC_SET_POLARITY(intr, pol) \ + GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_POLARITY_OFS + \ + GIC_INTR_OFS(intr)), (pol) << GIC_INTR_BIT(intr)) + +/* Triggering : Reset Value is always 0 */ +#define GIC_SH_SET_TRIGGER_OFS 0x0180 +#define GIC_SET_TRIGGER(intr, trig) \ + GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_TRIGGER_OFS + \ + GIC_INTR_OFS(intr)), (trig) << GIC_INTR_BIT(intr)) + +/* Mask manipulation */ +#define GIC_SH_SMASK_OFS 0x0380 +#define GIC_SET_INTR_MASK(intr) \ + GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_SMASK_OFS + \ + GIC_INTR_OFS(intr)), 1 << GIC_INTR_BIT(intr)) +#define GIC_SH_RMASK_OFS 0x0300 +#define GIC_CLR_INTR_MASK(intr) \ + GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_RMASK_OFS + \ + GIC_INTR_OFS(intr)), 1 << GIC_INTR_BIT(intr)) + +/* Register Map for Local Section */ +#define GIC_VPE_CTL_OFS 0x0000 +#define GIC_VPE_PEND_OFS 0x0004 +#define GIC_VPE_MASK_OFS 0x0008 +#define GIC_VPE_RMASK_OFS 0x000c +#define GIC_VPE_SMASK_OFS 0x0010 +#define GIC_VPE_WD_MAP_OFS 0x0040 +#define GIC_VPE_COMPARE_MAP_OFS 0x0044 +#define GIC_VPE_TIMER_MAP_OFS 0x0048 +#define GIC_VPE_PERFCTR_MAP_OFS 0x0050 +#define GIC_VPE_SWINT0_MAP_OFS 0x0054 +#define GIC_VPE_SWINT1_MAP_OFS 0x0058 +#define GIC_VPE_OTHER_ADDR_OFS 0x0080 +#define GIC_VPE_WD_CONFIG0_OFS 0x0090 +#define GIC_VPE_WD_COUNT0_OFS 0x0094 +#define GIC_VPE_WD_INITIAL0_OFS 0x0098 +#define GIC_VPE_COMPARE_LO_OFS 0x00a0 +#define GIC_VPE_COMPARE_HI 0x00a4 + +#define GIC_VPE_EIC_SHADOW_SET_BASE 0x0100 +#define GIC_VPE_EIC_SS(intr) \ + (GIC_EIC_SHADOW_SET_BASE + (4 * intr)) + +#define GIC_VPE_EIC_VEC_BASE 0x0800 +#define GIC_VPE_EIC_VEC(intr) \ + (GIC_VPE_EIC_VEC_BASE + (4 * intr)) + +#define GIC_VPE_TENABLE_NMI_OFS 0x1000 +#define GIC_VPE_TENABLE_YQ_OFS 0x1004 +#define GIC_VPE_TENABLE_INT_31_0_OFS 0x1080 +#define GIC_VPE_TENABLE_INT_63_32_OFS 0x1084 + +/* User Mode Visible Section Register Map */ +#define GIC_UMV_SH_COUNTER_31_00_OFS 0x0000 +#define GIC_UMV_SH_COUNTER_63_32_OFS 0x0004 + +/* Masks */ +#define GIC_SH_CONFIG_COUNTSTOP_SHF 28 +#define GIC_SH_CONFIG_COUNTSTOP_MSK (MSK(1) << GIC_SH_CONFIG_COUNTSTOP_SHF) + +#define GIC_SH_CONFIG_COUNTBITS_SHF 24 +#define GIC_SH_CONFIG_COUNTBITS_MSK (MSK(4) << GIC_SH_CONFIG_COUNTBITS_SHF) + +#define GIC_SH_CONFIG_NUMINTRS_SHF 16 +#define GIC_SH_CONFIG_NUMINTRS_MSK (MSK(8) << GIC_SH_CONFIG_NUMINTRS_SHF) + +#define GIC_SH_CONFIG_NUMVPES_SHF 0 +#define GIC_SH_CONFIG_NUMVPES_MSK (MSK(8) << GIC_SH_CONFIG_NUMVPES_SHF) + +#define GIC_SH_WEDGE_SET(intr) (intr | (0x1 << 31)) +#define GIC_SH_WEDGE_CLR(intr) (intr & ~(0x1 << 31)) + +#define GIC_MAP_TO_PIN_SHF 31 +#define GIC_MAP_TO_PIN_MSK (MSK(1) << GIC_MAP_TO_PIN_SHF) +#define GIC_MAP_TO_NMI_SHF 30 +#define GIC_MAP_TO_NMI_MSK (MSK(1) << GIC_MAP_TO_NMI_SHF) +#define GIC_MAP_TO_YQ_SHF 29 +#define GIC_MAP_TO_YQ_MSK (MSK(1) << GIC_MAP_TO_YQ_SHF) +#define GIC_MAP_SHF 0 +#define GIC_MAP_MSK (MSK(6) << GIC_MAP_SHF) + +/* GIC_VPE_CTL Masks */ +#define GIC_VPE_CTL_PERFCNT_RTBL_SHF 2 +#define GIC_VPE_CTL_PERFCNT_RTBL_MSK (MSK(1) << GIC_VPE_CTL_PERFCNT_RTBL_SHF) +#define GIC_VPE_CTL_TIMER_RTBL_SHF 1 +#define GIC_VPE_CTL_TIMER_RTBL_MSK (MSK(1) << GIC_VPE_CTL_TIMER_RTBL_SHF) +#define GIC_VPE_CTL_EIC_MODE_SHF 0 +#define GIC_VPE_CTL_EIC_MODE_MSK (MSK(1) << GIC_VPE_CTL_EIC_MODE_SHF) + +/* GIC_VPE_PEND Masks */ +#define GIC_VPE_PEND_WD_SHF 0 +#define GIC_VPE_PEND_WD_MSK (MSK(1) << GIC_VPE_PEND_WD_SHF) +#define GIC_VPE_PEND_CMP_SHF 1 +#define GIC_VPE_PEND_CMP_MSK (MSK(1) << GIC_VPE_PEND_CMP_SHF) +#define GIC_VPE_PEND_TIMER_SHF 2 +#define GIC_VPE_PEND_TIMER_MSK (MSK(1) << GIC_VPE_PEND_TIMER_SHF) +#define GIC_VPE_PEND_PERFCOUNT_SHF 3 +#define GIC_VPE_PEND_PERFCOUNT_MSK (MSK(1) << GIC_VPE_PEND_PERFCOUNT_SHF) +#define GIC_VPE_PEND_SWINT0_SHF 4 +#define GIC_VPE_PEND_SWINT0_MSK (MSK(1) << GIC_VPE_PEND_SWINT0_SHF) +#define GIC_VPE_PEND_SWINT1_SHF 5 +#define GIC_VPE_PEND_SWINT1_MSK (MSK(1) << GIC_VPE_PEND_SWINT1_SHF) + +/* GIC_VPE_RMASK Masks */ +#define GIC_VPE_RMASK_WD_SHF 0 +#define GIC_VPE_RMASK_WD_MSK (MSK(1) << GIC_VPE_RMASK_WD_SHF) +#define GIC_VPE_RMASK_CMP_SHF 1 +#define GIC_VPE_RMASK_CMP_MSK (MSK(1) << GIC_VPE_RMASK_CMP_SHF) +#define GIC_VPE_RMASK_TIMER_SHF 2 +#define GIC_VPE_RMASK_TIMER_MSK (MSK(1) << GIC_VPE_RMASK_TIMER_SHF) +#define GIC_VPE_RMASK_PERFCNT_SHF 3 +#define GIC_VPE_RMASK_PERFCNT_MSK (MSK(1) << GIC_VPE_RMASK_PERFCNT_SHF) +#define GIC_VPE_RMASK_SWINT0_SHF 4 +#define GIC_VPE_RMASK_SWINT0_MSK (MSK(1) << GIC_VPE_RMASK_SWINT0_SHF) +#define GIC_VPE_RMASK_SWINT1_SHF 5 +#define GIC_VPE_RMASK_SWINT1_MSK (MSK(1) << GIC_VPE_RMASK_SWINT1_SHF) + +/* GIC_VPE_SMASK Masks */ +#define GIC_VPE_SMASK_WD_SHF 0 +#define GIC_VPE_SMASK_WD_MSK (MSK(1) << GIC_VPE_SMASK_WD_SHF) +#define GIC_VPE_SMASK_CMP_SHF 1 +#define GIC_VPE_SMASK_CMP_MSK (MSK(1) << GIC_VPE_SMASK_CMP_SHF) +#define GIC_VPE_SMASK_TIMER_SHF 2 +#define GIC_VPE_SMASK_TIMER_MSK (MSK(1) << GIC_VPE_SMASK_TIMER_SHF) +#define GIC_VPE_SMASK_PERFCNT_SHF 3 +#define GIC_VPE_SMASK_PERFCNT_MSK (MSK(1) << GIC_VPE_SMASK_PERFCNT_SHF) +#define GIC_VPE_SMASK_SWINT0_SHF 4 +#define GIC_VPE_SMASK_SWINT0_MSK (MSK(1) << GIC_VPE_SMASK_SWINT0_SHF) +#define GIC_VPE_SMASK_SWINT1_SHF 5 +#define GIC_VPE_SMASK_SWINT1_MSK (MSK(1) << GIC_VPE_SMASK_SWINT1_SHF) + +/* + * Set the Mapping of Interrupt X to a VPE. + */ +#define GIC_SH_MAP_TO_VPE_SMASK(intr, vpe) \ + GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe)), \ + GIC_SH_MAP_TO_VPE_REG_BIT(vpe)) + +struct gic_pcpu_mask { + DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS); +}; + +struct gic_pending_regs { + DECLARE_BITMAP(pending, GIC_NUM_INTRS); +}; + +struct gic_intrmask_regs { + DECLARE_BITMAP(intrmask, GIC_NUM_INTRS); +}; + +/* + * Interrupt Meta-data specification. The ipiflag helps + * in building ipi_map. + */ +struct gic_intr_map { + unsigned int cpunum; /* Directed to this CPU */ +#define GIC_UNUSED 0xdead /* Dummy data */ + unsigned int pin; /* Directed to this Pin */ + unsigned int polarity; /* Polarity : +/- */ + unsigned int trigtype; /* Trigger : Edge/Levl */ + unsigned int flags; /* Misc flags */ +#define GIC_FLAG_IPI 0x01 +#define GIC_FLAG_TRANSPARENT 0x02 +}; + +qemu_irq *gic_init (uint32_t ncpus, CPUMIPSState *env, MemoryRegion *address_space); + +#endif /* _ASM_GICREGS_H */