From: Ben Herrenschmidt<address@hidden>
This patch implements the necessary infrastructure and hypercalls for
sPAPR's TCE (Translation Control Entry) IOMMU mechanism. This is necessary
for all virtual IO devices which do DMA (i.e. nearly all of them).
Signed-off-by: Ben Herrenschmidt<address@hidden>
Signed-off-by: David Gibson<address@hidden>
---
hw/spapr.c | 3 +-
hw/spapr_vio.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
hw/spapr_vio.h | 32 ++++++++
3 files changed, 266 insertions(+), 1 deletions(-)
diff --git a/hw/spapr.c b/hw/spapr.c
index e7f8864..a362889 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -62,7 +62,8 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t
ramsize,
uint32_t start_prop = cpu_to_be32(initrd_base);
uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
- char hypertas_prop[] =
"hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt";
+ char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt"
+ "\0hcall-tce";
uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
int i;
char *modelname;
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 45edd94..37cf51e 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -37,6 +37,7 @@
#endif /* CONFIG_FDT */
/* #define DEBUG_SPAPR */
+/* #define DEBUG_TCE */
#ifdef DEBUG_SPAPR
#define dprintf(fmt, ...) \
@@ -114,6 +115,28 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
return ret;
}
+ if (dev->rtce_window_size) {
+ uint32_t dma_prop[] = {cpu_to_be32(dev->reg),
+ 0, 0,
+ 0, cpu_to_be32(dev->rtce_window_size)};
+
+ ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-address-cells", 2);
+ if (ret< 0) {
+ return ret;
+ }
+
+ ret = fdt_setprop_cell(fdt, node_off, "ibm,#dma-size-cells", 2);
+ if (ret< 0) {
+ return ret;
+ }
+
+ ret = fdt_setprop(fdt, node_off, "ibm,my-dma-window", dma_prop,
+ sizeof(dma_prop));
+ if (ret< 0) {
+ return ret;
+ }
+ }
+
if (info->devnode) {
ret = (info->devnode)(dev, fdt, node_off);
if (ret< 0) {
@@ -125,6 +148,210 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
}
#endif /* CONFIG_FDT */
+/*
+ * RTCE handling
+ */
+
+static void rtce_init(VIOsPAPRDevice *dev)
+{
+ size_t size = (dev->rtce_window_size>> SPAPR_VIO_TCE_PAGE_SHIFT)
+ * sizeof(VIOsPAPR_RTCE);
+
+ if (size) {
+ dev->rtce_table = qemu_mallocz(size);
+ }
+}
+
+static target_ulong h_put_tce(CPUState *env, sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ target_ulong liobn = args[0];
+ target_ulong ioba = args[1];
+ target_ulong tce = args[2];
+ VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, liobn);
+ VIOsPAPR_RTCE *rtce;
+
+ if (!dev) {
+ fprintf(stderr, "spapr_vio_put_tce on non-existent LIOBN "
+ TARGET_FMT_lx "\n",
+ liobn);