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
check_idx(uint16_t idx)329e1e188cSClaudio Imbrenda static void check_idx(uint16_t idx)
339e1e188cSClaudio Imbrenda {
349e1e188cSClaudio Imbrenda assert(idx < smp_query_num_cpus());
359e1e188cSClaudio Imbrenda }
369e1e188cSClaudio Imbrenda
smp_query_num_cpus(void)37f77c0515SJanosch Frank int smp_query_num_cpus(void)
38f77c0515SJanosch Frank {
3952076a63SJanosch Frank return sclp_get_cpu_num();
40f77c0515SJanosch Frank }
41f77c0515SJanosch Frank
smp_get_lowcore(uint16_t idx)424e5dd758SClaudio Imbrenda struct lowcore *smp_get_lowcore(uint16_t idx)
434e5dd758SClaudio Imbrenda {
444e5dd758SClaudio Imbrenda if (THIS_CPU->idx == idx)
454e5dd758SClaudio Imbrenda return &lowcore;
464e5dd758SClaudio Imbrenda
474e5dd758SClaudio Imbrenda check_idx(idx);
484e5dd758SClaudio Imbrenda return cpus[idx].lowcore;
494e5dd758SClaudio Imbrenda }
504e5dd758SClaudio Imbrenda
smp_sigp(uint16_t idx,uint8_t order,unsigned long parm,uint32_t * status)519e1e188cSClaudio Imbrenda int smp_sigp(uint16_t idx, uint8_t order, unsigned long parm, uint32_t *status)
529e1e188cSClaudio Imbrenda {
539e1e188cSClaudio Imbrenda check_idx(idx);
549e1e188cSClaudio Imbrenda return sigp_retry(cpus[idx].addr, order, parm, status);
559e1e188cSClaudio Imbrenda }
569e1e188cSClaudio Imbrenda
smp_cpu_from_addr(uint16_t addr)57f77c0515SJanosch Frank struct cpu *smp_cpu_from_addr(uint16_t addr)
58f77c0515SJanosch Frank {
59f77c0515SJanosch Frank int i, num = smp_query_num_cpus();
60f77c0515SJanosch Frank
61f77c0515SJanosch Frank for (i = 0; i < num; i++) {
62f77c0515SJanosch Frank if (cpus[i].addr == addr)
63f77c0515SJanosch Frank return &cpus[i];
64f77c0515SJanosch Frank }
65f77c0515SJanosch Frank return NULL;
66f77c0515SJanosch Frank }
67f77c0515SJanosch Frank
smp_cpu_from_idx(uint16_t idx)689e1e188cSClaudio Imbrenda struct cpu *smp_cpu_from_idx(uint16_t idx)
699e1e188cSClaudio Imbrenda {
709e1e188cSClaudio Imbrenda check_idx(idx);
719e1e188cSClaudio Imbrenda return &cpus[idx];
729e1e188cSClaudio Imbrenda }
739e1e188cSClaudio Imbrenda
smp_cpu_addr(uint16_t idx)749e1e188cSClaudio Imbrenda uint16_t smp_cpu_addr(uint16_t idx)
759e1e188cSClaudio Imbrenda {
769e1e188cSClaudio Imbrenda check_idx(idx);
779e1e188cSClaudio Imbrenda return cpus[idx].addr;
789e1e188cSClaudio Imbrenda }
799e1e188cSClaudio Imbrenda
smp_cpu_stopped(uint16_t idx)809e1e188cSClaudio Imbrenda bool smp_cpu_stopped(uint16_t idx)
81f77c0515SJanosch Frank {
82f77c0515SJanosch Frank uint32_t status;
83f77c0515SJanosch Frank
846531c0b8SEric Farman if (smp_sigp(idx, SIGP_SENSE, 0, &status) != SIGP_CC_STATUS_STORED)
85f77c0515SJanosch Frank return false;
86f77c0515SJanosch Frank return !!(status & (SIGP_STATUS_CHECK_STOP|SIGP_STATUS_STOPPED));
87f77c0515SJanosch Frank }
88f77c0515SJanosch Frank
smp_sense_running_status(uint16_t idx)899e1e188cSClaudio Imbrenda bool smp_sense_running_status(uint16_t idx)
90f77c0515SJanosch Frank {
919e1e188cSClaudio Imbrenda if (smp_sigp(idx, SIGP_SENSE_RUNNING, 0, NULL) != SIGP_CC_STATUS_STORED)
92f77c0515SJanosch Frank return true;
93f77c0515SJanosch Frank /* Status stored condition code is equivalent to cpu not running. */
94f77c0515SJanosch Frank return false;
95f77c0515SJanosch Frank }
96f77c0515SJanosch Frank
smp_cpu_stop_nolock(uint16_t idx,bool store)979e1e188cSClaudio Imbrenda static int smp_cpu_stop_nolock(uint16_t idx, bool store)
98f77c0515SJanosch Frank {
99f77c0515SJanosch Frank uint8_t order = store ? SIGP_STOP_AND_STORE_STATUS : SIGP_STOP;
100f77c0515SJanosch Frank
1019e1e188cSClaudio Imbrenda /* refuse to work on the boot CPU */
1029e1e188cSClaudio Imbrenda if (idx == 0)
103f77c0515SJanosch Frank return -1;
104f77c0515SJanosch Frank
1056531c0b8SEric Farman if (smp_sigp(idx, order, 0, NULL))
106f77c0515SJanosch Frank return -1;
107f77c0515SJanosch Frank
1089e1e188cSClaudio Imbrenda while (!smp_cpu_stopped(idx))
109f77c0515SJanosch Frank mb();
1109e1e188cSClaudio Imbrenda /* idx has been already checked by the smp_* functions called above */
1119e1e188cSClaudio Imbrenda cpus[idx].active = false;
112f77c0515SJanosch Frank return 0;
113f77c0515SJanosch Frank }
114f77c0515SJanosch Frank
smp_cpu_stop(uint16_t idx)1159e1e188cSClaudio Imbrenda int smp_cpu_stop(uint16_t idx)
116f77c0515SJanosch Frank {
117f77c0515SJanosch Frank int rc;
118f77c0515SJanosch Frank
119f77c0515SJanosch Frank spin_lock(&lock);
1209e1e188cSClaudio Imbrenda rc = smp_cpu_stop_nolock(idx, false);
121f77c0515SJanosch Frank spin_unlock(&lock);
122f77c0515SJanosch Frank return rc;
123f77c0515SJanosch Frank }
124f77c0515SJanosch Frank
1251dac4f3cSEric Farman /*
1261dac4f3cSEric Farman * Functionally equivalent to smp_cpu_stop(), but without the
1271dac4f3cSEric Farman * elements that wait/serialize matters itself.
1281dac4f3cSEric Farman * Used to see if KVM itself is serialized correctly.
1291dac4f3cSEric Farman */
smp_cpu_stop_nowait(uint16_t idx)1301dac4f3cSEric Farman int smp_cpu_stop_nowait(uint16_t idx)
1311dac4f3cSEric Farman {
1321dac4f3cSEric Farman check_idx(idx);
1331dac4f3cSEric Farman
1341dac4f3cSEric Farman /* refuse to work on the boot CPU */
1351dac4f3cSEric Farman if (idx == 0)
1361dac4f3cSEric Farman return -1;
1371dac4f3cSEric Farman
1381dac4f3cSEric Farman spin_lock(&lock);
1391dac4f3cSEric Farman
1401dac4f3cSEric Farman /* Don't suppress a CC2 with sigp_retry() */
1411dac4f3cSEric Farman if (sigp(cpus[idx].addr, SIGP_STOP, 0, NULL)) {
1421dac4f3cSEric Farman spin_unlock(&lock);
1431dac4f3cSEric Farman return -1;
1441dac4f3cSEric Farman }
1451dac4f3cSEric Farman
1461dac4f3cSEric Farman cpus[idx].active = false;
1471dac4f3cSEric Farman spin_unlock(&lock);
1481dac4f3cSEric Farman
1491dac4f3cSEric Farman return 0;
1501dac4f3cSEric Farman }
1511dac4f3cSEric Farman
smp_cpu_stop_store_status(uint16_t idx)1529e1e188cSClaudio Imbrenda int smp_cpu_stop_store_status(uint16_t idx)
153f77c0515SJanosch Frank {
154f77c0515SJanosch Frank int rc;
155f77c0515SJanosch Frank
156f77c0515SJanosch Frank spin_lock(&lock);
1579e1e188cSClaudio Imbrenda rc = smp_cpu_stop_nolock(idx, true);
158f77c0515SJanosch Frank spin_unlock(&lock);
159f77c0515SJanosch Frank return rc;
160f77c0515SJanosch Frank }
161f77c0515SJanosch Frank
smp_cpu_restart_nolock(uint16_t idx,struct psw * psw)1629e1e188cSClaudio Imbrenda static int smp_cpu_restart_nolock(uint16_t idx, struct psw *psw)
1632ca255a0SJanosch Frank {
1642ca255a0SJanosch Frank int rc;
1652ca255a0SJanosch Frank
1669e1e188cSClaudio Imbrenda check_idx(idx);
1672ca255a0SJanosch Frank if (psw) {
1689e1e188cSClaudio Imbrenda cpus[idx].lowcore->restart_new_psw.mask = psw->mask;
1699e1e188cSClaudio Imbrenda cpus[idx].lowcore->restart_new_psw.addr = psw->addr;
1702ca255a0SJanosch Frank }
1712ca255a0SJanosch Frank /*
1722ca255a0SJanosch Frank * Stop the cpu, so we don't have a race between a running cpu
1732ca255a0SJanosch Frank * and the restart in the test that checks if the cpu is
1742ca255a0SJanosch Frank * running after the restart.
1752ca255a0SJanosch Frank */
1769e1e188cSClaudio Imbrenda smp_cpu_stop_nolock(idx, false);
1779e1e188cSClaudio Imbrenda rc = smp_sigp(idx, SIGP_RESTART, 0, NULL);
1782ca255a0SJanosch Frank if (rc)
1792ca255a0SJanosch Frank return rc;
1802ca255a0SJanosch Frank /*
1812ca255a0SJanosch Frank * The order has been accepted, but the actual restart may not
1822ca255a0SJanosch Frank * have been performed yet, so wait until the cpu is running.
1832ca255a0SJanosch Frank */
1849e1e188cSClaudio Imbrenda while (smp_cpu_stopped(idx))
1852ca255a0SJanosch Frank mb();
1869e1e188cSClaudio Imbrenda cpus[idx].active = true;
1872ca255a0SJanosch Frank return 0;
1882ca255a0SJanosch Frank }
1892ca255a0SJanosch Frank
smp_cpu_restart(uint16_t idx)1909e1e188cSClaudio Imbrenda int smp_cpu_restart(uint16_t idx)
191f77c0515SJanosch Frank {
1922ca255a0SJanosch Frank int rc;
193f77c0515SJanosch Frank
194f77c0515SJanosch Frank spin_lock(&lock);
1959e1e188cSClaudio Imbrenda rc = smp_cpu_restart_nolock(idx, NULL);
196f77c0515SJanosch Frank spin_unlock(&lock);
197f77c0515SJanosch Frank return rc;
198f77c0515SJanosch Frank }
199f77c0515SJanosch Frank
200f1cdb032SEric Farman /*
201f1cdb032SEric Farman * Functionally equivalent to smp_cpu_restart(), but without the
202f1cdb032SEric Farman * elements that wait/serialize matters here in the test.
203f1cdb032SEric Farman * Used to see if KVM itself is serialized correctly.
204f1cdb032SEric Farman */
smp_cpu_restart_nowait(uint16_t idx)205f1cdb032SEric Farman int smp_cpu_restart_nowait(uint16_t idx)
206f1cdb032SEric Farman {
207f1cdb032SEric Farman check_idx(idx);
208f1cdb032SEric Farman
209f1cdb032SEric Farman spin_lock(&lock);
210f1cdb032SEric Farman
211f1cdb032SEric Farman /* Don't suppress a CC2 with sigp_retry() */
212f1cdb032SEric Farman if (sigp(cpus[idx].addr, SIGP_RESTART, 0, NULL)) {
213f1cdb032SEric Farman spin_unlock(&lock);
214f1cdb032SEric Farman return -1;
215f1cdb032SEric Farman }
216f1cdb032SEric Farman
217f1cdb032SEric Farman cpus[idx].active = true;
218f1cdb032SEric Farman
219f1cdb032SEric Farman spin_unlock(&lock);
220f1cdb032SEric Farman
221f1cdb032SEric Farman return 0;
222f1cdb032SEric Farman }
223f1cdb032SEric Farman
smp_cpu_start(uint16_t idx,struct psw psw)2249e1e188cSClaudio Imbrenda int smp_cpu_start(uint16_t idx, struct psw psw)
225f77c0515SJanosch Frank {
2262ca255a0SJanosch Frank int rc;
227f77c0515SJanosch Frank
228f77c0515SJanosch Frank spin_lock(&lock);
2299e1e188cSClaudio Imbrenda rc = smp_cpu_restart_nolock(idx, &psw);
230f77c0515SJanosch Frank spin_unlock(&lock);
231f77c0515SJanosch Frank return rc;
232f77c0515SJanosch Frank }
233f77c0515SJanosch Frank
smp_cpu_destroy(uint16_t idx)2349e1e188cSClaudio Imbrenda int smp_cpu_destroy(uint16_t idx)
235f77c0515SJanosch Frank {
236f77c0515SJanosch Frank int rc;
237f77c0515SJanosch Frank
238f77c0515SJanosch Frank spin_lock(&lock);
2399e1e188cSClaudio Imbrenda rc = smp_cpu_stop_nolock(idx, false);
240f77c0515SJanosch Frank if (!rc) {
2419e1e188cSClaudio Imbrenda free_pages(cpus[idx].lowcore);
2429e1e188cSClaudio Imbrenda free_pages(cpus[idx].stack);
2439e1e188cSClaudio Imbrenda cpus[idx].lowcore = (void *)-1UL;
2449e1e188cSClaudio Imbrenda cpus[idx].stack = (void *)-1UL;
245f77c0515SJanosch Frank }
246f77c0515SJanosch Frank spin_unlock(&lock);
247f77c0515SJanosch Frank return rc;
248f77c0515SJanosch Frank }
249f77c0515SJanosch Frank
smp_cpu_setup_nolock(uint16_t idx,struct psw psw)2509e1e188cSClaudio Imbrenda static int smp_cpu_setup_nolock(uint16_t idx, struct psw psw)
251f77c0515SJanosch Frank {
252f77c0515SJanosch Frank struct lowcore *lc;
253f77c0515SJanosch Frank
2549e1e188cSClaudio Imbrenda if (cpus[idx].active)
2559e1e188cSClaudio Imbrenda return -1;
256f77c0515SJanosch Frank
2576531c0b8SEric Farman smp_sigp(idx, SIGP_INITIAL_CPU_RESET, 0, NULL);
258f77c0515SJanosch Frank
259550b4683SClaudio Imbrenda lc = alloc_pages_flags(1, AREA_DMA31);
2609e1e188cSClaudio Imbrenda cpus[idx].lowcore = lc;
2616531c0b8SEric Farman smp_sigp(idx, SIGP_SET_PREFIX, (unsigned long )lc, NULL);
262f77c0515SJanosch Frank
263f77c0515SJanosch Frank /* Copy all exception psws. */
2645a6a5506SClaudio Imbrenda memcpy(lc, cpus[0].lowcore, 512);
2654e5dd758SClaudio Imbrenda lc->this_cpu = &cpus[idx];
266f77c0515SJanosch Frank
267f77c0515SJanosch Frank /* Setup stack */
2689e1e188cSClaudio Imbrenda cpus[idx].stack = (uint64_t *)alloc_pages(2);
269f77c0515SJanosch Frank
270f77c0515SJanosch Frank /* Start without DAT and any other mask bits. */
2719e1e188cSClaudio Imbrenda lc->sw_int_psw.mask = psw.mask;
2729e1e188cSClaudio Imbrenda lc->sw_int_psw.addr = psw.addr;
2739e1e188cSClaudio Imbrenda lc->sw_int_grs[14] = psw.addr;
2749e1e188cSClaudio Imbrenda lc->sw_int_grs[15] = (uint64_t)cpus[idx].stack + (PAGE_SIZE * 4);
27544026818SJanosch Frank lc->restart_new_psw.mask = PSW_MASK_64;
276f77c0515SJanosch Frank lc->restart_new_psw.addr = (uint64_t)smp_cpu_setup_state;
277d34d3250SJanosch Frank lc->sw_int_crs[0] = BIT_ULL(CTL0_AFP);
278f77c0515SJanosch Frank
279f77c0515SJanosch Frank /* Start processing */
2809e1e188cSClaudio Imbrenda smp_cpu_restart_nolock(idx, NULL);
28124a8db62SJanosch Frank /* Wait until the cpu has finished setup and started the provided psw */
28224a8db62SJanosch Frank while (lc->restart_new_psw.addr != psw.addr)
28324a8db62SJanosch Frank mb();
2849e1e188cSClaudio Imbrenda
2859e1e188cSClaudio Imbrenda return 0;
2869e1e188cSClaudio Imbrenda }
2879e1e188cSClaudio Imbrenda
smp_cpu_setup(uint16_t idx,struct psw psw)2889e1e188cSClaudio Imbrenda int smp_cpu_setup(uint16_t idx, struct psw psw)
2899e1e188cSClaudio Imbrenda {
2909e1e188cSClaudio Imbrenda int rc = -1;
2919e1e188cSClaudio Imbrenda
2929e1e188cSClaudio Imbrenda spin_lock(&lock);
2939e1e188cSClaudio Imbrenda if (cpus) {
2949e1e188cSClaudio Imbrenda check_idx(idx);
2959e1e188cSClaudio Imbrenda rc = smp_cpu_setup_nolock(idx, psw);
2969e1e188cSClaudio Imbrenda }
297f77c0515SJanosch Frank spin_unlock(&lock);
298f77c0515SJanosch Frank return rc;
299f77c0515SJanosch Frank }
300f77c0515SJanosch Frank
301f77c0515SJanosch Frank /*
302f77c0515SJanosch Frank * Disregarding state, stop all cpus that once were online except for
303f77c0515SJanosch Frank * calling cpu.
304f77c0515SJanosch Frank */
smp_teardown(void)305f77c0515SJanosch Frank void smp_teardown(void)
306f77c0515SJanosch Frank {
307f77c0515SJanosch Frank int i = 0;
308f77c0515SJanosch Frank uint16_t this_cpu = stap();
30952076a63SJanosch Frank int num = smp_query_num_cpus();
310f77c0515SJanosch Frank
311f77c0515SJanosch Frank spin_lock(&lock);
31252076a63SJanosch Frank for (; i < num; i++) {
313f77c0515SJanosch Frank if (cpus[i].active &&
314f77c0515SJanosch Frank cpus[i].addr != this_cpu) {
315f77c0515SJanosch Frank sigp_retry(cpus[i].addr, SIGP_STOP, 0, NULL);
316f77c0515SJanosch Frank }
317f77c0515SJanosch Frank }
318f77c0515SJanosch Frank spin_unlock(&lock);
319f77c0515SJanosch Frank }
320f77c0515SJanosch Frank
321f77c0515SJanosch Frank /*Expected to be called from boot cpu */
322f77c0515SJanosch Frank extern uint64_t *stackptr;
smp_setup(void)323f77c0515SJanosch Frank void smp_setup(void)
324f77c0515SJanosch Frank {
325f77c0515SJanosch Frank int i = 0;
32652076a63SJanosch Frank int num = smp_query_num_cpus();
327f77c0515SJanosch Frank unsigned short cpu0_addr = stap();
32852076a63SJanosch Frank struct CPUEntry *entry = sclp_get_cpu_entries();
329f77c0515SJanosch Frank
330f77c0515SJanosch Frank spin_lock(&lock);
33152076a63SJanosch Frank if (num > 1)
33252076a63SJanosch Frank printf("SMP: Initializing, found %d cpus\n", num);
333f77c0515SJanosch Frank
3345a6a5506SClaudio Imbrenda cpus = calloc(num, sizeof(*cpus));
33552076a63SJanosch Frank for (i = 0; i < num; i++) {
33652076a63SJanosch Frank cpus[i].addr = entry[i].address;
337f77c0515SJanosch Frank cpus[i].active = false;
3384e5dd758SClaudio Imbrenda cpus[i].idx = i;
3395a6a5506SClaudio Imbrenda /*
3405a6a5506SClaudio Imbrenda * Fill in the boot CPU. If the boot CPU is not at index 0,
3415a6a5506SClaudio Imbrenda * swap it with the one at index 0. This guarantees that the
3425a6a5506SClaudio Imbrenda * boot CPU will always have index 0. If the boot CPU was
3435a6a5506SClaudio Imbrenda * already at index 0, a few extra useless assignments are
3445a6a5506SClaudio Imbrenda * performed, but everything will work ok.
3455a6a5506SClaudio Imbrenda * Notice that there is no guarantee that the list of CPUs
3465a6a5506SClaudio Imbrenda * returned by the Read SCP Info command is in any
3475a6a5506SClaudio Imbrenda * particular order, or that its order will stay consistent
3485a6a5506SClaudio Imbrenda * across multiple invocations.
3495a6a5506SClaudio Imbrenda */
35052076a63SJanosch Frank if (entry[i].address == cpu0_addr) {
3515a6a5506SClaudio Imbrenda cpus[i].addr = cpus[0].addr;
3525a6a5506SClaudio Imbrenda cpus[0].addr = cpu0_addr;
3535a6a5506SClaudio Imbrenda cpus[0].stack = stackptr;
3545a6a5506SClaudio Imbrenda cpus[0].lowcore = (void *)0;
3555a6a5506SClaudio Imbrenda cpus[0].active = true;
356*e5ce7b94SClaudio Imbrenda THIS_CPU = &cpus[0];
357f77c0515SJanosch Frank }
358f77c0515SJanosch Frank }
359f77c0515SJanosch Frank spin_unlock(&lock);
360f77c0515SJanosch Frank }
361