target-ppc: Add "compat" CPU option
PowerISA defines a compatibility mode for server POWERPC CPUs which is supported by the PCR special register which is hypervisor privileged. To support this mode for guests, SPAPR defines a set of virtual PVRs, one per PowerISA spec version. When a hypervisor needs a guest to work in a compatibility mode, it puts a virtual PVR value into @cpu-version property of a CPU node. This introduces a "compat" CPU option which defines maximal compatibility mode enabled. The supported modes are power6/power7/power8. This does not change the existing behaviour, new property will be used by next patches. Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru> Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
		
							parent
							
								
									af354f19a9
								
							
						
					
					
						commit
						8dfa3a5e85
					
				@ -595,6 +595,16 @@ enum {
 | 
				
			|||||||
    CPU_POWERPC_PA6T               = 0x00900000,
 | 
					    CPU_POWERPC_PA6T               = 0x00900000,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Logical PVR definitions for sPAPR */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
					    CPU_POWERPC_LOGICAL_2_04       = 0x0F000001,
 | 
				
			||||||
 | 
					    CPU_POWERPC_LOGICAL_2_05       = 0x0F000002,
 | 
				
			||||||
 | 
					    CPU_POWERPC_LOGICAL_2_06       = 0x0F000003,
 | 
				
			||||||
 | 
					    CPU_POWERPC_LOGICAL_2_06_PLUS  = 0x0F100003,
 | 
				
			||||||
 | 
					    CPU_POWERPC_LOGICAL_2_07       = 0x0F000004,
 | 
				
			||||||
 | 
					    CPU_POWERPC_LOGICAL_2_08       = 0x0F000005,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* System version register (used on MPC 8xxx)                                */
 | 
					/* System version register (used on MPC 8xxx)                                */
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
    POWERPC_SVR_NONE               = 0x00000000,
 | 
					    POWERPC_SVR_NONE               = 0x00000000,
 | 
				
			||||||
 | 
				
			|||||||
@ -83,6 +83,7 @@ typedef struct PowerPCCPUClass {
 | 
				
			|||||||
 * PowerPCCPU:
 | 
					 * PowerPCCPU:
 | 
				
			||||||
 * @env: #CPUPPCState
 | 
					 * @env: #CPUPPCState
 | 
				
			||||||
 * @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
 | 
					 * @cpu_dt_id: CPU index used in the device tree. KVM uses this index too
 | 
				
			||||||
 | 
					 * @max_compat: Maximal supported logical PVR from the command line
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * A PowerPC CPU.
 | 
					 * A PowerPC CPU.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@ -93,6 +94,7 @@ struct PowerPCCPU {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    CPUPPCState env;
 | 
					    CPUPPCState env;
 | 
				
			||||||
    int cpu_dt_id;
 | 
					    int cpu_dt_id;
 | 
				
			||||||
 | 
					    uint32_t max_compat;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
 | 
					static inline PowerPCCPU *ppc_env_get_cpu(CPUPPCState *env)
 | 
				
			||||||
 | 
				
			|||||||
@ -28,6 +28,8 @@
 | 
				
			|||||||
#include "mmu-hash32.h"
 | 
					#include "mmu-hash32.h"
 | 
				
			||||||
#include "mmu-hash64.h"
 | 
					#include "mmu-hash64.h"
 | 
				
			||||||
#include "qemu/error-report.h"
 | 
					#include "qemu/error-report.h"
 | 
				
			||||||
 | 
					#include "qapi/visitor.h"
 | 
				
			||||||
 | 
					#include "hw/qdev-properties.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//#define PPC_DUMP_CPU
 | 
					//#define PPC_DUMP_CPU
 | 
				
			||||||
//#define PPC_DEBUG_SPR
 | 
					//#define PPC_DEBUG_SPR
 | 
				
			||||||
@ -7680,6 +7682,76 @@ POWERPC_FAMILY(POWER5P)(ObjectClass *oc, void *data)
 | 
				
			|||||||
    pcc->l1_icache_size = 0x10000;
 | 
					    pcc->l1_icache_size = 0x10000;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void powerpc_get_compat(Object *obj, Visitor *v,
 | 
				
			||||||
 | 
					                               void *opaque, const char *name, Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    char *value = (char *)"";
 | 
				
			||||||
 | 
					    Property *prop = opaque;
 | 
				
			||||||
 | 
					    uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (*max_compat) {
 | 
				
			||||||
 | 
					    case CPU_POWERPC_LOGICAL_2_05:
 | 
				
			||||||
 | 
					        value = (char *)"power6";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case CPU_POWERPC_LOGICAL_2_06:
 | 
				
			||||||
 | 
					        value = (char *)"power7";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case CPU_POWERPC_LOGICAL_2_07:
 | 
				
			||||||
 | 
					        value = (char *)"power8";
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case 0:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        error_setg(errp, "Internal error: compat is set to %x",
 | 
				
			||||||
 | 
					                   max_compat ? *max_compat : -1);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    visit_type_str(v, &value, name, errp);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void powerpc_set_compat(Object *obj, Visitor *v,
 | 
				
			||||||
 | 
					                               void *opaque, const char *name, Error **errp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    Error *error = NULL;
 | 
				
			||||||
 | 
					    char *value = NULL;
 | 
				
			||||||
 | 
					    Property *prop = opaque;
 | 
				
			||||||
 | 
					    uint32_t *max_compat = qdev_get_prop_ptr(DEVICE(obj), prop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    visit_type_str(v, &value, name, &error);
 | 
				
			||||||
 | 
					    if (error) {
 | 
				
			||||||
 | 
					        error_propagate(errp, error);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (strcmp(value, "power6") == 0) {
 | 
				
			||||||
 | 
					        *max_compat = CPU_POWERPC_LOGICAL_2_05;
 | 
				
			||||||
 | 
					    } else if (strcmp(value, "power7") == 0) {
 | 
				
			||||||
 | 
					        *max_compat = CPU_POWERPC_LOGICAL_2_06;
 | 
				
			||||||
 | 
					    } else if (strcmp(value, "power8") == 0) {
 | 
				
			||||||
 | 
					        *max_compat = CPU_POWERPC_LOGICAL_2_07;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        error_setg(errp, "Invalid compatibility mode \"%s\"", value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    g_free(value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static PropertyInfo powerpc_compat_propinfo = {
 | 
				
			||||||
 | 
					    .name = "str",
 | 
				
			||||||
 | 
					    .legacy_name = "powerpc-server-compat",
 | 
				
			||||||
 | 
					    .get = powerpc_get_compat,
 | 
				
			||||||
 | 
					    .set = powerpc_set_compat,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEFINE_PROP_POWERPC_COMPAT(_n, _s, _f) \
 | 
				
			||||||
 | 
					    DEFINE_PROP(_n, _s, _f, powerpc_compat_propinfo, uint32_t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Property powerpc_servercpu_properties[] = {
 | 
				
			||||||
 | 
					    DEFINE_PROP_POWERPC_COMPAT("compat", PowerPCCPU, max_compat),
 | 
				
			||||||
 | 
					    DEFINE_PROP_END_OF_LIST(),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void init_proc_POWER7 (CPUPPCState *env)
 | 
					static void init_proc_POWER7 (CPUPPCState *env)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    gen_spr_ne_601(env);
 | 
					    gen_spr_ne_601(env);
 | 
				
			||||||
@ -7766,6 +7838,7 @@ POWERPC_FAMILY(POWER7)(ObjectClass *oc, void *data)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    dc->fw_name = "PowerPC,POWER7";
 | 
					    dc->fw_name = "PowerPC,POWER7";
 | 
				
			||||||
    dc->desc = "POWER7";
 | 
					    dc->desc = "POWER7";
 | 
				
			||||||
 | 
					    dc->props = powerpc_servercpu_properties;
 | 
				
			||||||
    pcc->pvr = CPU_POWERPC_POWER7_BASE;
 | 
					    pcc->pvr = CPU_POWERPC_POWER7_BASE;
 | 
				
			||||||
    pcc->pvr_mask = CPU_POWERPC_POWER7_MASK;
 | 
					    pcc->pvr_mask = CPU_POWERPC_POWER7_MASK;
 | 
				
			||||||
    pcc->init_proc = init_proc_POWER7;
 | 
					    pcc->init_proc = init_proc_POWER7;
 | 
				
			||||||
@ -7825,6 +7898,7 @@ POWERPC_FAMILY(POWER7P)(ObjectClass *oc, void *data)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    dc->fw_name = "PowerPC,POWER7+";
 | 
					    dc->fw_name = "PowerPC,POWER7+";
 | 
				
			||||||
    dc->desc = "POWER7+";
 | 
					    dc->desc = "POWER7+";
 | 
				
			||||||
 | 
					    dc->props = powerpc_servercpu_properties;
 | 
				
			||||||
    pcc->pvr = CPU_POWERPC_POWER7P_BASE;
 | 
					    pcc->pvr = CPU_POWERPC_POWER7P_BASE;
 | 
				
			||||||
    pcc->pvr_mask = CPU_POWERPC_POWER7P_MASK;
 | 
					    pcc->pvr_mask = CPU_POWERPC_POWER7P_MASK;
 | 
				
			||||||
    pcc->init_proc = init_proc_POWER7;
 | 
					    pcc->init_proc = init_proc_POWER7;
 | 
				
			||||||
@ -7896,6 +7970,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    dc->fw_name = "PowerPC,POWER8";
 | 
					    dc->fw_name = "PowerPC,POWER8";
 | 
				
			||||||
    dc->desc = "POWER8";
 | 
					    dc->desc = "POWER8";
 | 
				
			||||||
 | 
					    dc->props = powerpc_servercpu_properties;
 | 
				
			||||||
    pcc->pvr = CPU_POWERPC_POWER8_BASE;
 | 
					    pcc->pvr = CPU_POWERPC_POWER8_BASE;
 | 
				
			||||||
    pcc->pvr_mask = CPU_POWERPC_POWER8_MASK;
 | 
					    pcc->pvr_mask = CPU_POWERPC_POWER8_MASK;
 | 
				
			||||||
    pcc->init_proc = init_proc_POWER8;
 | 
					    pcc->init_proc = init_proc_POWER8;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user