mirror of
https://github.com/qemu/qemu.git
synced 2024-12-18 17:53:40 +08:00
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>
This commit is contained in:
commit
25ca6a1f5a
@ -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
|
||||
|
237
hw/ide/macio.c
237
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);
|
||||
@ -59,29 +87,90 @@ static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
|
||||
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);
|
||||
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,28 +212,97 @@ static void pmac_ide_transfer_cb(void *opaque, int ret)
|
||||
s->nsector -= n;
|
||||
}
|
||||
|
||||
/* end of transfer ? */
|
||||
if (s->nsector == 0) {
|
||||
s->status = READY_STAT | SEEK_STAT;
|
||||
ide_set_irq(s->bus);
|
||||
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,
|
||||
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
@ -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)))
|
||||
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;
|
||||
}
|
||||
|
@ -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));
|
||||
/* 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,47 +229,74 @@ 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]));
|
||||
/* 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++];
|
||||
|
||||
ret = macio_initfn_ide(s, &ns->ide[i], irq0, irq1, 0x16 + (i * 4));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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 = {
|
||||
|
@ -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
|
||||
|
@ -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" },
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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) */
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user