ppc: Rework POWER7 & POWER8 exception model
From: Benjamin Herrenschmidt <benh@kernel.crashing.org> This patch fixes the current AIL implementation for POWER8. The interrupt vector address can be calculated directly from LPCR when the exception is handled. The excp_prefix update becomes useless and we can cleanup the H_SET_MODE hcall. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> [clg: Removed LPES0/1 handling for HV vs. !HV Fixed LPCR_ILE case for POWERPC_EXCP_POWER8 ] Signed-off-by: Cédric Le Goater <clg@fr.ibm.com> [dwg: This was written as a cleanup, but it also fixes a real bug where setting an alternative interrupt location would not be correctly migrated] Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
parent
2e3a76ae3e
commit
5c94b2a5e5
@ -824,7 +824,6 @@ static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu,
|
|||||||
{
|
{
|
||||||
CPUState *cs;
|
CPUState *cs;
|
||||||
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
|
||||||
target_ulong prefix;
|
|
||||||
|
|
||||||
if (!(pcc->insns_flags2 & PPC2_ISA207S)) {
|
if (!(pcc->insns_flags2 & PPC2_ISA207S)) {
|
||||||
return H_P2;
|
return H_P2;
|
||||||
@ -836,25 +835,12 @@ static target_ulong h_set_mode_resource_addr_trans_mode(PowerPCCPU *cpu,
|
|||||||
return H_P4;
|
return H_P4;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (mflags) {
|
if (mflags == AIL_RESERVED) {
|
||||||
case H_SET_MODE_ADDR_TRANS_NONE:
|
|
||||||
prefix = 0;
|
|
||||||
break;
|
|
||||||
case H_SET_MODE_ADDR_TRANS_0001_8000:
|
|
||||||
prefix = 0x18000;
|
|
||||||
break;
|
|
||||||
case H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000:
|
|
||||||
prefix = 0xC000000000004000ULL;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return H_UNSUPPORTED_FLAG;
|
return H_UNSUPPORTED_FLAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
CPU_FOREACH(cs) {
|
CPU_FOREACH(cs) {
|
||||||
CPUPPCState *env = &POWERPC_CPU(cpu)->env;
|
|
||||||
|
|
||||||
set_spr(cs, SPR_LPCR, mflags << LPCR_AIL_SHIFT, LPCR_AIL);
|
set_spr(cs, SPR_LPCR, mflags << LPCR_AIL_SHIFT, LPCR_AIL);
|
||||||
env->excp_prefix = prefix;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return H_SUCCESS;
|
return H_SUCCESS;
|
||||||
|
@ -204,11 +204,6 @@ struct sPAPRMachineState {
|
|||||||
#define H_SET_MODE_ENDIAN_BIG 0
|
#define H_SET_MODE_ENDIAN_BIG 0
|
||||||
#define H_SET_MODE_ENDIAN_LITTLE 1
|
#define H_SET_MODE_ENDIAN_LITTLE 1
|
||||||
|
|
||||||
/* Flags for H_SET_MODE_RESOURCE_ADDR_TRANS_MODE */
|
|
||||||
#define H_SET_MODE_ADDR_TRANS_NONE 0
|
|
||||||
#define H_SET_MODE_ADDR_TRANS_0001_8000 2
|
|
||||||
#define H_SET_MODE_ADDR_TRANS_C000_0000_0000_4000 3
|
|
||||||
|
|
||||||
/* VASI States */
|
/* VASI States */
|
||||||
#define H_VASI_INVALID 0
|
#define H_VASI_INVALID 0
|
||||||
#define H_VASI_ENABLED 1
|
#define H_VASI_ENABLED 1
|
||||||
|
@ -167,6 +167,8 @@ enum powerpc_excp_t {
|
|||||||
POWERPC_EXCP_970,
|
POWERPC_EXCP_970,
|
||||||
/* POWER7 exception model */
|
/* POWER7 exception model */
|
||||||
POWERPC_EXCP_POWER7,
|
POWERPC_EXCP_POWER7,
|
||||||
|
/* POWER8 exception model */
|
||||||
|
POWERPC_EXCP_POWER8,
|
||||||
#endif /* defined(TARGET_PPC64) */
|
#endif /* defined(TARGET_PPC64) */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2277,6 +2279,14 @@ enum {
|
|||||||
HMER_XSCOM_STATUS_LSH = (63 - 23),
|
HMER_XSCOM_STATUS_LSH = (63 - 23),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Alternate Interrupt Location (AIL) */
|
||||||
|
enum {
|
||||||
|
AIL_NONE = 0,
|
||||||
|
AIL_RESERVED = 1,
|
||||||
|
AIL_0001_8000 = 2,
|
||||||
|
AIL_C000_0000_0000_4000 = 3,
|
||||||
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static inline target_ulong cpu_read_xer(CPUPPCState *env)
|
static inline target_ulong cpu_read_xer(CPUPPCState *env)
|
||||||
|
@ -77,7 +77,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
|||||||
CPUPPCState *env = &cpu->env;
|
CPUPPCState *env = &cpu->env;
|
||||||
target_ulong msr, new_msr, vector;
|
target_ulong msr, new_msr, vector;
|
||||||
int srr0, srr1, asrr0, asrr1;
|
int srr0, srr1, asrr0, asrr1;
|
||||||
int lpes0, lpes1, lev;
|
int lpes0, lpes1, lev, ail;
|
||||||
|
|
||||||
if (0) {
|
if (0) {
|
||||||
/* XXX: find a suitable condition to enable the hypervisor mode */
|
/* XXX: find a suitable condition to enable the hypervisor mode */
|
||||||
@ -108,6 +108,25 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
|||||||
asrr0 = -1;
|
asrr0 = -1;
|
||||||
asrr1 = -1;
|
asrr1 = -1;
|
||||||
|
|
||||||
|
/* Exception targetting modifiers
|
||||||
|
*
|
||||||
|
* AIL is initialized here but can be cleared by
|
||||||
|
* selected exceptions
|
||||||
|
*/
|
||||||
|
#if defined(TARGET_PPC64)
|
||||||
|
if (excp_model == POWERPC_EXCP_POWER7 ||
|
||||||
|
excp_model == POWERPC_EXCP_POWER8) {
|
||||||
|
if (excp_model == POWERPC_EXCP_POWER8) {
|
||||||
|
ail = (env->spr[SPR_LPCR] & LPCR_AIL) >> LPCR_AIL_SHIFT;
|
||||||
|
} else {
|
||||||
|
ail = 0;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif /* defined(TARGET_PPC64) */
|
||||||
|
{
|
||||||
|
ail = 0;
|
||||||
|
}
|
||||||
|
|
||||||
switch (excp) {
|
switch (excp) {
|
||||||
case POWERPC_EXCP_NONE:
|
case POWERPC_EXCP_NONE:
|
||||||
/* Should never happen */
|
/* Should never happen */
|
||||||
@ -146,6 +165,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
|||||||
/* XXX: find a suitable condition to enable the hypervisor mode */
|
/* XXX: find a suitable condition to enable the hypervisor mode */
|
||||||
new_msr |= (target_ulong)MSR_HVB;
|
new_msr |= (target_ulong)MSR_HVB;
|
||||||
}
|
}
|
||||||
|
ail = 0;
|
||||||
|
|
||||||
/* machine check exceptions don't have ME set */
|
/* machine check exceptions don't have ME set */
|
||||||
new_msr &= ~((target_ulong)1 << MSR_ME);
|
new_msr &= ~((target_ulong)1 << MSR_ME);
|
||||||
@ -344,6 +364,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
|||||||
/* XXX: find a suitable condition to enable the hypervisor mode */
|
/* XXX: find a suitable condition to enable the hypervisor mode */
|
||||||
new_msr |= (target_ulong)MSR_HVB;
|
new_msr |= (target_ulong)MSR_HVB;
|
||||||
}
|
}
|
||||||
|
ail = 0;
|
||||||
goto store_next;
|
goto store_next;
|
||||||
case POWERPC_EXCP_DSEG: /* Data segment exception */
|
case POWERPC_EXCP_DSEG: /* Data segment exception */
|
||||||
if (lpes1 == 0) {
|
if (lpes1 == 0) {
|
||||||
@ -630,7 +651,8 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TARGET_PPC64
|
#ifdef TARGET_PPC64
|
||||||
if (excp_model == POWERPC_EXCP_POWER7) {
|
if (excp_model == POWERPC_EXCP_POWER7 ||
|
||||||
|
excp_model == POWERPC_EXCP_POWER8) {
|
||||||
if (env->spr[SPR_LPCR] & LPCR_ILE) {
|
if (env->spr[SPR_LPCR] & LPCR_ILE) {
|
||||||
new_msr |= (target_ulong)1 << MSR_LE;
|
new_msr |= (target_ulong)1 << MSR_LE;
|
||||||
}
|
}
|
||||||
@ -650,6 +672,29 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
|
|||||||
excp);
|
excp);
|
||||||
}
|
}
|
||||||
vector |= env->excp_prefix;
|
vector |= env->excp_prefix;
|
||||||
|
|
||||||
|
/* AIL only works if there is no HV transition and we are running with
|
||||||
|
* translations enabled
|
||||||
|
*/
|
||||||
|
if (!((msr >> MSR_IR) & 1) || !((msr >> MSR_DR) & 1)) {
|
||||||
|
ail = 0;
|
||||||
|
}
|
||||||
|
/* Handle AIL */
|
||||||
|
if (ail) {
|
||||||
|
new_msr |= (1 << MSR_IR) | (1 << MSR_DR);
|
||||||
|
switch(ail) {
|
||||||
|
case AIL_0001_8000:
|
||||||
|
vector |= 0x18000;
|
||||||
|
break;
|
||||||
|
case AIL_C000_0000_0000_4000:
|
||||||
|
vector |= 0xc000000000004000ull;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cpu_abort(cs, "Invalid AIL combination %d\n", ail);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(TARGET_PPC64)
|
#if defined(TARGET_PPC64)
|
||||||
if (excp_model == POWERPC_EXCP_BOOKE) {
|
if (excp_model == POWERPC_EXCP_BOOKE) {
|
||||||
if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
|
if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
|
||||||
|
@ -8487,7 +8487,7 @@ POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)
|
|||||||
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
|
pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;
|
||||||
pcc->sps = &POWER7_POWER8_sps;
|
pcc->sps = &POWER7_POWER8_sps;
|
||||||
#endif
|
#endif
|
||||||
pcc->excp_model = POWERPC_EXCP_POWER7;
|
pcc->excp_model = POWERPC_EXCP_POWER8;
|
||||||
pcc->bus_model = PPC_FLAGS_INPUT_POWER7;
|
pcc->bus_model = PPC_FLAGS_INPUT_POWER7;
|
||||||
pcc->bfd_mach = bfd_mach_ppc64;
|
pcc->bfd_mach = bfd_mach_ppc64;
|
||||||
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
|
pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |
|
||||||
|
Loading…
Reference in New Issue
Block a user