diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2013-07-12 07:58:31 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2013-07-12 07:58:31 -0500 |
commit | 25ca6a1f5a3ee0a1ae670590877ed14f05e28fba (patch) | |
tree | 594b8455808884e8f28eee95570b9b0de0c54eb8 | |
parent | c170a23ca0097a95b44fc7cc604018cd3c3b7d44 (diff) | |
parent | f35ea98cd9f75db9286f05bf3dc4b532f4cb5eaa (diff) | |
download | qemu-25ca6a1f5a3ee0a1ae670590877ed14f05e28fba.zip qemu-25ca6a1f5a3ee0a1ae670590877ed14f05e28fba.tar.gz qemu-25ca6a1f5a3ee0a1ae670590877ed14f05e28fba.tar.bz2 |
Merge remote-tracking branch 'agraf/ppc-for-upstream' into staging
# By Alexander Graf (16) and others
# Via Alexander Graf
* agraf/ppc-for-upstream: (22 commits)
PPC: dbdma: Support more multi-issue DMA requests
PPC: Add timer handler for newworld mac-io
PPC: dbdma: Support unaligned DMA access
PPC: dbdma: Wait for DMA until we have data
PPC: dbdma: Move processing to io
PPC: dbdma: macio: Add DMA callback
PPC: dbdma: Move static bh variable to device struct
PPC: dbdma: Introduce kick function
PPC: dbdma: Move defines into header file
PPC: dbdma: Allow new commands in RUN state
PPC: dbdma: Fix debug print
PPC: Mac: Add debug prints in macio and dbdma code
PPC: dbdma: Replace tabs with spaces
PPC: Macio: Replace tabs with spaces
PPC: g3beige: Move secondary IDE bus to mac-io
PPC: Mac: Fix guest exported tbfreq values
target-ppc: Add POWER8 v1.0 CPU model
pseries: move interrupt controllers to hw/intc/
spapr: Respect -bios command line option for SLOF
spapr: Use named enum for function remove_hpte
...
Message-id: 1373562085-29728-1-git-send-email-agraf@suse.de
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
-rw-r--r-- | default-configs/ppc64-softmmu.mak | 2 | ||||
-rw-r--r-- | hw/ide/macio.c | 241 | ||||
-rw-r--r-- | hw/intc/Makefile.objs | 1 | ||||
-rw-r--r-- | hw/intc/xics.c (renamed from hw/ppc/xics.c) | 0 | ||||
-rw-r--r-- | hw/misc/macio/mac_dbdma.c | 193 | ||||
-rw-r--r-- | hw/misc/macio/macio.c | 126 | ||||
-rw-r--r-- | hw/ppc/Makefile.objs | 2 | ||||
-rw-r--r-- | hw/ppc/mac.h | 3 | ||||
-rw-r--r-- | hw/ppc/mac_newworld.c | 5 | ||||
-rw-r--r-- | hw/ppc/mac_oldworld.c | 22 | ||||
-rw-r--r-- | hw/ppc/spapr.c | 5 | ||||
-rw-r--r-- | hw/ppc/spapr_hcall.c | 10 | ||||
-rw-r--r-- | hw/ppc/spapr_pci.c | 4 | ||||
-rw-r--r-- | include/hw/ppc/mac_dbdma.h | 124 | ||||
-rw-r--r-- | target-ppc/cpu-models.c | 13 | ||||
-rw-r--r-- | target-ppc/cpu-models.h | 5 | ||||
-rw-r--r-- | target-ppc/translate_init.c | 159 |
17 files changed, 688 insertions, 227 deletions
diff --git a/default-configs/ppc64-softmmu.mak b/default-configs/ppc64-softmmu.mak index 5a72b5f..6d1933b 100644 --- a/default-configs/ppc64-softmmu.mak +++ b/default-configs/ppc64-softmmu.mak @@ -45,5 +45,7 @@ CONFIG_OPENPIC=y CONFIG_PSERIES=y CONFIG_E500=y CONFIG_OPENPIC_KVM=$(and $(CONFIG_E500),$(CONFIG_KVM)) +# For pSeries +CONFIG_XICS=$(CONFIG_PSERIES) # For PReP CONFIG_MC146818RTC=y diff --git a/hw/ide/macio.c b/hw/ide/macio.c index 4798202..38ad924 100644 --- a/hw/ide/macio.c +++ b/hw/ide/macio.c @@ -30,6 +30,22 @@ #include <hw/ide/internal.h> +/* debug MACIO */ +// #define DEBUG_MACIO + +#ifdef DEBUG_MACIO +static const int debug_macio = 1; +#else +static const int debug_macio = 0; +#endif + +#define MACIO_DPRINTF(fmt, ...) do { \ + if (debug_macio) { \ + printf(fmt , ## __VA_ARGS__); \ + } \ + } while (0) + + /***********************************************************/ /* MacIO based PowerPC IDE */ @@ -40,14 +56,26 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) DBDMA_io *io = opaque; MACIOIDEState *m = io->opaque; IDEState *s = idebus_active_if(&m->bus); + int unaligned; if (ret < 0) { m->aiocb = NULL; qemu_sglist_destroy(&s->sg); ide_atapi_io_error(s, ret); + io->remainder_len = 0; goto done; } + if (!m->dma_active) { + MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n", + s->nsector, io->len, s->status); + /* data not ready yet, wait for the channel to get restarted */ + io->processing = false; + return; + } + + MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size); + if (s->io_buffer_size > 0) { m->aiocb = NULL; qemu_sglist_destroy(&s->sg); @@ -55,33 +83,94 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) s->packet_transfer_size -= s->io_buffer_size; s->io_buffer_index += s->io_buffer_size; - s->lba += s->io_buffer_index >> 11; + s->lba += s->io_buffer_index >> 11; s->io_buffer_index &= 0x7ff; } - if (s->packet_transfer_size <= 0) + s->io_buffer_size = MIN(io->len, s->packet_transfer_size); + + MACIO_DPRINTF("remainder: %d io->len: %d size: %d\n", io->remainder_len, + io->len, s->packet_transfer_size); + if (io->remainder_len && io->len) { + /* guest wants the rest of its previous transfer */ + int remainder_len = MIN(io->remainder_len, io->len); + + MACIO_DPRINTF("copying remainder %d bytes\n", remainder_len); + + cpu_physical_memory_write(io->addr, io->remainder + 0x200 - + remainder_len, remainder_len); + + io->addr += remainder_len; + io->len -= remainder_len; + s->io_buffer_size = remainder_len; + io->remainder_len -= remainder_len; + /* treat remainder as individual transfer, start again */ + qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1, + &address_space_memory); + pmac_ide_atapi_transfer_cb(opaque, 0); + return; + } + + if (!s->packet_transfer_size) { + MACIO_DPRINTF("end of transfer\n"); ide_atapi_cmd_ok(s); + m->dma_active = false; + } if (io->len == 0) { + MACIO_DPRINTF("end of DMA\n"); goto done; } /* launch next transfer */ - s->io_buffer_size = io->len; + /* handle unaligned accesses first, get them over with and only do the + remaining bulk transfer using our async DMA helpers */ + unaligned = io->len & 0x1ff; + if (unaligned) { + int sector_num = (s->lba << 2) + (s->io_buffer_index >> 9); + int nsector = io->len >> 9; + + MACIO_DPRINTF("precopying unaligned %d bytes to %#lx\n", + unaligned, io->addr + io->len - unaligned); + + bdrv_read(s->bs, sector_num + nsector, io->remainder, 1); + cpu_physical_memory_write(io->addr + io->len - unaligned, + io->remainder, unaligned); + + io->len -= unaligned; + } + + MACIO_DPRINTF("io->len = %#x\n", io->len); qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1, &address_space_memory); qemu_sglist_add(&s->sg, io->addr, io->len); - io->addr += io->len; + io->addr += s->io_buffer_size; + io->remainder_len = MIN(s->packet_transfer_size - s->io_buffer_size, + (0x200 - unaligned) & 0x1ff); + MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len); + + /* We would read no data from the block layer, thus not get a callback. + Just fake completion manually. */ + if (!io->len) { + pmac_ide_atapi_transfer_cb(opaque, 0); + return; + } + io->len = 0; + MACIO_DPRINTF("sector_num=%d size=%d, cmd_cmd=%d\n", + (s->lba << 2) + (s->io_buffer_index >> 9), + s->packet_transfer_size, s->dma_cmd); + m->aiocb = dma_bdrv_read(s->bs, &s->sg, (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9), pmac_ide_atapi_transfer_cb, io); return; done: + MACIO_DPRINTF("done DMA\n"); bdrv_acct_done(s->bs, &s->acct); io->dma_end(opaque); } @@ -91,17 +180,29 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) DBDMA_io *io = opaque; MACIOIDEState *m = io->opaque; IDEState *s = idebus_active_if(&m->bus); - int n; + int n = 0; int64_t sector_num; + int unaligned; if (ret < 0) { + MACIO_DPRINTF("DMA error\n"); m->aiocb = NULL; qemu_sglist_destroy(&s->sg); - ide_dma_error(s); + ide_dma_error(s); + io->remainder_len = 0; goto done; } + if (!m->dma_active) { + MACIO_DPRINTF("waiting for data (%#x - %#x - %x)\n", + s->nsector, io->len, s->status); + /* data not ready yet, wait for the channel to get restarted */ + io->processing = false; + return; + } + sector_num = ide_get_sector(s); + MACIO_DPRINTF("io_buffer_size = %#x\n", s->io_buffer_size); if (s->io_buffer_size > 0) { m->aiocb = NULL; qemu_sglist_destroy(&s->sg); @@ -111,36 +212,105 @@ static void pmac_ide_transfer_cb(void *opaque, int ret) s->nsector -= n; } - /* end of transfer ? */ - if (s->nsector == 0) { + MACIO_DPRINTF("remainder: %d io->len: %d nsector: %d sector_num: %ld\n", + io->remainder_len, io->len, s->nsector, sector_num); + if (io->remainder_len && io->len) { + /* guest wants the rest of its previous transfer */ + int remainder_len = MIN(io->remainder_len, io->len); + uint8_t *p = &io->remainder[0x200 - remainder_len]; + + MACIO_DPRINTF("copying remainder %d bytes at %#lx\n", + remainder_len, io->addr); + + switch (s->dma_cmd) { + case IDE_DMA_READ: + cpu_physical_memory_write(io->addr, p, remainder_len); + break; + case IDE_DMA_WRITE: + cpu_physical_memory_read(io->addr, p, remainder_len); + bdrv_write(s->bs, sector_num - 1, io->remainder, 1); + break; + case IDE_DMA_TRIM: + break; + } + io->addr += remainder_len; + io->len -= remainder_len; + io->remainder_len -= remainder_len; + } + + if (s->nsector == 0 && !io->remainder_len) { + MACIO_DPRINTF("end of transfer\n"); s->status = READY_STAT | SEEK_STAT; ide_set_irq(s->bus); + m->dma_active = false; } - /* end of DMA ? */ if (io->len == 0) { + MACIO_DPRINTF("end of DMA\n"); goto done; } /* launch next transfer */ s->io_buffer_index = 0; - s->io_buffer_size = io->len; + s->io_buffer_size = MIN(io->len, s->nsector * 512); + + /* handle unaligned accesses first, get them over with and only do the + remaining bulk transfer using our async DMA helpers */ + unaligned = io->len & 0x1ff; + if (unaligned) { + int nsector = io->len >> 9; + + MACIO_DPRINTF("precopying unaligned %d bytes to %#lx\n", + unaligned, io->addr + io->len - unaligned); + + switch (s->dma_cmd) { + case IDE_DMA_READ: + bdrv_read(s->bs, sector_num + nsector, io->remainder, 1); + cpu_physical_memory_write(io->addr + io->len - unaligned, + io->remainder, unaligned); + break; + case IDE_DMA_WRITE: + /* cache the contents in our io struct */ + cpu_physical_memory_read(io->addr + io->len - unaligned, + io->remainder, unaligned); + break; + case IDE_DMA_TRIM: + break; + } + + io->len -= unaligned; + } + + MACIO_DPRINTF("io->len = %#x\n", io->len); qemu_sglist_init(&s->sg, DEVICE(m), io->len / MACIO_PAGE_SIZE + 1, &address_space_memory); qemu_sglist_add(&s->sg, io->addr, io->len); - io->addr += io->len; + io->addr += io->len + unaligned; + io->remainder_len = (0x200 - unaligned) & 0x1ff; + MACIO_DPRINTF("set remainder to: %d\n", io->remainder_len); + + /* We would read no data from the block layer, thus not get a callback. + Just fake completion manually. */ + if (!io->len) { + pmac_ide_transfer_cb(opaque, 0); + return; + } + io->len = 0; + MACIO_DPRINTF("sector_num=%" PRId64 " n=%d, nsector=%d, cmd_cmd=%d\n", + sector_num, n, s->nsector, s->dma_cmd); + switch (s->dma_cmd) { case IDE_DMA_READ: m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num, - pmac_ide_transfer_cb, io); + pmac_ide_transfer_cb, io); break; case IDE_DMA_WRITE: m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num, - pmac_ide_transfer_cb, io); + pmac_ide_transfer_cb, io); break; case IDE_DMA_TRIM: m->aiocb = dma_bdrv_io(s->bs, &s->sg, sector_num, @@ -162,6 +332,8 @@ static void pmac_ide_transfer(DBDMA_io *io) MACIOIDEState *m = io->opaque; IDEState *s = idebus_active_if(&m->bus); + MACIO_DPRINTF("\n"); + s->io_buffer_size = 0; if (s->drive_kind == IDE_CD) { bdrv_acct_start(s->bs, &s->acct, io->len, BDRV_ACCT_READ); @@ -322,11 +494,51 @@ static void macio_ide_reset(DeviceState *dev) ide_bus_reset(&d->bus); } +static int ide_nop(IDEDMA *dma) +{ + return 0; +} + +static int ide_nop_int(IDEDMA *dma, int x) +{ + return 0; +} + +static void ide_nop_restart(void *opaque, int x, RunState y) +{ +} + +static void ide_dbdma_start(IDEDMA *dma, IDEState *s, + BlockDriverCompletionFunc *cb) +{ + MACIOIDEState *m = container_of(dma, MACIOIDEState, dma); + + MACIO_DPRINTF("\n"); + m->dma_active = true; + DBDMA_kick(m->dbdma); +} + +static const IDEDMAOps dbdma_ops = { + .start_dma = ide_dbdma_start, + .start_transfer = ide_nop, + .prepare_buf = ide_nop_int, + .rw_buf = ide_nop_int, + .set_unit = ide_nop_int, + .add_status = ide_nop_int, + .set_inactive = ide_nop, + .restart_cb = ide_nop_restart, + .reset = ide_nop, +}; + static void macio_ide_realizefn(DeviceState *dev, Error **errp) { MACIOIDEState *s = MACIO_IDE(dev); ide_init2(&s->bus, s->irq); + + /* Register DMA callbacks */ + s->dma.ops = &dbdma_ops; + s->bus.dma = &s->dma; } static void macio_ide_initfn(Object *obj) @@ -363,7 +575,7 @@ static void macio_ide_register_types(void) type_register_static(&macio_ide_type_info); } -/* hd_table must contain 4 block drivers */ +/* hd_table must contain 2 block drivers */ void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table) { int i; @@ -377,6 +589,7 @@ void macio_ide_init_drives(MACIOIDEState *s, DriveInfo **hd_table) void macio_ide_register_dma(MACIOIDEState *s, void *dbdma, int channel) { + s->dbdma = dbdma; DBDMA_register_channel(dbdma, channel, s->dma_irq, pmac_ide_transfer, pmac_ide_flush, s); } diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs index 86f9d5b..2851eed 100644 --- a/hw/intc/Makefile.objs +++ b/hw/intc/Makefile.objs @@ -22,3 +22,4 @@ obj-$(CONFIG_IOAPIC) += ioapic.o obj-$(CONFIG_OMAP) += omap_intc.o obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o obj-$(CONFIG_SH4) += sh_intc.o +obj-$(CONFIG_XICS) += xics.o diff --git a/hw/ppc/xics.c b/hw/intc/xics.c index 091912e..091912e 100644 --- a/hw/ppc/xics.c +++ b/hw/intc/xics.c diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c index a1d7862..f47a736 100644 --- a/hw/misc/macio/mac_dbdma.c +++ b/hw/misc/macio/mac_dbdma.c @@ -54,122 +54,10 @@ /* */ -/* - * DBDMA control/status registers. All little-endian. - */ - -#define DBDMA_CONTROL 0x00 -#define DBDMA_STATUS 0x01 -#define DBDMA_CMDPTR_HI 0x02 -#define DBDMA_CMDPTR_LO 0x03 -#define DBDMA_INTR_SEL 0x04 -#define DBDMA_BRANCH_SEL 0x05 -#define DBDMA_WAIT_SEL 0x06 -#define DBDMA_XFER_MODE 0x07 -#define DBDMA_DATA2PTR_HI 0x08 -#define DBDMA_DATA2PTR_LO 0x09 -#define DBDMA_RES1 0x0A -#define DBDMA_ADDRESS_HI 0x0B -#define DBDMA_BRANCH_ADDR_HI 0x0C -#define DBDMA_RES2 0x0D -#define DBDMA_RES3 0x0E -#define DBDMA_RES4 0x0F - -#define DBDMA_REGS 16 -#define DBDMA_SIZE (DBDMA_REGS * sizeof(uint32_t)) - -#define DBDMA_CHANNEL_SHIFT 7 -#define DBDMA_CHANNEL_SIZE (1 << DBDMA_CHANNEL_SHIFT) - -#define DBDMA_CHANNELS (0x1000 >> DBDMA_CHANNEL_SHIFT) - -/* Bits in control and status registers */ - -#define RUN 0x8000 -#define PAUSE 0x4000 -#define FLUSH 0x2000 -#define WAKE 0x1000 -#define DEAD 0x0800 -#define ACTIVE 0x0400 -#define BT 0x0100 -#define DEVSTAT 0x00ff - -/* - * DBDMA command structure. These fields are all little-endian! - */ - -typedef struct dbdma_cmd { - uint16_t req_count; /* requested byte transfer count */ - uint16_t command; /* command word (has bit-fields) */ - uint32_t phy_addr; /* physical data address */ - uint32_t cmd_dep; /* command-dependent field */ - uint16_t res_count; /* residual count after completion */ - uint16_t xfer_status; /* transfer status */ -} dbdma_cmd; - -/* DBDMA command values in command field */ - -#define COMMAND_MASK 0xf000 -#define OUTPUT_MORE 0x0000 /* transfer memory data to stream */ -#define OUTPUT_LAST 0x1000 /* ditto followed by end marker */ -#define INPUT_MORE 0x2000 /* transfer stream data to memory */ -#define INPUT_LAST 0x3000 /* ditto, expect end marker */ -#define STORE_WORD 0x4000 /* write word (4 bytes) to device reg */ -#define LOAD_WORD 0x5000 /* read word (4 bytes) from device reg */ -#define DBDMA_NOP 0x6000 /* do nothing */ -#define DBDMA_STOP 0x7000 /* suspend processing */ - -/* Key values in command field */ - -#define KEY_MASK 0x0700 -#define KEY_STREAM0 0x0000 /* usual data stream */ -#define KEY_STREAM1 0x0100 /* control/status stream */ -#define KEY_STREAM2 0x0200 /* device-dependent stream */ -#define KEY_STREAM3 0x0300 /* device-dependent stream */ -#define KEY_STREAM4 0x0400 /* reserved */ -#define KEY_REGS 0x0500 /* device register space */ -#define KEY_SYSTEM 0x0600 /* system memory-mapped space */ -#define KEY_DEVICE 0x0700 /* device memory-mapped space */ - -/* Interrupt control values in command field */ - -#define INTR_MASK 0x0030 -#define INTR_NEVER 0x0000 /* don't interrupt */ -#define INTR_IFSET 0x0010 /* intr if condition bit is 1 */ -#define INTR_IFCLR 0x0020 /* intr if condition bit is 0 */ -#define INTR_ALWAYS 0x0030 /* always interrupt */ - -/* Branch control values in command field */ - -#define BR_MASK 0x000c -#define BR_NEVER 0x0000 /* don't branch */ -#define BR_IFSET 0x0004 /* branch if condition bit is 1 */ -#define BR_IFCLR 0x0008 /* branch if condition bit is 0 */ -#define BR_ALWAYS 0x000c /* always branch */ - -/* Wait control values in command field */ - -#define WAIT_MASK 0x0003 -#define WAIT_NEVER 0x0000 /* don't wait */ -#define WAIT_IFSET 0x0001 /* wait if condition bit is 1 */ -#define WAIT_IFCLR 0x0002 /* wait if condition bit is 0 */ -#define WAIT_ALWAYS 0x0003 /* always wait */ - -typedef struct DBDMA_channel { - int channel; - uint32_t regs[DBDMA_REGS]; - qemu_irq irq; - DBDMA_io io; - DBDMA_rw rw; - DBDMA_flush flush; - dbdma_cmd current; - int processing; -} DBDMA_channel; - -typedef struct { - MemoryRegion mem; - DBDMA_channel channels[DBDMA_CHANNELS]; -} DBDMAState; +static DBDMAState *dbdma_from_ch(DBDMA_channel *ch) +{ + return container_of(ch, DBDMAState, channels[ch->channel]); +} #ifdef DEBUG_DBDMA static void dump_dbdma_cmd(dbdma_cmd *cmd) @@ -224,7 +112,7 @@ static void conditional_interrupt(DBDMA_channel *ch) uint32_t status; int cond; - DBDMA_DPRINTF("conditional_interrupt\n"); + DBDMA_DPRINTF("%s\n", __func__); intr = le16_to_cpu(current->command) & INTR_MASK; @@ -233,6 +121,7 @@ static void conditional_interrupt(DBDMA_channel *ch) return; case INTR_ALWAYS: /* always interrupt */ qemu_irq_raise(ch->irq); + DBDMA_DPRINTF("%s: raise\n", __func__); return; } @@ -245,12 +134,16 @@ static void conditional_interrupt(DBDMA_channel *ch) switch(intr) { case INTR_IFSET: /* intr if condition bit is 1 */ - if (cond) + if (cond) { qemu_irq_raise(ch->irq); + DBDMA_DPRINTF("%s: raise\n", __func__); + } return; case INTR_IFCLR: /* intr if condition bit is 0 */ - if (!cond) + if (!cond) { qemu_irq_raise(ch->irq); + DBDMA_DPRINTF("%s: raise\n", __func__); + } return; } } @@ -360,7 +253,6 @@ static void conditional_branch(DBDMA_channel *ch) } } -static QEMUBH *dbdma_bh; static void channel_run(DBDMA_channel *ch); static void dbdma_end(DBDMA_io *io) @@ -368,6 +260,8 @@ static void dbdma_end(DBDMA_io *io) DBDMA_channel *ch = io->channel; dbdma_cmd *current = &ch->current; + DBDMA_DPRINTF("%s\n", __func__); + if (conditional_wait(ch)) goto wait; @@ -381,7 +275,9 @@ static void dbdma_end(DBDMA_io *io) conditional_branch(ch); wait: - ch->processing = 0; + /* Indicate that we're ready for a new DMA round */ + ch->io.processing = false; + if ((ch->regs[DBDMA_STATUS] & RUN) && (ch->regs[DBDMA_STATUS] & ACTIVE)) channel_run(ch); @@ -407,7 +303,7 @@ static void start_output(DBDMA_channel *ch, int key, uint32_t addr, ch->io.is_last = is_last; ch->io.dma_end = dbdma_end; ch->io.is_dma_out = 1; - ch->processing = 1; + ch->io.processing = true; if (ch->rw) { ch->rw(&ch->io); } @@ -422,6 +318,7 @@ static void start_input(DBDMA_channel *ch, int key, uint32_t addr, * are not implemented in the mac-io chip */ + DBDMA_DPRINTF("addr 0x%x key 0x%x\n", addr, key); if (!addr || key > KEY_STREAM3) { kill_channel(ch); return; @@ -432,7 +329,7 @@ static void start_input(DBDMA_channel *ch, int key, uint32_t addr, ch->io.is_last = is_last; ch->io.dma_end = dbdma_end; ch->io.is_dma_out = 0; - ch->processing = 1; + ch->io.processing = true; if (ch->rw) { ch->rw(&ch->io); } @@ -474,7 +371,7 @@ static void load_word(DBDMA_channel *ch, int key, uint32_t addr, next(ch); wait: - qemu_bh_schedule(dbdma_bh); + DBDMA_kick(dbdma_from_ch(ch)); } static void store_word(DBDMA_channel *ch, int key, uint32_t addr, @@ -512,7 +409,7 @@ static void store_word(DBDMA_channel *ch, int key, uint32_t addr, next(ch); wait: - qemu_bh_schedule(dbdma_bh); + DBDMA_kick(dbdma_from_ch(ch)); } static void nop(DBDMA_channel *ch) @@ -529,7 +426,7 @@ static void nop(DBDMA_channel *ch) conditional_branch(ch); wait: - qemu_bh_schedule(dbdma_bh); + DBDMA_kick(dbdma_from_ch(ch)); } static void stop(DBDMA_channel *ch) @@ -558,11 +455,11 @@ static void channel_run(DBDMA_channel *ch) switch (cmd) { case DBDMA_NOP: nop(ch); - return; + return; case DBDMA_STOP: stop(ch); - return; + return; } key = le16_to_cpu(current->command) & 0x0700; @@ -578,19 +475,19 @@ static void channel_run(DBDMA_channel *ch) switch (cmd) { case OUTPUT_MORE: start_output(ch, key, phy_addr, req_count, 0); - return; + return; case OUTPUT_LAST: start_output(ch, key, phy_addr, req_count, 1); - return; + return; case INPUT_MORE: start_input(ch, key, phy_addr, req_count, 0); - return; + return; case INPUT_LAST: start_input(ch, key, phy_addr, req_count, 1); - return; + return; } if (key < KEY_REGS) { @@ -615,11 +512,11 @@ static void channel_run(DBDMA_channel *ch) switch (cmd) { case LOAD_WORD: load_word(ch, key, phy_addr, req_count); - return; + return; case STORE_WORD: store_word(ch, key, phy_addr, req_count); - return; + return; } } @@ -630,7 +527,7 @@ static void DBDMA_run(DBDMAState *s) for (channel = 0; channel < DBDMA_CHANNELS; channel++) { DBDMA_channel *ch = &s->channels[channel]; uint32_t status = ch->regs[DBDMA_STATUS]; - if (!ch->processing && (status & RUN) && (status & ACTIVE)) { + if (!ch->io.processing && (status & RUN) && (status & ACTIVE)) { channel_run(ch); } } @@ -645,6 +542,11 @@ static void DBDMA_run_bh(void *opaque) DBDMA_run(s); } +void DBDMA_kick(DBDMAState *dbdma) +{ + qemu_bh_schedule(dbdma->bh); +} + void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, DBDMA_rw rw, DBDMA_flush flush, void *opaque) @@ -698,10 +600,12 @@ dbdma_control_write(DBDMA_channel *ch) ch->regs[DBDMA_STATUS] = status; - if (status & ACTIVE) - qemu_bh_schedule(dbdma_bh); - if ((status & FLUSH) && ch->flush) + if (status & ACTIVE) { + DBDMA_kick(dbdma_from_ch(ch)); + } + if ((status & FLUSH) && ch->flush) { ch->flush(&ch->io); + } } static void dbdma_write(void *opaque, hwaddr addr, @@ -712,15 +616,16 @@ static void dbdma_write(void *opaque, hwaddr addr, DBDMA_channel *ch = &s->channels[channel]; int reg = (addr - (channel << DBDMA_CHANNEL_SHIFT)) >> 2; - DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08x\n", addr, value); + DBDMA_DPRINTF("writel 0x" TARGET_FMT_plx " <= 0x%08"PRIx64"\n", + addr, value); DBDMA_DPRINTF("channel 0x%x reg 0x%x\n", (uint32_t)addr >> DBDMA_CHANNEL_SHIFT, reg); - /* cmdptr cannot be modified if channel is RUN or ACTIVE */ + /* cmdptr cannot be modified if channel is ACTIVE */ - if (reg == DBDMA_CMDPTR_LO && - (ch->regs[DBDMA_STATUS] & (RUN | ACTIVE))) - return; + if (reg == DBDMA_CMDPTR_LO && (ch->regs[DBDMA_STATUS] & ACTIVE)) { + return; + } ch->regs[reg] = value; @@ -853,7 +758,7 @@ void* DBDMA_init (MemoryRegion **dbdma_mem) vmstate_register(NULL, -1, &vmstate_dbdma, s); qemu_register_reset(dbdma_reset, s); - dbdma_bh = qemu_bh_new(DBDMA_run_bh, s); + s->bh = qemu_bh_new(DBDMA_run_bh, s); return s; } diff --git a/hw/misc/macio/macio.c b/hw/misc/macio/macio.c index 76a1cfb..c0d0bf7 100644 --- a/hw/misc/macio/macio.c +++ b/hw/misc/macio/macio.c @@ -52,10 +52,10 @@ typedef struct OldWorldMacIOState { MacIOState parent_obj; /*< public >*/ - qemu_irq irqs[3]; + qemu_irq irqs[5]; MacIONVRAMState nvram; - MACIOIDEState ide; + MACIOIDEState ide[2]; } OldWorldMacIOState; #define NEWWORLD_MACIO(obj) \ @@ -147,18 +147,32 @@ static int macio_common_initfn(PCIDevice *d) return 0; } +static int macio_initfn_ide(MacIOState *s, MACIOIDEState *ide, qemu_irq irq0, + qemu_irq irq1, int dmaid) +{ + SysBusDevice *sysbus_dev; + + 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); + return qdev_init(DEVICE(ide)); +} + static int macio_oldworld_initfn(PCIDevice *d) { MacIOState *s = MACIO(d); OldWorldMacIOState *os = OLDWORLD_MACIO(d); SysBusDevice *sysbus_dev; + int i; + int cur_irq = 0; int ret = macio_common_initfn(d); if (ret < 0) { return ret; } sysbus_dev = SYS_BUS_DEVICE(&s->cuda); - sysbus_connect_irq(sysbus_dev, 0, os->irqs[0]); + sysbus_connect_irq(sysbus_dev, 0, os->irqs[cur_irq++]); ret = qdev_init(DEVICE(&os->nvram)); if (ret < 0) { @@ -174,23 +188,39 @@ static int macio_oldworld_initfn(PCIDevice *d) memory_region_add_subregion(&s->bar, 0x00000, s->pic_mem); } - sysbus_dev = SYS_BUS_DEVICE(&os->ide); - sysbus_connect_irq(sysbus_dev, 0, os->irqs[1]); - sysbus_connect_irq(sysbus_dev, 1, os->irqs[2]); - macio_ide_register_dma(&os->ide, s->dbdma, 0x16); - ret = qdev_init(DEVICE(&os->ide)); - if (ret < 0) { - return ret; + /* IDE buses */ + for (i = 0; i < ARRAY_SIZE(os->ide); i++) { + qemu_irq irq0 = os->irqs[cur_irq++]; + qemu_irq irq1 = os->irqs[cur_irq++]; + + ret = macio_initfn_ide(s, &os->ide[i], irq0, irq1, 0x16 + (i * 4)); + if (ret < 0) { + return ret; + } } return 0; } +static void macio_init_ide(MacIOState *s, MACIOIDEState *ide, int index) +{ + gchar *name; + + object_initialize(ide, TYPE_MACIO_IDE); + qdev_set_parent_bus(DEVICE(ide), sysbus_get_default()); + memory_region_add_subregion(&s->bar, 0x1f000 + ((index + 1) * 0x1000), + &ide->mem); + name = g_strdup_printf("ide[%i]", index); + object_property_add_child(OBJECT(s), name, OBJECT(ide), NULL); + g_free(name); +} + static void macio_oldworld_init(Object *obj) { MacIOState *s = MACIO(obj); OldWorldMacIOState *os = OLDWORLD_MACIO(obj); DeviceState *dev; + int i; qdev_init_gpio_out(DEVICE(obj), os->irqs, ARRAY_SIZE(os->irqs)); @@ -199,48 +229,75 @@ static void macio_oldworld_init(Object *obj) qdev_prop_set_uint32(dev, "size", 0x2000); qdev_prop_set_uint32(dev, "it_shift", 4); - object_initialize(&os->ide, TYPE_MACIO_IDE); - qdev_set_parent_bus(DEVICE(&os->ide), sysbus_get_default()); - memory_region_add_subregion(&s->bar, 0x1f000 + (1 * 0x1000), &os->ide.mem); - object_property_add_child(obj, "ide", OBJECT(&os->ide), NULL); + for (i = 0; i < 2; i++) { + macio_init_ide(s, &os->ide[i], i); + } } +static void timer_write(void *opaque, hwaddr addr, uint64_t value, + unsigned size) +{ +} + +static uint64_t timer_read(void *opaque, hwaddr addr, unsigned size) +{ + uint32_t value = 0; + + switch (addr) { + case 0x38: + value = qemu_get_clock_ns(vm_clock); + break; + case 0x3c: + value = qemu_get_clock_ns(vm_clock) >> 32; + break; + } + + return value; +} + +static const MemoryRegionOps timer_ops = { + .read = timer_read, + .write = timer_write, + .endianness = DEVICE_NATIVE_ENDIAN, +}; + static int macio_newworld_initfn(PCIDevice *d) { MacIOState *s = MACIO(d); NewWorldMacIOState *ns = NEWWORLD_MACIO(d); SysBusDevice *sysbus_dev; + MemoryRegion *timer_memory = g_new(MemoryRegion, 1); + int i; + int cur_irq = 0; int ret = macio_common_initfn(d); if (ret < 0) { return ret; } sysbus_dev = SYS_BUS_DEVICE(&s->cuda); - sysbus_connect_irq(sysbus_dev, 0, ns->irqs[0]); + sysbus_connect_irq(sysbus_dev, 0, ns->irqs[cur_irq++]); if (s->pic_mem) { /* OpenPIC */ memory_region_add_subregion(&s->bar, 0x40000, s->pic_mem); } - sysbus_dev = SYS_BUS_DEVICE(&ns->ide[0]); - sysbus_connect_irq(sysbus_dev, 0, ns->irqs[1]); - sysbus_connect_irq(sysbus_dev, 1, ns->irqs[2]); - macio_ide_register_dma(&ns->ide[0], s->dbdma, 0x16); - ret = qdev_init(DEVICE(&ns->ide[0])); - if (ret < 0) { - return ret; - } + /* IDE buses */ + for (i = 0; i < ARRAY_SIZE(ns->ide); i++) { + qemu_irq irq0 = ns->irqs[cur_irq++]; + qemu_irq irq1 = ns->irqs[cur_irq++]; - sysbus_dev = SYS_BUS_DEVICE(&ns->ide[1]); - sysbus_connect_irq(sysbus_dev, 0, ns->irqs[3]); - sysbus_connect_irq(sysbus_dev, 1, ns->irqs[4]); - macio_ide_register_dma(&ns->ide[1], s->dbdma, 0x1a); - ret = qdev_init(DEVICE(&ns->ide[1])); - if (ret < 0) { - return ret; + ret = macio_initfn_ide(s, &ns->ide[i], irq0, irq1, 0x16 + (i * 4)); + if (ret < 0) { + return ret; + } } + /* Timer */ + memory_region_init_io(timer_memory, OBJECT(s), &timer_ops, NULL, "timer", + 0x1000); + memory_region_add_subregion(&s->bar, 0x15000, timer_memory); + return 0; } @@ -249,18 +306,11 @@ static void macio_newworld_init(Object *obj) MacIOState *s = MACIO(obj); NewWorldMacIOState *ns = NEWWORLD_MACIO(obj); int i; - gchar *name; qdev_init_gpio_out(DEVICE(obj), ns->irqs, ARRAY_SIZE(ns->irqs)); for (i = 0; i < 2; i++) { - object_initialize(&ns->ide[i], TYPE_MACIO_IDE); - qdev_set_parent_bus(DEVICE(&ns->ide[i]), sysbus_get_default()); - memory_region_add_subregion(&s->bar, 0x1f000 + ((i + 1) * 0x1000), - &ns->ide[i].mem); - name = g_strdup_printf("ide[%i]", i); - object_property_add_child(obj, name, OBJECT(&ns->ide[i]), NULL); - g_free(name); + macio_init_ide(s, &ns->ide[i], i); } } diff --git a/hw/ppc/Makefile.objs b/hw/ppc/Makefile.objs index be00d1d..7a1cd5d 100644 --- a/hw/ppc/Makefile.objs +++ b/hw/ppc/Makefile.objs @@ -1,7 +1,7 @@ # shared objects obj-y += ppc.o ppc_booke.o # IBM pSeries (sPAPR) -obj-$(CONFIG_PSERIES) += spapr.o xics.o spapr_vio.o spapr_events.o +obj-$(CONFIG_PSERIES) += spapr.o spapr_vio.o spapr_events.o obj-$(CONFIG_PSERIES) += spapr_hcall.o spapr_iommu.o spapr_rtas.o obj-$(CONFIG_PSERIES) += spapr_pci.o # PowerPC 4xx boards diff --git a/hw/ppc/mac.h b/hw/ppc/mac.h index 54efaed..1e578dd 100644 --- a/hw/ppc/mac.h +++ b/hw/ppc/mac.h @@ -131,6 +131,9 @@ typedef struct MACIOIDEState { MemoryRegion mem; IDEBus bus; BlockDriverAIOCB *aiocb; + IDEDMA dma; + void *dbdma; + bool dma_active; } MACIOIDEState; void macio_ide_init_drives(MACIOIDEState *ide, DriveInfo **hd_table); diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 77a8c2e..fe80348 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -71,6 +71,7 @@ #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 +#define TBFREQ (100UL * 1000UL * 1000UL) /* debug UniNorth */ //#define DEBUG_UNIN @@ -191,7 +192,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) env = &cpu->env; /* Set time-base frequency to 100 Mhz */ - cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL); + cpu_ppc_tb_init(env, TBFREQ); qemu_register_reset(ppc_core99_reset, cpu); } @@ -460,7 +461,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args) fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid()); #endif } else { - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec()); + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, TBFREQ); } /* Mac OS X requires a "known good" clock-frequency value; pass it one. */ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, 266000000); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 4663ed2..8b8c6b9 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -45,6 +45,7 @@ #define MAX_IDE_BUS 2 #define CFG_ADDR 0xf0000510 +#define TBFREQ 16600000UL static int fw_cfg_boot_set(void *opaque, const char *boot_device) { @@ -114,7 +115,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) env = &cpu->env; /* Set time-base frequency to 16.6 Mhz */ - cpu_ppc_tb_init(env, 16600000UL); + cpu_ppc_tb_init(env, TBFREQ); qemu_register_reset(ppc_heathrow_reset, cpu); } @@ -267,20 +268,19 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) macio = pci_create(pci_bus, -1, TYPE_OLDWORLD_MACIO); dev = DEVICE(macio); qdev_connect_gpio_out(dev, 0, pic[0x12]); /* CUDA */ - qdev_connect_gpio_out(dev, 1, pic[0x0D]); /* IDE */ - qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE DMA */ + qdev_connect_gpio_out(dev, 1, pic[0x0D]); /* IDE-0 */ + qdev_connect_gpio_out(dev, 2, pic[0x02]); /* IDE-0 DMA */ + qdev_connect_gpio_out(dev, 3, pic[0x0E]); /* IDE-1 */ + qdev_connect_gpio_out(dev, 4, pic[0x03]); /* IDE-1 DMA */ macio_init(macio, pic_mem, escc_bar); - /* First IDE channel is a MAC IDE on the MacIO bus */ macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), - "ide")); + "ide[0]")); macio_ide_init_drives(macio_ide, hd); - /* Second IDE channel is a CMD646 on the PCI bus */ - hd[0] = hd[MAX_IDE_DEVS]; - hd[1] = hd[MAX_IDE_DEVS + 1]; - hd[3] = hd[2] = NULL; - pci_cmd646_ide_init(pci_bus, hd, 0); + macio_ide = MACIO_IDE(object_resolve_path_component(OBJECT(macio), + "ide[1]")); + macio_ide_init_drives(macio_ide, &hd[MAX_IDE_DEVS]); dev = DEVICE(object_resolve_path_component(OBJECT(macio), "cuda")); adb_bus = qdev_get_child_bus(dev, "adb.0"); @@ -331,7 +331,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args) fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_KVM_PID, getpid()); #endif } else { - fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, get_ticks_per_sec()); + fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_TBFREQ, TBFREQ); } /* Mac OS X requires a "known good" clock-frequency value; pass it one. */ fw_cfg_add_i32(fw_cfg, FW_CFG_PPC_CLOCKFREQ, 266000000); diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 5c31ad3..48ae092 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -940,7 +940,10 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args) } } - filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, FW_FILE_NAME); + if (bios_name == NULL) { + bios_name = FW_FILE_NAME; + } + filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); fw_size = load_image_targphys(filename, 0, FW_MAX_SIZE); if (fw_size < 0) { hw_error("qemu: could not load LPAR rtas '%s'\n", filename); diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index e6f321d..ed32dec 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -121,14 +121,14 @@ static target_ulong h_enter(PowerPCCPU *cpu, sPAPREnvironment *spapr, return H_SUCCESS; } -enum { +typedef enum { REMOVE_SUCCESS = 0, REMOVE_NOT_FOUND = 1, REMOVE_PARM = 2, REMOVE_HW = 3, -}; +} RemoveResult; -static target_ulong remove_hpte(CPUPPCState *env, target_ulong ptex, +static RemoveResult remove_hpte(CPUPPCState *env, target_ulong ptex, target_ulong avpn, target_ulong flags, target_ulong *vp, target_ulong *rp) @@ -165,7 +165,7 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr, target_ulong flags = args[0]; target_ulong pte_index = args[1]; target_ulong avpn = args[2]; - int ret; + RemoveResult ret; ret = remove_hpte(env, pte_index, avpn, flags, &args[0], &args[1]); @@ -184,7 +184,7 @@ static target_ulong h_remove(PowerPCCPU *cpu, sPAPREnvironment *spapr, return H_HARDWARE; } - assert(0); + g_assert_not_reached(); } #define H_BULK_REMOVE_TYPE 0xc000000000000000ULL diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 18f2e2f..318bc9d 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -451,7 +451,7 @@ static uint64_t spapr_io_read(void *opaque, hwaddr addr, case 4: return cpu_inl(addr); } - assert(0); + g_assert_not_reached(); } static void spapr_io_write(void *opaque, hwaddr addr, @@ -468,7 +468,7 @@ static void spapr_io_write(void *opaque, hwaddr addr, cpu_outl(addr, data); return; } - assert(0); + g_assert_not_reached(); } static const MemoryRegionOps spapr_io_ops = { diff --git a/include/hw/ppc/mac_dbdma.h b/include/hw/ppc/mac_dbdma.h index 691263e..90efd27 100644 --- a/include/hw/ppc/mac_dbdma.h +++ b/include/hw/ppc/mac_dbdma.h @@ -37,12 +37,136 @@ struct DBDMA_io { int is_last; int is_dma_out; DBDMA_end dma_end; + /* DMA is in progress, don't start another one */ + bool processing; + /* unaligned last sector of a request */ + uint8_t remainder[0x200]; + int remainder_len; }; +/* + * DBDMA control/status registers. All little-endian. + */ + +#define DBDMA_CONTROL 0x00 +#define DBDMA_STATUS 0x01 +#define DBDMA_CMDPTR_HI 0x02 +#define DBDMA_CMDPTR_LO 0x03 +#define DBDMA_INTR_SEL 0x04 +#define DBDMA_BRANCH_SEL 0x05 +#define DBDMA_WAIT_SEL 0x06 +#define DBDMA_XFER_MODE 0x07 +#define DBDMA_DATA2PTR_HI 0x08 +#define DBDMA_DATA2PTR_LO 0x09 +#define DBDMA_RES1 0x0A +#define DBDMA_ADDRESS_HI 0x0B +#define DBDMA_BRANCH_ADDR_HI 0x0C +#define DBDMA_RES2 0x0D +#define DBDMA_RES3 0x0E +#define DBDMA_RES4 0x0F + +#define DBDMA_REGS 16 +#define DBDMA_SIZE (DBDMA_REGS * sizeof(uint32_t)) + +#define DBDMA_CHANNEL_SHIFT 7 +#define DBDMA_CHANNEL_SIZE (1 << DBDMA_CHANNEL_SHIFT) + +#define DBDMA_CHANNELS (0x1000 >> DBDMA_CHANNEL_SHIFT) + +/* Bits in control and status registers */ + +#define RUN 0x8000 +#define PAUSE 0x4000 +#define FLUSH 0x2000 +#define WAKE 0x1000 +#define DEAD 0x0800 +#define ACTIVE 0x0400 +#define BT 0x0100 +#define DEVSTAT 0x00ff + +/* + * DBDMA command structure. These fields are all little-endian! + */ + +typedef struct dbdma_cmd { + uint16_t req_count; /* requested byte transfer count */ + uint16_t command; /* command word (has bit-fields) */ + uint32_t phy_addr; /* physical data address */ + uint32_t cmd_dep; /* command-dependent field */ + uint16_t res_count; /* residual count after completion */ + uint16_t xfer_status; /* transfer status */ +} dbdma_cmd; + +/* DBDMA command values in command field */ + +#define COMMAND_MASK 0xf000 +#define OUTPUT_MORE 0x0000 /* transfer memory data to stream */ +#define OUTPUT_LAST 0x1000 /* ditto followed by end marker */ +#define INPUT_MORE 0x2000 /* transfer stream data to memory */ +#define INPUT_LAST 0x3000 /* ditto, expect end marker */ +#define STORE_WORD 0x4000 /* write word (4 bytes) to device reg */ +#define LOAD_WORD 0x5000 /* read word (4 bytes) from device reg */ +#define DBDMA_NOP 0x6000 /* do nothing */ +#define DBDMA_STOP 0x7000 /* suspend processing */ + +/* Key values in command field */ + +#define KEY_MASK 0x0700 +#define KEY_STREAM0 0x0000 /* usual data stream */ +#define KEY_STREAM1 0x0100 /* control/status stream */ +#define KEY_STREAM2 0x0200 /* device-dependent stream */ +#define KEY_STREAM3 0x0300 /* device-dependent stream */ +#define KEY_STREAM4 0x0400 /* reserved */ +#define KEY_REGS 0x0500 /* device register space */ +#define KEY_SYSTEM 0x0600 /* system memory-mapped space */ +#define KEY_DEVICE 0x0700 /* device memory-mapped space */ + +/* Interrupt control values in command field */ + +#define INTR_MASK 0x0030 +#define INTR_NEVER 0x0000 /* don't interrupt */ +#define INTR_IFSET 0x0010 /* intr if condition bit is 1 */ +#define INTR_IFCLR 0x0020 /* intr if condition bit is 0 */ +#define INTR_ALWAYS 0x0030 /* always interrupt */ + +/* Branch control values in command field */ + +#define BR_MASK 0x000c +#define BR_NEVER 0x0000 /* don't branch */ +#define BR_IFSET 0x0004 /* branch if condition bit is 1 */ +#define BR_IFCLR 0x0008 /* branch if condition bit is 0 */ +#define BR_ALWAYS 0x000c /* always branch */ + +/* Wait control values in command field */ + +#define WAIT_MASK 0x0003 +#define WAIT_NEVER 0x0000 /* don't wait */ +#define WAIT_IFSET 0x0001 /* wait if condition bit is 1 */ +#define WAIT_IFCLR 0x0002 /* wait if condition bit is 0 */ +#define WAIT_ALWAYS 0x0003 /* always wait */ + +typedef struct DBDMA_channel { + int channel; + uint32_t regs[DBDMA_REGS]; + qemu_irq irq; + DBDMA_io io; + DBDMA_rw rw; + DBDMA_flush flush; + dbdma_cmd current; +} DBDMA_channel; + +typedef struct { + MemoryRegion mem; + DBDMA_channel channels[DBDMA_CHANNELS]; + QEMUBH *bh; +} DBDMAState; + +/* Externally callable functions */ 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); #endif diff --git a/target-ppc/cpu-models.c b/target-ppc/cpu-models.c index 9bb68c8..9578ed8 100644 --- a/target-ppc/cpu-models.c +++ b/target-ppc/cpu-models.c @@ -792,17 +792,15 @@ POWERPC_DEF_SVR("MPC8572E", "MPC8572E", CPU_POWERPC_MPC8572E, POWERPC_SVR_8572E, e500v2) /* e600 family */ - POWERPC_DEF("e600", CPU_POWERPC_e600, 7400, + POWERPC_DEF("e600", CPU_POWERPC_e600, e600, "PowerPC e600 core") /* PowerPC e600 microcontrollers */ -#if defined(TODO) POWERPC_DEF_SVR("MPC8610", "MPC8610", - CPU_POWERPC_MPC8610, POWERPC_SVR_8610, 7400) -#endif + CPU_POWERPC_MPC8610, POWERPC_SVR_8610, e600) POWERPC_DEF_SVR("MPC8641", "MPC8641", - CPU_POWERPC_MPC8641, POWERPC_SVR_8641, 7400) + CPU_POWERPC_MPC8641, POWERPC_SVR_8641, e600) POWERPC_DEF_SVR("MPC8641D", "MPC8641D", - CPU_POWERPC_MPC8641D, POWERPC_SVR_8641D, 7400) + CPU_POWERPC_MPC8641D, POWERPC_SVR_8641D, e600) /* 32 bits "classic" PowerPC */ /* PowerPC 6xx family */ POWERPC_DEF("601_v0", CPU_POWERPC_601_v0, 601, @@ -1145,6 +1143,8 @@ "POWER7 v2.1") POWERPC_DEF("POWER7_v2.3", CPU_POWERPC_POWER7_v23, POWER7, "POWER7 v2.3") + POWERPC_DEF("POWER8_v1.0", CPU_POWERPC_POWER8_v10, POWER8, + "POWER8 v1.0") POWERPC_DEF("970", CPU_POWERPC_970, 970, "PowerPC 970") POWERPC_DEF("970fx_v1.0", CPU_POWERPC_970FX_v10, 970FX, @@ -1390,6 +1390,7 @@ PowerPCCPUAlias ppc_cpu_aliases[] = { { "Dino", "POWER3" }, { "POWER3+", "631" }, { "POWER7", "POWER7_v2.3" }, + { "POWER8", "POWER8_v1.0" }, { "970fx", "970fx_v3.1" }, { "970mp", "970mp_v1.1" }, { "Apache", "RS64" }, diff --git a/target-ppc/cpu-models.h b/target-ppc/cpu-models.h index ae8f7c7..01e488f 100644 --- a/target-ppc/cpu-models.h +++ b/target-ppc/cpu-models.h @@ -556,6 +556,7 @@ enum { CPU_POWERPC_POWER7_v20 = 0x003F0200, CPU_POWERPC_POWER7_v21 = 0x003F0201, CPU_POWERPC_POWER7_v23 = 0x003F0203, + CPU_POWERPC_POWER8_v10 = 0x004B0100, CPU_POWERPC_970 = 0x00390202, CPU_POWERPC_970FX_v10 = 0x00391100, CPU_POWERPC_970FX_v20 = 0x003C0200, @@ -732,9 +733,7 @@ enum { POWERPC_SVR_8568E = 0x807D0011 | POWERPC_SVR_E500, POWERPC_SVR_8572 = 0x80E00010 | POWERPC_SVR_E500, POWERPC_SVR_8572E = 0x80E80010 | POWERPC_SVR_E500, -#if 0 - POWERPC_SVR_8610 = xxx, -#endif + POWERPC_SVR_8610 = 0x80A00011, POWERPC_SVR_8641 = 0x80900021, POWERPC_SVR_8641D = 0x80900121, }; diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index b62f04a..79bfcd8 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -6479,6 +6479,131 @@ POWERPC_FAMILY(7457)(ObjectClass *oc, void *data) POWERPC_FLAG_BUS_CLK; } +static void init_proc_e600 (CPUPPCState *env) +{ + gen_spr_ne_601(env); + gen_spr_7xx(env); + /* Time base */ + gen_tbl(env); + /* 74xx specific SPR */ + gen_spr_74xx(env); + /* XXX : not implemented */ + spr_register(env, SPR_UBAMR, "UBAMR", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_LDSTCR, "LDSTCR", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_ICTRL, "ICTRL", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_MSSSR0, "MSSSR0", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC5, "PMC5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_UPMC5, "UPMC5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_PMC6, "PMC6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + /* XXX : not implemented */ + spr_register(env, SPR_UPMC6, "UPMC6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* SPRGs */ + spr_register(env, SPR_SPRG4, "SPRG4", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG4, "USPRG4", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG5, "SPRG5", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG5, "USPRG5", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG6, "SPRG6", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG6, "USPRG6", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + spr_register(env, SPR_SPRG7, "SPRG7", + SPR_NOACCESS, SPR_NOACCESS, + &spr_read_generic, &spr_write_generic, + 0x00000000); + spr_register(env, SPR_USPRG7, "USPRG7", + &spr_read_ureg, SPR_NOACCESS, + &spr_read_ureg, SPR_NOACCESS, + 0x00000000); + /* Memory management */ + gen_low_BATs(env); + gen_high_BATs(env); + gen_74xx_soft_tlb(env, 128, 2); + init_excp_7450(env); + env->dcache_line_size = 32; + env->icache_line_size = 32; + /* Allocate hardware IRQ controller */ + ppc6xx_irq_init(env); +} + +POWERPC_FAMILY(e600)(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "PowerPC e600"; + pcc->init_proc = init_proc_e600; + pcc->check_pow = check_pow_hid0_74xx; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | + PPC_CACHE_DCBA | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_MEM_TLBIA | PPC_74xx_TLB | + PPC_SEGMENT | PPC_EXTERN | + PPC_ALTIVEC; + pcc->insns_flags2 = PPC_NONE; + pcc->msr_mask = 0x000000000205FF77ULL; + pcc->mmu_model = POWERPC_MMU_32B; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash32_handle_mmu_fault; +#endif + pcc->excp_model = POWERPC_EXCP_74xx; + pcc->bus_model = PPC_FLAGS_INPUT_6xx; + pcc->bfd_mach = bfd_mach_ppc_7400; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK; +} + #if defined (TARGET_PPC64) #if defined(CONFIG_USER_ONLY) #define POWERPC970_HID5_INIT 0x00000080 @@ -7011,6 +7136,40 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data) pcc->l1_dcache_size = 0x8000; pcc->l1_icache_size = 0x8000; } + +POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc); + + dc->desc = "POWER8"; + pcc->init_proc = init_proc_POWER7; + pcc->check_pow = check_pow_nocheck; + pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_MFTB | + PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES | + PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE | + PPC_FLOAT_STFIWX | + PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ | + PPC_MEM_SYNC | PPC_MEM_EIEIO | + PPC_MEM_TLBIE | PPC_MEM_TLBSYNC | + PPC_64B | PPC_ALTIVEC | + PPC_SEGMENT_64B | PPC_SLBI | + PPC_POPCNTB | PPC_POPCNTWD; + pcc->insns_flags2 = PPC2_VSX | PPC2_DFP | PPC2_DBRX; + pcc->msr_mask = 0x800000000204FF36ULL; + pcc->mmu_model = POWERPC_MMU_2_06; +#if defined(CONFIG_SOFTMMU) + pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault; +#endif + pcc->excp_model = POWERPC_EXCP_POWER7; + pcc->bus_model = PPC_FLAGS_INPUT_POWER7; + pcc->bfd_mach = bfd_mach_ppc64; + pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE | + POWERPC_FLAG_BE | POWERPC_FLAG_PMM | + POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR; + pcc->l1_dcache_size = 0x8000; + pcc->l1_icache_size = 0x8000; +} #endif /* defined (TARGET_PPC64) */ |