diff mbox series

[PATCHv2,1/4] sun4m: implement IOMMU translation using IOMMU memory region

Message ID 1509106789-8626-2-git-send-email-mark.cave-ayland@ilande.co.uk
State New
Headers show
Series sun4m: implement memory region IOMMU translation and DMA API | expand

Commit Message

Mark Cave-Ayland Oct. 27, 2017, 12:19 p.m. UTC
Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
---
 hw/dma/sun4m_iommu.c     |   62 ++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/sparc/sun4m.h |    5 ++++
 2 files changed, 67 insertions(+)

Comments

Philippe Mathieu-Daudé Oct. 27, 2017, 3:37 p.m. UTC | #1
On 10/27/2017 09:19 AM, Mark Cave-Ayland wrote:
[...]
> +/* 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,

I never thought of it! I would have write (hwaddr)~0 but your way is
much cleaner.

> +        .perm = IOMMU_NONE,
> +    };
[...]
diff mbox series

Patch

diff --git a/hw/dma/sun4m_iommu.c b/hw/dma/sun4m_iommu.c
index 840064b..ce21a22 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 1f1cf91..6e21e10 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;