1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * ipmi_smic_sm.c |
4 | * |
5 | * The state-machine driver for an IPMI SMIC driver |
6 | * |
7 | * It started as a copy of Corey Minyard's driver for the KSC interface |
8 | * and the kernel patch "mmcdev-patch-245" by HP |
9 | * |
10 | * modified by: Hannes Schulz <schulz@schwaar.com> |
11 | * ipmi@schwaar.com |
12 | * |
13 | * |
14 | * Corey Minyard's driver for the KSC interface has the following |
15 | * copyright notice: |
16 | * Copyright 2002 MontaVista Software Inc. |
17 | * |
18 | * the kernel patch "mmcdev-patch-245" by HP has the following |
19 | * copyright notice: |
20 | * (c) Copyright 2001 Grant Grundler (c) Copyright |
21 | * 2001 Hewlett-Packard Company |
22 | */ |
23 | |
24 | #define DEBUG /* So dev_dbg() is always available. */ |
25 | |
26 | #include <linux/kernel.h> /* For printk. */ |
27 | #include <linux/string.h> |
28 | #include <linux/module.h> |
29 | #include <linux/moduleparam.h> |
30 | #include <linux/ipmi_msgdefs.h> /* for completion codes */ |
31 | #include "ipmi_si_sm.h" |
32 | |
33 | /* smic_debug is a bit-field |
34 | * SMIC_DEBUG_ENABLE - turned on for now |
35 | * SMIC_DEBUG_MSG - commands and their responses |
36 | * SMIC_DEBUG_STATES - state machine |
37 | */ |
38 | #define SMIC_DEBUG_STATES 4 |
39 | #define SMIC_DEBUG_MSG 2 |
40 | #define SMIC_DEBUG_ENABLE 1 |
41 | |
42 | static int smic_debug = 1; |
43 | module_param(smic_debug, int, 0644); |
44 | MODULE_PARM_DESC(smic_debug, "debug bitmask, 1=enable, 2=messages, 4=states" ); |
45 | |
46 | enum smic_states { |
47 | SMIC_IDLE, |
48 | SMIC_START_OP, |
49 | SMIC_OP_OK, |
50 | SMIC_WRITE_START, |
51 | SMIC_WRITE_NEXT, |
52 | SMIC_WRITE_END, |
53 | SMIC_WRITE2READ, |
54 | SMIC_READ_START, |
55 | SMIC_READ_NEXT, |
56 | SMIC_READ_END, |
57 | SMIC_HOSED |
58 | }; |
59 | |
60 | #define MAX_SMIC_READ_SIZE 80 |
61 | #define MAX_SMIC_WRITE_SIZE 80 |
62 | #define SMIC_MAX_ERROR_RETRIES 3 |
63 | |
64 | /* Timeouts in microseconds. */ |
65 | #define SMIC_RETRY_TIMEOUT (2*USEC_PER_SEC) |
66 | |
67 | /* SMIC Flags Register Bits */ |
68 | #define SMIC_RX_DATA_READY 0x80 |
69 | #define SMIC_TX_DATA_READY 0x40 |
70 | |
71 | /* |
72 | * SMIC_SMI and SMIC_EVM_DATA_AVAIL are only used by |
73 | * a few systems, and then only by Systems Management |
74 | * Interrupts, not by the OS. Always ignore these bits. |
75 | * |
76 | */ |
77 | #define SMIC_SMI 0x10 |
78 | #define SMIC_EVM_DATA_AVAIL 0x08 |
79 | #define SMIC_SMS_DATA_AVAIL 0x04 |
80 | #define SMIC_FLAG_BSY 0x01 |
81 | |
82 | /* SMIC Error Codes */ |
83 | #define EC_NO_ERROR 0x00 |
84 | #define EC_ABORTED 0x01 |
85 | #define EC_ILLEGAL_CONTROL 0x02 |
86 | #define EC_NO_RESPONSE 0x03 |
87 | #define EC_ILLEGAL_COMMAND 0x04 |
88 | #define EC_BUFFER_FULL 0x05 |
89 | |
90 | struct si_sm_data { |
91 | enum smic_states state; |
92 | struct si_sm_io *io; |
93 | unsigned char write_data[MAX_SMIC_WRITE_SIZE]; |
94 | int write_pos; |
95 | int write_count; |
96 | int orig_write_count; |
97 | unsigned char read_data[MAX_SMIC_READ_SIZE]; |
98 | int read_pos; |
99 | int truncated; |
100 | unsigned int error_retries; |
101 | long smic_timeout; |
102 | }; |
103 | |
104 | static unsigned int init_smic_data(struct si_sm_data *smic, |
105 | struct si_sm_io *io) |
106 | { |
107 | smic->state = SMIC_IDLE; |
108 | smic->io = io; |
109 | smic->write_pos = 0; |
110 | smic->write_count = 0; |
111 | smic->orig_write_count = 0; |
112 | smic->read_pos = 0; |
113 | smic->error_retries = 0; |
114 | smic->truncated = 0; |
115 | smic->smic_timeout = SMIC_RETRY_TIMEOUT; |
116 | |
117 | /* We use 3 bytes of I/O. */ |
118 | return 3; |
119 | } |
120 | |
121 | static int start_smic_transaction(struct si_sm_data *smic, |
122 | unsigned char *data, unsigned int size) |
123 | { |
124 | unsigned int i; |
125 | |
126 | if (size < 2) |
127 | return IPMI_REQ_LEN_INVALID_ERR; |
128 | if (size > MAX_SMIC_WRITE_SIZE) |
129 | return IPMI_REQ_LEN_EXCEEDED_ERR; |
130 | |
131 | if ((smic->state != SMIC_IDLE) && (smic->state != SMIC_HOSED)) { |
132 | dev_warn(smic->io->dev, |
133 | "SMIC in invalid state %d\n" , smic->state); |
134 | return IPMI_NOT_IN_MY_STATE_ERR; |
135 | } |
136 | |
137 | if (smic_debug & SMIC_DEBUG_MSG) { |
138 | dev_dbg(smic->io->dev, "%s -" , __func__); |
139 | for (i = 0; i < size; i++) |
140 | pr_cont(" %02x" , data[i]); |
141 | pr_cont("\n" ); |
142 | } |
143 | smic->error_retries = 0; |
144 | memcpy(smic->write_data, data, size); |
145 | smic->write_count = size; |
146 | smic->orig_write_count = size; |
147 | smic->write_pos = 0; |
148 | smic->read_pos = 0; |
149 | smic->state = SMIC_START_OP; |
150 | smic->smic_timeout = SMIC_RETRY_TIMEOUT; |
151 | return 0; |
152 | } |
153 | |
154 | static int smic_get_result(struct si_sm_data *smic, |
155 | unsigned char *data, unsigned int length) |
156 | { |
157 | int i; |
158 | |
159 | if (smic_debug & SMIC_DEBUG_MSG) { |
160 | dev_dbg(smic->io->dev, "smic_get result -" ); |
161 | for (i = 0; i < smic->read_pos; i++) |
162 | pr_cont(" %02x" , smic->read_data[i]); |
163 | pr_cont("\n" ); |
164 | } |
165 | if (length < smic->read_pos) { |
166 | smic->read_pos = length; |
167 | smic->truncated = 1; |
168 | } |
169 | memcpy(data, smic->read_data, smic->read_pos); |
170 | |
171 | if ((length >= 3) && (smic->read_pos < 3)) { |
172 | data[2] = IPMI_ERR_UNSPECIFIED; |
173 | smic->read_pos = 3; |
174 | } |
175 | if (smic->truncated) { |
176 | data[2] = IPMI_ERR_MSG_TRUNCATED; |
177 | smic->truncated = 0; |
178 | } |
179 | return smic->read_pos; |
180 | } |
181 | |
182 | static inline unsigned char read_smic_flags(struct si_sm_data *smic) |
183 | { |
184 | return smic->io->inputb(smic->io, 2); |
185 | } |
186 | |
187 | static inline unsigned char read_smic_status(struct si_sm_data *smic) |
188 | { |
189 | return smic->io->inputb(smic->io, 1); |
190 | } |
191 | |
192 | static inline unsigned char read_smic_data(struct si_sm_data *smic) |
193 | { |
194 | return smic->io->inputb(smic->io, 0); |
195 | } |
196 | |
197 | static inline void write_smic_flags(struct si_sm_data *smic, |
198 | unsigned char flags) |
199 | { |
200 | smic->io->outputb(smic->io, 2, flags); |
201 | } |
202 | |
203 | static inline void write_smic_control(struct si_sm_data *smic, |
204 | unsigned char control) |
205 | { |
206 | smic->io->outputb(smic->io, 1, control); |
207 | } |
208 | |
209 | static inline void write_si_sm_data(struct si_sm_data *smic, |
210 | unsigned char data) |
211 | { |
212 | smic->io->outputb(smic->io, 0, data); |
213 | } |
214 | |
215 | static inline void start_error_recovery(struct si_sm_data *smic, char *reason) |
216 | { |
217 | (smic->error_retries)++; |
218 | if (smic->error_retries > SMIC_MAX_ERROR_RETRIES) { |
219 | if (smic_debug & SMIC_DEBUG_ENABLE) |
220 | pr_warn("ipmi_smic_drv: smic hosed: %s\n" , reason); |
221 | smic->state = SMIC_HOSED; |
222 | } else { |
223 | smic->write_count = smic->orig_write_count; |
224 | smic->write_pos = 0; |
225 | smic->read_pos = 0; |
226 | smic->state = SMIC_START_OP; |
227 | smic->smic_timeout = SMIC_RETRY_TIMEOUT; |
228 | } |
229 | } |
230 | |
231 | static inline void write_next_byte(struct si_sm_data *smic) |
232 | { |
233 | write_si_sm_data(smic, data: smic->write_data[smic->write_pos]); |
234 | (smic->write_pos)++; |
235 | (smic->write_count)--; |
236 | } |
237 | |
238 | static inline void read_next_byte(struct si_sm_data *smic) |
239 | { |
240 | if (smic->read_pos >= MAX_SMIC_READ_SIZE) { |
241 | read_smic_data(smic); |
242 | smic->truncated = 1; |
243 | } else { |
244 | smic->read_data[smic->read_pos] = read_smic_data(smic); |
245 | smic->read_pos++; |
246 | } |
247 | } |
248 | |
249 | /* SMIC Control/Status Code Components */ |
250 | #define SMIC_GET_STATUS 0x00 /* Control form's name */ |
251 | #define SMIC_READY 0x00 /* Status form's name */ |
252 | #define SMIC_WR_START 0x01 /* Unified Control/Status names... */ |
253 | #define SMIC_WR_NEXT 0x02 |
254 | #define SMIC_WR_END 0x03 |
255 | #define SMIC_RD_START 0x04 |
256 | #define SMIC_RD_NEXT 0x05 |
257 | #define SMIC_RD_END 0x06 |
258 | #define SMIC_CODE_MASK 0x0f |
259 | |
260 | #define SMIC_CONTROL 0x00 |
261 | #define SMIC_STATUS 0x80 |
262 | #define SMIC_CS_MASK 0x80 |
263 | |
264 | #define SMIC_SMS 0x40 |
265 | #define SMIC_SMM 0x60 |
266 | #define SMIC_STREAM_MASK 0x60 |
267 | |
268 | /* SMIC Control Codes */ |
269 | #define SMIC_CC_SMS_GET_STATUS (SMIC_CONTROL|SMIC_SMS|SMIC_GET_STATUS) |
270 | #define SMIC_CC_SMS_WR_START (SMIC_CONTROL|SMIC_SMS|SMIC_WR_START) |
271 | #define SMIC_CC_SMS_WR_NEXT (SMIC_CONTROL|SMIC_SMS|SMIC_WR_NEXT) |
272 | #define SMIC_CC_SMS_WR_END (SMIC_CONTROL|SMIC_SMS|SMIC_WR_END) |
273 | #define SMIC_CC_SMS_RD_START (SMIC_CONTROL|SMIC_SMS|SMIC_RD_START) |
274 | #define SMIC_CC_SMS_RD_NEXT (SMIC_CONTROL|SMIC_SMS|SMIC_RD_NEXT) |
275 | #define SMIC_CC_SMS_RD_END (SMIC_CONTROL|SMIC_SMS|SMIC_RD_END) |
276 | |
277 | #define SMIC_CC_SMM_GET_STATUS (SMIC_CONTROL|SMIC_SMM|SMIC_GET_STATUS) |
278 | #define SMIC_CC_SMM_WR_START (SMIC_CONTROL|SMIC_SMM|SMIC_WR_START) |
279 | #define SMIC_CC_SMM_WR_NEXT (SMIC_CONTROL|SMIC_SMM|SMIC_WR_NEXT) |
280 | #define SMIC_CC_SMM_WR_END (SMIC_CONTROL|SMIC_SMM|SMIC_WR_END) |
281 | #define SMIC_CC_SMM_RD_START (SMIC_CONTROL|SMIC_SMM|SMIC_RD_START) |
282 | #define SMIC_CC_SMM_RD_NEXT (SMIC_CONTROL|SMIC_SMM|SMIC_RD_NEXT) |
283 | #define SMIC_CC_SMM_RD_END (SMIC_CONTROL|SMIC_SMM|SMIC_RD_END) |
284 | |
285 | /* SMIC Status Codes */ |
286 | #define SMIC_SC_SMS_READY (SMIC_STATUS|SMIC_SMS|SMIC_READY) |
287 | #define SMIC_SC_SMS_WR_START (SMIC_STATUS|SMIC_SMS|SMIC_WR_START) |
288 | #define SMIC_SC_SMS_WR_NEXT (SMIC_STATUS|SMIC_SMS|SMIC_WR_NEXT) |
289 | #define SMIC_SC_SMS_WR_END (SMIC_STATUS|SMIC_SMS|SMIC_WR_END) |
290 | #define SMIC_SC_SMS_RD_START (SMIC_STATUS|SMIC_SMS|SMIC_RD_START) |
291 | #define SMIC_SC_SMS_RD_NEXT (SMIC_STATUS|SMIC_SMS|SMIC_RD_NEXT) |
292 | #define SMIC_SC_SMS_RD_END (SMIC_STATUS|SMIC_SMS|SMIC_RD_END) |
293 | |
294 | #define SMIC_SC_SMM_READY (SMIC_STATUS|SMIC_SMM|SMIC_READY) |
295 | #define SMIC_SC_SMM_WR_START (SMIC_STATUS|SMIC_SMM|SMIC_WR_START) |
296 | #define SMIC_SC_SMM_WR_NEXT (SMIC_STATUS|SMIC_SMM|SMIC_WR_NEXT) |
297 | #define SMIC_SC_SMM_WR_END (SMIC_STATUS|SMIC_SMM|SMIC_WR_END) |
298 | #define SMIC_SC_SMM_RD_START (SMIC_STATUS|SMIC_SMM|SMIC_RD_START) |
299 | #define SMIC_SC_SMM_RD_NEXT (SMIC_STATUS|SMIC_SMM|SMIC_RD_NEXT) |
300 | #define SMIC_SC_SMM_RD_END (SMIC_STATUS|SMIC_SMM|SMIC_RD_END) |
301 | |
302 | /* these are the control/status codes we actually use |
303 | SMIC_CC_SMS_GET_STATUS 0x40 |
304 | SMIC_CC_SMS_WR_START 0x41 |
305 | SMIC_CC_SMS_WR_NEXT 0x42 |
306 | SMIC_CC_SMS_WR_END 0x43 |
307 | SMIC_CC_SMS_RD_START 0x44 |
308 | SMIC_CC_SMS_RD_NEXT 0x45 |
309 | SMIC_CC_SMS_RD_END 0x46 |
310 | |
311 | SMIC_SC_SMS_READY 0xC0 |
312 | SMIC_SC_SMS_WR_START 0xC1 |
313 | SMIC_SC_SMS_WR_NEXT 0xC2 |
314 | SMIC_SC_SMS_WR_END 0xC3 |
315 | SMIC_SC_SMS_RD_START 0xC4 |
316 | SMIC_SC_SMS_RD_NEXT 0xC5 |
317 | SMIC_SC_SMS_RD_END 0xC6 |
318 | */ |
319 | |
320 | static enum si_sm_result smic_event(struct si_sm_data *smic, long time) |
321 | { |
322 | unsigned char status; |
323 | unsigned char flags; |
324 | unsigned char data; |
325 | |
326 | if (smic->state == SMIC_HOSED) { |
327 | init_smic_data(smic, io: smic->io); |
328 | return SI_SM_HOSED; |
329 | } |
330 | if (smic->state != SMIC_IDLE) { |
331 | if (smic_debug & SMIC_DEBUG_STATES) |
332 | dev_dbg(smic->io->dev, |
333 | "%s - smic->smic_timeout = %ld, time = %ld\n" , |
334 | __func__, smic->smic_timeout, time); |
335 | /* |
336 | * FIXME: smic_event is sometimes called with time > |
337 | * SMIC_RETRY_TIMEOUT |
338 | */ |
339 | if (time < SMIC_RETRY_TIMEOUT) { |
340 | smic->smic_timeout -= time; |
341 | if (smic->smic_timeout < 0) { |
342 | start_error_recovery(smic, reason: "smic timed out." ); |
343 | return SI_SM_CALL_WITH_DELAY; |
344 | } |
345 | } |
346 | } |
347 | flags = read_smic_flags(smic); |
348 | if (flags & SMIC_FLAG_BSY) |
349 | return SI_SM_CALL_WITH_DELAY; |
350 | |
351 | status = read_smic_status(smic); |
352 | if (smic_debug & SMIC_DEBUG_STATES) |
353 | dev_dbg(smic->io->dev, |
354 | "%s - state = %d, flags = 0x%02x, status = 0x%02x\n" , |
355 | __func__, smic->state, flags, status); |
356 | |
357 | switch (smic->state) { |
358 | case SMIC_IDLE: |
359 | /* in IDLE we check for available messages */ |
360 | if (flags & SMIC_SMS_DATA_AVAIL) |
361 | return SI_SM_ATTN; |
362 | return SI_SM_IDLE; |
363 | |
364 | case SMIC_START_OP: |
365 | /* sanity check whether smic is really idle */ |
366 | write_smic_control(smic, SMIC_CC_SMS_GET_STATUS); |
367 | write_smic_flags(smic, flags: flags | SMIC_FLAG_BSY); |
368 | smic->state = SMIC_OP_OK; |
369 | break; |
370 | |
371 | case SMIC_OP_OK: |
372 | if (status != SMIC_SC_SMS_READY) { |
373 | /* this should not happen */ |
374 | start_error_recovery(smic, |
375 | reason: "state = SMIC_OP_OK," |
376 | " status != SMIC_SC_SMS_READY" ); |
377 | return SI_SM_CALL_WITH_DELAY; |
378 | } |
379 | /* OK so far; smic is idle let us start ... */ |
380 | write_smic_control(smic, SMIC_CC_SMS_WR_START); |
381 | write_next_byte(smic); |
382 | write_smic_flags(smic, flags: flags | SMIC_FLAG_BSY); |
383 | smic->state = SMIC_WRITE_START; |
384 | break; |
385 | |
386 | case SMIC_WRITE_START: |
387 | if (status != SMIC_SC_SMS_WR_START) { |
388 | start_error_recovery(smic, |
389 | reason: "state = SMIC_WRITE_START, " |
390 | "status != SMIC_SC_SMS_WR_START" ); |
391 | return SI_SM_CALL_WITH_DELAY; |
392 | } |
393 | /* |
394 | * we must not issue WR_(NEXT|END) unless |
395 | * TX_DATA_READY is set |
396 | * */ |
397 | if (flags & SMIC_TX_DATA_READY) { |
398 | if (smic->write_count == 1) { |
399 | /* last byte */ |
400 | write_smic_control(smic, SMIC_CC_SMS_WR_END); |
401 | smic->state = SMIC_WRITE_END; |
402 | } else { |
403 | write_smic_control(smic, SMIC_CC_SMS_WR_NEXT); |
404 | smic->state = SMIC_WRITE_NEXT; |
405 | } |
406 | write_next_byte(smic); |
407 | write_smic_flags(smic, flags: flags | SMIC_FLAG_BSY); |
408 | } else |
409 | return SI_SM_CALL_WITH_DELAY; |
410 | break; |
411 | |
412 | case SMIC_WRITE_NEXT: |
413 | if (status != SMIC_SC_SMS_WR_NEXT) { |
414 | start_error_recovery(smic, |
415 | reason: "state = SMIC_WRITE_NEXT, " |
416 | "status != SMIC_SC_SMS_WR_NEXT" ); |
417 | return SI_SM_CALL_WITH_DELAY; |
418 | } |
419 | /* this is the same code as in SMIC_WRITE_START */ |
420 | if (flags & SMIC_TX_DATA_READY) { |
421 | if (smic->write_count == 1) { |
422 | write_smic_control(smic, SMIC_CC_SMS_WR_END); |
423 | smic->state = SMIC_WRITE_END; |
424 | } else { |
425 | write_smic_control(smic, SMIC_CC_SMS_WR_NEXT); |
426 | smic->state = SMIC_WRITE_NEXT; |
427 | } |
428 | write_next_byte(smic); |
429 | write_smic_flags(smic, flags: flags | SMIC_FLAG_BSY); |
430 | } else |
431 | return SI_SM_CALL_WITH_DELAY; |
432 | break; |
433 | |
434 | case SMIC_WRITE_END: |
435 | if (status != SMIC_SC_SMS_WR_END) { |
436 | start_error_recovery(smic, |
437 | reason: "state = SMIC_WRITE_END, " |
438 | "status != SMIC_SC_SMS_WR_END" ); |
439 | return SI_SM_CALL_WITH_DELAY; |
440 | } |
441 | /* data register holds an error code */ |
442 | data = read_smic_data(smic); |
443 | if (data != 0) { |
444 | if (smic_debug & SMIC_DEBUG_ENABLE) |
445 | dev_dbg(smic->io->dev, |
446 | "SMIC_WRITE_END: data = %02x\n" , |
447 | data); |
448 | start_error_recovery(smic, |
449 | reason: "state = SMIC_WRITE_END, " |
450 | "data != SUCCESS" ); |
451 | return SI_SM_CALL_WITH_DELAY; |
452 | } else |
453 | smic->state = SMIC_WRITE2READ; |
454 | break; |
455 | |
456 | case SMIC_WRITE2READ: |
457 | /* |
458 | * we must wait for RX_DATA_READY to be set before we |
459 | * can continue |
460 | */ |
461 | if (flags & SMIC_RX_DATA_READY) { |
462 | write_smic_control(smic, SMIC_CC_SMS_RD_START); |
463 | write_smic_flags(smic, flags: flags | SMIC_FLAG_BSY); |
464 | smic->state = SMIC_READ_START; |
465 | } else |
466 | return SI_SM_CALL_WITH_DELAY; |
467 | break; |
468 | |
469 | case SMIC_READ_START: |
470 | if (status != SMIC_SC_SMS_RD_START) { |
471 | start_error_recovery(smic, |
472 | reason: "state = SMIC_READ_START, " |
473 | "status != SMIC_SC_SMS_RD_START" ); |
474 | return SI_SM_CALL_WITH_DELAY; |
475 | } |
476 | if (flags & SMIC_RX_DATA_READY) { |
477 | read_next_byte(smic); |
478 | write_smic_control(smic, SMIC_CC_SMS_RD_NEXT); |
479 | write_smic_flags(smic, flags: flags | SMIC_FLAG_BSY); |
480 | smic->state = SMIC_READ_NEXT; |
481 | } else |
482 | return SI_SM_CALL_WITH_DELAY; |
483 | break; |
484 | |
485 | case SMIC_READ_NEXT: |
486 | switch (status) { |
487 | /* |
488 | * smic tells us that this is the last byte to be read |
489 | * --> clean up |
490 | */ |
491 | case SMIC_SC_SMS_RD_END: |
492 | read_next_byte(smic); |
493 | write_smic_control(smic, SMIC_CC_SMS_RD_END); |
494 | write_smic_flags(smic, flags: flags | SMIC_FLAG_BSY); |
495 | smic->state = SMIC_READ_END; |
496 | break; |
497 | case SMIC_SC_SMS_RD_NEXT: |
498 | if (flags & SMIC_RX_DATA_READY) { |
499 | read_next_byte(smic); |
500 | write_smic_control(smic, SMIC_CC_SMS_RD_NEXT); |
501 | write_smic_flags(smic, flags: flags | SMIC_FLAG_BSY); |
502 | smic->state = SMIC_READ_NEXT; |
503 | } else |
504 | return SI_SM_CALL_WITH_DELAY; |
505 | break; |
506 | default: |
507 | start_error_recovery( |
508 | smic, |
509 | reason: "state = SMIC_READ_NEXT, " |
510 | "status != SMIC_SC_SMS_RD_(NEXT|END)" ); |
511 | return SI_SM_CALL_WITH_DELAY; |
512 | } |
513 | break; |
514 | |
515 | case SMIC_READ_END: |
516 | if (status != SMIC_SC_SMS_READY) { |
517 | start_error_recovery(smic, |
518 | reason: "state = SMIC_READ_END, " |
519 | "status != SMIC_SC_SMS_READY" ); |
520 | return SI_SM_CALL_WITH_DELAY; |
521 | } |
522 | data = read_smic_data(smic); |
523 | /* data register holds an error code */ |
524 | if (data != 0) { |
525 | if (smic_debug & SMIC_DEBUG_ENABLE) |
526 | dev_dbg(smic->io->dev, |
527 | "SMIC_READ_END: data = %02x\n" , |
528 | data); |
529 | start_error_recovery(smic, |
530 | reason: "state = SMIC_READ_END, " |
531 | "data != SUCCESS" ); |
532 | return SI_SM_CALL_WITH_DELAY; |
533 | } else { |
534 | smic->state = SMIC_IDLE; |
535 | return SI_SM_TRANSACTION_COMPLETE; |
536 | } |
537 | |
538 | case SMIC_HOSED: |
539 | init_smic_data(smic, io: smic->io); |
540 | return SI_SM_HOSED; |
541 | |
542 | default: |
543 | if (smic_debug & SMIC_DEBUG_ENABLE) { |
544 | dev_dbg(smic->io->dev, |
545 | "smic->state = %d\n" , smic->state); |
546 | start_error_recovery(smic, reason: "state = UNKNOWN" ); |
547 | return SI_SM_CALL_WITH_DELAY; |
548 | } |
549 | } |
550 | smic->smic_timeout = SMIC_RETRY_TIMEOUT; |
551 | return SI_SM_CALL_WITHOUT_DELAY; |
552 | } |
553 | |
554 | static int smic_detect(struct si_sm_data *smic) |
555 | { |
556 | /* |
557 | * It's impossible for the SMIC fnags register to be all 1's, |
558 | * (assuming a properly functioning, self-initialized BMC) |
559 | * but that's what you get from reading a bogus address, so we |
560 | * test that first. |
561 | */ |
562 | if (read_smic_flags(smic) == 0xff) |
563 | return 1; |
564 | |
565 | return 0; |
566 | } |
567 | |
568 | static void smic_cleanup(struct si_sm_data *kcs) |
569 | { |
570 | } |
571 | |
572 | static int smic_size(void) |
573 | { |
574 | return sizeof(struct si_sm_data); |
575 | } |
576 | |
577 | const struct si_sm_handlers smic_smi_handlers = { |
578 | .init_data = init_smic_data, |
579 | .start_transaction = start_smic_transaction, |
580 | .get_result = smic_get_result, |
581 | .event = smic_event, |
582 | .detect = smic_detect, |
583 | .cleanup = smic_cleanup, |
584 | .size = smic_size, |
585 | }; |
586 | |