summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2013-07-12 07:58:31 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2013-07-12 07:58:31 -0500
commit25ca6a1f5a3ee0a1ae670590877ed14f05e28fba (patch)
tree594b8455808884e8f28eee95570b9b0de0c54eb8
parentc170a23ca0097a95b44fc7cc604018cd3c3b7d44 (diff)
parentf35ea98cd9f75db9286f05bf3dc4b532f4cb5eaa (diff)
downloadhqemu-25ca6a1f5a3ee0a1ae670590877ed14f05e28fba.zip
hqemu-25ca6a1f5a3ee0a1ae670590877ed14f05e28fba.tar.gz
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.mak2
-rw-r--r--hw/ide/macio.c241
-rw-r--r--hw/intc/Makefile.objs1
-rw-r--r--hw/intc/xics.c (renamed from hw/ppc/xics.c)0
-rw-r--r--hw/misc/macio/mac_dbdma.c193
-rw-r--r--hw/misc/macio/macio.c126
-rw-r--r--hw/ppc/Makefile.objs2
-rw-r--r--hw/ppc/mac.h3
-rw-r--r--hw/ppc/mac_newworld.c5
-rw-r--r--hw/ppc/mac_oldworld.c22
-rw-r--r--hw/ppc/spapr.c5
-rw-r--r--hw/ppc/spapr_hcall.c10
-rw-r--r--hw/ppc/spapr_pci.c4
-rw-r--r--include/hw/ppc/mac_dbdma.h124
-rw-r--r--target-ppc/cpu-models.c13
-rw-r--r--target-ppc/cpu-models.h5
-rw-r--r--target-ppc/translate_init.c159
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) */
OpenPOWER on IntegriCloud