Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | |
2 | /* | |
3 | * IBM ASM Service Processor Device Driver | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU General Public License | |
16 | * along with this program; if not, write to the Free Software | |
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
18 | * | |
19 | * Copyright (C) IBM Corporation, 2004 | |
20 | * | |
d36b6910 | 21 | * Author: Max Asböck <amax@us.ibm.com> |
1da177e4 LT |
22 | * |
23 | */ | |
24 | ||
25 | #include <linux/kernel.h> | |
26 | #include <linux/types.h> | |
27 | #include <linux/errno.h> | |
28 | #include <linux/list.h> | |
29 | #include <linux/wait.h> | |
30 | #include <linux/spinlock.h> | |
31 | #include <linux/slab.h> | |
1da177e4 | 32 | #include <linux/module.h> |
1da177e4 | 33 | #include <linux/interrupt.h> |
a045171f | 34 | #include <linux/kref.h> |
1da177e4 | 35 | #include <linux/device.h> |
278d72ae | 36 | #include <linux/input.h> |
1da177e4 LT |
37 | |
38 | /* Driver identification */ | |
39 | #define DRIVER_NAME "ibmasm" | |
278d72ae MA |
40 | #define DRIVER_VERSION "1.0" |
41 | #define DRIVER_AUTHOR "Max Asbock <masbock@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>" | |
1da177e4 LT |
42 | #define DRIVER_DESC "IBM ASM Service Processor Driver" |
43 | ||
44 | #define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME) | |
45 | #define info(msg) printk(KERN_INFO "%s: " msg "\n", DRIVER_NAME) | |
46 | ||
278d72ae MA |
47 | extern int ibmasm_debug; |
48 | #define dbg(STR, ARGS...) \ | |
49 | do { \ | |
50 | if (ibmasm_debug) \ | |
51 | printk(KERN_DEBUG STR , ##ARGS); \ | |
52 | } while (0) | |
53 | ||
54 | static inline char *get_timestamp(char *buf) | |
55 | { | |
56 | struct timeval now; | |
57 | do_gettimeofday(&now); | |
58 | sprintf(buf, "%lu.%lu", now.tv_sec, now.tv_usec); | |
59 | return buf; | |
60 | } | |
1da177e4 | 61 | |
3110dc7a DT |
62 | #define IBMASM_CMD_PENDING 0 |
63 | #define IBMASM_CMD_COMPLETE 1 | |
1da177e4 LT |
64 | #define IBMASM_CMD_FAILED 2 |
65 | ||
66 | #define IBMASM_CMD_TIMEOUT_NORMAL 45 | |
67 | #define IBMASM_CMD_TIMEOUT_EXTRA 240 | |
68 | ||
f5ccc842 | 69 | #define IBMASM_CMD_MAX_BUFFER_SIZE 0x8000 |
1da177e4 LT |
70 | |
71 | #define REVERSE_HEARTBEAT_TIMEOUT 120 | |
72 | ||
73 | #define HEARTBEAT_BUFFER_SIZE 0x400 | |
74 | ||
75 | #ifdef IA64 | |
76 | #define IBMASM_DRIVER_VPD "Lin64 6.08 " | |
77 | #else | |
78 | #define IBMASM_DRIVER_VPD "Lin32 6.08 " | |
79 | #endif | |
80 | ||
81 | #define SYSTEM_STATE_OS_UP 5 | |
82 | #define SYSTEM_STATE_OS_DOWN 4 | |
83 | ||
84 | #define IBMASM_NAME_SIZE 16 | |
85 | ||
86 | #define IBMASM_NUM_EVENTS 10 | |
87 | #define IBMASM_EVENT_MAX_SIZE 2048u | |
88 | ||
89 | ||
90 | struct command { | |
91 | struct list_head queue_node; | |
92 | wait_queue_head_t wait; | |
93 | unsigned char *buffer; | |
94 | size_t buffer_size; | |
95 | int status; | |
a045171f | 96 | struct kref kref; |
88187605 | 97 | spinlock_t *lock; |
1da177e4 | 98 | }; |
a045171f | 99 | #define to_command(c) container_of(c, struct command, kref) |
1da177e4 | 100 | |
a045171f | 101 | void ibmasm_free_command(struct kref *kref); |
1da177e4 LT |
102 | static inline void command_put(struct command *cmd) |
103 | { | |
88187605 | 104 | unsigned long flags; |
6a88231f | 105 | spinlock_t *lock = cmd->lock; |
88187605 | 106 | |
6a88231f | 107 | spin_lock_irqsave(lock, flags); |
a045171f | 108 | kref_put(&cmd->kref, ibmasm_free_command); |
6a88231f | 109 | spin_unlock_irqrestore(lock, flags); |
1da177e4 LT |
110 | } |
111 | ||
112 | static inline void command_get(struct command *cmd) | |
113 | { | |
a045171f | 114 | kref_get(&cmd->kref); |
1da177e4 LT |
115 | } |
116 | ||
117 | ||
118 | struct ibmasm_event { | |
119 | unsigned int serial_number; | |
120 | unsigned int data_size; | |
121 | unsigned char data[IBMASM_EVENT_MAX_SIZE]; | |
122 | }; | |
123 | ||
124 | struct event_buffer { | |
125 | struct ibmasm_event events[IBMASM_NUM_EVENTS]; | |
126 | unsigned int next_serial_number; | |
127 | unsigned int next_index; | |
128 | struct list_head readers; | |
129 | }; | |
130 | ||
131 | struct event_reader { | |
b8acb808 | 132 | int cancelled; |
1da177e4 LT |
133 | unsigned int next_serial_number; |
134 | wait_queue_head_t wait; | |
135 | struct list_head node; | |
136 | unsigned int data_size; | |
137 | unsigned char data[IBMASM_EVENT_MAX_SIZE]; | |
138 | }; | |
139 | ||
140 | struct reverse_heartbeat { | |
141 | wait_queue_head_t wait; | |
142 | unsigned int stopped; | |
143 | }; | |
144 | ||
278d72ae | 145 | struct ibmasm_remote { |
736ce432 VM |
146 | struct input_dev *keybd_dev; |
147 | struct input_dev *mouse_dev; | |
1da177e4 LT |
148 | }; |
149 | ||
1da177e4 LT |
150 | struct service_processor { |
151 | struct list_head node; | |
152 | spinlock_t lock; | |
153 | void __iomem *base_address; | |
154 | unsigned int irq; | |
155 | struct command *current_command; | |
156 | struct command *heartbeat; | |
157 | struct list_head command_queue; | |
158 | struct event_buffer *event_buffer; | |
159 | char dirname[IBMASM_NAME_SIZE]; | |
160 | char devname[IBMASM_NAME_SIZE]; | |
161 | unsigned int number; | |
736ce432 | 162 | struct ibmasm_remote remote; |
1da177e4 LT |
163 | int serial_line; |
164 | struct device *dev; | |
165 | }; | |
166 | ||
167 | /* command processing */ | |
da6b9c92 DT |
168 | struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size); |
169 | void ibmasm_exec_command(struct service_processor *sp, struct command *cmd); | |
170 | void ibmasm_wait_for_response(struct command *cmd, int timeout); | |
171 | void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size); | |
1da177e4 LT |
172 | |
173 | /* event processing */ | |
da6b9c92 DT |
174 | int ibmasm_event_buffer_init(struct service_processor *sp); |
175 | void ibmasm_event_buffer_exit(struct service_processor *sp); | |
176 | void ibmasm_receive_event(struct service_processor *sp, void *data, unsigned int data_size); | |
177 | void ibmasm_event_reader_register(struct service_processor *sp, struct event_reader *reader); | |
178 | void ibmasm_event_reader_unregister(struct service_processor *sp, struct event_reader *reader); | |
179 | int ibmasm_get_next_event(struct service_processor *sp, struct event_reader *reader); | |
180 | void ibmasm_cancel_next_event(struct event_reader *reader); | |
1da177e4 LT |
181 | |
182 | /* heartbeat - from SP to OS */ | |
da6b9c92 DT |
183 | void ibmasm_register_panic_notifier(void); |
184 | void ibmasm_unregister_panic_notifier(void); | |
185 | int ibmasm_heartbeat_init(struct service_processor *sp); | |
186 | void ibmasm_heartbeat_exit(struct service_processor *sp); | |
187 | void ibmasm_receive_heartbeat(struct service_processor *sp, void *message, size_t size); | |
1da177e4 LT |
188 | |
189 | /* reverse heartbeat - from OS to SP */ | |
da6b9c92 DT |
190 | void ibmasm_init_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb); |
191 | int ibmasm_start_reverse_heartbeat(struct service_processor *sp, struct reverse_heartbeat *rhb); | |
192 | void ibmasm_stop_reverse_heartbeat(struct reverse_heartbeat *rhb); | |
1da177e4 LT |
193 | |
194 | /* dot commands */ | |
da6b9c92 DT |
195 | void ibmasm_receive_message(struct service_processor *sp, void *data, int data_size); |
196 | int ibmasm_send_driver_vpd(struct service_processor *sp); | |
197 | int ibmasm_send_os_state(struct service_processor *sp, int os_state); | |
1da177e4 LT |
198 | |
199 | /* low level message processing */ | |
da6b9c92 DT |
200 | int ibmasm_send_i2o_message(struct service_processor *sp); |
201 | irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id); | |
1da177e4 LT |
202 | |
203 | /* remote console */ | |
da6b9c92 DT |
204 | void ibmasm_handle_mouse_interrupt(struct service_processor *sp); |
205 | int ibmasm_init_remote_input_dev(struct service_processor *sp); | |
206 | void ibmasm_free_remote_input_dev(struct service_processor *sp); | |
1da177e4 LT |
207 | |
208 | /* file system */ | |
da6b9c92 DT |
209 | int ibmasmfs_register(void); |
210 | void ibmasmfs_unregister(void); | |
211 | void ibmasmfs_add_sp(struct service_processor *sp); | |
1da177e4 LT |
212 | |
213 | /* uart */ | |
214 | #ifdef CONFIG_SERIAL_8250 | |
da6b9c92 DT |
215 | void ibmasm_register_uart(struct service_processor *sp); |
216 | void ibmasm_unregister_uart(struct service_processor *sp); | |
1da177e4 LT |
217 | #else |
218 | #define ibmasm_register_uart(sp) do { } while(0) | |
219 | #define ibmasm_unregister_uart(sp) do { } while(0) | |
220 | #endif |