The modify is based on original author's method to switch openpic and mpic by static define, like the switch between USE_INTEL_GW80314 and USE_MPCxxx. (Although the support for intel has broken) So they can't be used at the same time. I guess it's not the correct way to do this. but I am not sure is the USE_MPC85xx and openpic are still needed? Signed-off-by: Liu Yu <yu.liu@xxxxxxxxxxxxx> --- hw/openpic.c | 384 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- hw/openpic.h | 19 +++ hw/ppc_mac.h | 14 +-- 3 files changed, 389 insertions(+), 28 deletions(-) create mode 100644 hw/openpic.h diff --git a/hw/openpic.c b/hw/openpic.c index b8da4d7..bc5f72b 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -35,6 +35,7 @@ #include "hw.h" #include "ppc_mac.h" #include "pci.h" +#include "openpic.h" //#define DEBUG_OPENPIC @@ -45,7 +46,8 @@ #endif #define ERROR(fmr, args...) do { printf("ERROR: " fmr , ##args); } while (0) -#define USE_MPCxxx /* Intel model is broken, for now */ +/*#define USE_MPCxxx |+ Intel model is broken, for now +|*/ +#define USE_MPC85xx /* Intel model is broken, for now */ #if defined (USE_INTEL_GW80314) /* Intel GW80314 I/O Companion chip */ @@ -84,15 +86,6 @@ enum { #define OPENPIC_LITTLE_ENDIAN 1 #define OPENPIC_BIG_ENDIAN 0 -#else -#error "Please select which OpenPic implementation is to be emulated" -#endif - -#if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \ - (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN) -#define OPENPIC_SWAP -#endif - /* Interrupt definitions */ #define IRQ_FE (EXT_IRQ) /* Internal functional IRQ */ #define IRQ_ERR (EXT_IRQ + 1) /* Error IRQ */ @@ -105,6 +98,61 @@ enum { #define IRQ_MBX0 (IRQ_DBL0 + MAX_DBL) /* First mailbox IRQ */ #endif +#elif defined(USE_MPC85xx) + +#define MPIC_MAP_SIZE 0x40000 + +#define MAX_CPU 1 +#define MAX_EXT 12 +#define MAX_INT 64 +#define MAX_DBL 0 +#define MAX_MBX 0 +#define MAX_TMR 4 +#define MAX_MSG 4 +#define MAX_MSI 8 +#define MAX_IPI 4 +#define MAX_IRQ (MAX_EXT + MAX_INT + MAX_TMR + MAX_MSG + MAX_MSI + (MAX_IPI * MAX_CPU)) + +#define VECTOR_BITS 8 +#define VID 0x0 /* MPIC version ID */ +#define VENI 0x00000000 /* Vendor ID */ + +enum { + IRQ_IPVP = 0, + IRQ_IDE, +}; + +enum ide_bits { + IDR_EP = 0, + IDR_CI0 = 1, + IDR_CI1 = 2, + IDR_P1 = 30, + IDR_P0 = 31, +}; + +#define OPENPIC_LITTLE_ENDIAN 0 +#define OPENPIC_BIG_ENDIAN 1 + +/* Interrupt definitions */ +#define EXT_IRQ 0 +#define INT_IRQ (EXT_IRQ + MAX_EXT) +#define TMR_IRQ (INT_IRQ + MAX_INT) +#define MSG_IRQ (TMR_IRQ + MAX_TMR) +#define MSI_IRQ (MSG_IRQ + MAX_MSG) +#define IPI_IRQ (MSI_IRQ + MAX_MSI) + +#define IRQ_IPI0 IPI_IRQ +#define IRQ_TIM0 TMR_IRQ + +#else +#error "Please select which OpenPic implementation is to be emulated" +#endif + +#if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \ + (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN) +#define OPENPIC_SWAP +#endif + #define BF_WIDTH(_bits_) \ (((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8)) @@ -157,6 +205,7 @@ enum IPVP_bits { #define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) typedef struct IRQ_dst_t { + uint32_t tfrr; uint32_t pctp; /* CPU current task priority */ uint32_t pcsr; /* CPU sensitivity register */ IRQ_queue_t raised; @@ -200,6 +249,8 @@ typedef struct openpic_t { #endif /* IRQ out is used when in bypass mode (not implemented) */ qemu_irq irq_out; + void (*reset) (struct openpic_t *); + void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *); } openpic_t; static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) @@ -286,7 +337,7 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) return; } DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ); - qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); + opp->irq_raise(opp, n_CPU, src); } /* update pic state because registers for n_IRQ have changed value */ @@ -551,8 +602,8 @@ static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val) case 0x00: /* FREP */ break; case 0x20: /* GLBC */ - if (val & 0x80000000) - openpic_reset(opp); + if (val & 0x80000000 && opp->reset) + opp->reset(opp); opp->glbc = val & ~0x80000000; break; case 0x80: /* VENI */ @@ -818,7 +869,7 @@ static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) { DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", idx, n_IRQ); - qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); + opp->irq_raise(opp, idx, src); } break; default: @@ -1001,6 +1052,11 @@ static void openpic_map(PCIDevice *pci_dev, int region_num, #endif } +static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src) +{ + qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); +} + qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, qemu_irq **irqs, qemu_irq irq_out) { @@ -1058,9 +1114,307 @@ qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, for (i = 0; i < nb_cpus; i++) opp->dst[i].irqs = irqs[i]; opp->irq_out = irq_out; - openpic_reset(opp); + + opp->irq_raise = openpic_irq_raise; + opp->reset = openpic_reset; + + opp->reset(opp); if (pmem_index) *pmem_index = opp->mem_index; return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ); } + +static void mpic_irq_raise(openpic_t *mpp, int n_CPU, IRQ_src_t *src) +{ + int n_ci = IDR_CI0 - n_CPU; + DPRINTF("%s: cpu:%d irq:%d (testbit idr:%x ci:%d)\n", __func__, + n_CPU, n_IRQ, mpp->src[n_IRQ].ide, n_ci); + if(test_bit(&src->ide, n_ci)) { + qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]); + } + else { + qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); + } +} + +static void mpic_reset (openpic_t *mpp) +{ + int i; + + mpp->glbc = 0x80000000; + /* Initialise controller registers */ + mpp->frep = 0x004f0002; + mpp->veni = VENI; + mpp->pint = 0x00000000; + mpp->spve = 0x0000FFFF; + /* Initialise IRQ sources */ + for (i = 0; i < MAX_IRQ; i++) { + mpp->src[i].ipvp = 0x80800000; + mpp->src[i].ide = 0x00000001; + } + /* Initialise IRQ destinations */ + for (i = 0; i < MAX_CPU; i++) { + mpp->dst[i].pctp = 0x0000000F; + mpp->dst[i].tfrr = 0x00000000; + memset(&mpp->dst[i].raised, 0, sizeof(IRQ_queue_t)); + mpp->dst[i].raised.next = -1; + memset(&mpp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); + mpp->dst[i].servicing.next = -1; + } + /* Initialise timers */ + for (i = 0; i < MAX_TMR; i++) { + mpp->timers[i].ticc = 0x00000000; + mpp->timers[i].tibc = 0x80000000; + } + /* Go out of RESET state */ + mpp->glbc = 0x00000000; +} + +static void mpic_timer_write (void *opaque, uint32_t addr, uint32_t val) +{ + openpic_t *mpp = opaque; + int idx, cpu; + + DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); + if (addr & 0xF) + return; +#if defined MPIC_SWAP + val = bswap32(val); +#endif + addr &= 0xFFFF; + cpu = addr >> 12; + idx = (addr >> 6) & 0x3; + switch (addr & 0x30) { + case 0x00: /* gtccr */ + break; + case 0x10: /* gtbcr */ + if ((mpp->timers[idx].ticc & 0x80000000) != 0 && + (val & 0x80000000) == 0 && + (mpp->timers[idx].tibc & 0x80000000) != 0) + mpp->timers[idx].ticc &= ~0x80000000; + mpp->timers[idx].tibc = val; + break; + case 0x20: /* GTIVPR */ + write_IRQreg(mpp, TMR_IRQ + idx, IRQ_IPVP, val); + break; + case 0x30: /* GTIDR & TFRR */ + if ((addr & 0xF0) == 0xF0) + mpp->dst[cpu].tfrr = val; + else + write_IRQreg(mpp, TMR_IRQ + idx, IRQ_IDE, val); + break; + } +} + +static uint32_t mpic_timer_read (void *opaque, uint32_t addr) +{ + openpic_t *mpp = opaque; + uint32_t retval; + int idx, cpu; + + DPRINTF("%s: addr %08x\n", __func__, addr); + retval = 0xFFFFFFFF; + if (addr & 0xF) + return retval; + addr &= 0xFFFF; + cpu = addr >> 12; + idx = (addr >> 6) & 0x3; + switch (addr & 0x30) { + case 0x00: /* gtccr */ + retval = mpp->timers[idx].ticc; + break; + case 0x10: /* gtbcr */ + retval = mpp->timers[idx].tibc; + break; + case 0x20: /* TIPV */ + retval = read_IRQreg(mpp, TMR_IRQ + idx, IRQ_IPVP); + break; + case 0x30: /* TIDR */ + if ((addr &0xF0) == 0XF0) + retval = mpp->dst[cpu].tfrr; + else + retval = read_IRQreg(mpp, TMR_IRQ + idx, IRQ_IDE); + break; + } + DPRINTF("%s: => %08x\n", __func__, retval); +#if defined MPIC_SWAP + retval = bswap32(retval); +#endif + + return retval; +} + +static void mpic_src_write (void *opaque, uint32_t addr, uint32_t val) +{ + openpic_t *mpp = opaque; + int idx; + + DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); + if (addr & 0xF) + return; +#if defined MPIC_SWAP + val = tswap32(val); +#endif + addr = addr & 0xFFF0; + if (addr < 0x180) { + idx = EXT_IRQ; + } else if (addr >= 0x200 && addr < 0xa00) { + idx = INT_IRQ; + addr -= 0x200; + } else if (addr >= 0x1600 && addr < 0x1700) { + idx = MSG_IRQ; + addr -= 0x1600; + } else if (addr >= 0x1C00 && addr < 0x1D00) { + idx = MSI_IRQ; + addr -= 0x1C00; + } else { + return; + } + idx += addr >> 5; + if (addr & 0x10) { + /* EXDE / IFEDE / IEEDE */ + write_IRQreg(mpp, idx, IRQ_IDE, val); + } else { + /* EXVP / IFEVP / IEEVP */ + write_IRQreg(mpp, idx, IRQ_IPVP, val); + } +} + +static uint32_t mpic_src_read (void *opaque, uint32_t addr) +{ + openpic_t *mpp = opaque; + uint32_t retval; + int idx; + + DPRINTF("%s: addr %08x\n", __func__, addr); + retval = 0xFFFFFFFF; + if (addr & 0xF) + return retval; + addr = addr & 0xFFF0; + if (addr < 0x180) { + idx = EXT_IRQ; + } else if (addr >= 0x200 && addr < 0xa00) { + idx = INT_IRQ; + addr -= 0x200; + } else if (addr >= 0x1600 && addr < 0x1700) { + idx = MSG_IRQ; + addr -= 0x1600; + } else if (addr >= 0x1C00 && addr < 0x1D00) { + idx = MSI_IRQ; + addr -= 0x1C00; + } else { + return retval; + } + idx += addr >> 5; + if (addr & 0x10) { + /* EXDE / IFEDE / IEEDE */ + retval = read_IRQreg(mpp, idx, IRQ_IDE); + } else { + /* EXVP / IFEVP / IEEVP */ + retval = read_IRQreg(mpp, idx, IRQ_IPVP); + } + DPRINTF("%s: => %08x\n", __func__, retval); +#if defined MPIC_SWAP + retval = tswap32(retval); +#endif + + return retval; +} + +static void mpic_writel (void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + openpic_t *mpp = opaque; + + addr &= 0x3FFFF; + DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val); + if (addr < 0x10F0) { + /* Global registers */ + openpic_gbl_write(mpp, addr, val); + } else if (addr < 0x10000) { + /* Timers registers */ + mpic_timer_write(mpp, addr, val); + } else if (addr < 0x20000) { + /* Source registers */ + mpic_src_write(mpp, addr, val); + } else if (addr < 0x30000){ + /* CPU registers */ + openpic_cpu_write(mpp, addr, val); + } else { + DPRINTF("wrong mpic write addr %p\n",addr); + } +} + +static uint32_t mpic_readl (void *opaque,target_phys_addr_t addr) +{ + openpic_t *mpp = opaque; + uint32_t retval = 0; + + addr &= 0x3FFFF; + DPRINTF("%s: offset %08x\n", __func__, (int)addr); + if (addr < 0x10F0) { + /* Global registers */ + retval = openpic_gbl_read(mpp, addr); + } else if (addr < 0x10000) { + /* Timers registers */ + retval = mpic_timer_read(mpp, addr); + } else if (addr < 0x20000) { + /* Source registers */ + retval = mpic_src_read(mpp, addr); + } else if (addr < 0x30000){ + /* CPU registers */ + retval = openpic_cpu_read(mpp, addr); + } else { + DPRINTF("wrong mpic read addr %p\n",addr); + } + + return retval; +} + +static CPUWriteMemoryFunc *mpic_write[] = { + &openpic_buggy_write, + &openpic_buggy_write, + &mpic_writel, +}; + +static CPUReadMemoryFunc *mpic_read[] = { + &openpic_buggy_read, + &openpic_buggy_read, + &mpic_readl, +}; + +qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus, + qemu_irq **irqs, qemu_irq irq_out) +{ + openpic_t *mpp; + int i; + + /* XXX: for now, only one CPU is supported */ + if (nb_cpus != 1) + return NULL; + + mpp = qemu_mallocz(sizeof(openpic_t)); + + mpp->mem_index = cpu_register_io_memory(0, mpic_read, mpic_write, mpp); + if (mpp->mem_index < 0) + goto free; + cpu_register_physical_memory(base, MPIC_MAP_SIZE, mpp->mem_index); + + mpp->nb_cpus = nb_cpus; + + for (i = 0; i < nb_cpus; i++) + mpp->dst[i].irqs = irqs[i]; + mpp->irq_out = irq_out; + + mpp->irq_raise = mpic_irq_raise; + mpp->reset = mpic_reset; + + mpp->reset(mpp); + + return qemu_allocate_irqs(openpic_set_irq, mpp, MAX_IRQ); + +free: + qemu_free(mpp); + return NULL; +} diff --git a/hw/openpic.h b/hw/openpic.h new file mode 100644 index 0000000..2f85e16 --- /dev/null +++ b/hw/openpic.h @@ -0,0 +1,19 @@ + +#if !defined(OPENPIC_H) +#define OPENPIC_H + +/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */ +enum { + OPENPIC_OUTPUT_INT = 0, /* IRQ */ + OPENPIC_OUTPUT_CINT, /* critical IRQ */ + OPENPIC_OUTPUT_MCK, /* Machine check event */ + OPENPIC_OUTPUT_DEBUG, /* Inconditional debug event */ + OPENPIC_OUTPUT_RESET, /* Core reset event */ + OPENPIC_OUTPUT_NB, +}; + +qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, + qemu_irq **irqs, qemu_irq irq_out); +qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus, + qemu_irq **irqs, qemu_irq irq_out); +#endif /* OPENPIC_H */ diff --git a/hw/ppc_mac.h b/hw/ppc_mac.h index cc70fb7..bf987b1 100644 --- a/hw/ppc_mac.h +++ b/hw/ppc_mac.h @@ -113,17 +113,5 @@ void adb_mouse_init(ADBBusState *bus); extern ADBBusState adb_bus; -/* openpic.c */ -/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */ -enum { - OPENPIC_OUTPUT_INT = 0, /* IRQ */ - OPENPIC_OUTPUT_CINT, /* critical IRQ */ - OPENPIC_OUTPUT_MCK, /* Machine check event */ - OPENPIC_OUTPUT_DEBUG, /* Inconditional debug event */ - OPENPIC_OUTPUT_RESET, /* Core reset event */ - OPENPIC_OUTPUT_NB, -}; -qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus, - qemu_irq **irqs, qemu_irq irq_out); - +#include "openpic.h" #endif /* !defined(__PPC_MAC_H__) */ -- 1.5.4 -- To unsubscribe from this list: send the line "unsubscribe kvm-ppc" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html