diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 9742c005d1e20cecd3af54cc6aeb9b7c9b57b4b6..ce194c6cec2320917c70825b0bcccb0572af63cd 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -255,114 +255,100 @@ static void pmac_ide_flush(DBDMA_io *io) } /* PowerMac IDE memory IO */ -static void pmac_ide_writeb (void *opaque, - hwaddr addr, uint32_t val) +static uint64_t pmac_ide_read(void *opaque, hwaddr addr, unsigned size) { MACIOIDEState *d = opaque; - - addr = (addr & 0xFFF) >> 4; - switch (addr) { - case 1 ... 7: - ide_ioport_write(&d->bus, addr, val); - break; - case 8: - case 22: - ide_cmd_write(&d->bus, 0, val); + uint64_t retval = 0xffffffff; + int reg = addr >> 4; + + switch (reg) { + case 0x0: + if (size == 2) { + retval = ide_data_readw(&d->bus, 0); + } else if (size == 4) { + retval = ide_data_readl(&d->bus, 0); + } break; - default: + case 0x1 ... 0x7: + if (size == 1) { + retval = ide_ioport_read(&d->bus, reg); + } break; - } -} - -static uint32_t pmac_ide_readb (void *opaque,hwaddr addr) -{ - uint8_t retval; - MACIOIDEState *d = opaque; - - addr = (addr & 0xFFF) >> 4; - switch (addr) { - case 1 ... 7: - retval = ide_ioport_read(&d->bus, addr); + case 0x8: + case 0x16: + if (size == 1) { + retval = ide_status_read(&d->bus, 0); + } break; - case 8: - case 22: - retval = ide_status_read(&d->bus, 0); + case 0x20: + if (size == 4) { + retval = d->timing_reg; + } break; - default: - retval = 0xFF; + case 0x30: + /* This is an interrupt state register that only exists + * in the KeyLargo and later variants. Bit 0x8000_0000 + * latches the DMA interrupt and has to be written to + * clear. Bit 0x4000_0000 is an image of the disk + * interrupt. MacOS X relies on this and will hang if + * we don't provide at least the disk interrupt + */ + if (size == 4) { + retval = d->irq_reg; + } break; } - return retval; -} - -static void pmac_ide_writew (void *opaque, - hwaddr addr, uint32_t val) -{ - MACIOIDEState *d = opaque; - - addr = (addr & 0xFFF) >> 4; - val = bswap16(val); - if (addr == 0) { - ide_data_writew(&d->bus, 0, val); - } -} - -static uint32_t pmac_ide_readw (void *opaque,hwaddr addr) -{ - uint16_t retval; - MACIOIDEState *d = opaque; - addr = (addr & 0xFFF) >> 4; - if (addr == 0) { - retval = ide_data_readw(&d->bus, 0); - } else { - retval = 0xFFFF; - } - retval = bswap16(retval); return retval; } -static void pmac_ide_writel (void *opaque, - hwaddr addr, uint32_t val) -{ - MACIOIDEState *d = opaque; - - addr = (addr & 0xFFF) >> 4; - val = bswap32(val); - if (addr == 0) { - ide_data_writel(&d->bus, 0, val); - } -} -static uint32_t pmac_ide_readl (void *opaque,hwaddr addr) +static void pmac_ide_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) { - uint32_t retval; MACIOIDEState *d = opaque; - - addr = (addr & 0xFFF) >> 4; - if (addr == 0) { - retval = ide_data_readl(&d->bus, 0); - } else { - retval = 0xFFFFFFFF; + int reg = addr >> 4; + + switch (reg) { + case 0x0: + if (size == 2) { + ide_data_writew(&d->bus, 0, val); + } else if (size == 4) { + ide_data_writel(&d->bus, 0, val); + } + break; + case 0x1 ... 0x7: + if (size == 1) { + ide_ioport_write(&d->bus, reg, val); + } + break; + case 0x8: + case 0x16: + if (size == 1) { + ide_cmd_write(&d->bus, 0, val); + } + break; + case 0x20: + if (size == 4) { + d->timing_reg = val; + } + break; + case 0x30: + if (size == 4) { + if (val & 0x80000000u) { + d->irq_reg &= 0x7fffffff; + } + } + break; } - retval = bswap32(retval); - return retval; } static const MemoryRegionOps pmac_ide_ops = { - .old_mmio = { - .write = { - pmac_ide_writeb, - pmac_ide_writew, - pmac_ide_writel, - }, - .read = { - pmac_ide_readb, - pmac_ide_readw, - pmac_ide_readl, - }, - }, - .endianness = DEVICE_NATIVE_ENDIAN, + .read = pmac_ide_read, + .write = pmac_ide_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, }; static const VMStateDescription vmstate_pmac = { @@ -426,13 +412,32 @@ static void macio_ide_realizefn(DeviceState *dev, Error **errp) { MACIOIDEState *s = MACIO_IDE(dev); - ide_init2(&s->bus, s->irq); + ide_init2(&s->bus, s->ide_irq); /* Register DMA callbacks */ s->dma.ops = &dbdma_ops; s->bus.dma = &s->dma; } +static void pmac_ide_irq(void *opaque, int n, int level) +{ + MACIOIDEState *s = opaque; + uint32_t mask = 0x80000000u >> n; + + /* We need to reflect the IRQ state in the irq register */ + if (level) { + s->irq_reg |= mask; + } else { + s->irq_reg &= ~mask; + } + + if (n) { + qemu_set_irq(s->real_ide_irq, level); + } else { + qemu_set_irq(s->real_dma_irq, level); + } +} + static void macio_ide_initfn(Object *obj) { SysBusDevice *d = SYS_BUS_DEVICE(obj); @@ -441,16 +446,28 @@ static void macio_ide_initfn(Object *obj) ide_bus_new(&s->bus, sizeof(s->bus), DEVICE(obj), 0, 2); memory_region_init_io(&s->mem, obj, &pmac_ide_ops, s, "pmac-ide", 0x1000); sysbus_init_mmio(d, &s->mem); - sysbus_init_irq(d, &s->irq); - sysbus_init_irq(d, &s->dma_irq); + sysbus_init_irq(d, &s->real_ide_irq); + sysbus_init_irq(d, &s->real_dma_irq); + s->dma_irq = qemu_allocate_irq(pmac_ide_irq, s, 0); + s->ide_irq = qemu_allocate_irq(pmac_ide_irq, s, 1); + + object_property_add_link(obj, "dbdma", TYPE_MAC_DBDMA, + (Object **) &s->dbdma, + qdev_prop_allow_set_link_before_realize, 0, NULL); } +static Property macio_ide_properties[] = { + DEFINE_PROP_UINT32("channel", MACIOIDEState, channel, 0), + DEFINE_PROP_END_OF_LIST(), +}; + static void macio_ide_class_init(ObjectClass *oc, void *data) { DeviceClass *dc = DEVICE_CLASS(oc); dc->realize = macio_ide_realizefn; dc->reset = macio_ide_reset; + dc->props = macio_ide_properties; dc->vmsd = &vmstate_pmac; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); } @@ -480,10 +497,9 @@ void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table) } } -void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel) +void macio_ide_register_dma(MACIOIDEState *s) { - s->dbdma = dbdma; - DBDMA_register_channel(dbdma, channel, s->dma_irq, + DBDMA_register_channel(s->dbdma, s->channel, s->dma_irq, pmac_ide_transfer, pmac_ide_flush, s); } diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c index 9dd285b92326314b72cffae31940624719c5a030..10d6e871fb6f51fc40ef561d2ce515a9e210f71b 100644 --- a/hw/intc/openpic.c +++ b/hw/intc/openpic.c @@ -92,6 +92,16 @@ static int get_current_cpu(void); #define RAVEN_MAX_TMR OPENPIC_MAX_TMR #define RAVEN_MAX_IPI OPENPIC_MAX_IPI +/* KeyLargo */ +#define KEYLARGO_MAX_CPU 4 +#define KEYLARGO_MAX_EXT 64 +#define KEYLARGO_MAX_IPI 4 +#define KEYLARGO_MAX_IRQ (64 + KEYLARGO_MAX_IPI) +#define KEYLARGO_MAX_TMR 0 +#define KEYLARGO_IPI_IRQ (KEYLARGO_MAX_EXT) /* First IPI IRQ */ +/* Timers don't exist but this makes the code happy... */ +#define KEYLARGO_TMR_IRQ (KEYLARGO_IPI_IRQ + KEYLARGO_MAX_IPI) + /* Interrupt definitions */ #define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */ #define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */ @@ -120,6 +130,7 @@ static FslMpicInfo fsl_mpic_42 = { #define VID_REVISION_1_3 3 #define VIR_GENERIC 0x00000000 /* Generic Vendor ID */ +#define VIR_MPIC2A 0x00004614 /* IBM MPIC-2A */ #define GCR_RESET 0x80000000 #define GCR_MODE_PASS 0x00000000 @@ -329,6 +340,8 @@ typedef struct OpenPICState { uint32_t nb_cpus; /* Timer registers */ OpenPICTimer timers[OPENPIC_MAX_TMR]; + uint32_t max_tmr; + /* Shared MSI registers */ OpenPICMSI msi[MAX_MSI]; uint32_t max_irq; @@ -1715,6 +1728,28 @@ static void openpic_realize(DeviceState *dev, Error **errp) return; } + map_list(opp, list_le, &list_count); + break; + + case OPENPIC_MODEL_KEYLARGO: + opp->nb_irqs = KEYLARGO_MAX_EXT; + opp->vid = VID_REVISION_1_2; + opp->vir = VIR_GENERIC; + opp->vector_mask = 0xFF; + opp->tfrr_reset = 4160000; + opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK; + opp->idr_reset = 0; + opp->max_irq = KEYLARGO_MAX_IRQ; + opp->irq_ipi0 = KEYLARGO_IPI_IRQ; + opp->irq_tim0 = KEYLARGO_TMR_IRQ; + opp->brr1 = -1; + opp->mpic_mode_mask = GCR_MODE_MIXED; + + if (opp->nb_cpus != 1) { + error_setg(errp, "Only UP supported today"); + return; + } + map_list(opp, list_le, &list_count); break; } diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c index 15452b9a28331e2abfea7f6c1cd7ead43f38ccf8..0eddf2e700951a359e02ab2fa3317e39ca92c645 100644 --- a/hw/misc/macio/mac_dbdma.c +++ b/hw/misc/macio/mac_dbdma.c @@ -96,9 +96,8 @@ static void dbdma_cmdptr_load(DBDMA_channel *ch) static void dbdma_cmdptr_save(DBDMA_channel *ch) { - DBDMA_DPRINTFCH(ch, "dbdma_cmdptr_save 0x%08x\n", - ch->regs[DBDMA_CMDPTR_LO]); - DBDMA_DPRINTFCH(ch, "xfer_status 0x%08x res_count 0x%04x\n", + DBDMA_DPRINTFCH(ch, "-> update 0x%08x stat=0x%08x, res=0x%04x\n", + ch->regs[DBDMA_CMDPTR_LO], le16_to_cpu(ch->current.xfer_status), le16_to_cpu(ch->current.res_count)); dma_memory_write(&address_space_memory, ch->regs[DBDMA_CMDPTR_LO], @@ -166,15 +165,14 @@ static int conditional_wait(DBDMA_channel *ch) uint16_t sel_mask, sel_value; uint32_t status; int cond; - - DBDMA_DPRINTFCH(ch, "conditional_wait\n"); + int res = 0; wait = le16_to_cpu(current->command) & WAIT_MASK; - switch(wait) { case WAIT_NEVER: /* don't wait */ return 0; case WAIT_ALWAYS: /* always wait */ + DBDMA_DPRINTFCH(ch, " [WAIT_ALWAYS]\n"); return 1; } @@ -187,15 +185,19 @@ static int conditional_wait(DBDMA_channel *ch) switch(wait) { case WAIT_IFSET: /* wait if condition bit is 1 */ - if (cond) - return 1; - return 0; + if (cond) { + res = 1; + } + DBDMA_DPRINTFCH(ch, " [WAIT_IFSET=%d]\n", res); + break; case WAIT_IFCLR: /* wait if condition bit is 0 */ - if (!cond) - return 1; - return 0; + if (!cond) { + res = 1; + } + DBDMA_DPRINTFCH(ch, " [WAIT_IFCLR=%d]\n", res); + break; } - return 0; + return res; } static void next(DBDMA_channel *ch) @@ -226,8 +228,6 @@ static void conditional_branch(DBDMA_channel *ch) uint32_t status; int cond; - DBDMA_DPRINTFCH(ch, "conditional_branch\n"); - /* check if we must branch */ br = le16_to_cpu(current->command) & BR_MASK; @@ -237,6 +237,7 @@ static void conditional_branch(DBDMA_channel *ch) next(ch); return; case BR_ALWAYS: /* always branch */ + DBDMA_DPRINTFCH(ch, " [BR_ALWAYS]\n"); branch(ch); return; } @@ -250,16 +251,22 @@ static void conditional_branch(DBDMA_channel *ch) switch(br) { case BR_IFSET: /* branch if condition bit is 1 */ - if (cond) + if (cond) { + DBDMA_DPRINTFCH(ch, " [BR_IFSET = 1]\n"); branch(ch); - else + } else { + DBDMA_DPRINTFCH(ch, " [BR_IFSET = 0]\n"); next(ch); + } return; case BR_IFCLR: /* branch if condition bit is 0 */ - if (!cond) + if (!cond) { + DBDMA_DPRINTFCH(ch, " [BR_IFCLR = 1]\n"); branch(ch); - else + } else { + DBDMA_DPRINTFCH(ch, " [BR_IFCLR = 0]\n"); next(ch); + } return; } } @@ -428,7 +435,7 @@ wait: static void stop(DBDMA_channel *ch) { - ch->regs[DBDMA_STATUS] &= ~(ACTIVE|DEAD|FLUSH); + ch->regs[DBDMA_STATUS] &= ~(ACTIVE); /* the stop command does not increment command pointer */ } @@ -471,18 +478,22 @@ static void channel_run(DBDMA_channel *ch) switch (cmd) { case OUTPUT_MORE: + DBDMA_DPRINTFCH(ch, "* OUTPUT_MORE *\n"); start_output(ch, key, phy_addr, req_count, 0); return; case OUTPUT_LAST: + DBDMA_DPRINTFCH(ch, "* OUTPUT_LAST *\n"); start_output(ch, key, phy_addr, req_count, 1); return; case INPUT_MORE: + DBDMA_DPRINTFCH(ch, "* INPUT_MORE *\n"); start_input(ch, key, phy_addr, req_count, 0); return; case INPUT_LAST: + DBDMA_DPRINTFCH(ch, "* INPUT_LAST *\n"); start_input(ch, key, phy_addr, req_count, 1); return; } @@ -508,10 +519,12 @@ static void channel_run(DBDMA_channel *ch) switch (cmd) { case LOAD_WORD: + DBDMA_DPRINTFCH(ch, "* LOAD_WORD *\n"); load_word(ch, key, phy_addr, req_count); return; case STORE_WORD: + DBDMA_DPRINTFCH(ch, "* STORE_WORD *\n"); store_word(ch, key, phy_addr, req_count); return; } @@ -562,43 +575,117 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, ch->io.opaque = opaque; } -static void -dbdma_control_write(DBDMA_channel *ch) +static void dbdma_control_write(DBDMA_channel *ch) { uint16_t mask, value; uint32_t status; + bool do_flush = false; mask = (ch->regs[DBDMA_CONTROL] >> 16) & 0xffff; value = ch->regs[DBDMA_CONTROL] & 0xffff; - value &= (RUN | PAUSE | FLUSH | WAKE | DEVSTAT); - + /* This is the status register which we'll update + * appropriately and store back + */ status = ch->regs[DBDMA_STATUS]; - status = (value & mask) | (status & ~mask); + /* RUN and PAUSE are bits under SW control only + * FLUSH and WAKE are set by SW and cleared by HW + * DEAD, ACTIVE and BT are only under HW control + * + * We handle ACTIVE separately at the end of the + * logic to ensure all cases are covered. + */ - if (status & WAKE) - status |= ACTIVE; - if (status & RUN) { - status |= ACTIVE; - status &= ~DEAD; + /* Setting RUN will tentatively activate the channel + */ + if ((mask & RUN) && (value & RUN)) { + status |= RUN; + DBDMA_DPRINTFCH(ch, " Setting RUN !\n"); + } + + /* Clearing RUN 1->0 will stop the channel */ + if ((mask & RUN) && !(value & RUN)) { + /* This has the side effect of clearing the DEAD bit */ + status &= ~(DEAD | RUN); + DBDMA_DPRINTFCH(ch, " Clearing RUN !\n"); + } + + /* Setting WAKE wakes up an idle channel if it's running + * + * Note: The doc doesn't say so but assume that only works + * on a channel whose RUN bit is set. + * + * We set WAKE in status, it's not terribly useful as it will + * be cleared on the next command fetch but it seems to mimmic + * the HW behaviour and is useful for the way we handle + * ACTIVE further down. + */ + if ((mask & WAKE) && (value & WAKE) && (status & RUN)) { + status |= WAKE; + DBDMA_DPRINTFCH(ch, " Setting WAKE !\n"); + } + + /* PAUSE being set will deactivate (or prevent activation) + * of the channel. We just copy it over for now, ACTIVE will + * be re-evaluated later. + */ + if (mask & PAUSE) { + status = (status & ~PAUSE) | (value & PAUSE); + DBDMA_DPRINTFCH(ch, " %sing PAUSE !\n", + (value & PAUSE) ? "sett" : "clear"); } - if (status & PAUSE) + + /* FLUSH is its own thing */ + if ((mask & FLUSH) && (value & FLUSH)) { + DBDMA_DPRINTFCH(ch, " Setting FLUSH !\n"); + /* We set flush directly in the status register, we do *NOT* + * set it in "status" so that it gets naturally cleared when + * we update the status register further down. That way it + * will be set only during the HW flush operation so it is + * visible to any completions happening during that time. + */ + ch->regs[DBDMA_STATUS] |= FLUSH; + do_flush = true; + } + + /* If either RUN or PAUSE is clear, so should ACTIVE be, + * otherwise, ACTIVE will be set if we modified RUN, PAUSE or + * set WAKE. That means that PAUSE was just cleared, RUN was + * just set or WAKE was just set. + */ + if ((status & PAUSE) || !(status & RUN)) { status &= ~ACTIVE; - if ((ch->regs[DBDMA_STATUS] & RUN) && !(status & RUN)) { - /* RUN is cleared */ - status &= ~(ACTIVE|DEAD); + DBDMA_DPRINTFCH(ch, " -> ACTIVE down !\n"); + + /* We stopped processing, we want the underlying HW command + * to complete *before* we clear the ACTIVE bit. Otherwise + * we can get into a situation where the command status will + * have RUN or ACTIVE not set which is going to confuse the + * MacOS driver. + */ + do_flush = true; + } else if (mask & (RUN | PAUSE)) { + status |= ACTIVE; + DBDMA_DPRINTFCH(ch, " -> ACTIVE up !\n"); + } else if ((mask & WAKE) && (value & WAKE)) { + status |= ACTIVE; + DBDMA_DPRINTFCH(ch, " -> ACTIVE up !\n"); } - if ((status & FLUSH) && ch->flush) { + DBDMA_DPRINTFCH(ch, " new status=0x%08x\n", status); + + /* If we need to flush the underlying HW, do it now, this happens + * both on FLUSH commands and when stopping the channel for safety. + */ + if (do_flush && ch->flush) { ch->flush(&ch->io); - status &= ~FLUSH; } - DBDMA_DPRINTFCH(ch, " status 0x%08x\n", status); - + /* Finally update the status register image */ ch->regs[DBDMA_STATUS] = status; + /* If active, make sure the BH gets to run */ if (status & ACTIVE) { DBDMA_kick(dbdma_from_ch(ch)); } @@ -666,13 +753,9 @@ static uint64_t dbdma_read(void *opaque, hwaddr addr, value = ch->regs[reg]; - DBDMA_DPRINTFCH(ch, "readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value); - DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n", - (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); - switch(reg) { case DBDMA_CONTROL: - value = 0; + value = ch->regs[DBDMA_STATUS]; break; case DBDMA_STATUS: case DBDMA_CMDPTR_LO: @@ -698,6 +781,10 @@ static uint64_t dbdma_read(void *opaque, hwaddr addr, break; } + DBDMA_DPRINTFCH(ch, "readl 0x" TARGET_FMT_plx " => 0x%08x\n", addr, value); + DBDMA_DPRINTFCH(ch, "channel 0x%x reg 0x%x\n", + (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); + return value; } @@ -764,51 +851,49 @@ static const VMStateDescription vmstate_dbdma = { } }; -static void dbdma_reset(void *opaque) +static void mac_dbdma_reset(DeviceState *d) { - DBDMAState *s = opaque; + DBDMAState *s = MAC_DBDMA(d); int i; - for (i = 0; i < DBDMA_CHANNELS; i++) + for (i = 0; i < DBDMA_CHANNELS; i++) { memset(s->channels[i].regs, 0, DBDMA_SIZE); + } } static void dbdma_unassigned_rw(DBDMA_io *io) -{ - DBDMA_channel *ch = io->channel; - qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n", - __func__, ch->channel); - ch->io.processing = false; -} - -static void dbdma_unassigned_flush(DBDMA_io *io) { DBDMA_channel *ch = io->channel; dbdma_cmd *current = &ch->current; uint16_t cmd; qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n", __func__, ch->channel); + ch->io.processing = false; cmd = le16_to_cpu(current->command) & COMMAND_MASK; if (cmd == OUTPUT_MORE || cmd == OUTPUT_LAST || cmd == INPUT_MORE || cmd == INPUT_LAST) { - current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS] | FLUSH); + current->xfer_status = cpu_to_le16(ch->regs[DBDMA_STATUS]); current->res_count = cpu_to_le16(io->len); dbdma_cmdptr_save(ch); } } -void* DBDMA_init (MemoryRegion **dbdma_mem) +static void dbdma_unassigned_flush(DBDMA_io *io) { - DBDMAState *s; - int i; + DBDMA_channel *ch = io->channel; + qemu_log_mask(LOG_GUEST_ERROR, "%s: use of unassigned channel %d\n", + __func__, ch->channel); +} - s = g_malloc0(sizeof(DBDMAState)); +static void mac_dbdma_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + DBDMAState *s = MAC_DBDMA(obj); + int i; for (i = 0; i < DBDMA_CHANNELS; i++) { - DBDMA_io *io = &s->channels[i].io; DBDMA_channel *ch = &s->channels[i]; - qemu_iovec_init(&io->iov, 1); ch->rw = dbdma_unassigned_rw; ch->flush = dbdma_unassigned_flush; @@ -816,12 +901,37 @@ void* DBDMA_init (MemoryRegion **dbdma_mem) ch->io.channel = ch; } - memory_region_init_io(&s->mem, NULL, &dbdma_ops, s, "dbdma", 0x1000); - *dbdma_mem = &s->mem; - vmstate_register(NULL, -1, &vmstate_dbdma, s); - qemu_register_reset(dbdma_reset, s); + memory_region_init_io(&s->mem, obj, &dbdma_ops, s, "dbdma", 0x1000); + sysbus_init_mmio(sbd, &s->mem); +} + +static void mac_dbdma_realize(DeviceState *dev, Error **errp) +{ + DBDMAState *s = MAC_DBDMA(dev); s->bh = qemu_bh_new(DBDMA_run_bh, s); +} + +static void mac_dbdma_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + + dc->realize = mac_dbdma_realize; + dc->reset = mac_dbdma_reset; + dc->vmsd = &vmstate_dbdma; +} + +static const TypeInfo mac_dbdma_type_info = { + .name = TYPE_MAC_DBDMA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(DBDMAState), + .instance_init = mac_dbdma_init, + .class_init = mac_dbdma_class_init +}; - return s; +static void mac_dbdma_register_types(void) +{ + type_register_static(&mac_dbdma_type_info); } + +type_init(mac_dbdma_register_types) diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 5d57f45dc6df174318d42ffff07e738abb4893d7..9aa7e7559b47122ee7a2cc51b7db8f0c9f453a45 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -41,7 +41,7 @@ typedef struct MacIOState MemoryRegion bar; CUDAState cuda; - void *dbdma; + DBDMAState *dbdma; MemoryRegion *pic_mem; MemoryRegion *escc_mem; uint64_t frequency; @@ -127,10 +127,15 @@ static void macio_common_realize(PCIDevice *d, Error **errp) MacIOState *s = MACIO(d); SysBusDevice *sysbus_dev; Error *err = NULL; - MemoryRegion *dbdma_mem; - s->dbdma = DBDMA_init(&dbdma_mem); - memory_region_add_subregion(&s->bar, 0x08000, dbdma_mem); + object_property_set_bool(OBJECT(s->dbdma), true, "realized", &err); + if (err) { + error_propagate(errp, err); + return; + } + sysbus_dev = SYS_BUS_DEVICE(s->dbdma); + memory_region_add_subregion(&s->bar, 0x08000, + sysbus_mmio_get_region(sysbus_dev, 0)); object_property_set_bool(OBJECT(&s->cuda), true, "realized", &err); if (err) { @@ -154,7 +159,10 @@ static void macio_realize_ide(MacIOState *s, MACIOIDEState *ide, sysbus_dev = SYS_BUS_DEVICE(ide); sysbus_connect_irq(sysbus_dev, 0, irq0); sysbus_connect_irq(sysbus_dev, 1, irq1); - macio_ide_register_dma(ide, s->dbdma, dmaid); + qdev_prop_set_uint32(DEVICE(ide), "channel", dmaid); + object_property_set_link(OBJECT(ide), OBJECT(s->dbdma), "dbdma", errp); + macio_ide_register_dma(ide); + object_property_set_bool(OBJECT(ide), true, "realized", errp); } @@ -334,6 +342,9 @@ static void macio_instance_init(Object *obj) object_initialize(&s->cuda, sizeof(s->cuda), TYPE_CUDA); qdev_set_parent_bus(DEVICE(&s->cuda), sysbus_get_default()); object_property_add_child(obj, "cuda", OBJECT(&s->cuda), NULL); + + s->dbdma = MAC_DBDMA(object_new(TYPE_MAC_DBDMA)); + object_property_add_child(obj, "dbdma", OBJECT(s->dbdma), NULL); } static const VMStateDescription vmstate_macio_oldworld = { diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 20cbddb4e465a9300b17bc47afac3dd3c6ab7edd..b501af16533d178f1614f55344bd2fddd2a935bd 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -131,8 +131,10 @@ typedef struct MACIOIDEState { /*< private >*/ SysBusDevice parent_obj; /*< public >*/ - - qemu_irq irq; + uint32_t channel; + qemu_irq real_ide_irq; + qemu_irq real_dma_irq; + qemu_irq ide_irq; qemu_irq dma_irq; MemoryRegion mem; @@ -140,10 +142,12 @@ typedef struct MACIOIDEState { IDEDMA dma; void *dbdma; bool dma_active; + uint32_t timing_reg; + uint32_t irq_reg; } MACIOIDEState; void macio_ide_init_drives(MACIOIDEState *ide, DriveInfo **hd_table); -void macio_ide_register_dma(MACIOIDEState *ide, void *dbdma, int channel); +void macio_ide_register_dma(MACIOIDEState *ide); void macio_init(PCIDevice *dev, MemoryRegion *pic_mem, diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index d013c412d611a6a12844c59f43cb3992013b2a8a..6d0ace20ca5534a0342025247b76f4b504d0c9fc 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -77,7 +77,7 @@ #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 #define TBFREQ (100UL * 1000UL * 1000UL) -#define CLOCKFREQ (266UL * 1000UL * 1000UL) +#define CLOCKFREQ (900UL * 1000UL * 1000UL) #define BUSFREQ (100UL * 1000UL * 1000UL) #define NDRV_VGA_FILENAME "qemu_vga.ndrv" @@ -342,7 +342,7 @@ static void ppc_core99_init(MachineState *machine) pic = g_new0(qemu_irq, 64); dev = qdev_create(NULL, TYPE_OPENPIC); - qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_RAVEN); + qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_KEYLARGO); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); pic_mem = s->mmio[0].memory; diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 61838c3e6f5e979a937c7900e183936d3f171ce1..bc7c8b7bd748a2edd975a16937e43819758d501f 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -371,8 +371,10 @@ static int heathrow_kvm_type(const char *arg) return 2; } -static void heathrow_machine_init(MachineClass *mc) +static void heathrow_class_init(ObjectClass *oc, void *data) { + MachineClass *mc = MACHINE_CLASS(oc); + mc->desc = "Heathrow based PowerMAC"; mc->init = ppc_heathrow_init; mc->block_default_type = IF_IDE; @@ -385,4 +387,15 @@ static void heathrow_machine_init(MachineClass *mc) mc->kvm_type = heathrow_kvm_type; } -DEFINE_MACHINE("g3beige", heathrow_machine_init) +static const TypeInfo ppc_heathrow_machine_info = { + .name = MACHINE_TYPE_NAME("g3beige"), + .parent = TYPE_MACHINE, + .class_init = heathrow_class_init +}; + +static void ppc_heathrow_register_types(void) +{ + type_register_static(&ppc_heathrow_machine_info); +} + +type_init(ppc_heathrow_register_types); diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index 47221158d415318f5512f737dbf92847f5f35681..d46d91c76f5cdf7d7e6374c8f400fb09e1c6dbc8 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -570,10 +570,14 @@ static void ppc_powernv_init(MachineState *machine) } fw_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); + if (!fw_filename) { + error_report("Could not find OPAL firmware '%s'", bios_name); + exit(1); + } fw_size = load_image_targphys(fw_filename, FW_LOAD_ADDR, FW_MAX_SIZE); if (fw_size < 0) { - error_report("Could not load OPAL '%s'", fw_filename); + error_report("Could not load OPAL firmware '%s'", fw_filename); exit(1); } g_free(fw_filename); diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c index e621d0aec502a4d2feebe8d64750d7b92a09c695..8e58065f5fc2d669c561833dcbff06858e904145 100644 --- a/hw/ppc/ppc405_uc.c +++ b/hw/ppc/ppc405_uc.c @@ -105,9 +105,12 @@ ram_addr_t ppc405_set_bootinfo (CPUPPCState *env, ppc4xx_bd_info_t *bd, /*****************************************************************************/ /* Peripheral local bus arbitrer */ enum { - PLB0_BESR = 0x084, - PLB0_BEAR = 0x086, - PLB0_ACR = 0x087, + PLB3A0_ACR = 0x077, + PLB4A0_ACR = 0x081, + PLB0_BESR = 0x084, + PLB0_BEAR = 0x086, + PLB0_ACR = 0x087, + PLB4A1_ACR = 0x089, }; typedef struct ppc4xx_plb_t ppc4xx_plb_t; @@ -179,9 +182,12 @@ void ppc4xx_plb_init(CPUPPCState *env) ppc4xx_plb_t *plb; plb = g_malloc0(sizeof(ppc4xx_plb_t)); + ppc_dcr_register(env, PLB3A0_ACR, plb, &dcr_read_plb, &dcr_write_plb); + ppc_dcr_register(env, PLB4A0_ACR, plb, &dcr_read_plb, &dcr_write_plb); ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb); ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb); ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb); + ppc_dcr_register(env, PLB4A1_ACR, plb, &dcr_read_plb, &dcr_write_plb); qemu_register_reset(ppc4xx_plb_reset, plb); } diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 17ea77618cb9c721cbc13f9bce2f0e411237b5c9..ff87f155d55ec3d216ed8a2f62e2ea1148d9b0e3 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1211,14 +1211,15 @@ static uint64_t spapr_get_patbe(PPCVirtualHypervisor *vhyp) */ static int get_htab_fd(sPAPRMachineState *spapr) { + Error *local_err = NULL; + if (spapr->htab_fd >= 0) { return spapr->htab_fd; } - spapr->htab_fd = kvmppc_get_htab_fd(false); + spapr->htab_fd = kvmppc_get_htab_fd(false, 0, &local_err); if (spapr->htab_fd < 0) { - error_report("Unable to open fd for reading hash table from KVM: %s", - strerror(errno)); + error_report_err(local_err); } return spapr->htab_fd; @@ -1239,6 +1240,19 @@ static hwaddr spapr_hpt_mask(PPCVirtualHypervisor *vhyp) return HTAB_SIZE(spapr) / HASH_PTEG_SIZE_64 - 1; } +static target_ulong spapr_encode_hpt_for_kvm_pr(PPCVirtualHypervisor *vhyp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(vhyp); + + assert(kvm_enabled()); + + if (!spapr->htab) { + return 0; + } + + return (target_ulong)(uintptr_t)spapr->htab | (spapr->htab_shift - 18); +} + static const ppc_hash_pte64_t *spapr_map_hptes(PPCVirtualHypervisor *vhyp, hwaddr ptex, int n) { @@ -1708,6 +1722,23 @@ static int htab_save_setup(QEMUFile *f, void *opaque) return 0; } +static void htab_save_chunk(QEMUFile *f, sPAPRMachineState *spapr, + int chunkstart, int n_valid, int n_invalid) +{ + qemu_put_be32(f, chunkstart); + qemu_put_be16(f, n_valid); + qemu_put_be16(f, n_invalid); + qemu_put_buffer(f, HPTE(spapr->htab, chunkstart), + HASH_PTE_SIZE_64 * n_valid); +} + +static void htab_save_end_marker(QEMUFile *f) +{ + qemu_put_be32(f, 0); + qemu_put_be16(f, 0); + qemu_put_be16(f, 0); +} + static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr, int64_t max_ns) { @@ -1739,11 +1770,7 @@ static void htab_save_first_pass(QEMUFile *f, sPAPRMachineState *spapr, if (index > chunkstart) { int n_valid = index - chunkstart; - qemu_put_be32(f, chunkstart); - qemu_put_be16(f, n_valid); - qemu_put_be16(f, 0); - qemu_put_buffer(f, HPTE(spapr->htab, chunkstart), - HASH_PTE_SIZE_64 * n_valid); + htab_save_chunk(f, spapr, chunkstart, n_valid, 0); if (has_timeout && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) { @@ -1805,11 +1832,7 @@ static int htab_save_later_pass(QEMUFile *f, sPAPRMachineState *spapr, int n_valid = invalidstart - chunkstart; int n_invalid = index - invalidstart; - qemu_put_be32(f, chunkstart); - qemu_put_be16(f, n_valid); - qemu_put_be16(f, n_invalid); - qemu_put_buffer(f, HPTE(spapr->htab, chunkstart), - HASH_PTE_SIZE_64 * n_valid); + htab_save_chunk(f, spapr, chunkstart, n_valid, n_invalid); sent += index - chunkstart; if (!final && (qemu_clock_get_ns(QEMU_CLOCK_REALTIME) - starttime) > max_ns) { @@ -1872,10 +1895,7 @@ static int htab_save_iterate(QEMUFile *f, void *opaque) rc = htab_save_later_pass(f, spapr, MAX_ITERATION_NS); } - /* End marker */ - qemu_put_be32(f, 0); - qemu_put_be16(f, 0); - qemu_put_be16(f, 0); + htab_save_end_marker(f); return rc; } @@ -1915,9 +1935,7 @@ static int htab_save_complete(QEMUFile *f, void *opaque) } /* End marker */ - qemu_put_be32(f, 0); - qemu_put_be16(f, 0); - qemu_put_be16(f, 0); + htab_save_end_marker(f); return 0; } @@ -1927,6 +1945,7 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id) sPAPRMachineState *spapr = opaque; uint32_t section_hdr; int fd = -1; + Error *local_err = NULL; if (version_id < 1 || version_id > 1) { error_report("htab_load() bad version"); @@ -1941,8 +1960,6 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id) } if (section_hdr) { - Error *local_err = NULL; - /* First section gives the htab size */ spapr_reallocate_hpt(spapr, section_hdr, &local_err); if (local_err) { @@ -1955,10 +1972,10 @@ static int htab_load(QEMUFile *f, void *opaque, int version_id) if (!spapr->htab) { assert(kvm_enabled()); - fd = kvmppc_get_htab_fd(true); + fd = kvmppc_get_htab_fd(true, 0, &local_err); if (fd < 0) { - error_report("Unable to open fd to restore KVM hash table: %s", - strerror(errno)); + error_report_err(local_err); + return fd; } } @@ -3600,6 +3617,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) vhc->unmap_hptes = spapr_unmap_hptes; vhc->store_hpte = spapr_store_hpte; vhc->get_patbe = spapr_get_patbe; + vhc->encode_hpt_for_kvm_pr = spapr_encode_hpt_for_kvm_pr; xic->ics_get = spapr_ics_get; xic->ics_resend = spapr_ics_resend; xic->icp_get = spapr_icp_get; diff --git a/hw/ppc/spapr_cpu_core.c b/hw/ppc/spapr_cpu_core.c index c08ee7571a50933807dd76c3c573a6a376251acf..3e20b1d8864417be21d0052d0b80c9ce09164fa5 100644 --- a/hw/ppc/spapr_cpu_core.c +++ b/hw/ppc/spapr_cpu_core.c @@ -18,6 +18,7 @@ #include "hw/ppc/ppc.h" #include "target/ppc/mmu-hash64.h" #include "sysemu/numa.h" +#include "sysemu/hw_accel.h" #include "qemu/error-report.h" void spapr_cpu_parse_features(sPAPRMachineState *spapr) @@ -73,7 +74,6 @@ void spapr_cpu_parse_features(sPAPRMachineState *spapr) static void spapr_cpu_reset(void *opaque) { - sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); PowerPCCPU *cpu = opaque; CPUState *cs = CPU(cpu); CPUPPCState *env = &cpu->env; @@ -86,20 +86,6 @@ static void spapr_cpu_reset(void *opaque) cs->halted = 1; env->spr[SPR_HIOR] = 0; - - /* - * This is a hack for the benefit of KVM PR - it abuses the SDR1 - * slot in kvm_sregs to communicate the userspace address of the - * HPT - */ - if (kvm_enabled()) { - env->spr[SPR_SDR1] = (target_ulong)(uintptr_t)spapr->htab - | (spapr->htab_shift - 18); - if (kvmppc_put_books_sregs(cpu) < 0) { - error_report("Unable to update SDR1 in KVM"); - exit(1); - } - } } static void spapr_cpu_destroy(PowerPCCPU *cpu) diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 57bb411394ed00f486ebd1b2623cf4c346ff341f..8d72bb7c1c34f762394c3204b5526ff72bcda017 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -686,6 +686,37 @@ static int rehash_hpt(PowerPCCPU *cpu, return H_SUCCESS; } +static void do_push_sregs_to_kvm_pr(CPUState *cs, run_on_cpu_data data) +{ + int ret; + + cpu_synchronize_state(cs); + + ret = kvmppc_put_books_sregs(POWERPC_CPU(cs)); + if (ret < 0) { + error_report("failed to push sregs to KVM: %s", strerror(-ret)); + exit(1); + } +} + +static void push_sregs_to_kvm_pr(sPAPRMachineState *spapr) +{ + CPUState *cs; + + /* + * This is a hack for the benefit of KVM PR - it abuses the SDR1 + * slot in kvm_sregs to communicate the userspace address of the + * HPT + */ + if (!kvm_enabled() || !spapr->htab) { + return; + } + + CPU_FOREACH(cs) { + run_on_cpu(cs, do_push_sregs_to_kvm_pr, RUN_ON_CPU_NULL); + } +} + static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, @@ -733,12 +764,7 @@ static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu, spapr->htab = pending->hpt; spapr->htab_shift = pending->shift; - if (kvm_enabled()) { - /* For KVM PR, update the HPT pointer */ - target_ulong sdr1 = (target_ulong)(uintptr_t)spapr->htab - | (spapr->htab_shift - 18); - kvmppc_update_sdr1(sdr1); - } + push_sregs_to_kvm_pr(spapr); pending->hpt = NULL; /* so it's not free()d */ } @@ -1564,12 +1590,7 @@ static target_ulong h_client_architecture_support(PowerPCCPU *cpu, * the point this is called, nothing should have been * entered into the existing HPT */ spapr_reallocate_hpt(spapr, maxshift, &error_fatal); - if (kvm_enabled()) { - /* For KVM PR, update the HPT pointer */ - target_ulong sdr1 = (target_ulong)(uintptr_t)spapr->htab - | (spapr->htab_shift - 18); - kvmppc_update_sdr1(sdr1); - } + push_sregs_to_kvm_pr(spapr); } } diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index cf54160526fae4b2ba0093d86197da5601e619e5..6126c800440f41fdbf481f3c0be1d3f262c65cc4 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1523,16 +1523,6 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) sPAPRMachineClass *smc = SPAPR_MACHINE_GET_CLASS(spapr); Error *local_err = NULL; - if ((sphb->buid != (uint64_t)-1) || (sphb->dma_liobn[0] != (uint32_t)-1) - || (sphb->dma_liobn[1] != (uint32_t)-1 && windows_supported == 2) - || (sphb->mem_win_addr != (hwaddr)-1) - || (sphb->mem64_win_addr != (hwaddr)-1) - || (sphb->io_win_addr != (hwaddr)-1)) { - error_setg(errp, "Either \"index\" or other parameters must" - " be specified for PAPR PHB, not both"); - return; - } - smc->phb_placement(spapr, sphb->index, &sphb->buid, &sphb->io_win_addr, &sphb->mem_win_addr, &sphb->mem64_win_addr, @@ -1541,46 +1531,20 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) error_propagate(errp, local_err); return; } - } - - if (sphb->buid == (uint64_t)-1) { - error_setg(errp, "BUID not specified for PHB"); - return; - } - - if ((sphb->dma_liobn[0] == (uint32_t)-1) || - ((sphb->dma_liobn[1] == (uint32_t)-1) && (windows_supported > 1))) { - error_setg(errp, "LIOBN(s) not specified for PHB"); - return; - } - - if (sphb->mem_win_addr == (hwaddr)-1) { - error_setg(errp, "Memory window address not specified for PHB"); - return; - } - - if (sphb->io_win_addr == (hwaddr)-1) { - error_setg(errp, "IO window address not specified for PHB"); + } else { + error_setg(errp, "\"index\" for PAPR PHB is mandatory"); return; } if (sphb->mem64_win_size != 0) { - if (sphb->mem64_win_addr == (hwaddr)-1) { - error_setg(errp, - "64-bit memory window address not specified for PHB"); - return; - } - if (sphb->mem_win_size > SPAPR_PCI_MEM32_WIN_SIZE) { error_setg(errp, "32-bit memory window of size 0x%"HWADDR_PRIx " (max 2 GiB)", sphb->mem_win_size); return; } - if (sphb->mem64_win_pciaddr == (hwaddr)-1) { - /* 64-bit window defaults to identity mapping */ - sphb->mem64_win_pciaddr = sphb->mem64_win_addr; - } + /* 64-bit window defaults to identity mapping */ + sphb->mem64_win_pciaddr = sphb->mem64_win_addr; } else if (sphb->mem_win_size > SPAPR_PCI_MEM32_WIN_SIZE) { /* * For compatibility with old configuration, if no 64-bit MMIO @@ -1622,18 +1586,16 @@ static void spapr_phb_realize(DeviceState *dev, Error **errp) memory_region_add_subregion(get_system_memory(), sphb->mem_win_addr, &sphb->mem32window); - if (sphb->mem64_win_pciaddr != (hwaddr)-1) { + if (sphb->mem64_win_size != 0) { namebuf = g_strdup_printf("%s.mmio64-alias", sphb->dtbusname); memory_region_init_alias(&sphb->mem64window, OBJECT(sphb), namebuf, &sphb->memspace, sphb->mem64_win_pciaddr, sphb->mem64_win_size); g_free(namebuf); - if (sphb->mem64_win_addr != (hwaddr)-1) { - memory_region_add_subregion(get_system_memory(), - sphb->mem64_win_addr, - &sphb->mem64window); - } + memory_region_add_subregion(get_system_memory(), + sphb->mem64_win_addr, + &sphb->mem64window); } /* Initialize IO regions */ @@ -1789,18 +1751,10 @@ static void spapr_phb_reset(DeviceState *qdev) static Property spapr_phb_properties[] = { DEFINE_PROP_UINT32("index", sPAPRPHBState, index, -1), - DEFINE_PROP_UINT64("buid", sPAPRPHBState, buid, -1), - DEFINE_PROP_UINT32("liobn", sPAPRPHBState, dma_liobn[0], -1), - DEFINE_PROP_UINT32("liobn64", sPAPRPHBState, dma_liobn[1], -1), - DEFINE_PROP_UINT64("mem_win_addr", sPAPRPHBState, mem_win_addr, -1), DEFINE_PROP_UINT64("mem_win_size", sPAPRPHBState, mem_win_size, SPAPR_PCI_MEM32_WIN_SIZE), - DEFINE_PROP_UINT64("mem64_win_addr", sPAPRPHBState, mem64_win_addr, -1), DEFINE_PROP_UINT64("mem64_win_size", sPAPRPHBState, mem64_win_size, SPAPR_PCI_MEM64_WIN_SIZE), - DEFINE_PROP_UINT64("mem64_win_pciaddr", sPAPRPHBState, mem64_win_pciaddr, - -1), - DEFINE_PROP_UINT64("io_win_addr", sPAPRPHBState, io_win_addr, -1), DEFINE_PROP_UINT64("io_win_size", sPAPRPHBState, io_win_size, SPAPR_PCI_IO_WIN_SIZE), DEFINE_PROP_BOOL("dynamic-reconfiguration", sPAPRPHBState, dr_enabled, diff --git a/hw/usb/hcd-ehci-sysbus.c b/hw/usb/hcd-ehci-sysbus.c index 6c20604d07497bc0c8066c226f3874f07670bf2a..3b83beb140d85be1df7fb4ea688f92f50011cc1c 100644 --- a/hw/usb/hcd-ehci-sysbus.c +++ b/hw/usb/hcd-ehci-sysbus.c @@ -142,6 +142,30 @@ static const TypeInfo ehci_tegra2_type_info = { .class_init = ehci_tegra2_class_init, }; +static void ehci_ppc4xx_init(Object *o) +{ + EHCISysBusState *s = SYS_BUS_EHCI(o); + + s->ehci.companion_enable = true; +} + +static void ehci_ppc4xx_class_init(ObjectClass *oc, void *data) +{ + SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc); + DeviceClass *dc = DEVICE_CLASS(oc); + + sec->capsbase = 0x0; + sec->opregbase = 0x10; + set_bit(DEVICE_CATEGORY_USB, dc->categories); +} + +static const TypeInfo ehci_ppc4xx_type_info = { + .name = TYPE_PPC4xx_EHCI, + .parent = TYPE_SYS_BUS_EHCI, + .class_init = ehci_ppc4xx_class_init, + .instance_init = ehci_ppc4xx_init, +}; + /* * Faraday FUSBH200 USB 2.0 EHCI */ @@ -224,6 +248,7 @@ static void ehci_sysbus_register_types(void) type_register_static(&ehci_xlnx_type_info); type_register_static(&ehci_exynos4210_type_info); type_register_static(&ehci_tegra2_type_info); + type_register_static(&ehci_ppc4xx_type_info); type_register_static(&ehci_fusbh200_type_info); } diff --git a/hw/usb/hcd-ehci.h b/hw/usb/hcd-ehci.h index 821f1ded435eca36a72fe4446af0cdff480b0437..0bc364b286110e118781a54a67479f871c1d340e 100644 --- a/hw/usb/hcd-ehci.h +++ b/hw/usb/hcd-ehci.h @@ -344,6 +344,7 @@ typedef struct EHCIPCIState { #define TYPE_SYS_BUS_EHCI "sysbus-ehci-usb" #define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb" #define TYPE_TEGRA2_EHCI "tegra2-ehci-usb" +#define TYPE_PPC4xx_EHCI "ppc4xx-ehci-usb" #define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb" #define SYS_BUS_EHCI(obj) \ diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index 267982e160b3f69e492efb73c7d54dae16dbfa44..17beeddb09a03778200ce61bbc1148febf153b5d 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -1999,7 +1999,9 @@ typedef struct { /*< public >*/ OHCIState ohci; + char *masterbus; uint32_t num_ports; + uint32_t firstport; dma_addr_t dma_offset; } OHCISysBusState; @@ -2007,10 +2009,15 @@ static void ohci_realize_pxa(DeviceState *dev, Error **errp) { OHCISysBusState *s = SYSBUS_OHCI(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); + Error *err = NULL; - /* Cannot fail as we pass NULL for masterbus */ - usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, NULL, 0, - &address_space_memory, &error_abort); + usb_ohci_init(&s->ohci, dev, s->num_ports, s->dma_offset, + s->masterbus, s->firstport, + &address_space_memory, &err); + if (err) { + error_propagate(errp, err); + return; + } sysbus_init_irq(sbd, &s->ohci.irq); sysbus_init_mmio(sbd, &s->ohci.mem); } @@ -2142,7 +2149,9 @@ static const TypeInfo ohci_pci_info = { }; static Property ohci_sysbus_properties[] = { + DEFINE_PROP_STRING("masterbus", OHCISysBusState, masterbus), DEFINE_PROP_UINT32("num-ports", OHCISysBusState, num_ports, 3), + DEFINE_PROP_UINT32("firstport", OHCISysBusState, firstport, 0), DEFINE_PROP_DMAADDR("dma-offset", OHCISysBusState, dma_offset, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/include/hw/ppc/mac_dbdma.h b/include/hw/ppc/mac_dbdma.h index a8603877d79cddbdb433771d0f45aaec5c93b7e0..26cc469de483a9632946912bd722ec79441ccd63 100644 --- a/include/hw/ppc/mac_dbdma.h +++ b/include/hw/ppc/mac_dbdma.h @@ -26,6 +26,7 @@ #include "exec/memory.h" #include "qemu/iov.h" #include "sysemu/dma.h" +#include "hw/sysbus.h" typedef struct DBDMA_io DBDMA_io; @@ -42,10 +43,6 @@ struct DBDMA_io { DBDMA_end dma_end; /* DMA is in progress, don't start another one */ bool processing; - /* unaligned last sector of a request */ - uint8_t head_remainder[0x200]; - uint8_t tail_remainder[0x200]; - QEMUIOVector iov; /* DMA request */ void *dma_mem; dma_addr_t dma_len; @@ -164,6 +161,8 @@ typedef struct DBDMA_channel { } DBDMA_channel; typedef struct { + SysBusDevice parent_obj; + MemoryRegion mem; DBDMA_channel channels[DBDMA_CHANNELS]; QEMUBH *bh; @@ -175,6 +174,8 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, DBDMA_rw rw, DBDMA_flush flush, void *opaque); void DBDMA_kick(DBDMAState *dbdma); -void* DBDMA_init (MemoryRegion **dbdma_mem); + +#define TYPE_MAC_DBDMA "mac-dbdma" +#define MAC_DBDMA(obj) OBJECT_CHECK(DBDMAState, (obj), TYPE_MAC_DBDMA) #endif diff --git a/include/hw/ppc/openpic.h b/include/hw/ppc/openpic.h index 6137e2d7a2f2d0ca0cc26f8f36ef0575949b3286..e55ce546aa49b05b212e990f98582518502d2c93 100644 --- a/include/hw/ppc/openpic.h +++ b/include/hw/ppc/openpic.h @@ -20,6 +20,7 @@ enum { #define OPENPIC_MODEL_RAVEN 0 #define OPENPIC_MODEL_FSL_MPIC_20 1 #define OPENPIC_MODEL_FSL_MPIC_42 2 +#define OPENPIC_MODEL_KEYLARGO 3 #define OPENPIC_MAX_SRC 256 #define OPENPIC_MAX_TMR 4 diff --git a/include/hw/ppc/pnv_xscom.h b/include/hw/ppc/pnv_xscom.h index 3757b2cab94bfc4d5fec8baebc35f6e509bf96aa..38077b479699ce08f1e737181fdf7e187b058735 100644 --- a/include/hw/ppc/pnv_xscom.h +++ b/include/hw/ppc/pnv_xscom.h @@ -54,7 +54,7 @@ typedef struct PnvXScomInterfaceClass { * PCB SLAVE 0x110Fxxxx */ -#define PNV_XSCOM_EX_CORE_BASE(base, i) (base | (((uint64_t)i) << 24)) +#define PNV_XSCOM_EX_CORE_BASE(base, i) ((base) | ((uint64_t)(i) << 24)) #define PNV_XSCOM_EX_CORE_SIZE 0x100000 #define PNV_XSCOM_LPC_BASE 0xb0020 diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c index 9626d6b7c40f57679b62d6248666b3a24cda6ce5..9d45702843d4e6658cec71bf9619dfaf6fd77ae4 100644 --- a/target/ppc/cpu-models.c +++ b/target/ppc/cpu-models.c @@ -167,6 +167,8 @@ "PowerPC 440 EPb") POWERPC_DEF("440epx", CPU_POWERPC_440EPX, 440EP, "PowerPC 440 EPX") + POWERPC_DEF("460exb", CPU_POWERPC_460EXb, 460EX, + "PowerPC 460 EXb") #if defined(TODO_USER_ONLY) POWERPC_DEF("440gpb", CPU_POWERPC_440GPb, 440GP, "PowerPC 440 GPb") @@ -786,6 +788,7 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { { "x2vp50", "x2vp20" }, { "440ep", "440epb" }, + { "460ex", "460exb" }, #if defined(TODO_USER_ONLY) { "440gp", "440gpc" }, { "440gr", "440gra" }, diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h index df31d7f49276eec2ee485b509492c4dc967052ac..25ef372d4c1dd3bc3d8f82eb34dc31a7311f8b37 100644 --- a/target/ppc/cpu-models.h +++ b/target/ppc/cpu-models.h @@ -44,184 +44,55 @@ enum { /* PowerPC 401 cores */ CPU_POWERPC_401A1 = 0x00210000, CPU_POWERPC_401B2 = 0x00220000, -#if 0 - CPU_POWERPC_401B3 = xxx, -#endif CPU_POWERPC_401C2 = 0x00230000, CPU_POWERPC_401D2 = 0x00240000, CPU_POWERPC_401E2 = 0x00250000, CPU_POWERPC_401F2 = 0x00260000, CPU_POWERPC_401G2 = 0x00270000, /* PowerPC 401 microcontrolers */ -#if 0 - CPU_POWERPC_401GF = xxx, -#endif #define CPU_POWERPC_IOP480 CPU_POWERPC_401B2 /* IBM Processor for Network Resources */ CPU_POWERPC_COBRA = 0x10100000, /* XXX: 405 ? */ -#if 0 - CPU_POWERPC_XIPCHIP = xxx, -#endif /* PowerPC 403 family */ /* PowerPC 403 microcontrollers */ CPU_POWERPC_403GA = 0x00200011, CPU_POWERPC_403GB = 0x00200100, CPU_POWERPC_403GC = 0x00200200, CPU_POWERPC_403GCX = 0x00201400, -#if 0 - CPU_POWERPC_403GP = xxx, -#endif /* PowerPC 405 family */ /* PowerPC 405 cores */ -#if 0 - CPU_POWERPC_405A3 = xxx, -#endif -#if 0 - CPU_POWERPC_405A4 = xxx, -#endif -#if 0 - CPU_POWERPC_405B3 = xxx, -#endif -#if 0 - CPU_POWERPC_405B4 = xxx, -#endif -#if 0 - CPU_POWERPC_405C3 = xxx, -#endif -#if 0 - CPU_POWERPC_405C4 = xxx, -#endif CPU_POWERPC_405D2 = 0x20010000, -#if 0 - CPU_POWERPC_405D3 = xxx, -#endif CPU_POWERPC_405D4 = 0x41810000, -#if 0 - CPU_POWERPC_405D5 = xxx, -#endif -#if 0 - CPU_POWERPC_405E4 = xxx, -#endif -#if 0 - CPU_POWERPC_405F4 = xxx, -#endif -#if 0 - CPU_POWERPC_405F5 = xxx, -#endif -#if 0 - CPU_POWERPC_405F6 = xxx, -#endif /* PowerPC 405 microcontrolers */ /* XXX: missing 0x200108a0 */ CPU_POWERPC_405CRa = 0x40110041, CPU_POWERPC_405CRb = 0x401100C5, CPU_POWERPC_405CRc = 0x40110145, CPU_POWERPC_405EP = 0x51210950, -#if 0 - CPU_POWERPC_405EXr = xxx, -#endif CPU_POWERPC_405EZ = 0x41511460, /* 0x51210950 ? */ -#if 0 - CPU_POWERPC_405FX = xxx, -#endif CPU_POWERPC_405GPa = 0x40110000, CPU_POWERPC_405GPb = 0x40110040, CPU_POWERPC_405GPc = 0x40110082, CPU_POWERPC_405GPd = 0x401100C4, CPU_POWERPC_405GPR = 0x50910951, -#if 0 - CPU_POWERPC_405H = xxx, -#endif -#if 0 - CPU_POWERPC_405L = xxx, -#endif CPU_POWERPC_405LP = 0x41F10000, -#if 0 - CPU_POWERPC_405PM = xxx, -#endif -#if 0 - CPU_POWERPC_405PS = xxx, -#endif -#if 0 - CPU_POWERPC_405S = xxx, -#endif /* IBM network processors */ CPU_POWERPC_NPE405H = 0x414100C0, CPU_POWERPC_NPE405H2 = 0x41410140, CPU_POWERPC_NPE405L = 0x416100C0, CPU_POWERPC_NPE4GS3 = 0x40B10000, -#if 0 - CPU_POWERPC_NPCxx1 = xxx, -#endif -#if 0 - CPU_POWERPC_NPR161 = xxx, -#endif -#if 0 - CPU_POWERPC_LC77700 = xxx, -#endif /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */ -#if 0 - CPU_POWERPC_STB01000 = xxx, -#endif -#if 0 - CPU_POWERPC_STB01010 = xxx, -#endif -#if 0 - CPU_POWERPC_STB0210 = xxx, /* 401B3 */ -#endif CPU_POWERPC_STB03 = 0x40310000, /* 0x40130000 ? */ -#if 0 - CPU_POWERPC_STB043 = xxx, -#endif -#if 0 - CPU_POWERPC_STB045 = xxx, -#endif CPU_POWERPC_STB04 = 0x41810000, CPU_POWERPC_STB25 = 0x51510950, -#if 0 - CPU_POWERPC_STB130 = xxx, -#endif /* Xilinx cores */ CPU_POWERPC_X2VP4 = 0x20010820, CPU_POWERPC_X2VP20 = 0x20010860, -#if 0 - CPU_POWERPC_ZL10310 = xxx, -#endif -#if 0 - CPU_POWERPC_ZL10311 = xxx, -#endif -#if 0 - CPU_POWERPC_ZL10320 = xxx, -#endif -#if 0 - CPU_POWERPC_ZL10321 = xxx, -#endif /* PowerPC 440 family */ /* Generic PowerPC 440 */ #define CPU_POWERPC_440 CPU_POWERPC_440GXf /* PowerPC 440 cores */ -#if 0 - CPU_POWERPC_440A4 = xxx, -#endif CPU_POWERPC_440_XILINX = 0x7ff21910, -#if 0 - CPU_POWERPC_440A5 = xxx, -#endif -#if 0 - CPU_POWERPC_440B4 = xxx, -#endif -#if 0 - CPU_POWERPC_440F5 = xxx, -#endif -#if 0 - CPU_POWERPC_440G5 = xxx, -#endif -#if 0 - CPU_POWERPC_440H4 = xxx, -#endif -#if 0 - CPU_POWERPC_440H6 = xxx, -#endif /* PowerPC 440 microcontrolers */ CPU_POWERPC_440EPa = 0x42221850, CPU_POWERPC_440EPb = 0x422218D3, @@ -234,24 +105,10 @@ enum { CPU_POWERPC_440GXb = 0x51B21851, CPU_POWERPC_440GXc = 0x51B21892, CPU_POWERPC_440GXf = 0x51B21894, -#if 0 - CPU_POWERPC_440S = xxx, -#endif CPU_POWERPC_440SP = 0x53221850, CPU_POWERPC_440SP2 = 0x53221891, CPU_POWERPC_440SPE = 0x53421890, - /* PowerPC 460 family */ -#if 0 - /* Generic PowerPC 464 */ -#define CPU_POWERPC_464 CPU_POWERPC_464H90 -#endif - /* PowerPC 464 microcontrolers */ -#if 0 - CPU_POWERPC_464H90 = xxx, -#endif -#if 0 - CPU_POWERPC_464H90FP = xxx, -#endif + CPU_POWERPC_460EXb = 0x130218A4, /* called 460 but 440 core */ /* Freescale embedded PowerPC cores */ /* PowerPC MPC 5xx cores (aka RCPU) */ CPU_POWERPC_MPC5xx = 0x00020020, @@ -280,45 +137,8 @@ enum { #define CPU_POWERPC_MPC5200B_v21 CPU_POWERPC_G2LEgp1 /* e200 family */ /* e200 cores */ -#if 0 - CPU_POWERPC_e200z0 = xxx, -#endif -#if 0 - CPU_POWERPC_e200z1 = xxx, -#endif -#if 0 /* ? */ - CPU_POWERPC_e200z3 = 0x81120000, -#endif CPU_POWERPC_e200z5 = 0x81000000, CPU_POWERPC_e200z6 = 0x81120000, - /* MPC55xx microcontrollers */ -#define CPU_POWERPC_MPC55xx CPU_POWERPC_MPC5567 -#if 0 -#define CPU_POWERPC_MPC5514E CPU_POWERPC_MPC5514E_v1 -#define CPU_POWERPC_MPC5514E_v0 CPU_POWERPC_e200z0 -#define CPU_POWERPC_MPC5514E_v1 CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5514G CPU_POWERPC_MPC5514G_v1 -#define CPU_POWERPC_MPC5514G_v0 CPU_POWERPC_e200z0 -#define CPU_POWERPC_MPC5514G_v1 CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5515S CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5516E CPU_POWERPC_MPC5516E_v1 -#define CPU_POWERPC_MPC5516E_v0 CPU_POWERPC_e200z0 -#define CPU_POWERPC_MPC5516E_v1 CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5516G CPU_POWERPC_MPC5516G_v1 -#define CPU_POWERPC_MPC5516G_v0 CPU_POWERPC_e200z0 -#define CPU_POWERPC_MPC5516G_v1 CPU_POWERPC_e200z1 -#define CPU_POWERPC_MPC5516S CPU_POWERPC_e200z1 -#endif -#if 0 -#define CPU_POWERPC_MPC5533 CPU_POWERPC_e200z3 -#define CPU_POWERPC_MPC5534 CPU_POWERPC_e200z3 -#endif -#define CPU_POWERPC_MPC5553 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5554 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5561 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5565 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5566 CPU_POWERPC_e200z6 -#define CPU_POWERPC_MPC5567 CPU_POWERPC_e200z6 /* e300 family */ /* e300 cores */ CPU_POWERPC_e300c1 = 0x00830010, @@ -326,11 +146,7 @@ enum { CPU_POWERPC_e300c3 = 0x00850010, CPU_POWERPC_e300c4 = 0x00860010, /* MPC83xx microcontrollers */ -#define CPU_POWERPC_MPC831x CPU_POWERPC_e300c3 -#define CPU_POWERPC_MPC832x CPU_POWERPC_e300c2 #define CPU_POWERPC_MPC834x CPU_POWERPC_e300c1 -#define CPU_POWERPC_MPC835x CPU_POWERPC_e300c1 -#define CPU_POWERPC_MPC836x CPU_POWERPC_e300c1 #define CPU_POWERPC_MPC837x CPU_POWERPC_e300c4 /* e500 family */ /* e500 cores */ @@ -438,9 +254,6 @@ enum { /* XXX: missing 0x000a0100 */ /* XXX: missing 0x00093102 */ CPU_POWERPC_604R = 0x000a0101, -#if 0 - CPU_POWERPC_604EV = xxx, /* XXX: same as 604R ? */ -#endif /* PowerPC 740/750 cores (aka G3) */ /* XXX: missing 0x00084202 */ CPU_POWERPC_7x0_v10 = 0x00080100, @@ -495,9 +308,6 @@ enum { CPU_POWERPC_7x5_v26 = 0x00083206, CPU_POWERPC_7x5_v27 = 0x00083207, CPU_POWERPC_7x5_v28 = 0x00083208, -#if 0 - CPU_POWERPC_7x5P = xxx, -#endif /* PowerPC 74xx cores (aka G4) */ /* XXX: missing 0x000C1101 */ CPU_POWERPC_7400_v10 = 0x000C0100, @@ -585,12 +395,6 @@ enum { /* XXX: should be POWER (RIOS), RSC3308, RSC4608, * POWER2 (RIOS2) & RSC2 (P2SC) here */ -#if 0 - CPU_POWER = xxx, /* 0x20000 ? 0x30000 for RSC ? */ -#endif -#if 0 - CPU_POWER2 = xxx, /* 0x40000 ? */ -#endif /* PA Semi core */ CPU_POWERPC_PA6T = 0x00900000, }; @@ -614,60 +418,6 @@ enum { POWERPC_SVR_5200B_v20 = 0x80110020, POWERPC_SVR_5200B_v21 = 0x80110021, #define POWERPC_SVR_55xx POWERPC_SVR_5567 -#if 0 - POWERPC_SVR_5533 = xxx, -#endif -#if 0 - POWERPC_SVR_5534 = xxx, -#endif -#if 0 - POWERPC_SVR_5553 = xxx, -#endif -#if 0 - POWERPC_SVR_5554 = xxx, -#endif -#if 0 - POWERPC_SVR_5561 = xxx, -#endif -#if 0 - POWERPC_SVR_5565 = xxx, -#endif -#if 0 - POWERPC_SVR_5566 = xxx, -#endif -#if 0 - POWERPC_SVR_5567 = xxx, -#endif -#if 0 - POWERPC_SVR_8313 = xxx, -#endif -#if 0 - POWERPC_SVR_8313E = xxx, -#endif -#if 0 - POWERPC_SVR_8314 = xxx, -#endif -#if 0 - POWERPC_SVR_8314E = xxx, -#endif -#if 0 - POWERPC_SVR_8315 = xxx, -#endif -#if 0 - POWERPC_SVR_8315E = xxx, -#endif -#if 0 - POWERPC_SVR_8321 = xxx, -#endif -#if 0 - POWERPC_SVR_8321E = xxx, -#endif -#if 0 - POWERPC_SVR_8323 = xxx, -#endif -#if 0 - POWERPC_SVR_8323E = xxx, -#endif POWERPC_SVR_8343 = 0x80570010, POWERPC_SVR_8343A = 0x80570030, POWERPC_SVR_8343E = 0x80560010, @@ -684,12 +434,6 @@ enum { POWERPC_SVR_8349A = 0x80510030, POWERPC_SVR_8349E = 0x80500010, POWERPC_SVR_8349EA = 0x80500030, -#if 0 - POWERPC_SVR_8358E = xxx, -#endif -#if 0 - POWERPC_SVR_8360E = xxx, -#endif #define POWERPC_SVR_E500 0x40000000 POWERPC_SVR_8377 = 0x80C70010 | POWERPC_SVR_E500, POWERPC_SVR_8377E = 0x80C60010 | POWERPC_SVR_E500, diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h index c9d3ffa89bcb9c59e27e5d847cb6be83709d7fed..64aef17f6fb7a0b7ecc753e8df36d8c2875630fc 100644 --- a/target/ppc/cpu.h +++ b/target/ppc/cpu.h @@ -1243,6 +1243,7 @@ struct PPCVirtualHypervisorClass { void (*store_hpte)(PPCVirtualHypervisor *vhyp, hwaddr ptex, uint64_t pte0, uint64_t pte1); uint64_t (*get_patbe)(PPCVirtualHypervisor *vhyp); + target_ulong (*encode_hpt_for_kvm_pr)(PPCVirtualHypervisor *vhyp); }; #define TYPE_PPC_VIRTUAL_HYPERVISOR "ppc-virtual-hypervisor" diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 1deaf106d2b98c5e218bf84e66c06846cb038815..171d3d8040db02051d21e889171d2da903eced19 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -131,7 +131,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_interrupt_level = kvm_check_extension(s, KVM_CAP_PPC_IRQ_LEVEL); cap_segstate = kvm_check_extension(s, KVM_CAP_PPC_SEGSTATE); cap_booke_sregs = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_SREGS); - cap_ppc_smt_possible = kvm_check_extension(s, KVM_CAP_PPC_SMT_POSSIBLE); + cap_ppc_smt_possible = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT_POSSIBLE); cap_ppc_rma = kvm_check_extension(s, KVM_CAP_PPC_RMA); cap_spapr_tce = kvm_check_extension(s, KVM_CAP_SPAPR_TCE); cap_spapr_tce_64 = kvm_check_extension(s, KVM_CAP_SPAPR_TCE_64); @@ -143,7 +143,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) cap_ppc_watchdog = kvm_check_extension(s, KVM_CAP_PPC_BOOKE_WATCHDOG); /* Note: we don't set cap_papr here, because this capability is * only activated after this by kvmppc_set_papr() */ - cap_htab_fd = kvm_check_extension(s, KVM_CAP_PPC_HTAB_FD); + cap_htab_fd = kvm_vm_check_extension(s, KVM_CAP_PPC_HTAB_FD); cap_fixup_hcalls = kvm_check_extension(s, KVM_CAP_PPC_FIXUP_HCALL); cap_ppc_smt = kvm_vm_check_extension(s, KVM_CAP_PPC_SMT); cap_htm = kvm_vm_check_extension(s, KVM_CAP_PPC_HTM); @@ -941,7 +941,13 @@ int kvmppc_put_books_sregs(PowerPCCPU *cpu) sregs.pvr = env->spr[SPR_PVR]; - sregs.u.s.sdr1 = env->spr[SPR_SDR1]; + if (cpu->vhyp) { + PPCVirtualHypervisorClass *vhc = + PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp); + sregs.u.s.sdr1 = vhc->encode_hpt_for_kvm_pr(cpu->vhyp); + } else { + sregs.u.s.sdr1 = env->spr[SPR_SDR1]; + } /* Sync SLB */ #ifdef TARGET_PPC64 @@ -2353,7 +2359,7 @@ int kvmppc_reset_htab(int shift_hint) /* Full emulation, tell caller to allocate htab itself */ return 0; } - if (kvm_check_extension(kvm_state, KVM_CAP_PPC_ALLOC_HTAB)) { + if (kvm_vm_check_extension(kvm_state, KVM_CAP_PPC_ALLOC_HTAB)) { int ret; ret = kvm_vm_ioctl(kvm_state, KVM_PPC_ALLOCATE_HTAB, &shift); if (ret == -ENOTTY) { @@ -2448,11 +2454,6 @@ bool kvmppc_has_cap_epr(void) return cap_epr; } -bool kvmppc_has_cap_htab_fd(void) -{ - return cap_htab_fd; -} - bool kvmppc_has_cap_fixup_hcalls(void) { return cap_fixup_hcalls; @@ -2555,19 +2556,29 @@ int kvmppc_define_rtas_kernel_token(uint32_t token, const char *function) return kvm_vm_ioctl(kvm_state, KVM_PPC_RTAS_DEFINE_TOKEN, &args); } -int kvmppc_get_htab_fd(bool write) +int kvmppc_get_htab_fd(bool write, uint64_t index, Error **errp) { struct kvm_get_htab_fd s = { .flags = write ? KVM_GET_HTAB_WRITE : 0, - .start_index = 0, + .start_index = index, }; + int ret; if (!cap_htab_fd) { - fprintf(stderr, "KVM version doesn't support saving the hash table\n"); - return -1; + error_setg(errp, "KVM version doesn't support %s the HPT", + write ? "writing" : "reading"); + return -ENOTSUP; } - return kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &s); + ret = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &s); + if (ret < 0) { + error_setg(errp, "Unable to open fd for %s HPT %s KVM: %s", + write ? "writing" : "reading", write ? "to" : "from", + strerror(errno)); + return -errno; + } + + return ret; } int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns) @@ -2647,17 +2658,10 @@ void kvm_arch_init_irq_routing(KVMState *s) void kvmppc_read_hptes(ppc_hash_pte64_t *hptes, hwaddr ptex, int n) { - struct kvm_get_htab_fd ghf = { - .flags = 0, - .start_index = ptex, - }; int fd, rc; int i; - fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf); - if (fd < 0) { - hw_error("kvmppc_read_hptes: Unable to open HPT fd"); - } + fd = kvmppc_get_htab_fd(false, ptex, &error_abort); i = 0; while (i < n) { @@ -2699,19 +2703,13 @@ void kvmppc_read_hptes(ppc_hash_pte64_t *hptes, hwaddr ptex, int n) void kvmppc_write_hpte(hwaddr ptex, uint64_t pte0, uint64_t pte1) { int fd, rc; - struct kvm_get_htab_fd ghf; struct { struct kvm_get_htab_header hdr; uint64_t pte0; uint64_t pte1; } buf; - ghf.flags = 0; - ghf.start_index = 0; /* Ignored */ - fd = kvm_vm_ioctl(kvm_state, KVM_PPC_GET_HTAB_FD, &ghf); - if (fd < 0) { - hw_error("kvmppc_write_hpte: Unable to open HPT fd"); - } + fd = kvmppc_get_htab_fd(true, 0 /* Ignored */, &error_abort); buf.hdr.n_valid = 1; buf.hdr.n_invalid = 0; @@ -2806,30 +2804,6 @@ int kvmppc_resize_hpt_commit(PowerPCCPU *cpu, target_ulong flags, int shift) return kvm_vm_ioctl(cs->kvm_state, KVM_PPC_RESIZE_HPT_COMMIT, &rhpt); } -static void kvmppc_pivot_hpt_cpu(CPUState *cs, run_on_cpu_data arg) -{ - target_ulong sdr1 = arg.target_ptr; - PowerPCCPU *cpu = POWERPC_CPU(cs); - CPUPPCState *env = &cpu->env; - - /* This is just for the benefit of PR KVM */ - cpu_synchronize_state(cs); - env->spr[SPR_SDR1] = sdr1; - if (kvmppc_put_books_sregs(cpu) < 0) { - error_report("Unable to update SDR1 in KVM"); - exit(1); - } -} - -void kvmppc_update_sdr1(target_ulong sdr1) -{ - CPUState *cs; - - CPU_FOREACH(cs) { - run_on_cpu(cs, kvmppc_pivot_hpt_cpu, RUN_ON_CPU_TARGET_PTR(sdr1)); - } -} - /* * This is a helper function to detect a post migration scenario * in which a guest, running as KVM-HV, freezes in cpu_post_load because diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index f780e6ec7b7265731374550a1ba3dc0f64ee27b2..d6be38ecafbddae8b4b7455add9d3ee366ae495d 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -51,8 +51,7 @@ uint64_t kvmppc_rma_size(uint64_t current_size, unsigned int hash_shift); #endif /* !CONFIG_USER_ONLY */ bool kvmppc_has_cap_epr(void); int kvmppc_define_rtas_kernel_token(uint32_t token, const char *function); -bool kvmppc_has_cap_htab_fd(void); -int kvmppc_get_htab_fd(bool write); +int kvmppc_get_htab_fd(bool write, uint64_t index, Error **errp); int kvmppc_save_htab(QEMUFile *f, int fd, size_t bufsize, int64_t max_ns); int kvmppc_load_htab_chunk(QEMUFile *f, int fd, uint32_t index, uint16_t n_valid, uint16_t n_invalid); @@ -68,7 +67,6 @@ PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); void kvmppc_check_papr_resize_hpt(Error **errp); int kvmppc_resize_hpt_prepare(PowerPCCPU *cpu, target_ulong flags, int shift); int kvmppc_resize_hpt_commit(PowerPCCPU *cpu, target_ulong flags, int shift); -void kvmppc_update_sdr1(target_ulong sdr1); bool kvmppc_pvr_workaround_required(PowerPCCPU *cpu); bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path); @@ -246,12 +244,7 @@ static inline int kvmppc_define_rtas_kernel_token(uint32_t token, return -1; } -static inline bool kvmppc_has_cap_htab_fd(void) -{ - return false; -} - -static inline int kvmppc_get_htab_fd(bool write) +static inline int kvmppc_get_htab_fd(bool write, uint64_t index, Error **errp) { return -1; } @@ -331,11 +324,6 @@ static inline int kvmppc_resize_hpt_commit(PowerPCCPU *cpu, return -ENOSYS; } -static inline void kvmppc_update_sdr1(target_ulong sdr1) -{ - abort(); -} - #endif #ifndef CONFIG_KVM diff --git a/target/ppc/translate_init.c b/target/ppc/translate_init.c index 466bf973478b4294f4f1a28b4c60d1684ad7a1a7..c6399a3a0d0d99558d5e8b42ffc0b6d6cee76f09 100644 --- a/target/ppc/translate_init.c +++ b/target/ppc/translate_init.c @@ -3833,6 +3833,44 @@ POWERPC_FAMILY(440EP)(ObjectClass *oc, void *data) POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; } +POWERPC_FAMILY(460EX)(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "PowerPC 460 EX"; + pcc->init_proc = init_proc_440EP; + pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | + PPC_FLOAT | PPC_FLOAT_FRES | PPC_FLOAT_FSEL | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_DCR | PPC_DCRX | PPC_WRTEE | PPC_RFMCI | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBZ | PPC_CACHE_DCBA | + PPC_MEM_TLBSYNC | PPC_MFTB | + PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC | + PPC_440_SPEC; + pcc->msr_mask = (1ull << MSR_POW) | + (1ull << MSR_CE) | + (1ull << MSR_EE) | + (1ull << MSR_PR) | + (1ull << MSR_FP) | + (1ull << MSR_ME) | + (1ull << MSR_FE0) | + (1ull << MSR_DWE) | + (1ull << MSR_DE) | + (1ull << MSR_FE1) | + (1ull << MSR_IR) | + (1ull << MSR_DR); + pcc->mmu_model = POWERPC_MMU_BOOKE; + pcc->excp_model = POWERPC_EXCP_BOOKE; + pcc->bus_model = PPC_FLAGS_INPUT_BookE; + pcc->bfd_mach = bfd_mach_ppc_403; + pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE | + POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK; +} + static void init_proc_440GP(CPUPPCState *env) { /* Time base */