Message ID | CAAu8pHvu1kp02kz-dvBNFYdV5Fnatj8b5t+s6xTYeYCTxxKVXg@mail.gmail.com |
---|---|
State | New |
Headers | show |
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
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
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 >
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
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(-) 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 */