summary refs log tree commit diff stats
path: root/hw/ppc/spapr_iommu.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/ppc/spapr_iommu.c')
-rw-r--r--hw/ppc/spapr_iommu.c107
1 files changed, 69 insertions, 38 deletions
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 37e98f9321..5aff4d5a05 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -32,7 +32,7 @@
 
 #include <libfdt.h>
 
-enum sPAPRTCEAccess {
+enum SpaprTceAccess {
     SPAPR_TCE_FAULT = 0,
     SPAPR_TCE_RO = 1,
     SPAPR_TCE_WO = 2,
@@ -42,11 +42,11 @@ enum sPAPRTCEAccess {
 #define IOMMU_PAGE_SIZE(shift)      (1ULL << (shift))
 #define IOMMU_PAGE_MASK(shift)      (~(IOMMU_PAGE_SIZE(shift) - 1))
 
-static QLIST_HEAD(, sPAPRTCETable) spapr_tce_tables;
+static QLIST_HEAD(, SpaprTceTable) spapr_tce_tables;
 
-sPAPRTCETable *spapr_tce_find_by_liobn(target_ulong liobn)
+SpaprTceTable *spapr_tce_find_by_liobn(target_ulong liobn)
 {
-    sPAPRTCETable *tcet;
+    SpaprTceTable *tcet;
 
     if (liobn & 0xFFFFFFFF00000000ULL) {
         hcall_dprintf("Request for out-of-bounds LIOBN 0x" TARGET_FMT_lx "\n",
@@ -115,7 +115,7 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(IOMMUMemoryRegion *iommu,
                                                IOMMUAccessFlags flag,
                                                int iommu_idx)
 {
-    sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
+    SpaprTceTable *tcet = container_of(iommu, SpaprTceTable, iommu);
     uint64_t tce;
     IOMMUTLBEntry ret = {
         .target_as = &address_space_memory,
@@ -141,9 +141,39 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(IOMMUMemoryRegion *iommu,
     return ret;
 }
 
+static void spapr_tce_replay(IOMMUMemoryRegion *iommu_mr, IOMMUNotifier *n)
+{
+    MemoryRegion *mr = MEMORY_REGION(iommu_mr);
+    IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_GET_CLASS(iommu_mr);
+    hwaddr addr, granularity;
+    IOMMUTLBEntry iotlb;
+    SpaprTceTable *tcet = container_of(iommu_mr, SpaprTceTable, iommu);
+
+    if (tcet->skipping_replay) {
+        return;
+    }
+
+    granularity = memory_region_iommu_get_min_page_size(iommu_mr);
+
+    for (addr = 0; addr < memory_region_size(mr); addr += granularity) {
+        iotlb = imrc->translate(iommu_mr, addr, IOMMU_NONE, n->iommu_idx);
+        if (iotlb.perm != IOMMU_NONE) {
+            n->notify(n, &iotlb);
+        }
+
+        /*
+         * if (2^64 - MR size) < granularity, it's possible to get an
+         * infinite loop here.  This should catch such a wraparound.
+         */
+        if ((addr + granularity) < addr) {
+            break;
+        }
+    }
+}
+
 static int spapr_tce_table_pre_save(void *opaque)
 {
-    sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque);
+    SpaprTceTable *tcet = SPAPR_TCE_TABLE(opaque);
 
     tcet->mig_table = tcet->table;
     tcet->mig_nb_table = tcet->nb_table;
@@ -156,7 +186,7 @@ static int spapr_tce_table_pre_save(void *opaque)
 
 static uint64_t spapr_tce_get_min_page_size(IOMMUMemoryRegion *iommu)
 {
-    sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
+    SpaprTceTable *tcet = container_of(iommu, SpaprTceTable, iommu);
 
     return 1ULL << tcet->page_shift;
 }
@@ -164,7 +194,7 @@ static uint64_t spapr_tce_get_min_page_size(IOMMUMemoryRegion *iommu)
 static int spapr_tce_get_attr(IOMMUMemoryRegion *iommu,
                               enum IOMMUMemoryRegionAttr attr, void *data)
 {
-    sPAPRTCETable *tcet = container_of(iommu, sPAPRTCETable, iommu);
+    SpaprTceTable *tcet = container_of(iommu, SpaprTceTable, iommu);
 
     if (attr == IOMMU_ATTR_SPAPR_TCE_FD && kvmppc_has_cap_spapr_vfio()) {
         *(int *) data = tcet->fd;
@@ -178,7 +208,7 @@ static void spapr_tce_notify_flag_changed(IOMMUMemoryRegion *iommu,
                                           IOMMUNotifierFlag old,
                                           IOMMUNotifierFlag new)
 {
-    struct sPAPRTCETable *tbl = container_of(iommu, sPAPRTCETable, iommu);
+    struct SpaprTceTable *tbl = container_of(iommu, SpaprTceTable, iommu);
 
     if (old == IOMMU_NOTIFIER_NONE && new != IOMMU_NOTIFIER_NONE) {
         spapr_tce_set_need_vfio(tbl, true);
@@ -189,7 +219,7 @@ static void spapr_tce_notify_flag_changed(IOMMUMemoryRegion *iommu,
 
 static int spapr_tce_table_post_load(void *opaque, int version_id)
 {
-    sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque);
+    SpaprTceTable *tcet = SPAPR_TCE_TABLE(opaque);
     uint32_t old_nb_table = tcet->nb_table;
     uint64_t old_bus_offset = tcet->bus_offset;
     uint32_t old_page_shift = tcet->page_shift;
@@ -223,7 +253,7 @@ static int spapr_tce_table_post_load(void *opaque, int version_id)
 
 static bool spapr_tce_table_ex_needed(void *opaque)
 {
-    sPAPRTCETable *tcet = opaque;
+    SpaprTceTable *tcet = opaque;
 
     return tcet->bus_offset || tcet->page_shift != 0xC;
 }
@@ -234,8 +264,8 @@ static const VMStateDescription vmstate_spapr_tce_table_ex = {
     .minimum_version_id = 1,
     .needed = spapr_tce_table_ex_needed,
     .fields = (VMStateField[]) {
-        VMSTATE_UINT64(bus_offset, sPAPRTCETable),
-        VMSTATE_UINT32(page_shift, sPAPRTCETable),
+        VMSTATE_UINT64(bus_offset, SpaprTceTable),
+        VMSTATE_UINT32(page_shift, SpaprTceTable),
         VMSTATE_END_OF_LIST()
     },
 };
@@ -248,12 +278,12 @@ static const VMStateDescription vmstate_spapr_tce_table = {
     .post_load = spapr_tce_table_post_load,
     .fields      = (VMStateField []) {
         /* Sanity check */
-        VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable, NULL),
+        VMSTATE_UINT32_EQUAL(liobn, SpaprTceTable, NULL),
 
         /* IOMMU state */
-        VMSTATE_UINT32(mig_nb_table, sPAPRTCETable),
-        VMSTATE_BOOL(bypass, sPAPRTCETable),
-        VMSTATE_VARRAY_UINT32_ALLOC(mig_table, sPAPRTCETable, mig_nb_table, 0,
+        VMSTATE_UINT32(mig_nb_table, SpaprTceTable),
+        VMSTATE_BOOL(bypass, SpaprTceTable),
+        VMSTATE_VARRAY_UINT32_ALLOC(mig_table, SpaprTceTable, mig_nb_table, 0,
                                     vmstate_info_uint64, uint64_t),
 
         VMSTATE_END_OF_LIST()
@@ -266,7 +296,7 @@ static const VMStateDescription vmstate_spapr_tce_table = {
 
 static void spapr_tce_table_realize(DeviceState *dev, Error **errp)
 {
-    sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
+    SpaprTceTable *tcet = SPAPR_TCE_TABLE(dev);
     Object *tcetobj = OBJECT(tcet);
     gchar *tmp;
 
@@ -288,7 +318,7 @@ static void spapr_tce_table_realize(DeviceState *dev, Error **errp)
                      tcet);
 }
 
-void spapr_tce_set_need_vfio(sPAPRTCETable *tcet, bool need_vfio)
+void spapr_tce_set_need_vfio(SpaprTceTable *tcet, bool need_vfio)
 {
     size_t table_size = tcet->nb_table * sizeof(uint64_t);
     uint64_t *oldtable;
@@ -317,9 +347,9 @@ void spapr_tce_set_need_vfio(sPAPRTCETable *tcet, bool need_vfio)
     tcet->fd = newfd;
 }
 
-sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn)
+SpaprTceTable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn)
 {
-    sPAPRTCETable *tcet;
+    SpaprTceTable *tcet;
     gchar *tmp;
 
     if (spapr_tce_find_by_liobn(liobn)) {
@@ -341,7 +371,7 @@ sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn)
     return tcet;
 }
 
-void spapr_tce_table_enable(sPAPRTCETable *tcet,
+void spapr_tce_table_enable(SpaprTceTable *tcet,
                             uint32_t page_shift, uint64_t bus_offset,
                             uint32_t nb_table)
 {
@@ -366,7 +396,7 @@ void spapr_tce_table_enable(sPAPRTCETable *tcet,
                                 MEMORY_REGION(&tcet->iommu));
 }
 
-void spapr_tce_table_disable(sPAPRTCETable *tcet)
+void spapr_tce_table_disable(SpaprTceTable *tcet)
 {
     if (!tcet->nb_table) {
         return;
@@ -385,7 +415,7 @@ void spapr_tce_table_disable(sPAPRTCETable *tcet)
 
 static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp)
 {
-    sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
+    SpaprTceTable *tcet = SPAPR_TCE_TABLE(dev);
 
     vmstate_unregister(DEVICE(tcet), &vmstate_spapr_tce_table, tcet);
 
@@ -394,14 +424,14 @@ static void spapr_tce_table_unrealize(DeviceState *dev, Error **errp)
     spapr_tce_table_disable(tcet);
 }
 
-MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet)
+MemoryRegion *spapr_tce_get_iommu(SpaprTceTable *tcet)
 {
     return &tcet->root;
 }
 
 static void spapr_tce_reset(DeviceState *dev)
 {
-    sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
+    SpaprTceTable *tcet = SPAPR_TCE_TABLE(dev);
     size_t table_size = tcet->nb_table * sizeof(uint64_t);
 
     if (tcet->nb_table) {
@@ -409,7 +439,7 @@ static void spapr_tce_reset(DeviceState *dev)
     }
 }
 
-static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
+static target_ulong put_tce_emu(SpaprTceTable *tcet, target_ulong ioba,
                                 target_ulong tce)
 {
     IOMMUTLBEntry entry;
@@ -435,7 +465,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
 }
 
 static target_ulong h_put_tce_indirect(PowerPCCPU *cpu,
-                                       sPAPRMachineState *spapr,
+                                       SpaprMachineState *spapr,
                                        target_ulong opcode, target_ulong *args)
 {
     int i;
@@ -445,7 +475,7 @@ static target_ulong h_put_tce_indirect(PowerPCCPU *cpu,
     target_ulong tce_list = args[2];
     target_ulong npages = args[3];
     target_ulong ret = H_PARAMETER, tce = 0;
-    sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+    SpaprTceTable *tcet = spapr_tce_find_by_liobn(liobn);
     CPUState *cs = CPU(cpu);
     hwaddr page_mask, page_size;
 
@@ -480,7 +510,7 @@ static target_ulong h_put_tce_indirect(PowerPCCPU *cpu,
     return ret;
 }
 
-static target_ulong h_stuff_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_stuff_tce(PowerPCCPU *cpu, SpaprMachineState *spapr,
                               target_ulong opcode, target_ulong *args)
 {
     int i;
@@ -489,7 +519,7 @@ static target_ulong h_stuff_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     target_ulong tce_value = args[2];
     target_ulong npages = args[3];
     target_ulong ret = H_PARAMETER;
-    sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+    SpaprTceTable *tcet = spapr_tce_find_by_liobn(liobn);
     hwaddr page_mask, page_size;
 
     if (!tcet) {
@@ -519,14 +549,14 @@ static target_ulong h_stuff_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     return ret;
 }
 
-static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_put_tce(PowerPCCPU *cpu, SpaprMachineState *spapr,
                               target_ulong opcode, target_ulong *args)
 {
     target_ulong liobn = args[0];
     target_ulong ioba = args[1];
     target_ulong tce = args[2];
     target_ulong ret = H_PARAMETER;
-    sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+    SpaprTceTable *tcet = spapr_tce_find_by_liobn(liobn);
 
     if (tcet) {
         hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
@@ -544,7 +574,7 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     return ret;
 }
 
-static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
+static target_ulong get_tce_emu(SpaprTceTable *tcet, target_ulong ioba,
                                 target_ulong *tce)
 {
     unsigned long index = (ioba - tcet->bus_offset) >> tcet->page_shift;
@@ -560,14 +590,14 @@ static target_ulong get_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
     return H_SUCCESS;
 }
 
-static target_ulong h_get_tce(PowerPCCPU *cpu, sPAPRMachineState *spapr,
+static target_ulong h_get_tce(PowerPCCPU *cpu, SpaprMachineState *spapr,
                               target_ulong opcode, target_ulong *args)
 {
     target_ulong liobn = args[0];
     target_ulong ioba = args[1];
     target_ulong tce = 0;
     target_ulong ret = H_PARAMETER;
-    sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+    SpaprTceTable *tcet = spapr_tce_find_by_liobn(liobn);
 
     if (tcet) {
         hwaddr page_mask = IOMMU_PAGE_MASK(tcet->page_shift);
@@ -619,7 +649,7 @@ int spapr_dma_dt(void *fdt, int node_off, const char *propname,
 }
 
 int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
-                      sPAPRTCETable *tcet)
+                      SpaprTceTable *tcet)
 {
     if (!tcet) {
         return 0;
@@ -650,7 +680,7 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
 static TypeInfo spapr_tce_table_info = {
     .name = TYPE_SPAPR_TCE_TABLE,
     .parent = TYPE_DEVICE,
-    .instance_size = sizeof(sPAPRTCETable),
+    .instance_size = sizeof(SpaprTceTable),
     .class_init = spapr_tce_table_class_init,
 };
 
@@ -659,6 +689,7 @@ static void spapr_iommu_memory_region_class_init(ObjectClass *klass, void *data)
     IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
 
     imrc->translate = spapr_tce_translate_iommu;
+    imrc->replay = spapr_tce_replay;
     imrc->get_min_page_size = spapr_tce_get_min_page_size;
     imrc->notify_flag_changed = spapr_tce_notify_flag_changed;
     imrc->get_attr = spapr_tce_get_attr;