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 42*4e5dd758SClaudio Imbrenda struct lowcore *smp_get_lowcore(uint16_t idx) 43*4e5dd758SClaudio Imbrenda { 44*4e5dd758SClaudio Imbrenda if (THIS_CPU->idx == idx) 45*4e5dd758SClaudio Imbrenda return &lowcore; 46*4e5dd758SClaudio Imbrenda 47*4e5dd758SClaudio Imbrenda check_idx(idx); 48*4e5dd758SClaudio Imbrenda return cpus[idx].lowcore; 49*4e5dd758SClaudio Imbrenda } 50*4e5dd758SClaudio Imbrenda 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 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 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 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 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 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 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 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 */ 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 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 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 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 */ 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 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 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 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); 265*4e5dd758SClaudio 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 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 */ 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; 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; 338*4e5dd758SClaudio 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; 356f77c0515SJanosch Frank } 357f77c0515SJanosch Frank } 358f77c0515SJanosch Frank spin_unlock(&lock); 359f77c0515SJanosch Frank } 360