Commit e2186023 authored by Michael Ellerman's avatar Michael Ellerman Committed by Benjamin Herrenschmidt

powerpc/powernv: Add support for POWER8 split core on powernv

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: default avatarMichael Ellerman <mpe@ellerman.id.au>
Signed-off-by: default avatarMichael Neuling <mikey@neuling.org>
Signed-off-by: default avatarSrivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Signed-off-by: default avatarMahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 3102f784
...@@ -225,6 +225,7 @@ ...@@ -225,6 +225,7 @@
#define CTRL_TE 0x00c00000 /* thread enable */ #define CTRL_TE 0x00c00000 /* thread enable */
#define CTRL_RUNLATCH 0x1 #define CTRL_RUNLATCH 0x1
#define SPRN_DAWR 0xB4 #define SPRN_DAWR 0xB4
#define SPRN_RPR 0xBA /* Relative Priority Register */
#define SPRN_CIABR 0xBB #define SPRN_CIABR 0xBB
#define CIABR_PRIV 0x3 #define CIABR_PRIV 0x3
#define CIABR_PRIV_USER 1 #define CIABR_PRIV_USER 1
...@@ -273,8 +274,10 @@ ...@@ -273,8 +274,10 @@
#define SPRN_HSRR1 0x13B /* Hypervisor Save/Restore 1 */ #define SPRN_HSRR1 0x13B /* Hypervisor Save/Restore 1 */
#define SPRN_IC 0x350 /* Virtual Instruction Count */ #define SPRN_IC 0x350 /* Virtual Instruction Count */
#define SPRN_VTB 0x351 /* Virtual Time Base */ #define SPRN_VTB 0x351 /* Virtual Time Base */
#define SPRN_LDBAR 0x352 /* LD Base Address Register */
#define SPRN_PMICR 0x354 /* Power Management Idle Control Reg */ #define SPRN_PMICR 0x354 /* Power Management Idle Control Reg */
#define SPRN_PMSR 0x355 /* Power Management Status Reg */ #define SPRN_PMSR 0x355 /* Power Management Status Reg */
#define SPRN_PMMAR 0x356 /* Power Management Memory Activity Register */
#define SPRN_PMCR 0x374 /* Power Management Control Register */ #define SPRN_PMCR 0x374 /* Power Management Control Register */
/* HFSCR and FSCR bit numbers are the same */ /* HFSCR and FSCR bit numbers are the same */
...@@ -434,6 +437,12 @@ ...@@ -434,6 +437,12 @@
#define HID0_BTCD (1<<1) /* Branch target cache disable */ #define HID0_BTCD (1<<1) /* Branch target cache disable */
#define HID0_NOPDST (1<<1) /* No-op dst, dstt, etc. instr. */ #define HID0_NOPDST (1<<1) /* No-op dst, dstt, etc. instr. */
#define HID0_NOPTI (1<<0) /* No-op dcbt and dcbst instr. */ #define HID0_NOPTI (1<<0) /* No-op dcbt and dcbst instr. */
/* POWER8 HID0 bits */
#define HID0_POWER8_4LPARMODE __MASK(61)
#define HID0_POWER8_2LPARMODE __MASK(57)
#define HID0_POWER8_1TO2LPAR __MASK(52)
#define HID0_POWER8_1TO4LPAR __MASK(51)
#define HID0_POWER8_DYNLPARDIS __MASK(48)
#define SPRN_HID1 0x3F1 /* Hardware Implementation Register 1 */ #define SPRN_HID1 0x3F1 /* Hardware Implementation Register 1 */
#ifdef CONFIG_6xx #ifdef CONFIG_6xx
......
obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o opal-async.o obj-y += setup.o opal-takeover.o opal-wrappers.o opal.o opal-async.o
obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o obj-y += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o obj-y += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
obj-y += opal-msglog.o obj-y += opal-msglog.o subcore.o subcore-asm.o
obj-$(CONFIG_SMP) += smp.o obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o obj-$(CONFIG_PCI) += pci.o pci-p5ioc2.o pci-ioda.o
......
...@@ -25,4 +25,6 @@ static inline int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask) ...@@ -25,4 +25,6 @@ static inline int pnv_pci_dma_set_mask(struct pci_dev *pdev, u64 dma_mask)
extern void pnv_lpc_init(void); extern void pnv_lpc_init(void);
bool cpu_core_split_required(void);
#endif /* _POWERNV_H */ #endif /* _POWERNV_H */
...@@ -161,15 +161,17 @@ static void pnv_smp_cpu_kill_self(void) ...@@ -161,15 +161,17 @@ static void pnv_smp_cpu_kill_self(void)
ppc64_runlatch_off(); ppc64_runlatch_off();
power7_nap(1); power7_nap(1);
ppc64_runlatch_on(); ppc64_runlatch_on();
if (!generic_check_cpu_restart(cpu)) {
DBG("CPU%d Unexpected exit while offline !\n", cpu); /* Reenable IRQs briefly to clear the IPI that woke us */
/* We may be getting an IPI, so we re-enable
* interrupts to process it, it will be ignored
* since we aren't online (hopefully)
*/
local_irq_enable(); local_irq_enable();
local_irq_disable(); local_irq_disable();
} mb();
if (cpu_core_split_required())
continue;
if (!generic_check_cpu_restart(cpu))
DBG("CPU%d Unexpected exit while offline !\n", cpu);
} }
mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1); mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1);
DBG("CPU%d coming online...\n", cpu); DBG("CPU%d coming online...\n", cpu);
......
/*
* 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
This diff is collapsed.
/*
* Copyright 2013, Michael Ellerman, 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.
*/
/* These are ordered and tested with <= */
#define SYNC_STEP_INITIAL 0
#define SYNC_STEP_UNSPLIT 1 /* Set by secondary when it sees unsplit */
#define SYNC_STEP_REAL_MODE 2 /* Set by secondary when in real mode */
#define SYNC_STEP_FINISHED 3 /* Set by secondary when split/unsplit is done */
#ifndef __ASSEMBLY__
void split_core_secondary_loop(u8 *state);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment