1fb9a0c74SPierre Morel /* SPDX-License-Identifier: GPL-2.0-only */ 2fb9a0c74SPierre Morel /* 3fb9a0c74SPierre Morel * CPU Topology 4fb9a0c74SPierre Morel * 5fb9a0c74SPierre Morel * Copyright IBM Corp. 2022 6fb9a0c74SPierre Morel * 7fb9a0c74SPierre Morel * Authors: 8fb9a0c74SPierre Morel * Pierre Morel <pmorel@linux.ibm.com> 9fb9a0c74SPierre Morel */ 10fb9a0c74SPierre Morel 11fb9a0c74SPierre Morel #include <libcflat.h> 12fb9a0c74SPierre Morel #include <asm/page.h> 13fb9a0c74SPierre Morel #include <asm/asm-offsets.h> 14fb9a0c74SPierre Morel #include <asm/interrupt.h> 15fb9a0c74SPierre Morel #include <asm/facility.h> 16fb9a0c74SPierre Morel #include <asm/barrier.h> 17fb9a0c74SPierre Morel #include <smp.h> 18fb9a0c74SPierre Morel #include <sclp.h> 19fb9a0c74SPierre Morel #include <s390x/hardware.h> 206f33f0b7SPierre Morel #include <s390x/stsi.h> 216f33f0b7SPierre Morel 226f33f0b7SPierre Morel static uint8_t pagebuf[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 236f33f0b7SPierre Morel 246f33f0b7SPierre Morel static int max_nested_lvl; 256f33f0b7SPierre Morel static int number_of_cpus; 266f33f0b7SPierre Morel static int cpus_in_masks; 276f33f0b7SPierre Morel static int max_cpus; 286f33f0b7SPierre Morel 296f33f0b7SPierre Morel /* 306f33f0b7SPierre Morel * Topology level as defined by architecture, all levels exists with 316f33f0b7SPierre Morel * a single container unless overwritten by the QEMU -smp parameter. 326f33f0b7SPierre Morel */ 336f33f0b7SPierre Morel static int expected_topo_lvl[CPU_TOPOLOGY_MAX_LEVEL] = { 1, 1, 1, 1, 1, 1 }; 34fb9a0c74SPierre Morel 35fb9a0c74SPierre Morel #define PTF_REQ_HORIZONTAL 0 36fb9a0c74SPierre Morel #define PTF_REQ_VERTICAL 1 37fb9a0c74SPierre Morel #define PTF_CHECK 2 38fb9a0c74SPierre Morel 39fb9a0c74SPierre Morel #define PTF_ERR_NO_REASON 0 40fb9a0c74SPierre Morel #define PTF_ERR_ALRDY_POLARIZED 1 41fb9a0c74SPierre Morel #define PTF_ERR_IN_PROGRESS 2 42fb9a0c74SPierre Morel 43fb9a0c74SPierre Morel extern int diag308_load_reset(u64); 44fb9a0c74SPierre Morel 45fb9a0c74SPierre Morel static int ptf(unsigned long fc, unsigned long *rc) 46fb9a0c74SPierre Morel { 47fb9a0c74SPierre Morel int cc; 48fb9a0c74SPierre Morel 49fb9a0c74SPierre Morel asm volatile( 50fb9a0c74SPierre Morel " ptf %1 \n" 51fb9a0c74SPierre Morel " ipm %0 \n" 52fb9a0c74SPierre Morel " srl %0,28 \n" 53fb9a0c74SPierre Morel : "=d" (cc), "+d" (fc) 54fb9a0c74SPierre Morel : 55fb9a0c74SPierre Morel : "cc"); 56fb9a0c74SPierre Morel 57fb9a0c74SPierre Morel *rc = fc >> 8; 58fb9a0c74SPierre Morel return cc; 59fb9a0c74SPierre Morel } 60fb9a0c74SPierre Morel 61fb9a0c74SPierre Morel static void check_privilege(int fc) 62fb9a0c74SPierre Morel { 63fb9a0c74SPierre Morel unsigned long rc; 64fb9a0c74SPierre Morel 65fb9a0c74SPierre Morel report_prefix_pushf("Privileged fc %d", fc); 66fb9a0c74SPierre Morel enter_pstate(); 67fb9a0c74SPierre Morel expect_pgm_int(); 68fb9a0c74SPierre Morel ptf(fc, &rc); 69fb9a0c74SPierre Morel check_pgm_int_code(PGM_INT_CODE_PRIVILEGED_OPERATION); 70fb9a0c74SPierre Morel report_prefix_pop(); 71fb9a0c74SPierre Morel } 72fb9a0c74SPierre Morel 73fb9a0c74SPierre Morel static void check_specifications(void) 74fb9a0c74SPierre Morel { 75fb9a0c74SPierre Morel unsigned long error = 0; 76fb9a0c74SPierre Morel unsigned long ptf_bits; 77fb9a0c74SPierre Morel unsigned long rc; 78fb9a0c74SPierre Morel int i; 79fb9a0c74SPierre Morel 80fb9a0c74SPierre Morel report_prefix_push("Specifications"); 81fb9a0c74SPierre Morel 82fb9a0c74SPierre Morel /* Function codes above 3 are undefined */ 83fb9a0c74SPierre Morel for (i = 4; i < 255; i++) { 84fb9a0c74SPierre Morel expect_pgm_int(); 85fb9a0c74SPierre Morel ptf(i, &rc); 86fb9a0c74SPierre Morel if (clear_pgm_int() != PGM_INT_CODE_SPECIFICATION) { 87fb9a0c74SPierre Morel report_fail("FC %d did not yield specification exception", i); 88fb9a0c74SPierre Morel error = 1; 89fb9a0c74SPierre Morel } 90fb9a0c74SPierre Morel } 91fb9a0c74SPierre Morel report(!error, "Undefined function codes"); 92fb9a0c74SPierre Morel 93fb9a0c74SPierre Morel /* Reserved bits must be 0 */ 94fb9a0c74SPierre Morel for (i = 8, error = 0; i < 64; i++) { 95fb9a0c74SPierre Morel ptf_bits = 0x01UL << i; 96fb9a0c74SPierre Morel expect_pgm_int(); 97fb9a0c74SPierre Morel ptf(ptf_bits, &rc); 98fb9a0c74SPierre Morel if (clear_pgm_int() != PGM_INT_CODE_SPECIFICATION) { 99fb9a0c74SPierre Morel report_fail("Reserved bit %d did not yield specification exception", i); 100fb9a0c74SPierre Morel error = 1; 101fb9a0c74SPierre Morel } 102fb9a0c74SPierre Morel } 103fb9a0c74SPierre Morel 104fb9a0c74SPierre Morel report(!error, "Reserved bits"); 105fb9a0c74SPierre Morel 106fb9a0c74SPierre Morel report_prefix_pop(); 107fb9a0c74SPierre Morel } 108fb9a0c74SPierre Morel 109fb9a0c74SPierre Morel static void check_polarization_change(void) 110fb9a0c74SPierre Morel { 111fb9a0c74SPierre Morel unsigned long rc; 112fb9a0c74SPierre Morel int cc; 113fb9a0c74SPierre Morel 114fb9a0c74SPierre Morel report_prefix_push("Polarization change"); 115fb9a0c74SPierre Morel 116fb9a0c74SPierre Morel /* We expect a clean state through reset */ 1171ad8ec94SNina Schoetterl-Glausch assert(diag308_load_reset(1)); 118fb9a0c74SPierre Morel 119fb9a0c74SPierre Morel /* 120fb9a0c74SPierre Morel * Set vertical polarization to verify that RESET sets 121fb9a0c74SPierre Morel * horizontal polarization back. 122fb9a0c74SPierre Morel */ 123fb9a0c74SPierre Morel cc = ptf(PTF_REQ_VERTICAL, &rc); 124fb9a0c74SPierre Morel report(cc == 0, "Set vertical polarization."); 125fb9a0c74SPierre Morel 1261ad8ec94SNina Schoetterl-Glausch assert(diag308_load_reset(1)); 127fb9a0c74SPierre Morel 128fb9a0c74SPierre Morel cc = ptf(PTF_CHECK, &rc); 129fb9a0c74SPierre Morel report(cc == 0, "Reset should clear topology report"); 130fb9a0c74SPierre Morel 131fb9a0c74SPierre Morel cc = ptf(PTF_REQ_HORIZONTAL, &rc); 132fb9a0c74SPierre Morel report(cc == 2 && rc == PTF_ERR_ALRDY_POLARIZED, 133fb9a0c74SPierre Morel "After RESET polarization is horizontal"); 134fb9a0c74SPierre Morel 135fb9a0c74SPierre Morel /* Flip between vertical and horizontal polarization */ 136fb9a0c74SPierre Morel cc = ptf(PTF_REQ_VERTICAL, &rc); 137fb9a0c74SPierre Morel report(cc == 0, "Change to vertical"); 138fb9a0c74SPierre Morel 139fb9a0c74SPierre Morel cc = ptf(PTF_CHECK, &rc); 1401ad8ec94SNina Schoetterl-Glausch report(cc == 1, "Should report change after horizontal -> vertical"); 141fb9a0c74SPierre Morel 142fb9a0c74SPierre Morel cc = ptf(PTF_REQ_VERTICAL, &rc); 143fb9a0c74SPierre Morel report(cc == 2 && rc == PTF_ERR_ALRDY_POLARIZED, "Double change to vertical"); 144fb9a0c74SPierre Morel 145fb9a0c74SPierre Morel cc = ptf(PTF_CHECK, &rc); 1461ad8ec94SNina Schoetterl-Glausch report(cc == 0, "Should not report change after vertical -> vertical"); 147fb9a0c74SPierre Morel 148fb9a0c74SPierre Morel cc = ptf(PTF_REQ_HORIZONTAL, &rc); 149fb9a0c74SPierre Morel report(cc == 0, "Change to horizontal"); 150fb9a0c74SPierre Morel 151fb9a0c74SPierre Morel cc = ptf(PTF_CHECK, &rc); 1521ad8ec94SNina Schoetterl-Glausch report(cc == 1, "Should report change after vertical -> horizontal"); 153fb9a0c74SPierre Morel 154fb9a0c74SPierre Morel cc = ptf(PTF_REQ_HORIZONTAL, &rc); 155fb9a0c74SPierre Morel report(cc == 2 && rc == PTF_ERR_ALRDY_POLARIZED, "Double change to horizontal"); 156fb9a0c74SPierre Morel 157fb9a0c74SPierre Morel cc = ptf(PTF_CHECK, &rc); 1581ad8ec94SNina Schoetterl-Glausch report(cc == 0, "Should not report change after horizontal -> horizontal"); 159fb9a0c74SPierre Morel 160fb9a0c74SPierre Morel report_prefix_pop(); 161fb9a0c74SPierre Morel } 162fb9a0c74SPierre Morel 163fb9a0c74SPierre Morel static void test_ptf(void) 164fb9a0c74SPierre Morel { 165fb9a0c74SPierre Morel check_privilege(PTF_REQ_HORIZONTAL); 166fb9a0c74SPierre Morel check_privilege(PTF_REQ_VERTICAL); 167fb9a0c74SPierre Morel check_privilege(PTF_CHECK); 168fb9a0c74SPierre Morel check_specifications(); 169fb9a0c74SPierre Morel check_polarization_change(); 170fb9a0c74SPierre Morel } 171fb9a0c74SPierre Morel 1726f33f0b7SPierre Morel /* 1736f33f0b7SPierre Morel * stsi_check_maxcpus 1746f33f0b7SPierre Morel * @info: Pointer to the stsi information 1756f33f0b7SPierre Morel * 1766f33f0b7SPierre Morel * The product of the numbers of containers per level 1776f33f0b7SPierre Morel * is the maximum number of CPU allowed by the machine. 1786f33f0b7SPierre Morel */ 1796f33f0b7SPierre Morel static void stsi_check_maxcpus(struct sysinfo_15_1_x *info) 1806f33f0b7SPierre Morel { 1816f33f0b7SPierre Morel int n, i; 1826f33f0b7SPierre Morel 1836f33f0b7SPierre Morel for (i = 0, n = 1; i < CPU_TOPOLOGY_MAX_LEVEL; i++) 1846f33f0b7SPierre Morel n *= info->mag[i] ?: 1; 1856f33f0b7SPierre Morel 1866f33f0b7SPierre Morel report(n == max_cpus, "Calculated max CPUs: %d", n); 1876f33f0b7SPierre Morel } 1886f33f0b7SPierre Morel 1896f33f0b7SPierre Morel /* 190*22e8195cSNina Schoetterl-Glausch * stsi_check_header 1916f33f0b7SPierre Morel * @info: Pointer to the stsi information 192*22e8195cSNina Schoetterl-Glausch * @sel2: stsi selector 2 value 1936f33f0b7SPierre Morel * 1946f33f0b7SPierre Morel * MAG field should match the architecture defined containers 1956f33f0b7SPierre Morel * when MNEST as returned by SCLP matches MNEST of the SYSIB. 1966f33f0b7SPierre Morel */ 197*22e8195cSNina Schoetterl-Glausch static void stsi_check_header(struct sysinfo_15_1_x *info, int sel2) 1986f33f0b7SPierre Morel { 1996f33f0b7SPierre Morel int i; 2006f33f0b7SPierre Morel 201*22e8195cSNina Schoetterl-Glausch report_prefix_push("Header"); 2026f33f0b7SPierre Morel 203*22e8195cSNina Schoetterl-Glausch /* Header is 16 bytes, each TLE 8 or 16, therefore alignment must be 8 at least */ 204*22e8195cSNina Schoetterl-Glausch report(IS_ALIGNED(info->length, 8), "Length %d multiple of 8", info->length); 205*22e8195cSNina Schoetterl-Glausch report(info->length < PAGE_SIZE, "Length %d in bounds", info->length); 206*22e8195cSNina Schoetterl-Glausch report(sel2 == info->mnest, "Valid mnest"); 2076f33f0b7SPierre Morel stsi_check_maxcpus(info); 2086f33f0b7SPierre Morel 2096f33f0b7SPierre Morel /* 2106f33f0b7SPierre Morel * It is not clear how the MAG fields are calculated when mnest 2116f33f0b7SPierre Morel * in the SYSIB 15.x is different from the maximum nested level 2126f33f0b7SPierre Morel * in the SCLP info, so we skip here for now. 2136f33f0b7SPierre Morel */ 2146f33f0b7SPierre Morel if (max_nested_lvl != info->mnest) { 2156f33f0b7SPierre Morel report_skip("No specification on layer aggregation"); 2166f33f0b7SPierre Morel goto done; 2176f33f0b7SPierre Morel } 2186f33f0b7SPierre Morel 2196f33f0b7SPierre Morel /* 2206f33f0b7SPierre Morel * MAG up to max_nested_lvl must match the architecture 2216f33f0b7SPierre Morel * defined containers. 2226f33f0b7SPierre Morel */ 2236f33f0b7SPierre Morel for (i = 0; i < max_nested_lvl; i++) 2246f33f0b7SPierre Morel report(info->mag[CPU_TOPOLOGY_MAX_LEVEL - i - 1] == expected_topo_lvl[i], 2256f33f0b7SPierre Morel "MAG %d field match %d == %d", 2266f33f0b7SPierre Morel i + 1, 2276f33f0b7SPierre Morel info->mag[CPU_TOPOLOGY_MAX_LEVEL - i - 1], 2286f33f0b7SPierre Morel expected_topo_lvl[i]); 2296f33f0b7SPierre Morel 2306f33f0b7SPierre Morel /* Above max_nested_lvl the MAG field must be null */ 2316f33f0b7SPierre Morel for (; i < CPU_TOPOLOGY_MAX_LEVEL; i++) 2326f33f0b7SPierre Morel report(info->mag[CPU_TOPOLOGY_MAX_LEVEL - i - 1] == 0, 2336f33f0b7SPierre Morel "MAG %d field match %d == %d", i + 1, 2346f33f0b7SPierre Morel info->mag[CPU_TOPOLOGY_MAX_LEVEL - i - 1], 0); 2356f33f0b7SPierre Morel 2366f33f0b7SPierre Morel done: 2376f33f0b7SPierre Morel report_prefix_pop(); 2386f33f0b7SPierre Morel } 2396f33f0b7SPierre Morel 2406f33f0b7SPierre Morel /** 2416f33f0b7SPierre Morel * check_tle: 2426f33f0b7SPierre Morel * @tc: pointer to first TLE 2436f33f0b7SPierre Morel * 2446f33f0b7SPierre Morel * Recursively check the containers TLEs until we 2456f33f0b7SPierre Morel * find a CPU TLE. 2466f33f0b7SPierre Morel */ 2476f33f0b7SPierre Morel static uint8_t *check_tle(void *tc) 2486f33f0b7SPierre Morel { 2496f33f0b7SPierre Morel struct topology_container *container = tc; 2506f33f0b7SPierre Morel struct topology_core *cpus; 2516f33f0b7SPierre Morel int n; 2526f33f0b7SPierre Morel 2536f33f0b7SPierre Morel if (container->nl) { 2546f33f0b7SPierre Morel report_info("NL: %d id: %d", container->nl, container->id); 2556f33f0b7SPierre Morel 2566f33f0b7SPierre Morel report(!(*(uint64_t *)tc & CONTAINER_TLE_RES_BITS), 2576f33f0b7SPierre Morel "reserved bits %016lx", 2586f33f0b7SPierre Morel *(uint64_t *)tc & CONTAINER_TLE_RES_BITS); 2596f33f0b7SPierre Morel 2606f33f0b7SPierre Morel return check_tle(tc + sizeof(*container)); 2616f33f0b7SPierre Morel } 2626f33f0b7SPierre Morel 2636f33f0b7SPierre Morel report_info("NL: %d", container->nl); 2646f33f0b7SPierre Morel cpus = tc; 2656f33f0b7SPierre Morel 2666f33f0b7SPierre Morel report(!(*(uint64_t *)tc & CPUS_TLE_RES_BITS), "reserved bits %016lx", 2676f33f0b7SPierre Morel *(uint64_t *)tc & CPUS_TLE_RES_BITS); 2686f33f0b7SPierre Morel 26931ebf55bSNina Schoetterl-Glausch report(cpus->type == CPU_TYPE_IFL, "type IFL"); 2706f33f0b7SPierre Morel 2716f33f0b7SPierre Morel report_info("origin: %d", cpus->origin); 2726f33f0b7SPierre Morel report_info("mask: %016lx", cpus->mask); 2736f33f0b7SPierre Morel report_info("dedicated: %d entitlement: %d", cpus->d, cpus->pp); 2746f33f0b7SPierre Morel 2756f33f0b7SPierre Morel n = __builtin_popcountl(cpus->mask); 2766f33f0b7SPierre Morel report(n <= expected_topo_lvl[0], "CPUs per mask: %d out of max %d", 2776f33f0b7SPierre Morel n, expected_topo_lvl[0]); 2786f33f0b7SPierre Morel cpus_in_masks += n; 2796f33f0b7SPierre Morel 2806f33f0b7SPierre Morel if (!cpus->d) 2816f33f0b7SPierre Morel report_skip("Not dedicated"); 2826f33f0b7SPierre Morel else 28331ebf55bSNina Schoetterl-Glausch report(cpus->pp == POLARIZATION_VERTICAL_HIGH || 28431ebf55bSNina Schoetterl-Glausch cpus->pp == POLARIZATION_HORIZONTAL, 28547abae77SNina Schoetterl-Glausch "Dedicated CPUs are either horizontally polarized or have high entitlement"); 2866f33f0b7SPierre Morel 2876f33f0b7SPierre Morel return tc + sizeof(*cpus); 2886f33f0b7SPierre Morel } 2896f33f0b7SPierre Morel 2906f33f0b7SPierre Morel /** 2916f33f0b7SPierre Morel * stsi_check_tle_coherency: 2926f33f0b7SPierre Morel * @info: Pointer to the stsi information 2936f33f0b7SPierre Morel * 2946f33f0b7SPierre Morel * We verify that we get the expected number of Topology List Entry 2956f33f0b7SPierre Morel * containers for a specific level. 2966f33f0b7SPierre Morel */ 2976f33f0b7SPierre Morel static void stsi_check_tle_coherency(struct sysinfo_15_1_x *info) 2986f33f0b7SPierre Morel { 2996f33f0b7SPierre Morel void *tc, *end; 3006f33f0b7SPierre Morel 3016f33f0b7SPierre Morel report_prefix_push("TLE"); 3026f33f0b7SPierre Morel cpus_in_masks = 0; 3036f33f0b7SPierre Morel 3046f33f0b7SPierre Morel tc = info->tle; 3056f33f0b7SPierre Morel end = (void *)info + info->length; 3066f33f0b7SPierre Morel 3076f33f0b7SPierre Morel while (tc < end) 3086f33f0b7SPierre Morel tc = check_tle(tc); 3096f33f0b7SPierre Morel 3106f33f0b7SPierre Morel report(cpus_in_masks == number_of_cpus, "CPUs in mask %d", 3116f33f0b7SPierre Morel cpus_in_masks); 3126f33f0b7SPierre Morel 3136f33f0b7SPierre Morel report_prefix_pop(); 3146f33f0b7SPierre Morel } 3156f33f0b7SPierre Morel 3166f33f0b7SPierre Morel /** 3176f33f0b7SPierre Morel * stsi_get_sysib: 3186f33f0b7SPierre Morel * @info: pointer to the STSI info structure 3196f33f0b7SPierre Morel * @sel2: the selector giving the topology level to check 3206f33f0b7SPierre Morel * 3216f33f0b7SPierre Morel * Fill the sysinfo_15_1_x info structure and check the 3226f33f0b7SPierre Morel * SYSIB header. 3236f33f0b7SPierre Morel * 3246f33f0b7SPierre Morel * Returns instruction validity. 3256f33f0b7SPierre Morel */ 3266f33f0b7SPierre Morel static int stsi_get_sysib(struct sysinfo_15_1_x *info, int sel2) 3276f33f0b7SPierre Morel { 3286f33f0b7SPierre Morel int ret; 3296f33f0b7SPierre Morel 3306f33f0b7SPierre Morel report_prefix_pushf("SYSIB"); 3316f33f0b7SPierre Morel 332fbc8a89bSNina Schoetterl-Glausch ret = stsi(info, 15, 1, sel2); 3336f33f0b7SPierre Morel 3346f33f0b7SPierre Morel if (max_nested_lvl >= sel2) { 3356f33f0b7SPierre Morel report(!ret, "Valid instruction"); 3366f33f0b7SPierre Morel } else { 3376f33f0b7SPierre Morel report(ret, "Invalid instruction"); 3386f33f0b7SPierre Morel } 3396f33f0b7SPierre Morel 3406f33f0b7SPierre Morel report_prefix_pop(); 3416f33f0b7SPierre Morel 3426f33f0b7SPierre Morel return ret; 3436f33f0b7SPierre Morel } 3446f33f0b7SPierre Morel 3456f33f0b7SPierre Morel /** 3466f33f0b7SPierre Morel * check_sysinfo_15_1_x: 3476f33f0b7SPierre Morel * @info: pointer to the STSI info structure 3486f33f0b7SPierre Morel * @sel2: the selector giving the topology level to check 3496f33f0b7SPierre Morel * 3506f33f0b7SPierre Morel * Check if the validity of the STSI instruction and then 3516f33f0b7SPierre Morel * calls specific checks on the information buffer. 3526f33f0b7SPierre Morel */ 3536f33f0b7SPierre Morel static void check_sysinfo_15_1_x(struct sysinfo_15_1_x *info, int sel2) 3546f33f0b7SPierre Morel { 3556f33f0b7SPierre Morel int ret; 3566f33f0b7SPierre Morel int cc; 3576f33f0b7SPierre Morel unsigned long rc; 3586f33f0b7SPierre Morel 3596f33f0b7SPierre Morel report_prefix_pushf("15_1_%d", sel2); 3606f33f0b7SPierre Morel 3616f33f0b7SPierre Morel ret = stsi_get_sysib(info, sel2); 3626f33f0b7SPierre Morel if (ret) { 3636f33f0b7SPierre Morel report_skip("Selector 2 not supported by architecture"); 3646f33f0b7SPierre Morel goto end; 3656f33f0b7SPierre Morel } 3666f33f0b7SPierre Morel 3676f33f0b7SPierre Morel report_prefix_pushf("H"); 3686f33f0b7SPierre Morel cc = ptf(PTF_REQ_HORIZONTAL, &rc); 3696f33f0b7SPierre Morel if (cc != 0 && rc != PTF_ERR_ALRDY_POLARIZED) { 3706f33f0b7SPierre Morel report_fail("Unable to set horizontal polarization"); 3716f33f0b7SPierre Morel goto vertical; 3726f33f0b7SPierre Morel } 3736f33f0b7SPierre Morel 374*22e8195cSNina Schoetterl-Glausch stsi_check_header(info, sel2); 3756f33f0b7SPierre Morel stsi_check_tle_coherency(info); 3766f33f0b7SPierre Morel 3776f33f0b7SPierre Morel vertical: 3786f33f0b7SPierre Morel report_prefix_pop(); 3796f33f0b7SPierre Morel report_prefix_pushf("V"); 3806f33f0b7SPierre Morel 3816f33f0b7SPierre Morel cc = ptf(PTF_REQ_VERTICAL, &rc); 3826f33f0b7SPierre Morel if (cc != 0 && rc != PTF_ERR_ALRDY_POLARIZED) { 3836f33f0b7SPierre Morel report_fail("Unable to set vertical polarization"); 3846f33f0b7SPierre Morel goto end; 3856f33f0b7SPierre Morel } 3866f33f0b7SPierre Morel 387*22e8195cSNina Schoetterl-Glausch stsi_check_header(info, sel2); 3886f33f0b7SPierre Morel stsi_check_tle_coherency(info); 3896f33f0b7SPierre Morel report_prefix_pop(); 3906f33f0b7SPierre Morel 3916f33f0b7SPierre Morel end: 3926f33f0b7SPierre Morel report_prefix_pop(); 3936f33f0b7SPierre Morel } 3946f33f0b7SPierre Morel 3956f33f0b7SPierre Morel /* 3966f33f0b7SPierre Morel * The Maximum Nested level is given by SCLP READ_SCP_INFO if the MNEST facility 3976f33f0b7SPierre Morel * is available. 3986f33f0b7SPierre Morel * If the MNEST facility is not available, sclp_get_stsi_mnest returns 0 and the 3996f33f0b7SPierre Morel * Maximum Nested level is 2 4006f33f0b7SPierre Morel */ 4016f33f0b7SPierre Morel #define S390_DEFAULT_MNEST 2 4026f33f0b7SPierre Morel static int sclp_get_mnest(void) 4036f33f0b7SPierre Morel { 4046f33f0b7SPierre Morel return sclp_get_stsi_mnest() ?: S390_DEFAULT_MNEST; 4056f33f0b7SPierre Morel } 4066f33f0b7SPierre Morel 4076f33f0b7SPierre Morel static int expected_num_cpus(void) 4086f33f0b7SPierre Morel { 4096f33f0b7SPierre Morel int i; 4106f33f0b7SPierre Morel int ncpus = 1; 4116f33f0b7SPierre Morel 4126f33f0b7SPierre Morel for (i = 0; i < CPU_TOPOLOGY_MAX_LEVEL; i++) 4136f33f0b7SPierre Morel ncpus *= expected_topo_lvl[i] ?: 1; 4146f33f0b7SPierre Morel 4156f33f0b7SPierre Morel return ncpus; 4166f33f0b7SPierre Morel } 4176f33f0b7SPierre Morel 4186f33f0b7SPierre Morel /** 4196f33f0b7SPierre Morel * test_stsi: 4206f33f0b7SPierre Morel * 4216f33f0b7SPierre Morel * Retrieves the maximum nested topology level supported by the architecture 4226f33f0b7SPierre Morel * and the number of CPUs. 4236f33f0b7SPierre Morel * Calls the checking for the STSI instruction in sel2 reverse level order 4246f33f0b7SPierre Morel * from 6 (CPU_TOPOLOGY_MAX_LEVEL) to 2 to have the most interesting level, 4256f33f0b7SPierre Morel * the one triggering a topology-change-report-pending condition, level 2, 4266f33f0b7SPierre Morel * at the end of the report. 4276f33f0b7SPierre Morel * 4286f33f0b7SPierre Morel */ 4296f33f0b7SPierre Morel static void test_stsi(void) 4306f33f0b7SPierre Morel { 4316f33f0b7SPierre Morel int sel2; 4326f33f0b7SPierre Morel 4336f33f0b7SPierre Morel max_cpus = expected_num_cpus(); 4346f33f0b7SPierre Morel report_info("Architecture max CPUs: %d", max_cpus); 4356f33f0b7SPierre Morel 4366f33f0b7SPierre Morel max_nested_lvl = sclp_get_mnest(); 4376f33f0b7SPierre Morel report_info("SCLP maximum nested level : %d", max_nested_lvl); 4386f33f0b7SPierre Morel 4396f33f0b7SPierre Morel number_of_cpus = sclp_get_cpu_num(); 4406f33f0b7SPierre Morel report_info("SCLP number of CPU: %d", number_of_cpus); 4416f33f0b7SPierre Morel 4426f33f0b7SPierre Morel /* STSI selector 2 can takes values between 2 and 6 */ 4436f33f0b7SPierre Morel for (sel2 = 6; sel2 >= 2; sel2--) 4446f33f0b7SPierre Morel check_sysinfo_15_1_x((struct sysinfo_15_1_x *)pagebuf, sel2); 4456f33f0b7SPierre Morel } 4466f33f0b7SPierre Morel 4476f33f0b7SPierre Morel /** 4486f33f0b7SPierre Morel * parse_topology_args: 4496f33f0b7SPierre Morel * @argc: number of arguments 4506f33f0b7SPierre Morel * @argv: argument array 4516f33f0b7SPierre Morel * 4526f33f0b7SPierre Morel * This function initialize the architecture topology levels 4536f33f0b7SPierre Morel * which should be the same as the one provided by the hypervisor. 4546f33f0b7SPierre Morel * 4556f33f0b7SPierre Morel * We use the current names found in IBM/Z literature, Linux and QEMU: 4566f33f0b7SPierre Morel * cores, sockets/packages, books, drawers and nodes to facilitate the 4576f33f0b7SPierre Morel * human machine interface but store the result in a machine abstract 4586f33f0b7SPierre Morel * array of architecture topology levels. 4596f33f0b7SPierre Morel * Note that when QEMU uses socket as a name for the topology level 1 4606f33f0b7SPierre Morel * Linux uses package or physical_package. 4616f33f0b7SPierre Morel */ 4626f33f0b7SPierre Morel static void parse_topology_args(int argc, char **argv) 4636f33f0b7SPierre Morel { 4646f33f0b7SPierre Morel int i; 4656f33f0b7SPierre Morel static const char * const levels[] = { "cores", "sockets", 4666f33f0b7SPierre Morel "books", "drawers" }; 4676f33f0b7SPierre Morel 4686f33f0b7SPierre Morel for (i = 1; i < argc; i++) { 4696f33f0b7SPierre Morel char *flag = argv[i]; 4706f33f0b7SPierre Morel int level; 4716f33f0b7SPierre Morel 4726f33f0b7SPierre Morel if (flag[0] != '-') 4736f33f0b7SPierre Morel report_abort("Argument is expected to begin with '-'"); 4746f33f0b7SPierre Morel flag++; 47585e1e05fSNina Schoetterl-Glausch for (level = 0; level < ARRAY_SIZE(levels); level++) { 4766f33f0b7SPierre Morel if (!strcmp(levels[level], flag)) 4776f33f0b7SPierre Morel break; 4786f33f0b7SPierre Morel } 4796f33f0b7SPierre Morel if (level == ARRAY_SIZE(levels)) 4806f33f0b7SPierre Morel report_abort("Unknown parameter %s", flag); 4816f33f0b7SPierre Morel 4826f33f0b7SPierre Morel expected_topo_lvl[level] = atol(argv[++i]); 4836f33f0b7SPierre Morel report_info("%s: %d", levels[level], expected_topo_lvl[level]); 4846f33f0b7SPierre Morel } 4856f33f0b7SPierre Morel } 4866f33f0b7SPierre Morel 487fb9a0c74SPierre Morel static struct { 488fb9a0c74SPierre Morel const char *name; 489fb9a0c74SPierre Morel void (*func)(void); 490fb9a0c74SPierre Morel } tests[] = { 491fb9a0c74SPierre Morel { "PTF", test_ptf }, 4926f33f0b7SPierre Morel { "STSI", test_stsi }, 493fb9a0c74SPierre Morel { NULL, NULL } 494fb9a0c74SPierre Morel }; 495fb9a0c74SPierre Morel 496fb9a0c74SPierre Morel int main(int argc, char *argv[]) 497fb9a0c74SPierre Morel { 498fb9a0c74SPierre Morel int i; 499fb9a0c74SPierre Morel 500fb9a0c74SPierre Morel report_prefix_push("CPU Topology"); 501fb9a0c74SPierre Morel 5026f33f0b7SPierre Morel parse_topology_args(argc, argv); 5036f33f0b7SPierre Morel 504fb9a0c74SPierre Morel if (!test_facility(11)) { 505fb9a0c74SPierre Morel report_skip("Topology facility not present"); 506fb9a0c74SPierre Morel goto end; 507fb9a0c74SPierre Morel } 508fb9a0c74SPierre Morel 509fb9a0c74SPierre Morel report_info("Virtual machine level %ld", stsi_get_fc()); 510fb9a0c74SPierre Morel 511fb9a0c74SPierre Morel for (i = 0; tests[i].name; i++) { 512fb9a0c74SPierre Morel report_prefix_push(tests[i].name); 513fb9a0c74SPierre Morel tests[i].func(); 514fb9a0c74SPierre Morel report_prefix_pop(); 515fb9a0c74SPierre Morel } 516fb9a0c74SPierre Morel 517fb9a0c74SPierre Morel end: 518fb9a0c74SPierre Morel report_prefix_pop(); 519fb9a0c74SPierre Morel return report_summary(); 520fb9a0c74SPierre Morel } 521