xref: /kvm-unit-tests/lib/s390x/smp.c (revision f1cdb0329ede1fb57d5d29d2c70c82c7979a5fce)
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(cpus[idx].addr, order, parm, status);
469e1e188cSClaudio Imbrenda }
479e1e188cSClaudio Imbrenda 
489e1e188cSClaudio Imbrenda int smp_sigp_retry(uint16_t idx, uint8_t order, unsigned long parm, uint32_t *status)
499e1e188cSClaudio Imbrenda {
509e1e188cSClaudio Imbrenda 	check_idx(idx);
519e1e188cSClaudio Imbrenda 	return sigp_retry(cpus[idx].addr, order, parm, status);
529e1e188cSClaudio Imbrenda }
539e1e188cSClaudio Imbrenda 
54f77c0515SJanosch Frank struct cpu *smp_cpu_from_addr(uint16_t addr)
55f77c0515SJanosch Frank {
56f77c0515SJanosch Frank 	int i, num = smp_query_num_cpus();
57f77c0515SJanosch Frank 
58f77c0515SJanosch Frank 	for (i = 0; i < num; i++) {
59f77c0515SJanosch Frank 		if (cpus[i].addr == addr)
60f77c0515SJanosch Frank 			return &cpus[i];
61f77c0515SJanosch Frank 	}
62f77c0515SJanosch Frank 	return NULL;
63f77c0515SJanosch Frank }
64f77c0515SJanosch Frank 
659e1e188cSClaudio Imbrenda struct cpu *smp_cpu_from_idx(uint16_t idx)
669e1e188cSClaudio Imbrenda {
679e1e188cSClaudio Imbrenda 	check_idx(idx);
689e1e188cSClaudio Imbrenda 	return &cpus[idx];
699e1e188cSClaudio Imbrenda }
709e1e188cSClaudio Imbrenda 
719e1e188cSClaudio Imbrenda uint16_t smp_cpu_addr(uint16_t idx)
729e1e188cSClaudio Imbrenda {
739e1e188cSClaudio Imbrenda 	check_idx(idx);
749e1e188cSClaudio Imbrenda 	return cpus[idx].addr;
759e1e188cSClaudio Imbrenda }
769e1e188cSClaudio Imbrenda 
779e1e188cSClaudio Imbrenda bool smp_cpu_stopped(uint16_t idx)
78f77c0515SJanosch Frank {
79f77c0515SJanosch Frank 	uint32_t status;
80f77c0515SJanosch Frank 
815b8d55c8SEric Farman 	if (smp_sigp_retry(idx, SIGP_SENSE, 0, &status) != SIGP_CC_STATUS_STORED)
82f77c0515SJanosch Frank 		return false;
83f77c0515SJanosch Frank 	return !!(status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED));
84f77c0515SJanosch Frank }
85f77c0515SJanosch Frank 
869e1e188cSClaudio Imbrenda bool smp_sense_running_status(uint16_t idx)
87f77c0515SJanosch Frank {
889e1e188cSClaudio Imbrenda 	if (smp_sigp(idx, SIGP_SENSE_RUNNING, 0, NULL) != SIGP_CC_STATUS_STORED)
89f77c0515SJanosch Frank 		return true;
90f77c0515SJanosch Frank 	/* Status stored condition code is equivalent to cpu not running. */
91f77c0515SJanosch Frank 	return false;
92f77c0515SJanosch Frank }
93f77c0515SJanosch Frank 
949e1e188cSClaudio Imbrenda static int smp_cpu_stop_nolock(uint16_t idx, bool store)
95f77c0515SJanosch Frank {
96f77c0515SJanosch Frank 	uint8_t order = store ? SIGP_STOP_AND_STORE_STATUS : SIGP_STOP;
97f77c0515SJanosch Frank 
989e1e188cSClaudio Imbrenda 	/* refuse to work on the boot CPU */
999e1e188cSClaudio Imbrenda 	if (idx == 0)
100f77c0515SJanosch Frank 		return -1;
101f77c0515SJanosch Frank 
1029e1e188cSClaudio Imbrenda 	if (smp_sigp_retry(idx, order, 0, NULL))
103f77c0515SJanosch Frank 		return -1;
104f77c0515SJanosch Frank 
1059e1e188cSClaudio Imbrenda 	while (!smp_cpu_stopped(idx))
106f77c0515SJanosch Frank 		mb();
1079e1e188cSClaudio Imbrenda 	/* idx has been already checked by the smp_* functions called above */
1089e1e188cSClaudio Imbrenda 	cpus[idx].active = false;
109f77c0515SJanosch Frank 	return 0;
110f77c0515SJanosch Frank }
111f77c0515SJanosch Frank 
1129e1e188cSClaudio Imbrenda int smp_cpu_stop(uint16_t idx)
113f77c0515SJanosch Frank {
114f77c0515SJanosch Frank 	int rc;
115f77c0515SJanosch Frank 
116f77c0515SJanosch Frank 	spin_lock(&lock);
1179e1e188cSClaudio Imbrenda 	rc = smp_cpu_stop_nolock(idx, false);
118f77c0515SJanosch Frank 	spin_unlock(&lock);
119f77c0515SJanosch Frank 	return rc;
120f77c0515SJanosch Frank }
121f77c0515SJanosch Frank 
1221dac4f3cSEric Farman /*
1231dac4f3cSEric Farman  * Functionally equivalent to smp_cpu_stop(), but without the
1241dac4f3cSEric Farman  * elements that wait/serialize matters itself.
1251dac4f3cSEric Farman  * Used to see if KVM itself is serialized correctly.
1261dac4f3cSEric Farman  */
1271dac4f3cSEric Farman int smp_cpu_stop_nowait(uint16_t idx)
1281dac4f3cSEric Farman {
1291dac4f3cSEric Farman 	check_idx(idx);
1301dac4f3cSEric Farman 
1311dac4f3cSEric Farman 	/* refuse to work on the boot CPU */
1321dac4f3cSEric Farman 	if (idx == 0)
1331dac4f3cSEric Farman 		return -1;
1341dac4f3cSEric Farman 
1351dac4f3cSEric Farman 	spin_lock(&lock);
1361dac4f3cSEric Farman 
1371dac4f3cSEric Farman 	/* Don't suppress a CC2 with sigp_retry() */
1381dac4f3cSEric Farman 	if (sigp(cpus[idx].addr, SIGP_STOP, 0, NULL)) {
1391dac4f3cSEric Farman 		spin_unlock(&lock);
1401dac4f3cSEric Farman 		return -1;
1411dac4f3cSEric Farman 	}
1421dac4f3cSEric Farman 
1431dac4f3cSEric Farman 	cpus[idx].active = false;
1441dac4f3cSEric Farman 	spin_unlock(&lock);
1451dac4f3cSEric Farman 
1461dac4f3cSEric Farman 	return 0;
1471dac4f3cSEric Farman }
1481dac4f3cSEric Farman 
1499e1e188cSClaudio Imbrenda int smp_cpu_stop_store_status(uint16_t idx)
150f77c0515SJanosch Frank {
151f77c0515SJanosch Frank 	int rc;
152f77c0515SJanosch Frank 
153f77c0515SJanosch Frank 	spin_lock(&lock);
1549e1e188cSClaudio Imbrenda 	rc = smp_cpu_stop_nolock(idx, true);
155f77c0515SJanosch Frank 	spin_unlock(&lock);
156f77c0515SJanosch Frank 	return rc;
157f77c0515SJanosch Frank }
158f77c0515SJanosch Frank 
1599e1e188cSClaudio Imbrenda static int smp_cpu_restart_nolock(uint16_t idx, struct psw *psw)
1602ca255a0SJanosch Frank {
1612ca255a0SJanosch Frank 	int rc;
1622ca255a0SJanosch Frank 
1639e1e188cSClaudio Imbrenda 	check_idx(idx);
1642ca255a0SJanosch Frank 	if (psw) {
1659e1e188cSClaudio Imbrenda 		cpus[idx].lowcore->restart_new_psw.mask = psw->mask;
1669e1e188cSClaudio Imbrenda 		cpus[idx].lowcore->restart_new_psw.addr = psw->addr;
1672ca255a0SJanosch Frank 	}
1682ca255a0SJanosch Frank 	/*
1692ca255a0SJanosch Frank 	 * Stop the cpu, so we don't have a race between a running cpu
1702ca255a0SJanosch Frank 	 * and the restart in the test that checks if the cpu is
1712ca255a0SJanosch Frank 	 * running after the restart.
1722ca255a0SJanosch Frank 	 */
1739e1e188cSClaudio Imbrenda 	smp_cpu_stop_nolock(idx, false);
1749e1e188cSClaudio Imbrenda 	rc = smp_sigp(idx, SIGP_RESTART, 0, NULL);
1752ca255a0SJanosch Frank 	if (rc)
1762ca255a0SJanosch Frank 		return rc;
1772ca255a0SJanosch Frank 	/*
1782ca255a0SJanosch Frank 	 * The order has been accepted, but the actual restart may not
1792ca255a0SJanosch Frank 	 * have been performed yet, so wait until the cpu is running.
1802ca255a0SJanosch Frank 	 */
1819e1e188cSClaudio Imbrenda 	while (smp_cpu_stopped(idx))
1822ca255a0SJanosch Frank 		mb();
1839e1e188cSClaudio Imbrenda 	cpus[idx].active = true;
1842ca255a0SJanosch Frank 	return 0;
1852ca255a0SJanosch Frank }
1862ca255a0SJanosch Frank 
1879e1e188cSClaudio Imbrenda int smp_cpu_restart(uint16_t idx)
188f77c0515SJanosch Frank {
1892ca255a0SJanosch Frank 	int rc;
190f77c0515SJanosch Frank 
191f77c0515SJanosch Frank 	spin_lock(&lock);
1929e1e188cSClaudio Imbrenda 	rc = smp_cpu_restart_nolock(idx, NULL);
193f77c0515SJanosch Frank 	spin_unlock(&lock);
194f77c0515SJanosch Frank 	return rc;
195f77c0515SJanosch Frank }
196f77c0515SJanosch Frank 
197*f1cdb032SEric Farman /*
198*f1cdb032SEric Farman  * Functionally equivalent to smp_cpu_restart(), but without the
199*f1cdb032SEric Farman  * elements that wait/serialize matters here in the test.
200*f1cdb032SEric Farman  * Used to see if KVM itself is serialized correctly.
201*f1cdb032SEric Farman  */
202*f1cdb032SEric Farman int smp_cpu_restart_nowait(uint16_t idx)
203*f1cdb032SEric Farman {
204*f1cdb032SEric Farman 	check_idx(idx);
205*f1cdb032SEric Farman 
206*f1cdb032SEric Farman 	spin_lock(&lock);
207*f1cdb032SEric Farman 
208*f1cdb032SEric Farman 	/* Don't suppress a CC2 with sigp_retry() */
209*f1cdb032SEric Farman 	if (sigp(cpus[idx].addr, SIGP_RESTART, 0, NULL)) {
210*f1cdb032SEric Farman 		spin_unlock(&lock);
211*f1cdb032SEric Farman 		return -1;
212*f1cdb032SEric Farman 	}
213*f1cdb032SEric Farman 
214*f1cdb032SEric Farman 	cpus[idx].active = true;
215*f1cdb032SEric Farman 
216*f1cdb032SEric Farman 	spin_unlock(&lock);
217*f1cdb032SEric Farman 
218*f1cdb032SEric Farman 	return 0;
219*f1cdb032SEric Farman }
220*f1cdb032SEric Farman 
2219e1e188cSClaudio Imbrenda int smp_cpu_start(uint16_t idx, struct psw psw)
222f77c0515SJanosch Frank {
2232ca255a0SJanosch Frank 	int rc;
224f77c0515SJanosch Frank 
225f77c0515SJanosch Frank 	spin_lock(&lock);
2269e1e188cSClaudio Imbrenda 	rc = smp_cpu_restart_nolock(idx, &psw);
227f77c0515SJanosch Frank 	spin_unlock(&lock);
228f77c0515SJanosch Frank 	return rc;
229f77c0515SJanosch Frank }
230f77c0515SJanosch Frank 
2319e1e188cSClaudio Imbrenda int smp_cpu_destroy(uint16_t idx)
232f77c0515SJanosch Frank {
233f77c0515SJanosch Frank 	int rc;
234f77c0515SJanosch Frank 
235f77c0515SJanosch Frank 	spin_lock(&lock);
2369e1e188cSClaudio Imbrenda 	rc = smp_cpu_stop_nolock(idx, false);
237f77c0515SJanosch Frank 	if (!rc) {
2389e1e188cSClaudio Imbrenda 		free_pages(cpus[idx].lowcore);
2399e1e188cSClaudio Imbrenda 		free_pages(cpus[idx].stack);
2409e1e188cSClaudio Imbrenda 		cpus[idx].lowcore = (void *)-1UL;
2419e1e188cSClaudio Imbrenda 		cpus[idx].stack = (void *)-1UL;
242f77c0515SJanosch Frank 	}
243f77c0515SJanosch Frank 	spin_unlock(&lock);
244f77c0515SJanosch Frank 	return rc;
245f77c0515SJanosch Frank }
246f77c0515SJanosch Frank 
2479e1e188cSClaudio Imbrenda static int smp_cpu_setup_nolock(uint16_t idx, struct psw psw)
248f77c0515SJanosch Frank {
249f77c0515SJanosch Frank 	struct lowcore *lc;
250f77c0515SJanosch Frank 
2519e1e188cSClaudio Imbrenda 	if (cpus[idx].active)
2529e1e188cSClaudio Imbrenda 		return -1;
253f77c0515SJanosch Frank 
2549e1e188cSClaudio Imbrenda 	smp_sigp_retry(idx, SIGP_INITIAL_CPU_RESET, 0, NULL);
255f77c0515SJanosch Frank 
256550b4683SClaudio Imbrenda 	lc = alloc_pages_flags(1, AREA_DMA31);
2579e1e188cSClaudio Imbrenda 	cpus[idx].lowcore = lc;
2589e1e188cSClaudio Imbrenda 	smp_sigp_retry(idx, SIGP_SET_PREFIX, (unsigned long )lc, NULL);
259f77c0515SJanosch Frank 
260f77c0515SJanosch Frank 	/* Copy all exception psws. */
2615a6a5506SClaudio Imbrenda 	memcpy(lc, cpus[0].lowcore, 512);
262f77c0515SJanosch Frank 
263f77c0515SJanosch Frank 	/* Setup stack */
2649e1e188cSClaudio Imbrenda 	cpus[idx].stack = (uint64_t *)alloc_pages(2);
265f77c0515SJanosch Frank 
266f77c0515SJanosch Frank 	/* Start without DAT and any other mask bits. */
2679e1e188cSClaudio Imbrenda 	lc->sw_int_psw.mask = psw.mask;
2689e1e188cSClaudio Imbrenda 	lc->sw_int_psw.addr = psw.addr;
2699e1e188cSClaudio Imbrenda 	lc->sw_int_grs[14] = psw.addr;
2709e1e188cSClaudio Imbrenda 	lc->sw_int_grs[15] = (uint64_t)cpus[idx].stack + (PAGE_SIZE * 4);
27144026818SJanosch Frank 	lc->restart_new_psw.mask = PSW_MASK_64;
272f77c0515SJanosch Frank 	lc->restart_new_psw.addr = (uint64_t)smp_cpu_setup_state;
273d34d3250SJanosch Frank 	lc->sw_int_crs[0] = BIT_ULL(CTL0_AFP);
274f77c0515SJanosch Frank 
275f77c0515SJanosch Frank 	/* Start processing */
2769e1e188cSClaudio Imbrenda 	smp_cpu_restart_nolock(idx, NULL);
27724a8db62SJanosch Frank 	/* Wait until the cpu has finished setup and started the provided psw */
27824a8db62SJanosch Frank 	while (lc->restart_new_psw.addr != psw.addr)
27924a8db62SJanosch Frank 		mb();
2809e1e188cSClaudio Imbrenda 
2819e1e188cSClaudio Imbrenda 	return 0;
2829e1e188cSClaudio Imbrenda }
2839e1e188cSClaudio Imbrenda 
2849e1e188cSClaudio Imbrenda int smp_cpu_setup(uint16_t idx, struct psw psw)
2859e1e188cSClaudio Imbrenda {
2869e1e188cSClaudio Imbrenda 	int rc = -1;
2879e1e188cSClaudio Imbrenda 
2889e1e188cSClaudio Imbrenda 	spin_lock(&lock);
2899e1e188cSClaudio Imbrenda 	if (cpus) {
2909e1e188cSClaudio Imbrenda 		check_idx(idx);
2919e1e188cSClaudio Imbrenda 		rc = smp_cpu_setup_nolock(idx, psw);
2929e1e188cSClaudio Imbrenda 	}
293f77c0515SJanosch Frank 	spin_unlock(&lock);
294f77c0515SJanosch Frank 	return rc;
295f77c0515SJanosch Frank }
296f77c0515SJanosch Frank 
297f77c0515SJanosch Frank /*
298f77c0515SJanosch Frank  * Disregarding state, stop all cpus that once were online except for
299f77c0515SJanosch Frank  * calling cpu.
300f77c0515SJanosch Frank  */
301f77c0515SJanosch Frank void smp_teardown(void)
302f77c0515SJanosch Frank {
303f77c0515SJanosch Frank 	int i = 0;
304f77c0515SJanosch Frank 	uint16_t this_cpu = stap();
30552076a63SJanosch Frank 	int num = smp_query_num_cpus();
306f77c0515SJanosch Frank 
307f77c0515SJanosch Frank 	spin_lock(&lock);
30852076a63SJanosch Frank 	for (; i < num; i++) {
309f77c0515SJanosch Frank 		if (cpus[i].active &&
310f77c0515SJanosch Frank 		    cpus[i].addr != this_cpu) {
311f77c0515SJanosch Frank 			sigp_retry(cpus[i].addr, SIGP_STOP, 0, NULL);
312f77c0515SJanosch Frank 		}
313f77c0515SJanosch Frank 	}
314f77c0515SJanosch Frank 	spin_unlock(&lock);
315f77c0515SJanosch Frank }
316f77c0515SJanosch Frank 
317f77c0515SJanosch Frank /*Expected to be called from boot cpu */
318f77c0515SJanosch Frank extern uint64_t *stackptr;
319f77c0515SJanosch Frank void smp_setup(void)
320f77c0515SJanosch Frank {
321f77c0515SJanosch Frank 	int i = 0;
32252076a63SJanosch Frank 	int num = smp_query_num_cpus();
323f77c0515SJanosch Frank 	unsigned short cpu0_addr = stap();
32452076a63SJanosch Frank 	struct CPUEntry *entry = sclp_get_cpu_entries();
325f77c0515SJanosch Frank 
326f77c0515SJanosch Frank 	spin_lock(&lock);
32752076a63SJanosch Frank 	if (num > 1)
32852076a63SJanosch Frank 		printf("SMP: Initializing, found %d cpus\n", num);
329f77c0515SJanosch Frank 
3305a6a5506SClaudio Imbrenda 	cpus = calloc(num, sizeof(*cpus));
33152076a63SJanosch Frank 	for (i = 0; i < num; i++) {
33252076a63SJanosch Frank 		cpus[i].addr = entry[i].address;
333f77c0515SJanosch Frank 		cpus[i].active = false;
3345a6a5506SClaudio Imbrenda 		/*
3355a6a5506SClaudio Imbrenda 		 * Fill in the boot CPU. If the boot CPU is not at index 0,
3365a6a5506SClaudio Imbrenda 		 * swap it with the one at index 0. This guarantees that the
3375a6a5506SClaudio Imbrenda 		 * boot CPU will always have index 0. If the boot CPU was
3385a6a5506SClaudio Imbrenda 		 * already at index 0, a few extra useless assignments are
3395a6a5506SClaudio Imbrenda 		 * performed, but everything will work ok.
3405a6a5506SClaudio Imbrenda 		 * Notice that there is no guarantee that the list of CPUs
3415a6a5506SClaudio Imbrenda 		 * returned by the Read SCP Info command is in any
3425a6a5506SClaudio Imbrenda 		 * particular order, or that its order will stay consistent
3435a6a5506SClaudio Imbrenda 		 * across multiple invocations.
3445a6a5506SClaudio Imbrenda 		 */
34552076a63SJanosch Frank 		if (entry[i].address == cpu0_addr) {
3465a6a5506SClaudio Imbrenda 			cpus[i].addr = cpus[0].addr;
3475a6a5506SClaudio Imbrenda 			cpus[0].addr = cpu0_addr;
3485a6a5506SClaudio Imbrenda 			cpus[0].stack = stackptr;
3495a6a5506SClaudio Imbrenda 			cpus[0].lowcore = (void *)0;
3505a6a5506SClaudio Imbrenda 			cpus[0].active = true;
351f77c0515SJanosch Frank 		}
352f77c0515SJanosch Frank 	}
353f77c0515SJanosch Frank 	spin_unlock(&lock);
354f77c0515SJanosch Frank }
355