xref: /OK3568_Linux_fs/kernel/drivers/misc/ibmasm/ibmasm.h (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-or-later */
2*4882a593Smuzhiyun 
3*4882a593Smuzhiyun /*
4*4882a593Smuzhiyun  * IBM ASM Service Processor Device Driver
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright (C) IBM Corporation, 2004
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * Author: Max Asböck <amax@us.ibm.com>
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/types.h>
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/list.h>
15*4882a593Smuzhiyun #include <linux/wait.h>
16*4882a593Smuzhiyun #include <linux/spinlock.h>
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include <linux/module.h>
19*4882a593Smuzhiyun #include <linux/interrupt.h>
20*4882a593Smuzhiyun #include <linux/kref.h>
21*4882a593Smuzhiyun #include <linux/device.h>
22*4882a593Smuzhiyun #include <linux/input.h>
23*4882a593Smuzhiyun #include <linux/time64.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* Driver identification */
26*4882a593Smuzhiyun #define DRIVER_NAME	"ibmasm"
27*4882a593Smuzhiyun #define DRIVER_VERSION  "1.0"
28*4882a593Smuzhiyun #define DRIVER_AUTHOR   "Max Asbock <masbock@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"
29*4882a593Smuzhiyun #define DRIVER_DESC     "IBM ASM Service Processor Driver"
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)
32*4882a593Smuzhiyun #define info(msg) printk(KERN_INFO "%s: " msg "\n", DRIVER_NAME)
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun extern int ibmasm_debug;
35*4882a593Smuzhiyun #define dbg(STR, ARGS...)					\
36*4882a593Smuzhiyun 	do {							\
37*4882a593Smuzhiyun 		if (ibmasm_debug)				\
38*4882a593Smuzhiyun 			printk(KERN_DEBUG STR , ##ARGS);	\
39*4882a593Smuzhiyun 	} while (0)
40*4882a593Smuzhiyun 
get_timestamp(char * buf)41*4882a593Smuzhiyun static inline char *get_timestamp(char *buf)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	struct timespec64 now;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	ktime_get_real_ts64(&now);
46*4882a593Smuzhiyun 	sprintf(buf, "%llu.%.08lu", (long long)now.tv_sec,
47*4882a593Smuzhiyun 				now.tv_nsec / NSEC_PER_USEC);
48*4882a593Smuzhiyun 	return buf;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun #define IBMASM_CMD_PENDING	0
52*4882a593Smuzhiyun #define IBMASM_CMD_COMPLETE	1
53*4882a593Smuzhiyun #define IBMASM_CMD_FAILED	2
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #define IBMASM_CMD_TIMEOUT_NORMAL	45
56*4882a593Smuzhiyun #define IBMASM_CMD_TIMEOUT_EXTRA	240
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #define IBMASM_CMD_MAX_BUFFER_SIZE	0x8000
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #define REVERSE_HEARTBEAT_TIMEOUT	120
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun #define HEARTBEAT_BUFFER_SIZE		0x400
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun #ifdef IA64
65*4882a593Smuzhiyun #define IBMASM_DRIVER_VPD "Lin64 6.08      "
66*4882a593Smuzhiyun #else
67*4882a593Smuzhiyun #define IBMASM_DRIVER_VPD "Lin32 6.08      "
68*4882a593Smuzhiyun #endif
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun #define SYSTEM_STATE_OS_UP      5
71*4882a593Smuzhiyun #define SYSTEM_STATE_OS_DOWN    4
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun #define IBMASM_NAME_SIZE	16
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun #define IBMASM_NUM_EVENTS	10
76*4882a593Smuzhiyun #define IBMASM_EVENT_MAX_SIZE	2048u
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun struct command {
80*4882a593Smuzhiyun 	struct list_head	queue_node;
81*4882a593Smuzhiyun 	wait_queue_head_t	wait;
82*4882a593Smuzhiyun 	unsigned char		*buffer;
83*4882a593Smuzhiyun 	size_t			buffer_size;
84*4882a593Smuzhiyun 	int			status;
85*4882a593Smuzhiyun 	struct kref		kref;
86*4882a593Smuzhiyun 	spinlock_t		*lock;
87*4882a593Smuzhiyun };
88*4882a593Smuzhiyun #define to_command(c) container_of(c, struct command, kref)
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun void ibmasm_free_command(struct kref *kref);
command_put(struct command * cmd)91*4882a593Smuzhiyun static inline void command_put(struct command *cmd)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	unsigned long flags;
94*4882a593Smuzhiyun 	spinlock_t *lock = cmd->lock;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	spin_lock_irqsave(lock, flags);
97*4882a593Smuzhiyun 	kref_put(&cmd->kref, ibmasm_free_command);
98*4882a593Smuzhiyun 	spin_unlock_irqrestore(lock, flags);
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
command_get(struct command * cmd)101*4882a593Smuzhiyun static inline void command_get(struct command *cmd)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	kref_get(&cmd->kref);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun struct ibmasm_event {
108*4882a593Smuzhiyun 	unsigned int	serial_number;
109*4882a593Smuzhiyun 	unsigned int	data_size;
110*4882a593Smuzhiyun 	unsigned char	data[IBMASM_EVENT_MAX_SIZE];
111*4882a593Smuzhiyun };
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun struct event_buffer {
114*4882a593Smuzhiyun 	struct ibmasm_event	events[IBMASM_NUM_EVENTS];
115*4882a593Smuzhiyun 	unsigned int		next_serial_number;
116*4882a593Smuzhiyun 	unsigned int		next_index;
117*4882a593Smuzhiyun 	struct list_head	readers;
118*4882a593Smuzhiyun };
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun struct event_reader {
121*4882a593Smuzhiyun 	int			cancelled;
122*4882a593Smuzhiyun 	unsigned int		next_serial_number;
123*4882a593Smuzhiyun 	wait_queue_head_t	wait;
124*4882a593Smuzhiyun 	struct list_head	node;
125*4882a593Smuzhiyun 	unsigned int		data_size;
126*4882a593Smuzhiyun 	unsigned char		data[IBMASM_EVENT_MAX_SIZE];
127*4882a593Smuzhiyun };
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun struct reverse_heartbeat {
130*4882a593Smuzhiyun 	wait_queue_head_t	wait;
131*4882a593Smuzhiyun 	unsigned int		stopped;
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun struct ibmasm_remote {
135*4882a593Smuzhiyun 	struct input_dev *keybd_dev;
136*4882a593Smuzhiyun 	struct input_dev *mouse_dev;
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun struct service_processor {
140*4882a593Smuzhiyun 	struct list_head	node;
141*4882a593Smuzhiyun 	spinlock_t		lock;
142*4882a593Smuzhiyun 	void __iomem		*base_address;
143*4882a593Smuzhiyun 	unsigned int		irq;
144*4882a593Smuzhiyun 	struct command		*current_command;
145*4882a593Smuzhiyun 	struct command		*heartbeat;
146*4882a593Smuzhiyun 	struct list_head	command_queue;
147*4882a593Smuzhiyun 	struct event_buffer	*event_buffer;
148*4882a593Smuzhiyun 	char			dirname[IBMASM_NAME_SIZE];
149*4882a593Smuzhiyun 	char			devname[IBMASM_NAME_SIZE];
150*4882a593Smuzhiyun 	unsigned int		number;
151*4882a593Smuzhiyun 	struct ibmasm_remote	remote;
152*4882a593Smuzhiyun 	int			serial_line;
153*4882a593Smuzhiyun 	struct device		*dev;
154*4882a593Smuzhiyun };
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun /* command processing */
157*4882a593Smuzhiyun struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size);
158*4882a593Smuzhiyun void ibmasm_exec_command(struct service_processor *sp, struct command *cmd);
159*4882a593Smuzhiyun void ibmasm_wait_for_response(struct command *cmd, int timeout);
160*4882a593Smuzhiyun void ibmasm_receive_command_response(struct service_processor *sp, void *response,  size_t size);
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun /* event processing */
163*4882a593Smuzhiyun int ibmasm_event_buffer_init(struct service_processor *sp);
164*4882a593Smuzhiyun void ibmasm_event_buffer_exit(struct service_processor *sp);
165*4882a593Smuzhiyun void ibmasm_receive_event(struct service_processor *sp, void *data,  unsigned int data_size);
166*4882a593Smuzhiyun void ibmasm_event_reader_register(struct service_processor *sp, struct event_reader *reader);
167*4882a593Smuzhiyun void ibmasm_event_reader_unregister(struct service_processor *sp, struct event_reader *reader);
168*4882a593Smuzhiyun int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *reader);
169*4882a593Smuzhiyun void ibmasm_cancel_next_event(struct event_reader *reader);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun /* heartbeat - from SP to OS */
172*4882a593Smuzhiyun void ibmasm_register_panic_notifier(void);
173*4882a593Smuzhiyun void ibmasm_unregister_panic_notifier(void);
174*4882a593Smuzhiyun int ibmasm_heartbeat_init(struct service_processor *sp);
175*4882a593Smuzhiyun void ibmasm_heartbeat_exit(struct service_processor *sp);
176*4882a593Smuzhiyun void ibmasm_receive_heartbeat(struct service_processor *sp,  void *message, size_t size);
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun /* reverse heartbeat - from OS to SP */
179*4882a593Smuzhiyun void ibmasm_init_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb);
180*4882a593Smuzhiyun int ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb);
181*4882a593Smuzhiyun void ibmasm_stop_reverse_heartbeat(struct reverse_heartbeat *rhb);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun /* dot commands */
184*4882a593Smuzhiyun void ibmasm_receive_message(struct service_processor *sp, void *data, int data_size);
185*4882a593Smuzhiyun int ibmasm_send_driver_vpd(struct service_processor *sp);
186*4882a593Smuzhiyun int ibmasm_send_os_state(struct service_processor *sp, int os_state);
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun /* low level message processing */
189*4882a593Smuzhiyun int ibmasm_send_i2o_message(struct service_processor *sp);
190*4882a593Smuzhiyun irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id);
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun /* remote console */
193*4882a593Smuzhiyun void ibmasm_handle_mouse_interrupt(struct service_processor *sp);
194*4882a593Smuzhiyun int ibmasm_init_remote_input_dev(struct service_processor *sp);
195*4882a593Smuzhiyun void ibmasm_free_remote_input_dev(struct service_processor *sp);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun /* file system */
198*4882a593Smuzhiyun int ibmasmfs_register(void);
199*4882a593Smuzhiyun void ibmasmfs_unregister(void);
200*4882a593Smuzhiyun void ibmasmfs_add_sp(struct service_processor *sp);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun /* uart */
203*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SERIAL_8250)
204*4882a593Smuzhiyun void ibmasm_register_uart(struct service_processor *sp);
205*4882a593Smuzhiyun void ibmasm_unregister_uart(struct service_processor *sp);
206*4882a593Smuzhiyun #else
207*4882a593Smuzhiyun #define ibmasm_register_uart(sp)	do { } while(0)
208*4882a593Smuzhiyun #define ibmasm_unregister_uart(sp)	do { } while(0)
209*4882a593Smuzhiyun #endif
210