* [Qemu-devel] [PATCH 3/3] sparc64: implement PCI and ISA irqs
@ 2012-03-11 11:02 Blue Swirl
2012-03-27 18:19 ` Artyom Tarasenko
0 siblings, 1 reply; 4+ messages in thread
From: Blue Swirl @ 2012-03-11 11:02 UTC (permalink / raw)
To: Michael S. Tsirkin, qemu-devel
[-- Attachment #1: Type: text/plain, Size: 11526 bytes --]
Generate correct trap for external interrupts. Map PCI and ISA IRQs to
RIC/UltraSPARC-IIi interrupt vectors.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
---
hw/apb_pci.c | 48 +++++++++++++++++++++++++++----------
hw/apb_pci.h | 3 +-
hw/sun4u.c | 57 ++++++++++++++++++++++++++++++--------------
target-sparc/cpu.h | 3 ++
target-sparc/ldst_helper.c | 20 ++++++++++----
5 files changed, 93 insertions(+), 38 deletions(-)
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index b10f31e..7e28808 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -66,6 +66,8 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
#define RESET_WCMASK 0x98000000
#define RESET_WMASK 0x60000000
+#define MAX_IVEC 0x30
+
typedef struct APBState {
SysBusDevice busdev;
PCIBus *bus;
@@ -77,7 +79,8 @@ typedef struct APBState {
uint32_t pci_control[16];
uint32_t pci_irq_map[8];
uint32_t obio_irq_map[32];
- qemu_irq pci_irqs[32];
+ qemu_irq *pbm_irqs;
+ qemu_irq *ivec_irqs;
uint32_t reset_control;
unsigned int nr_resets;
} APBState;
@@ -87,7 +90,7 @@ static void apb_config_writel (void *opaque,
target_phys_addr_t addr,
{
APBState *s = opaque;
- APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
+ APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n",
__func__, addr, val);
switch (addr & 0xffff) {
case 0x30 ... 0x4f: /* DMA error registers */
@@ -104,6 +107,12 @@ static void apb_config_writel (void *opaque,
target_phys_addr_t addr,
s->pci_irq_map[(addr & 0x3f) >> 3] |= val & ~PBM_PCI_IMR_MASK;
}
break;
+ case 0x1000 ... 0x1080: /* OBIO interrupt control */
+ if (addr & 4) {
+ s->obio_irq_map[(addr & 0xff) >> 3] &= PBM_PCI_IMR_MASK;
+ s->obio_irq_map[(addr & 0xff) >> 3] |= val & ~PBM_PCI_IMR_MASK;
+ }
+ break;
case 0x2000 ... 0x202f: /* PCI control */
s->pci_control[(addr & 0x3f) >> 2] = val;
break;
@@ -154,6 +163,13 @@ static uint64_t apb_config_readl (void *opaque,
val = 0;
}
break;
+ case 0x1000 ... 0x1080: /* OBIO interrupt control */
+ if (addr & 4) {
+ val = s->obio_irq_map[(addr & 0xff) >> 3];
+ } else {
+ val = 0;
+ }
+ break;
case 0x2000 ... 0x202f: /* PCI control */
val = s->pci_control[(addr & 0x3f) >> 2];
break;
@@ -190,7 +206,7 @@ static void apb_pci_config_write(void *opaque,
target_phys_addr_t addr,
APBState *s = opaque;
val = qemu_bswap_len(val, size);
- APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
+ APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n",
__func__, addr, val);
pci_data_write(s->bus, addr, val, size);
}
@@ -280,10 +296,19 @@ static void pci_apb_set_irq(void *opaque, int
irq_num, int level)
if (irq_num < 32) {
if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
- qemu_set_irq(s->pci_irqs[irq_num], level);
+ qemu_set_irq(s->ivec_irqs[irq_num], level);
+ } else {
+ APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
+ qemu_irq_lower(s->ivec_irqs[irq_num]);
+ }
+ } else {
+ /* OBIO IRQ map onto the next 16 INO. */
+ if (s->obio_irq_map[irq_num - 32] & PBM_PCI_IMR_ENABLED) {
+ APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
+ qemu_set_irq(s->ivec_irqs[irq_num], level);
} else {
APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
- qemu_irq_lower(s->pci_irqs[irq_num]);
+ qemu_irq_lower(s->ivec_irqs[irq_num]);
}
}
}
@@ -316,12 +341,12 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
PCIBus *pci_apb_init(target_phys_addr_t special_base,
target_phys_addr_t mem_base,
- qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
+ qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
+ qemu_irq **pbm_irqs)
{
DeviceState *dev;
SysBusDevice *s;
APBState *d;
- unsigned int i;
PCIDevice *pci_dev;
PCIBridge *br;
@@ -346,9 +371,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
get_system_io(),
0, 32);
- for (i = 0; i < 32; i++) {
- sysbus_connect_irq(s, i, pic[i]);
- }
+ *pbm_irqs = d->pbm_irqs;
+ d->ivec_irqs = ivec_irqs;
pci_create_simple(d->bus, 0, "pbm-pci");
@@ -402,9 +426,7 @@ static int pci_pbm_init_device(SysBusDevice *dev)
for (i = 0; i < 8; i++) {
s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
}
- for (i = 0; i < 32; i++) {
- sysbus_init_irq(dev, &s->pci_irqs[i]);
- }
+ s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC);
/* apb_config */
memory_region_init_io(&s->apb_config, &apb_config_ops, s, "apb-config",
diff --git a/hw/apb_pci.h b/hw/apb_pci.h
index 8869f9d..55f7c4c 100644
--- a/hw/apb_pci.h
+++ b/hw/apb_pci.h
@@ -5,5 +5,6 @@
PCIBus *pci_apb_init(target_phys_addr_t special_base,
target_phys_addr_t mem_base,
- qemu_irq *pic, PCIBus **bus2, PCIBus **bus3);
+ qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
+ qemu_irq **pbm_irqs);
#endif
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 423108f..e0adb9e 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -81,7 +81,7 @@
#define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
#define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
-#define MAX_PILS 16
+#define IVEC_MAX 0x30
#define TICK_MAX 0x7fffffffffffffffULL
@@ -304,18 +304,24 @@ static void cpu_kick_irq(CPUState *env)
qemu_cpu_kick(env);
}
-static void cpu_set_irq(void *opaque, int irq, int level)
+static void cpu_set_ivec_irq(void *opaque, int irq, int level)
{
CPUState *env = opaque;
if (level) {
- CPUIRQ_DPRINTF("Raise CPU IRQ %d\n", irq);
- env->pil_in |= 1 << irq;
- cpu_kick_irq(env);
- } else {
- CPUIRQ_DPRINTF("Lower CPU IRQ %d\n", irq);
- env->pil_in &= ~(1 << irq);
- cpu_check_irqs(env);
+ CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
+ env->interrupt_index = TT_IVEC;
+ env->pil_in |= 1 << 5;
+ env->ivec_status |= 0x20;
+ env->ivec_data[0] = (0x1f << 6) | irq;
+ env->ivec_data[1] = 0;
+ env->ivec_data[2] = 0;
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ } else {
+ CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
+ env->pil_in &= ~(1 << 5);
+ env->ivec_status &= ~0x20;
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
}
}
@@ -521,13 +527,29 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
}
}
-static void dummy_isa_irq_handler(void *opaque, int n, int level)
+static void isa_irq_handler(void *opaque, int n, int level)
{
+ static const int isa_irq_to_ivec[16] = {
+ [1] = 0x29, /* keyboard */
+ [4] = 0x2b, /* serial */
+ [6] = 0x27, /* floppy */
+ [7] = 0x22, /* parallel */
+ [12] = 0x2a, /* mouse */
+ };
+ qemu_irq *irqs = opaque;
+ int ivec;
+
+ assert(n < 16);
+ ivec = isa_irq_to_ivec[n];
+ EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec);
+ if (ivec) {
+ qemu_set_irq(irqs[ivec], level);
+ }
}
/* EBUS (Eight bit bus) bridge */
static ISABus *
-pci_ebus_init(PCIBus *bus, int devfn)
+pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs)
{
qemu_irq *isa_irq;
PCIDevice *pci_dev;
@@ -536,7 +558,7 @@ pci_ebus_init(PCIBus *bus, int devfn)
pci_dev = pci_create_simple(bus, devfn, "ebus");
isa_bus = DO_UPCAST(ISABus, qbus,
qdev_get_child_bus(&pci_dev->qdev, "isa.0"));
- isa_irq = qemu_allocate_irqs(dummy_isa_irq_handler, NULL, 16);
+ isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16);
isa_bus_irqs(isa_bus, isa_irq);
return isa_bus;
}
@@ -761,7 +783,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
long initrd_size, kernel_size;
PCIBus *pci_bus, *pci_bus2, *pci_bus3;
ISABus *isa_bus;
- qemu_irq *irq;
+ qemu_irq *ivec_irqs, *pbm_irqs;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
DriveInfo *fd[MAX_FD];
void *fw_cfg;
@@ -774,14 +796,13 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
prom_init(hwdef->prom_addr, bios_name);
-
- irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
- pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2,
- &pci_bus3);
+ ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, env, IVEC_MAX);
+ pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs,
&pci_bus2,
+ &pci_bus3, &pbm_irqs);
pci_vga_init(pci_bus);
// XXX Should be pci_bus3
- isa_bus = pci_ebus_init(pci_bus, -1);
+ isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs);
i = 0;
if (hwdef->console_serial_base) {
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index b81779b..8994000 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -491,6 +491,9 @@ typedef struct CPUSPARCState {
/* UA 2005 hyperprivileged registers */
uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr;
CPUTimer *hstick; // UA 2005
+ /* Interrupt vector registers */
+ uint64_t ivec_status;
+ uint64_t ivec_data[3];
uint32_t softint;
#define SOFTINT_TIMER 1
#define SOFTINT_STIMER (1 << 16)
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index b59707e..4c34346 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -1526,6 +1526,19 @@ uint64_t helper_ld_asi(target_ulong addr, int
asi, int size, int sign)
ret = env->dtlb[reg].tag;
break;
}
+ case 0x48: /* Interrupt dispatch, RO */
+ break;
+ case 0x49: /* Interrupt data receive */
+ ret = env->ivec_status;
+ break;
+ case 0x7f: /* Incoming interrupt vector, RO */
+ {
+ int reg = (addr >> 4) & 0x3;
+ if (reg < 3) {
+ ret = env->ivec_data[reg];
+ }
+ break;
+ }
case 0x46: /* D-cache data */
case 0x47: /* D-cache tag access */
case 0x4b: /* E-cache error enable */
@@ -1540,11 +1553,6 @@ uint64_t helper_ld_asi(target_ulong addr, int
asi, int size, int sign)
case 0x7e: /* E-cache tag */
break;
case 0x5b: /* D-MMU data pointer */
- case 0x48: /* Interrupt dispatch, RO */
- case 0x49: /* Interrupt data receive */
- case 0x7f: /* Incoming interrupt vector, RO */
- /* XXX */
- break;
case 0x54: /* I-MMU data in, WO */
case 0x57: /* I-MMU demap, WO */
case 0x5c: /* D-MMU data in, WO */
@@ -1954,7 +1962,7 @@ void helper_st_asi(target_ulong addr,
target_ulong val, int asi, int size)
demap_tlb(env->dtlb, addr, "dmmu", env);
return;
case 0x49: /* Interrupt data receive */
- /* XXX */
+ env->ivec_status = val & 0x20;
return;
case 0x46: /* D-cache data */
case 0x47: /* D-cache tag access */
--
1.7.9
[-- Attachment #2: 0003-sparc64-implement-PCI-and-ISA-irqs.patch --]
[-- Type: text/x-patch, Size: 12034 bytes --]
From d184e51d012650cf730cb9bc431315e1a8ad5a9a Mon Sep 17 00:00:00 2001
Message-Id: <d184e51d012650cf730cb9bc431315e1a8ad5a9a.1331463238.git.blauwirbel@gmail.com>
In-Reply-To: <4bd3c025d124cc8ce66346143d5ec906e565c47a.1331463238.git.blauwirbel@gmail.com>
References: <4bd3c025d124cc8ce66346143d5ec906e565c47a.1331463238.git.blauwirbel@gmail.com>
From: Blue Swirl <blauwirbel@gmail.com>
Date: Sat, 10 Mar 2012 20:37:00 +0000
Subject: [PATCH 3/3] sparc64: implement PCI and ISA irqs
Generate correct trap for external interrupts. Map PCI and ISA IRQs to
RIC/UltraSPARC-IIi interrupt vectors.
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
---
hw/apb_pci.c | 48 +++++++++++++++++++++++++++----------
hw/apb_pci.h | 3 +-
hw/sun4u.c | 57 ++++++++++++++++++++++++++++++--------------
target-sparc/cpu.h | 3 ++
target-sparc/ldst_helper.c | 20 ++++++++++----
5 files changed, 93 insertions(+), 38 deletions(-)
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
index b10f31e..7e28808 100644
--- a/hw/apb_pci.c
+++ b/hw/apb_pci.c
@@ -66,6 +66,8 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
#define RESET_WCMASK 0x98000000
#define RESET_WMASK 0x60000000
+#define MAX_IVEC 0x30
+
typedef struct APBState {
SysBusDevice busdev;
PCIBus *bus;
@@ -77,7 +79,8 @@ typedef struct APBState {
uint32_t pci_control[16];
uint32_t pci_irq_map[8];
uint32_t obio_irq_map[32];
- qemu_irq pci_irqs[32];
+ qemu_irq *pbm_irqs;
+ qemu_irq *ivec_irqs;
uint32_t reset_control;
unsigned int nr_resets;
} APBState;
@@ -87,7 +90,7 @@ static void apb_config_writel (void *opaque, target_phys_addr_t addr,
{
APBState *s = opaque;
- APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
+ APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n", __func__, addr, val);
switch (addr & 0xffff) {
case 0x30 ... 0x4f: /* DMA error registers */
@@ -104,6 +107,12 @@ static void apb_config_writel (void *opaque, target_phys_addr_t addr,
s->pci_irq_map[(addr & 0x3f) >> 3] |= val & ~PBM_PCI_IMR_MASK;
}
break;
+ case 0x1000 ... 0x1080: /* OBIO interrupt control */
+ if (addr & 4) {
+ s->obio_irq_map[(addr & 0xff) >> 3] &= PBM_PCI_IMR_MASK;
+ s->obio_irq_map[(addr & 0xff) >> 3] |= val & ~PBM_PCI_IMR_MASK;
+ }
+ break;
case 0x2000 ... 0x202f: /* PCI control */
s->pci_control[(addr & 0x3f) >> 2] = val;
break;
@@ -154,6 +163,13 @@ static uint64_t apb_config_readl (void *opaque,
val = 0;
}
break;
+ case 0x1000 ... 0x1080: /* OBIO interrupt control */
+ if (addr & 4) {
+ val = s->obio_irq_map[(addr & 0xff) >> 3];
+ } else {
+ val = 0;
+ }
+ break;
case 0x2000 ... 0x202f: /* PCI control */
val = s->pci_control[(addr & 0x3f) >> 2];
break;
@@ -190,7 +206,7 @@ static void apb_pci_config_write(void *opaque, target_phys_addr_t addr,
APBState *s = opaque;
val = qemu_bswap_len(val, size);
- APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
+ APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n", __func__, addr, val);
pci_data_write(s->bus, addr, val, size);
}
@@ -280,10 +296,19 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level)
if (irq_num < 32) {
if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
- qemu_set_irq(s->pci_irqs[irq_num], level);
+ qemu_set_irq(s->ivec_irqs[irq_num], level);
+ } else {
+ APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
+ qemu_irq_lower(s->ivec_irqs[irq_num]);
+ }
+ } else {
+ /* OBIO IRQ map onto the next 16 INO. */
+ if (s->obio_irq_map[irq_num - 32] & PBM_PCI_IMR_ENABLED) {
+ APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
+ qemu_set_irq(s->ivec_irqs[irq_num], level);
} else {
APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
- qemu_irq_lower(s->pci_irqs[irq_num]);
+ qemu_irq_lower(s->ivec_irqs[irq_num]);
}
}
}
@@ -316,12 +341,12 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
PCIBus *pci_apb_init(target_phys_addr_t special_base,
target_phys_addr_t mem_base,
- qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
+ qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
+ qemu_irq **pbm_irqs)
{
DeviceState *dev;
SysBusDevice *s;
APBState *d;
- unsigned int i;
PCIDevice *pci_dev;
PCIBridge *br;
@@ -346,9 +371,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
get_system_io(),
0, 32);
- for (i = 0; i < 32; i++) {
- sysbus_connect_irq(s, i, pic[i]);
- }
+ *pbm_irqs = d->pbm_irqs;
+ d->ivec_irqs = ivec_irqs;
pci_create_simple(d->bus, 0, "pbm-pci");
@@ -402,9 +426,7 @@ static int pci_pbm_init_device(SysBusDevice *dev)
for (i = 0; i < 8; i++) {
s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
}
- for (i = 0; i < 32; i++) {
- sysbus_init_irq(dev, &s->pci_irqs[i]);
- }
+ s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC);
/* apb_config */
memory_region_init_io(&s->apb_config, &apb_config_ops, s, "apb-config",
diff --git a/hw/apb_pci.h b/hw/apb_pci.h
index 8869f9d..55f7c4c 100644
--- a/hw/apb_pci.h
+++ b/hw/apb_pci.h
@@ -5,5 +5,6 @@
PCIBus *pci_apb_init(target_phys_addr_t special_base,
target_phys_addr_t mem_base,
- qemu_irq *pic, PCIBus **bus2, PCIBus **bus3);
+ qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
+ qemu_irq **pbm_irqs);
#endif
diff --git a/hw/sun4u.c b/hw/sun4u.c
index 423108f..e0adb9e 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -81,7 +81,7 @@
#define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
#define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
-#define MAX_PILS 16
+#define IVEC_MAX 0x30
#define TICK_MAX 0x7fffffffffffffffULL
@@ -304,18 +304,24 @@ static void cpu_kick_irq(CPUState *env)
qemu_cpu_kick(env);
}
-static void cpu_set_irq(void *opaque, int irq, int level)
+static void cpu_set_ivec_irq(void *opaque, int irq, int level)
{
CPUState *env = opaque;
if (level) {
- CPUIRQ_DPRINTF("Raise CPU IRQ %d\n", irq);
- env->pil_in |= 1 << irq;
- cpu_kick_irq(env);
- } else {
- CPUIRQ_DPRINTF("Lower CPU IRQ %d\n", irq);
- env->pil_in &= ~(1 << irq);
- cpu_check_irqs(env);
+ CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
+ env->interrupt_index = TT_IVEC;
+ env->pil_in |= 1 << 5;
+ env->ivec_status |= 0x20;
+ env->ivec_data[0] = (0x1f << 6) | irq;
+ env->ivec_data[1] = 0;
+ env->ivec_data[2] = 0;
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ } else {
+ CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
+ env->pil_in &= ~(1 << 5);
+ env->ivec_status &= ~0x20;
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
}
}
@@ -521,13 +527,29 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
}
}
-static void dummy_isa_irq_handler(void *opaque, int n, int level)
+static void isa_irq_handler(void *opaque, int n, int level)
{
+ static const int isa_irq_to_ivec[16] = {
+ [1] = 0x29, /* keyboard */
+ [4] = 0x2b, /* serial */
+ [6] = 0x27, /* floppy */
+ [7] = 0x22, /* parallel */
+ [12] = 0x2a, /* mouse */
+ };
+ qemu_irq *irqs = opaque;
+ int ivec;
+
+ assert(n < 16);
+ ivec = isa_irq_to_ivec[n];
+ EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec);
+ if (ivec) {
+ qemu_set_irq(irqs[ivec], level);
+ }
}
/* EBUS (Eight bit bus) bridge */
static ISABus *
-pci_ebus_init(PCIBus *bus, int devfn)
+pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs)
{
qemu_irq *isa_irq;
PCIDevice *pci_dev;
@@ -536,7 +558,7 @@ pci_ebus_init(PCIBus *bus, int devfn)
pci_dev = pci_create_simple(bus, devfn, "ebus");
isa_bus = DO_UPCAST(ISABus, qbus,
qdev_get_child_bus(&pci_dev->qdev, "isa.0"));
- isa_irq = qemu_allocate_irqs(dummy_isa_irq_handler, NULL, 16);
+ isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16);
isa_bus_irqs(isa_bus, isa_irq);
return isa_bus;
}
@@ -761,7 +783,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
long initrd_size, kernel_size;
PCIBus *pci_bus, *pci_bus2, *pci_bus3;
ISABus *isa_bus;
- qemu_irq *irq;
+ qemu_irq *ivec_irqs, *pbm_irqs;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
DriveInfo *fd[MAX_FD];
void *fw_cfg;
@@ -774,14 +796,13 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
prom_init(hwdef->prom_addr, bios_name);
-
- irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
- pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2,
- &pci_bus3);
+ ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, env, IVEC_MAX);
+ pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs, &pci_bus2,
+ &pci_bus3, &pbm_irqs);
pci_vga_init(pci_bus);
// XXX Should be pci_bus3
- isa_bus = pci_ebus_init(pci_bus, -1);
+ isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs);
i = 0;
if (hwdef->console_serial_base) {
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index b81779b..8994000 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -491,6 +491,9 @@ typedef struct CPUSPARCState {
/* UA 2005 hyperprivileged registers */
uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr;
CPUTimer *hstick; // UA 2005
+ /* Interrupt vector registers */
+ uint64_t ivec_status;
+ uint64_t ivec_data[3];
uint32_t softint;
#define SOFTINT_TIMER 1
#define SOFTINT_STIMER (1 << 16)
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index b59707e..4c34346 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -1526,6 +1526,19 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
ret = env->dtlb[reg].tag;
break;
}
+ case 0x48: /* Interrupt dispatch, RO */
+ break;
+ case 0x49: /* Interrupt data receive */
+ ret = env->ivec_status;
+ break;
+ case 0x7f: /* Incoming interrupt vector, RO */
+ {
+ int reg = (addr >> 4) & 0x3;
+ if (reg < 3) {
+ ret = env->ivec_data[reg];
+ }
+ break;
+ }
case 0x46: /* D-cache data */
case 0x47: /* D-cache tag access */
case 0x4b: /* E-cache error enable */
@@ -1540,11 +1553,6 @@ uint64_t helper_ld_asi(target_ulong addr, int asi, int size, int sign)
case 0x7e: /* E-cache tag */
break;
case 0x5b: /* D-MMU data pointer */
- case 0x48: /* Interrupt dispatch, RO */
- case 0x49: /* Interrupt data receive */
- case 0x7f: /* Incoming interrupt vector, RO */
- /* XXX */
- break;
case 0x54: /* I-MMU data in, WO */
case 0x57: /* I-MMU demap, WO */
case 0x5c: /* D-MMU data in, WO */
@@ -1954,7 +1962,7 @@ void helper_st_asi(target_ulong addr, target_ulong val, int asi, int size)
demap_tlb(env->dtlb, addr, "dmmu", env);
return;
case 0x49: /* Interrupt data receive */
- /* XXX */
+ env->ivec_status = val & 0x20;
return;
case 0x46: /* D-cache data */
case 0x47: /* D-cache tag access */
--
1.7.2.5
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH 3/3] sparc64: implement PCI and ISA irqs
2012-03-11 11:02 [Qemu-devel] [PATCH 3/3] sparc64: implement PCI and ISA irqs Blue Swirl
@ 2012-03-27 18:19 ` Artyom Tarasenko
2012-03-27 19:26 ` Blue Swirl
0 siblings, 1 reply; 4+ messages in thread
From: Artyom Tarasenko @ 2012-03-27 18:19 UTC (permalink / raw)
To: Blue Swirl; +Cc: qemu-devel, Michael S. Tsirkin
On Sun, Mar 11, 2012 at 12:02 PM, Blue Swirl <blauwirbel@gmail.com> wrote:
> Generate correct trap for external interrupts. Map PCI and ISA IRQs to
> RIC/UltraSPARC-IIi interrupt vectors.
>
> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
> ---
> hw/apb_pci.c | 48 +++++++++++++++++++++++++++----------
> hw/apb_pci.h | 3 +-
> hw/sun4u.c | 57 ++++++++++++++++++++++++++++++--------------
> target-sparc/cpu.h | 3 ++
> target-sparc/ldst_helper.c | 20 ++++++++++----
> 5 files changed, 93 insertions(+), 38 deletions(-)
>
> diff --git a/hw/apb_pci.c b/hw/apb_pci.c
> index b10f31e..7e28808 100644
> --- a/hw/apb_pci.c
> +++ b/hw/apb_pci.c
> @@ -66,6 +66,8 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
> #define RESET_WCMASK 0x98000000
> #define RESET_WMASK 0x60000000
>
> +#define MAX_IVEC 0x30
Shouldn't that be 0x40 (0x20 for OBIO and 0x20 for PCI)? I mean in
theory, obviously not all of them are used.
> +
> typedef struct APBState {
> SysBusDevice busdev;
> PCIBus *bus;
> @@ -77,7 +79,8 @@ typedef struct APBState {
> uint32_t pci_control[16];
> uint32_t pci_irq_map[8];
> uint32_t obio_irq_map[32];
> - qemu_irq pci_irqs[32];
> + qemu_irq *pbm_irqs;
> + qemu_irq *ivec_irqs;
> uint32_t reset_control;
> unsigned int nr_resets;
> } APBState;
> @@ -87,7 +90,7 @@ static void apb_config_writel (void *opaque,
> target_phys_addr_t addr,
> {
> APBState *s = opaque;
>
> - APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
> + APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n",
> __func__, addr, val);
>
> switch (addr & 0xffff) {
> case 0x30 ... 0x4f: /* DMA error registers */
> @@ -104,6 +107,12 @@ static void apb_config_writel (void *opaque,
> target_phys_addr_t addr,
> s->pci_irq_map[(addr & 0x3f) >> 3] |= val & ~PBM_PCI_IMR_MASK;
> }
> break;
> + case 0x1000 ... 0x1080: /* OBIO interrupt control */
> + if (addr & 4) {
> + s->obio_irq_map[(addr & 0xff) >> 3] &= PBM_PCI_IMR_MASK;
> + s->obio_irq_map[(addr & 0xff) >> 3] |= val & ~PBM_PCI_IMR_MASK;
> + }
> + break;
> case 0x2000 ... 0x202f: /* PCI control */
> s->pci_control[(addr & 0x3f) >> 2] = val;
> break;
> @@ -154,6 +163,13 @@ static uint64_t apb_config_readl (void *opaque,
> val = 0;
> }
> break;
> + case 0x1000 ... 0x1080: /* OBIO interrupt control */
> + if (addr & 4) {
> + val = s->obio_irq_map[(addr & 0xff) >> 3];
> + } else {
> + val = 0;
> + }
> + break;
> case 0x2000 ... 0x202f: /* PCI control */
> val = s->pci_control[(addr & 0x3f) >> 2];
> break;
> @@ -190,7 +206,7 @@ static void apb_pci_config_write(void *opaque,
> target_phys_addr_t addr,
> APBState *s = opaque;
>
> val = qemu_bswap_len(val, size);
> - APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
> + APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n",
> __func__, addr, val);
> pci_data_write(s->bus, addr, val, size);
> }
>
> @@ -280,10 +296,19 @@ static void pci_apb_set_irq(void *opaque, int
> irq_num, int level)
> if (irq_num < 32) {
> if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
> APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
> - qemu_set_irq(s->pci_irqs[irq_num], level);
> + qemu_set_irq(s->ivec_irqs[irq_num], level);
> + } else {
> + APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
> + qemu_irq_lower(s->ivec_irqs[irq_num]);
> + }
> + } else {
> + /* OBIO IRQ map onto the next 16 INO. */
> + if (s->obio_irq_map[irq_num - 32] & PBM_PCI_IMR_ENABLED) {
> + APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
> + qemu_set_irq(s->ivec_irqs[irq_num], level);
> } else {
> APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
> - qemu_irq_lower(s->pci_irqs[irq_num]);
> + qemu_irq_lower(s->ivec_irqs[irq_num]);
> }
> }
> }
> @@ -316,12 +341,12 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
>
> PCIBus *pci_apb_init(target_phys_addr_t special_base,
> target_phys_addr_t mem_base,
> - qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
> + qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
> + qemu_irq **pbm_irqs)
> {
> DeviceState *dev;
> SysBusDevice *s;
> APBState *d;
> - unsigned int i;
> PCIDevice *pci_dev;
> PCIBridge *br;
>
> @@ -346,9 +371,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
> get_system_io(),
> 0, 32);
>
> - for (i = 0; i < 32; i++) {
> - sysbus_connect_irq(s, i, pic[i]);
> - }
> + *pbm_irqs = d->pbm_irqs;
> + d->ivec_irqs = ivec_irqs;
>
> pci_create_simple(d->bus, 0, "pbm-pci");
>
> @@ -402,9 +426,7 @@ static int pci_pbm_init_device(SysBusDevice *dev)
> for (i = 0; i < 8; i++) {
> s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
> }
> - for (i = 0; i < 32; i++) {
> - sysbus_init_irq(dev, &s->pci_irqs[i]);
> - }
> + s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC);
>
> /* apb_config */
> memory_region_init_io(&s->apb_config, &apb_config_ops, s, "apb-config",
> diff --git a/hw/apb_pci.h b/hw/apb_pci.h
> index 8869f9d..55f7c4c 100644
> --- a/hw/apb_pci.h
> +++ b/hw/apb_pci.h
> @@ -5,5 +5,6 @@
>
> PCIBus *pci_apb_init(target_phys_addr_t special_base,
> target_phys_addr_t mem_base,
> - qemu_irq *pic, PCIBus **bus2, PCIBus **bus3);
> + qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
> + qemu_irq **pbm_irqs);
> #endif
> diff --git a/hw/sun4u.c b/hw/sun4u.c
> index 423108f..e0adb9e 100644
> --- a/hw/sun4u.c
> +++ b/hw/sun4u.c
> @@ -81,7 +81,7 @@
> #define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
> #define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
>
> -#define MAX_PILS 16
> +#define IVEC_MAX 0x30
>
> #define TICK_MAX 0x7fffffffffffffffULL
>
> @@ -304,18 +304,24 @@ static void cpu_kick_irq(CPUState *env)
> qemu_cpu_kick(env);
> }
>
> -static void cpu_set_irq(void *opaque, int irq, int level)
> +static void cpu_set_ivec_irq(void *opaque, int irq, int level)
> {
> CPUState *env = opaque;
>
> if (level) {
> - CPUIRQ_DPRINTF("Raise CPU IRQ %d\n", irq);
> - env->pil_in |= 1 << irq;
> - cpu_kick_irq(env);
> - } else {
> - CPUIRQ_DPRINTF("Lower CPU IRQ %d\n", irq);
> - env->pil_in &= ~(1 << irq);
> - cpu_check_irqs(env);
> + CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
> + env->interrupt_index = TT_IVEC;
> + env->pil_in |= 1 << 5;
Err. Spurious irq 5?
> + env->ivec_status |= 0x20;
> + env->ivec_data[0] = (0x1f << 6) | irq;
> + env->ivec_data[1] = 0;
> + env->ivec_data[2] = 0;
> + cpu_interrupt(env, CPU_INTERRUPT_HARD);
Shouldn't there be a cpu_interrupts_enabled(env) check before?
> + } else {
> + CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
> + env->pil_in &= ~(1 << 5);
> + env->ivec_status &= ~0x20;
> + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
> }
> }
>
> @@ -521,13 +527,29 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
> }
> }
>
> -static void dummy_isa_irq_handler(void *opaque, int n, int level)
> +static void isa_irq_handler(void *opaque, int n, int level)
> {
> + static const int isa_irq_to_ivec[16] = {
> + [1] = 0x29, /* keyboard */
> + [4] = 0x2b, /* serial */
> + [6] = 0x27, /* floppy */
> + [7] = 0x22, /* parallel */
> + [12] = 0x2a, /* mouse */
> + };
> + qemu_irq *irqs = opaque;
> + int ivec;
> +
> + assert(n < 16);
> + ivec = isa_irq_to_ivec[n];
> + EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec);
> + if (ivec) {
> + qemu_set_irq(irqs[ivec], level);
> + }
> }
>
> /* EBUS (Eight bit bus) bridge */
> static ISABus *
> -pci_ebus_init(PCIBus *bus, int devfn)
> +pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs)
> {
> qemu_irq *isa_irq;
> PCIDevice *pci_dev;
> @@ -536,7 +558,7 @@ pci_ebus_init(PCIBus *bus, int devfn)
> pci_dev = pci_create_simple(bus, devfn, "ebus");
> isa_bus = DO_UPCAST(ISABus, qbus,
> qdev_get_child_bus(&pci_dev->qdev, "isa.0"));
> - isa_irq = qemu_allocate_irqs(dummy_isa_irq_handler, NULL, 16);
> + isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16);
> isa_bus_irqs(isa_bus, isa_irq);
> return isa_bus;
> }
> @@ -761,7 +783,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
> long initrd_size, kernel_size;
> PCIBus *pci_bus, *pci_bus2, *pci_bus3;
> ISABus *isa_bus;
> - qemu_irq *irq;
> + qemu_irq *ivec_irqs, *pbm_irqs;
> DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
> DriveInfo *fd[MAX_FD];
> void *fw_cfg;
> @@ -774,14 +796,13 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
>
> prom_init(hwdef->prom_addr, bios_name);
>
> -
> - irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
> - pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2,
> - &pci_bus3);
> + ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, env, IVEC_MAX);
> + pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs,
> &pci_bus2,
> + &pci_bus3, &pbm_irqs);
> pci_vga_init(pci_bus);
>
> // XXX Should be pci_bus3
> - isa_bus = pci_ebus_init(pci_bus, -1);
> + isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs);
>
> i = 0;
> if (hwdef->console_serial_base) {
> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
> index b81779b..8994000 100644
> --- a/target-sparc/cpu.h
> +++ b/target-sparc/cpu.h
> @@ -491,6 +491,9 @@ typedef struct CPUSPARCState {
> /* UA 2005 hyperprivileged registers */
> uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr;
> CPUTimer *hstick; // UA 2005
> + /* Interrupt vector registers */
> + uint64_t ivec_status;
> + uint64_t ivec_data[3];
> uint32_t softint;
> #define SOFTINT_TIMER 1
> #define SOFTINT_STIMER (1 << 16)
> diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
> index b59707e..4c34346 100644
> --- a/target-sparc/ldst_helper.c
> +++ b/target-sparc/ldst_helper.c
> @@ -1526,6 +1526,19 @@ uint64_t helper_ld_asi(target_ulong addr, int
> asi, int size, int sign)
> ret = env->dtlb[reg].tag;
> break;
> }
> + case 0x48: /* Interrupt dispatch, RO */
> + break;
> + case 0x49: /* Interrupt data receive */
> + ret = env->ivec_status;
> + break;
> + case 0x7f: /* Incoming interrupt vector, RO */
> + {
> + int reg = (addr >> 4) & 0x3;
> + if (reg < 3) {
> + ret = env->ivec_data[reg];
> + }
> + break;
> + }
> case 0x46: /* D-cache data */
> case 0x47: /* D-cache tag access */
> case 0x4b: /* E-cache error enable */
> @@ -1540,11 +1553,6 @@ uint64_t helper_ld_asi(target_ulong addr, int
> asi, int size, int sign)
> case 0x7e: /* E-cache tag */
> break;
> case 0x5b: /* D-MMU data pointer */
> - case 0x48: /* Interrupt dispatch, RO */
> - case 0x49: /* Interrupt data receive */
> - case 0x7f: /* Incoming interrupt vector, RO */
> - /* XXX */
> - break;
> case 0x54: /* I-MMU data in, WO */
> case 0x57: /* I-MMU demap, WO */
> case 0x5c: /* D-MMU data in, WO */
> @@ -1954,7 +1962,7 @@ void helper_st_asi(target_ulong addr,
> target_ulong val, int asi, int size)
> demap_tlb(env->dtlb, addr, "dmmu", env);
> return;
> case 0x49: /* Interrupt data receive */
> - /* XXX */
> + env->ivec_status = val & 0x20;
> return;
> case 0x46: /* D-cache data */
> case 0x47: /* D-cache tag access */
> --
> 1.7.9
--
Regards,
Artyom Tarasenko
solaris/sparc under qemu blog: http://tyom.blogspot.com/search/label/qemu
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH 3/3] sparc64: implement PCI and ISA irqs
2012-03-27 18:19 ` Artyom Tarasenko
@ 2012-03-27 19:26 ` Blue Swirl
2012-03-28 17:55 ` Artyom Tarasenko
0 siblings, 1 reply; 4+ messages in thread
From: Blue Swirl @ 2012-03-27 19:26 UTC (permalink / raw)
To: Artyom Tarasenko; +Cc: qemu-devel, Michael S. Tsirkin
On Tue, Mar 27, 2012 at 18:19, Artyom Tarasenko <atar4qemu@gmail.com> wrote:
> On Sun, Mar 11, 2012 at 12:02 PM, Blue Swirl <blauwirbel@gmail.com> wrote:
>> Generate correct trap for external interrupts. Map PCI and ISA IRQs to
>> RIC/UltraSPARC-IIi interrupt vectors.
>>
>> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
>> ---
>> hw/apb_pci.c | 48 +++++++++++++++++++++++++++----------
>> hw/apb_pci.h | 3 +-
>> hw/sun4u.c | 57 ++++++++++++++++++++++++++++++--------------
>> target-sparc/cpu.h | 3 ++
>> target-sparc/ldst_helper.c | 20 ++++++++++----
>> 5 files changed, 93 insertions(+), 38 deletions(-)
>>
>> diff --git a/hw/apb_pci.c b/hw/apb_pci.c
>> index b10f31e..7e28808 100644
>> --- a/hw/apb_pci.c
>> +++ b/hw/apb_pci.c
>> @@ -66,6 +66,8 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
>> #define RESET_WCMASK 0x98000000
>> #define RESET_WMASK 0x60000000
>>
>> +#define MAX_IVEC 0x30
>
> Shouldn't that be 0x40 (0x20 for OBIO and 0x20 for PCI)? I mean in
> theory, obviously not all of them are used.
This is the maximum number (0x30 is PCI Bus Error), which actually
means that number of IRQ lines allocated should be MAX_IVEC + 1. 0x40
wouldn't hurt much.
>> +
>> typedef struct APBState {
>> SysBusDevice busdev;
>> PCIBus *bus;
>> @@ -77,7 +79,8 @@ typedef struct APBState {
>> uint32_t pci_control[16];
>> uint32_t pci_irq_map[8];
>> uint32_t obio_irq_map[32];
>> - qemu_irq pci_irqs[32];
>> + qemu_irq *pbm_irqs;
>> + qemu_irq *ivec_irqs;
>> uint32_t reset_control;
>> unsigned int nr_resets;
>> } APBState;
>> @@ -87,7 +90,7 @@ static void apb_config_writel (void *opaque,
>> target_phys_addr_t addr,
>> {
>> APBState *s = opaque;
>>
>> - APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
>> + APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n",
>> __func__, addr, val);
>>
>> switch (addr & 0xffff) {
>> case 0x30 ... 0x4f: /* DMA error registers */
>> @@ -104,6 +107,12 @@ static void apb_config_writel (void *opaque,
>> target_phys_addr_t addr,
>> s->pci_irq_map[(addr & 0x3f) >> 3] |= val & ~PBM_PCI_IMR_MASK;
>> }
>> break;
>> + case 0x1000 ... 0x1080: /* OBIO interrupt control */
>> + if (addr & 4) {
>> + s->obio_irq_map[(addr & 0xff) >> 3] &= PBM_PCI_IMR_MASK;
>> + s->obio_irq_map[(addr & 0xff) >> 3] |= val & ~PBM_PCI_IMR_MASK;
>> + }
>> + break;
>> case 0x2000 ... 0x202f: /* PCI control */
>> s->pci_control[(addr & 0x3f) >> 2] = val;
>> break;
>> @@ -154,6 +163,13 @@ static uint64_t apb_config_readl (void *opaque,
>> val = 0;
>> }
>> break;
>> + case 0x1000 ... 0x1080: /* OBIO interrupt control */
>> + if (addr & 4) {
>> + val = s->obio_irq_map[(addr & 0xff) >> 3];
>> + } else {
>> + val = 0;
>> + }
>> + break;
>> case 0x2000 ... 0x202f: /* PCI control */
>> val = s->pci_control[(addr & 0x3f) >> 2];
>> break;
>> @@ -190,7 +206,7 @@ static void apb_pci_config_write(void *opaque,
>> target_phys_addr_t addr,
>> APBState *s = opaque;
>>
>> val = qemu_bswap_len(val, size);
>> - APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr, val);
>> + APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n",
>> __func__, addr, val);
>> pci_data_write(s->bus, addr, val, size);
>> }
>>
>> @@ -280,10 +296,19 @@ static void pci_apb_set_irq(void *opaque, int
>> irq_num, int level)
>> if (irq_num < 32) {
>> if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
>> APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
>> - qemu_set_irq(s->pci_irqs[irq_num], level);
>> + qemu_set_irq(s->ivec_irqs[irq_num], level);
>> + } else {
>> + APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
>> + qemu_irq_lower(s->ivec_irqs[irq_num]);
>> + }
>> + } else {
>> + /* OBIO IRQ map onto the next 16 INO. */
>> + if (s->obio_irq_map[irq_num - 32] & PBM_PCI_IMR_ENABLED) {
>> + APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num, level);
>> + qemu_set_irq(s->ivec_irqs[irq_num], level);
>> } else {
>> APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__, irq_num);
>> - qemu_irq_lower(s->pci_irqs[irq_num]);
>> + qemu_irq_lower(s->ivec_irqs[irq_num]);
>> }
>> }
>> }
>> @@ -316,12 +341,12 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
>>
>> PCIBus *pci_apb_init(target_phys_addr_t special_base,
>> target_phys_addr_t mem_base,
>> - qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
>> + qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
>> + qemu_irq **pbm_irqs)
>> {
>> DeviceState *dev;
>> SysBusDevice *s;
>> APBState *d;
>> - unsigned int i;
>> PCIDevice *pci_dev;
>> PCIBridge *br;
>>
>> @@ -346,9 +371,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
>> get_system_io(),
>> 0, 32);
>>
>> - for (i = 0; i < 32; i++) {
>> - sysbus_connect_irq(s, i, pic[i]);
>> - }
>> + *pbm_irqs = d->pbm_irqs;
>> + d->ivec_irqs = ivec_irqs;
>>
>> pci_create_simple(d->bus, 0, "pbm-pci");
>>
>> @@ -402,9 +426,7 @@ static int pci_pbm_init_device(SysBusDevice *dev)
>> for (i = 0; i < 8; i++) {
>> s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
>> }
>> - for (i = 0; i < 32; i++) {
>> - sysbus_init_irq(dev, &s->pci_irqs[i]);
>> - }
>> + s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC);
>>
>> /* apb_config */
>> memory_region_init_io(&s->apb_config, &apb_config_ops, s, "apb-config",
>> diff --git a/hw/apb_pci.h b/hw/apb_pci.h
>> index 8869f9d..55f7c4c 100644
>> --- a/hw/apb_pci.h
>> +++ b/hw/apb_pci.h
>> @@ -5,5 +5,6 @@
>>
>> PCIBus *pci_apb_init(target_phys_addr_t special_base,
>> target_phys_addr_t mem_base,
>> - qemu_irq *pic, PCIBus **bus2, PCIBus **bus3);
>> + qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
>> + qemu_irq **pbm_irqs);
>> #endif
>> diff --git a/hw/sun4u.c b/hw/sun4u.c
>> index 423108f..e0adb9e 100644
>> --- a/hw/sun4u.c
>> +++ b/hw/sun4u.c
>> @@ -81,7 +81,7 @@
>> #define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
>> #define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
>>
>> -#define MAX_PILS 16
>> +#define IVEC_MAX 0x30
>>
>> #define TICK_MAX 0x7fffffffffffffffULL
>>
>> @@ -304,18 +304,24 @@ static void cpu_kick_irq(CPUState *env)
>> qemu_cpu_kick(env);
>> }
>>
>> -static void cpu_set_irq(void *opaque, int irq, int level)
>> +static void cpu_set_ivec_irq(void *opaque, int irq, int level)
>> {
>> CPUState *env = opaque;
>>
>> if (level) {
>> - CPUIRQ_DPRINTF("Raise CPU IRQ %d\n", irq);
>> - env->pil_in |= 1 << irq;
>> - cpu_kick_irq(env);
>> - } else {
>> - CPUIRQ_DPRINTF("Lower CPU IRQ %d\n", irq);
>> - env->pil_in &= ~(1 << irq);
>> - cpu_check_irqs(env);
>> + CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
>> + env->interrupt_index = TT_IVEC;
>> + env->pil_in |= 1 << 5;
>
> Err. Spurious irq 5?
Maybe, I can't find it in the manual and I can't remember why I did
that either. :-(
>
>> + env->ivec_status |= 0x20;
>> + env->ivec_data[0] = (0x1f << 6) | irq;
>> + env->ivec_data[1] = 0;
>> + env->ivec_data[2] = 0;
>> + cpu_interrupt(env, CPU_INTERRUPT_HARD);
>
> Shouldn't there be a cpu_interrupts_enabled(env) check before?
This is checked in the CPU loop, but the code there is not OK for
Sparc64 because of the assumptions with TT_EXTINT. I thought I fixed
that, but it looks like I didn't use that version for some reason.
>> + } else {
>> + CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
>> + env->pil_in &= ~(1 << 5);
>> + env->ivec_status &= ~0x20;
>> + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
>> }
>> }
>>
>> @@ -521,13 +527,29 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t limit)
>> }
>> }
>>
>> -static void dummy_isa_irq_handler(void *opaque, int n, int level)
>> +static void isa_irq_handler(void *opaque, int n, int level)
>> {
>> + static const int isa_irq_to_ivec[16] = {
>> + [1] = 0x29, /* keyboard */
>> + [4] = 0x2b, /* serial */
>> + [6] = 0x27, /* floppy */
>> + [7] = 0x22, /* parallel */
>> + [12] = 0x2a, /* mouse */
>> + };
>> + qemu_irq *irqs = opaque;
>> + int ivec;
>> +
>> + assert(n < 16);
>> + ivec = isa_irq_to_ivec[n];
>> + EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level, ivec);
>> + if (ivec) {
>> + qemu_set_irq(irqs[ivec], level);
>> + }
>> }
>>
>> /* EBUS (Eight bit bus) bridge */
>> static ISABus *
>> -pci_ebus_init(PCIBus *bus, int devfn)
>> +pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs)
>> {
>> qemu_irq *isa_irq;
>> PCIDevice *pci_dev;
>> @@ -536,7 +558,7 @@ pci_ebus_init(PCIBus *bus, int devfn)
>> pci_dev = pci_create_simple(bus, devfn, "ebus");
>> isa_bus = DO_UPCAST(ISABus, qbus,
>> qdev_get_child_bus(&pci_dev->qdev, "isa.0"));
>> - isa_irq = qemu_allocate_irqs(dummy_isa_irq_handler, NULL, 16);
>> + isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16);
>> isa_bus_irqs(isa_bus, isa_irq);
>> return isa_bus;
>> }
>> @@ -761,7 +783,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
>> long initrd_size, kernel_size;
>> PCIBus *pci_bus, *pci_bus2, *pci_bus3;
>> ISABus *isa_bus;
>> - qemu_irq *irq;
>> + qemu_irq *ivec_irqs, *pbm_irqs;
>> DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
>> DriveInfo *fd[MAX_FD];
>> void *fw_cfg;
>> @@ -774,14 +796,13 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
>>
>> prom_init(hwdef->prom_addr, bios_name);
>>
>> -
>> - irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
>> - pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq, &pci_bus2,
>> - &pci_bus3);
>> + ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, env, IVEC_MAX);
>> + pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs,
>> &pci_bus2,
>> + &pci_bus3, &pbm_irqs);
>> pci_vga_init(pci_bus);
>>
>> // XXX Should be pci_bus3
>> - isa_bus = pci_ebus_init(pci_bus, -1);
>> + isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs);
>>
>> i = 0;
>> if (hwdef->console_serial_base) {
>> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
>> index b81779b..8994000 100644
>> --- a/target-sparc/cpu.h
>> +++ b/target-sparc/cpu.h
>> @@ -491,6 +491,9 @@ typedef struct CPUSPARCState {
>> /* UA 2005 hyperprivileged registers */
>> uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr, ssr;
>> CPUTimer *hstick; // UA 2005
>> + /* Interrupt vector registers */
>> + uint64_t ivec_status;
>> + uint64_t ivec_data[3];
>> uint32_t softint;
>> #define SOFTINT_TIMER 1
>> #define SOFTINT_STIMER (1 << 16)
>> diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
>> index b59707e..4c34346 100644
>> --- a/target-sparc/ldst_helper.c
>> +++ b/target-sparc/ldst_helper.c
>> @@ -1526,6 +1526,19 @@ uint64_t helper_ld_asi(target_ulong addr, int
>> asi, int size, int sign)
>> ret = env->dtlb[reg].tag;
>> break;
>> }
>> + case 0x48: /* Interrupt dispatch, RO */
>> + break;
>> + case 0x49: /* Interrupt data receive */
>> + ret = env->ivec_status;
>> + break;
>> + case 0x7f: /* Incoming interrupt vector, RO */
>> + {
>> + int reg = (addr >> 4) & 0x3;
>> + if (reg < 3) {
>> + ret = env->ivec_data[reg];
>> + }
>> + break;
>> + }
>> case 0x46: /* D-cache data */
>> case 0x47: /* D-cache tag access */
>> case 0x4b: /* E-cache error enable */
>> @@ -1540,11 +1553,6 @@ uint64_t helper_ld_asi(target_ulong addr, int
>> asi, int size, int sign)
>> case 0x7e: /* E-cache tag */
>> break;
>> case 0x5b: /* D-MMU data pointer */
>> - case 0x48: /* Interrupt dispatch, RO */
>> - case 0x49: /* Interrupt data receive */
>> - case 0x7f: /* Incoming interrupt vector, RO */
>> - /* XXX */
>> - break;
>> case 0x54: /* I-MMU data in, WO */
>> case 0x57: /* I-MMU demap, WO */
>> case 0x5c: /* D-MMU data in, WO */
>> @@ -1954,7 +1962,7 @@ void helper_st_asi(target_ulong addr,
>> target_ulong val, int asi, int size)
>> demap_tlb(env->dtlb, addr, "dmmu", env);
>> return;
>> case 0x49: /* Interrupt data receive */
>> - /* XXX */
>> + env->ivec_status = val & 0x20;
>> return;
>> case 0x46: /* D-cache data */
>> case 0x47: /* D-cache tag access */
>> --
>> 1.7.9
>
>
>
> --
> Regards,
> Artyom Tarasenko
>
> solaris/sparc under qemu blog: http://tyom.blogspot.com/search/label/qemu
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] [PATCH 3/3] sparc64: implement PCI and ISA irqs
2012-03-27 19:26 ` Blue Swirl
@ 2012-03-28 17:55 ` Artyom Tarasenko
0 siblings, 0 replies; 4+ messages in thread
From: Artyom Tarasenko @ 2012-03-28 17:55 UTC (permalink / raw)
To: Blue Swirl; +Cc: qemu-devel, Michael S. Tsirkin
On 3/27/12, Blue Swirl <blauwirbel@gmail.com> wrote:
> On Tue, Mar 27, 2012 at 18:19, Artyom Tarasenko <atar4qemu@gmail.com> wrote:
>> On Sun, Mar 11, 2012 at 12:02 PM, Blue Swirl <blauwirbel@gmail.com> wrote:
>>> Generate correct trap for external interrupts. Map PCI and ISA IRQs to
>>> RIC/UltraSPARC-IIi interrupt vectors.
>>>
>>> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
>>> ---
>>> hw/apb_pci.c | 48 +++++++++++++++++++++++++++----------
>>> hw/apb_pci.h | 3 +-
>>> hw/sun4u.c | 57
>>> ++++++++++++++++++++++++++++++--------------
>>> target-sparc/cpu.h | 3 ++
>>> target-sparc/ldst_helper.c | 20 ++++++++++----
>>> 5 files changed, 93 insertions(+), 38 deletions(-)
>>>
>>> diff --git a/hw/apb_pci.c b/hw/apb_pci.c
>>> index b10f31e..7e28808 100644
>>> --- a/hw/apb_pci.c
>>> +++ b/hw/apb_pci.c
>>> @@ -66,6 +66,8 @@ do { printf("APB: " fmt , ## __VA_ARGS__); } while (0)
>>> #define RESET_WCMASK 0x98000000
>>> #define RESET_WMASK 0x60000000
>>>
>>> +#define MAX_IVEC 0x30
>>
>> Shouldn't that be 0x40 (0x20 for OBIO and 0x20 for PCI)? I mean in
>> theory, obviously not all of them are used.
>
> This is the maximum number (0x30 is PCI Bus Error), which actually
> means that number of IRQ lines allocated should be MAX_IVEC + 1.
MAX_IVEC + 3 ;-). 0x32 is power management wakeup
(http://fxr.watson.org/fxr/source/sun4u/io/pci/pci_intr.c?v=OPENSOLARIS)
> 0x40 wouldn't hurt much.
>
>>> +
>>> typedef struct APBState {
>>> SysBusDevice busdev;
>>> PCIBus *bus;
>>> @@ -77,7 +79,8 @@ typedef struct APBState {
>>> uint32_t pci_control[16];
>>> uint32_t pci_irq_map[8];
>>> uint32_t obio_irq_map[32];
>>> - qemu_irq pci_irqs[32];
>>> + qemu_irq *pbm_irqs;
>>> + qemu_irq *ivec_irqs;
>>> uint32_t reset_control;
>>> unsigned int nr_resets;
>>> } APBState;
>>> @@ -87,7 +90,7 @@ static void apb_config_writel (void *opaque,
>>> target_phys_addr_t addr,
>>> {
>>> APBState *s = opaque;
>>>
>>> - APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr,
>>> val);
>>> + APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n",
>>> __func__, addr, val);
>>>
>>> switch (addr & 0xffff) {
>>> case 0x30 ... 0x4f: /* DMA error registers */
>>> @@ -104,6 +107,12 @@ static void apb_config_writel (void *opaque,
>>> target_phys_addr_t addr,
>>> s->pci_irq_map[(addr & 0x3f) >> 3] |= val &
>>> ~PBM_PCI_IMR_MASK;
>>> }
>>> break;
>>> + case 0x1000 ... 0x1080: /* OBIO interrupt control */
>>> + if (addr & 4) {
>>> + s->obio_irq_map[(addr & 0xff) >> 3] &= PBM_PCI_IMR_MASK;
>>> + s->obio_irq_map[(addr & 0xff) >> 3] |= val &
>>> ~PBM_PCI_IMR_MASK;
>>> + }
>>> + break;
>>> case 0x2000 ... 0x202f: /* PCI control */
>>> s->pci_control[(addr & 0x3f) >> 2] = val;
>>> break;
>>> @@ -154,6 +163,13 @@ static uint64_t apb_config_readl (void *opaque,
>>> val = 0;
>>> }
>>> break;
>>> + case 0x1000 ... 0x1080: /* OBIO interrupt control */
>>> + if (addr & 4) {
>>> + val = s->obio_irq_map[(addr & 0xff) >> 3];
>>> + } else {
>>> + val = 0;
>>> + }
>>> + break;
>>> case 0x2000 ... 0x202f: /* PCI control */
>>> val = s->pci_control[(addr & 0x3f) >> 2];
>>> break;
>>> @@ -190,7 +206,7 @@ static void apb_pci_config_write(void *opaque,
>>> target_phys_addr_t addr,
>>> APBState *s = opaque;
>>>
>>> val = qemu_bswap_len(val, size);
>>> - APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %x\n", __func__, addr,
>>> val);
>>> + APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n",
>>> __func__, addr, val);
>>> pci_data_write(s->bus, addr, val, size);
>>> }
>>>
>>> @@ -280,10 +296,19 @@ static void pci_apb_set_irq(void *opaque, int
>>> irq_num, int level)
>>> if (irq_num < 32) {
>>> if (s->pci_irq_map[irq_num >> 2] & PBM_PCI_IMR_ENABLED) {
>>> APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num,
>>> level);
>>> - qemu_set_irq(s->pci_irqs[irq_num], level);
>>> + qemu_set_irq(s->ivec_irqs[irq_num], level);
>>> + } else {
>>> + APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__,
>>> irq_num);
>>> + qemu_irq_lower(s->ivec_irqs[irq_num]);
>>> + }
>>> + } else {
>>> + /* OBIO IRQ map onto the next 16 INO. */
>>> + if (s->obio_irq_map[irq_num - 32] & PBM_PCI_IMR_ENABLED) {
>>> + APB_DPRINTF("%s: set irq %d level %d\n", __func__, irq_num,
>>> level);
>>> + qemu_set_irq(s->ivec_irqs[irq_num], level);
>>> } else {
>>> APB_DPRINTF("%s: not enabled: lower irq %d\n", __func__,
>>> irq_num);
>>> - qemu_irq_lower(s->pci_irqs[irq_num]);
>>> + qemu_irq_lower(s->ivec_irqs[irq_num]);
>>> }
>>> }
>>> }
>>> @@ -316,12 +341,12 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
>>>
>>> PCIBus *pci_apb_init(target_phys_addr_t special_base,
>>> target_phys_addr_t mem_base,
>>> - qemu_irq *pic, PCIBus **bus2, PCIBus **bus3)
>>> + qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
>>> + qemu_irq **pbm_irqs)
>>> {
>>> DeviceState *dev;
>>> SysBusDevice *s;
>>> APBState *d;
>>> - unsigned int i;
>>> PCIDevice *pci_dev;
>>> PCIBridge *br;
>>>
>>> @@ -346,9 +371,8 @@ PCIBus *pci_apb_init(target_phys_addr_t special_base,
>>> get_system_io(),
>>> 0, 32);
>>>
>>> - for (i = 0; i < 32; i++) {
>>> - sysbus_connect_irq(s, i, pic[i]);
>>> - }
>>> + *pbm_irqs = d->pbm_irqs;
>>> + d->ivec_irqs = ivec_irqs;
>>>
>>> pci_create_simple(d->bus, 0, "pbm-pci");
>>>
>>> @@ -402,9 +426,7 @@ static int pci_pbm_init_device(SysBusDevice *dev)
>>> for (i = 0; i < 8; i++) {
>>> s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
>>> }
>>> - for (i = 0; i < 32; i++) {
>>> - sysbus_init_irq(dev, &s->pci_irqs[i]);
>>> - }
>>> + s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC);
>>>
>>> /* apb_config */
>>> memory_region_init_io(&s->apb_config, &apb_config_ops, s,
>>> "apb-config",
>>> diff --git a/hw/apb_pci.h b/hw/apb_pci.h
>>> index 8869f9d..55f7c4c 100644
>>> --- a/hw/apb_pci.h
>>> +++ b/hw/apb_pci.h
>>> @@ -5,5 +5,6 @@
>>>
>>> PCIBus *pci_apb_init(target_phys_addr_t special_base,
>>> target_phys_addr_t mem_base,
>>> - qemu_irq *pic, PCIBus **bus2, PCIBus **bus3);
>>> + qemu_irq *ivec_irqs, PCIBus **bus2, PCIBus **bus3,
>>> + qemu_irq **pbm_irqs);
>>> #endif
>>> diff --git a/hw/sun4u.c b/hw/sun4u.c
>>> index 423108f..e0adb9e 100644
>>> --- a/hw/sun4u.c
>>> +++ b/hw/sun4u.c
>>> @@ -81,7 +81,7 @@
>>> #define FW_CFG_SPARC64_HEIGHT (FW_CFG_ARCH_LOCAL + 0x01)
>>> #define FW_CFG_SPARC64_DEPTH (FW_CFG_ARCH_LOCAL + 0x02)
>>>
>>> -#define MAX_PILS 16
>>> +#define IVEC_MAX 0x30
>>>
>>> #define TICK_MAX 0x7fffffffffffffffULL
>>>
>>> @@ -304,18 +304,24 @@ static void cpu_kick_irq(CPUState *env)
>>> qemu_cpu_kick(env);
>>> }
>>>
>>> -static void cpu_set_irq(void *opaque, int irq, int level)
>>> +static void cpu_set_ivec_irq(void *opaque, int irq, int level)
>>> {
>>> CPUState *env = opaque;
>>>
>>> if (level) {
>>> - CPUIRQ_DPRINTF("Raise CPU IRQ %d\n", irq);
>>> - env->pil_in |= 1 << irq;
>>> - cpu_kick_irq(env);
>>> - } else {
>>> - CPUIRQ_DPRINTF("Lower CPU IRQ %d\n", irq);
>>> - env->pil_in &= ~(1 << irq);
>>> - cpu_check_irqs(env);
>>> + CPUIRQ_DPRINTF("Raise IVEC IRQ %d\n", irq);
>>> + env->interrupt_index = TT_IVEC;
>>> + env->pil_in |= 1 << 5;
>>
>> Err. Spurious irq 5?
>
> Maybe, I can't find it in the manual and I can't remember why I did
> that either. :-(
>
>>
>>> + env->ivec_status |= 0x20;
>>> + env->ivec_data[0] = (0x1f << 6) | irq;
>>> + env->ivec_data[1] = 0;
>>> + env->ivec_data[2] = 0;
>>> + cpu_interrupt(env, CPU_INTERRUPT_HARD);
>>
>> Shouldn't there be a cpu_interrupts_enabled(env) check before?
>
> This is checked in the CPU loop, but the code there is not OK for
> Sparc64 because of the assumptions with TT_EXTINT. I thought I fixed
> that, but it looks like I didn't use that version for some reason.
And btw, what happens if multiple vector interrupts are triggered? I
think ivec_data shan't be overwritten if ivec_status!=0.
>>> + } else {
>>> + CPUIRQ_DPRINTF("Lower IVEC IRQ %d\n", irq);
>>> + env->pil_in &= ~(1 << 5);
>>> + env->ivec_status &= ~0x20;
>>> + cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
>>> }
>>> }
>>>
>>> @@ -521,13 +527,29 @@ void cpu_tick_set_limit(CPUTimer *timer, uint64_t
>>> limit)
>>> }
>>> }
>>>
>>> -static void dummy_isa_irq_handler(void *opaque, int n, int level)
>>> +static void isa_irq_handler(void *opaque, int n, int level)
>>> {
>>> + static const int isa_irq_to_ivec[16] = {
>>> + [1] = 0x29, /* keyboard */
>>> + [4] = 0x2b, /* serial */
>>> + [6] = 0x27, /* floppy */
>>> + [7] = 0x22, /* parallel */
>>> + [12] = 0x2a, /* mouse */
>>> + };
>>> + qemu_irq *irqs = opaque;
>>> + int ivec;
>>> +
>>> + assert(n < 16);
>>> + ivec = isa_irq_to_ivec[n];
>>> + EBUS_DPRINTF("Set ISA IRQ %d level %d -> ivec 0x%x\n", n, level,
>>> ivec);
>>> + if (ivec) {
>>> + qemu_set_irq(irqs[ivec], level);
>>> + }
>>> }
>>>
>>> /* EBUS (Eight bit bus) bridge */
>>> static ISABus *
>>> -pci_ebus_init(PCIBus *bus, int devfn)
>>> +pci_ebus_init(PCIBus *bus, int devfn, qemu_irq *irqs)
>>> {
>>> qemu_irq *isa_irq;
>>> PCIDevice *pci_dev;
>>> @@ -536,7 +558,7 @@ pci_ebus_init(PCIBus *bus, int devfn)
>>> pci_dev = pci_create_simple(bus, devfn, "ebus");
>>> isa_bus = DO_UPCAST(ISABus, qbus,
>>> qdev_get_child_bus(&pci_dev->qdev, "isa.0"));
>>> - isa_irq = qemu_allocate_irqs(dummy_isa_irq_handler, NULL, 16);
>>> + isa_irq = qemu_allocate_irqs(isa_irq_handler, irqs, 16);
>>> isa_bus_irqs(isa_bus, isa_irq);
>>> return isa_bus;
>>> }
>>> @@ -761,7 +783,7 @@ static void sun4uv_init(MemoryRegion
>>> *address_space_mem,
>>> long initrd_size, kernel_size;
>>> PCIBus *pci_bus, *pci_bus2, *pci_bus3;
>>> ISABus *isa_bus;
>>> - qemu_irq *irq;
>>> + qemu_irq *ivec_irqs, *pbm_irqs;
>>> DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
>>> DriveInfo *fd[MAX_FD];
>>> void *fw_cfg;
>>> @@ -774,14 +796,13 @@ static void sun4uv_init(MemoryRegion
>>> *address_space_mem,
>>>
>>> prom_init(hwdef->prom_addr, bios_name);
>>>
>>> -
>>> - irq = qemu_allocate_irqs(cpu_set_irq, env, MAX_PILS);
>>> - pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, irq,
>>> &pci_bus2,
>>> - &pci_bus3);
>>> + ivec_irqs = qemu_allocate_irqs(cpu_set_ivec_irq, env, IVEC_MAX);
>>> + pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, ivec_irqs,
>>> &pci_bus2,
>>> + &pci_bus3, &pbm_irqs);
>>> pci_vga_init(pci_bus);
>>>
>>> // XXX Should be pci_bus3
>>> - isa_bus = pci_ebus_init(pci_bus, -1);
>>> + isa_bus = pci_ebus_init(pci_bus, -1, pbm_irqs);
>>>
>>> i = 0;
>>> if (hwdef->console_serial_base) {
>>> diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
>>> index b81779b..8994000 100644
>>> --- a/target-sparc/cpu.h
>>> +++ b/target-sparc/cpu.h
>>> @@ -491,6 +491,9 @@ typedef struct CPUSPARCState {
>>> /* UA 2005 hyperprivileged registers */
>>> uint64_t hpstate, htstate[MAXTL_MAX], hintp, htba, hver, hstick_cmpr,
>>> ssr;
>>> CPUTimer *hstick; // UA 2005
>>> + /* Interrupt vector registers */
>>> + uint64_t ivec_status;
>>> + uint64_t ivec_data[3];
>>> uint32_t softint;
>>> #define SOFTINT_TIMER 1
>>> #define SOFTINT_STIMER (1 << 16)
>>> diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
>>> index b59707e..4c34346 100644
>>> --- a/target-sparc/ldst_helper.c
>>> +++ b/target-sparc/ldst_helper.c
>>> @@ -1526,6 +1526,19 @@ uint64_t helper_ld_asi(target_ulong addr, int
>>> asi, int size, int sign)
>>> ret = env->dtlb[reg].tag;
>>> break;
>>> }
>>> + case 0x48: /* Interrupt dispatch, RO */
>>> + break;
>>> + case 0x49: /* Interrupt data receive */
>>> + ret = env->ivec_status;
>>> + break;
>>> + case 0x7f: /* Incoming interrupt vector, RO */
>>> + {
>>> + int reg = (addr >> 4) & 0x3;
>>> + if (reg < 3) {
>>> + ret = env->ivec_data[reg];
>>> + }
>>> + break;
>>> + }
>>> case 0x46: /* D-cache data */
>>> case 0x47: /* D-cache tag access */
>>> case 0x4b: /* E-cache error enable */
>>> @@ -1540,11 +1553,6 @@ uint64_t helper_ld_asi(target_ulong addr, int
>>> asi, int size, int sign)
>>> case 0x7e: /* E-cache tag */
>>> break;
>>> case 0x5b: /* D-MMU data pointer */
>>> - case 0x48: /* Interrupt dispatch, RO */
>>> - case 0x49: /* Interrupt data receive */
>>> - case 0x7f: /* Incoming interrupt vector, RO */
>>> - /* XXX */
>>> - break;
>>> case 0x54: /* I-MMU data in, WO */
>>> case 0x57: /* I-MMU demap, WO */
>>> case 0x5c: /* D-MMU data in, WO */
>>> @@ -1954,7 +1962,7 @@ void helper_st_asi(target_ulong addr,
>>> target_ulong val, int asi, int size)
>>> demap_tlb(env->dtlb, addr, "dmmu", env);
>>> return;
>>> case 0x49: /* Interrupt data receive */
>>> - /* XXX */
>>> + env->ivec_status = val & 0x20;
>>> return;
>>> case 0x46: /* D-cache data */
>>> case 0x47: /* D-cache tag access */
>>> --
>>> 1.7.9
>>
>>
>>
>> --
>> Regards,
>> Artyom Tarasenko
>>
>> solaris/sparc under qemu blog: http://tyom.blogspot.com/search/label/qemu
>
--
Regards,
Artyom Tarasenko
solaris/sparc under qemu blog: http://tyom.blogspot.com/search/label/qemu
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-03-28 17:55 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-11 11:02 [Qemu-devel] [PATCH 3/3] sparc64: implement PCI and ISA irqs Blue Swirl
2012-03-27 18:19 ` Artyom Tarasenko
2012-03-27 19:26 ` Blue Swirl
2012-03-28 17:55 ` Artyom Tarasenko
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.