salinfo.c revision 6188e10d38b8d7244ee7776d5f1f88c837b4b93f
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * salinfo.c 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Creates entries in /proc/sal for various system features. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 6e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * Copyright (c) 2003, 2006 Silicon Graphics, Inc. All rights reserved. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2003 Hewlett-Packard Co 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bjorn Helgaas <bjorn.helgaas@hp.com> 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 10/30/2001 jbarnes@sgi.com copied much of Stephane's palinfo 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * code to create this file 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Oct 23 2003 kaos@sgi.com 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Replace IPI with set_cpus_allowed() to read a record from the required cpu. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Redesign salinfo log processing to separate interrupt and user space 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * contexts. 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Cache the record across multi-block reads from user space. 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Support > 64 cpus. 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Delete module_exit and MOD_INC/DEC_COUNT, salinfo cannot be a module. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Jan 28 2004 kaos@sgi.com 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Periodically check for outstanding MCA or INIT records. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Dec 5 2004 kaos@sgi.com 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Standardize which records are cleared automatically. 25289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens * 26289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens * Aug 18 2005 kaos@sgi.com 27289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens * mca.c may not pass a buffer, a NULL buffer just indicates that a new 28289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens * record is available in SAL. 29289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens * Replace some NR_CPUS by cpus_online, for hotplug cpu. 30e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * 31e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * Jan 5 2006 kaos@sgi.com 32e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * Handle hotplug cpus coming online. 33e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * Handle hotplug cpus going offline while they still have outstanding records. 34e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * Use the cpu_* macros consistently. 35e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * Replace the counting semaphore with a mutex and a test if the cpumask is non-empty. 36e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * Modify the locking to make the test for "work to do" an atomic operation. 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39a9415644583ef344e02f84faf5fe24bfadb2af8eRandy Dunlap#include <linux/capability.h> 40e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens#include <linux/cpu.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h> 476188e10d38b8d7244ee7776d5f1f88c837b4b93fMatthew Wilcox#include <linux/semaphore.h> 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sal.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jesse Barnes <jbarnes@sgi.com>"); 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("/proc interface to IA-64 SAL features"); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int salinfo_read(char *page, char **start, off_t off, int count, int *eof, void *data); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct { 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *name; /* name of the proc entry */ 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long feature; /* feature bit */ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry *entry; /* registered entry (removal) */ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} salinfo_entry_t; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * List {name,feature} pairs for every entry in /proc/sal/<feature> 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that this module exports 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic salinfo_entry_t salinfo_entries[]={ 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "bus_lock", IA64_SAL_PLATFORM_FEATURE_BUS_LOCK, }, 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "irq_redirection", IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT, }, 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "ipi_redirection", IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT, }, 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "itc_drift", IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT, }, 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NR_SALINFO_ENTRIES ARRAY_SIZE(salinfo_entries) 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *salinfo_log_name[] = { 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "mca", 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "init", 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "cmc", 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "cpe", 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct proc_dir_entry *salinfo_proc_entries[ 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ARRAY_SIZE(salinfo_entries) + /* /proc/sal/bus_lock */ 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ARRAY_SIZE(salinfo_log_name) + /* /proc/sal/{mca,...} */ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (2 * ARRAY_SIZE(salinfo_log_name)) + /* /proc/sal/mca/{event,data} */ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1]; /* /proc/sal */ 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Some records we get ourselves, some are accessed as saved data in buffers 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that are owned by mca.c. 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct salinfo_data_saved { 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8* buffer; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 size; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 id; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cpu; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* State transitions. Actions are :- 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write "read <cpunum>" to the data file. 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write "clear <cpunum>" to the data file. 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write "oemdata <cpunum> <offset> to the data file. 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read from the data file. 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Close the data file. 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start state is NO_DATA. 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NO_DATA 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "read <cpunum>" -> NO_DATA or LOG_RECORD. 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "clear <cpunum>" -> NO_DATA or LOG_RECORD. 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "oemdata <cpunum> <offset> -> return -EINVAL. 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read data -> return EOF. 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * close -> unchanged. Free record areas. 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LOG_RECORD 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "read <cpunum>" -> NO_DATA or LOG_RECORD. 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "clear <cpunum>" -> NO_DATA or LOG_RECORD. 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "oemdata <cpunum> <offset> -> format the oem data, goto OEMDATA. 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read data -> return the INIT/MCA/CMC/CPE record. 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * close -> unchanged. Keep record areas. 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OEMDATA 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "read <cpunum>" -> NO_DATA or LOG_RECORD. 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "clear <cpunum>" -> NO_DATA or LOG_RECORD. 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "oemdata <cpunum> <offset> -> format the oem data, goto OEMDATA. 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read data -> return the formatted oemdata. 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * close -> unchanged. Keep record areas. 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Closing the data file does not change the state. This allows shell scripts 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to manipulate salinfo data, each shell redirection opens the file, does one 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * action then closes it again. The record areas are only freed at close when 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the state is NO_DATA. 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum salinfo_state { 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATE_NO_DATA, 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATE_LOG_RECORD, 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATE_OEMDATA, 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct salinfo_data { 142e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpumask_t cpu_event; /* which cpus have outstanding events */ 143e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens struct semaphore mutex; 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *log_buffer; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 log_size; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *oemdata; /* decoded oem data */ 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 oemdata_size; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int open; /* single-open to prevent races */ 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 type; 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 saved_num; /* using a saved record? */ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum salinfo_state state :8; /* processing state */ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 padding; 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cpu_check; /* next CPU to check */ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data_saved data_saved[5];/* save last 5 records from mca.c, must be < 255 */ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct salinfo_data salinfo_data[ARRAY_SIZE(salinfo_log_name)]; 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15971841b8fe7dd8caffd07482cbed4a99874bfbb70Keith Owensstatic DEFINE_SPINLOCK(data_lock); 16071841b8fe7dd8caffd07482cbed4a99874bfbb70Keith Owensstatic DEFINE_SPINLOCK(data_saved_lock); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** salinfo_platform_oemdata - optional callback to decode oemdata from an error 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * record. 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @sect_header: pointer to the start of the section to decode. 16572fdbdce3d52282f8ea95f512e871791256754e6Simon Arlott * @oemdata: returns vmalloc area containing the decoded output. 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @oemdata_size: returns length of decoded output (strlen). 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Description: If user space asks for oem data to be decoded by the kernel 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and/or prom and the platform has set salinfo_platform_oemdata to the address 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of a platform specific routine then call that routine. salinfo_platform_oemdata 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vmalloc's and formats its output area, returning the address of the text 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and its strlen. Returns 0 for success, -ve for error. The callback is 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * invoked on the cpu that generated the error record. 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint (*salinfo_platform_oemdata)(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct salinfo_platform_oemdata_parms { 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const u8 *efi_guid; 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 **oemdata; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 *oemdata_size; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 184e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens/* Kick the mutex that tells user space that there is work to do. Instead of 185e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * trying to track the state of the mutex across multiple cpus, in user 186e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * context, interrupt context, non-maskable interrupt context and hotplug cpu, 187e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * it is far easier just to grab the mutex if it is free then release it. 188e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * 189e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * This routine must be called with data_saved_lock held, to make the down/up 190e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * operation atomic. 191e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens */ 192e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owensstatic void 193e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owenssalinfo_work_to_do(struct salinfo_data *data) 194e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens{ 195e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens down_trylock(&data->mutex); 196e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens up(&data->mutex); 197e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens} 198e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_platform_oemdata_cpu(void *context) 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_platform_oemdata_parms *parms = context; 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parms->ret = salinfo_platform_oemdata(parms->efi_guid, parms->oemdata, parms->oemdata_size); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshift1_data_saved (struct salinfo_data *data, int shift) 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(data->data_saved+shift, data->data_saved+shift+1, 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ARRAY_SIZE(data->data_saved) - (shift+1)) * sizeof(data->data_saved[0])); 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(data->data_saved + ARRAY_SIZE(data->data_saved) - 1, 0, 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(data->data_saved[0])); 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This routine is invoked in interrupt context. Note: mca.c enables 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupts before calling this code for CMC/CPE. MCA and INIT events are 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not irq safe, do not call any routines that use spinlocks, they may deadlock. 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MCA and INIT records are recorded, a timer event will look for any 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * outstanding events and wake up the user space code. 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The buffer passed from mca.c points to the output from ia64_log_get. This is 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a persistent buffer but its contents can change between the interrupt and 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when user space processes the record. Save the record id to identify 224289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens * changes. If the buffer is NULL then just update the bitmap. 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe) 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data = salinfo_data + type; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data_saved *data_saved; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags = 0; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int saved_size = ARRAY_SIZE(data->data_saved); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(type >= ARRAY_SIZE(salinfo_log_name)); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 237e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (irqsafe) 238e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_lock_irqsave(&data_saved_lock, flags); 239289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens if (buffer) { 240289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) { 241289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens if (!data_saved->buffer) 242289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens break; 243289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens } 244289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens if (i == saved_size) { 245289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens if (!data->saved_num) { 246289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens shift1_data_saved(data, 0); 247289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens data_saved = data->data_saved + saved_size - 1; 248289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens } else 249289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens data_saved = NULL; 250289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens } 251289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens if (data_saved) { 252289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens data_saved->cpu = smp_processor_id(); 253289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens data_saved->id = ((sal_log_record_header_t *)buffer)->id; 254289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens data_saved->size = size; 255289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens data_saved->buffer = buffer; 256289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens } 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 258e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_set(smp_processor_id(), data->cpu_event); 259e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (irqsafe) { 260e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens salinfo_work_to_do(data); 261e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Check for outstanding MCA/INIT records every minute (arbitrary) */ 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SALINFO_TIMER_DELAY (60*HZ) 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct timer_list salinfo_timer; 26843ed3baf623410b3fa6ca14a9d3f6deca3493c56Hidetoshi Setoextern void ia64_mlogbuf_dump(void); 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_timeout_check(struct salinfo_data *data) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 273e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens unsigned long flags; 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data->open) 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 276e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (!cpus_empty(data->cpu_event)) { 277e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_lock_irqsave(&data_saved_lock, flags); 278e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens salinfo_work_to_do(data); 279e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 283e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owensstatic void 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_timeout (unsigned long arg) 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 28643ed3baf623410b3fa6ca14a9d3f6deca3493c56Hidetoshi Seto ia64_mlogbuf_dump(); 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_INIT); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&salinfo_timer); 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_event_open(struct inode *inode, struct file *file) 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_event_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 304b66ffad90429a2ed84c6e8954d205539f6cc86a9Josef Sipek struct inode *inode = file->f_path.dentry->d_inode; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry *entry = PDE(inode); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data = entry->data; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char cmd[32]; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, n, cpu = -1; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsretry: 312e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (cpus_empty(data->cpu_event) && down_trylock(&data->mutex)) { 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (file->f_flags & O_NONBLOCK) 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 315e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (down_interruptible(&data->mutex)) 31605f70395c642bed0300bc1955bfa8c0f93de2bc2Keith Owens return -EINTR; 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = data->cpu_check; 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < NR_CPUS; i++) { 321e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (cpu_isset(n, data->cpu_event)) { 322e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (!cpu_online(n)) { 323e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_clear(n, data->cpu_event); 324e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens continue; 325e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu = n; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++n == NR_CPUS) 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = 0; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cpu == -1) 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto retry; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33643ed3baf623410b3fa6ca14a9d3f6deca3493c56Hidetoshi Seto ia64_mlogbuf_dump(); 33743ed3baf623410b3fa6ca14a9d3f6deca3493c56Hidetoshi Seto 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* for next read, start checking at next CPU */ 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->cpu_check = cpu; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++data->cpu_check == NR_CPUS) 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->cpu_check = 0; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snprintf(cmd, sizeof(cmd), "read %d\n", cpu); 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = strlen(cmd); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size > count) 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = count; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(buffer, cmd, size)) 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return size; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3545dfe4c964a0dd7bb3a1d64a4166835a153146207Arjan van de Venstatic const struct file_operations salinfo_event_fops = { 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = salinfo_event_open, 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = salinfo_event_read, 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_open(struct inode *inode, struct file *file) 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry *entry = PDE(inode); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data = entry->data; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&data_lock); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->open) { 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&data_lock); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->open = 1; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&data_lock); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->state == STATE_NO_DATA && 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(data->log_buffer = vmalloc(ia64_sal_get_state_info_size(data->type)))) { 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->open = 0; 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_release(struct inode *inode, struct file *file) 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry *entry = PDE(inode); 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data = entry->data; 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->state == STATE_NO_DATA) { 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vfree(data->log_buffer); 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vfree(data->oemdata); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->log_buffer = NULL; 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->oemdata = NULL; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&data_lock); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->open = 0; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&data_lock); 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscall_on_cpu(int cpu, void (*fn)(void *), void *arg) 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 406e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpumask_t save_cpus_allowed = current->cpus_allowed; 407e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpumask_t new_cpus_allowed = cpumask_of_cpu(cpu); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_cpus_allowed(current, new_cpus_allowed); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*fn)(arg); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds set_cpus_allowed(current, save_cpus_allowed); 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_read_cpu(void *context) 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data = context; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sal_log_record_header_t *rh; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->log_size = ia64_sal_get_state_info(data->type, (u64 *) data->log_buffer); 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rh = (sal_log_record_header_t *)(data->log_buffer); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear corrected errors as they are read from SAL */ 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rh->severity == sal_log_severity_corrected) 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ia64_sal_clear_state_info(data->type); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_new_read(int cpu, struct salinfo_data *data) 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data_saved *data_saved; 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int saved_size = ARRAY_SIZE(data->data_saved); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->saved_num = 0; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&data_saved_lock, flags); 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsretry: 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) { 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data_saved->buffer && data_saved->cpu == cpu) { 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sal_log_record_header_t *rh = (sal_log_record_header_t *)(data_saved->buffer); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->log_size = data_saved->size; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(data->log_buffer, rh, data->log_size); 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds barrier(); /* id check must not be moved */ 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rh->id == data_saved->id) { 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->saved_num = i+1; 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* saved record changed by mca.c since interrupt, discard it */ 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift1_data_saved(data, i); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto retry; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&data_saved_lock, flags); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data->saved_num) 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds call_on_cpu(cpu, salinfo_log_read_cpu, data); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data->log_size) { 456e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens data->state = STATE_NO_DATA; 457e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_clear(cpu, data->cpu_event); 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 459e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens data->state = STATE_LOG_RECORD; 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 466b66ffad90429a2ed84c6e8954d205539f6cc86a9Josef Sipek struct inode *inode = file->f_path.dentry->d_inode; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry *entry = PDE(inode); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data = entry->data; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 bufsize; 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->state == STATE_LOG_RECORD) { 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = data->log_buffer; 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bufsize = data->log_size; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (data->state == STATE_OEMDATA) { 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = data->oemdata; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bufsize = data->oemdata_size; 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = NULL; 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bufsize = 0; 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return simple_read_from_buffer(buffer, count, ppos, buf, bufsize); 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_clear_cpu(void *context) 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data = context; 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ia64_sal_clear_state_info(data->type); 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_clear(struct salinfo_data *data, int cpu) 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sal_log_record_header_t *rh; 496e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens unsigned long flags; 497e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_lock_irqsave(&data_saved_lock, flags); 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->state = STATE_NO_DATA; 499e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (!cpu_isset(cpu, data->cpu_event)) { 500e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 502e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 503e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_clear(cpu, data->cpu_event); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->saved_num) { 505e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens shift1_data_saved(data, data->saved_num - 1); 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->saved_num = 0; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 508e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rh = (sal_log_record_header_t *)(data->log_buffer); 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Corrected errors have already been cleared from SAL */ 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rh->severity != sal_log_severity_corrected) 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds call_on_cpu(cpu, salinfo_log_clear_cpu, data); 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clearing a record may make a new record visible */ 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_log_new_read(cpu, data); 515e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (data->state == STATE_LOG_RECORD) { 516e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_lock_irqsave(&data_saved_lock, flags); 517e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_set(cpu, data->cpu_event); 518e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens salinfo_work_to_do(data); 519e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 520e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 527b66ffad90429a2ed84c6e8954d205539f6cc86a9Josef Sipek struct inode *inode = file->f_path.dentry->d_inode; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry *entry = PDE(inode); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data = entry->data; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char cmd[32]; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 offset; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cpu; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = sizeof(cmd); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < size) 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = count; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(cmd, buffer, size)) 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sscanf(cmd, "read %d", &cpu) == 1) { 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_log_new_read(cpu, data); 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (sscanf(cmd, "clear %d", &cpu) == 1) { 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = salinfo_log_clear(data, cpu))) 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = ret; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (sscanf(cmd, "oemdata %d %d", &cpu, &offset) == 2) { 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->state != STATE_LOG_RECORD && data->state != STATE_OEMDATA) 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offset > data->log_size - sizeof(efi_guid_t)) 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->state = STATE_OEMDATA; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (salinfo_platform_oemdata) { 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_platform_oemdata_parms parms = { 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .efi_guid = data->log_buffer + offset, 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .oemdata = &data->oemdata, 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .oemdata_size = &data->oemdata_size 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds call_on_cpu(cpu, salinfo_platform_oemdata_cpu, &parms); 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (parms.ret) 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = parms.ret; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->oemdata_size = 0; 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5705dfe4c964a0dd7bb3a1d64a4166835a153146207Arjan van de Venstatic const struct file_operations salinfo_data_fops = { 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = salinfo_log_open, 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = salinfo_log_release, 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = salinfo_log_read, 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = salinfo_log_write, 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 577db6a5cef7f474a5bad476a31f4e4c69a69fab8b1Satyam Sharmastatic int __cpuinit 578e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owenssalinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) 579e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens{ 580e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens unsigned int i, cpu = (unsigned long)hcpu; 581e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens unsigned long flags; 582e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens struct salinfo_data *data; 583e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens switch (action) { 584e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens case CPU_ONLINE: 5858bb7844286fb8c9fce6f65d8288aeb09d03a5e0dRafael J. Wysocki case CPU_ONLINE_FROZEN: 586e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_lock_irqsave(&data_saved_lock, flags); 587e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens for (i = 0, data = salinfo_data; 588e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens i < ARRAY_SIZE(salinfo_data); 589e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens ++i, ++data) { 590e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_set(cpu, data->cpu_event); 591e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens salinfo_work_to_do(data); 592e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 593e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 594e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens break; 595e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens case CPU_DEAD: 5968bb7844286fb8c9fce6f65d8288aeb09d03a5e0dRafael J. Wysocki case CPU_DEAD_FROZEN: 597e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_lock_irqsave(&data_saved_lock, flags); 598e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens for (i = 0, data = salinfo_data; 599e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens i < ARRAY_SIZE(salinfo_data); 600e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens ++i, ++data) { 601e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens struct salinfo_data_saved *data_saved; 602e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens int j; 603e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens for (j = ARRAY_SIZE(data->data_saved) - 1, data_saved = data->data_saved + j; 604e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens j >= 0; 605e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens --j, --data_saved) { 606e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (data_saved->buffer && data_saved->cpu == cpu) { 607e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens shift1_data_saved(data, j); 608e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 609e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 610e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_clear(cpu, data->cpu_event); 611e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 612e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 613e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens break; 614e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 615e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens return NOTIFY_OK; 616e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens} 617e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens 618db6a5cef7f474a5bad476a31f4e4c69a69fab8b1Satyam Sharmastatic struct notifier_block salinfo_cpu_notifier __cpuinitdata = 619e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens{ 620e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens .notifier_call = salinfo_cpu_callback, 621e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens .priority = 0, 622e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens}; 623e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_init(void) 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry *salinfo_dir; /* /proc/sal dir entry */ 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry **sdir = salinfo_proc_entries; /* keeps track of every entry */ 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry *dir, *entry; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data; 631e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens int i, j; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_dir = proc_mkdir("sal", NULL); 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!salinfo_dir) 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i < NR_SALINFO_ENTRIES; i++) { 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* pass the feature bit in question as misc data */ 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *sdir++ = create_proc_read_entry (salinfo_entries[i].name, 0, salinfo_dir, 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_read, (void *)salinfo_entries[i].feature); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(salinfo_log_name); i++) { 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = salinfo_data + i; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->type = i; 646e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens init_MUTEX(&data->mutex); 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dir = proc_mkdir(salinfo_log_name[i], salinfo_dir); 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dir) 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = create_proc_entry("event", S_IRUSR, dir); 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!entry) 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->data = data; 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->proc_fops = &salinfo_event_fops; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *sdir++ = entry; 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry = create_proc_entry("data", S_IRUSR | S_IWUSR, dir); 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!entry) 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->data = data; 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds entry->proc_fops = &salinfo_data_fops; 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *sdir++ = entry; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we missed any events before now */ 666e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens for_each_online_cpu(j) 667e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_set(j, data->cpu_event); 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *sdir++ = dir; 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *sdir++ = salinfo_dir; 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&salinfo_timer); 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY; 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_timer.function = &salinfo_timeout; 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&salinfo_timer); 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6795a67e4c5b6faaccf31740a07d93704166405d880Chandra Seetharaman register_hotcpu_notifier(&salinfo_cpu_notifier); 680e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'data' contains an integer that corresponds to the feature we're 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * testing 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_read(char *page, char **start, off_t off, int count, int *eof, void *data) 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len = 0; 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = sprintf(page, (sal_platform_features & (unsigned long)data) ? "1\n" : "0\n"); 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len <= off+count) *eof = 1; 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *start = page + off; 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len -= off; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len>count) len = count; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len<0) len = 0; 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return len; 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(salinfo_init); 707