xref: /openbmc/linux/drivers/misc/ibmasm/command.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds 
2*1da177e4SLinus Torvalds /*
3*1da177e4SLinus Torvalds  * IBM ASM Service Processor Device Driver
4*1da177e4SLinus Torvalds  *
5*1da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
6*1da177e4SLinus Torvalds  * it under the terms of the GNU General Public License as published by
7*1da177e4SLinus Torvalds  * the Free Software Foundation; either version 2 of the License, or
8*1da177e4SLinus Torvalds  * (at your option) any later version.
9*1da177e4SLinus Torvalds  *
10*1da177e4SLinus Torvalds  * This program is distributed in the hope that it will be useful,
11*1da177e4SLinus Torvalds  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*1da177e4SLinus Torvalds  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*1da177e4SLinus Torvalds  * GNU General Public License for more details.
14*1da177e4SLinus Torvalds  *
15*1da177e4SLinus Torvalds  * You should have received a copy of the GNU General Public License
16*1da177e4SLinus Torvalds  * along with this program; if not, write to the Free Software
17*1da177e4SLinus Torvalds  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18*1da177e4SLinus Torvalds  *
19*1da177e4SLinus Torvalds  * Copyright (C) IBM Corporation, 2004
20*1da177e4SLinus Torvalds  *
21*1da177e4SLinus Torvalds  * Author: Max Asb�ck <amax@us.ibm.com>
22*1da177e4SLinus Torvalds  *
23*1da177e4SLinus Torvalds  */
24*1da177e4SLinus Torvalds 
25*1da177e4SLinus Torvalds #include "ibmasm.h"
26*1da177e4SLinus Torvalds 
27*1da177e4SLinus Torvalds static void exec_next_command(struct service_processor *sp);
28*1da177e4SLinus Torvalds static void free_command(struct kobject *kobj);
29*1da177e4SLinus Torvalds 
30*1da177e4SLinus Torvalds static struct kobj_type ibmasm_cmd_kobj_type = {
31*1da177e4SLinus Torvalds 	.release = free_command,
32*1da177e4SLinus Torvalds };
33*1da177e4SLinus Torvalds 
34*1da177e4SLinus Torvalds 
35*1da177e4SLinus Torvalds struct command *ibmasm_new_command(size_t buffer_size)
36*1da177e4SLinus Torvalds {
37*1da177e4SLinus Torvalds 	struct command *cmd;
38*1da177e4SLinus Torvalds 
39*1da177e4SLinus Torvalds 	if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE)
40*1da177e4SLinus Torvalds 		return NULL;
41*1da177e4SLinus Torvalds 
42*1da177e4SLinus Torvalds 	cmd = kmalloc(sizeof(struct command), GFP_KERNEL);
43*1da177e4SLinus Torvalds 	if (cmd == NULL)
44*1da177e4SLinus Torvalds 		return NULL;
45*1da177e4SLinus Torvalds 
46*1da177e4SLinus Torvalds 	memset(cmd, 0, sizeof(*cmd));
47*1da177e4SLinus Torvalds 
48*1da177e4SLinus Torvalds 	cmd->buffer = kmalloc(buffer_size, GFP_KERNEL);
49*1da177e4SLinus Torvalds 	if (cmd->buffer == NULL) {
50*1da177e4SLinus Torvalds 		kfree(cmd);
51*1da177e4SLinus Torvalds 		return NULL;
52*1da177e4SLinus Torvalds 	}
53*1da177e4SLinus Torvalds 	memset(cmd->buffer, 0, buffer_size);
54*1da177e4SLinus Torvalds 	cmd->buffer_size = buffer_size;
55*1da177e4SLinus Torvalds 
56*1da177e4SLinus Torvalds 	kobject_init(&cmd->kobj);
57*1da177e4SLinus Torvalds 	cmd->kobj.ktype = &ibmasm_cmd_kobj_type;
58*1da177e4SLinus Torvalds 
59*1da177e4SLinus Torvalds 	cmd->status = IBMASM_CMD_PENDING;
60*1da177e4SLinus Torvalds 	init_waitqueue_head(&cmd->wait);
61*1da177e4SLinus Torvalds 	INIT_LIST_HEAD(&cmd->queue_node);
62*1da177e4SLinus Torvalds 
63*1da177e4SLinus Torvalds 	return cmd;
64*1da177e4SLinus Torvalds }
65*1da177e4SLinus Torvalds 
66*1da177e4SLinus Torvalds static void free_command(struct kobject *kobj)
67*1da177e4SLinus Torvalds {
68*1da177e4SLinus Torvalds 	struct command *cmd = to_command(kobj);
69*1da177e4SLinus Torvalds 
70*1da177e4SLinus Torvalds 	list_del(&cmd->queue_node);
71*1da177e4SLinus Torvalds 	kfree(cmd->buffer);
72*1da177e4SLinus Torvalds 	kfree(cmd);
73*1da177e4SLinus Torvalds }
74*1da177e4SLinus Torvalds 
75*1da177e4SLinus Torvalds static void enqueue_command(struct service_processor *sp, struct command *cmd)
76*1da177e4SLinus Torvalds {
77*1da177e4SLinus Torvalds 	list_add_tail(&cmd->queue_node, &sp->command_queue);
78*1da177e4SLinus Torvalds }
79*1da177e4SLinus Torvalds 
80*1da177e4SLinus Torvalds static struct command *dequeue_command(struct service_processor *sp)
81*1da177e4SLinus Torvalds {
82*1da177e4SLinus Torvalds 	struct command *cmd;
83*1da177e4SLinus Torvalds 	struct list_head *next;
84*1da177e4SLinus Torvalds 
85*1da177e4SLinus Torvalds 	if (list_empty(&sp->command_queue))
86*1da177e4SLinus Torvalds 		return NULL;
87*1da177e4SLinus Torvalds 
88*1da177e4SLinus Torvalds 	next = sp->command_queue.next;
89*1da177e4SLinus Torvalds 	list_del_init(next);
90*1da177e4SLinus Torvalds 	cmd = list_entry(next, struct command, queue_node);
91*1da177e4SLinus Torvalds 
92*1da177e4SLinus Torvalds 	return cmd;
93*1da177e4SLinus Torvalds }
94*1da177e4SLinus Torvalds 
95*1da177e4SLinus Torvalds static inline void do_exec_command(struct service_processor *sp)
96*1da177e4SLinus Torvalds {
97*1da177e4SLinus Torvalds 	if (ibmasm_send_i2o_message(sp)) {
98*1da177e4SLinus Torvalds 		sp->current_command->status = IBMASM_CMD_FAILED;
99*1da177e4SLinus Torvalds 		exec_next_command(sp);
100*1da177e4SLinus Torvalds 	}
101*1da177e4SLinus Torvalds }
102*1da177e4SLinus Torvalds 
103*1da177e4SLinus Torvalds /**
104*1da177e4SLinus Torvalds  * exec_command
105*1da177e4SLinus Torvalds  * send a command to a service processor
106*1da177e4SLinus Torvalds  * Commands are executed sequentially. One command (sp->current_command)
107*1da177e4SLinus Torvalds  * is sent to the service processor. Once the interrupt handler gets a
108*1da177e4SLinus Torvalds  * message of type command_response, the message is copied into
109*1da177e4SLinus Torvalds  * the current commands buffer,
110*1da177e4SLinus Torvalds  */
111*1da177e4SLinus Torvalds void ibmasm_exec_command(struct service_processor *sp, struct command *cmd)
112*1da177e4SLinus Torvalds {
113*1da177e4SLinus Torvalds 	unsigned long flags;
114*1da177e4SLinus Torvalds 
115*1da177e4SLinus Torvalds 	spin_lock_irqsave(&sp->lock, flags);
116*1da177e4SLinus Torvalds 
117*1da177e4SLinus Torvalds 	if (!sp->current_command) {
118*1da177e4SLinus Torvalds 		command_get(cmd);
119*1da177e4SLinus Torvalds 		sp->current_command = cmd;
120*1da177e4SLinus Torvalds 		spin_unlock_irqrestore(&sp->lock, flags);
121*1da177e4SLinus Torvalds 
122*1da177e4SLinus Torvalds 		do_exec_command(sp);
123*1da177e4SLinus Torvalds 	} else {
124*1da177e4SLinus Torvalds 		enqueue_command(sp, cmd);
125*1da177e4SLinus Torvalds 		spin_unlock_irqrestore(&sp->lock, flags);
126*1da177e4SLinus Torvalds 	}
127*1da177e4SLinus Torvalds }
128*1da177e4SLinus Torvalds 
129*1da177e4SLinus Torvalds static void exec_next_command(struct service_processor *sp)
130*1da177e4SLinus Torvalds {
131*1da177e4SLinus Torvalds 	unsigned long flags;
132*1da177e4SLinus Torvalds 
133*1da177e4SLinus Torvalds 	wake_up(&sp->current_command->wait);
134*1da177e4SLinus Torvalds 	command_put(sp->current_command);
135*1da177e4SLinus Torvalds 
136*1da177e4SLinus Torvalds 	spin_lock_irqsave(&sp->lock, flags);
137*1da177e4SLinus Torvalds 	sp->current_command = dequeue_command(sp);
138*1da177e4SLinus Torvalds 	if (sp->current_command) {
139*1da177e4SLinus Torvalds 		command_get(sp->current_command);
140*1da177e4SLinus Torvalds 		spin_unlock_irqrestore(&sp->lock, flags);
141*1da177e4SLinus Torvalds 		do_exec_command(sp);
142*1da177e4SLinus Torvalds 	} else {
143*1da177e4SLinus Torvalds 		spin_unlock_irqrestore(&sp->lock, flags);
144*1da177e4SLinus Torvalds 	}
145*1da177e4SLinus Torvalds }
146*1da177e4SLinus Torvalds 
147*1da177e4SLinus Torvalds /**
148*1da177e4SLinus Torvalds  * Sleep until a command has failed or a response has been received
149*1da177e4SLinus Torvalds  * and the command status been updated by the interrupt handler.
150*1da177e4SLinus Torvalds  * (see receive_response).
151*1da177e4SLinus Torvalds  */
152*1da177e4SLinus Torvalds void ibmasm_wait_for_response(struct command *cmd, int timeout)
153*1da177e4SLinus Torvalds {
154*1da177e4SLinus Torvalds 	wait_event_interruptible_timeout(cmd->wait,
155*1da177e4SLinus Torvalds 				cmd->status == IBMASM_CMD_COMPLETE ||
156*1da177e4SLinus Torvalds 				cmd->status == IBMASM_CMD_FAILED,
157*1da177e4SLinus Torvalds 				timeout * HZ);
158*1da177e4SLinus Torvalds }
159*1da177e4SLinus Torvalds 
160*1da177e4SLinus Torvalds /**
161*1da177e4SLinus Torvalds  * receive_command_response
162*1da177e4SLinus Torvalds  * called by the interrupt handler when a dot command of type command_response
163*1da177e4SLinus Torvalds  * was received.
164*1da177e4SLinus Torvalds  */
165*1da177e4SLinus Torvalds void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size)
166*1da177e4SLinus Torvalds {
167*1da177e4SLinus Torvalds 	struct command *cmd = sp->current_command;
168*1da177e4SLinus Torvalds 
169*1da177e4SLinus Torvalds 	if (!sp->current_command)
170*1da177e4SLinus Torvalds 		return;
171*1da177e4SLinus Torvalds 
172*1da177e4SLinus Torvalds 	memcpy(cmd->buffer, response, min(size, cmd->buffer_size));
173*1da177e4SLinus Torvalds 	cmd->status = IBMASM_CMD_COMPLETE;
174*1da177e4SLinus Torvalds 	exec_next_command(sp);
175*1da177e4SLinus Torvalds }
176