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:
Cédric Le Goater 2016-04-03 19:57:50 +02:00 committed by David Gibson
parent 2e3a76ae3e
commit 5c94b2a5e5
5 changed files with 59 additions and 23 deletions

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -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) {

View File

@ -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 |