summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlue Swirl <blauwirbel@gmail.com>2010-09-11 16:38:33 +0000
committerBlue Swirl <blauwirbel@gmail.com>2010-09-11 16:38:33 +0000
commit73d7434279e390505164afd02360eebe4b43c7fa (patch)
tree309f298ec1dcba9be54fb0604a92811cc3095dbe
parent24e0e38b83616ee7b540a270d8c4f24edf94f802 (diff)
downloadqemu-73d7434279e390505164afd02360eebe4b43c7fa.tar.gz
qemu-73d7434279e390505164afd02360eebe4b43c7fa.tar.bz2
qemu-73d7434279e390505164afd02360eebe4b43c7fa.zip
ESP: fix ESP DMA access when DMA is not enabled
Sending ESP a command caused it to trigger DMA immediately even if DMA was not enabled at the DMA controller. Add a signal from DMA controller to ESP to tell ESP about changes in DMA enable bit. Also use the correct function for setting up GPIO outputs. This fixes NetBSD 1.6.1 through 3.0 boot. Thanks to Artyom Tarasenko for extensive debugging of the problem. Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
-rw-r--r--hw/esp.c53
-rw-r--r--hw/esp.h3
-rw-r--r--hw/mips_jazz.c4
-rw-r--r--hw/sparc32_dma.c23
-rw-r--r--hw/sun4m.c23
5 files changed, 88 insertions, 18 deletions
diff --git a/hw/esp.c b/hw/esp.c
index 349052a024..910fd31665 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -80,6 +80,8 @@ struct ESPState {
ESPDMAMemoryReadWriteFunc dma_memory_read;
ESPDMAMemoryReadWriteFunc dma_memory_write;
void *dma_opaque;
+ int dma_enabled;
+ void (*dma_cb)(ESPState *s);
};
#define ESP_TCLO 0x0
@@ -167,6 +169,24 @@ static void esp_lower_irq(ESPState *s)
}
}
+static void esp_dma_enable(void *opaque, int irq, int level)
+{
+ DeviceState *d = opaque;
+ ESPState *s = container_of(d, ESPState, busdev.qdev);
+
+ if (level) {
+ s->dma_enabled = 1;
+ DPRINTF("Raise enable\n");
+ if (s->dma_cb) {
+ s->dma_cb(s);
+ s->dma_cb = NULL;
+ }
+ } else {
+ DPRINTF("Lower enable\n");
+ s->dma_enabled = 0;
+ }
+}
+
static uint32_t get_cmd(ESPState *s, uint8_t *buf)
{
uint32_t dmalen;
@@ -243,6 +263,10 @@ static void handle_satn(ESPState *s)
uint8_t buf[32];
int len;
+ if (!s->dma_enabled) {
+ s->dma_cb = handle_satn;
+ return;
+ }
len = get_cmd(s, buf);
if (len)
do_cmd(s, buf);
@@ -253,6 +277,10 @@ static void handle_s_without_atn(ESPState *s)
uint8_t buf[32];
int len;
+ if (!s->dma_enabled) {
+ s->dma_cb = handle_s_without_atn;
+ return;
+ }
len = get_cmd(s, buf);
if (len) {
do_busid_cmd(s, buf, 0);
@@ -261,6 +289,10 @@ static void handle_s_without_atn(ESPState *s)
static void handle_satn_stop(ESPState *s)
{
+ if (!s->dma_enabled) {
+ s->dma_cb = handle_satn_stop;
+ return;
+ }
s->cmdlen = get_cmd(s, s->cmdbuf);
if (s->cmdlen) {
DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
@@ -431,6 +463,7 @@ static void esp_hard_reset(DeviceState *d)
s->ti_wptr = 0;
s->dma = 0;
s->do_cmd = 0;
+ s->dma_cb = NULL;
s->rregs[ESP_CFG1] = 7;
}
@@ -450,6 +483,18 @@ static void parent_esp_reset(void *opaque, int irq, int level)
}
}
+static void esp_gpio_demux(void *opaque, int irq, int level)
+{
+ switch (irq) {
+ case 0:
+ parent_esp_reset(opaque, irq, level);
+ break;
+ case 1:
+ esp_dma_enable(opaque, irq, level);
+ break;
+ }
+}
+
static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
{
ESPState *s = opaque;
@@ -646,7 +691,8 @@ static const VMStateDescription vmstate_esp = {
void esp_init(target_phys_addr_t espaddr, int it_shift,
ESPDMAMemoryReadWriteFunc dma_memory_read,
ESPDMAMemoryReadWriteFunc dma_memory_write,
- void *dma_opaque, qemu_irq irq, qemu_irq *reset)
+ void *dma_opaque, qemu_irq irq, qemu_irq *reset,
+ qemu_irq *dma_enable)
{
DeviceState *dev;
SysBusDevice *s;
@@ -658,11 +704,14 @@ void esp_init(target_phys_addr_t espaddr, int it_shift,
esp->dma_memory_write = dma_memory_write;
esp->dma_opaque = dma_opaque;
esp->it_shift = it_shift;
+ /* XXX for now until rc4030 has been changed to use DMA enable signal */
+ esp->dma_enabled = 1;
qdev_init_nofail(dev);
s = sysbus_from_qdev(dev);
sysbus_connect_irq(s, 0, irq);
sysbus_mmio_map(s, 0, espaddr);
*reset = qdev_get_gpio_in(dev, 0);
+ *dma_enable = qdev_get_gpio_in(dev, 1);
}
static int esp_init1(SysBusDevice *dev)
@@ -676,7 +725,7 @@ static int esp_init1(SysBusDevice *dev)
esp_io_memory = cpu_register_io_memory(esp_mem_read, esp_mem_write, s);
sysbus_init_mmio(dev, ESP_REGS << s->it_shift, esp_io_memory);
- qdev_init_gpio_in(&dev->qdev, parent_esp_reset, 1);
+ qdev_init_gpio_in(&dev->qdev, esp_gpio_demux, 2);
scsi_bus_new(&s->bus, &dev->qdev, 0, ESP_MAX_DEVS, esp_command_complete);
return scsi_bus_legacy_handle_cmdline(&s->bus);
diff --git a/hw/esp.h b/hw/esp.h
index 605f953754..62bfd4d129 100644
--- a/hw/esp.h
+++ b/hw/esp.h
@@ -7,6 +7,7 @@ typedef void (*ESPDMAMemoryReadWriteFunc)(void *opaque, uint8_t *buf, int len);
void esp_init(target_phys_addr_t espaddr, int it_shift,
ESPDMAMemoryReadWriteFunc dma_memory_read,
ESPDMAMemoryReadWriteFunc dma_memory_write,
- void *dma_opaque, qemu_irq irq, qemu_irq *reset);
+ void *dma_opaque, qemu_irq irq, qemu_irq *reset,
+ qemu_irq *dma_enable);
#endif
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 5d5305a82d..66397c0c9a 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -137,7 +137,7 @@ void mips_jazz_init (ram_addr_t ram_size,
NICInfo *nd;
PITState *pit;
DriveInfo *fds[MAX_FD];
- qemu_irq esp_reset;
+ qemu_irq esp_reset, dma_enable;
qemu_irq *cpu_exit_irq;
ram_addr_t ram_offset;
ram_addr_t bios_offset;
@@ -245,7 +245,7 @@ void mips_jazz_init (ram_addr_t ram_size,
/* SCSI adapter */
esp_init(0x80002000, 0,
rc4030_dma_read, rc4030_dma_write, dmas[0],
- rc4030[5], &esp_reset);
+ rc4030[5], &esp_reset, &dma_enable);
/* Floppy */
if (drive_get_max_bus(IF_FLOPPY) >= MAX_FD) {
diff --git a/hw/sparc32_dma.c b/hw/sparc32_dma.c
index b52170787b..984ffc3e53 100644
--- a/hw/sparc32_dma.c
+++ b/hw/sparc32_dma.c
@@ -58,6 +58,7 @@
#define DMA_INTR 1
#define DMA_INTREN 0x10
#define DMA_WRITE_MEM 0x100
+#define DMA_EN 0x200
#define DMA_LOADED 0x04000000
#define DMA_DRAIN_FIFO 0x40
#define DMA_RESET 0x80
@@ -72,7 +73,12 @@ struct DMAState {
uint32_t dmaregs[DMA_REGS];
qemu_irq irq;
void *iommu;
- qemu_irq dev_reset;
+ qemu_irq gpio[2];
+};
+
+enum {
+ GPIO_RESET = 0,
+ GPIO_DMA,
};
/* Note: on sparc, the lance 16 bit bus is swapped */
@@ -201,12 +207,21 @@ static void dma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
}
}
if (val & DMA_RESET) {
- qemu_irq_raise(s->dev_reset);
- qemu_irq_lower(s->dev_reset);
+ qemu_irq_raise(s->gpio[GPIO_RESET]);
+ qemu_irq_lower(s->gpio[GPIO_RESET]);
} else if (val & DMA_DRAIN_FIFO) {
val &= ~DMA_DRAIN_FIFO;
} else if (val == 0)
val = DMA_DRAIN_FIFO;
+
+ if (val & DMA_EN && !(s->dmaregs[0] & DMA_EN)) {
+ DPRINTF("Raise DMA enable\n");
+ qemu_irq_raise(s->gpio[GPIO_DMA]);
+ } else if (!(val & DMA_EN) && !!(s->dmaregs[0] & DMA_EN)) {
+ DPRINTF("Lower DMA enable\n");
+ qemu_irq_lower(s->gpio[GPIO_DMA]);
+ }
+
val &= ~DMA_CSR_RO_MASK;
val |= DMA_VER;
s->dmaregs[0] = (s->dmaregs[0] & DMA_CSR_RO_MASK) | val;
@@ -262,7 +277,7 @@ static int sparc32_dma_init1(SysBusDevice *dev)
sysbus_init_mmio(dev, DMA_SIZE, dma_io_memory);
qdev_init_gpio_in(&dev->qdev, dma_set_irq, 1);
- qdev_init_gpio_out(&dev->qdev, &s->dev_reset, 1);
+ qdev_init_gpio_out(&dev->qdev, s->gpio, 2);
return 0;
}
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 7d7a7df1cf..0392109230 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -810,7 +810,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
void *iommu, *espdma, *ledma, *nvram;
qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS],
espdma_irq, ledma_irq;
- qemu_irq esp_reset;
+ qemu_irq esp_reset, dma_enable;
qemu_irq fdc_tc;
qemu_irq *cpu_halt;
unsigned long kernel_size;
@@ -930,11 +930,12 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
exit(1);
}
- esp_reset = qdev_get_gpio_in(espdma, 0);
esp_init(hwdef->esp_base, 2,
espdma_memory_read, espdma_memory_write,
- espdma, espdma_irq, &esp_reset);
+ espdma, espdma_irq, &esp_reset, &dma_enable);
+ qdev_connect_gpio_out(espdma, 0, esp_reset);
+ qdev_connect_gpio_out(espdma, 1, dma_enable);
if (hwdef->cs_base) {
sysbus_create_simple("SUNW,CS4231", hwdef->cs_base,
@@ -1494,7 +1495,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
void *iounits[MAX_IOUNITS], *espdma, *ledma, *nvram;
qemu_irq *cpu_irqs[MAX_CPUS], sbi_irq[32], sbi_cpu_irq[MAX_CPUS],
espdma_irq, ledma_irq;
- qemu_irq esp_reset;
+ qemu_irq esp_reset, dma_enable;
unsigned long kernel_size;
void *fw_cfg;
DeviceState *dev;
@@ -1561,10 +1562,12 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
exit(1);
}
- esp_reset = qdev_get_gpio_in(espdma, 0);
esp_init(hwdef->esp_base, 2,
espdma_memory_read, espdma_memory_write,
- espdma, espdma_irq, &esp_reset);
+ espdma, espdma_irq, &esp_reset, &dma_enable);
+
+ qdev_connect_gpio_out(espdma, 0, esp_reset);
+ qdev_connect_gpio_out(espdma, 1, dma_enable);
kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
RAM_size);
@@ -1683,7 +1686,7 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
{
void *iommu, *espdma, *ledma, *nvram;
qemu_irq *cpu_irqs, slavio_irq[8], espdma_irq, ledma_irq;
- qemu_irq esp_reset;
+ qemu_irq esp_reset, dma_enable;
qemu_irq fdc_tc;
unsigned long kernel_size;
DriveInfo *fd[MAX_FD];
@@ -1751,10 +1754,12 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
exit(1);
}
- esp_reset = qdev_get_gpio_in(espdma, 0);
esp_init(hwdef->esp_base, 2,
espdma_memory_read, espdma_memory_write,
- espdma, espdma_irq, &esp_reset);
+ espdma, espdma_irq, &esp_reset, &dma_enable);
+
+ qdev_connect_gpio_out(espdma, 0, esp_reset);
+ qdev_connect_gpio_out(espdma, 1, dma_enable);
kernel_size = sun4m_load_kernel(kernel_filename, initrd_filename,
RAM_size);