On Tue, Mar 27, 2012 at 18:19, Artyom Tarasenko <atar4q...@gmail.com> wrote: > On Sun, Mar 11, 2012 at 12:02 PM, Blue Swirl <blauwir...@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 <blauwir...@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