diff options
-rw-r--r-- | hw/ppc/spapr.c | 75 | ||||
-rw-r--r-- | hw/ppc/spapr_hcall.c | 36 | ||||
-rw-r--r-- | hw/ppc/trace-events | 2 | ||||
-rw-r--r-- | include/hw/ppc/spapr.h | 11 | ||||
-rw-r--r-- | target/ppc/kvm.c | 13 | ||||
-rw-r--r-- | target/ppc/kvm_ppc.h | 5 |
6 files changed, 142 insertions, 0 deletions
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index a58dd54392..232afac3d9 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -874,6 +874,11 @@ static void spapr_dt_rtas(sPAPRMachineState *spapr, void *fdt) if (!kvm_enabled() || kvmppc_spapr_use_multitce()) { add_str(hypertas, "hcall-multi-tce"); } + + if (spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) { + add_str(hypertas, "hcall-hpt-resize"); + } + _FDT(fdt_setprop(fdt, rtas, "ibm,hypertas-functions", hypertas->str, hypertas->len)); g_string_free(hypertas, TRUE); @@ -2148,12 +2153,41 @@ static void ppc_spapr_init(MachineState *machine) hwaddr node0_size = spapr_node0_size(); long load_limit, fw_size; char *filename; + Error *resize_hpt_err = NULL; msi_nonbroken = true; QLIST_INIT(&spapr->phbs); QTAILQ_INIT(&spapr->pending_dimm_unplugs); + /* Check HPT resizing availability */ + kvmppc_check_papr_resize_hpt(&resize_hpt_err); + if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DEFAULT) { + /* + * If the user explicitly requested a mode we should either + * supply it, or fail completely (which we do below). But if + * it's not set explicitly, we reset our mode to something + * that works + */ + if (resize_hpt_err) { + spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED; + error_free(resize_hpt_err); + resize_hpt_err = NULL; + } else { + spapr->resize_hpt = smc->resize_hpt_default; + } + } + + assert(spapr->resize_hpt != SPAPR_RESIZE_HPT_DEFAULT); + + if ((spapr->resize_hpt != SPAPR_RESIZE_HPT_DISABLED) && resize_hpt_err) { + /* + * User requested HPT resize, but this host can't supply it. Bail out + */ + error_report_err(resize_hpt_err); + exit(1); + } + /* Allocate RMA if necessary */ rma_alloc_size = kvmppc_alloc_rma(&rma); @@ -2579,6 +2613,40 @@ static void spapr_set_modern_hotplug_events(Object *obj, bool value, spapr->use_hotplug_event_source = value; } +static char *spapr_get_resize_hpt(Object *obj, Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + + switch (spapr->resize_hpt) { + case SPAPR_RESIZE_HPT_DEFAULT: + return g_strdup("default"); + case SPAPR_RESIZE_HPT_DISABLED: + return g_strdup("disabled"); + case SPAPR_RESIZE_HPT_ENABLED: + return g_strdup("enabled"); + case SPAPR_RESIZE_HPT_REQUIRED: + return g_strdup("required"); + } + g_assert_not_reached(); +} + +static void spapr_set_resize_hpt(Object *obj, const char *value, Error **errp) +{ + sPAPRMachineState *spapr = SPAPR_MACHINE(obj); + + if (strcmp(value, "default") == 0) { + spapr->resize_hpt = SPAPR_RESIZE_HPT_DEFAULT; + } else if (strcmp(value, "disabled") == 0) { + spapr->resize_hpt = SPAPR_RESIZE_HPT_DISABLED; + } else if (strcmp(value, "enabled") == 0) { + spapr->resize_hpt = SPAPR_RESIZE_HPT_ENABLED; + } else if (strcmp(value, "required") == 0) { + spapr->resize_hpt = SPAPR_RESIZE_HPT_REQUIRED; + } else { + error_setg(errp, "Bad value for \"resize-hpt\" property"); + } +} + static void spapr_machine_initfn(Object *obj) { sPAPRMachineState *spapr = SPAPR_MACHINE(obj); @@ -2603,6 +2671,12 @@ static void spapr_machine_initfn(Object *obj) ppc_compat_add_property(obj, "max-cpu-compat", &spapr->max_compat_pvr, "Maximum permitted CPU compatibility mode", &error_fatal); + + object_property_add_str(obj, "resize-hpt", + spapr_get_resize_hpt, spapr_set_resize_hpt, NULL); + object_property_set_description(obj, "resize-hpt", + "Resizing of the Hash Page Table (enabled, disabled, required)", + NULL); } static void spapr_machine_finalizefn(Object *obj) @@ -3361,6 +3435,7 @@ static void spapr_machine_class_init(ObjectClass *oc, void *data) smc->dr_lmb_enabled = true; smc->tcg_default_cpu = "POWER8"; mc->has_hotpluggable_cpus = true; + smc->resize_hpt_default = SPAPR_RESIZE_HPT_DISABLED; fwc->get_dev_path = spapr_get_fw_dev_path; nc->nmi_monitor_handler = spapr_nmi; smc->phb_placement = spapr_phb_placement; diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c index 8624ce8d5b..6ea8fa7394 100644 --- a/hw/ppc/spapr_hcall.c +++ b/hw/ppc/spapr_hcall.c @@ -354,6 +354,38 @@ static target_ulong h_read(PowerPCCPU *cpu, sPAPRMachineState *spapr, return H_SUCCESS; } +static target_ulong h_resize_hpt_prepare(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong shift = args[1]; + + if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) { + return H_AUTHORITY; + } + + trace_spapr_h_resize_hpt_prepare(flags, shift); + return H_HARDWARE; +} + +static target_ulong h_resize_hpt_commit(PowerPCCPU *cpu, + sPAPRMachineState *spapr, + target_ulong opcode, + target_ulong *args) +{ + target_ulong flags = args[0]; + target_ulong shift = args[1]; + + if (spapr->resize_hpt == SPAPR_RESIZE_HPT_DISABLED) { + return H_AUTHORITY; + } + + trace_spapr_h_resize_hpt_commit(flags, shift); + return H_HARDWARE; +} + static target_ulong h_set_sprg0(PowerPCCPU *cpu, sPAPRMachineState *spapr, target_ulong opcode, target_ulong *args) { @@ -1246,6 +1278,10 @@ static void hypercall_register_types(void) /* hcall-bulk */ spapr_register_hypercall(H_BULK_REMOVE, h_bulk_remove); + /* hcall-hpt-resize */ + spapr_register_hypercall(H_RESIZE_HPT_PREPARE, h_resize_hpt_prepare); + spapr_register_hypercall(H_RESIZE_HPT_COMMIT, h_resize_hpt_commit); + /* hcall-splpar */ spapr_register_hypercall(H_REGISTER_VPA, h_register_vpa); spapr_register_hypercall(H_CEDE, h_cede); diff --git a/hw/ppc/trace-events b/hw/ppc/trace-events index 8e79f7eaf6..0f7d9be4ef 100644 --- a/hw/ppc/trace-events +++ b/hw/ppc/trace-events @@ -16,6 +16,8 @@ spapr_cas_continue(unsigned long n) "Copy changes to the guest: %ld bytes" # hw/ppc/spapr_hcall.c spapr_cas_pvr_try(uint32_t pvr) "%x" spapr_cas_pvr(uint32_t cur_pvr, bool explicit_match, uint32_t new_pvr) "current=%x, explicit_match=%u, new=%x" +spapr_h_resize_hpt_prepare(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64 +spapr_h_resize_hpt_commit(uint64_t flags, uint64_t shift) "flags=0x%"PRIx64", shift=%"PRIu64 # hw/ppc/spapr_iommu.c spapr_iommu_put(uint64_t liobn, uint64_t ioba, uint64_t tce, uint64_t ret) "liobn=%"PRIx64" ioba=0x%"PRIx64" tce=0x%"PRIx64" ret=%"PRId64 diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 2ddec025d2..10ddb90711 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -42,6 +42,13 @@ typedef struct sPAPRMachineClass sPAPRMachineClass; #define SPAPR_MACHINE_CLASS(klass) \ OBJECT_CLASS_CHECK(sPAPRMachineClass, klass, TYPE_SPAPR_MACHINE) +typedef enum { + SPAPR_RESIZE_HPT_DEFAULT = 0, + SPAPR_RESIZE_HPT_DISABLED, + SPAPR_RESIZE_HPT_ENABLED, + SPAPR_RESIZE_HPT_REQUIRED, +} sPAPRResizeHPT; + /** * sPAPRMachineClass: */ @@ -58,6 +65,7 @@ struct sPAPRMachineClass { uint64_t *buid, hwaddr *pio, hwaddr *mmio32, hwaddr *mmio64, unsigned n_dma, uint32_t *liobns, Error **errp); + sPAPRResizeHPT resize_hpt_default; }; /** @@ -73,6 +81,7 @@ struct sPAPRMachineState { ICSState *ics; sPAPRRTCState rtc; + sPAPRResizeHPT resize_hpt; void *htab; uint32_t htab_shift; uint64_t patb_entry; /* Process tbl registed in H_REGISTER_PROCESS_TABLE */ @@ -367,6 +376,8 @@ struct sPAPRMachineState { #define H_XIRR_X 0x2FC #define H_RANDOM 0x300 #define H_SET_MODE 0x31C +#define H_RESIZE_HPT_PREPARE 0x36C +#define H_RESIZE_HPT_COMMIT 0x370 #define H_CLEAN_SLB 0x374 #define H_INVALIDATE_PID 0x378 #define H_REGISTER_PROC_TBL 0x37C diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index f7a7ea5858..8bafd1e932 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -22,6 +22,7 @@ #include <linux/kvm.h> #include "qemu-common.h" +#include "qapi/error.h" #include "qemu/error-report.h" #include "cpu.h" #include "cpu-models.h" @@ -2709,3 +2710,15 @@ int kvmppc_enable_hwrng(void) return kvmppc_enable_hcall(kvm_state, H_RANDOM); } + +void kvmppc_check_papr_resize_hpt(Error **errp) +{ + if (!kvm_enabled()) { + return; + } + + /* TODO: Check for resize-capable KVM implementations */ + + error_setg(errp, + "Hash page table resizing not available with this KVM version"); +} diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index eab7c8fdb3..9be706c5c9 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -63,6 +63,7 @@ bool kvmppc_has_cap_mmu_hash_v3(void); int kvmppc_enable_hwrng(void); int kvmppc_put_books_sregs(PowerPCCPU *cpu); PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); +void kvmppc_check_papr_resize_hpt(Error **errp); bool kvmppc_is_mem_backend_page_size_ok(const char *obj_path); @@ -297,6 +298,10 @@ static inline PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void) return NULL; } +static inline void kvmppc_check_papr_resize_hpt(Error **errp) +{ + return; +} #endif #ifndef CONFIG_KVM |