blob: 276d3fb68094a53d6815979688b89cd412e8b489 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001
2/*
3 * IBM ASM Service Processor Device Driver
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 * Copyright (C) IBM Corporation, 2004
20 *
Dmitry Torokhov3110dc72007-07-17 04:03:58 -070021 * Author: Max Asböck <amax@us.ibm.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 *
23 */
24
25#include "ibmasm.h"
Max Asbock88187602005-06-21 17:16:36 -070026#include "lowlevel.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28static void exec_next_command(struct service_processor *sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Max Asbock88187602005-06-21 17:16:36 -070030static atomic_t command_count = ATOMIC_INIT(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
Max Asbock88187602005-06-21 17:16:36 -070032struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -070033{
34 struct command *cmd;
35
36 if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE)
37 return NULL;
38
Yoann Padioleaudd00cc42007-07-19 01:49:03 -070039 cmd = kzalloc(sizeof(struct command), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 if (cmd == NULL)
41 return NULL;
42
Linus Torvalds1da177e2005-04-16 15:20:36 -070043
Yoann Padioleaudd00cc42007-07-19 01:49:03 -070044 cmd->buffer = kzalloc(buffer_size, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 if (cmd->buffer == NULL) {
46 kfree(cmd);
47 return NULL;
48 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 cmd->buffer_size = buffer_size;
50
Greg Kroah-Hartmana0451712007-12-03 21:16:20 -070051 kref_init(&cmd->kref);
Max Asbock88187602005-06-21 17:16:36 -070052 cmd->lock = &sp->lock;
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54 cmd->status = IBMASM_CMD_PENDING;
55 init_waitqueue_head(&cmd->wait);
56 INIT_LIST_HEAD(&cmd->queue_node);
57
Max Asbock88187602005-06-21 17:16:36 -070058 atomic_inc(&command_count);
59 dbg("command count: %d\n", atomic_read(&command_count));
60
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 return cmd;
62}
63
Greg Kroah-Hartmana0451712007-12-03 21:16:20 -070064void ibmasm_free_command(struct kref *kref)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065{
Greg Kroah-Hartmana0451712007-12-03 21:16:20 -070066 struct command *cmd = to_command(kref);
Dmitry Torokhov3110dc72007-07-17 04:03:58 -070067
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 list_del(&cmd->queue_node);
Max Asbock88187602005-06-21 17:16:36 -070069 atomic_dec(&command_count);
70 dbg("command count: %d\n", atomic_read(&command_count));
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 kfree(cmd->buffer);
72 kfree(cmd);
73}
74
75static void enqueue_command(struct service_processor *sp, struct command *cmd)
76{
77 list_add_tail(&cmd->queue_node, &sp->command_queue);
78}
79
80static struct command *dequeue_command(struct service_processor *sp)
81{
82 struct command *cmd;
83 struct list_head *next;
84
85 if (list_empty(&sp->command_queue))
86 return NULL;
87
88 next = sp->command_queue.next;
89 list_del_init(next);
90 cmd = list_entry(next, struct command, queue_node);
91
92 return cmd;
93}
94
95static inline void do_exec_command(struct service_processor *sp)
96{
Max Asbock88187602005-06-21 17:16:36 -070097 char tsbuf[32];
98
Harvey Harrison6e574192008-04-29 00:59:20 -070099 dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
Max Asbock88187602005-06-21 17:16:36 -0700100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 if (ibmasm_send_i2o_message(sp)) {
102 sp->current_command->status = IBMASM_CMD_FAILED;
Max Asbock88187602005-06-21 17:16:36 -0700103 wake_up(&sp->current_command->wait);
104 command_put(sp->current_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 exec_next_command(sp);
106 }
107}
Dmitry Torokhov3110dc72007-07-17 04:03:58 -0700108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109/**
110 * exec_command
111 * send a command to a service processor
112 * Commands are executed sequentially. One command (sp->current_command)
113 * is sent to the service processor. Once the interrupt handler gets a
114 * message of type command_response, the message is copied into
Dmitry Torokhov3110dc72007-07-17 04:03:58 -0700115 * the current commands buffer,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 */
117void ibmasm_exec_command(struct service_processor *sp, struct command *cmd)
118{
119 unsigned long flags;
Max Asbock88187602005-06-21 17:16:36 -0700120 char tsbuf[32];
121
Harvey Harrison6e574192008-04-29 00:59:20 -0700122 dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
124 spin_lock_irqsave(&sp->lock, flags);
125
126 if (!sp->current_command) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 sp->current_command = cmd;
Max Asbock88187602005-06-21 17:16:36 -0700128 command_get(sp->current_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 spin_unlock_irqrestore(&sp->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 do_exec_command(sp);
131 } else {
132 enqueue_command(sp, cmd);
133 spin_unlock_irqrestore(&sp->lock, flags);
134 }
135}
136
137static void exec_next_command(struct service_processor *sp)
138{
139 unsigned long flags;
Max Asbock88187602005-06-21 17:16:36 -0700140 char tsbuf[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
Harvey Harrison6e574192008-04-29 00:59:20 -0700142 dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144 spin_lock_irqsave(&sp->lock, flags);
145 sp->current_command = dequeue_command(sp);
146 if (sp->current_command) {
147 command_get(sp->current_command);
148 spin_unlock_irqrestore(&sp->lock, flags);
149 do_exec_command(sp);
150 } else {
151 spin_unlock_irqrestore(&sp->lock, flags);
152 }
153}
154
Dmitry Torokhov3110dc72007-07-17 04:03:58 -0700155/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 * Sleep until a command has failed or a response has been received
157 * and the command status been updated by the interrupt handler.
158 * (see receive_response).
159 */
160void ibmasm_wait_for_response(struct command *cmd, int timeout)
161{
162 wait_event_interruptible_timeout(cmd->wait,
163 cmd->status == IBMASM_CMD_COMPLETE ||
164 cmd->status == IBMASM_CMD_FAILED,
165 timeout * HZ);
166}
167
168/**
169 * receive_command_response
170 * called by the interrupt handler when a dot command of type command_response
171 * was received.
172 */
173void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size)
174{
175 struct command *cmd = sp->current_command;
176
Dmitry Torokhov3110dc72007-07-17 04:03:58 -0700177 if (!sp->current_command)
178 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Max Asbock88187602005-06-21 17:16:36 -0700180 memcpy_fromio(cmd->buffer, response, min(size, cmd->buffer_size));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 cmd->status = IBMASM_CMD_COMPLETE;
Max Asbock88187602005-06-21 17:16:36 -0700182 wake_up(&sp->current_command->wait);
183 command_put(sp->current_command);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 exec_next_command(sp);
185}