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