summaryrefslogtreecommitdiff
path: root/hw/ppc
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2013-07-18 14:32:58 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2013-07-29 10:37:08 -0500
commita83000f5e3fac30a7f213af1ba6a8f827622854d (patch)
tree7bf4b793f453f37a241d0dbd147f5ec258cfb217 /hw/ppc
parentdb1b58e937fd80513a4bb14432808495a5846ffe (diff)
downloadqemu-a83000f5e3fac30a7f213af1ba6a8f827622854d.tar.gz
spapr-tce: make sPAPRTCETable a proper device
Model TCE tables as a device that's hooked up as a child object to the owner. Besides the code cleanup, we get a few nice benefits: 1) free actually works now (it was dead code before) 2) the TCE information is visible in the device tree 3) we can expose table information as properties such that if we change the window_size, we can use globals to keep migration working. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Message-id: 1374175984-8930-6-git-send-email-aliguori@us.ibm.com [dwg: pseries: savevm support for PAPR TCE tables] Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> [alexey: ppc kvm: fix to compile] Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'hw/ppc')
-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
4 files changed, 99 insertions, 54 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);
}