1 /* 2 * salinfo.c 3 * 4 * Creates entries in /proc/sal for various system features. 5 * 6 * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. 7 * Copyright (c) 2003 Hewlett-Packard Co 8 * Bjorn Helgaas <bjorn.helgaas@hp.com> 9 * 10 * 10/30/2001 jbarnes@sgi.com copied much of Stephane's palinfo 11 * code to create this file 12 * Oct 23 2003 kaos@sgi.com 13 * Replace IPI with set_cpus_allowed() to read a record from the required cpu. 14 * Redesign salinfo log processing to separate interrupt and user space 15 * contexts. 16 * Cache the record across multi-block reads from user space. 17 * Support > 64 cpus. 18 * Delete module_exit and MOD_INC/DEC_COUNT, salinfo cannot be a module. 19 * 20 * Jan 28 2004 kaos@sgi.com 21 * Periodically check for outstanding MCA or INIT records. 22 * 23 * Dec 5 2004 kaos@sgi.com 24 * Standardize which records are cleared automatically. 25 * 26 * Aug 18 2005 kaos@sgi.com 27 * mca.c may not pass a buffer, a NULL buffer just indicates that a new 28 * record is available in SAL. 29 * Replace some NR_CPUS by cpus_online, for hotplug cpu. 30 */ 31 32 #include <linux/types.h> 33 #include <linux/proc_fs.h> 34 #include <linux/module.h> 35 #include <linux/smp.h> 36 #include <linux/smp_lock.h> 37 #include <linux/timer.h> 38 #include <linux/vmalloc.h> 39 40 #include <asm/semaphore.h> 41 #include <asm/sal.h> 42 #include <asm/uaccess.h> 43 44 MODULE_AUTHOR("Jesse Barnes <jbarnes@sgi.com>"); 45 MODULE_DESCRIPTION("/proc interface to IA-64 SAL features"); 46 MODULE_LICENSE("GPL"); 47 48 static int salinfo_read(char *page, char **start, off_t off, int count, int *eof, void *data); 49 50 typedef struct { 51 const char *name; /* name of the proc entry */ 52 unsigned long feature; /* feature bit */ 53 struct proc_dir_entry *entry; /* registered entry (removal) */ 54 } salinfo_entry_t; 55 56 /* 57 * List {name,feature} pairs for every entry in /proc/sal/<feature> 58 * that this module exports 59 */ 60 static salinfo_entry_t salinfo_entries[]={ 61 { "bus_lock", IA64_SAL_PLATFORM_FEATURE_BUS_LOCK, }, 62 { "irq_redirection", IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT, }, 63 { "ipi_redirection", IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT, }, 64 { "itc_drift", IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT, }, 65 }; 66 67 #define NR_SALINFO_ENTRIES ARRAY_SIZE(salinfo_entries) 68 69 static char *salinfo_log_name[] = { 70 "mca", 71 "init", 72 "cmc", 73 "cpe", 74 }; 75 76 static struct proc_dir_entry *salinfo_proc_entries[ 77 ARRAY_SIZE(salinfo_entries) + /* /proc/sal/bus_lock */ 78 ARRAY_SIZE(salinfo_log_name) + /* /proc/sal/{mca,...} */ 79 (2 * ARRAY_SIZE(salinfo_log_name)) + /* /proc/sal/mca/{event,data} */ 80 1]; /* /proc/sal */ 81 82 /* Some records we get ourselves, some are accessed as saved data in buffers 83 * that are owned by mca.c. 84 */ 85 struct salinfo_data_saved { 86 u8* buffer; 87 u64 size; 88 u64 id; 89 int cpu; 90 }; 91 92 /* State transitions. Actions are :- 93 * Write "read <cpunum>" to the data file. 94 * Write "clear <cpunum>" to the data file. 95 * Write "oemdata <cpunum> <offset> to the data file. 96 * Read from the data file. 97 * Close the data file. 98 * 99 * Start state is NO_DATA. 100 * 101 * NO_DATA 102 * write "read <cpunum>" -> NO_DATA or LOG_RECORD. 103 * write "clear <cpunum>" -> NO_DATA or LOG_RECORD. 104 * write "oemdata <cpunum> <offset> -> return -EINVAL. 105 * read data -> return EOF. 106 * close -> unchanged. Free record areas. 107 * 108 * LOG_RECORD 109 * write "read <cpunum>" -> NO_DATA or LOG_RECORD. 110 * write "clear <cpunum>" -> NO_DATA or LOG_RECORD. 111 * write "oemdata <cpunum> <offset> -> format the oem data, goto OEMDATA. 112 * read data -> return the INIT/MCA/CMC/CPE record. 113 * close -> unchanged. Keep record areas. 114 * 115 * OEMDATA 116 * write "read <cpunum>" -> NO_DATA or LOG_RECORD. 117 * write "clear <cpunum>" -> NO_DATA or LOG_RECORD. 118 * write "oemdata <cpunum> <offset> -> format the oem data, goto OEMDATA. 119 * read data -> return the formatted oemdata. 120 * close -> unchanged. Keep record areas. 121 * 122 * Closing the data file does not change the state. This allows shell scripts 123 * to manipulate salinfo data, each shell redirection opens the file, does one 124 * action then closes it again. The record areas are only freed at close when 125 * the state is NO_DATA. 126 */ 127 enum salinfo_state { 128 STATE_NO_DATA, 129 STATE_LOG_RECORD, 130 STATE_OEMDATA, 131 }; 132 133 struct salinfo_data { 134 volatile cpumask_t cpu_event; /* which cpus have outstanding events */ 135 struct semaphore sem; /* count of cpus with outstanding events (bits set in cpu_event) */ 136 u8 *log_buffer; 137 u64 log_size; 138 u8 *oemdata; /* decoded oem data */ 139 u64 oemdata_size; 140 int open; /* single-open to prevent races */ 141 u8 type; 142 u8 saved_num; /* using a saved record? */ 143 enum salinfo_state state :8; /* processing state */ 144 u8 padding; 145 int cpu_check; /* next CPU to check */ 146 struct salinfo_data_saved data_saved[5];/* save last 5 records from mca.c, must be < 255 */ 147 }; 148 149 static struct salinfo_data salinfo_data[ARRAY_SIZE(salinfo_log_name)]; 150 151 static DEFINE_SPINLOCK(data_lock); 152 static DEFINE_SPINLOCK(data_saved_lock); 153 154 /** salinfo_platform_oemdata - optional callback to decode oemdata from an error 155 * record. 156 * @sect_header: pointer to the start of the section to decode. 157 * @oemdata: returns vmalloc area containing the decded output. 158 * @oemdata_size: returns length of decoded output (strlen). 159 * 160 * Description: If user space asks for oem data to be decoded by the kernel 161 * and/or prom and the platform has set salinfo_platform_oemdata to the address 162 * of a platform specific routine then call that routine. salinfo_platform_oemdata 163 * vmalloc's and formats its output area, returning the address of the text 164 * and its strlen. Returns 0 for success, -ve for error. The callback is 165 * invoked on the cpu that generated the error record. 166 */ 167 int (*salinfo_platform_oemdata)(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size); 168 169 struct salinfo_platform_oemdata_parms { 170 const u8 *efi_guid; 171 u8 **oemdata; 172 u64 *oemdata_size; 173 int ret; 174 }; 175 176 static void 177 salinfo_platform_oemdata_cpu(void *context) 178 { 179 struct salinfo_platform_oemdata_parms *parms = context; 180 parms->ret = salinfo_platform_oemdata(parms->efi_guid, parms->oemdata, parms->oemdata_size); 181 } 182 183 static void 184 shift1_data_saved (struct salinfo_data *data, int shift) 185 { 186 memcpy(data->data_saved+shift, data->data_saved+shift+1, 187 (ARRAY_SIZE(data->data_saved) - (shift+1)) * sizeof(data->data_saved[0])); 188 memset(data->data_saved + ARRAY_SIZE(data->data_saved) - 1, 0, 189 sizeof(data->data_saved[0])); 190 } 191 192 /* This routine is invoked in interrupt context. Note: mca.c enables 193 * interrupts before calling this code for CMC/CPE. MCA and INIT events are 194 * not irq safe, do not call any routines that use spinlocks, they may deadlock. 195 * MCA and INIT records are recorded, a timer event will look for any 196 * outstanding events and wake up the user space code. 197 * 198 * The buffer passed from mca.c points to the output from ia64_log_get. This is 199 * a persistent buffer but its contents can change between the interrupt and 200 * when user space processes the record. Save the record id to identify 201 * changes. If the buffer is NULL then just update the bitmap. 202 */ 203 void 204 salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe) 205 { 206 struct salinfo_data *data = salinfo_data + type; 207 struct salinfo_data_saved *data_saved; 208 unsigned long flags = 0; 209 int i; 210 int saved_size = ARRAY_SIZE(data->data_saved); 211 212 BUG_ON(type >= ARRAY_SIZE(salinfo_log_name)); 213 214 if (buffer) { 215 if (irqsafe) 216 spin_lock_irqsave(&data_saved_lock, flags); 217 for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) { 218 if (!data_saved->buffer) 219 break; 220 } 221 if (i == saved_size) { 222 if (!data->saved_num) { 223 shift1_data_saved(data, 0); 224 data_saved = data->data_saved + saved_size - 1; 225 } else 226 data_saved = NULL; 227 } 228 if (data_saved) { 229 data_saved->cpu = smp_processor_id(); 230 data_saved->id = ((sal_log_record_header_t *)buffer)->id; 231 data_saved->size = size; 232 data_saved->buffer = buffer; 233 } 234 if (irqsafe) 235 spin_unlock_irqrestore(&data_saved_lock, flags); 236 } 237 238 if (!test_and_set_bit(smp_processor_id(), &data->cpu_event)) { 239 if (irqsafe) 240 up(&data->sem); 241 } 242 } 243 244 /* Check for outstanding MCA/INIT records every minute (arbitrary) */ 245 #define SALINFO_TIMER_DELAY (60*HZ) 246 static struct timer_list salinfo_timer; 247 248 static void 249 salinfo_timeout_check(struct salinfo_data *data) 250 { 251 int i; 252 if (!data->open) 253 return; 254 for_each_online_cpu(i) { 255 if (test_bit(i, &data->cpu_event)) { 256 /* double up() is not a problem, user space will see no 257 * records for the additional "events". 258 */ 259 up(&data->sem); 260 } 261 } 262 } 263 264 static void 265 salinfo_timeout (unsigned long arg) 266 { 267 salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA); 268 salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_INIT); 269 salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY; 270 add_timer(&salinfo_timer); 271 } 272 273 static int 274 salinfo_event_open(struct inode *inode, struct file *file) 275 { 276 if (!capable(CAP_SYS_ADMIN)) 277 return -EPERM; 278 return 0; 279 } 280 281 static ssize_t 282 salinfo_event_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) 283 { 284 struct inode *inode = file->f_dentry->d_inode; 285 struct proc_dir_entry *entry = PDE(inode); 286 struct salinfo_data *data = entry->data; 287 char cmd[32]; 288 size_t size; 289 int i, n, cpu = -1; 290 291 retry: 292 if (down_trylock(&data->sem)) { 293 if (file->f_flags & O_NONBLOCK) 294 return -EAGAIN; 295 if (down_interruptible(&data->sem)) 296 return -EINTR; 297 } 298 299 n = data->cpu_check; 300 for (i = 0; i < NR_CPUS; i++) { 301 if (test_bit(n, &data->cpu_event) && cpu_online(n)) { 302 cpu = n; 303 break; 304 } 305 if (++n == NR_CPUS) 306 n = 0; 307 } 308 309 if (cpu == -1) 310 goto retry; 311 312 /* events are sticky until the user says "clear" */ 313 up(&data->sem); 314 315 /* for next read, start checking at next CPU */ 316 data->cpu_check = cpu; 317 if (++data->cpu_check == NR_CPUS) 318 data->cpu_check = 0; 319 320 snprintf(cmd, sizeof(cmd), "read %d\n", cpu); 321 322 size = strlen(cmd); 323 if (size > count) 324 size = count; 325 if (copy_to_user(buffer, cmd, size)) 326 return -EFAULT; 327 328 return size; 329 } 330 331 static struct file_operations salinfo_event_fops = { 332 .open = salinfo_event_open, 333 .read = salinfo_event_read, 334 }; 335 336 static int 337 salinfo_log_open(struct inode *inode, struct file *file) 338 { 339 struct proc_dir_entry *entry = PDE(inode); 340 struct salinfo_data *data = entry->data; 341 342 if (!capable(CAP_SYS_ADMIN)) 343 return -EPERM; 344 345 spin_lock(&data_lock); 346 if (data->open) { 347 spin_unlock(&data_lock); 348 return -EBUSY; 349 } 350 data->open = 1; 351 spin_unlock(&data_lock); 352 353 if (data->state == STATE_NO_DATA && 354 !(data->log_buffer = vmalloc(ia64_sal_get_state_info_size(data->type)))) { 355 data->open = 0; 356 return -ENOMEM; 357 } 358 359 return 0; 360 } 361 362 static int 363 salinfo_log_release(struct inode *inode, struct file *file) 364 { 365 struct proc_dir_entry *entry = PDE(inode); 366 struct salinfo_data *data = entry->data; 367 368 if (data->state == STATE_NO_DATA) { 369 vfree(data->log_buffer); 370 vfree(data->oemdata); 371 data->log_buffer = NULL; 372 data->oemdata = NULL; 373 } 374 spin_lock(&data_lock); 375 data->open = 0; 376 spin_unlock(&data_lock); 377 return 0; 378 } 379 380 static void 381 call_on_cpu(int cpu, void (*fn)(void *), void *arg) 382 { 383 cpumask_t save_cpus_allowed, new_cpus_allowed; 384 memcpy(&save_cpus_allowed, ¤t->cpus_allowed, sizeof(save_cpus_allowed)); 385 memset(&new_cpus_allowed, 0, sizeof(new_cpus_allowed)); 386 set_bit(cpu, &new_cpus_allowed); 387 set_cpus_allowed(current, new_cpus_allowed); 388 (*fn)(arg); 389 set_cpus_allowed(current, save_cpus_allowed); 390 } 391 392 static void 393 salinfo_log_read_cpu(void *context) 394 { 395 struct salinfo_data *data = context; 396 sal_log_record_header_t *rh; 397 data->log_size = ia64_sal_get_state_info(data->type, (u64 *) data->log_buffer); 398 rh = (sal_log_record_header_t *)(data->log_buffer); 399 /* Clear corrected errors as they are read from SAL */ 400 if (rh->severity == sal_log_severity_corrected) 401 ia64_sal_clear_state_info(data->type); 402 } 403 404 static void 405 salinfo_log_new_read(int cpu, struct salinfo_data *data) 406 { 407 struct salinfo_data_saved *data_saved; 408 unsigned long flags; 409 int i; 410 int saved_size = ARRAY_SIZE(data->data_saved); 411 412 data->saved_num = 0; 413 spin_lock_irqsave(&data_saved_lock, flags); 414 retry: 415 for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) { 416 if (data_saved->buffer && data_saved->cpu == cpu) { 417 sal_log_record_header_t *rh = (sal_log_record_header_t *)(data_saved->buffer); 418 data->log_size = data_saved->size; 419 memcpy(data->log_buffer, rh, data->log_size); 420 barrier(); /* id check must not be moved */ 421 if (rh->id == data_saved->id) { 422 data->saved_num = i+1; 423 break; 424 } 425 /* saved record changed by mca.c since interrupt, discard it */ 426 shift1_data_saved(data, i); 427 goto retry; 428 } 429 } 430 spin_unlock_irqrestore(&data_saved_lock, flags); 431 432 if (!data->saved_num) 433 call_on_cpu(cpu, salinfo_log_read_cpu, data); 434 if (!data->log_size) { 435 data->state = STATE_NO_DATA; 436 clear_bit(cpu, &data->cpu_event); 437 } else { 438 data->state = STATE_LOG_RECORD; 439 } 440 } 441 442 static ssize_t 443 salinfo_log_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) 444 { 445 struct inode *inode = file->f_dentry->d_inode; 446 struct proc_dir_entry *entry = PDE(inode); 447 struct salinfo_data *data = entry->data; 448 u8 *buf; 449 u64 bufsize; 450 451 if (data->state == STATE_LOG_RECORD) { 452 buf = data->log_buffer; 453 bufsize = data->log_size; 454 } else if (data->state == STATE_OEMDATA) { 455 buf = data->oemdata; 456 bufsize = data->oemdata_size; 457 } else { 458 buf = NULL; 459 bufsize = 0; 460 } 461 return simple_read_from_buffer(buffer, count, ppos, buf, bufsize); 462 } 463 464 static void 465 salinfo_log_clear_cpu(void *context) 466 { 467 struct salinfo_data *data = context; 468 ia64_sal_clear_state_info(data->type); 469 } 470 471 static int 472 salinfo_log_clear(struct salinfo_data *data, int cpu) 473 { 474 sal_log_record_header_t *rh; 475 data->state = STATE_NO_DATA; 476 if (!test_bit(cpu, &data->cpu_event)) 477 return 0; 478 down(&data->sem); 479 clear_bit(cpu, &data->cpu_event); 480 if (data->saved_num) { 481 unsigned long flags; 482 spin_lock_irqsave(&data_saved_lock, flags); 483 shift1_data_saved(data, data->saved_num - 1 ); 484 data->saved_num = 0; 485 spin_unlock_irqrestore(&data_saved_lock, flags); 486 } 487 rh = (sal_log_record_header_t *)(data->log_buffer); 488 /* Corrected errors have already been cleared from SAL */ 489 if (rh->severity != sal_log_severity_corrected) 490 call_on_cpu(cpu, salinfo_log_clear_cpu, data); 491 /* clearing a record may make a new record visible */ 492 salinfo_log_new_read(cpu, data); 493 if (data->state == STATE_LOG_RECORD && 494 !test_and_set_bit(cpu, &data->cpu_event)) 495 up(&data->sem); 496 return 0; 497 } 498 499 static ssize_t 500 salinfo_log_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) 501 { 502 struct inode *inode = file->f_dentry->d_inode; 503 struct proc_dir_entry *entry = PDE(inode); 504 struct salinfo_data *data = entry->data; 505 char cmd[32]; 506 size_t size; 507 u32 offset; 508 int cpu; 509 510 size = sizeof(cmd); 511 if (count < size) 512 size = count; 513 if (copy_from_user(cmd, buffer, size)) 514 return -EFAULT; 515 516 if (sscanf(cmd, "read %d", &cpu) == 1) { 517 salinfo_log_new_read(cpu, data); 518 } else if (sscanf(cmd, "clear %d", &cpu) == 1) { 519 int ret; 520 if ((ret = salinfo_log_clear(data, cpu))) 521 count = ret; 522 } else if (sscanf(cmd, "oemdata %d %d", &cpu, &offset) == 2) { 523 if (data->state != STATE_LOG_RECORD && data->state != STATE_OEMDATA) 524 return -EINVAL; 525 if (offset > data->log_size - sizeof(efi_guid_t)) 526 return -EINVAL; 527 data->state = STATE_OEMDATA; 528 if (salinfo_platform_oemdata) { 529 struct salinfo_platform_oemdata_parms parms = { 530 .efi_guid = data->log_buffer + offset, 531 .oemdata = &data->oemdata, 532 .oemdata_size = &data->oemdata_size 533 }; 534 call_on_cpu(cpu, salinfo_platform_oemdata_cpu, &parms); 535 if (parms.ret) 536 count = parms.ret; 537 } else 538 data->oemdata_size = 0; 539 } else 540 return -EINVAL; 541 542 return count; 543 } 544 545 static struct file_operations salinfo_data_fops = { 546 .open = salinfo_log_open, 547 .release = salinfo_log_release, 548 .read = salinfo_log_read, 549 .write = salinfo_log_write, 550 }; 551 552 static int __init 553 salinfo_init(void) 554 { 555 struct proc_dir_entry *salinfo_dir; /* /proc/sal dir entry */ 556 struct proc_dir_entry **sdir = salinfo_proc_entries; /* keeps track of every entry */ 557 struct proc_dir_entry *dir, *entry; 558 struct salinfo_data *data; 559 int i, j, online; 560 561 salinfo_dir = proc_mkdir("sal", NULL); 562 if (!salinfo_dir) 563 return 0; 564 565 for (i=0; i < NR_SALINFO_ENTRIES; i++) { 566 /* pass the feature bit in question as misc data */ 567 *sdir++ = create_proc_read_entry (salinfo_entries[i].name, 0, salinfo_dir, 568 salinfo_read, (void *)salinfo_entries[i].feature); 569 } 570 571 for (i = 0; i < ARRAY_SIZE(salinfo_log_name); i++) { 572 data = salinfo_data + i; 573 data->type = i; 574 sema_init(&data->sem, 0); 575 dir = proc_mkdir(salinfo_log_name[i], salinfo_dir); 576 if (!dir) 577 continue; 578 579 entry = create_proc_entry("event", S_IRUSR, dir); 580 if (!entry) 581 continue; 582 entry->data = data; 583 entry->proc_fops = &salinfo_event_fops; 584 *sdir++ = entry; 585 586 entry = create_proc_entry("data", S_IRUSR | S_IWUSR, dir); 587 if (!entry) 588 continue; 589 entry->data = data; 590 entry->proc_fops = &salinfo_data_fops; 591 *sdir++ = entry; 592 593 /* we missed any events before now */ 594 online = 0; 595 for_each_online_cpu(j) { 596 set_bit(j, &data->cpu_event); 597 ++online; 598 } 599 sema_init(&data->sem, online); 600 601 *sdir++ = dir; 602 } 603 604 *sdir++ = salinfo_dir; 605 606 init_timer(&salinfo_timer); 607 salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY; 608 salinfo_timer.function = &salinfo_timeout; 609 add_timer(&salinfo_timer); 610 611 return 0; 612 } 613 614 /* 615 * 'data' contains an integer that corresponds to the feature we're 616 * testing 617 */ 618 static int 619 salinfo_read(char *page, char **start, off_t off, int count, int *eof, void *data) 620 { 621 int len = 0; 622 623 len = sprintf(page, (sal_platform_features & (unsigned long)data) ? "1\n" : "0\n"); 624 625 if (len <= off+count) *eof = 1; 626 627 *start = page + off; 628 len -= off; 629 630 if (len>count) len = count; 631 if (len<0) len = 0; 632 633 return len; 634 } 635 636 module_init(salinfo_init); 637