forked from Minki/linux
e2186023f2
Upcoming POWER8 chips support a concept called split core. This is where the core can be split into subcores that although not full cores, are able to appear as full cores to a guest. The splitting & unsplitting procedure is mildly complicated, and explained at length in the comments within the patch. One notable detail is that when splitting or unsplitting we need to pull offline cpus out of their offline state to do work as part of the procedure. The interface for changing the split mode is via a sysfs file, eg: $ echo 2 > /sys/devices/system/cpu/subcores_per_core Currently supported values are '1', '2' and '4'. And indicate respectively that the core should be unsplit, split in half, and split in quarters. These modes correspond to threads_per_subcore of 8, 4 and 2. We do not allow changing the split mode while KVM VMs are active. This is to prevent the value changing while userspace is configuring the VM, and also to prevent the mode being changed in such a way that existing guests are unable to be run. CPU hotplug fixes by Srivatsa. max_cpus fixes by Mahesh. cpuset fixes by benh. Fix for irq race by paulus. The rest by mikey and mpe. Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com> Signed-off-by: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
96 lines
2.0 KiB
ArmAsm
96 lines
2.0 KiB
ArmAsm
/*
|
|
* Copyright 2013, Michael (Ellerman|Neuling), IBM Corporation.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*/
|
|
|
|
#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
|