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>
master
Anthony Liguori 2013-07-12 07:58:31 -05:00
commit 25ca6a1f5a
17 changed files with 690 additions and 229 deletions

View File

@ -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

View File

@ -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) {
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,
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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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,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]));
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++];
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);
}
}

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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 = {

View File

@ -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

View File

@ -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" },

View File

@ -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,
};

View File

@ -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) */