Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -225,6 +225,7 @@
#define   CTRL_TE	0x00c00000	/* thread enable */
#define   CTRL_RUNLATCH	0x1
#define SPRN_DAWR	0xB4
#define SPRN_RPR	0xBA	/* Relative Priority Register */
#define SPRN_CIABR	0xBB
#define   CIABR_PRIV		0x3
#define   CIABR_PRIV_USER	1
@@ -273,8 +274,10 @@
#define SPRN_HSRR1	0x13B	/* Hypervisor Save/Restore 1 */
#define SPRN_IC		0x350	/* Virtual Instruction Count */
#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_PMSR	0x355   /* Power Management Status Reg */
#define SPRN_PMMAR	0x356	/* Power Management Memory Activity Register */
#define SPRN_PMCR	0x374	/* Power Management Control Register */

/* HFSCR and FSCR bit numbers are the same */
@@ -434,6 +437,12 @@
#define HID0_BTCD	(1<<1)		/* Branch target cache disable */
#define HID0_NOPDST	(1<<1)		/* No-op dst, dstt, etc. 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 */
#ifdef CONFIG_6xx
+1 −1
Original line number Diff line number Diff line
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			+= 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_PCI)	+= pci.o pci-p5ioc2.o pci-ioda.o
+2 −0
Original line number Diff line number Diff line
@@ -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);

bool cpu_core_split_required(void);

#endif /* _POWERNV_H */
+10 −8
Original line number Diff line number Diff line
@@ -161,15 +161,17 @@ static void pnv_smp_cpu_kill_self(void)
		ppc64_runlatch_off();
		power7_nap(1);
		ppc64_runlatch_on();
		if (!generic_check_cpu_restart(cpu)) {
			DBG("CPU%d Unexpected exit while offline !\n", cpu);
			/* We may be getting an IPI, so we re-enable
			 * interrupts to process it, it will be ignored
			 * since we aren't online (hopefully)
			 */

		/* Reenable IRQs briefly to clear the IPI that woke us */
		local_irq_enable();
		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);
	DBG("CPU%d coming online...\n", cpu);
+95 −0
Original line number Diff line number Diff line
/*
 * 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
Loading