diff options
author | Alexey Kardashevskiy <aik@ozlabs.ru> | 2014-05-27 15:36:30 +1000 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2014-06-16 13:24:39 +0200 |
commit | da95324ebe462b14a3507af02eb4a689c8a1619f (patch) | |
tree | 246278f453437fa1e744a1c02869710006554c74 /hw/ppc | |
parent | a1d59c0ffadf17d546f53f4bda06e8adcf616ede (diff) | |
download | qemu-da95324ebe462b14a3507af02eb4a689c8a1619f.zip qemu-da95324ebe462b14a3507af02eb4a689c8a1619f.tar.gz qemu-da95324ebe462b14a3507af02eb4a689c8a1619f.tar.bz2 |
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/ppc')
-rw-r--r-- | hw/ppc/spapr.c | 3 | ||||
-rw-r--r-- | hw/ppc/spapr_iommu.c | 78 |
2 files changed, 81 insertions, 0 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 39f1963..8f612c9 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 8c7382c..b855e7c 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 = { |