Separate the DMA controllers - Convert ESP to new DMA methods (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2143 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
91cc029598
commit
67e999be93
@ -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)
|
||||
|
172
hw/esp.c
172
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;
|
||||
}
|
||||
|
10
hw/iommu.c
10
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,
|
||||
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;
|
||||
|
249
hw/sparc32_dma.c
Normal file
249
hw/sparc32_dma.c
Normal file
@ -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;
|
||||
}
|
29
hw/sun4m.c
29
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,
|
||||
|
45
vl.h
45
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;
|
||||
|
Loading…
Reference in New Issue
Block a user