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,11 +600,13 @@ 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, | ||||
|                         uint64_t value, unsigned size) | ||||
| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Anthony Liguori
						Anthony Liguori