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> 43e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells#include <linux/seq_file.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/smp.h> 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/vmalloc.h> 486188e10d38b8d7244ee7776d5f1f88c837b4b93fMatthew Wilcox#include <linux/semaphore.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/sal.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h> 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jesse Barnes <jbarnes@sgi.com>"); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("/proc interface to IA-64 SAL features"); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howellsstatic const struct file_operations proc_salinfo_fops; 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct { 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *name; /* name of the proc entry */ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long feature; /* feature bit */ 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry *entry; /* registered entry (removal) */ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} salinfo_entry_t; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * List {name,feature} pairs for every entry in /proc/sal/<feature> 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that this module exports 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 69e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howellsstatic const salinfo_entry_t salinfo_entries[]={ 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "bus_lock", IA64_SAL_PLATFORM_FEATURE_BUS_LOCK, }, 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "irq_redirection", IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT, }, 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "ipi_redirection", IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT, }, 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { "itc_drift", IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT, }, 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NR_SALINFO_ENTRIES ARRAY_SIZE(salinfo_entries) 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *salinfo_log_name[] = { 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "mca", 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "init", 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "cmc", 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "cpe", 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct proc_dir_entry *salinfo_proc_entries[ 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ARRAY_SIZE(salinfo_entries) + /* /proc/sal/bus_lock */ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ARRAY_SIZE(salinfo_log_name) + /* /proc/sal/{mca,...} */ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (2 * ARRAY_SIZE(salinfo_log_name)) + /* /proc/sal/mca/{event,data} */ 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1]; /* /proc/sal */ 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Some records we get ourselves, some are accessed as saved data in buffers 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that are owned by mca.c. 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct salinfo_data_saved { 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8* buffer; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 size; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 id; 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cpu; 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* State transitions. Actions are :- 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write "read <cpunum>" to the data file. 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write "clear <cpunum>" to the data file. 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write "oemdata <cpunum> <offset> to the data file. 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read from the data file. 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Close the data file. 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start state is NO_DATA. 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NO_DATA 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "read <cpunum>" -> NO_DATA or LOG_RECORD. 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "clear <cpunum>" -> NO_DATA or LOG_RECORD. 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "oemdata <cpunum> <offset> -> return -EINVAL. 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read data -> return EOF. 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * close -> unchanged. Free record areas. 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LOG_RECORD 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "read <cpunum>" -> NO_DATA or LOG_RECORD. 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "clear <cpunum>" -> NO_DATA or LOG_RECORD. 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "oemdata <cpunum> <offset> -> format the oem data, goto OEMDATA. 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read data -> return the INIT/MCA/CMC/CPE record. 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * close -> unchanged. Keep record areas. 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OEMDATA 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "read <cpunum>" -> NO_DATA or LOG_RECORD. 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "clear <cpunum>" -> NO_DATA or LOG_RECORD. 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write "oemdata <cpunum> <offset> -> format the oem data, goto OEMDATA. 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * read data -> return the formatted oemdata. 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * close -> unchanged. Keep record areas. 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Closing the data file does not change the state. This allows shell scripts 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to manipulate salinfo data, each shell redirection opens the file, does one 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * action then closes it again. The record areas are only freed at close when 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the state is NO_DATA. 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum salinfo_state { 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATE_NO_DATA, 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATE_LOG_RECORD, 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds STATE_OEMDATA, 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct salinfo_data { 143e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpumask_t cpu_event; /* which cpus have outstanding events */ 144e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens struct semaphore mutex; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *log_buffer; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 log_size; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *oemdata; /* decoded oem data */ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 oemdata_size; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int open; /* single-open to prevent races */ 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 type; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 saved_num; /* using a saved record? */ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum salinfo_state state :8; /* processing state */ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 padding; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cpu_check; /* next CPU to check */ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data_saved data_saved[5];/* save last 5 records from mca.c, must be < 255 */ 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct salinfo_data salinfo_data[ARRAY_SIZE(salinfo_log_name)]; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16071841b8fe7dd8caffd07482cbed4a99874bfbb70Keith Owensstatic DEFINE_SPINLOCK(data_lock); 16171841b8fe7dd8caffd07482cbed4a99874bfbb70Keith Owensstatic DEFINE_SPINLOCK(data_saved_lock); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/** salinfo_platform_oemdata - optional callback to decode oemdata from an error 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * record. 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @sect_header: pointer to the start of the section to decode. 16672fdbdce3d52282f8ea95f512e871791256754e6Simon Arlott * @oemdata: returns vmalloc area containing the decoded output. 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * @oemdata_size: returns length of decoded output (strlen). 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Description: If user space asks for oem data to be decoded by the kernel 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and/or prom and the platform has set salinfo_platform_oemdata to the address 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of a platform specific routine then call that routine. salinfo_platform_oemdata 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * vmalloc's and formats its output area, returning the address of the text 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and its strlen. Returns 0 for success, -ve for error. The callback is 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * invoked on the cpu that generated the error record. 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint (*salinfo_platform_oemdata)(const u8 *sect_header, u8 **oemdata, u64 *oemdata_size); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct salinfo_platform_oemdata_parms { 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const u8 *efi_guid; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 **oemdata; 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 *oemdata_size; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 185e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens/* Kick the mutex that tells user space that there is work to do. Instead of 186e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * trying to track the state of the mutex across multiple cpus, in user 187e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * context, interrupt context, non-maskable interrupt context and hotplug cpu, 188e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * it is far easier just to grab the mutex if it is free then release it. 189e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * 190e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * This routine must be called with data_saved_lock held, to make the down/up 191e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens * operation atomic. 192e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens */ 193e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owensstatic void 194e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owenssalinfo_work_to_do(struct salinfo_data *data) 195e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens{ 196fa276f36f3d8743295e067fb483b42dca8bd1eceJan Beulich (void)(down_trylock(&data->mutex) ?: 0); 197e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens up(&data->mutex); 198e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens} 199e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_platform_oemdata_cpu(void *context) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_platform_oemdata_parms *parms = context; 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds parms->ret = salinfo_platform_oemdata(parms->efi_guid, parms->oemdata, parms->oemdata_size); 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshift1_data_saved (struct salinfo_data *data, int shift) 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(data->data_saved+shift, data->data_saved+shift+1, 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ARRAY_SIZE(data->data_saved) - (shift+1)) * sizeof(data->data_saved[0])); 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(data->data_saved + ARRAY_SIZE(data->data_saved) - 1, 0, 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sizeof(data->data_saved[0])); 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* This routine is invoked in interrupt context. Note: mca.c enables 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupts before calling this code for CMC/CPE. MCA and INIT events are 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not irq safe, do not call any routines that use spinlocks, they may deadlock. 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MCA and INIT records are recorded, a timer event will look for any 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * outstanding events and wake up the user space code. 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The buffer passed from mca.c points to the output from ia64_log_get. This is 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a persistent buffer but its contents can change between the interrupt and 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * when user space processes the record. Save the record id to identify 225289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens * changes. If the buffer is NULL then just update the bitmap. 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe) 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data = salinfo_data + type; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data_saved *data_saved; 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags = 0; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int saved_size = ARRAY_SIZE(data->data_saved); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BUG_ON(type >= ARRAY_SIZE(salinfo_log_name)); 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 238e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (irqsafe) 239e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_lock_irqsave(&data_saved_lock, flags); 240289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens if (buffer) { 241289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) { 242289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens if (!data_saved->buffer) 243289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens break; 244289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens } 245289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens if (i == saved_size) { 246289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens if (!data->saved_num) { 247289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens shift1_data_saved(data, 0); 248289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens data_saved = data->data_saved + saved_size - 1; 249289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens } else 250289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens data_saved = NULL; 251289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens } 252289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens if (data_saved) { 253289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens data_saved->cpu = smp_processor_id(); 254289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens data_saved->id = ((sal_log_record_header_t *)buffer)->id; 255289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens data_saved->size = size; 256289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens data_saved->buffer = buffer; 257289d773ee89ea80dcc364ef97d1be7ad1817387eKeith Owens } 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 259e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_set(smp_processor_id(), data->cpu_event); 260e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (irqsafe) { 261e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens salinfo_work_to_do(data); 262e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Check for outstanding MCA/INIT records every minute (arbitrary) */ 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SALINFO_TIMER_DELAY (60*HZ) 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct timer_list salinfo_timer; 26943ed3baf623410b3fa6ca14a9d3f6deca3493c56Hidetoshi Setoextern void ia64_mlogbuf_dump(void); 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_timeout_check(struct salinfo_data *data) 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 274e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens unsigned long flags; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data->open) 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 277e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (!cpus_empty(data->cpu_event)) { 278e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_lock_irqsave(&data_saved_lock, flags); 279e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens salinfo_work_to_do(data); 280e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 284e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owensstatic void 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_timeout (unsigned long arg) 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 28743ed3baf623410b3fa6ca14a9d3f6deca3493c56Hidetoshi Seto ia64_mlogbuf_dump(); 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_INIT); 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&salinfo_timer); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_event_open(struct inode *inode, struct file *file) 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_event_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 305d9dda78bad879595d8c4220a067fc029d6484a16Al Viro struct salinfo_data *data = PDE_DATA(file_inode(file)); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char cmd[32]; 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, n, cpu = -1; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsretry: 311e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (cpus_empty(data->cpu_event) && down_trylock(&data->mutex)) { 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (file->f_flags & O_NONBLOCK) 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EAGAIN; 314e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (down_interruptible(&data->mutex)) 31505f70395c642bed0300bc1955bfa8c0f93de2bc2Keith Owens return -EINTR; 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = data->cpu_check; 3195dd3c9949a3e92ea7fd8c75d888031f7aff1f1d0Rusty Russell for (i = 0; i < nr_cpu_ids; i++) { 320e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (cpu_isset(n, data->cpu_event)) { 321e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (!cpu_online(n)) { 322e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_clear(n, data->cpu_event); 323e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens continue; 324e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu = n; 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3285dd3c9949a3e92ea7fd8c75d888031f7aff1f1d0Rusty Russell if (++n == nr_cpu_ids) 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = 0; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cpu == -1) 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto retry; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33543ed3baf623410b3fa6ca14a9d3f6deca3493c56Hidetoshi Seto ia64_mlogbuf_dump(); 33643ed3baf623410b3fa6ca14a9d3f6deca3493c56Hidetoshi Seto 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* for next read, start checking at next CPU */ 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->cpu_check = cpu; 3395dd3c9949a3e92ea7fd8c75d888031f7aff1f1d0Rusty Russell if (++data->cpu_check == nr_cpu_ids) 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->cpu_check = 0; 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds snprintf(cmd, sizeof(cmd), "read %d\n", cpu); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = strlen(cmd); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (size > count) 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = count; 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_to_user(buffer, cmd, size)) 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return size; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3535dfe4c964a0dd7bb3a1d64a4166835a153146207Arjan van de Venstatic const struct file_operations salinfo_event_fops = { 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = salinfo_event_open, 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = salinfo_event_read, 3566038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .llseek = noop_llseek, 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_open(struct inode *inode, struct file *file) 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 362d9dda78bad879595d8c4220a067fc029d6484a16Al Viro struct salinfo_data *data = PDE_DATA(inode); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!capable(CAP_SYS_ADMIN)) 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EPERM; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&data_lock); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->open) { 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&data_lock); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->open = 1; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&data_lock); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->state == STATE_NO_DATA && 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(data->log_buffer = vmalloc(ia64_sal_get_state_info_size(data->type)))) { 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->open = 0; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_release(struct inode *inode, struct file *file) 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 387d9dda78bad879595d8c4220a067fc029d6484a16Al Viro struct salinfo_data *data = PDE_DATA(inode); 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->state == STATE_NO_DATA) { 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vfree(data->log_buffer); 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vfree(data->oemdata); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->log_buffer = NULL; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->oemdata = NULL; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&data_lock); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->open = 0; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&data_lock); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscall_on_cpu(int cpu, void (*fn)(void *), void *arg) 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 404e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpumask_t save_cpus_allowed = current->cpus_allowed; 405552dce3a071f0de2a84023fbba7f3b4ac36602cdJulia Lawall set_cpus_allowed_ptr(current, cpumask_of(cpu)); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (*fn)(arg); 407552dce3a071f0de2a84023fbba7f3b4ac36602cdJulia Lawall set_cpus_allowed_ptr(current, &save_cpus_allowed); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_read_cpu(void *context) 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data = context; 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sal_log_record_header_t *rh; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->log_size = ia64_sal_get_state_info(data->type, (u64 *) data->log_buffer); 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rh = (sal_log_record_header_t *)(data->log_buffer); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear corrected errors as they are read from SAL */ 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rh->severity == sal_log_severity_corrected) 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ia64_sal_clear_state_info(data->type); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_new_read(int cpu, struct salinfo_data *data) 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data_saved *data_saved; 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long flags; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int saved_size = ARRAY_SIZE(data->data_saved); 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->saved_num = 0; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irqsave(&data_saved_lock, flags); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsretry: 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) { 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data_saved->buffer && data_saved->cpu == cpu) { 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sal_log_record_header_t *rh = (sal_log_record_header_t *)(data_saved->buffer); 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->log_size = data_saved->size; 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(data->log_buffer, rh, data->log_size); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds barrier(); /* id check must not be moved */ 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rh->id == data_saved->id) { 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->saved_num = i+1; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* saved record changed by mca.c since interrupt, discard it */ 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds shift1_data_saved(data, i); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto retry; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irqrestore(&data_saved_lock, flags); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data->saved_num) 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds call_on_cpu(cpu, salinfo_log_read_cpu, data); 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!data->log_size) { 453e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens data->state = STATE_NO_DATA; 454e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_clear(cpu, data->cpu_event); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 456e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens data->state = STATE_LOG_RECORD; 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 463d9dda78bad879595d8c4220a067fc029d6484a16Al Viro struct salinfo_data *data = PDE_DATA(file_inode(file)); 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 *buf; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u64 bufsize; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->state == STATE_LOG_RECORD) { 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = data->log_buffer; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bufsize = data->log_size; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (data->state == STATE_OEMDATA) { 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = data->oemdata; 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bufsize = data->oemdata_size; 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = NULL; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bufsize = 0; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return simple_read_from_buffer(buffer, count, ppos, buf, bufsize); 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_clear_cpu(void *context) 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data = context; 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ia64_sal_clear_state_info(data->type); 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_clear(struct salinfo_data *data, int cpu) 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sal_log_record_header_t *rh; 491e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens unsigned long flags; 492e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_lock_irqsave(&data_saved_lock, flags); 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->state = STATE_NO_DATA; 494e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (!cpu_isset(cpu, data->cpu_event)) { 495e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 497e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 498e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_clear(cpu, data->cpu_event); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->saved_num) { 500e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens shift1_data_saved(data, data->saved_num - 1); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->saved_num = 0; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 503e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rh = (sal_log_record_header_t *)(data->log_buffer); 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Corrected errors have already been cleared from SAL */ 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rh->severity != sal_log_severity_corrected) 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds call_on_cpu(cpu, salinfo_log_clear_cpu, data); 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* clearing a record may make a new record visible */ 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_log_new_read(cpu, data); 510e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (data->state == STATE_LOG_RECORD) { 511e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_lock_irqsave(&data_saved_lock, flags); 512e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_set(cpu, data->cpu_event); 513e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens salinfo_work_to_do(data); 514e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 515e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_log_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 522d9dda78bad879595d8c4220a067fc029d6484a16Al Viro struct salinfo_data *data = PDE_DATA(file_inode(file)); 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char cmd[32]; 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size_t size; 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 offset; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int cpu; 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = sizeof(cmd); 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (count < size) 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds size = count; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (copy_from_user(cmd, buffer, size)) 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EFAULT; 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sscanf(cmd, "read %d", &cpu) == 1) { 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_log_new_read(cpu, data); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (sscanf(cmd, "clear %d", &cpu) == 1) { 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((ret = salinfo_log_clear(data, cpu))) 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = ret; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (sscanf(cmd, "oemdata %d %d", &cpu, &offset) == 2) { 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->state != STATE_LOG_RECORD && data->state != STATE_OEMDATA) 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (offset > data->log_size - sizeof(efi_guid_t)) 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->state = STATE_OEMDATA; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (salinfo_platform_oemdata) { 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_platform_oemdata_parms parms = { 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .efi_guid = data->log_buffer + offset, 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .oemdata = &data->oemdata, 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .oemdata_size = &data->oemdata_size 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds }; 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds call_on_cpu(cpu, salinfo_platform_oemdata_cpu, &parms); 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (parms.ret) 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds count = parms.ret; 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->oemdata_size = 0; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5635dfe4c964a0dd7bb3a1d64a4166835a153146207Arjan van de Venstatic const struct file_operations salinfo_data_fops = { 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .open = salinfo_log_open, 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .release = salinfo_log_release, 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .read = salinfo_log_read, 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .write = salinfo_log_write, 5686038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .llseek = default_llseek, 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 571ccce9bb83ed20bca52f82ff9d7cf889d23a2ec01Paul Gortmakerstatic int 572e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owenssalinfo_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu) 573e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens{ 574e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens unsigned int i, cpu = (unsigned long)hcpu; 575e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens unsigned long flags; 576e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens struct salinfo_data *data; 577e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens switch (action) { 578e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens case CPU_ONLINE: 5798bb7844286fb8c9fce6f65d8288aeb09d03a5e0dRafael J. Wysocki case CPU_ONLINE_FROZEN: 580e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_lock_irqsave(&data_saved_lock, flags); 581e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens for (i = 0, data = salinfo_data; 582e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens i < ARRAY_SIZE(salinfo_data); 583e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens ++i, ++data) { 584e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_set(cpu, data->cpu_event); 585e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens salinfo_work_to_do(data); 586e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 587e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 588e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens break; 589e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens case CPU_DEAD: 5908bb7844286fb8c9fce6f65d8288aeb09d03a5e0dRafael J. Wysocki case CPU_DEAD_FROZEN: 591e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_lock_irqsave(&data_saved_lock, flags); 592e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens for (i = 0, data = salinfo_data; 593e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens i < ARRAY_SIZE(salinfo_data); 594e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens ++i, ++data) { 595e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens struct salinfo_data_saved *data_saved; 596e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens int j; 597e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens for (j = ARRAY_SIZE(data->data_saved) - 1, data_saved = data->data_saved + j; 598e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens j >= 0; 599e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens --j, --data_saved) { 600e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens if (data_saved->buffer && data_saved->cpu == cpu) { 601e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens shift1_data_saved(data, j); 602e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 603e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 604e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_clear(cpu, data->cpu_event); 605e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 606e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens spin_unlock_irqrestore(&data_saved_lock, flags); 607e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens break; 608e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens } 609e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens return NOTIFY_OK; 610e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens} 611e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens 612ccce9bb83ed20bca52f82ff9d7cf889d23a2ec01Paul Gortmakerstatic struct notifier_block salinfo_cpu_notifier = 613e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens{ 614e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens .notifier_call = salinfo_cpu_callback, 615e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens .priority = 0, 616e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens}; 617e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssalinfo_init(void) 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry *salinfo_dir; /* /proc/sal dir entry */ 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry **sdir = salinfo_proc_entries; /* keeps track of every entry */ 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct proc_dir_entry *dir, *entry; 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct salinfo_data *data; 625e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens int i, j; 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_dir = proc_mkdir("sal", NULL); 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!salinfo_dir) 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i < NR_SALINFO_ENTRIES; i++) { 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* pass the feature bit in question as misc data */ 633e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells *sdir++ = proc_create_data(salinfo_entries[i].name, 0, salinfo_dir, 634e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells &proc_salinfo_fops, 635e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells (void *)salinfo_entries[i].feature); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 638eff722b06bdd6de326894ea2353ec0eda3e5ed34Srivatsa S. Bhat cpu_notifier_register_begin(); 639eff722b06bdd6de326894ea2353ec0eda3e5ed34Srivatsa S. Bhat 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < ARRAY_SIZE(salinfo_log_name); i++) { 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = salinfo_data + i; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->type = i; 643383f9f1741cd03687303f82543bbae11935a2ad6Thomas Gleixner sema_init(&data->mutex, 1); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dir = proc_mkdir(salinfo_log_name[i], salinfo_dir); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dir) 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 648e23637681bef5b69a68c8ac399732b941f1af023Denis V. Lunev entry = proc_create_data("event", S_IRUSR, dir, 649e23637681bef5b69a68c8ac399732b941f1af023Denis V. Lunev &salinfo_event_fops, data); 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!entry) 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *sdir++ = entry; 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 654e23637681bef5b69a68c8ac399732b941f1af023Denis V. Lunev entry = proc_create_data("data", S_IRUSR | S_IWUSR, dir, 655e23637681bef5b69a68c8ac399732b941f1af023Denis V. Lunev &salinfo_data_fops, data); 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!entry) 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *sdir++ = entry; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* we missed any events before now */ 661e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens for_each_online_cpu(j) 662e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens cpu_set(j, data->cpu_event); 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *sdir++ = dir; 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *sdir++ = salinfo_dir; 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_timer(&salinfo_timer); 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY; 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds salinfo_timer.function = &salinfo_timeout; 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds add_timer(&salinfo_timer); 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 674eff722b06bdd6de326894ea2353ec0eda3e5ed34Srivatsa S. Bhat __register_hotcpu_notifier(&salinfo_cpu_notifier); 675eff722b06bdd6de326894ea2353ec0eda3e5ed34Srivatsa S. Bhat 676eff722b06bdd6de326894ea2353ec0eda3e5ed34Srivatsa S. Bhat cpu_notifier_register_done(); 677e026cca0f2c09c4c28c902db6384fd8a412671d6Keith Owens 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'data' contains an integer that corresponds to the feature we're 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * testing 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 685e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howellsstatic int proc_salinfo_show(struct seq_file *m, void *v) 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 687e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells unsigned long data = (unsigned long)v; 688e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells seq_puts(m, (sal_platform_features & data) ? "1\n" : "0\n"); 689e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells return 0; 690e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells} 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 692e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howellsstatic int proc_salinfo_open(struct inode *inode, struct file *file) 693e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells{ 694e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells return single_open(file, proc_salinfo_show, PDE_DATA(inode)); 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 697e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howellsstatic const struct file_operations proc_salinfo_fops = { 698e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells .open = proc_salinfo_open, 699e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells .read = seq_read, 700e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells .llseek = seq_lseek, 70175401461610bf5fad0347bbd8cf7514a1f3b0cd4Al Viro .release = single_release, 702e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells}; 703e781c3d794282d9fa3ba377fdef221fc948974ecDavid Howells 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(salinfo_init); 705