ipmi_si_intf.c 87.4 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
7
8
9
10
11
/*
 * ipmi_si.c
 *
 * The interface to the IPMI driver for the system interfaces (KCS, SMIC,
 * BT).
 *
 * Author: MontaVista Software, Inc.
 *         Corey Minyard <minyard@mvista.com>
 *         source@mvista.com
 *
 * Copyright 2002 MontaVista Software Inc.
12
 * Copyright 2006 IBM Corp., Christian Krafft <krafft@de.ibm.com>
Linus Torvalds's avatar
Linus Torvalds committed
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 *
 *  This program is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; either version 2 of the License, or (at your
 *  option) any later version.
 *
 *
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
 *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
 *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * This file holds the "policy" for the interface to the SMI state
 * machine.  It does the configuration, handles timers and interrupts,
 * and drives the real SMI state machine.
 */

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <asm/system.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/ioport.h>
54
#include <linux/notifier.h>
55
#include <linux/mutex.h>
Matt Domsch's avatar
Matt Domsch committed
56
#include <linux/kthread.h>
Linus Torvalds's avatar
Linus Torvalds committed
57
58
59
60
61
62
63
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <linux/rcupdate.h>
#include <linux/ipmi_smi.h>
#include <asm/io.h>
#include "ipmi_si_sm.h"
#include <linux/init.h>
64
#include <linux/dmi.h>
65
66
#include <linux/string.h>
#include <linux/ctype.h>
67
#include <linux/pnp.h>
68

69
#ifdef CONFIG_PPC_OF
70
71
#include <linux/of_device.h>
#include <linux/of_platform.h>
72
73
#endif

74
#define PFX "ipmi_si: "
Linus Torvalds's avatar
Linus Torvalds committed
75
76
77
78
79
80
81
82
83

/* Measure times between events in the driver. */
#undef DEBUG_TIMING

/* Call every 10 ms. */
#define SI_TIMEOUT_TIME_USEC	10000
#define SI_USEC_PER_JIFFY	(1000000/HZ)
#define SI_TIMEOUT_JIFFIES	(SI_TIMEOUT_TIME_USEC/SI_USEC_PER_JIFFY)
#define SI_SHORT_TIMEOUT_USEC  250 /* .25ms when the SM request a
84
				      short timeout */
Linus Torvalds's avatar
Linus Torvalds committed
85
86
87
88
89
90
91
92
93

enum si_intf_state {
	SI_NORMAL,
	SI_GETTING_FLAGS,
	SI_GETTING_EVENTS,
	SI_CLEARING_FLAGS,
	SI_CLEARING_FLAGS_THEN_SET_IRQ,
	SI_GETTING_MESSAGES,
	SI_ENABLE_INTERRUPTS1,
Corey Minyard's avatar
Corey Minyard committed
94
95
96
	SI_ENABLE_INTERRUPTS2,
	SI_DISABLE_INTERRUPTS1,
	SI_DISABLE_INTERRUPTS2
Linus Torvalds's avatar
Linus Torvalds committed
97
98
99
	/* FIXME - add watchdog stuff. */
};

100
101
102
103
104
/* Some BT-specific defines we need here. */
#define IPMI_BT_INTMASK_REG		2
#define IPMI_BT_INTMASK_CLEAR_IRQ_BIT	2
#define IPMI_BT_INTMASK_ENABLE_IRQ_BIT	1

Linus Torvalds's avatar
Linus Torvalds committed
105
106
107
enum si_type {
    SI_KCS, SI_SMIC, SI_BT
};
108
static char *si_to_str[] = { "kcs", "smic", "bt" };
Linus Torvalds's avatar
Linus Torvalds committed
109

110
111
112
113
114
115
116
117
enum ipmi_addr_src {
	SI_INVALID = 0, SI_HOTMOD, SI_HARDCODED, SI_SPMI, SI_ACPI, SI_SMBIOS,
	SI_PCI,	SI_DEVICETREE, SI_DEFAULT
};
static char *ipmi_addr_src_to_str[] = { NULL, "hotmod", "hardcoded", "SPMI",
					"ACPI", "SMBIOS", "PCI",
					"device-tree", "default" };

118
119
#define DEVICE_NAME "ipmi_si"

120
121
122
123
124
static struct platform_driver ipmi_driver = {
	.driver = {
		.name = DEVICE_NAME,
		.bus = &platform_bus_type
	}
125
};
126

127
128
129
130

/*
 * Indexes into stats[] in smi_info below.
 */
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
enum si_stat_indexes {
	/*
	 * Number of times the driver requested a timer while an operation
	 * was in progress.
	 */
	SI_STAT_short_timeouts = 0,

	/*
	 * Number of times the driver requested a timer while nothing was in
	 * progress.
	 */
	SI_STAT_long_timeouts,

	/* Number of times the interface was idle while being polled. */
	SI_STAT_idles,

	/* Number of interrupts the driver handled. */
	SI_STAT_interrupts,

	/* Number of time the driver got an ATTN from the hardware. */
	SI_STAT_attentions,
152

153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
	/* Number of times the driver requested flags from the hardware. */
	SI_STAT_flag_fetches,

	/* Number of times the hardware didn't follow the state machine. */
	SI_STAT_hosed_count,

	/* Number of completed messages. */
	SI_STAT_complete_transactions,

	/* Number of IPMI events received from the hardware. */
	SI_STAT_events,

	/* Number of watchdog pretimeouts. */
	SI_STAT_watchdog_pretimeouts,

	/* Number of asyncronous messages received. */
	SI_STAT_incoming_messages,


	/* This *must* remain last, add new values above this. */
	SI_NUM_STATS
};
175

176
struct smi_info {
Corey Minyard's avatar
Corey Minyard committed
177
	int                    intf_num;
Linus Torvalds's avatar
Linus Torvalds committed
178
179
180
181
182
183
184
185
186
187
188
	ipmi_smi_t             intf;
	struct si_sm_data      *si_sm;
	struct si_sm_handlers  *handlers;
	enum si_type           si_type;
	spinlock_t             si_lock;
	spinlock_t             msg_lock;
	struct list_head       xmit_msgs;
	struct list_head       hp_xmit_msgs;
	struct ipmi_smi_msg    *curr_msg;
	enum si_intf_state     si_state;

189
190
191
192
	/*
	 * Used to handle the various types of I/O that can occur with
	 * IPMI
	 */
Linus Torvalds's avatar
Linus Torvalds committed
193
194
195
196
197
198
	struct si_sm_io io;
	int (*io_setup)(struct smi_info *info);
	void (*io_cleanup)(struct smi_info *info);
	int (*irq_setup)(struct smi_info *info);
	void (*irq_cleanup)(struct smi_info *info);
	unsigned int io_size;
199
	enum ipmi_addr_src addr_source; /* ACPI, PCI, SMBIOS, hardcode, etc. */
200
201
	void (*addr_source_cleanup)(struct smi_info *info);
	void *addr_source_data;
Linus Torvalds's avatar
Linus Torvalds committed
202

203
204
205
206
207
	/*
	 * Per-OEM handler, called from handle_flags().  Returns 1
	 * when handle_flags() needs to be re-run or 0 indicating it
	 * set si_state itself.
	 */
208
209
	int (*oem_data_avail_handler)(struct smi_info *smi_info);

210
211
212
213
214
	/*
	 * Flags from the last GET_MSG_FLAGS command, used when an ATTN
	 * is set to hold the flags until we are done handling everything
	 * from the flags.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
215
216
217
#define RECEIVE_MSG_AVAIL	0x01
#define EVENT_MSG_BUFFER_FULL	0x02
#define WDT_PRE_TIMEOUT_INT	0x08
218
219
220
221
#define OEM0_DATA_AVAIL     0x20
#define OEM1_DATA_AVAIL     0x40
#define OEM2_DATA_AVAIL     0x80
#define OEM_DATA_AVAIL      (OEM0_DATA_AVAIL | \
222
223
			     OEM1_DATA_AVAIL | \
			     OEM2_DATA_AVAIL)
Linus Torvalds's avatar
Linus Torvalds committed
224
225
	unsigned char       msg_flags;

226
227
228
	/* Does the BMC have an event buffer? */
	char		    has_event_buffer;

229
230
231
232
	/*
	 * If set to true, this will request events the next time the
	 * state machine is idle.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
233
234
	atomic_t            req_events;

235
236
237
238
239
	/*
	 * If true, run the state machine to completion on every send
	 * call.  Generally used after a panic to make sure stuff goes
	 * out.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
240
241
242
243
244
	int                 run_to_completion;

	/* The I/O port of an SI interface. */
	int                 port;

245
246
247
248
249
	/*
	 * The space between start addresses of the two ports.  For
	 * instance, if the first port is 0xca2 and the spacing is 4, then
	 * the second port is 0xca6.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
250
251
252
253
254
255
256
257
258
259
260
261
	unsigned int        spacing;

	/* zero if no irq; */
	int                 irq;

	/* The timer for this si. */
	struct timer_list   si_timer;

	/* The time (in jiffies) the last timeout occurred at. */
	unsigned long       last_timeout_jiffies;

	/* Used to gracefully stop the timer without race conditions. */
Corey Minyard's avatar
Corey Minyard committed
262
	atomic_t            stop_operation;
Linus Torvalds's avatar
Linus Torvalds committed
263

264
265
266
267
268
269
	/*
	 * The driver will disable interrupts when it gets into a
	 * situation where it cannot handle messages due to lack of
	 * memory.  Once that situation clears up, it will re-enable
	 * interrupts.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
270
271
	int interrupt_disabled;

272
	/* From the get device id response... */
273
	struct ipmi_device_id device_id;
Linus Torvalds's avatar
Linus Torvalds committed
274

275
276
277
278
	/* Driver model stuff. */
	struct device *dev;
	struct platform_device *pdev;

279
280
281
282
	/*
	 * True if we allocated the device, false if it came from
	 * someplace else (like PCI).
	 */
283
284
	int dev_registered;

Linus Torvalds's avatar
Linus Torvalds committed
285
286
287
288
	/* Slave address, could be reported from DMI. */
	unsigned char slave_addr;

	/* Counters and things for the proc filesystem. */
289
	atomic_t stats[SI_NUM_STATS];
Corey Minyard's avatar
Corey Minyard committed
290

291
	struct task_struct *thread;
292
293

	struct list_head link;
Linus Torvalds's avatar
Linus Torvalds committed
294
295
};

296
297
298
299
300
#define smi_inc_stat(smi, stat) \
	atomic_inc(&(smi)->stats[SI_STAT_ ## stat])
#define smi_get_stat(smi, stat) \
	((unsigned int) atomic_read(&(smi)->stats[SI_STAT_ ## stat]))

301
302
303
304
305
#define SI_MAX_PARMS 4

static int force_kipmid[SI_MAX_PARMS];
static int num_force_kipmid;

306
307
308
static unsigned int kipmid_max_busy_us[SI_MAX_PARMS];
static int num_max_busy_us;

309
310
static int unload_when_empty = 1;

311
static int add_smi(struct smi_info *smi);
312
static int try_smi_init(struct smi_info *smi);
313
static void cleanup_one_si(struct smi_info *to_clean);
314

315
static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
316
static int register_xaction_notifier(struct notifier_block *nb)
317
{
318
	return atomic_notifier_chain_register(&xaction_notifier_list, nb);
319
320
}

Linus Torvalds's avatar
Linus Torvalds committed
321
322
323
324
static void deliver_recv_msg(struct smi_info *smi_info,
			     struct ipmi_smi_msg *msg)
{
	/* Deliver the message to the upper layer with the lock
325
	   released. */
326
327
328
329
330
331
332
333

	if (smi_info->run_to_completion) {
		ipmi_smi_msg_received(smi_info->intf, msg);
	} else {
		spin_unlock(&(smi_info->si_lock));
		ipmi_smi_msg_received(smi_info->intf, msg);
		spin_lock(&(smi_info->si_lock));
	}
Linus Torvalds's avatar
Linus Torvalds committed
334
335
}

Corey Minyard's avatar
Corey Minyard committed
336
static void return_hosed_msg(struct smi_info *smi_info, int cCode)
Linus Torvalds's avatar
Linus Torvalds committed
337
338
339
{
	struct ipmi_smi_msg *msg = smi_info->curr_msg;

Corey Minyard's avatar
Corey Minyard committed
340
341
342
343
	if (cCode < 0 || cCode > IPMI_ERR_UNSPECIFIED)
		cCode = IPMI_ERR_UNSPECIFIED;
	/* else use it as is */

Linus Torvalds's avatar
Linus Torvalds committed
344
345
346
	/* Make it a reponse */
	msg->rsp[0] = msg->data[0] | 4;
	msg->rsp[1] = msg->data[1];
Corey Minyard's avatar
Corey Minyard committed
347
	msg->rsp[2] = cCode;
Linus Torvalds's avatar
Linus Torvalds committed
348
349
350
351
352
353
354
355
356
357
358
359
360
361
	msg->rsp_size = 3;

	smi_info->curr_msg = NULL;
	deliver_recv_msg(smi_info, msg);
}

static enum si_sm_result start_next_msg(struct smi_info *smi_info)
{
	int              rv;
	struct list_head *entry = NULL;
#ifdef DEBUG_TIMING
	struct timeval t;
#endif

362
363
364
365
	/*
	 * No need to save flags, we aleady have interrupts off and we
	 * already hold the SMI lock.
	 */
366
367
	if (!smi_info->run_to_completion)
		spin_lock(&(smi_info->msg_lock));
Linus Torvalds's avatar
Linus Torvalds committed
368
369

	/* Pick the high priority queue first. */
370
	if (!list_empty(&(smi_info->hp_xmit_msgs))) {
Linus Torvalds's avatar
Linus Torvalds committed
371
		entry = smi_info->hp_xmit_msgs.next;
372
	} else if (!list_empty(&(smi_info->xmit_msgs))) {
Linus Torvalds's avatar
Linus Torvalds committed
373
374
375
		entry = smi_info->xmit_msgs.next;
	}

376
	if (!entry) {
Linus Torvalds's avatar
Linus Torvalds committed
377
378
379
380
381
382
383
384
385
386
387
		smi_info->curr_msg = NULL;
		rv = SI_SM_IDLE;
	} else {
		int err;

		list_del(entry);
		smi_info->curr_msg = list_entry(entry,
						struct ipmi_smi_msg,
						link);
#ifdef DEBUG_TIMING
		do_gettimeofday(&t);
388
		printk(KERN_DEBUG "**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
Linus Torvalds's avatar
Linus Torvalds committed
389
#endif
390
391
		err = atomic_notifier_call_chain(&xaction_notifier_list,
				0, smi_info);
392
393
394
395
		if (err & NOTIFY_STOP_MASK) {
			rv = SI_SM_CALL_WITHOUT_DELAY;
			goto out;
		}
Linus Torvalds's avatar
Linus Torvalds committed
396
397
398
399
		err = smi_info->handlers->start_transaction(
			smi_info->si_sm,
			smi_info->curr_msg->data,
			smi_info->curr_msg->data_size);
400
		if (err)
Corey Minyard's avatar
Corey Minyard committed
401
			return_hosed_msg(smi_info, err);
Linus Torvalds's avatar
Linus Torvalds committed
402
403
404

		rv = SI_SM_CALL_WITHOUT_DELAY;
	}
405
 out:
406
407
	if (!smi_info->run_to_completion)
		spin_unlock(&(smi_info->msg_lock));
Linus Torvalds's avatar
Linus Torvalds committed
408
409
410
411
412
413
414
415

	return rv;
}

static void start_enable_irq(struct smi_info *smi_info)
{
	unsigned char msg[2];

416
417
418
419
	/*
	 * If we are enabling interrupts, we have to tell the
	 * BMC to use them.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
420
421
422
423
424
425
426
	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;

	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
	smi_info->si_state = SI_ENABLE_INTERRUPTS1;
}

Corey Minyard's avatar
Corey Minyard committed
427
428
429
430
431
432
433
434
435
436
437
static void start_disable_irq(struct smi_info *smi_info)
{
	unsigned char msg[2];

	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;

	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
	smi_info->si_state = SI_DISABLE_INTERRUPTS1;
}

Linus Torvalds's avatar
Linus Torvalds committed
438
439
440
441
442
443
444
445
446
447
448
449
450
static void start_clear_flags(struct smi_info *smi_info)
{
	unsigned char msg[3];

	/* Make sure the watchdog pre-timeout flag is not set at startup. */
	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
	msg[2] = WDT_PRE_TIMEOUT_INT;

	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
	smi_info->si_state = SI_CLEARING_FLAGS;
}

451
452
453
454
455
456
/*
 * When we have a situtaion where we run out of memory and cannot
 * allocate messages, we just leave them in the BMC and run the system
 * polled until we can allocate some memory.  Once we have some
 * memory, we will re-enable the interrupt.
 */
Linus Torvalds's avatar
Linus Torvalds committed
457
458
static inline void disable_si_irq(struct smi_info *smi_info)
{
459
	if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
Corey Minyard's avatar
Corey Minyard committed
460
		start_disable_irq(smi_info);
Linus Torvalds's avatar
Linus Torvalds committed
461
		smi_info->interrupt_disabled = 1;
462
463
464
		if (!atomic_read(&smi_info->stop_operation))
			mod_timer(&smi_info->si_timer,
				  jiffies + SI_TIMEOUT_JIFFIES);
Linus Torvalds's avatar
Linus Torvalds committed
465
466
467
468
469
470
	}
}

static inline void enable_si_irq(struct smi_info *smi_info)
{
	if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
Corey Minyard's avatar
Corey Minyard committed
471
		start_enable_irq(smi_info);
Linus Torvalds's avatar
Linus Torvalds committed
472
473
474
475
476
477
		smi_info->interrupt_disabled = 0;
	}
}

static void handle_flags(struct smi_info *smi_info)
{
478
 retry:
Linus Torvalds's avatar
Linus Torvalds committed
479
480
	if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
		/* Watchdog pre-timeout */
481
		smi_inc_stat(smi_info, watchdog_pretimeouts);
Linus Torvalds's avatar
Linus Torvalds committed
482
483
484
485
486
487
488
489
490

		start_clear_flags(smi_info);
		smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
		spin_unlock(&(smi_info->si_lock));
		ipmi_smi_watchdog_pretimeout(smi_info->intf);
		spin_lock(&(smi_info->si_lock));
	} else if (smi_info->msg_flags & RECEIVE_MSG_AVAIL) {
		/* Messages available. */
		smi_info->curr_msg = ipmi_alloc_smi_msg();
491
		if (!smi_info->curr_msg) {
Linus Torvalds's avatar
Linus Torvalds committed
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
			disable_si_irq(smi_info);
			smi_info->si_state = SI_NORMAL;
			return;
		}
		enable_si_irq(smi_info);

		smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
		smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
		smi_info->curr_msg->data_size = 2;

		smi_info->handlers->start_transaction(
			smi_info->si_sm,
			smi_info->curr_msg->data,
			smi_info->curr_msg->data_size);
		smi_info->si_state = SI_GETTING_MESSAGES;
	} else if (smi_info->msg_flags & EVENT_MSG_BUFFER_FULL) {
		/* Events available. */
		smi_info->curr_msg = ipmi_alloc_smi_msg();
510
		if (!smi_info->curr_msg) {
Linus Torvalds's avatar
Linus Torvalds committed
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
			disable_si_irq(smi_info);
			smi_info->si_state = SI_NORMAL;
			return;
		}
		enable_si_irq(smi_info);

		smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
		smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
		smi_info->curr_msg->data_size = 2;

		smi_info->handlers->start_transaction(
			smi_info->si_sm,
			smi_info->curr_msg->data,
			smi_info->curr_msg->data_size);
		smi_info->si_state = SI_GETTING_EVENTS;
526
	} else if (smi_info->msg_flags & OEM_DATA_AVAIL &&
527
		   smi_info->oem_data_avail_handler) {
528
529
		if (smi_info->oem_data_avail_handler(smi_info))
			goto retry;
530
	} else
Linus Torvalds's avatar
Linus Torvalds committed
531
532
533
534
535
536
537
538
539
540
		smi_info->si_state = SI_NORMAL;
}

static void handle_transaction_done(struct smi_info *smi_info)
{
	struct ipmi_smi_msg *msg;
#ifdef DEBUG_TIMING
	struct timeval t;

	do_gettimeofday(&t);
541
	printk(KERN_DEBUG "**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
Linus Torvalds's avatar
Linus Torvalds committed
542
543
544
#endif
	switch (smi_info->si_state) {
	case SI_NORMAL:
545
		if (!smi_info->curr_msg)
Linus Torvalds's avatar
Linus Torvalds committed
546
547
548
549
550
551
552
553
			break;

		smi_info->curr_msg->rsp_size
			= smi_info->handlers->get_result(
				smi_info->si_sm,
				smi_info->curr_msg->rsp,
				IPMI_MAX_MSG_LENGTH);

554
555
556
557
558
		/*
		 * Do this here becase deliver_recv_msg() releases the
		 * lock, and a new message can be put in during the
		 * time the lock is released.
		 */
Linus Torvalds's avatar
Linus Torvalds committed
559
560
561
562
563
564
565
566
567
568
569
570
571
		msg = smi_info->curr_msg;
		smi_info->curr_msg = NULL;
		deliver_recv_msg(smi_info, msg);
		break;

	case SI_GETTING_FLAGS:
	{
		unsigned char msg[4];
		unsigned int  len;

		/* We got the flags from the SMI, now handle them. */
		len = smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
		if (msg[2] != 0) {
572
			/* Error fetching flags, just give up for now. */
Linus Torvalds's avatar
Linus Torvalds committed
573
574
			smi_info->si_state = SI_NORMAL;
		} else if (len < 4) {
575
576
577
578
			/*
			 * Hmm, no flags.  That's technically illegal, but
			 * don't use uninitialized data.
			 */
Linus Torvalds's avatar
Linus Torvalds committed
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
			smi_info->si_state = SI_NORMAL;
		} else {
			smi_info->msg_flags = msg[3];
			handle_flags(smi_info);
		}
		break;
	}

	case SI_CLEARING_FLAGS:
	case SI_CLEARING_FLAGS_THEN_SET_IRQ:
	{
		unsigned char msg[3];

		/* We cleared the flags. */
		smi_info->handlers->get_result(smi_info->si_sm, msg, 3);
		if (msg[2] != 0) {
			/* Error clearing flags */
596
597
			dev_warn(smi_info->dev,
				 "Error clearing flags: %2.2x\n", msg[2]);
Linus Torvalds's avatar
Linus Torvalds committed
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
		}
		if (smi_info->si_state == SI_CLEARING_FLAGS_THEN_SET_IRQ)
			start_enable_irq(smi_info);
		else
			smi_info->si_state = SI_NORMAL;
		break;
	}

	case SI_GETTING_EVENTS:
	{
		smi_info->curr_msg->rsp_size
			= smi_info->handlers->get_result(
				smi_info->si_sm,
				smi_info->curr_msg->rsp,
				IPMI_MAX_MSG_LENGTH);

614
615
616
617
618
		/*
		 * Do this here becase deliver_recv_msg() releases the
		 * lock, and a new message can be put in during the
		 * time the lock is released.
		 */
Linus Torvalds's avatar
Linus Torvalds committed
619
620
621
622
623
624
625
626
627
628
		msg = smi_info->curr_msg;
		smi_info->curr_msg = NULL;
		if (msg->rsp[2] != 0) {
			/* Error getting event, probably done. */
			msg->done(msg);

			/* Take off the event flag. */
			smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
			handle_flags(smi_info);
		} else {
629
			smi_inc_stat(smi_info, events);
Linus Torvalds's avatar
Linus Torvalds committed
630

631
632
633
634
635
636
			/*
			 * Do this before we deliver the message
			 * because delivering the message releases the
			 * lock and something else can mess with the
			 * state.
			 */
Linus Torvalds's avatar
Linus Torvalds committed
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
			handle_flags(smi_info);

			deliver_recv_msg(smi_info, msg);
		}
		break;
	}

	case SI_GETTING_MESSAGES:
	{
		smi_info->curr_msg->rsp_size
			= smi_info->handlers->get_result(
				smi_info->si_sm,
				smi_info->curr_msg->rsp,
				IPMI_MAX_MSG_LENGTH);

652
653
654
655
656
		/*
		 * Do this here becase deliver_recv_msg() releases the
		 * lock, and a new message can be put in during the
		 * time the lock is released.
		 */
Linus Torvalds's avatar
Linus Torvalds committed
657
658
659
660
661
662
663
664
665
666
		msg = smi_info->curr_msg;
		smi_info->curr_msg = NULL;
		if (msg->rsp[2] != 0) {
			/* Error getting event, probably done. */
			msg->done(msg);

			/* Take off the msg flag. */
			smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
			handle_flags(smi_info);
		} else {
667
			smi_inc_stat(smi_info, incoming_messages);
Linus Torvalds's avatar
Linus Torvalds committed
668

669
670
671
672
673
674
			/*
			 * Do this before we deliver the message
			 * because delivering the message releases the
			 * lock and something else can mess with the
			 * state.
			 */
Linus Torvalds's avatar
Linus Torvalds committed
675
676
677
678
679
680
681
682
683
684
685
686
687
688
			handle_flags(smi_info);

			deliver_recv_msg(smi_info, msg);
		}
		break;
	}

	case SI_ENABLE_INTERRUPTS1:
	{
		unsigned char msg[4];

		/* We got the flags from the SMI, now handle them. */
		smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
		if (msg[2] != 0) {
689
690
			dev_warn(smi_info->dev, "Could not enable interrupts"
				 ", failed get, using polled mode.\n");
Linus Torvalds's avatar
Linus Torvalds committed
691
692
693
694
			smi_info->si_state = SI_NORMAL;
		} else {
			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
Corey Minyard's avatar
Corey Minyard committed
695
696
697
			msg[2] = (msg[3] |
				  IPMI_BMC_RCV_MSG_INTR |
				  IPMI_BMC_EVT_MSG_INTR);
Linus Torvalds's avatar
Linus Torvalds committed
698
699
700
701
702
703
704
705
706
707
708
709
710
			smi_info->handlers->start_transaction(
				smi_info->si_sm, msg, 3);
			smi_info->si_state = SI_ENABLE_INTERRUPTS2;
		}
		break;
	}

	case SI_ENABLE_INTERRUPTS2:
	{
		unsigned char msg[4];

		/* We got the flags from the SMI, now handle them. */
		smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
711
712
713
714
		if (msg[2] != 0)
			dev_warn(smi_info->dev, "Could not enable interrupts"
				 ", failed set, using polled mode.\n");
		else
715
			smi_info->interrupt_disabled = 0;
Linus Torvalds's avatar
Linus Torvalds committed
716
717
718
		smi_info->si_state = SI_NORMAL;
		break;
	}
Corey Minyard's avatar
Corey Minyard committed
719
720
721
722
723
724
725
726

	case SI_DISABLE_INTERRUPTS1:
	{
		unsigned char msg[4];

		/* We got the flags from the SMI, now handle them. */
		smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
		if (msg[2] != 0) {
727
728
			dev_warn(smi_info->dev, "Could not disable interrupts"
				 ", failed get.\n");
Corey Minyard's avatar
Corey Minyard committed
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
			smi_info->si_state = SI_NORMAL;
		} else {
			msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
			msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
			msg[2] = (msg[3] &
				  ~(IPMI_BMC_RCV_MSG_INTR |
				    IPMI_BMC_EVT_MSG_INTR));
			smi_info->handlers->start_transaction(
				smi_info->si_sm, msg, 3);
			smi_info->si_state = SI_DISABLE_INTERRUPTS2;
		}
		break;
	}

	case SI_DISABLE_INTERRUPTS2:
	{
		unsigned char msg[4];

		/* We got the flags from the SMI, now handle them. */
		smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
		if (msg[2] != 0) {
750
751
			dev_warn(smi_info->dev, "Could not disable interrupts"
				 ", failed set.\n");
Corey Minyard's avatar
Corey Minyard committed
752
753
754
755
		}
		smi_info->si_state = SI_NORMAL;
		break;
	}
Linus Torvalds's avatar
Linus Torvalds committed
756
757
758
	}
}

759
760
761
762
763
/*
 * Called on timeouts and events.  Timeouts should pass the elapsed
 * time, interrupts should pass in zero.  Must be called with
 * si_lock held and interrupts disabled.
 */
Linus Torvalds's avatar
Linus Torvalds committed
764
765
766
767
768
769
static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
					   int time)
{
	enum si_sm_result si_sm_result;

 restart:
770
771
772
773
774
775
776
777
	/*
	 * There used to be a loop here that waited a little while
	 * (around 25us) before giving up.  That turned out to be
	 * pointless, the minimum delays I was seeing were in the 300us
	 * range, which is far too long to wait in an interrupt.  So
	 * we just run until the state machine tells us something
	 * happened or it needs a delay.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
778
779
780
781
782
	si_sm_result = smi_info->handlers->event(smi_info->si_sm, time);
	time = 0;
	while (si_sm_result == SI_SM_CALL_WITHOUT_DELAY)
		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);

783
	if (si_sm_result == SI_SM_TRANSACTION_COMPLETE) {
784
		smi_inc_stat(smi_info, complete_transactions);
Linus Torvalds's avatar
Linus Torvalds committed
785
786
787

		handle_transaction_done(smi_info);
		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
788
	} else if (si_sm_result == SI_SM_HOSED) {
789
		smi_inc_stat(smi_info, hosed_count);
Linus Torvalds's avatar
Linus Torvalds committed
790

791
792
793
794
		/*
		 * Do the before return_hosed_msg, because that
		 * releases the lock.
		 */
Linus Torvalds's avatar
Linus Torvalds committed
795
796
		smi_info->si_state = SI_NORMAL;
		if (smi_info->curr_msg != NULL) {
797
798
799
800
801
			/*
			 * If we were handling a user message, format
			 * a response to send to the upper layer to
			 * tell it about the error.
			 */
Corey Minyard's avatar
Corey Minyard committed
802
			return_hosed_msg(smi_info, IPMI_ERR_UNSPECIFIED);
Linus Torvalds's avatar
Linus Torvalds committed
803
804
805
806
		}
		si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
	}

807
808
809
810
	/*
	 * We prefer handling attn over new messages.  But don't do
	 * this if there is not yet an upper layer to handle anything.
	 */
811
	if (likely(smi_info->intf) && si_sm_result == SI_SM_ATTN) {
Linus Torvalds's avatar
Linus Torvalds committed
812
813
		unsigned char msg[2];

814
		smi_inc_stat(smi_info, attentions);
Linus Torvalds's avatar
Linus Torvalds committed
815

816
817
818
819
820
821
822
		/*
		 * Got a attn, send down a get message flags to see
		 * what's causing it.  It would be better to handle
		 * this in the upper layer, but due to the way
		 * interrupts work with the SMI, that's not really
		 * possible.
		 */
Linus Torvalds's avatar
Linus Torvalds committed
823
824
825
826
827
828
829
830
831
832
833
		msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
		msg[1] = IPMI_GET_MSG_FLAGS_CMD;

		smi_info->handlers->start_transaction(
			smi_info->si_sm, msg, 2);
		smi_info->si_state = SI_GETTING_FLAGS;
		goto restart;
	}

	/* If we are currently idle, try to start the next message. */
	if (si_sm_result == SI_SM_IDLE) {
834
		smi_inc_stat(smi_info, idles);
Linus Torvalds's avatar
Linus Torvalds committed
835
836
837
838

		si_sm_result = start_next_msg(smi_info);
		if (si_sm_result != SI_SM_IDLE)
			goto restart;
839
	}
Linus Torvalds's avatar
Linus Torvalds committed
840
841

	if ((si_sm_result == SI_SM_IDLE)
842
843
844
845
846
	    && (atomic_read(&smi_info->req_events))) {
		/*
		 * We are idle and the upper layer requested that I fetch
		 * events, so do so.
		 */
847
		atomic_set(&smi_info->req_events, 0);
Linus Torvalds's avatar
Linus Torvalds committed
848

849
850
851
		smi_info->curr_msg = ipmi_alloc_smi_msg();
		if (!smi_info->curr_msg)
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
852

853
854
855
		smi_info->curr_msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
		smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
		smi_info->curr_msg->data_size = 2;
Linus Torvalds's avatar
Linus Torvalds committed
856
857

		smi_info->handlers->start_transaction(
858
859
860
861
			smi_info->si_sm,
			smi_info->curr_msg->data,
			smi_info->curr_msg->data_size);
		smi_info->si_state = SI_GETTING_EVENTS;
Linus Torvalds's avatar
Linus Torvalds committed
862
863
		goto restart;
	}
864
 out:
Linus Torvalds's avatar
Linus Torvalds committed
865
866
867
868
869
870
871
872
873
874
875
876
877
878
	return si_sm_result;
}

static void sender(void                *send_info,
		   struct ipmi_smi_msg *msg,
		   int                 priority)
{
	struct smi_info   *smi_info = send_info;
	enum si_sm_result result;
	unsigned long     flags;
#ifdef DEBUG_TIMING
	struct timeval    t;
#endif

879
880
881
882
883
884
885
886
887
	if (atomic_read(&smi_info->stop_operation)) {
		msg->rsp[0] = msg->data[0] | 4;
		msg->rsp[1] = msg->data[1];
		msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
		msg->rsp_size = 3;
		deliver_recv_msg(smi_info, msg);
		return;
	}

Linus Torvalds's avatar
Linus Torvalds committed
888
889
890
891
892
#ifdef DEBUG_TIMING
	do_gettimeofday(&t);
	printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif

893
894
	mod_timer(&smi_info->si_timer, jiffies + SI_TIMEOUT_JIFFIES);

Matthew Garrett's avatar
Matthew Garrett committed
895
896
897
	if (smi_info->thread)
		wake_up_process(smi_info->thread);

Linus Torvalds's avatar
Linus Torvalds committed
898
	if (smi_info->run_to_completion) {
Corey Minyard's avatar
Corey Minyard committed
899
900
901
902
903
904
905
906
907
908
		/*
		 * If we are running to completion, then throw it in
		 * the list and run transactions until everything is
		 * clear.  Priority doesn't matter here.
		 */

		/*
		 * Run to completion means we are single-threaded, no
		 * need for locks.
		 */
Linus Torvalds's avatar
Linus Torvalds committed
909
910
911
912
913
914
915
916
917
918
919
		list_add_tail(&(msg->link), &(smi_info->xmit_msgs));

		result = smi_event_handler(smi_info, 0);
		while (result != SI_SM_IDLE) {
			udelay(SI_SHORT_TIMEOUT_USEC);
			result = smi_event_handler(smi_info,
						   SI_SHORT_TIMEOUT_USEC);
		}
		return;
	}

Corey Minyard's avatar
Corey Minyard committed
920
921
922
923
924
925
926
927
	spin_lock_irqsave(&smi_info->msg_lock, flags);
	if (priority > 0)
		list_add_tail(&msg->link, &smi_info->hp_xmit_msgs);
	else
		list_add_tail(&msg->link, &smi_info->xmit_msgs);
	spin_unlock_irqrestore(&smi_info->msg_lock, flags);

	spin_lock_irqsave(&smi_info->si_lock, flags);
928
	if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL)
Linus Torvalds's avatar
Linus Torvalds committed
929
		start_next_msg(smi_info);
Corey Minyard's avatar
Corey Minyard committed
930
	spin_unlock_irqrestore(&smi_info->si_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
}

static void set_run_to_completion(void *send_info, int i_run_to_completion)
{
	struct smi_info   *smi_info = send_info;
	enum si_sm_result result;

	smi_info->run_to_completion = i_run_to_completion;
	if (i_run_to_completion) {
		result = smi_event_handler(smi_info, 0);
		while (result != SI_SM_IDLE) {
			udelay(SI_SHORT_TIMEOUT_USEC);
			result = smi_event_handler(smi_info,
						   SI_SHORT_TIMEOUT_USEC);
		}
	}
}

949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
/*
 * Use -1 in the nsec value of the busy waiting timespec to tell that
 * we are spinning in kipmid looking for something and not delaying
 * between checks
 */
static inline void ipmi_si_set_not_busy(struct timespec *ts)
{
	ts->tv_nsec = -1;
}
static inline int ipmi_si_is_busy(struct timespec *ts)
{
	return ts->tv_nsec != -1;
}

static int ipmi_thread_busy_wait(enum si_sm_result smi_result,
				 const struct smi_info *smi_info,
				 struct timespec *busy_until)
{
	unsigned int max_busy_us = 0;

	if (smi_info->intf_num < num_max_busy_us)
		max_busy_us = kipmid_max_busy_us[smi_info->intf_num];
	if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY)
		ipmi_si_set_not_busy(busy_until);
	else if (!ipmi_si_is_busy(busy_until)) {
		getnstimeofday(busy_until);
		timespec_add_ns(busy_until, max_busy_us*NSEC_PER_USEC);
	} else {
		struct timespec now;
		getnstimeofday(&now);
		if (unlikely(timespec_compare(&now, busy_until) > 0)) {
			ipmi_si_set_not_busy(busy_until);
			return 0;
		}
	}
	return 1;
}


/*
 * A busy-waiting loop for speeding up IPMI operation.
 *
 * Lousy hardware makes this hard.  This is only enabled for systems
 * that are not BT and do not have interrupts.  It starts spinning
 * when an operation is complete or until max_busy tells it to stop
 * (if that is enabled).  See the paragraph on kimid_max_busy_us in
 * Documentation/IPMI.txt for details.
 */
Corey Minyard's avatar
Corey Minyard committed
997
998
999
static int ipmi_thread(void *data)
{
	struct smi_info *smi_info = data;
Matt Domsch's avatar
Matt Domsch committed
1000
	unsigned long flags;
For faster browsing, not all history is shown. View entire blame