at v2.6.20 353 lines 9.9 kB view raw
1/* 2 * drivers/s390/sysinfo.c 3 * 4 * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation 5 * Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com) 6 */ 7 8#include <linux/kernel.h> 9#include <linux/mm.h> 10#include <linux/proc_fs.h> 11#include <linux/init.h> 12#include <asm/ebcdic.h> 13 14struct sysinfo_1_1_1 { 15 char reserved_0[32]; 16 char manufacturer[16]; 17 char type[4]; 18 char reserved_1[12]; 19 char model_capacity[16]; 20 char sequence[16]; 21 char plant[4]; 22 char model[16]; 23}; 24 25struct sysinfo_1_2_1 { 26 char reserved_0[80]; 27 char sequence[16]; 28 char plant[4]; 29 char reserved_1[2]; 30 unsigned short cpu_address; 31}; 32 33struct sysinfo_1_2_2 { 34 char format; 35 char reserved_0[1]; 36 unsigned short acc_offset; 37 char reserved_1[24]; 38 unsigned int secondary_capability; 39 unsigned int capability; 40 unsigned short cpus_total; 41 unsigned short cpus_configured; 42 unsigned short cpus_standby; 43 unsigned short cpus_reserved; 44 unsigned short adjustment[0]; 45}; 46 47struct sysinfo_1_2_2_extension { 48 unsigned int alt_capability; 49 unsigned short alt_adjustment[0]; 50}; 51 52struct sysinfo_2_2_1 { 53 char reserved_0[80]; 54 char sequence[16]; 55 char plant[4]; 56 unsigned short cpu_id; 57 unsigned short cpu_address; 58}; 59 60struct sysinfo_2_2_2 { 61 char reserved_0[32]; 62 unsigned short lpar_number; 63 char reserved_1; 64 unsigned char characteristics; 65 unsigned short cpus_total; 66 unsigned short cpus_configured; 67 unsigned short cpus_standby; 68 unsigned short cpus_reserved; 69 char name[8]; 70 unsigned int caf; 71 char reserved_2[16]; 72 unsigned short cpus_dedicated; 73 unsigned short cpus_shared; 74}; 75 76#define LPAR_CHAR_DEDICATED (1 << 7) 77#define LPAR_CHAR_SHARED (1 << 6) 78#define LPAR_CHAR_LIMITED (1 << 5) 79 80struct sysinfo_3_2_2 { 81 char reserved_0[31]; 82 unsigned char count; 83 struct { 84 char reserved_0[4]; 85 unsigned short cpus_total; 86 unsigned short cpus_configured; 87 unsigned short cpus_standby; 88 unsigned short cpus_reserved; 89 char name[8]; 90 unsigned int caf; 91 char cpi[16]; 92 char reserved_1[24]; 93 94 } vm[8]; 95}; 96 97static inline int stsi(void *sysinfo, int fc, int sel1, int sel2) 98{ 99 register int r0 asm("0") = (fc << 28) | sel1; 100 register int r1 asm("1") = sel2; 101 102 asm volatile( 103 " stsi 0(%2)\n" 104 "0: jz 2f\n" 105 "1: lhi %0,%3\n" 106 "2:\n" 107 EX_TABLE(0b,1b) 108 : "+d" (r0) : "d" (r1), "a" (sysinfo), "K" (-ENOSYS) 109 : "cc", "memory" ); 110 return r0; 111} 112 113static inline int stsi_0(void) 114{ 115 int rc = stsi (NULL, 0, 0, 0); 116 return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28); 117} 118 119static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len) 120{ 121 if (stsi(info, 1, 1, 1) == -ENOSYS) 122 return len; 123 124 EBCASC(info->manufacturer, sizeof(info->manufacturer)); 125 EBCASC(info->type, sizeof(info->type)); 126 EBCASC(info->model, sizeof(info->model)); 127 EBCASC(info->sequence, sizeof(info->sequence)); 128 EBCASC(info->plant, sizeof(info->plant)); 129 EBCASC(info->model_capacity, sizeof(info->model_capacity)); 130 len += sprintf(page + len, "Manufacturer: %-16.16s\n", 131 info->manufacturer); 132 len += sprintf(page + len, "Type: %-4.4s\n", 133 info->type); 134 if (info->model[0] != '\0') 135 /* 136 * Sigh: the model field has been renamed with System z9 137 * to model_capacity and a new model field has been added 138 * after the plant field. To avoid confusing older programs 139 * the "Model:" prints "model_capacity model" or just 140 * "model_capacity" if the model string is empty . 141 */ 142 len += sprintf(page + len, 143 "Model: %-16.16s %-16.16s\n", 144 info->model_capacity, info->model); 145 else 146 len += sprintf(page + len, "Model: %-16.16s\n", 147 info->model_capacity); 148 len += sprintf(page + len, "Sequence Code: %-16.16s\n", 149 info->sequence); 150 len += sprintf(page + len, "Plant: %-4.4s\n", 151 info->plant); 152 len += sprintf(page + len, "Model Capacity: %-16.16s\n", 153 info->model_capacity); 154 return len; 155} 156 157#if 0 /* Currently unused */ 158static int stsi_1_2_1(struct sysinfo_1_2_1 *info, char *page, int len) 159{ 160 if (stsi(info, 1, 2, 1) == -ENOSYS) 161 return len; 162 163 len += sprintf(page + len, "\n"); 164 EBCASC(info->sequence, sizeof(info->sequence)); 165 EBCASC(info->plant, sizeof(info->plant)); 166 len += sprintf(page + len, "Sequence Code of CPU: %-16.16s\n", 167 info->sequence); 168 len += sprintf(page + len, "Plant of CPU: %-16.16s\n", 169 info->plant); 170 return len; 171} 172#endif 173 174static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len) 175{ 176 struct sysinfo_1_2_2_extension *ext; 177 int i; 178 179 if (stsi(info, 1, 2, 2) == -ENOSYS) 180 return len; 181 ext = (struct sysinfo_1_2_2_extension *) 182 ((unsigned long) info + info->acc_offset); 183 184 len += sprintf(page + len, "\n"); 185 len += sprintf(page + len, "CPUs Total: %d\n", 186 info->cpus_total); 187 len += sprintf(page + len, "CPUs Configured: %d\n", 188 info->cpus_configured); 189 len += sprintf(page + len, "CPUs Standby: %d\n", 190 info->cpus_standby); 191 len += sprintf(page + len, "CPUs Reserved: %d\n", 192 info->cpus_reserved); 193 194 if (info->format == 1) { 195 /* 196 * Sigh 2. According to the specification the alternate 197 * capability field is a 32 bit floating point number 198 * if the higher order 8 bits are not zero. Printing 199 * a floating point number in the kernel is a no-no, 200 * always print the number as 32 bit unsigned integer. 201 * The user-space needs to know about the stange 202 * encoding of the alternate cpu capability. 203 */ 204 len += sprintf(page + len, "Capability: %u %u\n", 205 info->capability, ext->alt_capability); 206 for (i = 2; i <= info->cpus_total; i++) 207 len += sprintf(page + len, 208 "Adjustment %02d-way: %u %u\n", 209 i, info->adjustment[i-2], 210 ext->alt_adjustment[i-2]); 211 212 } else { 213 len += sprintf(page + len, "Capability: %u\n", 214 info->capability); 215 for (i = 2; i <= info->cpus_total; i++) 216 len += sprintf(page + len, 217 "Adjustment %02d-way: %u\n", 218 i, info->adjustment[i-2]); 219 } 220 221 if (info->secondary_capability != 0) 222 len += sprintf(page + len, "Secondary Capability: %d\n", 223 info->secondary_capability); 224 225 return len; 226} 227 228#if 0 /* Currently unused */ 229static int stsi_2_2_1(struct sysinfo_2_2_1 *info, char *page, int len) 230{ 231 if (stsi(info, 2, 2, 1) == -ENOSYS) 232 return len; 233 234 len += sprintf(page + len, "\n"); 235 EBCASC (info->sequence, sizeof(info->sequence)); 236 EBCASC (info->plant, sizeof(info->plant)); 237 len += sprintf(page + len, "Sequence Code of logical CPU: %-16.16s\n", 238 info->sequence); 239 len += sprintf(page + len, "Plant of logical CPU: %-16.16s\n", 240 info->plant); 241 return len; 242} 243#endif 244 245static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len) 246{ 247 if (stsi(info, 2, 2, 2) == -ENOSYS) 248 return len; 249 250 EBCASC (info->name, sizeof(info->name)); 251 252 len += sprintf(page + len, "\n"); 253 len += sprintf(page + len, "LPAR Number: %d\n", 254 info->lpar_number); 255 256 len += sprintf(page + len, "LPAR Characteristics: "); 257 if (info->characteristics & LPAR_CHAR_DEDICATED) 258 len += sprintf(page + len, "Dedicated "); 259 if (info->characteristics & LPAR_CHAR_SHARED) 260 len += sprintf(page + len, "Shared "); 261 if (info->characteristics & LPAR_CHAR_LIMITED) 262 len += sprintf(page + len, "Limited "); 263 len += sprintf(page + len, "\n"); 264 265 len += sprintf(page + len, "LPAR Name: %-8.8s\n", 266 info->name); 267 268 len += sprintf(page + len, "LPAR Adjustment: %d\n", 269 info->caf); 270 271 len += sprintf(page + len, "LPAR CPUs Total: %d\n", 272 info->cpus_total); 273 len += sprintf(page + len, "LPAR CPUs Configured: %d\n", 274 info->cpus_configured); 275 len += sprintf(page + len, "LPAR CPUs Standby: %d\n", 276 info->cpus_standby); 277 len += sprintf(page + len, "LPAR CPUs Reserved: %d\n", 278 info->cpus_reserved); 279 len += sprintf(page + len, "LPAR CPUs Dedicated: %d\n", 280 info->cpus_dedicated); 281 len += sprintf(page + len, "LPAR CPUs Shared: %d\n", 282 info->cpus_shared); 283 return len; 284} 285 286static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len) 287{ 288 int i; 289 290 if (stsi(info, 3, 2, 2) == -ENOSYS) 291 return len; 292 for (i = 0; i < info->count; i++) { 293 EBCASC (info->vm[i].name, sizeof(info->vm[i].name)); 294 EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi)); 295 len += sprintf(page + len, "\n"); 296 len += sprintf(page + len, "VM%02d Name: %-8.8s\n", 297 i, info->vm[i].name); 298 len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n", 299 i, info->vm[i].cpi); 300 301 len += sprintf(page + len, "VM%02d Adjustment: %d\n", 302 i, info->vm[i].caf); 303 304 len += sprintf(page + len, "VM%02d CPUs Total: %d\n", 305 i, info->vm[i].cpus_total); 306 len += sprintf(page + len, "VM%02d CPUs Configured: %d\n", 307 i, info->vm[i].cpus_configured); 308 len += sprintf(page + len, "VM%02d CPUs Standby: %d\n", 309 i, info->vm[i].cpus_standby); 310 len += sprintf(page + len, "VM%02d CPUs Reserved: %d\n", 311 i, info->vm[i].cpus_reserved); 312 } 313 return len; 314} 315 316 317static int proc_read_sysinfo(char *page, char **start, 318 off_t off, int count, 319 int *eof, void *data) 320{ 321 unsigned long info = get_zeroed_page (GFP_KERNEL); 322 int level, len; 323 324 if (!info) 325 return 0; 326 327 len = 0; 328 level = stsi_0(); 329 if (level >= 1) 330 len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len); 331 332 if (level >= 1) 333 len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len); 334 335 if (level >= 2) 336 len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len); 337 338 if (level >= 3) 339 len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len); 340 341 free_page (info); 342 return len; 343} 344 345static __init int create_proc_sysinfo(void) 346{ 347 create_proc_read_entry("sysinfo", 0444, NULL, 348 proc_read_sysinfo, NULL); 349 return 0; 350} 351 352__initcall(create_proc_sysinfo); 353