1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun /*
4*4882a593Smuzhiyun * IBM ASM Service Processor Device Driver
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright (C) IBM Corporation, 2004
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Author: Max Asböck <amax@us.ibm.com>
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/sched.h>
12*4882a593Smuzhiyun #include <linux/slab.h>
13*4882a593Smuzhiyun #include "ibmasm.h"
14*4882a593Smuzhiyun #include "lowlevel.h"
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun static void exec_next_command(struct service_processor *sp);
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun static atomic_t command_count = ATOMIC_INIT(0);
19*4882a593Smuzhiyun
ibmasm_new_command(struct service_processor * sp,size_t buffer_size)20*4882a593Smuzhiyun struct command *ibmasm_new_command(struct service_processor *sp, size_t buffer_size)
21*4882a593Smuzhiyun {
22*4882a593Smuzhiyun struct command *cmd;
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun if (buffer_size > IBMASM_CMD_MAX_BUFFER_SIZE)
25*4882a593Smuzhiyun return NULL;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun cmd = kzalloc(sizeof(struct command), GFP_KERNEL);
28*4882a593Smuzhiyun if (cmd == NULL)
29*4882a593Smuzhiyun return NULL;
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun cmd->buffer = kzalloc(buffer_size, GFP_KERNEL);
33*4882a593Smuzhiyun if (cmd->buffer == NULL) {
34*4882a593Smuzhiyun kfree(cmd);
35*4882a593Smuzhiyun return NULL;
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun cmd->buffer_size = buffer_size;
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun kref_init(&cmd->kref);
40*4882a593Smuzhiyun cmd->lock = &sp->lock;
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun cmd->status = IBMASM_CMD_PENDING;
43*4882a593Smuzhiyun init_waitqueue_head(&cmd->wait);
44*4882a593Smuzhiyun INIT_LIST_HEAD(&cmd->queue_node);
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun atomic_inc(&command_count);
47*4882a593Smuzhiyun dbg("command count: %d\n", atomic_read(&command_count));
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun return cmd;
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
ibmasm_free_command(struct kref * kref)52*4882a593Smuzhiyun void ibmasm_free_command(struct kref *kref)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun struct command *cmd = to_command(kref);
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun list_del(&cmd->queue_node);
57*4882a593Smuzhiyun atomic_dec(&command_count);
58*4882a593Smuzhiyun dbg("command count: %d\n", atomic_read(&command_count));
59*4882a593Smuzhiyun kfree(cmd->buffer);
60*4882a593Smuzhiyun kfree(cmd);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun
enqueue_command(struct service_processor * sp,struct command * cmd)63*4882a593Smuzhiyun static void enqueue_command(struct service_processor *sp, struct command *cmd)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun list_add_tail(&cmd->queue_node, &sp->command_queue);
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun
dequeue_command(struct service_processor * sp)68*4882a593Smuzhiyun static struct command *dequeue_command(struct service_processor *sp)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun struct command *cmd;
71*4882a593Smuzhiyun struct list_head *next;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun if (list_empty(&sp->command_queue))
74*4882a593Smuzhiyun return NULL;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun next = sp->command_queue.next;
77*4882a593Smuzhiyun list_del_init(next);
78*4882a593Smuzhiyun cmd = list_entry(next, struct command, queue_node);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun return cmd;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
do_exec_command(struct service_processor * sp)83*4882a593Smuzhiyun static inline void do_exec_command(struct service_processor *sp)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun char tsbuf[32];
86*4882a593Smuzhiyun
87*4882a593Smuzhiyun dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun if (ibmasm_send_i2o_message(sp)) {
90*4882a593Smuzhiyun sp->current_command->status = IBMASM_CMD_FAILED;
91*4882a593Smuzhiyun wake_up(&sp->current_command->wait);
92*4882a593Smuzhiyun command_put(sp->current_command);
93*4882a593Smuzhiyun exec_next_command(sp);
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun /*
98*4882a593Smuzhiyun * exec_command
99*4882a593Smuzhiyun * send a command to a service processor
100*4882a593Smuzhiyun * Commands are executed sequentially. One command (sp->current_command)
101*4882a593Smuzhiyun * is sent to the service processor. Once the interrupt handler gets a
102*4882a593Smuzhiyun * message of type command_response, the message is copied into
103*4882a593Smuzhiyun * the current commands buffer,
104*4882a593Smuzhiyun */
ibmasm_exec_command(struct service_processor * sp,struct command * cmd)105*4882a593Smuzhiyun void ibmasm_exec_command(struct service_processor *sp, struct command *cmd)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun unsigned long flags;
108*4882a593Smuzhiyun char tsbuf[32];
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun spin_lock_irqsave(&sp->lock, flags);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun if (!sp->current_command) {
115*4882a593Smuzhiyun sp->current_command = cmd;
116*4882a593Smuzhiyun command_get(sp->current_command);
117*4882a593Smuzhiyun spin_unlock_irqrestore(&sp->lock, flags);
118*4882a593Smuzhiyun do_exec_command(sp);
119*4882a593Smuzhiyun } else {
120*4882a593Smuzhiyun enqueue_command(sp, cmd);
121*4882a593Smuzhiyun spin_unlock_irqrestore(&sp->lock, flags);
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun
exec_next_command(struct service_processor * sp)125*4882a593Smuzhiyun static void exec_next_command(struct service_processor *sp)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun unsigned long flags;
128*4882a593Smuzhiyun char tsbuf[32];
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun spin_lock_irqsave(&sp->lock, flags);
133*4882a593Smuzhiyun sp->current_command = dequeue_command(sp);
134*4882a593Smuzhiyun if (sp->current_command) {
135*4882a593Smuzhiyun command_get(sp->current_command);
136*4882a593Smuzhiyun spin_unlock_irqrestore(&sp->lock, flags);
137*4882a593Smuzhiyun do_exec_command(sp);
138*4882a593Smuzhiyun } else {
139*4882a593Smuzhiyun spin_unlock_irqrestore(&sp->lock, flags);
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun /*
144*4882a593Smuzhiyun * Sleep until a command has failed or a response has been received
145*4882a593Smuzhiyun * and the command status been updated by the interrupt handler.
146*4882a593Smuzhiyun * (see receive_response).
147*4882a593Smuzhiyun */
ibmasm_wait_for_response(struct command * cmd,int timeout)148*4882a593Smuzhiyun void ibmasm_wait_for_response(struct command *cmd, int timeout)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun wait_event_interruptible_timeout(cmd->wait,
151*4882a593Smuzhiyun cmd->status == IBMASM_CMD_COMPLETE ||
152*4882a593Smuzhiyun cmd->status == IBMASM_CMD_FAILED,
153*4882a593Smuzhiyun timeout * HZ);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun /*
157*4882a593Smuzhiyun * receive_command_response
158*4882a593Smuzhiyun * called by the interrupt handler when a dot command of type command_response
159*4882a593Smuzhiyun * was received.
160*4882a593Smuzhiyun */
ibmasm_receive_command_response(struct service_processor * sp,void * response,size_t size)161*4882a593Smuzhiyun void ibmasm_receive_command_response(struct service_processor *sp, void *response, size_t size)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun struct command *cmd = sp->current_command;
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun if (!sp->current_command)
166*4882a593Smuzhiyun return;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun memcpy_fromio(cmd->buffer, response, min(size, cmd->buffer_size));
169*4882a593Smuzhiyun cmd->status = IBMASM_CMD_COMPLETE;
170*4882a593Smuzhiyun wake_up(&sp->current_command->wait);
171*4882a593Smuzhiyun command_put(sp->current_command);
172*4882a593Smuzhiyun exec_next_command(sp);
173*4882a593Smuzhiyun }
174