summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorAlexey Kardashevskiy <aik@ozlabs.ru>2014-05-27 15:36:30 +1000
committerAlexander Graf <agraf@suse.de>2014-06-16 13:24:39 +0200
commitda95324ebe462b14a3507af02eb4a689c8a1619f (patch)
tree246278f453437fa1e744a1c02869710006554c74 /hw
parenta1d59c0ffadf17d546f53f4bda06e8adcf616ede (diff)
downloadqemu-da95324ebe462b14a3507af02eb4a689c8a1619f.tar.gz
spapr_iommu: Enable multiple TCE requests
Currently only single TCE entry per request is supported (H_PUT_TCE). However PAPR+ specification allows multiple entry requests such as H_PUT_TCE_INDIRECT and H_STUFF_TCE. Having less transitions to the host kernel via ioctls, support of these calls can accelerate IOMMU operations. This implements H_STUFF_TCE and H_PUT_TCE_INDIRECT. This advertises "multi-tce" capability to the guest if the host kernel supports it (KVM_CAP_SPAPR_MULTITCE) or guest is running in TCG mode. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'hw')
-rw-r--r--hw/ppc/spapr.c3
-rw-r--r--hw/ppc/spapr_iommu.c78
2 files changed, 81 insertions, 0 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 39f196304d..8f612c9347 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -537,6 +537,9 @@ static void *spapr_create_fdt_skel(hwaddr initrd_base,
/* RTAS */
_FDT((fdt_begin_node(fdt, "rtas")));
+ if (!kvm_enabled() || kvmppc_spapr_use_multitce()) {
+ add_str(hypertas, "hcall-multi-tce");
+ }
_FDT((fdt_property(fdt, "ibm,hypertas-functions", hypertas->str,
hypertas->len)));
g_string_free(hypertas, TRUE);
diff --git a/hw/ppc/spapr_iommu.c b/hw/ppc/spapr_iommu.c
index 8c7382c289..b855e7ca6b 100644
--- a/hw/ppc/spapr_iommu.c
+++ b/hw/ppc/spapr_iommu.c
@@ -226,6 +226,82 @@ static target_ulong put_tce_emu(sPAPRTCETable *tcet, target_ulong ioba,
return H_SUCCESS;
}
+static target_ulong h_put_tce_indirect(PowerPCCPU *cpu,
+ sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ int i;
+ target_ulong liobn = args[0];
+ target_ulong ioba = args[1];
+ target_ulong ioba1 = ioba;
+ target_ulong tce_list = args[2];
+ target_ulong npages = args[3];
+ target_ulong ret = H_PARAMETER;
+ sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+ CPUState *cs = CPU(cpu);
+
+ if (!tcet) {
+ return H_PARAMETER;
+ }
+
+ if (npages > 512) {
+ return H_PARAMETER;
+ }
+
+ ioba &= ~SPAPR_TCE_PAGE_MASK;
+ tce_list &= ~SPAPR_TCE_PAGE_MASK;
+
+ for (i = 0; i < npages; ++i, ioba += SPAPR_TCE_PAGE_SIZE) {
+ target_ulong tce = ldq_phys(cs->as, tce_list +
+ i * sizeof(target_ulong));
+ ret = put_tce_emu(tcet, ioba, tce);
+ if (ret) {
+ break;
+ }
+ }
+
+ /* Trace last successful or the first problematic entry */
+ i = i ? (i - 1) : 0;
+ trace_spapr_iommu_indirect(liobn, ioba1, tce_list, i,
+ ldq_phys(cs->as,
+ tce_list + i * sizeof(target_ulong)),
+ ret);
+
+ return ret;
+}
+
+static target_ulong h_stuff_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
+ target_ulong opcode, target_ulong *args)
+{
+ int i;
+ target_ulong liobn = args[0];
+ target_ulong ioba = args[1];
+ target_ulong tce_value = args[2];
+ target_ulong npages = args[3];
+ target_ulong ret = H_PARAMETER;
+ sPAPRTCETable *tcet = spapr_tce_find_by_liobn(liobn);
+
+ if (!tcet) {
+ return H_PARAMETER;
+ }
+
+ if (npages > tcet->nb_table) {
+ return H_PARAMETER;
+ }
+
+ ioba &= ~SPAPR_TCE_PAGE_MASK;
+
+ for (i = 0; i < npages; ++i, ioba += SPAPR_TCE_PAGE_SIZE) {
+ ret = put_tce_emu(tcet, ioba, tce_value);
+ if (ret) {
+ break;
+ }
+ }
+ trace_spapr_iommu_stuff(liobn, ioba, tce_value, npages, ret);
+
+ return ret;
+}
+
static target_ulong h_put_tce(PowerPCCPU *cpu, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
@@ -333,6 +409,8 @@ static void spapr_tce_table_class_init(ObjectClass *klass, void *data)
/* hcall-tce */
spapr_register_hypercall(H_PUT_TCE, h_put_tce);
spapr_register_hypercall(H_GET_TCE, h_get_tce);
+ spapr_register_hypercall(H_PUT_TCE_INDIRECT, h_put_tce_indirect);
+ spapr_register_hypercall(H_STUFF_TCE, h_stuff_tce);
}
static TypeInfo spapr_tce_table_info = {