X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/6e355d901baec118f0eb40ecd75a4278625f5d03..bdd4df332a1bdb20b7fa39ea741f7830e41e1187:/hw/openpic.c diff --git a/hw/openpic.c b/hw/openpic.c index 68af9c1de1..8b3784a6bd 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -2,6 +2,7 @@ * OpenPIC emulation * * Copyright (c) 2004 Jocelyn Mayer + * 2011 Alexander Graf * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -56,13 +57,13 @@ #define MAX_MBX 4 #define MAX_TMR 4 #define VECTOR_BITS 8 -#define MAX_IPI 0 +#define MAX_IPI 4 #define VID (0x00000000) #elif defined(USE_MPCxxx) -#define MAX_CPU 2 +#define MAX_CPU 15 #define MAX_IRQ 128 #define MAX_DBL 0 #define MAX_MBX 0 @@ -127,20 +128,33 @@ enum { #define MPIC_MSI_REG_START 0x11C00 #define MPIC_MSI_REG_SIZE 0x100 #define MPIC_CPU_REG_START 0x20000 -#define MPIC_CPU_REG_SIZE 0x100 +#define MPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000) + +/* + * Block Revision Register1 (BRR1): QEMU does not fully emulate + * any version on MPIC. So to start with, set the IP version to 0. + * + * NOTE: This is Freescale MPIC specific register. Keep it here till + * this code is refactored for different variants of OPENPIC and MPIC. + */ +#define FSL_BRR1_IPID (0x0040 << 16) /* 16 bit IP-block ID */ +#define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */ +#define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */ enum mpic_ide_bits { - IDR_EP = 0, - IDR_CI0 = 1, - IDR_CI1 = 2, - IDR_P1 = 30, - IDR_P0 = 31, + IDR_EP = 31, + IDR_CI0 = 30, + IDR_CI1 = 29, + IDR_P1 = 1, + IDR_P0 = 0, }; #else #error "Please select which OpenPic implementation is to be emulated" #endif +#define OPENPIC_PAGE_SIZE 4096 + #define BF_WIDTH(_bits_) \ (((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8)) @@ -159,6 +173,16 @@ static inline int test_bit (uint32_t *field, int bit) return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0; } +static int get_current_cpu(void) +{ + return cpu_single_env->cpu_index; +} + +static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, + int idx); +static void openpic_cpu_write_internal(void *opaque, hwaddr addr, + uint32_t val, int idx); + enum { IRQ_EXTERNAL = 0x01, IRQ_INTERNAL = 0x02, @@ -203,7 +227,11 @@ typedef struct IRQ_dst_t { typedef struct openpic_t { PCIDevice pci_dev; - int mem_index; + MemoryRegion mem; + + /* Sub-regions */ + MemoryRegion sub_io_mem[7]; + /* Global registers */ uint32_t frep; /* Feature reporting register */ uint32_t glbc; /* Global configuration register */ @@ -219,20 +247,20 @@ typedef struct openpic_t { int nb_cpus; /* Timer registers */ struct { - uint32_t ticc; /* Global timer current count register */ - uint32_t tibc; /* Global timer base count register */ + uint32_t ticc; /* Global timer current count register */ + uint32_t tibc; /* Global timer base count register */ } timers[MAX_TMR]; #if MAX_DBL > 0 /* Doorbell registers */ uint32_t dar; /* Doorbell activate register */ struct { - uint32_t dmr; /* Doorbell messaging register */ + uint32_t dmr; /* Doorbell messaging register */ } doorbells[MAX_DBL]; #endif #if MAX_MBX > 0 /* Mailbox registers */ struct { - uint32_t mbr; /* Mailbox register */ + uint32_t mbr; /* Mailbox register */ } mailboxes[MAX_MAILBOXES]; #endif /* IRQ out is used when in bypass mode (not implemented) */ @@ -240,19 +268,10 @@ typedef struct openpic_t { int max_irq; int irq_ipi0; int irq_tim0; - int need_swap; void (*reset) (void *); void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *); } openpic_t; -static inline uint32_t openpic_swap32(openpic_t *opp, uint32_t val) -{ - if (opp->need_swap) - return bswap32(val); - - return val; -} - static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) { set_bit(q->queue, n_IRQ); @@ -276,14 +295,14 @@ static void IRQ_check (openpic_t *opp, IRQ_queue_t *q) next = -1; priority = -1; for (i = 0; i < opp->max_irq; i++) { - if (IRQ_testbit(q, i)) { + if (IRQ_testbit(q, i)) { DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", i, IPVP_PRIORITY(opp->src[i].ipvp), priority); - if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) { - next = i; - priority = IPVP_PRIORITY(opp->src[i].ipvp); - } - } + if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) { + next = i; + priority = IPVP_PRIORITY(opp->src[i].ipvp); + } + } } q->next = next; q->priority = priority; @@ -293,7 +312,7 @@ static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q) { if (q->next == -1) { /* XXX: optimize */ - IRQ_check(opp, q); + IRQ_check(opp, q); } return q->next; @@ -309,16 +328,16 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) src = &opp->src[n_IRQ]; priority = IPVP_PRIORITY(src->ipvp); if (priority <= dst->pctp) { - /* Too low priority */ + /* Too low priority */ DPRINTF("%s: IRQ %d has too low priority on CPU %d\n", __func__, n_IRQ, n_CPU); - return; + return; } if (IRQ_testbit(&dst->raised, n_IRQ)) { - /* Interrupt miss */ + /* Interrupt miss */ DPRINTF("%s: IRQ %d was missed on CPU %d\n", __func__, n_IRQ, n_CPU); - return; + return; } set_bit(&src->ipvp, IPVP_ACTIVITY); IRQ_setbit(&dst->raised, n_IRQ); @@ -354,14 +373,14 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) return; } if (test_bit(&src->ipvp, IPVP_MASK)) { - /* Interrupt source is disabled */ + /* Interrupt source is disabled */ DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); - return; + return; } if (IPVP_PRIORITY(src->ipvp) == 0) { - /* Priority set to zero */ + /* Priority set to zero */ DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ); - return; + return; } if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { /* IRQ already active */ @@ -369,9 +388,9 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) return; } if (src->ide == 0x00000000) { - /* No target */ + /* No target */ DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); - return; + return; } if (src->ide == (1 << src->last_cpu)) { @@ -434,159 +453,150 @@ static void openpic_reset (void *opaque) opp->micr = 0x00000000; /* Initialise IRQ sources */ for (i = 0; i < opp->max_irq; i++) { - opp->src[i].ipvp = 0xA0000000; - opp->src[i].ide = 0x00000000; + opp->src[i].ipvp = 0xA0000000; + opp->src[i].ide = 0x00000000; } /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { - opp->dst[i].pctp = 0x0000000F; - opp->dst[i].pcsr = 0x00000000; - memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); - memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); + opp->dst[i].pctp = 0x0000000F; + opp->dst[i].pcsr = 0x00000000; + memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); + opp->dst[i].raised.next = -1; + memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); + opp->dst[i].servicing.next = -1; } /* Initialise timers */ for (i = 0; i < MAX_TMR; i++) { - opp->timers[i].ticc = 0x00000000; - opp->timers[i].tibc = 0x80000000; + opp->timers[i].ticc = 0x00000000; + opp->timers[i].tibc = 0x80000000; } /* Initialise doorbells */ #if MAX_DBL > 0 opp->dar = 0x00000000; for (i = 0; i < MAX_DBL; i++) { - opp->doorbells[i].dmr = 0x00000000; + opp->doorbells[i].dmr = 0x00000000; } #endif /* Initialise mailboxes */ #if MAX_MBX > 0 for (i = 0; i < MAX_MBX; i++) { /* ? */ - opp->mailboxes[i].mbr = 0x00000000; + opp->mailboxes[i].mbr = 0x00000000; } #endif /* Go out of RESET state */ opp->glbc = 0x00000000; } -static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg) +static inline uint32_t read_IRQreg_ide(openpic_t *opp, int n_IRQ) { - uint32_t retval; - - switch (reg) { - case IRQ_IPVP: - retval = opp->src[n_IRQ].ipvp; - break; - case IRQ_IDE: - retval = opp->src[n_IRQ].ide; - break; - } + return opp->src[n_IRQ].ide; +} - return retval; +static inline uint32_t read_IRQreg_ipvp(openpic_t *opp, int n_IRQ) +{ + return opp->src[n_IRQ].ipvp; } -static inline void write_IRQreg (openpic_t *opp, int n_IRQ, - uint32_t reg, uint32_t val) +static inline void write_IRQreg_ide(openpic_t *opp, int n_IRQ, uint32_t val) { uint32_t tmp; - switch (reg) { - case IRQ_IPVP: - /* NOTE: not fully accurate for special IRQs, but simple and - sufficient */ - /* ACTIVITY bit is read-only */ - opp->src[n_IRQ].ipvp = - (opp->src[n_IRQ].ipvp & 0x40000000) | - (val & 0x800F00FF); - openpic_update_irq(opp, n_IRQ); - DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", - n_IRQ, val, opp->src[n_IRQ].ipvp); - break; - case IRQ_IDE: - tmp = val & 0xC0000000; - tmp |= val & ((1 << MAX_CPU) - 1); - opp->src[n_IRQ].ide = tmp; - DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide); - break; - } + tmp = val & 0xC0000000; + tmp |= val & ((1ULL << MAX_CPU) - 1); + opp->src[n_IRQ].ide = tmp; + DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide); +} + +static inline void write_IRQreg_ipvp(openpic_t *opp, int n_IRQ, uint32_t val) +{ + /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ + /* ACTIVITY bit is read-only */ + opp->src[n_IRQ].ipvp = (opp->src[n_IRQ].ipvp & 0x40000000) + | (val & 0x800F00FF); + openpic_update_irq(opp, n_IRQ); + DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", n_IRQ, val, + opp->src[n_IRQ].ipvp); } #if 0 // Code provision for Intel model #if MAX_DBL > 0 static uint32_t read_doorbell_register (openpic_t *opp, - int n_dbl, uint32_t offset) + int n_dbl, uint32_t offset) { uint32_t retval; switch (offset) { case DBL_IPVP_OFFSET: - retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP); - break; + retval = read_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl); + break; case DBL_IDE_OFFSET: - retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE); - break; + retval = read_IRQreg_ide(opp, IRQ_DBL0 + n_dbl); + break; case DBL_DMR_OFFSET: - retval = opp->doorbells[n_dbl].dmr; - break; + retval = opp->doorbells[n_dbl].dmr; + break; } return retval; } static void write_doorbell_register (penpic_t *opp, int n_dbl, - uint32_t offset, uint32_t value) + uint32_t offset, uint32_t value) { switch (offset) { case DBL_IVPR_OFFSET: - write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value); - break; + write_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl, value); + break; case DBL_IDE_OFFSET: - write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value); - break; + write_IRQreg_ide(opp, IRQ_DBL0 + n_dbl, value); + break; case DBL_DMR_OFFSET: - opp->doorbells[n_dbl].dmr = value; - break; + opp->doorbells[n_dbl].dmr = value; + break; } } #endif #if MAX_MBX > 0 static uint32_t read_mailbox_register (openpic_t *opp, - int n_mbx, uint32_t offset) + int n_mbx, uint32_t offset) { uint32_t retval; switch (offset) { case MBX_MBR_OFFSET: - retval = opp->mailboxes[n_mbx].mbr; - break; + retval = opp->mailboxes[n_mbx].mbr; + break; case MBX_IVPR_OFFSET: - retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP); - break; + retval = read_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx); + break; case MBX_DMR_OFFSET: - retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE); - break; + retval = read_IRQreg_ide(opp, IRQ_MBX0 + n_mbx); + break; } return retval; } static void write_mailbox_register (openpic_t *opp, int n_mbx, - uint32_t address, uint32_t value) + uint32_t address, uint32_t value) { switch (offset) { case MBX_MBR_OFFSET: - opp->mailboxes[n_mbx].mbr = value; - break; + opp->mailboxes[n_mbx].mbr = value; + break; case MBX_IVPR_OFFSET: - write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value); - break; + write_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx, value); + break; case MBX_DMR_OFFSET: - write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value); - break; + write_IRQreg_ide(opp, IRQ_MBX0 + n_mbx, value); + break; } } #endif #endif /* 0 : Code provision for Intel model */ -static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t val) +static void openpic_gbl_write (void *opaque, hwaddr addr, uint32_t val) { openpic_t *opp = opaque; IRQ_dst_t *dst; @@ -595,21 +605,29 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); if (addr & 0xF) return; -#if defined TARGET_WORDS_BIGENDIAN - val = openpic_swap32(opp, val); -#endif - addr &= 0xFF; switch (addr) { - case 0x00: /* FREP */ + case 0x00: /* Block Revision Register1 (BRR1) is Readonly */ break; - case 0x20: /* GLBC */ + case 0x40: + case 0x50: + case 0x60: + case 0x70: + case 0x80: + case 0x90: + case 0xA0: + case 0xB0: + openpic_cpu_write_internal(opp, addr, val, get_current_cpu()); + break; + case 0x1000: /* FREP */ + break; + case 0x1020: /* GLBC */ if (val & 0x80000000 && opp->reset) opp->reset(opp); opp->glbc = val & ~0x80000000; - break; - case 0x80: /* VENI */ - break; - case 0x90: /* PINT */ + break; + case 0x1080: /* VENI */ + break; + case 0x1090: /* PINT */ for (idx = 0; idx < opp->nb_cpus; idx++) { if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) { DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx); @@ -622,31 +640,29 @@ static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t v } } opp->pint = val; - break; -#if MAX_IPI > 0 - case 0xA0: /* IPI_IPVP */ - case 0xB0: - case 0xC0: - case 0xD0: + break; + case 0x10A0: /* IPI_IPVP */ + case 0x10B0: + case 0x10C0: + case 0x10D0: { int idx; - idx = (addr - 0xA0) >> 4; - write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP, val); + idx = (addr - 0x10A0) >> 4; + write_IRQreg_ipvp(opp, opp->irq_ipi0 + idx, val); } break; -#endif - case 0xE0: /* SPVE */ + case 0x10E0: /* SPVE */ opp->spve = val & 0x000000FF; break; - case 0xF0: /* TIFR */ + case 0x10F0: /* TIFR */ opp->tifr = val; - break; + break; default: break; } } -static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr) +static uint32_t openpic_gbl_read (void *opaque, hwaddr addr) { openpic_t *opp = opaque; uint32_t retval; @@ -655,45 +671,50 @@ static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr) retval = 0xFFFFFFFF; if (addr & 0xF) return retval; - addr &= 0xFF; switch (addr) { - case 0x00: /* FREP */ + case 0x1000: /* FREP */ retval = opp->frep; break; - case 0x20: /* GLBC */ + case 0x1020: /* GLBC */ retval = opp->glbc; - break; - case 0x80: /* VENI */ + break; + case 0x1080: /* VENI */ retval = opp->veni; - break; - case 0x90: /* PINT */ + break; + case 0x1090: /* PINT */ retval = 0x00000000; - break; -#if MAX_IPI > 0 - case 0xA0: /* IPI_IPVP */ + break; + case 0x00: /* Block Revision Register1 (BRR1) */ + case 0x40: + case 0x50: + case 0x60: + case 0x70: + case 0x80: + case 0x90: + case 0xA0: case 0xB0: - case 0xC0: - case 0xD0: + retval = openpic_cpu_read_internal(opp, addr, get_current_cpu()); + break; + case 0x10A0: /* IPI_IPVP */ + case 0x10B0: + case 0x10C0: + case 0x10D0: { int idx; - idx = (addr - 0xA0) >> 4; - retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP); + idx = (addr - 0x10A0) >> 4; + retval = read_IRQreg_ipvp(opp, opp->irq_ipi0 + idx); } - break; -#endif - case 0xE0: /* SPVE */ + break; + case 0x10E0: /* SPVE */ retval = opp->spve; break; - case 0xF0: /* TIFR */ + case 0x10F0: /* TIFR */ retval = opp->tifr; - break; + break; default: break; } DPRINTF("%s: => %08x\n", __func__, retval); -#if defined TARGET_WORDS_BIGENDIAN - retval = openpic_swap32(opp, retval); -#endif return retval; } @@ -706,10 +727,7 @@ static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val) DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); if (addr & 0xF) return; -#if defined TARGET_WORDS_BIGENDIAN - val = openpic_swap32(opp, val); -#endif - addr -= 0x1100; + addr -= 0x10; addr &= 0xFFFF; idx = (addr & 0xFFF0) >> 6; addr = addr & 0x30; @@ -717,18 +735,18 @@ static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val) case 0x00: /* TICC */ break; case 0x10: /* TIBC */ - if ((opp->timers[idx].ticc & 0x80000000) != 0 && - (val & 0x80000000) == 0 && + if ((opp->timers[idx].ticc & 0x80000000) != 0 && + (val & 0x80000000) == 0 && (opp->timers[idx].tibc & 0x80000000) != 0) - opp->timers[idx].ticc &= ~0x80000000; - opp->timers[idx].tibc = val; - break; + opp->timers[idx].ticc &= ~0x80000000; + opp->timers[idx].tibc = val; + break; case 0x20: /* TIVP */ - write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP, val); - break; + write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val); + break; case 0x30: /* TIDE */ - write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE, val); - break; + write_IRQreg_ide(opp, opp->irq_tim0 + idx, val); + break; } } @@ -742,28 +760,25 @@ static uint32_t openpic_timer_read (void *opaque, uint32_t addr) retval = 0xFFFFFFFF; if (addr & 0xF) return retval; - addr -= 0x1100; + addr -= 0x10; addr &= 0xFFFF; idx = (addr & 0xFFF0) >> 6; addr = addr & 0x30; switch (addr) { case 0x00: /* TICC */ - retval = opp->timers[idx].ticc; + retval = opp->timers[idx].ticc; break; case 0x10: /* TIBC */ - retval = opp->timers[idx].tibc; - break; + retval = opp->timers[idx].tibc; + break; case 0x20: /* TIPV */ - retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP); - break; + retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx); + break; case 0x30: /* TIDE */ - retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE); - break; + retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx); + break; } DPRINTF("%s: => %08x\n", __func__, retval); -#if defined TARGET_WORDS_BIGENDIAN - retval = openpic_swap32(opp, retval); -#endif return retval; } @@ -776,17 +791,14 @@ static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val) DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); if (addr & 0xF) return; -#if defined TARGET_WORDS_BIGENDIAN - val = openpic_swap32(opp, val); -#endif addr = addr & 0xFFF0; idx = addr >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - write_IRQreg(opp, idx, IRQ_IDE, val); + write_IRQreg_ide(opp, idx, val); } else { /* EXVP / IFEVP / IEEVP */ - write_IRQreg(opp, idx, IRQ_IPVP, val); + write_IRQreg_ipvp(opp, idx, val); } } @@ -804,64 +816,60 @@ static uint32_t openpic_src_read (void *opaque, uint32_t addr) idx = addr >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg(opp, idx, IRQ_IDE); + retval = read_IRQreg_ide(opp, idx); } else { /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg(opp, idx, IRQ_IPVP); + retval = read_IRQreg_ipvp(opp, idx); } DPRINTF("%s: => %08x\n", __func__, retval); -#if defined TARGET_WORDS_BIGENDIAN - retval = openpic_swap32(opp, retval); -#endif return retval; } -static void openpic_cpu_write (void *opaque, target_phys_addr_t addr, uint32_t val) +static void openpic_cpu_write_internal(void *opaque, hwaddr addr, + uint32_t val, int idx) { openpic_t *opp = opaque; IRQ_src_t *src; IRQ_dst_t *dst; - int idx, s_IRQ, n_IRQ; + int s_IRQ, n_IRQ; - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); + DPRINTF("%s: cpu %d addr " TARGET_FMT_plx " <= %08x\n", __func__, idx, + addr, val); if (addr & 0xF) return; -#if defined TARGET_WORDS_BIGENDIAN - val = openpic_swap32(opp, val); -#endif - addr &= 0x1FFF0; - idx = addr / 0x1000; dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { #if MAX_IPI > 0 - case 0x40: /* PIPD */ + case 0x40: /* IPIDR */ case 0x50: case 0x60: case 0x70: idx = (addr - 0x40) >> 4; - write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE, val); + /* we use IDE as mask which CPUs to deliver the IPI to still. */ + write_IRQreg_ide(opp, opp->irq_ipi0 + idx, + opp->src[opp->irq_ipi0 + idx].ide | val); openpic_set_irq(opp, opp->irq_ipi0 + idx, 1); openpic_set_irq(opp, opp->irq_ipi0 + idx, 0); break; #endif case 0x80: /* PCTP */ - dst->pctp = val & 0x0000000F; - break; + dst->pctp = val & 0x0000000F; + break; case 0x90: /* WHOAMI */ - /* Read-only register */ - break; + /* Read-only register */ + break; case 0xA0: /* PIAC */ - /* Read-only register */ - break; + /* Read-only register */ + break; case 0xB0: /* PEOI */ DPRINTF("PEOI\n"); - s_IRQ = IRQ_get_next(opp, &dst->servicing); - IRQ_resetbit(&dst->servicing, s_IRQ); - dst->servicing.next = -1; - /* Set up next servicing IRQ */ - s_IRQ = IRQ_get_next(opp, &dst->servicing); + s_IRQ = IRQ_get_next(opp, &dst->servicing); + IRQ_resetbit(&dst->servicing, s_IRQ); + dst->servicing.next = -1; + /* Set up next servicing IRQ */ + s_IRQ = IRQ_get_next(opp, &dst->servicing); /* Check queued interrupts. */ n_IRQ = IRQ_get_next(opp, &dst->raised); src = &opp->src[n_IRQ]; @@ -872,95 +880,108 @@ static void openpic_cpu_write (void *opaque, target_phys_addr_t addr, uint32_t v idx, n_IRQ); opp->irq_raise(opp, idx, src); } - break; + break; default: break; } } -static uint32_t openpic_cpu_read (void *opaque, target_phys_addr_t addr) +static void openpic_cpu_write(void *opaque, hwaddr addr, uint32_t val) +{ + openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12); +} + +static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, + int idx) { openpic_t *opp = opaque; IRQ_src_t *src; IRQ_dst_t *dst; uint32_t retval; - int idx, n_IRQ; + int n_IRQ; - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); + DPRINTF("%s: cpu %d addr " TARGET_FMT_plx "\n", __func__, idx, addr); retval = 0xFFFFFFFF; if (addr & 0xF) return retval; - addr &= 0x1FFF0; - idx = addr / 0x1000; dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { + case 0x00: /* Block Revision Register1 (BRR1) */ + retval = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN; + break; case 0x80: /* PCTP */ - retval = dst->pctp; - break; + retval = dst->pctp; + break; case 0x90: /* WHOAMI */ - retval = idx; - break; + retval = idx; + break; case 0xA0: /* PIAC */ DPRINTF("Lower OpenPIC INT output\n"); qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); - n_IRQ = IRQ_get_next(opp, &dst->raised); + n_IRQ = IRQ_get_next(opp, &dst->raised); DPRINTF("PIAC: irq=%d\n", n_IRQ); - if (n_IRQ == -1) { - /* No more interrupt pending */ + if (n_IRQ == -1) { + /* No more interrupt pending */ retval = IPVP_VECTOR(opp->spve); - } else { - src = &opp->src[n_IRQ]; - if (!test_bit(&src->ipvp, IPVP_ACTIVITY) || - !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) { - /* - Spurious level-sensitive IRQ - * - Priorities has been changed - * and the pending IRQ isn't allowed anymore - */ - reset_bit(&src->ipvp, IPVP_ACTIVITY); - retval = IPVP_VECTOR(opp->spve); - } else { - /* IRQ enter servicing state */ - IRQ_setbit(&dst->servicing, n_IRQ); - retval = IPVP_VECTOR(src->ipvp); - } - IRQ_resetbit(&dst->raised, n_IRQ); - dst->raised.next = -1; - if (!test_bit(&src->ipvp, IPVP_SENSE)) { + } else { + src = &opp->src[n_IRQ]; + if (!test_bit(&src->ipvp, IPVP_ACTIVITY) || + !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) { + /* - Spurious level-sensitive IRQ + * - Priorities has been changed + * and the pending IRQ isn't allowed anymore + */ + reset_bit(&src->ipvp, IPVP_ACTIVITY); + retval = IPVP_VECTOR(opp->spve); + } else { + /* IRQ enter servicing state */ + IRQ_setbit(&dst->servicing, n_IRQ); + retval = IPVP_VECTOR(src->ipvp); + } + IRQ_resetbit(&dst->raised, n_IRQ); + dst->raised.next = -1; + if (!test_bit(&src->ipvp, IPVP_SENSE)) { /* edge-sensitive IRQ */ - reset_bit(&src->ipvp, IPVP_ACTIVITY); + reset_bit(&src->ipvp, IPVP_ACTIVITY); src->pending = 0; } - } - break; + + if ((n_IRQ >= opp->irq_ipi0) && (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) { + src->ide &= ~(1 << idx); + if (src->ide && !test_bit(&src->ipvp, IPVP_SENSE)) { + /* trigger on CPUs that didn't know about it yet */ + openpic_set_irq(opp, n_IRQ, 1); + openpic_set_irq(opp, n_IRQ, 0); + /* if all CPUs knew about it, set active bit again */ + set_bit(&src->ipvp, IPVP_ACTIVITY); + } + } + } + break; case 0xB0: /* PEOI */ - retval = 0; - break; -#if MAX_IPI > 0 - case 0x40: /* IDE */ - case 0x50: - idx = (addr - 0x40) >> 4; - retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE); + retval = 0; break; -#endif default: break; } DPRINTF("%s: => %08x\n", __func__, retval); -#if defined TARGET_WORDS_BIGENDIAN - retval = openpic_swap32(opp, retval); -#endif return retval; } +static uint32_t openpic_cpu_read(void *opaque, hwaddr addr) +{ + return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12); +} + static void openpic_buggy_write (void *opaque, - target_phys_addr_t addr, uint32_t val) + hwaddr addr, uint32_t val) { printf("Invalid OPENPIC write access !\n"); } -static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr) +static uint32_t openpic_buggy_read (void *opaque, hwaddr addr) { printf("Invalid OPENPIC read access !\n"); @@ -968,7 +989,7 @@ static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr) } static void openpic_writel (void *opaque, - target_phys_addr_t addr, uint32_t val) + hwaddr addr, uint32_t val) { openpic_t *opp = opaque; @@ -989,7 +1010,7 @@ static void openpic_writel (void *opaque, } } -static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr) +static uint32_t openpic_readl (void *opaque,hwaddr addr) { openpic_t *opp = opaque; uint32_t retval; @@ -1013,46 +1034,34 @@ static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr) return retval; } -static CPUWriteMemoryFunc * const openpic_write[] = { - &openpic_buggy_write, - &openpic_buggy_write, - &openpic_writel, -}; +static uint64_t openpic_read(void *opaque, hwaddr addr, + unsigned size) +{ + openpic_t *opp = opaque; -static CPUReadMemoryFunc * const openpic_read[] = { - &openpic_buggy_read, - &openpic_buggy_read, - &openpic_readl, -}; + switch (size) { + case 4: return openpic_readl(opp, addr); + default: return openpic_buggy_read(opp, addr); + } +} -static void openpic_map(PCIDevice *pci_dev, int region_num, - pcibus_t addr, pcibus_t size, int type) +static void openpic_write(void *opaque, hwaddr addr, + uint64_t data, unsigned size) { - openpic_t *opp; + openpic_t *opp = opaque; - DPRINTF("Map OpenPIC\n"); - opp = (openpic_t *)pci_dev; - /* Global registers */ - DPRINTF("Register OPENPIC gbl %08x => %08x\n", - addr + 0x1000, addr + 0x1000 + 0x100); - /* Timer registers */ - DPRINTF("Register OPENPIC timer %08x => %08x\n", - addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR); - /* Interrupt source registers */ - DPRINTF("Register OPENPIC src %08x => %08x\n", - addr + 0x10000, addr + 0x10000 + 0x20 * (OPENPIC_EXT_IRQ + 2)); - /* Per CPU registers */ - DPRINTF("Register OPENPIC dst %08x => %08x\n", - addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU); - cpu_register_physical_memory(addr, 0x40000, opp->mem_index); -#if 0 // Don't implement ISU for now - opp_io_memory = cpu_register_io_memory(openpic_src_read, - openpic_src_write); - cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2), - opp_io_memory); -#endif + switch (size) { + case 4: return openpic_writel(opp, addr, data); + default: return openpic_buggy_write(opp, addr, data); + } } +static const MemoryRegionOps openpic_ops = { + .read = openpic_read, + .write = openpic_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) { unsigned int i; @@ -1189,36 +1198,17 @@ 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 *openpic_init (MemoryRegion **pmem, int nb_cpus, qemu_irq **irqs, qemu_irq irq_out) { openpic_t *opp; - uint8_t *pci_conf; int i, m; /* XXX: for now, only one CPU is supported */ if (nb_cpus != 1) return NULL; - if (bus) { - opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t), - -1, NULL, NULL); - if (opp == NULL) - return NULL; - pci_conf = opp->pci_dev.config; - pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM); - pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2); - pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME? - pci_conf[PCI_HEADER_TYPE] = PCI_HEADER_TYPE_NORMAL; // header_type - pci_conf[0x3d] = 0x00; // no interrupt pin - - /* Register I/O spaces */ - pci_register_bar((PCIDevice *)opp, 0, 0x40000, - PCI_BASE_ADDRESS_SPACE_MEMORY, &openpic_map); - } else { - opp = qemu_mallocz(sizeof(openpic_t)); - } - opp->mem_index = cpu_register_io_memory(openpic_read, - openpic_write, opp); + opp = g_malloc0(sizeof(openpic_t)); + memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000); // isu_base &= 0xFFFC0000; opp->nb_cpus = nb_cpus; @@ -1246,16 +1236,16 @@ 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; - opp->need_swap = 1; - register_savevm("openpic", 0, 2, openpic_save, openpic_load, opp); + register_savevm(&opp->pci_dev.qdev, "openpic", 0, 2, + openpic_save, openpic_load, opp); qemu_register_reset(openpic_reset, opp); opp->irq_raise = openpic_irq_raise; opp->reset = openpic_reset; - if (pmem_index) - *pmem_index = opp->mem_index; + if (pmem) + *pmem = &opp->mem; return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq); } @@ -1279,7 +1269,7 @@ static void mpic_reset (void *opaque) mpp->glbc = 0x80000000; /* Initialise controller registers */ - mpp->frep = 0x004f0002; + mpp->frep = 0x004f0002 | ((mpp->nb_cpus - 1) << 8); mpp->veni = VENI; mpp->pint = 0x00000000; mpp->spve = 0x0000FFFF; @@ -1288,6 +1278,10 @@ static void mpic_reset (void *opaque) mpp->src[i].ipvp = 0x80800000; mpp->src[i].ide = 0x00000001; } + /* Set IDE for IPIs to 0 so we don't get spurious interrupts */ + for (i = mpp->irq_ipi0; i < (mpp->irq_ipi0 + MAX_IPI); i++) { + mpp->src[i].ide = 0; + } /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { mpp->dst[i].pctp = 0x0000000F; @@ -1306,7 +1300,7 @@ static void mpic_reset (void *opaque) mpp->glbc = 0x00000000; } -static void mpic_timer_write (void *opaque, target_phys_addr_t addr, uint32_t val) +static void mpic_timer_write (void *opaque, hwaddr addr, uint32_t val) { openpic_t *mpp = opaque; int idx, cpu; @@ -1328,18 +1322,18 @@ static void mpic_timer_write (void *opaque, target_phys_addr_t addr, uint32_t va mpp->timers[idx].tibc = val; break; case 0x20: /* GTIVPR */ - write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP, val); + write_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx, val); break; case 0x30: /* GTIDR & TFRR */ if ((addr & 0xF0) == 0xF0) mpp->dst[cpu].tfrr = val; else - write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE, val); + write_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx, val); break; } } -static uint32_t mpic_timer_read (void *opaque, target_phys_addr_t addr) +static uint32_t mpic_timer_read (void *opaque, hwaddr addr) { openpic_t *mpp = opaque; uint32_t retval; @@ -1360,13 +1354,13 @@ static uint32_t mpic_timer_read (void *opaque, target_phys_addr_t addr) retval = mpp->timers[idx].tibc; break; case 0x20: /* TIPV */ - retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP); + retval = read_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx); break; case 0x30: /* TIDR */ if ((addr &0xF0) == 0XF0) retval = mpp->dst[cpu].tfrr; else - retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE); + retval = read_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx); break; } DPRINTF("%s: => %08x\n", __func__, retval); @@ -1374,7 +1368,7 @@ static uint32_t mpic_timer_read (void *opaque, target_phys_addr_t addr) return retval; } -static void mpic_src_ext_write (void *opaque, target_phys_addr_t addr, +static void mpic_src_ext_write (void *opaque, hwaddr addr, uint32_t val) { openpic_t *mpp = opaque; @@ -1384,20 +1378,19 @@ static void mpic_src_ext_write (void *opaque, target_phys_addr_t addr, if (addr & 0xF) return; - addr -= MPIC_EXT_REG_START & (TARGET_PAGE_SIZE - 1); if (addr < MPIC_EXT_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - write_IRQreg(mpp, idx, IRQ_IDE, val); + write_IRQreg_ide(mpp, idx, val); } else { /* EXVP / IFEVP / IEEVP */ - write_IRQreg(mpp, idx, IRQ_IPVP, val); + write_IRQreg_ipvp(mpp, idx, val); } } } -static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr) +static uint32_t mpic_src_ext_read (void *opaque, hwaddr addr) { openpic_t *mpp = opaque; uint32_t retval; @@ -1408,15 +1401,14 @@ static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr) if (addr & 0xF) return retval; - addr -= MPIC_EXT_REG_START & (TARGET_PAGE_SIZE - 1); if (addr < MPIC_EXT_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg(mpp, idx, IRQ_IDE); + retval = read_IRQreg_ide(mpp, idx); } else { /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg(mpp, idx, IRQ_IPVP); + retval = read_IRQreg_ipvp(mpp, idx); } DPRINTF("%s: => %08x\n", __func__, retval); } @@ -1424,7 +1416,7 @@ static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr) return retval; } -static void mpic_src_int_write (void *opaque, target_phys_addr_t addr, +static void mpic_src_int_write (void *opaque, hwaddr addr, uint32_t val) { openpic_t *mpp = opaque; @@ -1434,20 +1426,19 @@ static void mpic_src_int_write (void *opaque, target_phys_addr_t addr, if (addr & 0xF) return; - addr -= MPIC_INT_REG_START & (TARGET_PAGE_SIZE - 1); if (addr < MPIC_INT_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - write_IRQreg(mpp, idx, IRQ_IDE, val); + write_IRQreg_ide(mpp, idx, val); } else { /* EXVP / IFEVP / IEEVP */ - write_IRQreg(mpp, idx, IRQ_IPVP, val); + write_IRQreg_ipvp(mpp, idx, val); } } } -static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr) +static uint32_t mpic_src_int_read (void *opaque, hwaddr addr) { openpic_t *mpp = opaque; uint32_t retval; @@ -1458,15 +1449,14 @@ static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr) if (addr & 0xF) return retval; - addr -= MPIC_INT_REG_START & (TARGET_PAGE_SIZE - 1); if (addr < MPIC_INT_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg(mpp, idx, IRQ_IDE); + retval = read_IRQreg_ide(mpp, idx); } else { /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg(mpp, idx, IRQ_IPVP); + retval = read_IRQreg_ipvp(mpp, idx); } DPRINTF("%s: => %08x\n", __func__, retval); } @@ -1474,7 +1464,7 @@ static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr) return retval; } -static void mpic_src_msg_write (void *opaque, target_phys_addr_t addr, +static void mpic_src_msg_write (void *opaque, hwaddr addr, uint32_t val) { openpic_t *mpp = opaque; @@ -1484,20 +1474,19 @@ static void mpic_src_msg_write (void *opaque, target_phys_addr_t addr, if (addr & 0xF) return; - addr -= MPIC_MSG_REG_START & (TARGET_PAGE_SIZE - 1); if (addr < MPIC_MSG_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - write_IRQreg(mpp, idx, IRQ_IDE, val); + write_IRQreg_ide(mpp, idx, val); } else { /* EXVP / IFEVP / IEEVP */ - write_IRQreg(mpp, idx, IRQ_IPVP, val); + write_IRQreg_ipvp(mpp, idx, val); } } } -static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr) +static uint32_t mpic_src_msg_read (void *opaque, hwaddr addr) { openpic_t *mpp = opaque; uint32_t retval; @@ -1508,15 +1497,14 @@ static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr) if (addr & 0xF) return retval; - addr -= MPIC_MSG_REG_START & (TARGET_PAGE_SIZE - 1); if (addr < MPIC_MSG_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg(mpp, idx, IRQ_IDE); + retval = read_IRQreg_ide(mpp, idx); } else { /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg(mpp, idx, IRQ_IPVP); + retval = read_IRQreg_ipvp(mpp, idx); } DPRINTF("%s: => %08x\n", __func__, retval); } @@ -1524,7 +1512,7 @@ static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr) return retval; } -static void mpic_src_msi_write (void *opaque, target_phys_addr_t addr, +static void mpic_src_msi_write (void *opaque, hwaddr addr, uint32_t val) { openpic_t *mpp = opaque; @@ -1534,19 +1522,18 @@ static void mpic_src_msi_write (void *opaque, target_phys_addr_t addr, if (addr & 0xF) return; - addr -= MPIC_MSI_REG_START & (TARGET_PAGE_SIZE - 1); if (addr < MPIC_MSI_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - write_IRQreg(mpp, idx, IRQ_IDE, val); + write_IRQreg_ide(mpp, idx, val); } else { /* EXVP / IFEVP / IEEVP */ - write_IRQreg(mpp, idx, IRQ_IPVP, val); + write_IRQreg_ipvp(mpp, idx, val); } } } -static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr) +static uint32_t mpic_src_msi_read (void *opaque, hwaddr addr) { openpic_t *mpp = opaque; uint32_t retval; @@ -1557,15 +1544,14 @@ static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr) if (addr & 0xF) return retval; - addr -= MPIC_MSI_REG_START & (TARGET_PAGE_SIZE - 1); if (addr < MPIC_MSI_REG_SIZE) { idx += (addr & 0xFFF0) >> 5; if (addr & 0x10) { /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg(mpp, idx, IRQ_IDE); + retval = read_IRQreg_ide(mpp, idx); } else { /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg(mpp, idx, IRQ_IPVP); + retval = read_IRQreg_ipvp(mpp, idx); } DPRINTF("%s: => %08x\n", __func__, retval); } @@ -1573,124 +1559,136 @@ static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr) return retval; } -static CPUWriteMemoryFunc * const mpic_glb_write[] = { - &openpic_buggy_write, - &openpic_buggy_write, - &openpic_gbl_write, -}; - -static CPUReadMemoryFunc * const mpic_glb_read[] = { - &openpic_buggy_read, - &openpic_buggy_read, - &openpic_gbl_read, +static const MemoryRegionOps mpic_glb_ops = { + .old_mmio = { + .write = { openpic_buggy_write, + openpic_buggy_write, + openpic_gbl_write, + }, + .read = { openpic_buggy_read, + openpic_buggy_read, + openpic_gbl_read, + }, + }, + .endianness = DEVICE_BIG_ENDIAN, }; -static CPUWriteMemoryFunc * const mpic_tmr_write[] = { - &openpic_buggy_write, - &openpic_buggy_write, - &mpic_timer_write, +static const MemoryRegionOps mpic_tmr_ops = { + .old_mmio = { + .write = { openpic_buggy_write, + openpic_buggy_write, + mpic_timer_write, + }, + .read = { openpic_buggy_read, + openpic_buggy_read, + mpic_timer_read, + }, + }, + .endianness = DEVICE_BIG_ENDIAN, }; -static CPUReadMemoryFunc * const mpic_tmr_read[] = { - &openpic_buggy_read, - &openpic_buggy_read, - &mpic_timer_read, +static const MemoryRegionOps mpic_cpu_ops = { + .old_mmio = { + .write = { openpic_buggy_write, + openpic_buggy_write, + openpic_cpu_write, + }, + .read = { openpic_buggy_read, + openpic_buggy_read, + openpic_cpu_read, + }, + }, + .endianness = DEVICE_BIG_ENDIAN, }; -static CPUWriteMemoryFunc * const mpic_cpu_write[] = { - &openpic_buggy_write, - &openpic_buggy_write, - &openpic_cpu_write, +static const MemoryRegionOps mpic_ext_ops = { + .old_mmio = { + .write = { openpic_buggy_write, + openpic_buggy_write, + mpic_src_ext_write, + }, + .read = { openpic_buggy_read, + openpic_buggy_read, + mpic_src_ext_read, + }, + }, + .endianness = DEVICE_BIG_ENDIAN, }; -static CPUReadMemoryFunc * const mpic_cpu_read[] = { - &openpic_buggy_read, - &openpic_buggy_read, - &openpic_cpu_read, +static const MemoryRegionOps mpic_int_ops = { + .old_mmio = { + .write = { openpic_buggy_write, + openpic_buggy_write, + mpic_src_int_write, + }, + .read = { openpic_buggy_read, + openpic_buggy_read, + mpic_src_int_read, + }, + }, + .endianness = DEVICE_BIG_ENDIAN, }; -static CPUWriteMemoryFunc * const mpic_ext_write[] = { - &openpic_buggy_write, - &openpic_buggy_write, - &mpic_src_ext_write, +static const MemoryRegionOps mpic_msg_ops = { + .old_mmio = { + .write = { openpic_buggy_write, + openpic_buggy_write, + mpic_src_msg_write, + }, + .read = { openpic_buggy_read, + openpic_buggy_read, + mpic_src_msg_read, + }, + }, + .endianness = DEVICE_BIG_ENDIAN, }; -static CPUReadMemoryFunc * const mpic_ext_read[] = { - &openpic_buggy_read, - &openpic_buggy_read, - &mpic_src_ext_read, +static const MemoryRegionOps mpic_msi_ops = { + .old_mmio = { + .write = { openpic_buggy_write, + openpic_buggy_write, + mpic_src_msi_write, + }, + .read = { openpic_buggy_read, + openpic_buggy_read, + mpic_src_msi_read, + }, + }, + .endianness = DEVICE_BIG_ENDIAN, }; -static CPUWriteMemoryFunc * const mpic_int_write[] = { - &openpic_buggy_write, - &openpic_buggy_write, - &mpic_src_int_write, -}; - -static CPUReadMemoryFunc * const mpic_int_read[] = { - &openpic_buggy_read, - &openpic_buggy_read, - &mpic_src_int_read, -}; - -static CPUWriteMemoryFunc * const mpic_msg_write[] = { - &openpic_buggy_write, - &openpic_buggy_write, - &mpic_src_msg_write, -}; - -static CPUReadMemoryFunc * const mpic_msg_read[] = { - &openpic_buggy_read, - &openpic_buggy_read, - &mpic_src_msg_read, -}; -static CPUWriteMemoryFunc * const mpic_msi_write[] = { - &openpic_buggy_write, - &openpic_buggy_write, - &mpic_src_msi_write, -}; - -static CPUReadMemoryFunc * const mpic_msi_read[] = { - &openpic_buggy_read, - &openpic_buggy_read, - &mpic_src_msi_read, -}; - -qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus, - qemu_irq **irqs, qemu_irq irq_out) +qemu_irq *mpic_init (MemoryRegion *address_space, hwaddr base, + int nb_cpus, qemu_irq **irqs, qemu_irq irq_out) { - openpic_t *mpp; - int i; + openpic_t *mpp; + int i; struct { - CPUReadMemoryFunc * const *read; - CPUWriteMemoryFunc * const *write; - target_phys_addr_t start_addr; - ram_addr_t size; + const char *name; + MemoryRegionOps const *ops; + hwaddr start_addr; + ram_addr_t size; } const list[] = { - {mpic_glb_read, mpic_glb_write, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE}, - {mpic_tmr_read, mpic_tmr_write, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE}, - {mpic_ext_read, mpic_ext_write, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE}, - {mpic_int_read, mpic_int_write, MPIC_INT_REG_START, MPIC_INT_REG_SIZE}, - {mpic_msg_read, mpic_msg_write, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE}, - {mpic_msi_read, mpic_msi_write, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE}, - {mpic_cpu_read, mpic_cpu_write, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE}, + {"glb", &mpic_glb_ops, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE}, + {"tmr", &mpic_tmr_ops, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE}, + {"ext", &mpic_ext_ops, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE}, + {"int", &mpic_int_ops, MPIC_INT_REG_START, MPIC_INT_REG_SIZE}, + {"msg", &mpic_msg_ops, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE}, + {"msi", &mpic_msi_ops, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE}, + {"cpu", &mpic_cpu_ops, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE}, }; - /* XXX: for now, only one CPU is supported */ - if (nb_cpus != 1) - return NULL; + mpp = g_malloc0(sizeof(openpic_t)); - mpp = qemu_mallocz(sizeof(openpic_t)); + memory_region_init(&mpp->mem, "mpic", 0x40000); + memory_region_add_subregion(address_space, base, &mpp->mem); for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) { - int mem_index; - mem_index = cpu_register_io_memory(list[i].read, list[i].write, mpp); - if (mem_index < 0) { - goto free; - } - cpu_register_physical_memory(base + list[i].start_addr, - list[i].size, mem_index); + memory_region_init_io(&mpp->sub_io_mem[i], list[i].ops, mpp, + list[i].name, list[i].size); + + memory_region_add_subregion(&mpp->mem, list[i].start_addr, + &mpp->sub_io_mem[i]); } mpp->nb_cpus = nb_cpus; @@ -1701,17 +1699,12 @@ qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus, for (i = 0; i < nb_cpus; i++) mpp->dst[i].irqs = irqs[i]; mpp->irq_out = irq_out; - mpp->need_swap = 0; /* MPIC has the same endian as target */ mpp->irq_raise = mpic_irq_raise; mpp->reset = mpic_reset; - register_savevm("mpic", 0, 2, openpic_save, openpic_load, mpp); + register_savevm(NULL, "mpic", 0, 2, openpic_save, openpic_load, mpp); qemu_register_reset(mpic_reset, mpp); return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq); - -free: - qemu_free(mpp); - return NULL; }