root/arch/powerpc/platforms/powernv/subcore-asm.S
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright 2013, Michael (Ellerman|Neuling), IBM Corporation.
 */

#include <asm/asm-offsets.h>
#include <asm/ppc_asm.h>
#include <asm/reg.h>

#include "subcore.h"


_GLOBAL(split_core_secondary_loop)
        /*
         * r3 = u8 *state, used throughout the routine
         * r4 = temp
         * r5 = temp
         * ..
         * r12 = MSR
         */
        mfmsr   r12

        /* Disable interrupts so SRR0/1 don't get trashed */
        li      r4,0
        ori     r4,r4,MSR_EE|MSR_SE|MSR_BE|MSR_RI
        andc    r4,r12,r4
        sync
        mtmsrd  r4

        /* Switch to real mode and leave interrupts off */
        li      r5, MSR_IR|MSR_DR
        andc    r5, r4, r5

        LOAD_REG_ADDR(r4, real_mode)

        mtspr   SPRN_SRR0,r4
        mtspr   SPRN_SRR1,r5
        rfid
        b       .       /* prevent speculative execution */

real_mode:
        /* Grab values from unsplit SPRs */
        mfspr   r6,  SPRN_LDBAR
        mfspr   r7,  SPRN_PMMAR
        mfspr   r8,  SPRN_PMCR
        mfspr   r9,  SPRN_RPR
        mfspr   r10, SPRN_SDR1

        /* Order reading the SPRs vs telling the primary we are ready to split */
        sync

        /* Tell thread 0 we are in real mode */
        li      r4, SYNC_STEP_REAL_MODE
        stb     r4, 0(r3)

        li      r5, (HID0_POWER8_4LPARMODE | HID0_POWER8_2LPARMODE)@highest
        sldi    r5, r5, 48

        /* Loop until we see the split happen in HID0 */
1:      mfspr   r4, SPRN_HID0
        and.    r4, r4, r5
        beq     1b

        /*
         * We only need to initialise the below regs once for each subcore,
         * but it's simpler and harmless to do it on each thread.
         */

        /* Make sure various SPRS have sane values */
        li      r4, 0
        mtspr   SPRN_LPID, r4
        mtspr   SPRN_PCR, r4
        mtspr   SPRN_HDEC, r4

        /* Restore SPR values now we are split */
        mtspr   SPRN_LDBAR, r6
        mtspr   SPRN_PMMAR, r7
        mtspr   SPRN_PMCR, r8
        mtspr   SPRN_RPR, r9
        mtspr   SPRN_SDR1, r10

        LOAD_REG_ADDR(r5, virtual_mode)

        /* Get out of real mode */
        mtspr   SPRN_SRR0,r5
        mtspr   SPRN_SRR1,r12
        rfid
        b       .       /* prevent speculative execution */

virtual_mode:
        blr