Skip to content

Commit

Permalink
Merge pull request #3 from rmatinata/rmm-spurr-fix
Browse files Browse the repository at this point in the history
SPURR and RTAS Fixes
  • Loading branch information
malcolmcrossley committed Apr 30, 2018
2 parents ffccbb8 + cbe7e27 commit 73a5797
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 15 deletions.
1 change: 1 addition & 0 deletions hw/ppc/spapr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

}

Expand Down
54 changes: 51 additions & 3 deletions hw/ppc/spapr_rtas.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -281,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;
Expand All @@ -299,6 +310,42 @@ static void rtas_ibm_get_system_parameter(PowerPCCPU *cpu,
ret = sysparm_st(buffer, length, &param_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;
Expand All @@ -321,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;
Expand Down
3 changes: 3 additions & 0 deletions include/hw/ppc/spapr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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__) */
1 change: 1 addition & 0 deletions linux-headers/asm-powerpc/kvm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
140 changes: 140 additions & 0 deletions target-ppc/kvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "qemu/osdep.h"
#include <dirent.h>
#include <glob.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/vfs.h>
Expand Down Expand Up @@ -2682,3 +2683,142 @@ 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);
}
}

/* 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;
}

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;
}
33 changes: 21 additions & 12 deletions target-ppc/kvm_ppc.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ 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);
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

Expand Down Expand Up @@ -153,6 +156,24 @@ 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;
}

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)
{
Expand Down Expand Up @@ -316,16 +337,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__ */

0 comments on commit 73a5797

Please sign in to comment.