From 776c12a84f3f8f3baf633a027b2ba5218a27be1b Mon Sep 17 00:00:00 2001 From: "Ricardo M. Matinata" Date: Wed, 25 Apr 2018 23:45:07 +0000 Subject: [PATCH 1/5] Remove duplicated declaration of KVM_INTERRUPT_S* --- target-ppc/kvm_ppc.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 15c8af37f7eb..4c6aaeb07975 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -316,16 +316,4 @@ static inline void kvmppc_icbi_range(PowerPCCPU *cpu, uint8_t *addr, int len) #endif /* CONFIG_KVM */ -#ifndef KVM_INTERRUPT_SET -#define KVM_INTERRUPT_SET -1 -#endif - -#ifndef KVM_INTERRUPT_UNSET -#define KVM_INTERRUPT_UNSET -2 -#endif - -#ifndef KVM_INTERRUPT_SET_LEVEL -#define KVM_INTERRUPT_SET_LEVEL -3 -#endif - #endif /* __KVM_PPC_H__ */ From 5c7d96806c24d455ab515eb1dfc1cfc3f9e15099 Mon Sep 17 00:00:00 2001 From: Nikunj A Dadhania Date: Mon, 23 Apr 2018 11:43:02 +0530 Subject: [PATCH 2/5] target/ppc/kvm: set vcpu as online/offline Set the newly added register(KVM_REG_PPC_ONLINE) to indicate if the vcpu is online(1) or offline(0) KVM will use this information to set the RWMR register, which controls the PURR and SPURR accumulation. CC: paulus@samba.org Signed-off-by: Nikunj A Dadhania Signed-off-by: Ricardo M. Matinata --- hw/ppc/spapr.c | 1 + hw/ppc/spapr_rtas.c | 4 ++++ linux-headers/asm-powerpc/kvm.h | 1 + target-ppc/kvm.c | 9 +++++++++ target-ppc/kvm_ppc.h | 6 ++++++ 5 files changed, 21 insertions(+) diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c index 89dce7822864..4d0c0c829b15 100644 --- a/hw/ppc/spapr.c +++ b/hw/ppc/spapr.c @@ -1200,6 +1200,7 @@ static void ppc_spapr_reset(void) first_ppc_cpu->env.gpr[5] = 0; first_cpu->halted = 0; first_ppc_cpu->env.nip = SPAPR_ENTRY_POINT; + kvmppc_set_reg_ppc_online(first_ppc_cpu, 1); } diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index e53ecc040ab6..d8fd74d4f96e 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -31,6 +31,7 @@ #include "hw/qdev.h" #include "sysemu/device_tree.h" #include "sysemu/cpus.h" +#include "kvm_ppc.h" #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" @@ -223,6 +224,8 @@ static void rtas_start_cpu(PowerPCCPU *cpu_, sPAPRMachineState *spapr, spapr_cpu_set_endianness(cpu); spapr_cpu_update_tb_offset(cpu); + kvmppc_set_reg_ppc_online(cpu, 1); + qemu_cpu_kick(cs); rtas_st(rets, 0, RTAS_OUT_SUCCESS); @@ -242,6 +245,7 @@ static void rtas_stop_self(PowerPCCPU *cpu, sPAPRMachineState *spapr, CPUPPCState *env = &cpu->env; cs->halted = 1; + kvmppc_set_reg_ppc_online(cpu, 0); qemu_cpu_kick(cs); /* * While stopping a CPU, the guest calls H_CPPR which diff --git a/linux-headers/asm-powerpc/kvm.h b/linux-headers/asm-powerpc/kvm.h index b1e235dfcd6f..a5ce4b546ef4 100644 --- a/linux-headers/asm-powerpc/kvm.h +++ b/linux-headers/asm-powerpc/kvm.h @@ -580,6 +580,7 @@ struct kvm_ppc_cpu_char { #define KVM_REG_PPC_WORT (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb9) #define KVM_REG_PPC_SPRG9 (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xba) #define KVM_REG_PPC_DBSR (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xbb) +#define KVM_REG_PPC_ONLINE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xbf) /* Transactional Memory checkpointed state: * This is all GPRs, all VSX regs and a subset of SPRs diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index f338ae1de4ae..e8769a5871bb 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -2682,3 +2682,12 @@ int kvmppc_enable_hwrng(void) return kvmppc_enable_hcall(kvm_state, H_RANDOM); } + +void kvmppc_set_reg_ppc_online(PowerPCCPU *cpu, unsigned int online) +{ + CPUState *cs = CPU(cpu); + + if (kvm_enabled()) { + kvm_set_one_reg(cs, KVM_REG_PPC_ONLINE, &online); + } +} diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 4c6aaeb07975..e96502a94da6 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -59,6 +59,7 @@ uint64_t kvmppc_get_cap_ppc_cpu_char_behaviour(void); int kvmppc_enable_hwrng(void); int kvmppc_put_books_sregs(PowerPCCPU *cpu); PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); +void kvmppc_set_reg_ppc_online(PowerPCCPU *cpu, unsigned int online); #else @@ -153,6 +154,11 @@ static inline int kvmppc_booke_watchdog_enable(PowerPCCPU *cpu) return -1; } +static inline void kvmppc_set_reg_ppc_online(PowerPCCPU *cpu, unsigned int online) +{ + return; +} + #ifndef CONFIG_USER_ONLY static inline off_t kvmppc_alloc_rma(void **rma) { From 8f45eb0a634c44eb92537abd69d58c92e2ef5b74 Mon Sep 17 00:00:00 2001 From: "Ricardo M. Matinata" Date: Fri, 27 Apr 2018 21:11:43 +0000 Subject: [PATCH 3/5] target-ppc: Add helper funtions for counting cores and chips Add helper fucnctions for counting physical cores and chips, from the underlying host (KVM only). These functions will be used by later patches. Signed-off-by: Ricardo M. Matinata --- target-ppc/kvm.c | 110 +++++++++++++++++++++++++++++++++++++++++++ target-ppc/kvm_ppc.h | 6 +++ 2 files changed, 116 insertions(+) diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index e8769a5871bb..6c9c27496950 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -16,6 +16,7 @@ #include "qemu/osdep.h" #include +#include #include #include #include @@ -2691,3 +2692,112 @@ void kvmppc_set_reg_ppc_online(PowerPCCPU *cpu, unsigned int online) kvm_set_one_reg(cs, KVM_REG_PPC_ONLINE, &online); } } + +/* Read an identifier from the file @path and add the identifier + * to the hash table @gt unless its already in the table. + */ +static int kvmppc_hash_file_contents(GHashTable *gt, char *path) +{ + uint32_t idx; + + idx = kvmppc_read_int_dt(path); + if (idx == -1) { + return -1; + } + + if (g_hash_table_contains(gt, GINT_TO_POINTER(idx))) { + return 0; + } + + if (!g_hash_table_insert(gt, GINT_TO_POINTER(idx), NULL)) { + fprintf(stderr, "%s() Unable to add key %d\n", __func__, idx); + return -1; + } + + return 0; +} + +static int kvmppc_glob_count_ids_dt(const char *pattern, int *count) +{ + int i, rc; + glob_t dtglob; + GHashTable *htbl; + + rc = glob(pattern, GLOB_NOSORT, NULL, &dtglob); + if (rc) + return -1; + + rc = -1; + htbl = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, NULL); + + for (i = 0; i < dtglob.gl_pathc; i++) { + if (kvmppc_hash_file_contents(htbl, dtglob.gl_pathv[i])) { + goto cleanup; + } + } + + *count = g_hash_table_size(htbl); + rc = 0; + +cleanup: + globfree(&dtglob); + g_hash_table_remove_all(htbl); + g_hash_table_destroy(htbl); + + return rc; +} + +/* Each socket's (aka module's) id is contained in the 'ibm,hw-module-id' + * file in an "xscom" directory (/proc/device-tree/xscom*). Similarly each + * chip's id is contained in the 'ibm,chip-id' file in an xscom directory. + * + * Search the xscom directories and count the number of _UNIQUE_ modules + * and chips in the system. + * + * If the system does not contain 'ibm,hw-module-id', it is assumed to be + * one chip per module (SCM), so make modules count equals to chips count. + * + * Return 0 if one or more modules and chips each are found. Return -1 + * otherwise. + */ +static int kvmppc_count_sockets_chips_dt(int *num_sockets, int *num_chips) +{ + const char *chip_pattern = "/proc/device-tree/xscom*/ibm,chip-id"; + const char *module_pattern = +"/proc/device-tree/xscom*/ibm,hw-module-id"; + + if (kvmppc_glob_count_ids_dt(module_pattern, num_sockets)) + // SCM system + if (kvmppc_glob_count_ids_dt(chip_pattern, num_sockets)) + return -1; + if (kvmppc_glob_count_ids_dt(chip_pattern, num_chips)) + return -1; + + if (*num_sockets == 0 || *num_chips == 0) { + return -1; + } + + return 0; +} + +int kvmppc_count_ppc_cores_dt(void) +{ + int rc,num_cores = 0; + const char *cores_pattern = "/proc/device-tree/cpus/PowerPC,POWER*"; + glob_t dtglob; + + rc = glob(cores_pattern, GLOB_NOSORT, NULL, &dtglob); + if (rc) { + fprintf(stderr, "%s() glob(%s) returns %d, errno %d\n", __func__, + cores_pattern, rc, errno); + return -1; + } + + num_cores = dtglob.gl_pathc; + globfree(&dtglob); + + if (num_cores == 0) + return -1; + + return num_cores; +} diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index e96502a94da6..011a4766eab0 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -60,6 +60,7 @@ int kvmppc_enable_hwrng(void); int kvmppc_put_books_sregs(PowerPCCPU *cpu); PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); void kvmppc_set_reg_ppc_online(PowerPCCPU *cpu, unsigned int online); +int kvmppc_count_ppc_cores_dt(void); #else @@ -159,6 +160,11 @@ static inline void kvmppc_set_reg_ppc_online(PowerPCCPU *cpu, unsigned int onlin return; } +static inline int kvmppc_count_ppc_cores_dt(void) +{ + return -1; +} + #ifndef CONFIG_USER_ONLY static inline off_t kvmppc_alloc_rma(void **rma) { From 5b5e7a60d655df67c086530acb8085b59d343e39 Mon Sep 17 00:00:00 2001 From: "Ricardo M. Matinata" Date: Fri, 27 Apr 2018 21:18:00 +0000 Subject: [PATCH 4/5] hw/ppc: Modify rtas_get_sysparm(RTAS_SYSPARM_SPLPAR_CHARACTERISTICS) Modify RTAS_SYSPARM_SPLPAR_CHARACTERISTICS from rtas_get_sysparm() call in qemu so MaxEntCap, DesProcs and MaxPlatProcs key returns values as per specified in the PAPR. Linux does not actually make use of these values, currently, but other OSes depend on the correct interpretation of these values. As for DesProcs, the PAPR says "The desired number of virtual processors set by the system administrator in the partition definition. The desired number of processors can change without a reboot of the partition. ". The PAPR uses the term "virtual processors" a bit loosely, but in practice, this should be equal to the number of virtual cores assigned to the guest. According to PAPR, MaxEntCap should be "The maximum entitled capacity currently that can be assigned to the partition through DLPAR/WLM. The capacity is expressed as a percentage of a physical processor. The Maximum entitled capacity is set up by the system administrator in the partition definition. A change in the maximum entitled capacity maximum takes effect on the next reboot of the partition (...) The maximum numeric value of Maximum Entitled Capacity is the number of processors on the platform multiplied by 100". To be consistent with the interpretation of "processor" as being core, this should be set as the max. number of virtual cores set for the VM multiplied by 100. Now regarding MaxPlatProcs, the PAPR says "The maximum number of processors that can be active on the platform. A change in the maximum platform processors takes effect on the next reboot of the partition.". When KVM is running, this is the number of actual cores from the host. Signed-off-by: Ricardo M. Matinata --- hw/ppc/spapr_rtas.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index d8fd74d4f96e..d4848c701c6e 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -285,14 +285,21 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu, switch (parameter) { case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: { + int virtcores_nr = smp_cpus / smp_threads; + int max_virtcores_nr = max_cpus / smp_threads; + int max_ent = max_virtcores_nr * 100; + int physical_cores_nr = kvmppc_count_ppc_cores_dt(); + if (physical_cores_nr < 0) { + physical_cores_nr = max_virtcores_nr; + } char *param_val = g_strdup_printf("MaxEntCap=%d," "DesMem=%llu," "DesProcs=%d," "MaxPlatProcs=%d", - max_cpus, + max_ent, current_machine->ram_size / M_BYTE, - smp_cpus, - max_cpus); + virtcores_nr, + physical_cores_nr); ret = sysparm_st(buffer, length, param_val, strlen(param_val) + 1); g_free(param_val); break; From cbe7e270293d9b301a6e10a7e6719a04032c721a Mon Sep 17 00:00:00 2001 From: "Ricardo M. Matinata" Date: Fri, 27 Apr 2018 22:58:45 +0000 Subject: [PATCH 5/5] hw/ppc: Implement rtas_get_sysparm(PROCESSOR_MODULE_INFO) Implement RTAS_SYSPARM_PROCESSOR_MODULE_INFO parameter to rtas_get_sysparm() call in qemu. This call returns the processor module (socket), chip and core information as specified in the PAPR. Currently, number of modules types is set to one (since in practice it is the case) Signed-off-by: Ricardo M. Matinata --- hw/ppc/spapr_rtas.c | 37 +++++++++++++++++++++++++++++++++++++ include/hw/ppc/spapr.h | 3 +++ target-ppc/kvm.c | 21 +++++++++++++++++++++ target-ppc/kvm_ppc.h | 9 +++++++++ 4 files changed, 70 insertions(+) diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index d4848c701c6e..7a342e01fcf5 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -310,6 +310,42 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu, ret = sysparm_st(buffer, length, ¶m_val, sizeof(param_val)); break; } + case RTAS_SYSPARM_PROCESSOR_MODULE_INFO: { + int i, offset = 0; + uint16_t cores[SPAPR_MAX_MODULE_TYPES], + chips[SPAPR_MAX_MODULE_TYPES], + sockets[SPAPR_MAX_MODULE_TYPES], + mtypes = 0, len; + + if (kvmppc_rtas_get_proc_module_info(&mtypes,sockets,chips,cores)) { + ret = RTAS_OUT_NOT_SUPPORTED; + break; + } + len = (mtypes*6) + 2; + + stw_be_phys(&address_space_memory, + ppc64_phys_to_real(buffer+offset), len); + offset += 2; + + stw_be_phys(&address_space_memory, + ppc64_phys_to_real(buffer+offset), mtypes); + offset += 2; + + for (i = 0; i < mtypes; i++) { + stw_be_phys(&address_space_memory, + ppc64_phys_to_real(buffer+offset), sockets[i]); + offset += 2; + stw_be_phys(&address_space_memory, + ppc64_phys_to_real(buffer+offset), chips[i]); + offset += 2; + stw_be_phys(&address_space_memory, + ppc64_phys_to_real(buffer+offset), cores[i]); + offset += 2; + } + + ret = RTAS_OUT_SUCCESS; + break; + } case RTAS_SYSPARM_UUID: ret = sysparm_st(buffer, length, qemu_uuid, (qemu_uuid_set ? 16 : 0)); break; @@ -332,6 +368,7 @@ static void rtas_ibm_set_system_parameter(PowerPCCPU *cpu, switch (parameter) { case RTAS_SYSPARM_SPLPAR_CHARACTERISTICS: case RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE: + case RTAS_SYSPARM_PROCESSOR_MODULE_INFO: case RTAS_SYSPARM_UUID: ret = RTAS_OUT_NOT_AUTHORIZED; break; diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index ff5dc8753c49..23112da66ef3 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -489,6 +489,7 @@ int spapr_allocate_irq_block(int num, bool lsi, bool msi); /* RTAS ibm,get-system-parameter token values */ #define RTAS_SYSPARM_SPLPAR_CHARACTERISTICS 20 #define RTAS_SYSPARM_DIAGNOSTICS_RUN_MODE 42 +#define RTAS_SYSPARM_PROCESSOR_MODULE_INFO 43 #define RTAS_SYSPARM_UUID 48 /* RTAS indicator/sensor types @@ -658,4 +659,6 @@ int spapr_rng_populate_dt(void *fdt); */ #define SPAPR_LMB_FLAGS_ASSIGNED 0x00000008 +#define SPAPR_MAX_MODULE_TYPES 1 + #endif /* !defined (__HW_SPAPR_H__) */ diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 6c9c27496950..2350e48c15e9 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -2801,3 +2801,24 @@ int kvmppc_count_ppc_cores_dt(void) return num_cores; } + +int kvmppc_rtas_get_proc_module_info(uint16_t *mtypes, uint16_t *sockets, uint16_t *chips, uint16_t *cores) +{ + int _sockets = 0, _chips = 0, _cores = 0; + + /* POWER systems only support 1 module type per system + * currently + */ + mtypes[0] = 1; + if (kvmppc_count_sockets_chips_dt(&_sockets, &_chips)) + return -1; + _cores = kvmppc_count_ppc_cores_dt(); + if ( _cores <= 0 ) + return -1; + + sockets[0] = _sockets; + chips[0] = _chips / _sockets; + cores[0] = _cores / _chips; + + return 0; +} diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h index 011a4766eab0..5c02c28f5879 100644 --- a/target-ppc/kvm_ppc.h +++ b/target-ppc/kvm_ppc.h @@ -61,6 +61,7 @@ int kvmppc_put_books_sregs(PowerPCCPU *cpu); PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void); void kvmppc_set_reg_ppc_online(PowerPCCPU *cpu, unsigned int online); int kvmppc_count_ppc_cores_dt(void); +int kvmppc_rtas_get_proc_module_info(uint16_t *mtypes, uint16_t *sockets, uint16_t *chips, uint16_t *cores); #else @@ -165,6 +166,14 @@ static inline int kvmppc_count_ppc_cores_dt(void) return -1; } +static int kvmppc_rtas_get_proc_module_info(uint16_t *mtypes, + uint16_t *sockets, + uint16_t *chips, + uint16_t *cores) +{ + return -1; +} + #ifndef CONFIG_USER_ONLY static inline off_t kvmppc_alloc_rma(void **rma) {