1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2395d31d4SMartin Schwidefsky /* 3395d31d4SMartin Schwidefsky * Copyright IBM Corp. 2008 4395d31d4SMartin Schwidefsky * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) 5395d31d4SMartin Schwidefsky */ 6395d31d4SMartin Schwidefsky 7395d31d4SMartin Schwidefsky #define KMSG_COMPONENT "cpu" 8395d31d4SMartin Schwidefsky #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 9395d31d4SMartin Schwidefsky 104ecf0a43SHeiko Carstens #include <linux/stop_machine.h> 11ca21872eSHeiko Carstens #include <linux/cpufeature.h> 12157467baSHeiko Carstens #include <linux/bitops.h> 13395d31d4SMartin Schwidefsky #include <linux/kernel.h> 1468e21be2SIngo Molnar #include <linux/sched/mm.h> 15395d31d4SMartin Schwidefsky #include <linux/init.h> 16395d31d4SMartin Schwidefsky #include <linux/seq_file.h> 17589ee628SIngo Molnar #include <linux/mm_types.h> 18395d31d4SMartin Schwidefsky #include <linux/delay.h> 1919726cecSHeiko Carstens #include <linux/cpu.h> 2068e21be2SIngo Molnar 211ec2772eSMartin Schwidefsky #include <asm/diag.h> 22097a116cSHeiko Carstens #include <asm/facility.h> 23395d31d4SMartin Schwidefsky #include <asm/elf.h> 24395d31d4SMartin Schwidefsky #include <asm/lowcore.h> 25395d31d4SMartin Schwidefsky #include <asm/param.h> 264d92f502SHeiko Carstens #include <asm/smp.h> 27395d31d4SMartin Schwidefsky 28097a116cSHeiko Carstens struct cpu_info { 29097a116cSHeiko Carstens unsigned int cpu_mhz_dynamic; 30097a116cSHeiko Carstens unsigned int cpu_mhz_static; 31097a116cSHeiko Carstens struct cpuid cpu_id; 32097a116cSHeiko Carstens }; 33097a116cSHeiko Carstens 34097a116cSHeiko Carstens static DEFINE_PER_CPU(struct cpu_info, cpu_info); 3538f2c691SMartin Schwidefsky static DEFINE_PER_CPU(int, cpu_relax_retry); 36097a116cSHeiko Carstens 37097a116cSHeiko Carstens static bool machine_has_cpu_mhz; 38097a116cSHeiko Carstens 39097a116cSHeiko Carstens void __init cpu_detect_mhz_feature(void) 40097a116cSHeiko Carstens { 41097a116cSHeiko Carstens if (test_facility(34) && __ecag(ECAG_CPU_ATTRIBUTE, 0) != -1UL) 42970ba6acSHeiko Carstens machine_has_cpu_mhz = true; 43097a116cSHeiko Carstens } 44097a116cSHeiko Carstens 45097a116cSHeiko Carstens static void update_cpu_mhz(void *arg) 46097a116cSHeiko Carstens { 47097a116cSHeiko Carstens unsigned long mhz; 48097a116cSHeiko Carstens struct cpu_info *c; 49097a116cSHeiko Carstens 50097a116cSHeiko Carstens mhz = __ecag(ECAG_CPU_ATTRIBUTE, 0); 51097a116cSHeiko Carstens c = this_cpu_ptr(&cpu_info); 52097a116cSHeiko Carstens c->cpu_mhz_dynamic = mhz >> 32; 53097a116cSHeiko Carstens c->cpu_mhz_static = mhz & 0xffffffff; 54097a116cSHeiko Carstens } 55097a116cSHeiko Carstens 56097a116cSHeiko Carstens void s390_update_cpu_mhz(void) 57097a116cSHeiko Carstens { 58097a116cSHeiko Carstens s390_adjust_jiffies(); 59097a116cSHeiko Carstens if (machine_has_cpu_mhz) 60097a116cSHeiko Carstens on_each_cpu(update_cpu_mhz, NULL, 0); 61097a116cSHeiko Carstens } 6294038a99SMartin Schwidefsky 634ecf0a43SHeiko Carstens void notrace stop_machine_yield(const struct cpumask *cpumask) 644d92f502SHeiko Carstens { 6538f2c691SMartin Schwidefsky int cpu, this_cpu; 6638f2c691SMartin Schwidefsky 6738f2c691SMartin Schwidefsky this_cpu = smp_processor_id(); 6838f2c691SMartin Schwidefsky if (__this_cpu_inc_return(cpu_relax_retry) >= spin_retry) { 6938f2c691SMartin Schwidefsky __this_cpu_write(cpu_relax_retry, 0); 7038f2c691SMartin Schwidefsky cpu = cpumask_next_wrap(this_cpu, cpumask, this_cpu, false); 7138f2c691SMartin Schwidefsky if (cpu >= nr_cpu_ids) 7238f2c691SMartin Schwidefsky return; 7338f2c691SMartin Schwidefsky if (arch_vcpu_is_preempted(cpu)) 7438f2c691SMartin Schwidefsky smp_yield_cpu(cpu); 751ec2772eSMartin Schwidefsky } 764d92f502SHeiko Carstens } 774d92f502SHeiko Carstens 7894038a99SMartin Schwidefsky /* 7994038a99SMartin Schwidefsky * cpu_init - initializes state that is per-CPU. 8094038a99SMartin Schwidefsky */ 81e2741f17SPaul Gortmaker void cpu_init(void) 8294038a99SMartin Schwidefsky { 83097a116cSHeiko Carstens struct cpuid *id = this_cpu_ptr(&cpu_info.cpu_id); 8494038a99SMartin Schwidefsky 8594038a99SMartin Schwidefsky get_cpu_id(id); 86097a116cSHeiko Carstens if (machine_has_cpu_mhz) 87097a116cSHeiko Carstens update_cpu_mhz(NULL); 88f1f10076SVegard Nossum mmgrab(&init_mm); 8994038a99SMartin Schwidefsky current->active_mm = &init_mm; 9094038a99SMartin Schwidefsky BUG_ON(current->mm); 9194038a99SMartin Schwidefsky enter_lazy_tlb(&init_mm, current); 9294038a99SMartin Schwidefsky } 9394038a99SMartin Schwidefsky 9494038a99SMartin Schwidefsky /* 958f00b3e2SHendrik Brueckner * cpu_have_feature - Test CPU features on module initialization 968f00b3e2SHendrik Brueckner */ 978f00b3e2SHendrik Brueckner int cpu_have_feature(unsigned int num) 988f00b3e2SHendrik Brueckner { 998f00b3e2SHendrik Brueckner return elf_hwcap & (1UL << num); 1008f00b3e2SHendrik Brueckner } 1018f00b3e2SHendrik Brueckner EXPORT_SYMBOL(cpu_have_feature); 1028f00b3e2SHendrik Brueckner 103157467baSHeiko Carstens static void show_facilities(struct seq_file *m) 104157467baSHeiko Carstens { 105157467baSHeiko Carstens unsigned int bit; 106157467baSHeiko Carstens long *facilities; 107157467baSHeiko Carstens 108157467baSHeiko Carstens facilities = (long *)&S390_lowcore.stfle_fac_list; 109157467baSHeiko Carstens seq_puts(m, "facilities :"); 110157467baSHeiko Carstens for_each_set_bit_inv(bit, facilities, MAX_FACILITY_BIT) 111157467baSHeiko Carstens seq_printf(m, " %d", bit); 112157467baSHeiko Carstens seq_putc(m, '\n'); 113157467baSHeiko Carstens } 114157467baSHeiko Carstens 115219a21b3SHeiko Carstens static void show_cpu_summary(struct seq_file *m, void *v) 116395d31d4SMartin Schwidefsky { 117fbf3c542SHeiko Carstens static const char *hwcap_str[] = { 118395d31d4SMartin Schwidefsky "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", 119a8fd6168SMartin Schwidefsky "edat", "etf3eh", "highgprs", "te", "vx", "vxd", "vxe", "gs", 120a8fd6168SMartin Schwidefsky "vxe2", "vxp", "sort", "dflt" 121395d31d4SMartin Schwidefsky }; 1227f16d7e7SDavid Hildenbrand static const char * const int_hwcap_str[] = { 1237f16d7e7SDavid Hildenbrand "sie" 1247f16d7e7SDavid Hildenbrand }; 125219a21b3SHeiko Carstens int i, cpu; 126395d31d4SMartin Schwidefsky 127395d31d4SMartin Schwidefsky seq_printf(m, "vendor_id : IBM/S390\n" 128395d31d4SMartin Schwidefsky "# processors : %i\n" 129395d31d4SMartin Schwidefsky "bogomips per cpu: %lu.%02lu\n", 130395d31d4SMartin Schwidefsky num_online_cpus(), loops_per_jiffy/(500000/HZ), 131395d31d4SMartin Schwidefsky (loops_per_jiffy/(5000/HZ))%100); 13210f4954aSHeiko Carstens seq_printf(m, "max thread id : %d\n", smp_cpu_mtid); 133395d31d4SMartin Schwidefsky seq_puts(m, "features\t: "); 134fbf3c542SHeiko Carstens for (i = 0; i < ARRAY_SIZE(hwcap_str); i++) 135395d31d4SMartin Schwidefsky if (hwcap_str[i] && (elf_hwcap & (1UL << i))) 136395d31d4SMartin Schwidefsky seq_printf(m, "%s ", hwcap_str[i]); 1377f16d7e7SDavid Hildenbrand for (i = 0; i < ARRAY_SIZE(int_hwcap_str); i++) 1387f16d7e7SDavid Hildenbrand if (int_hwcap_str[i] && (int_hwcap & (1UL << i))) 1397f16d7e7SDavid Hildenbrand seq_printf(m, "%s ", int_hwcap_str[i]); 140395d31d4SMartin Schwidefsky seq_puts(m, "\n"); 141157467baSHeiko Carstens show_facilities(m); 1426668022cSHeiko Carstens show_cacheinfo(m); 143219a21b3SHeiko Carstens for_each_online_cpu(cpu) { 144097a116cSHeiko Carstens struct cpuid *id = &per_cpu(cpu_info.cpu_id, cpu); 145219a21b3SHeiko Carstens 146219a21b3SHeiko Carstens seq_printf(m, "processor %d: " 147395d31d4SMartin Schwidefsky "version = %02X, " 148395d31d4SMartin Schwidefsky "identification = %06X, " 149395d31d4SMartin Schwidefsky "machine = %04X\n", 150219a21b3SHeiko Carstens cpu, id->version, id->ident, id->machine); 151395d31d4SMartin Schwidefsky } 152219a21b3SHeiko Carstens } 153219a21b3SHeiko Carstens 154fb835102SAlexander Gordeev static void show_cpu_topology(struct seq_file *m, unsigned long n) 155fb835102SAlexander Gordeev { 156fb835102SAlexander Gordeev #ifdef CONFIG_SCHED_TOPOLOGY 157fb835102SAlexander Gordeev seq_printf(m, "physical id : %d\n", topology_physical_package_id(n)); 158fb835102SAlexander Gordeev seq_printf(m, "core id : %d\n", topology_core_id(n)); 159fb835102SAlexander Gordeev seq_printf(m, "book id : %d\n", topology_book_id(n)); 160fb835102SAlexander Gordeev seq_printf(m, "drawer id : %d\n", topology_drawer_id(n)); 161fb835102SAlexander Gordeev seq_printf(m, "dedicated : %d\n", topology_cpu_dedicated(n)); 162fb835102SAlexander Gordeev #endif /* CONFIG_SCHED_TOPOLOGY */ 163fb835102SAlexander Gordeev } 164fb835102SAlexander Gordeev 165fb835102SAlexander Gordeev static void show_cpu_ids(struct seq_file *m, unsigned long n) 166fb835102SAlexander Gordeev { 167fb835102SAlexander Gordeev struct cpuid *id = &per_cpu(cpu_info.cpu_id, n); 168fb835102SAlexander Gordeev 169fb835102SAlexander Gordeev seq_printf(m, "version : %02X\n", id->version); 170fb835102SAlexander Gordeev seq_printf(m, "identification : %06X\n", id->ident); 171fb835102SAlexander Gordeev seq_printf(m, "machine : %04X\n", id->machine); 172fb835102SAlexander Gordeev } 173fb835102SAlexander Gordeev 174097a116cSHeiko Carstens static void show_cpu_mhz(struct seq_file *m, unsigned long n) 175097a116cSHeiko Carstens { 176097a116cSHeiko Carstens struct cpu_info *c = per_cpu_ptr(&cpu_info, n); 177097a116cSHeiko Carstens 178097a116cSHeiko Carstens seq_printf(m, "cpu MHz dynamic : %d\n", c->cpu_mhz_dynamic); 179097a116cSHeiko Carstens seq_printf(m, "cpu MHz static : %d\n", c->cpu_mhz_static); 180097a116cSHeiko Carstens } 181097a116cSHeiko Carstens 182219a21b3SHeiko Carstens /* 183219a21b3SHeiko Carstens * show_cpuinfo - Get information on one CPU for use by procfs. 184219a21b3SHeiko Carstens */ 185219a21b3SHeiko Carstens static int show_cpuinfo(struct seq_file *m, void *v) 186219a21b3SHeiko Carstens { 187219a21b3SHeiko Carstens unsigned long n = (unsigned long) v - 1; 188219a21b3SHeiko Carstens 189219a21b3SHeiko Carstens if (!n) 190219a21b3SHeiko Carstens show_cpu_summary(m, v); 191097a116cSHeiko Carstens if (!machine_has_cpu_mhz) 192097a116cSHeiko Carstens return 0; 193109ab954SHeiko Carstens seq_printf(m, "\ncpu number : %ld\n", n); 194fb835102SAlexander Gordeev show_cpu_topology(m, n); 195fb835102SAlexander Gordeev show_cpu_ids(m, n); 196097a116cSHeiko Carstens show_cpu_mhz(m, n); 197395d31d4SMartin Schwidefsky return 0; 198395d31d4SMartin Schwidefsky } 199395d31d4SMartin Schwidefsky 200281eaa8cSHeiko Carstens static inline void *c_update(loff_t *pos) 201281eaa8cSHeiko Carstens { 202281eaa8cSHeiko Carstens if (*pos) 203281eaa8cSHeiko Carstens *pos = cpumask_next(*pos - 1, cpu_online_mask); 204281eaa8cSHeiko Carstens return *pos < nr_cpu_ids ? (void *)*pos + 1 : NULL; 205281eaa8cSHeiko Carstens } 206281eaa8cSHeiko Carstens 207395d31d4SMartin Schwidefsky static void *c_start(struct seq_file *m, loff_t *pos) 208395d31d4SMartin Schwidefsky { 209281eaa8cSHeiko Carstens get_online_cpus(); 210281eaa8cSHeiko Carstens return c_update(pos); 211395d31d4SMartin Schwidefsky } 212395d31d4SMartin Schwidefsky 213395d31d4SMartin Schwidefsky static void *c_next(struct seq_file *m, void *v, loff_t *pos) 214395d31d4SMartin Schwidefsky { 215395d31d4SMartin Schwidefsky ++*pos; 216281eaa8cSHeiko Carstens return c_update(pos); 217395d31d4SMartin Schwidefsky } 218395d31d4SMartin Schwidefsky 219395d31d4SMartin Schwidefsky static void c_stop(struct seq_file *m, void *v) 220395d31d4SMartin Schwidefsky { 221281eaa8cSHeiko Carstens put_online_cpus(); 222395d31d4SMartin Schwidefsky } 223395d31d4SMartin Schwidefsky 224395d31d4SMartin Schwidefsky const struct seq_operations cpuinfo_op = { 225395d31d4SMartin Schwidefsky .start = c_start, 226395d31d4SMartin Schwidefsky .next = c_next, 227395d31d4SMartin Schwidefsky .stop = c_stop, 228395d31d4SMartin Schwidefsky .show = show_cpuinfo, 229395d31d4SMartin Schwidefsky }; 2306b73044bSMartin Schwidefsky 2316b73044bSMartin Schwidefsky int s390_isolate_bp(void) 2326b73044bSMartin Schwidefsky { 2336b73044bSMartin Schwidefsky if (!test_facility(82)) 2346b73044bSMartin Schwidefsky return -EOPNOTSUPP; 2356b73044bSMartin Schwidefsky set_thread_flag(TIF_ISOLATE_BP); 2366b73044bSMartin Schwidefsky return 0; 2376b73044bSMartin Schwidefsky } 2386b73044bSMartin Schwidefsky EXPORT_SYMBOL(s390_isolate_bp); 2396b73044bSMartin Schwidefsky 2406b73044bSMartin Schwidefsky int s390_isolate_bp_guest(void) 2416b73044bSMartin Schwidefsky { 2426b73044bSMartin Schwidefsky if (!test_facility(82)) 2436b73044bSMartin Schwidefsky return -EOPNOTSUPP; 2446b73044bSMartin Schwidefsky set_thread_flag(TIF_ISOLATE_BP_GUEST); 2456b73044bSMartin Schwidefsky return 0; 2466b73044bSMartin Schwidefsky } 2476b73044bSMartin Schwidefsky EXPORT_SYMBOL(s390_isolate_bp_guest); 248