Commit d8ce5fd6 authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt Committed by David Gibson
Browse files

target/ppc: Add Hypervisor Virtualization Interrupt on POWER9



This adds support for delivering that exception

Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: default avatarCédric Le Goater <clg@kaod.org>
Reviewed-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
Message-Id: <20190215161648.9600-9-clg@kaod.org>
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
parent f8154fd2
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -160,8 +160,10 @@ enum {
    /* Server doorbell variants */
    POWERPC_EXCP_SDOOR    = 99,
    POWERPC_EXCP_SDOOR_HV = 100,
    /* ISA 3.00 additions */
    POWERPC_EXCP_HVIRT    = 101,
    /* EOL                                                                   */
    POWERPC_EXCP_NB       = 101,
    POWERPC_EXCP_NB       = 102,
    /* QEMU exceptions: used internally during code translation              */
    POWERPC_EXCP_STOP         = 0x200, /* stop translation                   */
    POWERPC_EXCP_BRANCH       = 0x201, /* branch instruction                 */
@@ -2349,6 +2351,7 @@ enum {
    PPC_INTERRUPT_PERFM,          /* Performance monitor interrupt        */
    PPC_INTERRUPT_HMI,            /* Hypervisor Maintainance interrupt    */
    PPC_INTERRUPT_HDOORBELL,      /* Hypervisor Doorbell interrupt        */
    PPC_INTERRUPT_HVIRT,          /* Hypervisor virtualization interrupt  */
};

/* Processor Compatibility mask (PCR) */
+16 −1
Original line number Diff line number Diff line
@@ -97,6 +97,9 @@ static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
    case POWERPC_EXCP_HV_MAINT:
        *msr |= 0xaull << (63 - 45);
        break;
    case POWERPC_EXCP_HVIRT:
        *msr |= 0x9ull << (63 - 45);
        break;
    default:
        cpu_abort(cs, "Unsupported exception %d in Power Save mode\n",
                  excp);
@@ -427,6 +430,7 @@ static inline void powerpc_excp(PowerPCCPU *cpu, int excp_model, int excp)
    case POWERPC_EXCP_HISEG:     /* Hypervisor instruction segment exception */
    case POWERPC_EXCP_SDOOR_HV:  /* Hypervisor Doorbell interrupt            */
    case POWERPC_EXCP_HV_EMU:
    case POWERPC_EXCP_HVIRT:     /* Hypervisor virtualization                */
        srr0 = SPR_HSRR0;
        srr1 = SPR_HSRR1;
        new_msr |= (target_ulong)MSR_HVB;
@@ -809,7 +813,18 @@ static void ppc_hw_interrupt(CPUPPCState *env)
            return;
        }
    }
    /* Extermal interrupt can ignore MSR:EE under some circumstances */

    /* Hypervisor virtualization interrupt */
    if (env->pending_interrupts & (1 << PPC_INTERRUPT_HVIRT)) {
        /* LPCR will be clear when not supported so this will work */
        bool hvice = !!(env->spr[SPR_LPCR] & LPCR_HVICE);
        if ((async_deliver || msr_hv == 0) && hvice) {
            powerpc_excp(cpu, env->excp_model, POWERPC_EXCP_HVIRT);
            return;
        }
    }

    /* External interrupt can ignore MSR:EE under some circumstances */
    if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
        bool lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
        if (async_deliver || (env->has_hv_mode && msr_hv == 0 && !lpes0)) {
+15 −1
Original line number Diff line number Diff line
@@ -3313,6 +3313,15 @@ static void init_excp_POWER8(CPUPPCState *env)
#endif
}

static void init_excp_POWER9(CPUPPCState *env)
{
    init_excp_POWER8(env);

#if !defined(CONFIG_USER_ONLY)
    env->excp_vectors[POWERPC_EXCP_HVIRT]    = 0x00000EA0;
#endif
}

#endif

/*****************************************************************************/
@@ -8783,7 +8792,7 @@ static void init_proc_POWER9(CPUPPCState *env)
    env->icache_line_size = 128;

    /* Allocate hardware IRQ controller */
    init_excp_POWER8(env);
    init_excp_POWER9(env);
    ppcPOWER7_irq_init(ppc_env_get_cpu(env));
}

@@ -8836,6 +8845,11 @@ static bool cpu_has_work_POWER9(CPUState *cs)
            (env->spr[SPR_LPCR] & LPCR_HDEE)) {
            return true;
        }
        /* Hypervisor virtualization exception */
        if ((env->pending_interrupts & (1u << PPC_INTERRUPT_HVIRT)) &&
            (env->spr[SPR_LPCR] & LPCR_HVEE)) {
            return true;
        }
        if (env->pending_interrupts & (1u << PPC_INTERRUPT_RESET)) {
            return true;
        }