^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright IBM Corp. 2001, 2009
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Author(s): Ulrich Weigand <Ulrich.Weigand@de.ibm.com>,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Martin Schwidefsky <schwidefsky@de.ibm.com>,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/debugfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/proc_fs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/seq_file.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/ebcdic.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/debug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/sysinfo.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/cpcmd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/topology.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/fpu/api.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) int topology_max_mnest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static inline int __stsi(void *sysinfo, int fc, int sel1, int sel2, int *lvl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) register int r0 asm("0") = (fc << 28) | sel1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) register int r1 asm("1") = sel2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) int rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) " stsi 0(%3)\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) "0: jz 2f\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) "1: lhi %1,%4\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) "2:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) EX_TABLE(0b, 1b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) : "+d" (r0), "+d" (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) : "d" (r1), "a" (sysinfo), "K" (-EOPNOTSUPP)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) : "cc", "memory");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) *lvl = ((unsigned int) r0) >> 28;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * stsi - store system information
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * Returns the current configuration level if function code 0 was specified.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * Otherwise returns 0 on success or a negative value on error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) int stsi(void *sysinfo, int fc, int sel1, int sel2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int lvl, rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) rc = __stsi(sysinfo, fc, sel1, sel2, &lvl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (rc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return fc ? 0 : lvl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) EXPORT_SYMBOL(stsi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) #ifdef CONFIG_PROC_FS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static bool convert_ext_name(unsigned char encoding, char *name, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) switch (encoding) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) case 1: /* EBCDIC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) EBCASC(name, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) case 2: /* UTF-8 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (stsi(info, 1, 1, 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) EBCASC(info->manufacturer, sizeof(info->manufacturer));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) EBCASC(info->type, sizeof(info->type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) EBCASC(info->model, sizeof(info->model));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) EBCASC(info->sequence, sizeof(info->sequence));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) EBCASC(info->plant, sizeof(info->plant));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) EBCASC(info->model_capacity, sizeof(info->model_capacity));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) seq_printf(m, "Manufacturer: %-16.16s\n", info->manufacturer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) seq_printf(m, "Type: %-4.4s\n", info->type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (info->lic)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) seq_printf(m, "LIC Identifier: %016lx\n", info->lic);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * Sigh: the model field has been renamed with System z9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * to model_capacity and a new model field has been added
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * after the plant field. To avoid confusing older programs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) * the "Model:" prints "model_capacity model" or just
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * "model_capacity" if the model string is empty .
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) seq_printf(m, "Model: %-16.16s", info->model_capacity);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) if (info->model[0] != '\0')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) seq_printf(m, " %-16.16s", info->model);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) seq_putc(m, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) seq_printf(m, "Sequence Code: %-16.16s\n", info->sequence);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) seq_printf(m, "Plant: %-4.4s\n", info->plant);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) seq_printf(m, "Model Capacity: %-16.16s %08u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) info->model_capacity, info->model_cap_rating);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) if (info->model_perm_cap_rating)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) seq_printf(m, "Model Perm. Capacity: %-16.16s %08u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) info->model_perm_cap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) info->model_perm_cap_rating);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (info->model_temp_cap_rating)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) seq_printf(m, "Model Temp. Capacity: %-16.16s %08u\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) info->model_temp_cap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) info->model_temp_cap_rating);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) if (info->ncr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) seq_printf(m, "Nominal Cap. Rating: %08u\n", info->ncr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (info->npr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) seq_printf(m, "Nominal Perm. Rating: %08u\n", info->npr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (info->ntr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) seq_printf(m, "Nominal Temp. Rating: %08u\n", info->ntr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (info->cai) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) seq_printf(m, "Capacity Adj. Ind.: %d\n", info->cai);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) seq_printf(m, "Capacity Ch. Reason: %d\n", info->ccr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) seq_printf(m, "Capacity Transient: %d\n", info->t);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) if (info->p) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) for (i = 1; i <= ARRAY_SIZE(info->typepct); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) seq_printf(m, "Type %d Percentage: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) i, info->typepct[i - 1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) static void stsi_15_1_x(struct seq_file *m, struct sysinfo_15_1_x *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) seq_putc(m, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (!MACHINE_HAS_TOPOLOGY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (stsi(info, 15, 1, topology_max_mnest))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) seq_printf(m, "CPU Topology HW: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) for (i = 0; i < TOPOLOGY_NR_MAG; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) seq_printf(m, " %d", info->mag[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) seq_putc(m, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #ifdef CONFIG_SCHED_TOPOLOGY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) store_topology(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) seq_printf(m, "CPU Topology SW: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) for (i = 0; i < TOPOLOGY_NR_MAG; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) seq_printf(m, " %d", info->mag[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) seq_putc(m, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static void stsi_1_2_2(struct seq_file *m, struct sysinfo_1_2_2 *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) struct sysinfo_1_2_2_extension *ext;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (stsi(info, 1, 2, 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) ext = (struct sysinfo_1_2_2_extension *)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) ((unsigned long) info + info->acc_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) seq_printf(m, "CPUs Total: %d\n", info->cpus_total);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) seq_printf(m, "CPUs Configured: %d\n", info->cpus_configured);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) seq_printf(m, "CPUs Standby: %d\n", info->cpus_standby);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) seq_printf(m, "CPUs Reserved: %d\n", info->cpus_reserved);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (info->mt_installed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) seq_printf(m, "CPUs G-MTID: %d\n", info->mt_gtid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) seq_printf(m, "CPUs S-MTID: %d\n", info->mt_stid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) * Sigh 2. According to the specification the alternate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) * capability field is a 32 bit floating point number
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) * if the higher order 8 bits are not zero. Printing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) * a floating point number in the kernel is a no-no,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) * always print the number as 32 bit unsigned integer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * The user-space needs to know about the strange
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * encoding of the alternate cpu capability.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) seq_printf(m, "Capability: %u", info->capability);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (info->format == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) seq_printf(m, " %u", ext->alt_capability);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) seq_putc(m, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (info->nominal_cap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) seq_printf(m, "Nominal Capability: %d\n", info->nominal_cap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) if (info->secondary_cap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) seq_printf(m, "Secondary Capability: %d\n", info->secondary_cap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) for (i = 2; i <= info->cpus_total; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) seq_printf(m, "Adjustment %02d-way: %u",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) i, info->adjustment[i-2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (info->format == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) seq_printf(m, " %u", ext->alt_adjustment[i-2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) seq_putc(m, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (stsi(info, 2, 2, 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) EBCASC(info->name, sizeof(info->name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) seq_putc(m, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) seq_printf(m, "LPAR Number: %d\n", info->lpar_number);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) seq_printf(m, "LPAR Characteristics: ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (info->characteristics & LPAR_CHAR_DEDICATED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) seq_printf(m, "Dedicated ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (info->characteristics & LPAR_CHAR_SHARED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) seq_printf(m, "Shared ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (info->characteristics & LPAR_CHAR_LIMITED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) seq_printf(m, "Limited ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) seq_putc(m, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) seq_printf(m, "LPAR Name: %-8.8s\n", info->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) seq_printf(m, "LPAR Adjustment: %d\n", info->caf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) seq_printf(m, "LPAR CPUs Total: %d\n", info->cpus_total);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) seq_printf(m, "LPAR CPUs Configured: %d\n", info->cpus_configured);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) seq_printf(m, "LPAR CPUs Standby: %d\n", info->cpus_standby);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) seq_printf(m, "LPAR CPUs Reserved: %d\n", info->cpus_reserved);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) seq_printf(m, "LPAR CPUs Dedicated: %d\n", info->cpus_dedicated);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) seq_printf(m, "LPAR CPUs Shared: %d\n", info->cpus_shared);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) if (info->mt_installed) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) seq_printf(m, "LPAR CPUs G-MTID: %d\n", info->mt_gtid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) seq_printf(m, "LPAR CPUs S-MTID: %d\n", info->mt_stid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) seq_printf(m, "LPAR CPUs PS-MTID: %d\n", info->mt_psmtid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (convert_ext_name(info->vsne, info->ext_name, sizeof(info->ext_name))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) seq_printf(m, "LPAR Extended Name: %-.256s\n", info->ext_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) seq_printf(m, "LPAR UUID: %pUb\n", &info->uuid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) static void print_ext_name(struct seq_file *m, int lvl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) struct sysinfo_3_2_2 *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) size_t len = sizeof(info->ext_names[lvl]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) if (!convert_ext_name(info->vm[lvl].evmne, info->ext_names[lvl], len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) seq_printf(m, "VM%02d Extended Name: %-.256s\n", lvl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) info->ext_names[lvl]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) static void print_uuid(struct seq_file *m, int i, struct sysinfo_3_2_2 *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (uuid_is_null(&info->vm[i].uuid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) seq_printf(m, "VM%02d UUID: %pUb\n", i, &info->vm[i].uuid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) static void stsi_3_2_2(struct seq_file *m, struct sysinfo_3_2_2 *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (stsi(info, 3, 2, 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) for (i = 0; i < info->count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) EBCASC(info->vm[i].name, sizeof(info->vm[i].name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) EBCASC(info->vm[i].cpi, sizeof(info->vm[i].cpi));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) seq_putc(m, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) seq_printf(m, "VM%02d Name: %-8.8s\n", i, info->vm[i].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) seq_printf(m, "VM%02d Control Program: %-16.16s\n", i, info->vm[i].cpi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) seq_printf(m, "VM%02d Adjustment: %d\n", i, info->vm[i].caf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) seq_printf(m, "VM%02d CPUs Total: %d\n", i, info->vm[i].cpus_total);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) seq_printf(m, "VM%02d CPUs Configured: %d\n", i, info->vm[i].cpus_configured);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) seq_printf(m, "VM%02d CPUs Standby: %d\n", i, info->vm[i].cpus_standby);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) seq_printf(m, "VM%02d CPUs Reserved: %d\n", i, info->vm[i].cpus_reserved);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) print_ext_name(m, i, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) print_uuid(m, i, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static int sysinfo_show(struct seq_file *m, void *v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) void *info = (void *)get_zeroed_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) int level;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) level = stsi(NULL, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if (level >= 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) stsi_1_1_1(m, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (level >= 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) stsi_15_1_x(m, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) if (level >= 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) stsi_1_2_2(m, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) if (level >= 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) stsi_2_2_2(m, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) if (level >= 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) stsi_3_2_2(m, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) free_page((unsigned long)info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static int __init sysinfo_create_proc(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) proc_create_single("sysinfo", 0444, NULL, sysinfo_show);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) device_initcall(sysinfo_create_proc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) #endif /* CONFIG_PROC_FS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) * Service levels interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) static DECLARE_RWSEM(service_level_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) static LIST_HEAD(service_level_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) int register_service_level(struct service_level *slr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) struct service_level *ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) down_write(&service_level_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) list_for_each_entry(ptr, &service_level_list, list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) if (ptr == slr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) up_write(&service_level_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) list_add_tail(&slr->list, &service_level_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) up_write(&service_level_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) EXPORT_SYMBOL(register_service_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) int unregister_service_level(struct service_level *slr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) struct service_level *ptr, *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) int rc = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) down_write(&service_level_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) list_for_each_entry_safe(ptr, next, &service_level_list, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) if (ptr != slr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) list_del(&ptr->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) up_write(&service_level_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) EXPORT_SYMBOL(unregister_service_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) static void *service_level_start(struct seq_file *m, loff_t *pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) down_read(&service_level_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) return seq_list_start(&service_level_list, *pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) static void *service_level_next(struct seq_file *m, void *p, loff_t *pos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) return seq_list_next(p, &service_level_list, pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) static void service_level_stop(struct seq_file *m, void *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) up_read(&service_level_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) static int service_level_show(struct seq_file *m, void *p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) struct service_level *slr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) slr = list_entry(p, struct service_level, list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) slr->seq_print(m, slr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) static const struct seq_operations service_level_seq_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) .start = service_level_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) .next = service_level_next,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) .stop = service_level_stop,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) .show = service_level_show
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) static void service_level_vm_print(struct seq_file *m,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) struct service_level *slr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) char *query_buffer, *str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) query_buffer = kmalloc(1024, GFP_KERNEL | GFP_DMA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) if (!query_buffer)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) cpcmd("QUERY CPLEVEL", query_buffer, 1024, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) str = strchr(query_buffer, '\n');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) if (str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) *str = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) seq_printf(m, "VM: %s\n", query_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) kfree(query_buffer);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) static struct service_level service_level_vm = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) .seq_print = service_level_vm_print
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) static __init int create_proc_service_level(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) proc_create_seq("service_levels", 0, NULL, &service_level_seq_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (MACHINE_IS_VM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) register_service_level(&service_level_vm);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) subsys_initcall(create_proc_service_level);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) * CPU capability might have changed. Therefore recalculate loops_per_jiffy.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) void s390_adjust_jiffies(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) struct sysinfo_1_2_2 *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) unsigned long capability;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) struct kernel_fpu fpu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) info = (void *) get_zeroed_page(GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (stsi(info, 1, 2, 2) == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) * Major sigh. The cpu capability encoding is "special".
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) * If the first 9 bits of info->capability are 0 then it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) * is a 32 bit unsigned integer in the range 0 .. 2^23.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) * If the first 9 bits are != 0 then it is a 32 bit float.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) * In addition a lower value indicates a proportionally
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) * higher cpu capacity. Bogomips are the other way round.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * To get to a halfway suitable number we divide 1e7
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) * by the cpu capability number. Yes, that means a floating
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) * point division ..
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) kernel_fpu_begin(&fpu, KERNEL_FPR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) asm volatile(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) " sfpc %3\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) " l %0,%1\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) " tmlh %0,0xff80\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) " jnz 0f\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) " cefbr %%f2,%0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) " j 1f\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) "0: le %%f2,%1\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) "1: cefbr %%f0,%2\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) " debr %%f0,%%f2\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) " cgebr %0,5,%%f0\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) : "=&d" (capability)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) : "Q" (info->capability), "d" (10000000), "d" (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) : "cc"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) );
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) kernel_fpu_end(&fpu, KERNEL_FPR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) * Really old machine without stsi block for basic
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) * cpu information. Report 42.0 bogomips.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) capability = 42;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) loops_per_jiffy = capability * (500000/HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) free_page((unsigned long) info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) * calibrate the delay loop
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) void calibrate_delay(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) s390_adjust_jiffies();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) /* Print the good old Bogomips line .. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) printk(KERN_DEBUG "Calibrating delay loop (skipped)... "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) (loops_per_jiffy/(5000/HZ)) % 100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) #ifdef CONFIG_DEBUG_FS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) #define STSI_FILE(fc, s1, s2) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) static int stsi_open_##fc##_##s1##_##s2(struct inode *inode, struct file *file)\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) file->private_data = (void *) get_zeroed_page(GFP_KERNEL); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) if (!file->private_data) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) return -ENOMEM; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) if (stsi(file->private_data, fc, s1, s2)) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) free_page((unsigned long)file->private_data); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) file->private_data = NULL; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) return -EACCES; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return nonseekable_open(inode, file); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) static const struct file_operations stsi_##fc##_##s1##_##s2##_fs_ops = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) .open = stsi_open_##fc##_##s1##_##s2, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) .release = stsi_release, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) .read = stsi_read, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) .llseek = no_llseek, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) static int stsi_release(struct inode *inode, struct file *file)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) free_page((unsigned long)file->private_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) static ssize_t stsi_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) return simple_read_from_buffer(buf, size, ppos, file->private_data, PAGE_SIZE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) STSI_FILE( 1, 1, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) STSI_FILE( 1, 2, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) STSI_FILE( 1, 2, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) STSI_FILE( 2, 2, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) STSI_FILE( 2, 2, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) STSI_FILE( 3, 2, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) STSI_FILE(15, 1, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) STSI_FILE(15, 1, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) STSI_FILE(15, 1, 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) STSI_FILE(15, 1, 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) STSI_FILE(15, 1, 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) struct stsi_file {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) const struct file_operations *fops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) static struct stsi_file stsi_file[] __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) {.fops = &stsi_1_1_1_fs_ops, .name = "1_1_1"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) {.fops = &stsi_1_2_1_fs_ops, .name = "1_2_1"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) {.fops = &stsi_1_2_2_fs_ops, .name = "1_2_2"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) {.fops = &stsi_2_2_1_fs_ops, .name = "2_2_1"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) {.fops = &stsi_2_2_2_fs_ops, .name = "2_2_2"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) {.fops = &stsi_3_2_2_fs_ops, .name = "3_2_2"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) {.fops = &stsi_15_1_2_fs_ops, .name = "15_1_2"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) {.fops = &stsi_15_1_3_fs_ops, .name = "15_1_3"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) {.fops = &stsi_15_1_4_fs_ops, .name = "15_1_4"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) {.fops = &stsi_15_1_5_fs_ops, .name = "15_1_5"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) {.fops = &stsi_15_1_6_fs_ops, .name = "15_1_6"},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) static u8 stsi_0_0_0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) static __init int stsi_init_debugfs(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) struct dentry *stsi_root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) struct stsi_file *sf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) int lvl, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) stsi_root = debugfs_create_dir("stsi", arch_debugfs_dir);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) lvl = stsi(NULL, 0, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) if (lvl > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) stsi_0_0_0 = lvl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) debugfs_create_u8("0_0_0", 0400, stsi_root, &stsi_0_0_0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) for (i = 0; i < ARRAY_SIZE(stsi_file); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) sf = &stsi_file[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) debugfs_create_file(sf->name, 0400, stsi_root, NULL, sf->fops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) if (IS_ENABLED(CONFIG_SCHED_TOPOLOGY) && MACHINE_HAS_TOPOLOGY) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) char link_to[10];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) sprintf(link_to, "15_1_%d", topology_mnest_limit());
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) debugfs_create_symlink("topology", stsi_root, link_to);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) device_initcall(stsi_init_debugfs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) #endif /* CONFIG_DEBUG_FS */