xref: /kvm-unit-tests/lib/s390x/smp.c (revision 6531c0b81f8131e799e073254ad23363364b73bc)
16c9f99dfSJanosch Frank /* SPDX-License-Identifier: GPL-2.0-only */
2f77c0515SJanosch Frank /*
3f77c0515SJanosch Frank  * s390x smp
4f77c0515SJanosch Frank  * Based on Linux's arch/s390/kernel/smp.c and
5f77c0515SJanosch Frank  * arch/s390/include/asm/sigp.h
6f77c0515SJanosch Frank  *
7f77c0515SJanosch Frank  * Copyright (c) 2019 IBM Corp
8f77c0515SJanosch Frank  *
9f77c0515SJanosch Frank  * Authors:
10f77c0515SJanosch Frank  *  Janosch Frank <frankja@linux.ibm.com>
11f77c0515SJanosch Frank  */
12f77c0515SJanosch Frank #include <libcflat.h>
13d34d3250SJanosch Frank #include <bitops.h>
14f77c0515SJanosch Frank #include <asm/arch_def.h>
15f77c0515SJanosch Frank #include <asm/sigp.h>
16f77c0515SJanosch Frank #include <asm/page.h>
17f77c0515SJanosch Frank #include <asm/barrier.h>
18f77c0515SJanosch Frank #include <asm/spinlock.h>
19f77c0515SJanosch Frank #include <asm/asm-offsets.h>
20f77c0515SJanosch Frank 
21f77c0515SJanosch Frank #include <alloc.h>
22f77c0515SJanosch Frank #include <alloc_page.h>
23f77c0515SJanosch Frank 
24f77c0515SJanosch Frank #include "smp.h"
25f77c0515SJanosch Frank #include "sclp.h"
26f77c0515SJanosch Frank 
27f77c0515SJanosch Frank static struct cpu *cpus;
28f77c0515SJanosch Frank static struct spinlock lock;
29f77c0515SJanosch Frank 
30f77c0515SJanosch Frank extern void smp_cpu_setup_state(void);
31f77c0515SJanosch Frank 
329e1e188cSClaudio Imbrenda static void check_idx(uint16_t idx)
339e1e188cSClaudio Imbrenda {
349e1e188cSClaudio Imbrenda 	assert(idx < smp_query_num_cpus());
359e1e188cSClaudio Imbrenda }
369e1e188cSClaudio Imbrenda 
37f77c0515SJanosch Frank int smp_query_num_cpus(void)
38f77c0515SJanosch Frank {
3952076a63SJanosch Frank 	return sclp_get_cpu_num();
40f77c0515SJanosch Frank }
41f77c0515SJanosch Frank 
429e1e188cSClaudio Imbrenda int smp_sigp(uint16_t idx, uint8_t order, unsigned long parm, uint32_t *status)
439e1e188cSClaudio Imbrenda {
449e1e188cSClaudio Imbrenda 	check_idx(idx);
459e1e188cSClaudio Imbrenda 	return sigp_retry(cpus[idx].addr, order, parm, status);
469e1e188cSClaudio Imbrenda }
479e1e188cSClaudio Imbrenda 
48f77c0515SJanosch Frank struct cpu *smp_cpu_from_addr(uint16_t addr)
49f77c0515SJanosch Frank {
50f77c0515SJanosch Frank 	int i, num = smp_query_num_cpus();
51f77c0515SJanosch Frank 
52f77c0515SJanosch Frank 	for (i = 0; i < num; i++) {
53f77c0515SJanosch Frank 		if (cpus[i].addr == addr)
54f77c0515SJanosch Frank 			return &cpus[i];
55f77c0515SJanosch Frank 	}
56f77c0515SJanosch Frank 	return NULL;
57f77c0515SJanosch Frank }
58f77c0515SJanosch Frank 
599e1e188cSClaudio Imbrenda struct cpu *smp_cpu_from_idx(uint16_t idx)
609e1e188cSClaudio Imbrenda {
619e1e188cSClaudio Imbrenda 	check_idx(idx);
629e1e188cSClaudio Imbrenda 	return &cpus[idx];
639e1e188cSClaudio Imbrenda }
649e1e188cSClaudio Imbrenda 
659e1e188cSClaudio Imbrenda uint16_t smp_cpu_addr(uint16_t idx)
669e1e188cSClaudio Imbrenda {
679e1e188cSClaudio Imbrenda 	check_idx(idx);
689e1e188cSClaudio Imbrenda 	return cpus[idx].addr;
699e1e188cSClaudio Imbrenda }
709e1e188cSClaudio Imbrenda 
719e1e188cSClaudio Imbrenda bool smp_cpu_stopped(uint16_t idx)
72f77c0515SJanosch Frank {
73f77c0515SJanosch Frank 	uint32_t status;
74f77c0515SJanosch Frank 
75*6531c0b8SEric Farman 	if (smp_sigp(idx, SIGP_SENSE, 0, &status) != SIGP_CC_STATUS_STORED)
76f77c0515SJanosch Frank 		return false;
77f77c0515SJanosch Frank 	return !!(status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED));
78f77c0515SJanosch Frank }
79f77c0515SJanosch Frank 
809e1e188cSClaudio Imbrenda bool smp_sense_running_status(uint16_t idx)
81f77c0515SJanosch Frank {
829e1e188cSClaudio Imbrenda 	if (smp_sigp(idx, SIGP_SENSE_RUNNING, 0, NULL) != SIGP_CC_STATUS_STORED)
83f77c0515SJanosch Frank 		return true;
84f77c0515SJanosch Frank 	/* Status stored condition code is equivalent to cpu not running. */
85f77c0515SJanosch Frank 	return false;
86f77c0515SJanosch Frank }
87f77c0515SJanosch Frank 
889e1e188cSClaudio Imbrenda static int smp_cpu_stop_nolock(uint16_t idx, bool store)
89f77c0515SJanosch Frank {
90f77c0515SJanosch Frank 	uint8_t order = store ? SIGP_STOP_AND_STORE_STATUS : SIGP_STOP;
91f77c0515SJanosch Frank 
929e1e188cSClaudio Imbrenda 	/* refuse to work on the boot CPU */
939e1e188cSClaudio Imbrenda 	if (idx == 0)
94f77c0515SJanosch Frank 		return -1;
95f77c0515SJanosch Frank 
96*6531c0b8SEric Farman 	if (smp_sigp(idx, order, 0, NULL))
97f77c0515SJanosch Frank 		return -1;
98f77c0515SJanosch Frank 
999e1e188cSClaudio Imbrenda 	while (!smp_cpu_stopped(idx))
100f77c0515SJanosch Frank 		mb();
1019e1e188cSClaudio Imbrenda 	/* idx has been already checked by the smp_* functions called above */
1029e1e188cSClaudio Imbrenda 	cpus[idx].active = false;
103f77c0515SJanosch Frank 	return 0;
104f77c0515SJanosch Frank }
105f77c0515SJanosch Frank 
1069e1e188cSClaudio Imbrenda int smp_cpu_stop(uint16_t idx)
107f77c0515SJanosch Frank {
108f77c0515SJanosch Frank 	int rc;
109f77c0515SJanosch Frank 
110f77c0515SJanosch Frank 	spin_lock(&lock);
1119e1e188cSClaudio Imbrenda 	rc = smp_cpu_stop_nolock(idx, false);
112f77c0515SJanosch Frank 	spin_unlock(&lock);
113f77c0515SJanosch Frank 	return rc;
114f77c0515SJanosch Frank }
115f77c0515SJanosch Frank 
1161dac4f3cSEric Farman /*
1171dac4f3cSEric Farman  * Functionally equivalent to smp_cpu_stop(), but without the
1181dac4f3cSEric Farman  * elements that wait/serialize matters itself.
1191dac4f3cSEric Farman  * Used to see if KVM itself is serialized correctly.
1201dac4f3cSEric Farman  */
1211dac4f3cSEric Farman int smp_cpu_stop_nowait(uint16_t idx)
1221dac4f3cSEric Farman {
1231dac4f3cSEric Farman 	check_idx(idx);
1241dac4f3cSEric Farman 
1251dac4f3cSEric Farman 	/* refuse to work on the boot CPU */
1261dac4f3cSEric Farman 	if (idx == 0)
1271dac4f3cSEric Farman 		return -1;
1281dac4f3cSEric Farman 
1291dac4f3cSEric Farman 	spin_lock(&lock);
1301dac4f3cSEric Farman 
1311dac4f3cSEric Farman 	/* Don't suppress a CC2 with sigp_retry() */
1321dac4f3cSEric Farman 	if (sigp(cpus[idx].addr, SIGP_STOP, 0, NULL)) {
1331dac4f3cSEric Farman 		spin_unlock(&lock);
1341dac4f3cSEric Farman 		return -1;
1351dac4f3cSEric Farman 	}
1361dac4f3cSEric Farman 
1371dac4f3cSEric Farman 	cpus[idx].active = false;
1381dac4f3cSEric Farman 	spin_unlock(&lock);
1391dac4f3cSEric Farman 
1401dac4f3cSEric Farman 	return 0;
1411dac4f3cSEric Farman }
1421dac4f3cSEric Farman 
1439e1e188cSClaudio Imbrenda int smp_cpu_stop_store_status(uint16_t idx)
144f77c0515SJanosch Frank {
145f77c0515SJanosch Frank 	int rc;
146f77c0515SJanosch Frank 
147f77c0515SJanosch Frank 	spin_lock(&lock);
1489e1e188cSClaudio Imbrenda 	rc = smp_cpu_stop_nolock(idx, true);
149f77c0515SJanosch Frank 	spin_unlock(&lock);
150f77c0515SJanosch Frank 	return rc;
151f77c0515SJanosch Frank }
152f77c0515SJanosch Frank 
1539e1e188cSClaudio Imbrenda static int smp_cpu_restart_nolock(uint16_t idx, struct psw *psw)
1542ca255a0SJanosch Frank {
1552ca255a0SJanosch Frank 	int rc;
1562ca255a0SJanosch Frank 
1579e1e188cSClaudio Imbrenda 	check_idx(idx);
1582ca255a0SJanosch Frank 	if (psw) {
1599e1e188cSClaudio Imbrenda 		cpus[idx].lowcore->restart_new_psw.mask = psw->mask;
1609e1e188cSClaudio Imbrenda 		cpus[idx].lowcore->restart_new_psw.addr = psw->addr;
1612ca255a0SJanosch Frank 	}
1622ca255a0SJanosch Frank 	/*
1632ca255a0SJanosch Frank 	 * Stop the cpu, so we don't have a race between a running cpu
1642ca255a0SJanosch Frank 	 * and the restart in the test that checks if the cpu is
1652ca255a0SJanosch Frank 	 * running after the restart.
1662ca255a0SJanosch Frank 	 */
1679e1e188cSClaudio Imbrenda 	smp_cpu_stop_nolock(idx, false);
1689e1e188cSClaudio Imbrenda 	rc = smp_sigp(idx, SIGP_RESTART, 0, NULL);
1692ca255a0SJanosch Frank 	if (rc)
1702ca255a0SJanosch Frank 		return rc;
1712ca255a0SJanosch Frank 	/*
1722ca255a0SJanosch Frank 	 * The order has been accepted, but the actual restart may not
1732ca255a0SJanosch Frank 	 * have been performed yet, so wait until the cpu is running.
1742ca255a0SJanosch Frank 	 */
1759e1e188cSClaudio Imbrenda 	while (smp_cpu_stopped(idx))
1762ca255a0SJanosch Frank 		mb();
1779e1e188cSClaudio Imbrenda 	cpus[idx].active = true;
1782ca255a0SJanosch Frank 	return 0;
1792ca255a0SJanosch Frank }
1802ca255a0SJanosch Frank 
1819e1e188cSClaudio Imbrenda int smp_cpu_restart(uint16_t idx)
182f77c0515SJanosch Frank {
1832ca255a0SJanosch Frank 	int rc;
184f77c0515SJanosch Frank 
185f77c0515SJanosch Frank 	spin_lock(&lock);
1869e1e188cSClaudio Imbrenda 	rc = smp_cpu_restart_nolock(idx, NULL);
187f77c0515SJanosch Frank 	spin_unlock(&lock);
188f77c0515SJanosch Frank 	return rc;
189f77c0515SJanosch Frank }
190f77c0515SJanosch Frank 
191f1cdb032SEric Farman /*
192f1cdb032SEric Farman  * Functionally equivalent to smp_cpu_restart(), but without the
193f1cdb032SEric Farman  * elements that wait/serialize matters here in the test.
194f1cdb032SEric Farman  * Used to see if KVM itself is serialized correctly.
195f1cdb032SEric Farman  */
196f1cdb032SEric Farman int smp_cpu_restart_nowait(uint16_t idx)
197f1cdb032SEric Farman {
198f1cdb032SEric Farman 	check_idx(idx);
199f1cdb032SEric Farman 
200f1cdb032SEric Farman 	spin_lock(&lock);
201f1cdb032SEric Farman 
202f1cdb032SEric Farman 	/* Don't suppress a CC2 with sigp_retry() */
203f1cdb032SEric Farman 	if (sigp(cpus[idx].addr, SIGP_RESTART, 0, NULL)) {
204f1cdb032SEric Farman 		spin_unlock(&lock);
205f1cdb032SEric Farman 		return -1;
206f1cdb032SEric Farman 	}
207f1cdb032SEric Farman 
208f1cdb032SEric Farman 	cpus[idx].active = true;
209f1cdb032SEric Farman 
210f1cdb032SEric Farman 	spin_unlock(&lock);
211f1cdb032SEric Farman 
212f1cdb032SEric Farman 	return 0;
213f1cdb032SEric Farman }
214f1cdb032SEric Farman 
2159e1e188cSClaudio Imbrenda int smp_cpu_start(uint16_t idx, struct psw psw)
216f77c0515SJanosch Frank {
2172ca255a0SJanosch Frank 	int rc;
218f77c0515SJanosch Frank 
219f77c0515SJanosch Frank 	spin_lock(&lock);
2209e1e188cSClaudio Imbrenda 	rc = smp_cpu_restart_nolock(idx, &psw);
221f77c0515SJanosch Frank 	spin_unlock(&lock);
222f77c0515SJanosch Frank 	return rc;
223f77c0515SJanosch Frank }
224f77c0515SJanosch Frank 
2259e1e188cSClaudio Imbrenda int smp_cpu_destroy(uint16_t idx)
226f77c0515SJanosch Frank {
227f77c0515SJanosch Frank 	int rc;
228f77c0515SJanosch Frank 
229f77c0515SJanosch Frank 	spin_lock(&lock);
2309e1e188cSClaudio Imbrenda 	rc = smp_cpu_stop_nolock(idx, false);
231f77c0515SJanosch Frank 	if (!rc) {
2329e1e188cSClaudio Imbrenda 		free_pages(cpus[idx].lowcore);
2339e1e188cSClaudio Imbrenda 		free_pages(cpus[idx].stack);
2349e1e188cSClaudio Imbrenda 		cpus[idx].lowcore = (void *)-1UL;
2359e1e188cSClaudio Imbrenda 		cpus[idx].stack = (void *)-1UL;
236f77c0515SJanosch Frank 	}
237f77c0515SJanosch Frank 	spin_unlock(&lock);
238f77c0515SJanosch Frank 	return rc;
239f77c0515SJanosch Frank }
240f77c0515SJanosch Frank 
2419e1e188cSClaudio Imbrenda static int smp_cpu_setup_nolock(uint16_t idx, struct psw psw)
242f77c0515SJanosch Frank {
243f77c0515SJanosch Frank 	struct lowcore *lc;
244f77c0515SJanosch Frank 
2459e1e188cSClaudio Imbrenda 	if (cpus[idx].active)
2469e1e188cSClaudio Imbrenda 		return -1;
247f77c0515SJanosch Frank 
248*6531c0b8SEric Farman 	smp_sigp(idx, SIGP_INITIAL_CPU_RESET, 0, NULL);
249f77c0515SJanosch Frank 
250550b4683SClaudio Imbrenda 	lc = alloc_pages_flags(1, AREA_DMA31);
2519e1e188cSClaudio Imbrenda 	cpus[idx].lowcore = lc;
252*6531c0b8SEric Farman 	smp_sigp(idx, SIGP_SET_PREFIX, (unsigned long )lc, NULL);
253f77c0515SJanosch Frank 
254f77c0515SJanosch Frank 	/* Copy all exception psws. */
2555a6a5506SClaudio Imbrenda 	memcpy(lc, cpus[0].lowcore, 512);
256f77c0515SJanosch Frank 
257f77c0515SJanosch Frank 	/* Setup stack */
2589e1e188cSClaudio Imbrenda 	cpus[idx].stack = (uint64_t *)alloc_pages(2);
259f77c0515SJanosch Frank 
260f77c0515SJanosch Frank 	/* Start without DAT and any other mask bits. */
2619e1e188cSClaudio Imbrenda 	lc->sw_int_psw.mask = psw.mask;
2629e1e188cSClaudio Imbrenda 	lc->sw_int_psw.addr = psw.addr;
2639e1e188cSClaudio Imbrenda 	lc->sw_int_grs[14] = psw.addr;
2649e1e188cSClaudio Imbrenda 	lc->sw_int_grs[15] = (uint64_t)cpus[idx].stack + (PAGE_SIZE * 4);
26544026818SJanosch Frank 	lc->restart_new_psw.mask = PSW_MASK_64;
266f77c0515SJanosch Frank 	lc->restart_new_psw.addr = (uint64_t)smp_cpu_setup_state;
267d34d3250SJanosch Frank 	lc->sw_int_crs[0] = BIT_ULL(CTL0_AFP);
268f77c0515SJanosch Frank 
269f77c0515SJanosch Frank 	/* Start processing */
2709e1e188cSClaudio Imbrenda 	smp_cpu_restart_nolock(idx, NULL);
27124a8db62SJanosch Frank 	/* Wait until the cpu has finished setup and started the provided psw */
27224a8db62SJanosch Frank 	while (lc->restart_new_psw.addr != psw.addr)
27324a8db62SJanosch Frank 		mb();
2749e1e188cSClaudio Imbrenda 
2759e1e188cSClaudio Imbrenda 	return 0;
2769e1e188cSClaudio Imbrenda }
2779e1e188cSClaudio Imbrenda 
2789e1e188cSClaudio Imbrenda int smp_cpu_setup(uint16_t idx, struct psw psw)
2799e1e188cSClaudio Imbrenda {
2809e1e188cSClaudio Imbrenda 	int rc = -1;
2819e1e188cSClaudio Imbrenda 
2829e1e188cSClaudio Imbrenda 	spin_lock(&lock);
2839e1e188cSClaudio Imbrenda 	if (cpus) {
2849e1e188cSClaudio Imbrenda 		check_idx(idx);
2859e1e188cSClaudio Imbrenda 		rc = smp_cpu_setup_nolock(idx, psw);
2869e1e188cSClaudio Imbrenda 	}
287f77c0515SJanosch Frank 	spin_unlock(&lock);
288f77c0515SJanosch Frank 	return rc;
289f77c0515SJanosch Frank }
290f77c0515SJanosch Frank 
291f77c0515SJanosch Frank /*
292f77c0515SJanosch Frank  * Disregarding state, stop all cpus that once were online except for
293f77c0515SJanosch Frank  * calling cpu.
294f77c0515SJanosch Frank  */
295f77c0515SJanosch Frank void smp_teardown(void)
296f77c0515SJanosch Frank {
297f77c0515SJanosch Frank 	int i = 0;
298f77c0515SJanosch Frank 	uint16_t this_cpu = stap();
29952076a63SJanosch Frank 	int num = smp_query_num_cpus();
300f77c0515SJanosch Frank 
301f77c0515SJanosch Frank 	spin_lock(&lock);
30252076a63SJanosch Frank 	for (; i < num; i++) {
303f77c0515SJanosch Frank 		if (cpus[i].active &&
304f77c0515SJanosch Frank 		    cpus[i].addr != this_cpu) {
305f77c0515SJanosch Frank 			sigp_retry(cpus[i].addr, SIGP_STOP, 0, NULL);
306f77c0515SJanosch Frank 		}
307f77c0515SJanosch Frank 	}
308f77c0515SJanosch Frank 	spin_unlock(&lock);
309f77c0515SJanosch Frank }
310f77c0515SJanosch Frank 
311f77c0515SJanosch Frank /*Expected to be called from boot cpu */
312f77c0515SJanosch Frank extern uint64_t *stackptr;
313f77c0515SJanosch Frank void smp_setup(void)
314f77c0515SJanosch Frank {
315f77c0515SJanosch Frank 	int i = 0;
31652076a63SJanosch Frank 	int num = smp_query_num_cpus();
317f77c0515SJanosch Frank 	unsigned short cpu0_addr = stap();
31852076a63SJanosch Frank 	struct CPUEntry *entry = sclp_get_cpu_entries();
319f77c0515SJanosch Frank 
320f77c0515SJanosch Frank 	spin_lock(&lock);
32152076a63SJanosch Frank 	if (num > 1)
32252076a63SJanosch Frank 		printf("SMP: Initializing, found %d cpus\n", num);
323f77c0515SJanosch Frank 
3245a6a5506SClaudio Imbrenda 	cpus = calloc(num, sizeof(*cpus));
32552076a63SJanosch Frank 	for (i = 0; i < num; i++) {
32652076a63SJanosch Frank 		cpus[i].addr = entry[i].address;
327f77c0515SJanosch Frank 		cpus[i].active = false;
3285a6a5506SClaudio Imbrenda 		/*
3295a6a5506SClaudio Imbrenda 		 * Fill in the boot CPU. If the boot CPU is not at index 0,
3305a6a5506SClaudio Imbrenda 		 * swap it with the one at index 0. This guarantees that the
3315a6a5506SClaudio Imbrenda 		 * boot CPU will always have index 0. If the boot CPU was
3325a6a5506SClaudio Imbrenda 		 * already at index 0, a few extra useless assignments are
3335a6a5506SClaudio Imbrenda 		 * performed, but everything will work ok.
3345a6a5506SClaudio Imbrenda 		 * Notice that there is no guarantee that the list of CPUs
3355a6a5506SClaudio Imbrenda 		 * returned by the Read SCP Info command is in any
3365a6a5506SClaudio Imbrenda 		 * particular order, or that its order will stay consistent
3375a6a5506SClaudio Imbrenda 		 * across multiple invocations.
3385a6a5506SClaudio Imbrenda 		 */
33952076a63SJanosch Frank 		if (entry[i].address == cpu0_addr) {
3405a6a5506SClaudio Imbrenda 			cpus[i].addr = cpus[0].addr;
3415a6a5506SClaudio Imbrenda 			cpus[0].addr = cpu0_addr;
3425a6a5506SClaudio Imbrenda 			cpus[0].stack = stackptr;
3435a6a5506SClaudio Imbrenda 			cpus[0].lowcore = (void *)0;
3445a6a5506SClaudio Imbrenda 			cpus[0].active = true;
345f77c0515SJanosch Frank 		}
346f77c0515SJanosch Frank 	}
347f77c0515SJanosch Frank 	spin_unlock(&lock);
348f77c0515SJanosch Frank }
349