diff --git a/Makefile.target b/Makefile.target index 9ce7e7f5b8e9b6aaa6f22b584fc68387ba2852df..65c336298199d7f8926466099eb35556d2b80a5d 100644 --- a/Makefile.target +++ b/Makefile.target @@ -359,8 +359,8 @@ VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o VL_OBJS+= cirrus_vga.o parallel.o else -VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o slavio_intctl.o -VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o +VL_OBJS+= sun4m.o tcx.o pcnet.o iommu.o m48t59.o slavio_intctl.o +VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o sparc32_dma.o endif endif ifeq ($(TARGET_BASE_ARCH), arm) diff --git a/hw/esp.c b/hw/esp.c index 991e5151feca1b2a2d97870deed1969e1b3a9a8f..be5600183aaeb67e4e7d22b99a0992494424cb9b 100644 --- a/hw/esp.c +++ b/hw/esp.c @@ -1,5 +1,5 @@ /* - * QEMU ESP emulation + * QEMU ESP/NCR53C9x emulation * * Copyright (c) 2005-2006 Fabrice Bellard * @@ -26,33 +26,31 @@ /* debug ESP card */ //#define DEBUG_ESP +/* + * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O), also + * produced as NCR89C100. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt + * and + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt + */ + #ifdef DEBUG_ESP #define DPRINTF(fmt, args...) \ do { printf("ESP: " fmt , ##args); } while (0) -#define pic_set_irq(irq, level) \ -do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0) #else #define DPRINTF(fmt, args...) #endif -#define ESPDMA_REGS 4 -#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1) #define ESP_MAXREG 0x3f #define TI_BUFSZ 32 -#define DMA_VER 0xa0000000 -#define DMA_INTR 1 -#define DMA_INTREN 0x10 -#define DMA_WRITE_MEM 0x100 -#define DMA_LOADED 0x04000000 + typedef struct ESPState ESPState; struct ESPState { BlockDriverState **bd; uint8_t rregs[ESP_MAXREG]; uint8_t wregs[ESP_MAXREG]; - int irq; - uint32_t espdmaregs[ESPDMA_REGS]; - uint32_t ti_size; + int32_t ti_size; uint32_t ti_rptr, ti_wptr; uint8_t ti_buf[TI_BUFSZ]; int sense; @@ -66,6 +64,7 @@ struct ESPState { uint32_t dma_left; uint8_t *async_buf; uint32_t async_len; + void *dma_opaque; }; #define STAT_DO 0x00 @@ -97,9 +96,7 @@ static int get_cmd(ESPState *s, uint8_t *buf) target = s->wregs[4] & 7; DPRINTF("get_cmd: len %d target %d\n", dmalen, target); if (s->dma) { - DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", - s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->espdmaregs[1]); - sparc_iommu_memory_read(s->espdmaregs[1], buf, dmalen); + espdma_memory_read(s->dma_opaque, buf, dmalen); } else { buf[0] = 0; memcpy(&buf[1], s->ti_buf, dmalen); @@ -116,13 +113,12 @@ static int get_cmd(ESPState *s, uint8_t *buf) s->async_len = 0; } - if (target >= 4 || !s->scsi_dev[target]) { + if (target >= MAX_DISKS || !s->scsi_dev[target]) { // No such drive s->rregs[4] = STAT_IN; s->rregs[5] = INTR_DC; s->rregs[6] = SEQ_0; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); + espdma_raise_irq(s->dma_opaque); return 0; } s->current_dev = s->scsi_dev[target]; @@ -137,25 +133,21 @@ static void do_cmd(ESPState *s, uint8_t *buf) DPRINTF("do_cmd: busid 0x%x\n", buf[0]); lun = buf[0] & 7; datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun); - if (datalen == 0) { - s->ti_size = 0; - } else { + s->ti_size = datalen; + if (datalen != 0) { s->rregs[4] = STAT_IN | STAT_TC; s->dma_left = 0; if (datalen > 0) { s->rregs[4] |= STAT_DI; - s->ti_size = datalen; scsi_read_data(s->current_dev, 0); } else { s->rregs[4] |= STAT_DO; - s->ti_size = -datalen; scsi_write_data(s->current_dev, 0); } } s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); + espdma_raise_irq(s->dma_opaque); } static void handle_satn(ESPState *s) @@ -174,12 +166,10 @@ static void handle_satn_stop(ESPState *s) if (s->cmdlen) { DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen); s->do_cmd = 1; - s->espdmaregs[1] += s->cmdlen; s->rregs[4] = STAT_IN | STAT_TC | STAT_CD; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); + espdma_raise_irq(s->dma_opaque); } } @@ -189,9 +179,7 @@ static void write_response(ESPState *s) s->ti_buf[0] = s->sense; s->ti_buf[1] = 0; if (s->dma) { - DPRINTF("DMA Direction: %c\n", - s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r'); - sparc_iommu_memory_write(s->espdmaregs[1], s->ti_buf, 2); + espdma_memory_write(s->dma_opaque, s->ti_buf, 2); s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; s->rregs[5] = INTR_BS | INTR_FC; s->rregs[6] = SEQ_CD; @@ -201,9 +189,7 @@ static void write_response(ESPState *s) s->ti_wptr = 0; s->rregs[7] = 2; } - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); - + espdma_raise_irq(s->dma_opaque); } static void esp_dma_done(ESPState *s) @@ -212,24 +198,19 @@ static void esp_dma_done(ESPState *s) s->rregs[5] = INTR_BS; s->rregs[6] = 0; s->rregs[7] = 0; - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); + espdma_raise_irq(s->dma_opaque); } static void esp_do_dma(ESPState *s) { - uint32_t addr, len; + uint32_t len; int to_device; - to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; - addr = s->espdmaregs[1]; + to_device = (s->ti_size < 0); len = s->dma_left; - DPRINTF("DMA address %08x len %08x\n", addr, len); if (s->do_cmd) { - s->espdmaregs[1] += len; - s->ti_size -= len; DPRINTF("command len %d + %d\n", s->cmdlen, len); - sparc_iommu_memory_read(addr, &s->cmdbuf[s->cmdlen], len); + espdma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); s->ti_size = 0; s->cmdlen = 0; s->do_cmd = 0; @@ -244,19 +225,20 @@ static void esp_do_dma(ESPState *s) len = s->async_len; } if (to_device) { - sparc_iommu_memory_read(addr, s->async_buf, len); + espdma_memory_read(s->dma_opaque, s->async_buf, len); } else { - sparc_iommu_memory_write(addr, s->async_buf, len); + espdma_memory_write(s->dma_opaque, s->async_buf, len); } - s->ti_size -= len; s->dma_left -= len; s->async_buf += len; s->async_len -= len; - s->espdmaregs[1] += len; if (s->async_len == 0) { if (to_device) { + // ti_size is negative + s->ti_size += len; scsi_write_data(s->current_dev, 0); } else { + s->ti_size -= len; scsi_read_data(s->current_dev, 0); } } @@ -303,6 +285,8 @@ static void handle_ti(ESPState *s) if (s->do_cmd) minlen = (dmalen < 32) ? dmalen : 32; + else if (s->ti_size < 0) + minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size; else minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; DPRINTF("Transfer Information len %d\n", minlen); @@ -320,13 +304,13 @@ static void handle_ti(ESPState *s) } } -static void esp_reset(void *opaque) +void esp_reset(void *opaque) { ESPState *s = opaque; + memset(s->rregs, 0, ESP_MAXREG); memset(s->wregs, 0, ESP_MAXREG); s->rregs[0x0e] = 0x4; // Indicate fas100a - memset(s->espdmaregs, 0, ESPDMA_REGS * 4); s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; @@ -353,7 +337,7 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) } else { s->rregs[2] = s->ti_buf[s->ti_rptr++]; } - pic_set_irq(s->irq, 1); + espdma_raise_irq(s->dma_opaque); } if (s->ti_size == 0) { s->ti_rptr = 0; @@ -364,8 +348,7 @@ static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) // interrupt // Clear interrupt/error status bits s->rregs[4] &= ~(STAT_IN | STAT_GE | STAT_PE); - pic_set_irq(s->irq, 0); - s->espdmaregs[0] &= ~DMA_INTR; + espdma_clear_irq(s->dma_opaque); break; default: break; @@ -426,8 +409,7 @@ static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) DPRINTF("Bus reset (%2.2x)\n", val); s->rregs[5] = INTR_RST; if (!(s->wregs[8] & 0x40)) { - s->espdmaregs[0] |= DMA_INTR; - pic_set_irq(s->irq, 1); + espdma_raise_irq(s->dma_opaque); } break; case 0x10: @@ -490,68 +472,12 @@ static CPUWriteMemoryFunc *esp_mem_write[3] = { esp_mem_writeb, }; -static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr) -{ - ESPState *s = opaque; - uint32_t saddr; - - saddr = (addr & ESPDMA_MAXADDR) >> 2; - DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]); - - return s->espdmaregs[saddr]; -} - -static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) -{ - ESPState *s = opaque; - uint32_t saddr; - - saddr = (addr & ESPDMA_MAXADDR) >> 2; - DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val); - switch (saddr) { - case 0: - if (!(val & DMA_INTREN)) - pic_set_irq(s->irq, 0); - if (val & 0x80) { - esp_reset(s); - } else if (val & 0x40) { - val &= ~0x40; - } else if (val == 0) - val = 0x40; - val &= 0x0fffffff; - val |= DMA_VER; - break; - case 1: - s->espdmaregs[0] |= DMA_LOADED; - break; - default: - break; - } - s->espdmaregs[saddr] = val; -} - -static CPUReadMemoryFunc *espdma_mem_read[3] = { - espdma_mem_readl, - espdma_mem_readl, - espdma_mem_readl, -}; - -static CPUWriteMemoryFunc *espdma_mem_write[3] = { - espdma_mem_writel, - espdma_mem_writel, - espdma_mem_writel, -}; - static void esp_save(QEMUFile *f, void *opaque) { ESPState *s = opaque; - unsigned int i; qemu_put_buffer(f, s->rregs, ESP_MAXREG); qemu_put_buffer(f, s->wregs, ESP_MAXREG); - qemu_put_be32s(f, &s->irq); - for (i = 0; i < ESPDMA_REGS; i++) - qemu_put_be32s(f, &s->espdmaregs[i]); qemu_put_be32s(f, &s->ti_size); qemu_put_be32s(f, &s->ti_rptr); qemu_put_be32s(f, &s->ti_wptr); @@ -562,16 +488,12 @@ static void esp_save(QEMUFile *f, void *opaque) static int esp_load(QEMUFile *f, void *opaque, int version_id) { ESPState *s = opaque; - unsigned int i; - if (version_id != 1) - return -EINVAL; + if (version_id != 2) + return -EINVAL; // Cannot emulate 1 qemu_get_buffer(f, s->rregs, ESP_MAXREG); qemu_get_buffer(f, s->wregs, ESP_MAXREG); - qemu_get_be32s(f, &s->irq); - for (i = 0; i < ESPDMA_REGS; i++) - qemu_get_be32s(f, &s->espdmaregs[i]); qemu_get_be32s(f, &s->ti_size); qemu_get_be32s(f, &s->ti_rptr); qemu_get_be32s(f, &s->ti_wptr); @@ -581,28 +503,25 @@ static int esp_load(QEMUFile *f, void *opaque, int version_id) return 0; } -void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr) +void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque) { ESPState *s; - int esp_io_memory, espdma_io_memory; + int esp_io_memory; int i; s = qemu_mallocz(sizeof(ESPState)); if (!s) - return; + return NULL; s->bd = bd; - s->irq = irq; + s->dma_opaque = dma_opaque; esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s); cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory); - espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s); - cpu_register_physical_memory(espdaddr, 16, espdma_io_memory); - esp_reset(s); - register_savevm("esp", espaddr, 1, esp_save, esp_load, s); + register_savevm("esp", espaddr, 2, esp_save, esp_load, s); qemu_register_reset(esp_reset, s); for (i = 0; i < MAX_DISKS; i++) { if (bs_table[i]) { @@ -611,5 +530,6 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd scsi_disk_init(bs_table[i], 0, esp_command_complete, s); } } -} + return s; +} diff --git a/hw/iommu.c b/hw/iommu.c index 83001bd7f1f72fb3ea567b5b4c7896b88ae9b587..5c2768cee318b69bc35534f5c7228e063f4d52e1 100644 --- a/hw/iommu.c +++ b/hw/iommu.c @@ -206,19 +206,11 @@ static uint32_t iommu_translate_pa(IOMMUState *s, uint32_t addr, uint32_t pa) return pa; } -uint32_t iommu_translate_local(void *opaque, uint32_t addr) -{ - uint32_t flags; - flags = iommu_page_get_flags(opaque, addr); - return iommu_translate_pa(opaque, addr, flags); -} - -void sparc_iommu_memory_rw_local(void *opaque, target_phys_addr_t addr, - uint8_t *buf, int len, int is_write) +void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, + uint8_t *buf, int len, int is_write) { int l, flags; target_ulong page, phys_addr; - void * p; while (len > 0) { page = addr & TARGET_PAGE_MASK; diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c new file mode 100644 index 0000000000000000000000000000000000000000..d8d7e6a83e3c7d70f252ed1d2e34b40aa1b55f20 --- /dev/null +++ b/hw/sparc32_dma.c @@ -0,0 +1,249 @@ +/* + * QEMU Sparc32 DMA controller emulation + * + * Copyright (c) 2006 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +/* debug DMA */ +//#define DEBUG_DMA + +/* + * This is the DMA controller part of chip STP2000 (Master I/O), also + * produced as NCR89C100. See + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt + * and + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/DMA2.txt + */ + +#ifdef DEBUG_DMA +#define DPRINTF(fmt, args...) \ +do { printf("DMA: " fmt , ##args); } while (0) +#define pic_set_irq_new(ctl, irq, level) \ + do { printf("DMA: set_irq(%d): %d\n", (irq), (level)); \ + pic_set_irq_new((ctl), (irq),(level));} while (0) +#else +#define DPRINTF(fmt, args...) +#endif + +#define DMA_REGS 8 +#define DMA_MAXADDR (DMA_REGS * 4 - 1) + +#define DMA_VER 0xa0000000 +#define DMA_INTR 1 +#define DMA_INTREN 0x10 +#define DMA_WRITE_MEM 0x100 +#define DMA_LOADED 0x04000000 +#define DMA_RESET 0x80 + +typedef struct DMAState DMAState; + +struct DMAState { + uint32_t dmaregs[DMA_REGS]; + int espirq, leirq; + void *iommu, *esp_opaque, *lance_opaque, *intctl; +}; + +void ledma_set_irq(void *opaque, int isr) +{ + DMAState *s = opaque; + + pic_set_irq_new(s->intctl, s->leirq, isr); +} + +void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len) +{ + DMAState *s = opaque; + + DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n", + s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); + sparc_iommu_memory_read(s->iommu, addr | s->dmaregs[7], buf, len); +} + +void ledma_memory_write(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len) +{ + DMAState *s = opaque; + + DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n", + s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); + sparc_iommu_memory_write(s->iommu, addr | s->dmaregs[7], buf, len); +} + +void espdma_raise_irq(void *opaque) +{ + DMAState *s = opaque; + + s->dmaregs[0] |= DMA_INTR; + pic_set_irq_new(s->intctl, s->espirq, 1); +} + +void espdma_clear_irq(void *opaque) +{ + DMAState *s = opaque; + + s->dmaregs[0] &= ~DMA_INTR; + pic_set_irq_new(s->intctl, s->espirq, 0); +} + +void espdma_memory_read(void *opaque, uint8_t *buf, int len) +{ + DMAState *s = opaque; + + DPRINTF("DMA read, direction: %c, addr 0x%8.8x\n", + s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); + sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len); + s->dmaregs[0] |= DMA_INTR; + s->dmaregs[1] += len; +} + +void espdma_memory_write(void *opaque, uint8_t *buf, int len) +{ + DMAState *s = opaque; + + DPRINTF("DMA write, direction: %c, addr 0x%8.8x\n", + s->dmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', s->dmaregs[1]); + sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len); + s->dmaregs[0] |= DMA_INTR; + s->dmaregs[1] += len; +} + +static uint32_t dma_mem_readl(void *opaque, target_phys_addr_t addr) +{ + DMAState *s = opaque; + uint32_t saddr; + + saddr = (addr & DMA_MAXADDR) >> 2; + DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->dmaregs[saddr]); + + return s->dmaregs[saddr]; +} + +static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) +{ + DMAState *s = opaque; + uint32_t saddr; + + saddr = (addr & DMA_MAXADDR) >> 2; + DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->dmaregs[saddr], val); + switch (saddr) { + case 0: + if (!(val & DMA_INTREN)) + pic_set_irq_new(s->intctl, s->espirq, 0); + if (val & DMA_RESET) { + esp_reset(s->esp_opaque); + } else if (val & 0x40) { + val &= ~0x40; + } else if (val == 0) + val = 0x40; + val &= 0x0fffffff; + val |= DMA_VER; + break; + case 1: + s->dmaregs[0] |= DMA_LOADED; + break; + case 4: + if (!(val & DMA_INTREN)) + pic_set_irq_new(s->intctl, s->leirq, 0); + if (val & DMA_RESET) + pcnet_h_reset(s->lance_opaque); + val &= 0x0fffffff; + val |= DMA_VER; + break; + default: + break; + } + s->dmaregs[saddr] = val; +} + +static CPUReadMemoryFunc *dma_mem_read[3] = { + dma_mem_readl, + dma_mem_readl, + dma_mem_readl, +}; + +static CPUWriteMemoryFunc *dma_mem_write[3] = { + dma_mem_writel, + dma_mem_writel, + dma_mem_writel, +}; + +static void dma_reset(void *opaque) +{ + DMAState *s = opaque; + + memset(s->dmaregs, 0, DMA_REGS * 4); + s->dmaregs[0] = DMA_VER; + s->dmaregs[4] = DMA_VER; +} + +static void dma_save(QEMUFile *f, void *opaque) +{ + DMAState *s = opaque; + unsigned int i; + + for (i = 0; i < DMA_REGS; i++) + qemu_put_be32s(f, &s->dmaregs[i]); +} + +static int dma_load(QEMUFile *f, void *opaque, int version_id) +{ + DMAState *s = opaque; + unsigned int i; + + if (version_id != 1) + return -EINVAL; + for (i = 0; i < DMA_REGS; i++) + qemu_get_be32s(f, &s->dmaregs[i]); + + return 0; +} + +void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu, void *intctl) +{ + DMAState *s; + int dma_io_memory; + + s = qemu_mallocz(sizeof(DMAState)); + if (!s) + return NULL; + + s->espirq = espirq; + s->leirq = leirq; + s->iommu = iommu; + s->intctl = intctl; + + dma_io_memory = cpu_register_io_memory(0, dma_mem_read, dma_mem_write, s); + cpu_register_physical_memory(daddr, 16 * 2, dma_io_memory); + + register_savevm("sparc32_dma", daddr, 1, dma_save, dma_load, s); + qemu_register_reset(dma_reset, s); + + return s; +} + +void sparc32_dma_set_reset_data(void *opaque, void *esp_opaque, + void *lance_opaque) +{ + DMAState *s = opaque; + + s->esp_opaque = esp_opaque; + s->lance_opaque = lance_opaque; +} diff --git a/hw/sun4m.c b/hw/sun4m.c index 09a157c0a7277710b478ac8a5a64ae5cf2a3b9c1..94629364d0836d3a3916255e842a3c33ffa07a47 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -37,10 +37,9 @@ #define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */ #define PHYS_JJ_TCX_FB 0x50000000 /* TCX frame buffer */ #define PHYS_JJ_SLAVIO 0x70000000 /* Slavio base */ -#define PHYS_JJ_ESPDMA 0x78400000 /* ESP DMA controller */ +#define PHYS_JJ_DMA 0x78400000 /* DMA controller */ #define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */ #define PHYS_JJ_ESP_IRQ 18 -#define PHYS_JJ_LEDMA 0x78400010 /* Lance DMA controller */ #define PHYS_JJ_LE 0x78C00000 /* Lance ethernet */ #define PHYS_JJ_LE_IRQ 16 #define PHYS_JJ_CLOCK 0x71D00000 /* Per-CPU timer/counter, L14 */ @@ -192,25 +191,6 @@ void pic_set_irq_cpu(int irq, int level, unsigned int cpu) slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu); } -static void *iommu; - -uint32_t iommu_translate(uint32_t addr) -{ - return iommu_translate_local(iommu, addr); -} - -void sparc_iommu_memory_read(target_phys_addr_t addr, - uint8_t *buf, int len) -{ - return sparc_iommu_memory_rw_local(iommu, addr, buf, len, 0); -} - -void sparc_iommu_memory_write(target_phys_addr_t addr, - uint8_t *buf, int len) -{ - return sparc_iommu_memory_rw_local(iommu, addr, buf, len, 1); -} - static void *slavio_misc; void qemu_system_powerdown(void) @@ -235,6 +215,7 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, int ret, linux_boot; unsigned int i; long vram_size = 0x100000, prom_offset, initrd_size, kernel_size; + void *iommu, *dma, *main_esp, *main_lance = NULL; linux_boot = (kernel_filename != NULL); @@ -255,12 +236,13 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, for(i = 0; i < smp_cpus; i++) { slavio_intctl_set_cpu(slavio_intctl, i, envs[i]); } + dma = sparc32_dma_init(PHYS_JJ_DMA, PHYS_JJ_ESP_IRQ, PHYS_JJ_LE_IRQ, iommu, slavio_intctl); tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height); if (nd_table[0].vlan) { if (nd_table[0].model == NULL || strcmp(nd_table[0].model, "lance") == 0) { - lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA); + main_lance = lance_init(&nd_table[0], PHYS_JJ_LE, dma); } else { fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model); exit (1); @@ -276,8 +258,9 @@ static void sun4m_init(int ram_size, int vga_ram_size, int boot_device, // Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]); fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table); - esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA); + main_esp = esp_init(bs_table, PHYS_JJ_ESP, dma); slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ); + sparc32_dma_set_reset_data(dma, main_esp, main_lance); prom_offset = ram_size + vram_size; cpu_register_physical_memory(PROM_ADDR, diff --git a/vl.h b/vl.h index 14116fa75077566df61474d4f45b7731a7726b2b..9612c6c6c331ca8f1df64d1cfae933ffc84595b0 100644 --- a/vl.h +++ b/vl.h @@ -924,6 +924,9 @@ void pci_rtl8139_init(PCIBus *bus, NICInfo *nd); /* pcnet.c */ void pci_pcnet_init(PCIBus *bus, NICInfo *nd); +void pcnet_h_reset(void *opaque); +void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque); + /* pckbd.c */ @@ -1027,22 +1030,24 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val); /* sun4m.c */ extern QEMUMachine sun4m_machine; void pic_set_irq_cpu(int irq, int level, unsigned int cpu); -/* ??? Remove iommu_translate once lance emulation has been converted. */ -uint32_t iommu_translate(uint32_t addr); -void sparc_iommu_memory_read(target_phys_addr_t addr, - uint8_t *buf, int len); -void sparc_iommu_memory_write(target_phys_addr_t addr, - uint8_t *buf, int len); /* iommu.c */ void *iommu_init(uint32_t addr); -/* ??? Remove iommu_translate_local. */ -uint32_t iommu_translate_local(void *opaque, uint32_t addr); -void sparc_iommu_memory_rw_local(void *opaque, target_phys_addr_t addr, +void sparc_iommu_memory_rw(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write); +static inline void sparc_iommu_memory_read(void *opaque, + target_phys_addr_t addr, + uint8_t *buf, int len) +{ + sparc_iommu_memory_rw(opaque, addr, buf, len, 0); +} -/* lance.c */ -void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr); +static inline void sparc_iommu_memory_write(void *opaque, + target_phys_addr_t addr, + uint8_t *buf, int len) +{ + sparc_iommu_memory_rw(opaque, addr, buf, len, 1); +} /* tcx.c */ void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base, @@ -1074,7 +1079,23 @@ void *slavio_misc_init(uint32_t base, int irq); void slavio_set_power_fail(void *opaque, int power_failing); /* esp.c */ -void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr); +void *esp_init(BlockDriverState **bd, uint32_t espaddr, void *dma_opaque); +void esp_reset(void *opaque); + +/* sparc32_dma.c */ +void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu, + void *intctl); +void ledma_set_irq(void *opaque, int isr); +void ledma_memory_read(void *opaque, target_phys_addr_t addr, uint8_t *buf, + int len); +void ledma_memory_write(void *opaque, target_phys_addr_t addr, uint8_t *buf, + int len); +void espdma_raise_irq(void *opaque); +void espdma_clear_irq(void *opaque); +void espdma_memory_read(void *opaque, uint8_t *buf, int len); +void espdma_memory_write(void *opaque, uint8_t *buf, int len); +void sparc32_dma_set_reset_data(void *opaque, void *esp_opaque, + void *lance_opaque); /* sun4u.c */ extern QEMUMachine sun4u_machine;