0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/sched.h>
0012 #include <linux/slab.h>
0013 #include "ibmasm.h"
0014 #include "lowlevel.h"
0015
0016 static void exec_next_command(struct service_processor *sp);
0017
0018 static atomic_t command_count = ATOMIC_INIT(0);
0019
0020 struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size)
0021 {
0022 struct command *cmd;
0023
0024 if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE)
0025 return NULL;
0026
0027 cmd = kzalloc(sizeof(struct command), GFP_KERNEL);
0028 if (cmd == NULL)
0029 return NULL;
0030
0031
0032 cmd->buffer = kzalloc(buffer_size, GFP_KERNEL);
0033 if (cmd->buffer == NULL) {
0034 kfree(cmd);
0035 return NULL;
0036 }
0037 cmd->buffer_size = buffer_size;
0038
0039 kref_init(&cmd->kref);
0040 cmd->lock = &sp->lock;
0041
0042 cmd->status = IBMASM_CMD_PENDING;
0043 init_waitqueue_head(&cmd->wait);
0044 INIT_LIST_HEAD(&cmd->queue_node);
0045
0046 atomic_inc(&command_count);
0047 dbg("command count: %d\n", atomic_read(&command_count));
0048
0049 return cmd;
0050 }
0051
0052 void ibmasm_free_command(struct kref *kref)
0053 {
0054 struct command *cmd = to_command(kref);
0055
0056 list_del(&cmd->queue_node);
0057 atomic_dec(&command_count);
0058 dbg("command count: %d\n", atomic_read(&command_count));
0059 kfree(cmd->buffer);
0060 kfree(cmd);
0061 }
0062
0063 static void enqueue_command(struct service_processor *sp, struct command *cmd)
0064 {
0065 list_add_tail(&cmd->queue_node, &sp->command_queue);
0066 }
0067
0068 static struct command *dequeue_command(struct service_processor *sp)
0069 {
0070 struct command *cmd;
0071 struct list_head *next;
0072
0073 if (list_empty(&sp->command_queue))
0074 return NULL;
0075
0076 next = sp->command_queue.next;
0077 list_del_init(next);
0078 cmd = list_entry(next, struct command, queue_node);
0079
0080 return cmd;
0081 }
0082
0083 static inline void do_exec_command(struct service_processor *sp)
0084 {
0085 char tsbuf[32];
0086
0087 dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
0088
0089 if (ibmasm_send_i2o_message(sp)) {
0090 sp->current_command->status = IBMASM_CMD_FAILED;
0091 wake_up(&sp->current_command->wait);
0092 command_put(sp->current_command);
0093 exec_next_command(sp);
0094 }
0095 }
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105 void ibmasm_exec_command(struct service_processor *sp, struct command *cmd)
0106 {
0107 unsigned long flags;
0108 char tsbuf[32];
0109
0110 dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
0111
0112 spin_lock_irqsave(&sp->lock, flags);
0113
0114 if (!sp->current_command) {
0115 sp->current_command = cmd;
0116 command_get(sp->current_command);
0117 spin_unlock_irqrestore(&sp->lock, flags);
0118 do_exec_command(sp);
0119 } else {
0120 enqueue_command(sp, cmd);
0121 spin_unlock_irqrestore(&sp->lock, flags);
0122 }
0123 }
0124
0125 static void exec_next_command(struct service_processor *sp)
0126 {
0127 unsigned long flags;
0128 char tsbuf[32];
0129
0130 dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
0131
0132 spin_lock_irqsave(&sp->lock, flags);
0133 sp->current_command = dequeue_command(sp);
0134 if (sp->current_command) {
0135 command_get(sp->current_command);
0136 spin_unlock_irqrestore(&sp->lock, flags);
0137 do_exec_command(sp);
0138 } else {
0139 spin_unlock_irqrestore(&sp->lock, flags);
0140 }
0141 }
0142
0143
0144
0145
0146
0147
0148 void ibmasm_wait_for_response(struct command *cmd, int timeout)
0149 {
0150 wait_event_interruptible_timeout(cmd->wait,
0151 cmd->status == IBMASM_CMD_COMPLETE ||
0152 cmd->status == IBMASM_CMD_FAILED,
0153 timeout * HZ);
0154 }
0155
0156
0157
0158
0159
0160
0161 void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size)
0162 {
0163 struct command *cmd = sp->current_command;
0164
0165 if (!sp->current_command)
0166 return;
0167
0168 memcpy_fromio(cmd->buffer, response, min(size, cmd->buffer_size));
0169 cmd->status = IBMASM_CMD_COMPLETE;
0170 wake_up(&sp->current_command->wait);
0171 command_put(sp->current_command);
0172 exec_next_command(sp);
0173 }