summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
Diffstat (limited to 'hw')
-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
12 files changed, 394 insertions, 218 deletions
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 479820239e..38ad92423d 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 86f9d5b9df..2851eed25f 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 091912e2ca..091912e2ca 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 a1d7862a66..f47a736182 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 76a1cfba32..c0d0bf7287 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 be00d1da3b..7a1cd5d89e 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 54efaed627..1e578dd59d 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 77a8c2e28b..fe803480a7 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 4663ed2730..8b8c6b93a5 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 5c31ad36bd..48ae09283d 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 e6f321d538..ed32decebf 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 18f2e2f842..318bc9d6ef 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 = {