Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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);