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