From 6a1f53f0fe51011d1222b15aa10328fce8546c76 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:21 +0100 Subject: [PATCH 01/17] sparc32_dma: rename SPARC32_DMA type to SPARC32_DMA_DEVICE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also update the function names to match as appropriate. While we're here rename the type from sparc32_dma to sparc32-dma in order to match the current QOM convention. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/dma/sparc32_dma.c | 67 ++++++++++++++++++++++---------------------- hw/sparc/sun4m.c | 2 +- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index eb491b50ca..a8d31c1ac6 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -61,12 +61,13 @@ /* XXX SCSI and ethernet should have different read-only bit masks */ #define DMA_CSR_RO_MASK 0xfe000007 -#define TYPE_SPARC32_DMA "sparc32_dma" -#define SPARC32_DMA(obj) OBJECT_CHECK(DMAState, (obj), TYPE_SPARC32_DMA) +#define TYPE_SPARC32_DMA_DEVICE "sparc32-dma-device" +#define SPARC32_DMA_DEVICE(obj) OBJECT_CHECK(DMADeviceState, (obj), \ + TYPE_SPARC32_DMA_DEVICE) -typedef struct DMAState DMAState; +typedef struct DMADeviceState DMADeviceState; -struct DMAState { +struct DMADeviceState { SysBusDevice parent_obj; MemoryRegion iomem; @@ -86,7 +87,7 @@ enum { void ledma_memory_read(void *opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap) { - DMAState *s = opaque; + DMADeviceState *s = opaque; int i; addr |= s->dmaregs[3]; @@ -106,7 +107,7 @@ void ledma_memory_read(void *opaque, hwaddr addr, void ledma_memory_write(void *opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap) { - DMAState *s = opaque; + DMADeviceState *s = opaque; int l, i; uint16_t tmp_buf[32]; @@ -134,7 +135,7 @@ void ledma_memory_write(void *opaque, hwaddr addr, static void dma_set_irq(void *opaque, int irq, int level) { - DMAState *s = opaque; + DMADeviceState *s = opaque; if (level) { s->dmaregs[0] |= DMA_INTR; if (s->dmaregs[0] & DMA_INTREN) { @@ -154,7 +155,7 @@ static void dma_set_irq(void *opaque, int irq, int level) void espdma_memory_read(void *opaque, uint8_t *buf, int len) { - DMAState *s = opaque; + DMADeviceState *s = opaque; trace_espdma_memory_read(s->dmaregs[1]); sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len); @@ -163,7 +164,7 @@ void espdma_memory_read(void *opaque, uint8_t *buf, int len) void espdma_memory_write(void *opaque, uint8_t *buf, int len) { - DMAState *s = opaque; + DMADeviceState *s = opaque; trace_espdma_memory_write(s->dmaregs[1]); sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len); @@ -173,7 +174,7 @@ void espdma_memory_write(void *opaque, uint8_t *buf, int len) static uint64_t dma_mem_read(void *opaque, hwaddr addr, unsigned size) { - DMAState *s = opaque; + DMADeviceState *s = opaque; uint32_t saddr; if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) { @@ -190,7 +191,7 @@ static uint64_t dma_mem_read(void *opaque, hwaddr addr, static void dma_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) { - DMAState *s = opaque; + DMADeviceState *s = opaque; uint32_t saddr; if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) { @@ -252,28 +253,28 @@ static const MemoryRegionOps dma_mem_ops = { }, }; -static void dma_reset(DeviceState *d) +static void sparc32_dma_device_reset(DeviceState *d) { - DMAState *s = SPARC32_DMA(d); + DMADeviceState *s = SPARC32_DMA_DEVICE(d); memset(s->dmaregs, 0, DMA_SIZE); s->dmaregs[0] = DMA_VER; } -static const VMStateDescription vmstate_dma = { +static const VMStateDescription vmstate_sparc32_dma_device = { .name ="sparc32_dma", .version_id = 2, .minimum_version_id = 2, .fields = (VMStateField[]) { - VMSTATE_UINT32_ARRAY(dmaregs, DMAState, DMA_REGS), + VMSTATE_UINT32_ARRAY(dmaregs, DMADeviceState, DMA_REGS), VMSTATE_END_OF_LIST() } }; -static void sparc32_dma_init(Object *obj) +static void sparc32_dma_device_init(Object *obj) { DeviceState *dev = DEVICE(obj); - DMAState *s = SPARC32_DMA(obj); + DMADeviceState *s = SPARC32_DMA_DEVICE(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); sysbus_init_irq(sbd, &s->irq); @@ -284,9 +285,9 @@ static void sparc32_dma_init(Object *obj) qdev_init_gpio_out(dev, s->gpio, 2); } -static void sparc32_dma_realize(DeviceState *dev, Error **errp) +static void sparc32_dma_device_realize(DeviceState *dev, Error **errp) { - DMAState *s = SPARC32_DMA(dev); + DMADeviceState *s = SPARC32_DMA_DEVICE(dev); int reg_size; reg_size = s->is_ledma ? DMA_ETH_SIZE : DMA_SIZE; @@ -294,35 +295,35 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp) "dma", reg_size); } -static Property sparc32_dma_properties[] = { - DEFINE_PROP_PTR("iommu_opaque", DMAState, iommu), - DEFINE_PROP_UINT32("is_ledma", DMAState, is_ledma, 0), +static Property sparc32_dma_device_properties[] = { + DEFINE_PROP_PTR("iommu_opaque", DMADeviceState, iommu), + DEFINE_PROP_UINT32("is_ledma", DMADeviceState, is_ledma, 0), DEFINE_PROP_END_OF_LIST(), }; -static void sparc32_dma_class_init(ObjectClass *klass, void *data) +static void sparc32_dma_device_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); - dc->reset = dma_reset; - dc->vmsd = &vmstate_dma; - dc->props = sparc32_dma_properties; - dc->realize = sparc32_dma_realize; + dc->reset = sparc32_dma_device_reset; + dc->vmsd = &vmstate_sparc32_dma_device; + dc->props = sparc32_dma_device_properties; + dc->realize = sparc32_dma_device_realize; /* Reason: pointer property "iommu_opaque" */ dc->user_creatable = false; } -static const TypeInfo sparc32_dma_info = { - .name = TYPE_SPARC32_DMA, +static const TypeInfo sparc32_dma_device_info = { + .name = TYPE_SPARC32_DMA_DEVICE, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(DMAState), - .instance_init = sparc32_dma_init, - .class_init = sparc32_dma_class_init, + .instance_size = sizeof(DMADeviceState), + .instance_init = sparc32_dma_device_init, + .class_init = sparc32_dma_device_class_init, }; static void sparc32_dma_register_types(void) { - type_register_static(&sparc32_dma_info); + type_register_static(&sparc32_dma_device_info); } type_init(sparc32_dma_register_types) diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 68b23784c5..92763935c1 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -312,7 +312,7 @@ static void *sparc32_dma_init(hwaddr daddr, qemu_irq parent_irq, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "sparc32_dma"); + dev = qdev_create(NULL, "sparc32-dma-device"); qdev_prop_set_ptr(dev, "iommu_opaque", iommu); qdev_prop_set_uint32(dev, "is_ledma", is_ledma); qdev_init_nofail(dev); From 52d39e5b67f0d75544837cac9c7be21873ed649f Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:21 +0100 Subject: [PATCH 02/17] sparc32_dma: split esp and le into separate DMA devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Due to slight differences in behaviour accessing the registers for the esp and le devices, create two separate SPARC32_DMA_DEVICE types and update the sun4m machine to use. Note that by using different device types we already know the size of the register block and the value of is_ledma at init time, allowing us to drop the SPARC32_DMA_DEVICE realize function and the is_ledma device property. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Acked-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/dma/sparc32_dma.c | 63 +++++++++++++++++++++++++++++++++++--------- hw/sparc/sun4m.c | 3 +-- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index a8d31c1ac6..e4ff4a8f7a 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -78,6 +78,22 @@ struct DMADeviceState { uint32_t is_ledma; }; +#define TYPE_SPARC32_ESPDMA_DEVICE "sparc32-espdma" +#define SPARC32_ESPDMA_DEVICE(obj) OBJECT_CHECK(ESPDMADeviceState, (obj), \ + TYPE_SPARC32_ESPDMA_DEVICE) + +typedef struct ESPDMADeviceState { + DMADeviceState parent_obj; +} ESPDMADeviceState; + +#define TYPE_SPARC32_LEDMA_DEVICE "sparc32-ledma" +#define SPARC32_LEDMA_DEVICE(obj) OBJECT_CHECK(LEDMADeviceState, (obj), \ + TYPE_SPARC32_LEDMA_DEVICE) + +typedef struct LEDMADeviceState { + DMADeviceState parent_obj; +} LEDMADeviceState; + enum { GPIO_RESET = 0, GPIO_DMA, @@ -285,19 +301,8 @@ static void sparc32_dma_device_init(Object *obj) qdev_init_gpio_out(dev, s->gpio, 2); } -static void sparc32_dma_device_realize(DeviceState *dev, Error **errp) -{ - DMADeviceState *s = SPARC32_DMA_DEVICE(dev); - int reg_size; - - reg_size = s->is_ledma ? DMA_ETH_SIZE : DMA_SIZE; - memory_region_init_io(&s->iomem, OBJECT(dev), &dma_mem_ops, s, - "dma", reg_size); -} - static Property sparc32_dma_device_properties[] = { DEFINE_PROP_PTR("iommu_opaque", DMADeviceState, iommu), - DEFINE_PROP_UINT32("is_ledma", DMADeviceState, is_ledma, 0), DEFINE_PROP_END_OF_LIST(), }; @@ -308,7 +313,6 @@ static void sparc32_dma_device_class_init(ObjectClass *klass, void *data) dc->reset = sparc32_dma_device_reset; dc->vmsd = &vmstate_sparc32_dma_device; dc->props = sparc32_dma_device_properties; - dc->realize = sparc32_dma_device_realize; /* Reason: pointer property "iommu_opaque" */ dc->user_creatable = false; } @@ -316,14 +320,49 @@ static void sparc32_dma_device_class_init(ObjectClass *klass, void *data) static const TypeInfo sparc32_dma_device_info = { .name = TYPE_SPARC32_DMA_DEVICE, .parent = TYPE_SYS_BUS_DEVICE, + .abstract = true, .instance_size = sizeof(DMADeviceState), .instance_init = sparc32_dma_device_init, .class_init = sparc32_dma_device_class_init, }; +static void sparc32_espdma_device_init(Object *obj) +{ + DMADeviceState *s = SPARC32_DMA_DEVICE(obj); + + memory_region_init_io(&s->iomem, OBJECT(s), &dma_mem_ops, s, + "espdma-mmio", DMA_SIZE); + s->is_ledma = 0; +} + +static const TypeInfo sparc32_espdma_device_info = { + .name = TYPE_SPARC32_ESPDMA_DEVICE, + .parent = TYPE_SPARC32_DMA_DEVICE, + .instance_size = sizeof(ESPDMADeviceState), + .instance_init = sparc32_espdma_device_init, +}; + +static void sparc32_ledma_device_init(Object *obj) +{ + DMADeviceState *s = SPARC32_DMA_DEVICE(obj); + + memory_region_init_io(&s->iomem, OBJECT(s), &dma_mem_ops, s, + "ledma-mmio", DMA_ETH_SIZE); + s->is_ledma = 1; +} + +static const TypeInfo sparc32_ledma_device_info = { + .name = TYPE_SPARC32_LEDMA_DEVICE, + .parent = TYPE_SPARC32_DMA_DEVICE, + .instance_size = sizeof(LEDMADeviceState), + .instance_init = sparc32_ledma_device_init, +}; + static void sparc32_dma_register_types(void) { type_register_static(&sparc32_dma_device_info); + type_register_static(&sparc32_espdma_device_info); + type_register_static(&sparc32_ledma_device_info); } type_init(sparc32_dma_register_types) diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 92763935c1..8593a8747f 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -312,9 +312,8 @@ static void *sparc32_dma_init(hwaddr daddr, qemu_irq parent_irq, DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "sparc32-dma-device"); + dev = qdev_create(NULL, is_ledma ? "sparc32-ledma" : "sparc32-espdma"); qdev_prop_set_ptr(dev, "iommu_opaque", iommu); - qdev_prop_set_uint32(dev, "is_ledma", is_ledma); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); sysbus_connect_irq(s, 0, parent_irq); From 9db2cf3f29a843829b9dff870948ddfb26eb1288 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:21 +0100 Subject: [PATCH 03/17] sparc32_dma: move type declarations from sparc32_dma.c to sparc32_dma.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Acked-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/dma/sparc32_dma.c | 34 ------------------------------- include/hw/sparc/sparc32_dma.h | 37 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index e4ff4a8f7a..ae8fa06962 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -40,7 +40,6 @@ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/DMA2.txt */ -#define DMA_REGS 4 #define DMA_SIZE (4 * sizeof(uint32_t)) /* We need the mask, because one instance of the device is not page aligned (ledma, start address 0x0010) */ @@ -61,39 +60,6 @@ /* XXX SCSI and ethernet should have different read-only bit masks */ #define DMA_CSR_RO_MASK 0xfe000007 -#define TYPE_SPARC32_DMA_DEVICE "sparc32-dma-device" -#define SPARC32_DMA_DEVICE(obj) OBJECT_CHECK(DMADeviceState, (obj), \ - TYPE_SPARC32_DMA_DEVICE) - -typedef struct DMADeviceState DMADeviceState; - -struct DMADeviceState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint32_t dmaregs[DMA_REGS]; - qemu_irq irq; - void *iommu; - qemu_irq gpio[2]; - uint32_t is_ledma; -}; - -#define TYPE_SPARC32_ESPDMA_DEVICE "sparc32-espdma" -#define SPARC32_ESPDMA_DEVICE(obj) OBJECT_CHECK(ESPDMADeviceState, (obj), \ - TYPE_SPARC32_ESPDMA_DEVICE) - -typedef struct ESPDMADeviceState { - DMADeviceState parent_obj; -} ESPDMADeviceState; - -#define TYPE_SPARC32_LEDMA_DEVICE "sparc32-ledma" -#define SPARC32_LEDMA_DEVICE(obj) OBJECT_CHECK(LEDMADeviceState, (obj), \ - TYPE_SPARC32_LEDMA_DEVICE) - -typedef struct LEDMADeviceState { - DMADeviceState parent_obj; -} LEDMADeviceState; - enum { GPIO_RESET = 0, GPIO_DMA, diff --git a/include/hw/sparc/sparc32_dma.h b/include/hw/sparc/sparc32_dma.h index 9497b13d34..df7491dfd6 100644 --- a/include/hw/sparc/sparc32_dma.h +++ b/include/hw/sparc/sparc32_dma.h @@ -1,6 +1,43 @@ #ifndef SPARC32_DMA_H #define SPARC32_DMA_H +#include "hw/sysbus.h" + +#define DMA_REGS 4 + +#define TYPE_SPARC32_DMA_DEVICE "sparc32-dma-device" +#define SPARC32_DMA_DEVICE(obj) OBJECT_CHECK(DMADeviceState, (obj), \ + TYPE_SPARC32_DMA_DEVICE) + +typedef struct DMADeviceState DMADeviceState; + +struct DMADeviceState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + uint32_t dmaregs[DMA_REGS]; + qemu_irq irq; + void *iommu; + qemu_irq gpio[2]; + uint32_t is_ledma; +}; + +#define TYPE_SPARC32_ESPDMA_DEVICE "sparc32-espdma" +#define SPARC32_ESPDMA_DEVICE(obj) OBJECT_CHECK(ESPDMADeviceState, (obj), \ + TYPE_SPARC32_ESPDMA_DEVICE) + +typedef struct ESPDMADeviceState { + DMADeviceState parent_obj; +} ESPDMADeviceState; + +#define TYPE_SPARC32_LEDMA_DEVICE "sparc32-ledma" +#define SPARC32_LEDMA_DEVICE(obj) OBJECT_CHECK(LEDMADeviceState, (obj), \ + TYPE_SPARC32_LEDMA_DEVICE) + +typedef struct LEDMADeviceState { + DMADeviceState parent_obj; +} LEDMADeviceState; + /* sparc32_dma.c */ void ledma_memory_read(void *opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap); From 9540619d82da44d5c0a1e8895598461b8d5e3dca Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:21 +0100 Subject: [PATCH 04/17] sun4m: move DMA device wiring from sparc32_dma_init() to sun4m_hw_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using the sysbus interface it is possible to wire up the esp/le devices to the sun4m DMA controller directly during sun4m_hw_init() instead of passing qemu_irqs into the sparc32_dma_init() function. This is an intermediate step to allow further reorganisation as more logic is moved into the relevant SPARC32 DMA devices; there will be a final refactoring of sparc32_dma_init() once this work is complete. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/sparc/sun4m.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 8593a8747f..67d771ce5d 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -306,8 +306,7 @@ static void *iommu_init(hwaddr addr, uint32_t version, qemu_irq irq) return s; } -static void *sparc32_dma_init(hwaddr daddr, qemu_irq parent_irq, - void *iommu, qemu_irq *dev_irq, int is_ledma) +static void *sparc32_dma_init(hwaddr daddr, void *iommu, int is_ledma) { DeviceState *dev; SysBusDevice *s; @@ -316,8 +315,6 @@ static void *sparc32_dma_init(hwaddr daddr, qemu_irq parent_irq, qdev_prop_set_ptr(dev, "iommu_opaque", iommu); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); - sysbus_connect_irq(s, 0, parent_irq); - *dev_irq = qdev_get_gpio_in(dev, 0); sysbus_mmio_map(s, 0, daddr); return s; @@ -819,9 +816,10 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, { DeviceState *slavio_intctl; unsigned int i; - void *iommu, *espdma, *ledma, *nvram; - qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS], - espdma_irq, ledma_irq; + void *iommu, *nvram; + DeviceState *espdma, *ledma; + SysBusDevice *sbd; + qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS]; qemu_irq esp_reset, dma_enable; qemu_irq fdc_tc; unsigned long kernel_size; @@ -877,11 +875,13 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, empty_slot_init(hwdef->iommu_pad_base,hwdef->iommu_pad_len); } - espdma = sparc32_dma_init(hwdef->dma_base, slavio_irq[18], - iommu, &espdma_irq, 0); + espdma = sparc32_dma_init(hwdef->dma_base, iommu, 0); + sbd = SYS_BUS_DEVICE(espdma); + sysbus_connect_irq(sbd, 0, slavio_irq[18]); - ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, - slavio_irq[16], iommu, &ledma_irq, 1); + ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, iommu, 1); + sbd = SYS_BUS_DEVICE(ledma); + sysbus_connect_irq(sbd, 0, slavio_irq[16]); if (graphic_depth != 8 && graphic_depth != 24) { error_report("Unsupported depth: %d", graphic_depth); @@ -934,7 +934,8 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, empty_slot_init(hwdef->sx_base, 0x2000); } - lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq); + lance_init(&nd_table[0], hwdef->le_base, ledma, + qdev_get_gpio_in(ledma, 0)); nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x2000, 1968, 8); @@ -966,7 +967,9 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, esp_init(hwdef->esp_base, 2, espdma_memory_read, espdma_memory_write, - espdma, espdma_irq, &esp_reset, &dma_enable); + espdma, + qdev_get_gpio_in(espdma, 0), + &esp_reset, &dma_enable); qdev_connect_gpio_out(espdma, 0, esp_reset); qdev_connect_gpio_out(espdma, 1, dma_enable); From 9227f296a9be63f946bf8e552f24527a63a75b6d Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:21 +0100 Subject: [PATCH 05/17] sun4m_iommu: move TYPE_SUN4M_IOMMU declaration to sun4m.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is in preparation to allow the type to be used elsewhere. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/dma/sun4m_iommu.c | 14 -------------- include/hw/sparc/sun4m.h | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/hw/dma/sun4m_iommu.c b/hw/dma/sun4m_iommu.c index 335ef63cbc..840064b5e2 100644 --- a/hw/dma/sun4m_iommu.c +++ b/hw/dma/sun4m_iommu.c @@ -36,7 +36,6 @@ * http://mediacast.sun.com/users/Barton808/media/Sun4M_SystemArchitecture_edited2.pdf */ -#define IOMMU_NREGS (4*4096/4) #define IOMMU_CTRL (0x0000 >> 2) #define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */ #define IOMMU_CTRL_VERS 0x0f000000 /* Version */ @@ -128,19 +127,6 @@ #define IOMMU_PAGE_SIZE (1 << IOMMU_PAGE_SHIFT) #define IOMMU_PAGE_MASK ~(IOMMU_PAGE_SIZE - 1) -#define TYPE_SUN4M_IOMMU "iommu" -#define SUN4M_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4M_IOMMU) - -typedef struct IOMMUState { - SysBusDevice parent_obj; - - MemoryRegion iomem; - uint32_t regs[IOMMU_NREGS]; - hwaddr iostart; - qemu_irq irq; - uint32_t version; -} IOMMUState; - static uint64_t iommu_mem_read(void *opaque, hwaddr addr, unsigned size) { diff --git a/include/hw/sparc/sun4m.h b/include/hw/sparc/sun4m.h index 580d87b252..1f1cf91ed9 100644 --- a/include/hw/sparc/sun4m.h +++ b/include/hw/sparc/sun4m.h @@ -4,10 +4,26 @@ #include "qemu-common.h" #include "exec/hwaddr.h" #include "qapi/qmp/types.h" +#include "hw/sysbus.h" /* Devices used by sparc32 system. */ /* iommu.c */ +#define TYPE_SUN4M_IOMMU "iommu" +#define SUN4M_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4M_IOMMU) + +#define IOMMU_NREGS (4 * 4096 / 4) + +typedef struct IOMMUState { + SysBusDevice parent_obj; + + MemoryRegion iomem; + uint32_t regs[IOMMU_NREGS]; + hwaddr iostart; + qemu_irq irq; + uint32_t version; +} IOMMUState; + void sparc_iommu_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write); static inline void sparc_iommu_memory_read(void *opaque, From f542ad03888ff0fad87db269186b79fe2ce1823b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:21 +0100 Subject: [PATCH 06/17] sparc32_dma: use object link instead of qdev property to pass IOMMU reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables us to remove the last remaining (opaque) qdev property. Whilst we are here, also update iommu_init() to use TYPE_SUN4M_IOMMU instead of a hardcoded string. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/dma/sparc32_dma.c | 13 +++++-------- hw/sparc/sun4m.c | 4 ++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index ae8fa06962..c56a2ba139 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -263,24 +263,21 @@ static void sparc32_dma_device_init(Object *obj) sysbus_init_mmio(sbd, &s->iomem); + object_property_add_link(OBJECT(dev), "iommu", TYPE_SUN4M_IOMMU, + (Object **) &s->iommu, + qdev_prop_allow_set_link_before_realize, + 0, NULL); + qdev_init_gpio_in(dev, dma_set_irq, 1); qdev_init_gpio_out(dev, s->gpio, 2); } -static Property sparc32_dma_device_properties[] = { - DEFINE_PROP_PTR("iommu_opaque", DMADeviceState, iommu), - DEFINE_PROP_END_OF_LIST(), -}; - static void sparc32_dma_device_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); dc->reset = sparc32_dma_device_reset; dc->vmsd = &vmstate_sparc32_dma_device; - dc->props = sparc32_dma_device_properties; - /* Reason: pointer property "iommu_opaque" */ - dc->user_creatable = false; } static const TypeInfo sparc32_dma_device_info = { diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 67d771ce5d..e06e408390 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -296,7 +296,7 @@ static void *iommu_init(hwaddr addr, uint32_t version, qemu_irq irq) DeviceState *dev; SysBusDevice *s; - dev = qdev_create(NULL, "iommu"); + dev = qdev_create(NULL, TYPE_SUN4M_IOMMU); qdev_prop_set_uint32(dev, "version", version); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); @@ -312,7 +312,7 @@ static void *sparc32_dma_init(hwaddr daddr, void *iommu, int is_ledma) SysBusDevice *s; dev = qdev_create(NULL, is_ledma ? "sparc32-ledma" : "sparc32-espdma"); - qdev_prop_set_ptr(dev, "iommu_opaque", iommu); + object_property_set_link(OBJECT(dev), OBJECT(iommu), "iommu", &error_abort); qdev_init_nofail(dev); s = SYS_BUS_DEVICE(dev); sysbus_mmio_map(s, 0, daddr); From 1b13a60c1c15d7d69164f6d89465915838ddc07b Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:22 +0100 Subject: [PATCH 07/17] esp: move TYPE_ESP and SysBusESPState from esp.c to esp.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables them to be used outside of esp.c. Signed-off-by: Mark Cave-Ayland CC: Paolo Bonzini Reviewed-by: Artyom Tarasenko Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/scsi/esp.c | 13 ------------- include/hw/scsi/esp.h | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c index 22c2d91e39..ee586e7d6c 100644 --- a/hw/scsi/esp.c +++ b/hw/scsi/esp.c @@ -592,19 +592,6 @@ const VMStateDescription vmstate_esp = { } }; -#define TYPE_ESP "esp" -#define ESP_STATE(obj) OBJECT_CHECK(SysBusESPState, (obj), TYPE_ESP) - -typedef struct { - /*< private >*/ - SysBusDevice parent_obj; - /*< public >*/ - - MemoryRegion iomem; - uint32_t it_shift; - ESPState esp; -} SysBusESPState; - static void sysbus_esp_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size) { diff --git a/include/hw/scsi/esp.h b/include/hw/scsi/esp.h index d2c48869e1..3b160f858c 100644 --- a/include/hw/scsi/esp.h +++ b/include/hw/scsi/esp.h @@ -2,6 +2,7 @@ #define QEMU_HW_ESP_H #include "hw/scsi/scsi.h" +#include "hw/sysbus.h" /* esp.c */ #define ESP_MAX_DEVS 7 @@ -52,6 +53,19 @@ struct ESPState { void (*dma_cb)(ESPState *s); }; +#define TYPE_ESP "esp" +#define ESP_STATE(obj) OBJECT_CHECK(SysBusESPState, (obj), TYPE_ESP) + +typedef struct { + /*< private >*/ + SysBusDevice parent_obj; + /*< public >*/ + + MemoryRegion iomem; + uint32_t it_shift; + ESPState esp; +} SysBusESPState; + #define ESP_TCLO 0x0 #define ESP_TCMID 0x1 #define ESP_FIFO 0x2 From 7f773ff5d0d2172a7fb4a16a283c1fc5965f6fac Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:22 +0100 Subject: [PATCH 08/17] sparc32_dma: make esp device child of espdma device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes it possible to reference the esp device from the espdma device as required, and by wiring up the device ourselves in sun4m.c we can drop use of the esp_init() function. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Acked-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/dma/sparc32_dma.c | 26 ++++++++++++++++++++++++++ hw/sparc/sun4m.c | 19 ++++++++----------- include/hw/sparc/sparc32_dma.h | 3 +++ 3 files changed, 37 insertions(+), 11 deletions(-) diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index c56a2ba139..6009b94473 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -298,11 +298,37 @@ static void sparc32_espdma_device_init(Object *obj) s->is_ledma = 0; } +static void sparc32_espdma_device_realize(DeviceState *dev, Error **errp) +{ + DeviceState *d; + SysBusESPState *sysbus; + ESPState *esp; + + d = qdev_create(NULL, TYPE_ESP); + object_property_add_child(OBJECT(dev), "esp", OBJECT(d), errp); + sysbus = ESP_STATE(d); + esp = &sysbus->esp; + esp->dma_memory_read = espdma_memory_read; + esp->dma_memory_write = espdma_memory_write; + esp->dma_opaque = SPARC32_DMA_DEVICE(dev); + sysbus->it_shift = 2; + esp->dma_enabled = 1; + qdev_init_nofail(d); +} + +static void sparc32_espdma_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = sparc32_espdma_device_realize; +} + static const TypeInfo sparc32_espdma_device_info = { .name = TYPE_SPARC32_ESPDMA_DEVICE, .parent = TYPE_SPARC32_DMA_DEVICE, .instance_size = sizeof(ESPDMADeviceState), .instance_init = sparc32_espdma_device_init, + .class_init = sparc32_espdma_device_class_init, }; static void sparc32_ledma_device_init(Object *obj) diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index e06e408390..26ef35ab62 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -817,10 +817,9 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, DeviceState *slavio_intctl; unsigned int i; void *iommu, *nvram; - DeviceState *espdma, *ledma; + DeviceState *espdma, *esp, *ledma; SysBusDevice *sbd; qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS]; - qemu_irq esp_reset, dma_enable; qemu_irq fdc_tc; unsigned long kernel_size; DriveInfo *fd[MAX_FD]; @@ -879,6 +878,13 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, sbd = SYS_BUS_DEVICE(espdma); sysbus_connect_irq(sbd, 0, slavio_irq[18]); + esp = DEVICE(object_resolve_path_component(OBJECT(espdma), "esp")); + sbd = SYS_BUS_DEVICE(esp); + sysbus_mmio_map(sbd, 0, hwdef->esp_base); + sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(espdma, 0)); + qdev_connect_gpio_out(espdma, 0, qdev_get_gpio_in(esp, 0)); + qdev_connect_gpio_out(espdma, 1, qdev_get_gpio_in(esp, 1)); + ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, iommu, 1); sbd = SYS_BUS_DEVICE(ledma); sysbus_connect_irq(sbd, 0, slavio_irq[16]); @@ -965,15 +971,6 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, slavio_misc_init(hwdef->slavio_base, hwdef->aux1_base, hwdef->aux2_base, slavio_irq[30], fdc_tc); - esp_init(hwdef->esp_base, 2, - espdma_memory_read, espdma_memory_write, - espdma, - qdev_get_gpio_in(espdma, 0), - &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, slavio_irq[5]); diff --git a/include/hw/sparc/sparc32_dma.h b/include/hw/sparc/sparc32_dma.h index df7491dfd6..365160f2d1 100644 --- a/include/hw/sparc/sparc32_dma.h +++ b/include/hw/sparc/sparc32_dma.h @@ -2,6 +2,7 @@ #define SPARC32_DMA_H #include "hw/sysbus.h" +#include "hw/scsi/esp.h" #define DMA_REGS 4 @@ -28,6 +29,8 @@ struct DMADeviceState { typedef struct ESPDMADeviceState { DMADeviceState parent_obj; + + SysBusESPState *esp; } ESPDMADeviceState; #define TYPE_SPARC32_LEDMA_DEVICE "sparc32-ledma" From 76d28ca7653b69df5e9a4e11b2d15cbe885e5698 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:22 +0100 Subject: [PATCH 09/17] lance: move TYPE_LANCE and SysBusPCNetState from lance.c to lance.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This enables them to be used outside of lance.c. We also update the comment to refer to the SPARC32 lance device rather than the AMD PCNet-II device (of which lance is a register-compatible subset). Signed-off-by: Mark Cave-Ayland CC: Jason Wang Reviewed-by: Peter Maydell Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/net/lance.c | 11 +---------- include/hw/net/lance.h | 45 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 10 deletions(-) create mode 100644 include/hw/net/lance.h diff --git a/hw/net/lance.c b/hw/net/lance.c index 92b0c68274..23929fd1e6 100644 --- a/hw/net/lance.c +++ b/hw/net/lance.c @@ -41,19 +41,10 @@ #include "qemu/timer.h" #include "qemu/sockets.h" #include "hw/sparc/sun4m.h" -#include "pcnet.h" +#include "hw/net/lance.h" #include "trace.h" #include "sysemu/sysemu.h" -#define TYPE_LANCE "lance" -#define SYSBUS_PCNET(obj) \ - OBJECT_CHECK(SysBusPCNetState, (obj), TYPE_LANCE) - -typedef struct { - SysBusDevice parent_obj; - - PCNetState state; -} SysBusPCNetState; static void parent_lance_reset(void *opaque, int irq, int level) { diff --git a/include/hw/net/lance.h b/include/hw/net/lance.h new file mode 100644 index 0000000000..ffdd35c4d7 --- /dev/null +++ b/include/hw/net/lance.h @@ -0,0 +1,45 @@ +/* + * QEMU Lance (Am7990) device emulation + * + * Copyright (c) 2004 Antony T Curtis + * Copyright (c) 2017 Mark Cave-Ayland + * + * This represents the Sparc32 lance (Am7990) ethernet device which is an + * earlier register-compatible member of the AMD PC-Net II (Am79C970A) family. + * + * 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. + */ + +#ifndef LANCE_H +#define LANCE_H + +#include "net/net.h" +#include "hw/net/pcnet.h" + +#define TYPE_LANCE "lance" +#define SYSBUS_PCNET(obj) \ + OBJECT_CHECK(SysBusPCNetState, (obj), TYPE_LANCE) + +typedef struct { + SysBusDevice parent_obj; + + PCNetState state; +} SysBusPCNetState; + +#endif From e6ca02a46ae0fafe59544b789e9172efa1a929c1 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:22 +0100 Subject: [PATCH 10/17] sparc32_dma: make lance device child of ledma device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes it possible to reference the lance device from the ledma device as required. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Acked-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/dma/sparc32_dma.c | 22 ++++++++++++++++++++++ hw/sparc/sun4m.c | 31 +++++++------------------------ include/hw/sparc/sparc32_dma.h | 3 +++ 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index 6009b94473..d4cff74871 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -340,11 +340,33 @@ static void sparc32_ledma_device_init(Object *obj) s->is_ledma = 1; } +static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp) +{ + DeviceState *d; + NICInfo *nd = &nd_table[0]; + + qemu_check_nic_model(nd, TYPE_LANCE); + + d = qdev_create(NULL, TYPE_LANCE); + object_property_add_child(OBJECT(dev), "lance", OBJECT(d), errp); + qdev_set_nic_properties(d, nd); + qdev_prop_set_ptr(d, "dma", dev); + qdev_init_nofail(d); +} + +static void sparc32_ledma_device_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = sparc32_ledma_device_realize; +} + static const TypeInfo sparc32_ledma_device_info = { .name = TYPE_SPARC32_LEDMA_DEVICE, .parent = TYPE_SPARC32_DMA_DEVICE, .instance_size = sizeof(LEDMADeviceState), .instance_init = sparc32_ledma_device_init, + .class_init = sparc32_ledma_device_class_init, }; static void sparc32_dma_register_types(void) diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 26ef35ab62..e091e2e7f0 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -320,26 +320,6 @@ static void *sparc32_dma_init(hwaddr daddr, void *iommu, int is_ledma) return s; } -static void lance_init(NICInfo *nd, hwaddr leaddr, - void *dma_opaque, qemu_irq irq) -{ - DeviceState *dev; - SysBusDevice *s; - qemu_irq reset; - - qemu_check_nic_model(&nd_table[0], "lance"); - - dev = qdev_create(NULL, "lance"); - qdev_set_nic_properties(dev, nd); - qdev_prop_set_ptr(dev, "dma", dma_opaque); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(s, 0, leaddr); - sysbus_connect_irq(s, 0, irq); - reset = qdev_get_gpio_in(dev, 0); - qdev_connect_gpio_out(dma_opaque, 0, reset); -} - static DeviceState *slavio_intctl_init(hwaddr addr, hwaddr addrg, qemu_irq **parent_irq) @@ -817,7 +797,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, DeviceState *slavio_intctl; unsigned int i; void *iommu, *nvram; - DeviceState *espdma, *esp, *ledma; + DeviceState *espdma, *esp, *ledma, *lance; SysBusDevice *sbd; qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS]; qemu_irq fdc_tc; @@ -889,6 +869,12 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, sbd = SYS_BUS_DEVICE(ledma); sysbus_connect_irq(sbd, 0, slavio_irq[16]); + lance = DEVICE(object_resolve_path_component(OBJECT(ledma), "lance")); + sbd = SYS_BUS_DEVICE(lance); + sysbus_mmio_map(sbd, 0, hwdef->le_base); + sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(ledma, 0)); + qdev_connect_gpio_out(ledma, 0, qdev_get_gpio_in(lance, 0)); + if (graphic_depth != 8 && graphic_depth != 24) { error_report("Unsupported depth: %d", graphic_depth); exit (1); @@ -940,9 +926,6 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, empty_slot_init(hwdef->sx_base, 0x2000); } - lance_init(&nd_table[0], hwdef->le_base, ledma, - qdev_get_gpio_in(ledma, 0)); - nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x2000, 1968, 8); slavio_timer_init_all(hwdef->counter_base, slavio_irq[19], slavio_cpu_irq, smp_cpus); diff --git a/include/hw/sparc/sparc32_dma.h b/include/hw/sparc/sparc32_dma.h index 365160f2d1..5e39d81c8c 100644 --- a/include/hw/sparc/sparc32_dma.h +++ b/include/hw/sparc/sparc32_dma.h @@ -3,6 +3,7 @@ #include "hw/sysbus.h" #include "hw/scsi/esp.h" +#include "hw/net/lance.h" #define DMA_REGS 4 @@ -39,6 +40,8 @@ typedef struct ESPDMADeviceState { typedef struct LEDMADeviceState { DMADeviceState parent_obj; + + SysBusPCNetState *lance; } LEDMADeviceState; /* sparc32_dma.c */ From 6aa62ed6b8cef3623083b1a90cecfb854f7c4a79 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:22 +0100 Subject: [PATCH 11/17] sparc32_dma: introduce new SPARC32_DMA type container object MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a new SPARC32_DMA container object (including an appropriate container memory region) and add instances of the SPARC32_ESPDMA_DEVICE and SPARC32_LEDMA_DEVICE as child objects. The benefit is that most of the gpio wiring complexity between esp/espdma and lance/ledma is now hidden within the SPARC32_DMA realize function. Since the sun4m IOMMU is already QOMified we can find a reference to it using object_resolve_path_type() allowing us to completely remove all external references to the iommu pointer. Finally we rework sun4m's sparc32_dma_init() to invoke the new SPARC32_DMA object and wire up the remaining board memory regions/IRQs. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Acked-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/dma/sparc32_dma.c | 70 ++++++++++++++++++++++++++++++++++ hw/sparc/sun4m.c | 66 ++++++++++++++++---------------- include/hw/sparc/sparc32_dma.h | 12 ++++++ 3 files changed, 114 insertions(+), 34 deletions(-) diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index d4cff74871..582b7cc976 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -30,6 +30,7 @@ #include "hw/sparc/sparc32_dma.h" #include "hw/sparc/sun4m.h" #include "hw/sysbus.h" +#include "qapi/error.h" #include "trace.h" /* @@ -369,11 +370,80 @@ static const TypeInfo sparc32_ledma_device_info = { .class_init = sparc32_ledma_device_class_init, }; +static void sparc32_dma_realize(DeviceState *dev, Error **errp) +{ + SPARC32DMAState *s = SPARC32_DMA(dev); + DeviceState *espdma, *esp, *ledma, *lance; + SysBusDevice *sbd; + Object *iommu; + + iommu = object_resolve_path_type("", TYPE_SUN4M_IOMMU, NULL); + if (!iommu) { + error_setg(errp, "unable to locate sun4m IOMMU device"); + return; + } + + espdma = qdev_create(NULL, TYPE_SPARC32_ESPDMA_DEVICE); + object_property_set_link(OBJECT(espdma), iommu, "iommu", errp); + object_property_add_child(OBJECT(s), "espdma", OBJECT(espdma), errp); + qdev_init_nofail(espdma); + + esp = DEVICE(object_resolve_path_component(OBJECT(espdma), "esp")); + sbd = SYS_BUS_DEVICE(esp); + sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(espdma, 0)); + qdev_connect_gpio_out(espdma, 0, qdev_get_gpio_in(esp, 0)); + qdev_connect_gpio_out(espdma, 1, qdev_get_gpio_in(esp, 1)); + + sbd = SYS_BUS_DEVICE(espdma); + memory_region_add_subregion(&s->dmamem, 0x0, + sysbus_mmio_get_region(sbd, 0)); + + ledma = qdev_create(NULL, TYPE_SPARC32_LEDMA_DEVICE); + object_property_set_link(OBJECT(ledma), iommu, "iommu", errp); + object_property_add_child(OBJECT(s), "ledma", OBJECT(ledma), errp); + qdev_init_nofail(ledma); + + lance = DEVICE(object_resolve_path_component(OBJECT(ledma), "lance")); + sbd = SYS_BUS_DEVICE(lance); + sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(ledma, 0)); + qdev_connect_gpio_out(ledma, 0, qdev_get_gpio_in(lance, 0)); + + sbd = SYS_BUS_DEVICE(ledma); + memory_region_add_subregion(&s->dmamem, 0x10, + sysbus_mmio_get_region(sbd, 0)); +} + +static void sparc32_dma_init(Object *obj) +{ + SPARC32DMAState *s = SPARC32_DMA(obj); + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + + memory_region_init(&s->dmamem, OBJECT(s), "dma", DMA_SIZE + DMA_ETH_SIZE); + sysbus_init_mmio(sbd, &s->dmamem); +} + +static void sparc32_dma_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = sparc32_dma_realize; +} + +static const TypeInfo sparc32_dma_info = { + .name = TYPE_SPARC32_DMA, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SPARC32DMAState), + .instance_init = sparc32_dma_init, + .class_init = sparc32_dma_class_init, +}; + + static void sparc32_dma_register_types(void) { type_register_static(&sparc32_dma_device_info); type_register_static(&sparc32_espdma_device_info); type_register_static(&sparc32_ledma_device_info); + type_register_static(&sparc32_dma_info); } type_init(sparc32_dma_register_types) diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index e091e2e7f0..24c2b8a555 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -306,18 +306,36 @@ static void *iommu_init(hwaddr addr, uint32_t version, qemu_irq irq) return s; } -static void *sparc32_dma_init(hwaddr daddr, void *iommu, int is_ledma) +static void *sparc32_dma_init(hwaddr dma_base, + hwaddr esp_base, qemu_irq espdma_irq, + hwaddr le_base, qemu_irq ledma_irq) { - DeviceState *dev; - SysBusDevice *s; + DeviceState *dma; + ESPDMADeviceState *espdma; + LEDMADeviceState *ledma; + SysBusESPState *esp; + SysBusPCNetState *lance; - dev = qdev_create(NULL, is_ledma ? "sparc32-ledma" : "sparc32-espdma"); - object_property_set_link(OBJECT(dev), OBJECT(iommu), "iommu", &error_abort); - qdev_init_nofail(dev); - s = SYS_BUS_DEVICE(dev); - sysbus_mmio_map(s, 0, daddr); + dma = qdev_create(NULL, TYPE_SPARC32_DMA); + qdev_init_nofail(dma); + sysbus_mmio_map(SYS_BUS_DEVICE(dma), 0, dma_base); - return s; + espdma = SPARC32_ESPDMA_DEVICE(object_resolve_path_component( + OBJECT(dma), "espdma")); + sysbus_connect_irq(SYS_BUS_DEVICE(espdma), 0, espdma_irq); + + esp = ESP_STATE(object_resolve_path_component(OBJECT(espdma), "esp")); + sysbus_mmio_map(SYS_BUS_DEVICE(esp), 0, esp_base); + + ledma = SPARC32_LEDMA_DEVICE(object_resolve_path_component( + OBJECT(dma), "ledma")); + sysbus_connect_irq(SYS_BUS_DEVICE(ledma), 0, ledma_irq); + + lance = SYSBUS_PCNET(object_resolve_path_component( + OBJECT(ledma), "lance")); + sysbus_mmio_map(SYS_BUS_DEVICE(lance), 0, le_base); + + return dma; } static DeviceState *slavio_intctl_init(hwaddr addr, @@ -796,9 +814,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, { DeviceState *slavio_intctl; unsigned int i; - void *iommu, *nvram; - DeviceState *espdma, *esp, *ledma, *lance; - SysBusDevice *sbd; + void *nvram; qemu_irq *cpu_irqs[MAX_CPUS], slavio_irq[32], slavio_cpu_irq[MAX_CPUS]; qemu_irq fdc_tc; unsigned long kernel_size; @@ -843,8 +859,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, afx_init(hwdef->afx_base); } - iommu = iommu_init(hwdef->iommu_base, hwdef->iommu_version, - slavio_irq[30]); + iommu_init(hwdef->iommu_base, hwdef->iommu_version, slavio_irq[30]); if (hwdef->iommu_pad_base) { /* On the real hardware (SS-5, LX) the MMU is not padded, but aliased. @@ -854,26 +869,9 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, empty_slot_init(hwdef->iommu_pad_base,hwdef->iommu_pad_len); } - espdma = sparc32_dma_init(hwdef->dma_base, iommu, 0); - sbd = SYS_BUS_DEVICE(espdma); - sysbus_connect_irq(sbd, 0, slavio_irq[18]); - - esp = DEVICE(object_resolve_path_component(OBJECT(espdma), "esp")); - sbd = SYS_BUS_DEVICE(esp); - sysbus_mmio_map(sbd, 0, hwdef->esp_base); - sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(espdma, 0)); - qdev_connect_gpio_out(espdma, 0, qdev_get_gpio_in(esp, 0)); - qdev_connect_gpio_out(espdma, 1, qdev_get_gpio_in(esp, 1)); - - ledma = sparc32_dma_init(hwdef->dma_base + 16ULL, iommu, 1); - sbd = SYS_BUS_DEVICE(ledma); - sysbus_connect_irq(sbd, 0, slavio_irq[16]); - - lance = DEVICE(object_resolve_path_component(OBJECT(ledma), "lance")); - sbd = SYS_BUS_DEVICE(lance); - sysbus_mmio_map(sbd, 0, hwdef->le_base); - sysbus_connect_irq(sbd, 0, qdev_get_gpio_in(ledma, 0)); - qdev_connect_gpio_out(ledma, 0, qdev_get_gpio_in(lance, 0)); + sparc32_dma_init(hwdef->dma_base, + hwdef->esp_base, slavio_irq[18], + hwdef->le_base, slavio_irq[16]); if (graphic_depth != 8 && graphic_depth != 24) { error_report("Unsupported depth: %d", graphic_depth); diff --git a/include/hw/sparc/sparc32_dma.h b/include/hw/sparc/sparc32_dma.h index 5e39d81c8c..5deeca6c12 100644 --- a/include/hw/sparc/sparc32_dma.h +++ b/include/hw/sparc/sparc32_dma.h @@ -44,6 +44,18 @@ typedef struct LEDMADeviceState { SysBusPCNetState *lance; } LEDMADeviceState; +#define TYPE_SPARC32_DMA "sparc32-dma" +#define SPARC32_DMA(obj) OBJECT_CHECK(SPARC32DMAState, (obj), \ + TYPE_SPARC32_DMA) + +typedef struct SPARC32DMAState { + SysBusDevice parent_obj; + + MemoryRegion dmamem; + ESPDMADeviceState *espdma; + LEDMADeviceState *ledma; +} SPARC32DMAState; + /* sparc32_dma.c */ void ledma_memory_read(void *opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap); From 4ca3d368d2a66e6e0739fd1cb4552e68d060d337 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:22 +0100 Subject: [PATCH 12/17] sparc32_dma: remove is_ledma hack and replace with memory region alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This hack originated from before the memory region API was introduced, and increased the size of the ledma DMA device to capture incorrect accesses beyond the end of the ledma device. A full analysis can be found on Artyom's blog at http://tyom.blogspot.co.uk/2010/10/bug-in-all-solaris-versions-after-57.html. With the memory API we can now simply alias the incorrect access onto its intended destination allowing us to remove the hack. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/dma/sparc32_dma.c | 20 ++++++-------------- include/hw/sparc/sparc32_dma.h | 2 +- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index 582b7cc976..f64787e904 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -160,12 +160,6 @@ static uint64_t dma_mem_read(void *opaque, hwaddr addr, DMADeviceState *s = opaque; uint32_t saddr; - if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) { - /* aliased to espdma, but we can't get there from here */ - /* buggy driver if using undocumented behavior, just return 0 */ - trace_sparc32_dma_mem_readl(addr, 0); - return 0; - } saddr = (addr & DMA_MASK) >> 2; trace_sparc32_dma_mem_readl(addr, s->dmaregs[saddr]); return s->dmaregs[saddr]; @@ -177,11 +171,6 @@ static void dma_mem_write(void *opaque, hwaddr addr, DMADeviceState *s = opaque; uint32_t saddr; - if (s->is_ledma && (addr > DMA_MAX_REG_OFFSET)) { - /* aliased to espdma, but we can't get there from here */ - trace_sparc32_dma_mem_writel(addr, 0, val); - return; - } saddr = (addr & DMA_MASK) >> 2; trace_sparc32_dma_mem_writel(addr, s->dmaregs[saddr], val); switch (saddr) { @@ -296,7 +285,6 @@ static void sparc32_espdma_device_init(Object *obj) memory_region_init_io(&s->iomem, OBJECT(s), &dma_mem_ops, s, "espdma-mmio", DMA_SIZE); - s->is_ledma = 0; } static void sparc32_espdma_device_realize(DeviceState *dev, Error **errp) @@ -337,8 +325,7 @@ static void sparc32_ledma_device_init(Object *obj) DMADeviceState *s = SPARC32_DMA_DEVICE(obj); memory_region_init_io(&s->iomem, OBJECT(s), &dma_mem_ops, s, - "ledma-mmio", DMA_ETH_SIZE); - s->is_ledma = 1; + "ledma-mmio", DMA_SIZE); } static void sparc32_ledma_device_realize(DeviceState *dev, Error **errp) @@ -411,6 +398,11 @@ static void sparc32_dma_realize(DeviceState *dev, Error **errp) sbd = SYS_BUS_DEVICE(ledma); memory_region_add_subregion(&s->dmamem, 0x10, sysbus_mmio_get_region(sbd, 0)); + + /* Add ledma alias to handle SunOS 5.7 - Solaris 9 invalid access bug */ + memory_region_init_alias(&s->ledma_alias, OBJECT(dev), "ledma-alias", + sysbus_mmio_get_region(sbd, 0), 0x4, 0x4); + memory_region_add_subregion(&s->dmamem, 0x20, &s->ledma_alias); } static void sparc32_dma_init(Object *obj) diff --git a/include/hw/sparc/sparc32_dma.h b/include/hw/sparc/sparc32_dma.h index 5deeca6c12..ab42c5421b 100644 --- a/include/hw/sparc/sparc32_dma.h +++ b/include/hw/sparc/sparc32_dma.h @@ -21,7 +21,6 @@ struct DMADeviceState { qemu_irq irq; void *iommu; qemu_irq gpio[2]; - uint32_t is_ledma; }; #define TYPE_SPARC32_ESPDMA_DEVICE "sparc32-espdma" @@ -52,6 +51,7 @@ typedef struct SPARC32DMAState { SysBusDevice parent_obj; MemoryRegion dmamem; + MemoryRegion ledma_alias; ESPDMADeviceState *espdma; LEDMADeviceState *ledma; } SPARC32DMAState; From 331b7fc1569d65eb9e083e6d3e3c9352fcccd4f9 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Sat, 14 Oct 2017 13:22:22 +0100 Subject: [PATCH 13/17] sparc32_dma: add len to esp/le DMA memory tracing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is surprisingly useful when trying to debug DMA issues. Signed-off-by: Mark Cave-Ayland Reviewed-by: Artyom Tarasenko Reviewed-by: Philippe Mathieu-Daudé Tested-by: Philippe Mathieu-Daudé --- hw/dma/sparc32_dma.c | 8 ++++---- hw/dma/trace-events | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index f64787e904..7d00f1a68f 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -74,7 +74,7 @@ void ledma_memory_read(void *opaque, hwaddr addr, int i; addr |= s->dmaregs[3]; - trace_ledma_memory_read(addr); + trace_ledma_memory_read(addr, len); if (do_bswap) { sparc_iommu_memory_read(s->iommu, addr, buf, len); } else { @@ -95,7 +95,7 @@ void ledma_memory_write(void *opaque, hwaddr addr, uint16_t tmp_buf[32]; addr |= s->dmaregs[3]; - trace_ledma_memory_write(addr); + trace_ledma_memory_write(addr, len); if (do_bswap) { sparc_iommu_memory_write(s->iommu, addr, buf, len); } else { @@ -140,7 +140,7 @@ void espdma_memory_read(void *opaque, uint8_t *buf, int len) { DMADeviceState *s = opaque; - trace_espdma_memory_read(s->dmaregs[1]); + trace_espdma_memory_read(s->dmaregs[1], len); sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len); s->dmaregs[1] += len; } @@ -149,7 +149,7 @@ void espdma_memory_write(void *opaque, uint8_t *buf, int len) { DMADeviceState *s = opaque; - trace_espdma_memory_write(s->dmaregs[1]); + trace_espdma_memory_write(s->dmaregs[1], len); sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len); s->dmaregs[1] += len; } diff --git a/hw/dma/trace-events b/hw/dma/trace-events index 428469a140..6b367f053b 100644 --- a/hw/dma/trace-events +++ b/hw/dma/trace-events @@ -7,12 +7,12 @@ rc4030_read(uint64_t addr, uint32_t ret) "read reg[0x%"PRIx64"] = 0x%x" rc4030_write(uint64_t addr, uint32_t val) "write reg[0x%"PRIx64"] = 0x%x" # hw/dma/sparc32_dma.c -ledma_memory_read(uint64_t addr) "DMA read addr 0x%"PRIx64 -ledma_memory_write(uint64_t addr) "DMA write addr 0x%"PRIx64 +ledma_memory_read(uint64_t addr, int len) "DMA read addr 0x%"PRIx64 " len %d" +ledma_memory_write(uint64_t addr, int len) "DMA write addr 0x%"PRIx64 " len %d" sparc32_dma_set_irq_raise(void) "Raise IRQ" sparc32_dma_set_irq_lower(void) "Lower IRQ" -espdma_memory_read(uint32_t addr) "DMA read addr 0x%08x" -espdma_memory_write(uint32_t addr) "DMA write addr 0x%08x" +espdma_memory_read(uint32_t addr, int len) "DMA read addr 0x%08x len %d" +espdma_memory_write(uint32_t addr, int len) "DMA write addr 0x%08x len %d" sparc32_dma_mem_readl(uint64_t addr, uint32_t ret) "read dmareg 0x%"PRIx64": 0x%08x" sparc32_dma_mem_writel(uint64_t addr, uint32_t old, uint32_t val) "write dmareg 0x%"PRIx64": 0x%08x -> 0x%08x" sparc32_dma_enable_raise(void) "Raise DMA enable" From 8413846631113f42f0cd18165f465a6193af7f30 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 27 Oct 2017 13:09:03 +0100 Subject: [PATCH 14/17] sun4m: implement IOMMU translation using IOMMU memory region Signed-off-by: Mark Cave-Ayland --- hw/dma/sun4m_iommu.c | 62 ++++++++++++++++++++++++++++++++++++++++ include/hw/sparc/sun4m.h | 5 ++++ 2 files changed, 67 insertions(+) diff --git a/hw/dma/sun4m_iommu.c b/hw/dma/sun4m_iommu.c index 840064b5e2..ce21a22d72 100644 --- a/hw/dma/sun4m_iommu.c +++ b/hw/dma/sun4m_iommu.c @@ -278,6 +278,49 @@ static void iommu_bad_addr(IOMMUState *s, hwaddr addr, qemu_irq_raise(s->irq); } +/* Called from RCU critical section */ +static IOMMUTLBEntry sun4m_translate_iommu(IOMMUMemoryRegion *iommu, + hwaddr addr, + IOMMUAccessFlags flags) +{ + IOMMUState *is = container_of(iommu, IOMMUState, iommu); + hwaddr page, pa; + int is_write = (flags & IOMMU_WO) ? 1 : 0; + uint32_t pte; + IOMMUTLBEntry ret = { + .target_as = &address_space_memory, + .iova = 0, + .translated_addr = 0, + .addr_mask = ~(hwaddr)0, + .perm = IOMMU_NONE, + }; + + page = addr & IOMMU_PAGE_MASK; + pte = iommu_page_get_flags(is, page); + if (!(pte & IOPTE_VALID)) { + iommu_bad_addr(is, page, is_write); + return ret; + } + + pa = iommu_translate_pa(addr, pte); + if (is_write && !(pte & IOPTE_WRITE)) { + iommu_bad_addr(is, page, is_write); + return ret; + } + + if (pte & IOPTE_WRITE) { + ret.perm = IOMMU_RW; + } else { + ret.perm = IOMMU_RO; + } + + ret.iova = page; + ret.translated_addr = pa; + ret.addr_mask = ~IOMMU_PAGE_MASK; + + return ret; +} + void sparc_iommu_memory_rw(void *opaque, hwaddr addr, uint8_t *buf, int len, int is_write) { @@ -340,6 +383,11 @@ static void iommu_init(Object *obj) IOMMUState *s = SUN4M_IOMMU(obj); SysBusDevice *dev = SYS_BUS_DEVICE(obj); + memory_region_init_iommu(&s->iommu, sizeof(s->iommu), + TYPE_SUN4M_IOMMU_MEMORY_REGION, OBJECT(dev), + "iommu-sun4m", UINT64_MAX); + address_space_init(&s->iommu_as, MEMORY_REGION(&s->iommu), "iommu-as"); + sysbus_init_irq(dev, &s->irq); memory_region_init_io(&s->iomem, obj, &iommu_mem_ops, s, "iommu", @@ -369,9 +417,23 @@ static const TypeInfo iommu_info = { .class_init = iommu_class_init, }; +static void sun4m_iommu_memory_region_class_init(ObjectClass *klass, void *data) +{ + IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass); + + imrc->translate = sun4m_translate_iommu; +} + +static const TypeInfo sun4m_iommu_memory_region_info = { + .parent = TYPE_IOMMU_MEMORY_REGION, + .name = TYPE_SUN4M_IOMMU_MEMORY_REGION, + .class_init = sun4m_iommu_memory_region_class_init, +}; + static void iommu_register_types(void) { type_register_static(&iommu_info); + type_register_static(&sun4m_iommu_memory_region_info); } type_init(iommu_register_types) diff --git a/include/hw/sparc/sun4m.h b/include/hw/sparc/sun4m.h index 1f1cf91ed9..6e21e1046f 100644 --- a/include/hw/sparc/sun4m.h +++ b/include/hw/sparc/sun4m.h @@ -12,11 +12,16 @@ #define TYPE_SUN4M_IOMMU "iommu" #define SUN4M_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4M_IOMMU) +#define TYPE_SUN4M_IOMMU_MEMORY_REGION "sun4m-iommu-memory-region" + #define IOMMU_NREGS (4 * 4096 / 4) typedef struct IOMMUState { SysBusDevice parent_obj; + AddressSpace iommu_as; + IOMMUMemoryRegion iommu; + MemoryRegion iomem; uint32_t regs[IOMMU_NREGS]; hwaddr iostart; From c413e9a426e263816dd2c11c62589e0532bcf7e9 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 27 Oct 2017 13:09:03 +0100 Subject: [PATCH 15/17] sparc32_dma: switch over to using IOMMU memory region and DMA API Signed-off-by: Mark Cave-Ayland --- hw/dma/sparc32_dma.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/hw/dma/sparc32_dma.c b/hw/dma/sparc32_dma.c index 7d00f1a68f..01afb758b6 100644 --- a/hw/dma/sparc32_dma.c +++ b/hw/dma/sparc32_dma.c @@ -30,6 +30,7 @@ #include "hw/sparc/sparc32_dma.h" #include "hw/sparc/sun4m.h" #include "hw/sysbus.h" +#include "sysemu/dma.h" #include "qapi/error.h" #include "trace.h" @@ -71,16 +72,17 @@ void ledma_memory_read(void *opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap) { DMADeviceState *s = opaque; + IOMMUState *is = (IOMMUState *)s->iommu; int i; addr |= s->dmaregs[3]; trace_ledma_memory_read(addr, len); if (do_bswap) { - sparc_iommu_memory_read(s->iommu, addr, buf, len); + dma_memory_read(&is->iommu_as, addr, buf, len); } else { addr &= ~1; len &= ~1; - sparc_iommu_memory_read(s->iommu, addr, buf, len); + dma_memory_read(&is->iommu_as, addr, buf, len); for(i = 0; i < len; i += 2) { bswap16s((uint16_t *)(buf + i)); } @@ -91,13 +93,14 @@ void ledma_memory_write(void *opaque, hwaddr addr, uint8_t *buf, int len, int do_bswap) { DMADeviceState *s = opaque; + IOMMUState *is = (IOMMUState *)s->iommu; int l, i; uint16_t tmp_buf[32]; addr |= s->dmaregs[3]; trace_ledma_memory_write(addr, len); if (do_bswap) { - sparc_iommu_memory_write(s->iommu, addr, buf, len); + dma_memory_write(&is->iommu_as, addr, buf, len); } else { addr &= ~1; len &= ~1; @@ -108,7 +111,7 @@ void ledma_memory_write(void *opaque, hwaddr addr, for(i = 0; i < l; i += 2) { tmp_buf[i >> 1] = bswap16(*(uint16_t *)(buf + i)); } - sparc_iommu_memory_write(s->iommu, addr, (uint8_t *)tmp_buf, l); + dma_memory_write(&is->iommu_as, addr, tmp_buf, l); len -= l; buf += l; addr += l; @@ -139,18 +142,20 @@ static void dma_set_irq(void *opaque, int irq, int level) void espdma_memory_read(void *opaque, uint8_t *buf, int len) { DMADeviceState *s = opaque; + IOMMUState *is = (IOMMUState *)s->iommu; trace_espdma_memory_read(s->dmaregs[1], len); - sparc_iommu_memory_read(s->iommu, s->dmaregs[1], buf, len); + dma_memory_read(&is->iommu_as, s->dmaregs[1], buf, len); s->dmaregs[1] += len; } void espdma_memory_write(void *opaque, uint8_t *buf, int len) { DMADeviceState *s = opaque; + IOMMUState *is = (IOMMUState *)s->iommu; trace_espdma_memory_write(s->dmaregs[1], len); - sparc_iommu_memory_write(s->iommu, s->dmaregs[1], buf, len); + dma_memory_write(&is->iommu_as, s->dmaregs[1], buf, len); s->dmaregs[1] += len; } From 3cc71c7992704c595b9945fe98fdc4d2d08ce48c Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 27 Oct 2017 13:09:03 +0100 Subject: [PATCH 16/17] sun4m_iommu: remove legacy sparc_iommu_memory_rw() function With the switch to the IOMMU memory region and DMA API, this is no longer required. Signed-off-by: Mark Cave-Ayland --- hw/dma/sun4m_iommu.c | 33 --------------------------------- include/hw/sparc/sun4m.h | 16 ---------------- 2 files changed, 49 deletions(-) diff --git a/hw/dma/sun4m_iommu.c b/hw/dma/sun4m_iommu.c index ce21a22d72..30a05e8823 100644 --- a/hw/dma/sun4m_iommu.c +++ b/hw/dma/sun4m_iommu.c @@ -321,39 +321,6 @@ static IOMMUTLBEntry sun4m_translate_iommu(IOMMUMemoryRegion *iommu, return ret; } -void sparc_iommu_memory_rw(void *opaque, hwaddr addr, - uint8_t *buf, int len, int is_write) -{ - int l; - uint32_t flags; - hwaddr page, phys_addr; - - while (len > 0) { - page = addr & IOMMU_PAGE_MASK; - l = (page + IOMMU_PAGE_SIZE) - addr; - if (l > len) - l = len; - flags = iommu_page_get_flags(opaque, page); - if (!(flags & IOPTE_VALID)) { - iommu_bad_addr(opaque, page, is_write); - return; - } - phys_addr = iommu_translate_pa(addr, flags); - if (is_write) { - if (!(flags & IOPTE_WRITE)) { - iommu_bad_addr(opaque, page, is_write); - return; - } - cpu_physical_memory_write(phys_addr, buf, l); - } else { - cpu_physical_memory_read(phys_addr, buf, l); - } - len -= l; - buf += l; - addr += l; - } -} - static const VMStateDescription vmstate_iommu = { .name ="iommu", .version_id = 2, diff --git a/include/hw/sparc/sun4m.h b/include/hw/sparc/sun4m.h index 6e21e1046f..c2d044843a 100644 --- a/include/hw/sparc/sun4m.h +++ b/include/hw/sparc/sun4m.h @@ -29,22 +29,6 @@ typedef struct IOMMUState { uint32_t version; } IOMMUState; -void sparc_iommu_memory_rw(void *opaque, hwaddr addr, - uint8_t *buf, int len, int is_write); -static inline void sparc_iommu_memory_read(void *opaque, - hwaddr addr, - uint8_t *buf, int len) -{ - sparc_iommu_memory_rw(opaque, addr, buf, len, 0); -} - -static inline void sparc_iommu_memory_write(void *opaque, - hwaddr addr, - uint8_t *buf, int len) -{ - sparc_iommu_memory_rw(opaque, addr, buf, len, 1); -} - /* sparc32_dma.c */ #include "hw/sparc/sparc32_dma.h" From badd3d62c619d24a5af62198374f42b7c510ee41 Mon Sep 17 00:00:00 2001 From: Mark Cave-Ayland Date: Fri, 27 Oct 2017 13:09:03 +0100 Subject: [PATCH 17/17] sun4m: change TYPE_SUN4M_IOMMU macro from "iommu" to "sun4m-iommu" This is a legacy artifact from when the sun4m IOMMU implementation was the only IOMMU available within QEMU. Signed-off-by: Mark Cave-Ayland --- include/hw/sparc/sun4m.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/sparc/sun4m.h b/include/hw/sparc/sun4m.h index c2d044843a..c557b0dd53 100644 --- a/include/hw/sparc/sun4m.h +++ b/include/hw/sparc/sun4m.h @@ -9,7 +9,7 @@ /* Devices used by sparc32 system. */ /* iommu.c */ -#define TYPE_SUN4M_IOMMU "iommu" +#define TYPE_SUN4M_IOMMU "sun4m-iommu" #define SUN4M_IOMMU(obj) OBJECT_CHECK(IOMMUState, (obj), TYPE_SUN4M_IOMMU) #define TYPE_SUN4M_IOMMU_MEMORY_REGION "sun4m-iommu-memory-region"