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