xref: /OK3568_Linux_fs/kernel/drivers/char/ipmi/ipmi_smic_sm.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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