aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/ppc/spapr.c3
-rw-r--r--hw/ppc/spapr_iommu.c146
-rw-r--r--hw/ppc/spapr_pci.c2
-rw-r--r--hw/ppc/spapr_vio.c2
-rw-r--r--include/hw/ppc/spapr.h23
-rw-r--r--target-ppc/kvm.c4
6 files changed, 117 insertions, 63 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 48ae09283d..e340708371 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -848,9 +848,6 @@ static void ppc_spapr_init(QEMUMachineInitArgs *args)
/* Set up EPOW events infrastructure */
spapr_events_init(spapr);
- /* Set up IOMMU */
- spapr_iommu_init();
-
/* Set up VIO bus */
spapr->vio_bus = spapr_vio_bus_init();
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 89b33a5478..3d4a1fcfe1 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -36,17 +36,6 @@ enum sPAPRTCEAccess {
SPAPR_TCE_RW = 3,
};
-struct sPAPRTCETable {
- uint32_t liobn;
- uint32_t window_size;
- sPAPRTCE *table;
- bool bypass;
- int fd;
- MemoryRegion iommu;
- QLIST_ENTRY(sPAPRTCETable) list;
-};
-
-
QLIST_HEAD(spapr_tce_tables, sPAPRTCETable) spapr_tce_tables;
static sPAPRTCETable *spapr_tce_find_by_liobn(uint32_t liobn)
@@ -96,7 +85,7 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr)
return (IOMMUTLBEntry) { .perm = IOMMU_NONE };
}
- tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT].tce;
+ tce = tcet->table[addr >> SPAPR_TCE_PAGE_SHIFT];
#ifdef DEBUG_TCE
fprintf(stderr, " -> *paddr=0x%llx, *len=0x%llx\n",
@@ -112,55 +101,97 @@ static IOMMUTLBEntry spapr_tce_translate_iommu(MemoryRegion *iommu, hwaddr addr)
};
}
+static int spapr_tce_table_pre_load(void *opaque)
+{
+ sPAPRTCETable *tcet = SPAPR_TCE_TABLE(opaque);
+
+ tcet->nb_table = tcet->window_size >> SPAPR_TCE_PAGE_SHIFT;
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_spapr_tce_table = {
+ .name = "spapr_iommu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .pre_load = spapr_tce_table_pre_load,
+ .fields = (VMStateField []) {
+ /* Sanity check */
+ VMSTATE_UINT32_EQUAL(liobn, sPAPRTCETable),
+ VMSTATE_UINT32_EQUAL(window_size, sPAPRTCETable),
+
+ /* IOMMU state */
+ VMSTATE_BOOL(bypass, sPAPRTCETable),
+ VMSTATE_VARRAY_UINT32(table, sPAPRTCETable, nb_table, 0, vmstate_info_uint64, uint64_t),
+
+ VMSTATE_END_OF_LIST()
+ },
+};
+
static MemoryRegionIOMMUOps spapr_iommu_ops = {
.translate = spapr_tce_translate_iommu,
};
-sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, size_t window_size)
+static int spapr_tce_table_realize(DeviceState *dev)
{
- sPAPRTCETable *tcet;
-
- if (spapr_tce_find_by_liobn(liobn)) {
- fprintf(stderr, "Attempted to create TCE table with duplicate"
- " LIOBN 0x%x\n", liobn);
- return NULL;
- }
-
- if (!window_size) {
- return NULL;
- }
-
- tcet = g_malloc0(sizeof(*tcet));
- tcet->liobn = liobn;
- tcet->window_size = window_size;
+ sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
if (kvm_enabled()) {
- tcet->table = kvmppc_create_spapr_tce(liobn,
- window_size,
+ tcet->table = kvmppc_create_spapr_tce(tcet->liobn,
+ tcet->window_size,
&tcet->fd);
}
if (!tcet->table) {
- size_t table_size = (window_size >> SPAPR_TCE_PAGE_SHIFT)
- * sizeof(sPAPRTCE);
+ size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT)
+ * sizeof(uint64_t);
tcet->table = g_malloc0(table_size);
}
+ tcet->nb_table = tcet->window_size >> SPAPR_TCE_PAGE_SHIFT;
#ifdef DEBUG_TCE
fprintf(stderr, "spapr_iommu: New TCE table @ %p, liobn=0x%x, "
"table @ %p, fd=%d\n", tcet, liobn, tcet->table, tcet->fd);
#endif
- memory_region_init_iommu(&tcet->iommu, OBJECT(owner), &spapr_iommu_ops,
+ memory_region_init_iommu(&tcet->iommu, OBJECT(dev), &spapr_iommu_ops,
"iommu-spapr", UINT64_MAX);
QLIST_INSERT_HEAD(&spapr_tce_tables, tcet, list);
+ return 0;
+}
+
+sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn, size_t window_size)
+{
+ sPAPRTCETable *tcet;
+
+ if (spapr_tce_find_by_liobn(liobn)) {
+ fprintf(stderr, "Attempted to create TCE table with duplicate"
+ " LIOBN 0x%x\n", liobn);
+ return NULL;
+ }
+
+ if (!window_size) {
+ return NULL;
+ }
+
+ tcet = SPAPR_TCE_TABLE(object_new(TYPE_SPAPR_TCE_TABLE));
+ tcet->liobn = liobn;
+ tcet->window_size = window_size;
+
+ object_property_add_child(OBJECT(owner), "tce-table", OBJECT(tcet), NULL);
+
+ qdev_init_nofail(DEVICE(tcet));
+
return tcet;
}
-void spapr_tce_free(sPAPRTCETable *tcet)
+static void spapr_tce_table_finalize(Object *obj)
{
+ sPAPRTCETable *tcet = SPAPR_TCE_TABLE(obj);
+
QLIST_REMOVE(tcet, list);
if (!kvm_enabled() ||
@@ -168,8 +199,6 @@ void spapr_tce_free(sPAPRTCETable *tcet)
tcet->window_size) != 0)) {
g_free(tcet->table);
}
-
- g_free(tcet);
}
MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet)
@@ -182,10 +211,11 @@ void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass)
tcet->bypass = bypass;
}
-void spapr_tce_reset(sPAPRTCETable *tcet)
+static void spapr_tce_reset(DeviceState *dev)
{
+ sPAPRTCETable *tcet = SPAPR_TCE_TABLE(dev);
size_t table_size = (tcet->window_size >> SPAPR_TCE_PAGE_SHIFT)
- * sizeof(sPAPRTCE);
+ * sizeof(uint64_t);
tcet->bypass = false;
memset(tcet->table, 0, table_size);
@@ -194,7 +224,6 @@ void spapr_tce_reset(sPAPRTCETable *tcet)
static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
target_ulong tce)
{
- sPAPRTCE *tcep;
IOMMUTLBEntry entry;
if (ioba >= tcet->window_size) {
@@ -203,8 +232,7 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
return H_PARAMETER;
}
- tcep = tcet->table + (ioba >> SPAPR_TCE_PAGE_SHIFT);
- tcep->tce = tce;
+ tcet->table[ioba >> SPAPR_TCE_PAGE_SHIFT] = tce;
entry.target_as = &address_space_memory,
entry.iova = ioba & ~SPAPR_TCE_PAGE_MASK;
@@ -238,14 +266,6 @@ static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
return H_PARAMETER;
}
-void spapr_iommu_init(void)
-{
- QLIST_INIT(&spapr_tce_tables);
-
- /* hcall-tce */
- spapr_register_hypercall(H_PUT_TCE, h_put_tce);
-}
-
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
uint32_t liobn, uint64_t window, uint32_t size)
{
@@ -286,3 +306,31 @@ int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname,
return spapr_dma_dt(fdt, node_off, propname,
tcet->liobn, 0, tcet->window_size);
}
+
+static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ dc->vmsd = &vmstate_spapr_tce_table;
+ dc->init = spapr_tce_table_realize;
+ dc->reset = spapr_tce_reset;
+
+ QLIST_INIT(&spapr_tce_tables);
+
+ /* hcall-tce */
+ spapr_register_hypercall(H_PUT_TCE, h_put_tce);
+}
+
+static TypeInfo spapr_tce_table_info = {
+ .name = TYPE_SPAPR_TCE_TABLE,
+ .parent = TYPE_DEVICE,
+ .instance_size = sizeof(sPAPRTCETable),
+ .class_init = spapr_tce_table_class_init,
+ .instance_finalize = spapr_tce_table_finalize,
+};
+
+static void register_types(void)
+{
+ type_register_static(&spapr_tce_table_info);
+}
+
+type_init(register_types);
diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c
index c880a757c8..9dc6ca31db 100644
--- a/hw/ppc/spapr_pci.c
+++ b/hw/ppc/spapr_pci.c
@@ -645,7 +645,7 @@ static void spapr_phb_reset(DeviceState *qdev)
sPAPRPHBState *sphb = SPAPR_PCI_HOST_BRIDGE(s);
/* Reset the IOMMU state */
- spapr_tce_reset(sphb->tcet);
+ device_reset(DEVICE(sphb->tcet));
}
static Property spapr_phb_properties[] = {
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c
index 75ce19f0e3..c3f85bf078 100644
--- a/hw/ppc/spapr_vio.c
+++ b/hw/ppc/spapr_vio.c
@@ -316,7 +316,7 @@ int spapr_vio_send_crq(VIOsPAPRDevice *dev, uint8_t *crq)
static void spapr_vio_quiesce_one(VIOsPAPRDevice *dev)
{
if (dev->tcet) {
- spapr_tce_reset(dev->tcet);
+ device_reset(DEVICE(dev->tcet));
}
free_crq(dev);
}
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index de95480734..82ad7c0068 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -334,10 +334,6 @@ int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr,
#define SPAPR_TCE_PAGE_SIZE (1ULL << SPAPR_TCE_PAGE_SHIFT)
#define SPAPR_TCE_PAGE_MASK (SPAPR_TCE_PAGE_SIZE - 1)
-typedef struct sPAPRTCE {
- uint64_t tce;
-} sPAPRTCE;
-
#define SPAPR_VIO_BASE_LIOBN 0x00000000
#define SPAPR_PCI_BASE_LIOBN 0x80000000
@@ -345,14 +341,27 @@ typedef struct sPAPRTCE {
typedef struct sPAPRTCETable sPAPRTCETable;
-void spapr_iommu_init(void);
+#define TYPE_SPAPR_TCE_TABLE "spapr-tce-table"
+#define SPAPR_TCE_TABLE(obj) \
+ OBJECT_CHECK(sPAPRTCETable, (obj), TYPE_SPAPR_TCE_TABLE)
+
+struct sPAPRTCETable {
+ DeviceState parent;
+ uint32_t liobn;
+ uint32_t window_size;
+ uint32_t nb_table;
+ uint64_t *table;
+ bool bypass;
+ int fd;
+ MemoryRegion iommu;
+ QLIST_ENTRY(sPAPRTCETable) list;
+};
+
void spapr_events_init(sPAPREnvironment *spapr);
void spapr_events_fdt_skel(void *fdt, uint32_t epow_irq);
sPAPRTCETable *spapr_tce_new_table(DeviceState *owner, uint32_t liobn,
size_t window_size);
MemoryRegion *spapr_tce_get_iommu(sPAPRTCETable *tcet);
-void spapr_tce_free(sPAPRTCETable *tcet);
-void spapr_tce_reset(sPAPRTCETable *tcet);
void spapr_tce_set_bypass(sPAPRTCETable *tcet, bool bypass);
int spapr_dma_dt(void *fdt, int node_off, const char *propname,
uint32_t liobn, uint64_t window, uint32_t size);
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index b0099e122f..9f2e4f0457 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -1626,7 +1626,7 @@ void *kvmppc_create_spapr_tce(uint32_t liobn, uint32_t window_size, int *pfd)
return NULL;
}
- len = (window_size / SPAPR_TCE_PAGE_SIZE) * sizeof(sPAPRTCE);
+ len = (window_size / SPAPR_TCE_PAGE_SIZE) * sizeof(uint64_t);
/* FIXME: round this up to page size */
table = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
@@ -1649,7 +1649,7 @@ int kvmppc_remove_spapr_tce(void *table, int fd, uint32_t window_size)
return -1;
}
- len = (window_size / SPAPR_TCE_PAGE_SIZE)*sizeof(sPAPRTCE);
+ len = (window_size / SPAPR_TCE_PAGE_SIZE)*sizeof(uint64_t);
if ((munmap(table, len) < 0) ||
(close(fd) < 0)) {
fprintf(stderr, "KVM: Unexpected error removing TCE table: %s",