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. > + > 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