blob: 92d6358433643c2b531b75f4808a511e44fad96f [file] [log] [blame]
Andrew Jeffery4fe996c2018-02-27 12:16:48 +10301// SPDX-License-Identifier: Apache-2.0
2// Copyright (C) 2018 IBM Corp.
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +11003
4#define _GNU_SOURCE
5#include <assert.h>
6#include <errno.h>
7#include <fcntl.h>
8#include <getopt.h>
9#include <limits.h>
10#include <poll.h>
11#include <stdbool.h>
12#include <stdint.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <syslog.h>
17#include <signal.h>
18#include <sys/ioctl.h>
19#include <sys/mman.h>
20#include <sys/stat.h>
21#include <sys/timerfd.h>
22#include <sys/types.h>
23#include <time.h>
24#include <unistd.h>
25#include <inttypes.h>
26
Andrew Jeffery26558db2018-08-10 00:22:38 +093027#include "mboxd.h"
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110028#include "common.h"
Andrew Jeffery457a6e52018-08-08 11:21:08 +093029#include "transport_mbox.h"
Andrew Jefferyf593b1b2018-08-08 11:01:04 +093030#include "windows.h"
Andrew Jefferycd186112018-08-08 10:47:55 +093031#include "lpc.h"
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110032
Patrick Williams68a24c92023-07-25 12:02:16 -050033#pragma GCC diagnostic push
34#pragma GCC diagnostic ignored "-Wpointer-arith"
35
Andrew Jeffery1e531af2018-08-07 13:32:57 +093036struct errno_map {
37 int rc;
38 int mbox_errno;
39};
40
41static const struct errno_map errno_map_v1[] = {
42 { 0, MBOX_R_SUCCESS },
43 { EACCES, MBOX_R_PARAM_ERROR },
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093044 { EBADMSG, MBOX_R_PARAM_ERROR },
Andrew Jeffery1e531af2018-08-07 13:32:57 +093045 { EBUSY, MBOX_R_SYSTEM_ERROR },
46 { EINVAL, MBOX_R_PARAM_ERROR },
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093047 { ENOTSUP, MBOX_R_PARAM_ERROR },
Andrew Jeffery1e531af2018-08-07 13:32:57 +093048 { EPERM, MBOX_R_PARAM_ERROR },
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093049 { EPROTO, MBOX_R_PARAM_ERROR },
Andrew Jeffery1e531af2018-08-07 13:32:57 +093050 { ETIMEDOUT, MBOX_R_TIMEOUT },
51 { -1, MBOX_R_SYSTEM_ERROR },
52};
53
54static const struct errno_map errno_map_v2[] = {
55 { 0, MBOX_R_SUCCESS },
Andrew Jefferyc7d19472018-08-08 11:43:08 +093056 { EACCES, MBOX_R_WINDOW_ERROR },
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093057 { EBADMSG, MBOX_R_SEQ_ERROR },
Andrew Jeffery1e531af2018-08-07 13:32:57 +093058 { EBUSY, MBOX_R_BUSY },
59 { EINVAL, MBOX_R_PARAM_ERROR },
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093060 { ENOTSUP, MBOX_R_PARAM_ERROR },
Andrew Jeffery1e531af2018-08-07 13:32:57 +093061 { EPERM, MBOX_R_WINDOW_ERROR },
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093062 { EPROTO, MBOX_R_PARAM_ERROR },
Andrew Jeffery1e531af2018-08-07 13:32:57 +093063 { ETIMEDOUT, MBOX_R_TIMEOUT },
64 { -1, MBOX_R_SYSTEM_ERROR },
65};
66
67static const struct errno_map *errno_maps[] = {
68 [0] = NULL,
69 [1] = errno_map_v1,
70 [2] = errno_map_v2,
71};
72
73static inline int mbox_xlate_errno(struct mbox_context *context,
74 int rc)
75{
76 const struct errno_map *entry;
77
78 rc = -rc;
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093079 MSG_DBG("Translating errno %d: %s\n", rc, strerror(rc));
Andrew Jeffery1e531af2018-08-07 13:32:57 +093080 for(entry = errno_maps[context->version]; entry->rc != -1; entry++) {
81 if (rc == entry->rc) {
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093082 return entry->mbox_errno;
Andrew Jeffery1e531af2018-08-07 13:32:57 +093083 }
84 }
85
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093086 return entry->mbox_errno;
Andrew Jeffery1e531af2018-08-07 13:32:57 +093087}
88
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110089/*
Andrew Jeffery5335f092018-08-09 14:56:08 +093090 * transport_mbox_flush_events() - Write to the BMC controlled status register
91 * (reg 15)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110092 * @context: The mbox context pointer
93 *
94 * Return: 0 on success otherwise negative error code
95 */
Andrew Jefferyf62601b2018-11-01 13:44:25 +103096static int transport_mbox_flush_events(struct mbox_context *context, uint8_t events)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110097{
98 int rc;
99
100 /* Seek mbox registers */
101 rc = lseek(context->fds[MBOX_FD].fd, MBOX_BMC_EVENT, SEEK_SET);
102 if (rc != MBOX_BMC_EVENT) {
103 MSG_ERR("Couldn't lseek mbox to byte %d: %s\n", MBOX_BMC_EVENT,
104 strerror(errno));
Andrew Jeffery5335f092018-08-09 14:56:08 +0930105 return -errno;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100106 }
107
108 /* Write to mbox status register */
Andrew Jefferyf62601b2018-11-01 13:44:25 +1030109 rc = write(context->fds[MBOX_FD].fd, &events, 1);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100110 if (rc != 1) {
111 MSG_ERR("Couldn't write to BMC status reg: %s\n",
112 strerror(errno));
Andrew Jeffery5335f092018-08-09 14:56:08 +0930113 return -errno;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100114 }
115
116 /* Reset to start */
117 rc = lseek(context->fds[MBOX_FD].fd, 0, SEEK_SET);
118 if (rc) {
119 MSG_ERR("Couldn't reset MBOX offset to zero: %s\n",
120 strerror(errno));
Andrew Jeffery5335f092018-08-09 14:56:08 +0930121 return -errno;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100122 }
123
124 return 0;
125}
126
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030127static int transport_mbox_put_events(struct mbox_context *context,
128 uint8_t mask)
Andrew Jeffery4414fb82018-08-20 12:13:09 +0930129{
Andrew Jefferyf62601b2018-11-01 13:44:25 +1030130 return transport_mbox_flush_events(context, context->bmc_events & mask);
Andrew Jeffery4414fb82018-08-20 12:13:09 +0930131}
132
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030133static int transport_mbox_update_events(struct mbox_context *context,
Patrick Williams68a24c92023-07-25 12:02:16 -0500134 uint8_t events __attribute__((unused)),
135 uint8_t mask)
Andrew Jeffery4414fb82018-08-20 12:13:09 +0930136{
Andrew Jefferyf62601b2018-11-01 13:44:25 +1030137 return transport_mbox_flush_events(context, context->bmc_events & mask);
Andrew Jeffery4414fb82018-08-20 12:13:09 +0930138}
139
Andrew Jeffery23a48212018-08-10 14:41:48 +0930140static const struct transport_ops transport_mbox_ops = {
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030141 .put_events = transport_mbox_put_events,
142 .set_events = transport_mbox_update_events,
143 .clear_events = transport_mbox_update_events,
Andrew Jeffery23a48212018-08-10 14:41:48 +0930144};
145
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100146/* Command Handlers */
147
148/*
149 * Command: RESET_STATE
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500150 * Reset the LPC mapping to point back at the flash, or memory in case we're
151 * using a virtual pnor.
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100152 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930153static int mbox_handle_reset(struct mbox_context *context,
Patrick Williams68a24c92023-07-25 12:02:16 -0500154 union mbox_regs *req __attribute__((unused)),
155 struct mbox_msg *resp __attribute__((unused)))
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100156{
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930157 return context->protocol->reset(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100158}
159
160/*
161 * Command: GET_MBOX_INFO
162 * Get the API version, default window size and block size
163 * We also set the LPC mapping to point to the reserved memory region here so
164 * this command must be called before any window manipulation
165 *
166 * V1:
167 * ARGS[0]: API Version
168 *
169 * RESP[0]: API Version
170 * RESP[1:2]: Default read window size (number of blocks)
171 * RESP[3:4]: Default write window size (number of blocks)
172 * RESP[5]: Block size (as shift)
173 *
174 * V2:
175 * ARGS[0]: API Version
176 *
177 * RESP[0]: API Version
178 * RESP[1:2]: Default read window size (number of blocks)
179 * RESP[3:4]: Default write window size (number of blocks)
180 * RESP[5]: Block size (as shift)
181 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930182static int mbox_handle_mbox_info(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100183 union mbox_regs *req, struct mbox_msg *resp)
184{
185 uint8_t mbox_api_version = req->msg.args[0];
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930186 struct protocol_get_info io = {
187 .req = { .api_version = mbox_api_version }
188 };
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100189 int rc;
190
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930191 rc = context->protocol->get_info(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100192 if (rc < 0) {
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930193 return rc;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100194 }
195
Andrew Jeffery23a48212018-08-10 14:41:48 +0930196 /*
197 * Switch transport to mbox, however we need to delay flushing the
198 * event state until after the command is processed.
199 */
200 context->transport = &transport_mbox_ops;
201
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930202 resp->args[0] = io.resp.api_version;
203 if (io.resp.api_version == API_VERSION_1) {
204 put_u16(&resp->args[1], io.resp.v1.read_window_size);
205 put_u16(&resp->args[3], io.resp.v1.write_window_size);
206 } else if (io.resp.api_version >= API_VERSION_2) {
207 resp->args[5] = io.resp.v2.block_size_shift;
208 put_u16(&resp->args[6], io.resp.v2.timeout);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100209 }
210
211 return 0;
212}
213
214/*
215 * Command: GET_FLASH_INFO
216 * Get the flash size and erase granularity
217 *
218 * V1:
219 * RESP[0:3]: Flash Size (bytes)
220 * RESP[4:7]: Erase Size (bytes)
221 * V2:
222 * RESP[0:1]: Flash Size (number of blocks)
223 * RESP[2:3]: Erase Size (number of blocks)
224 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930225static int mbox_handle_flash_info(struct mbox_context *context,
Patrick Williams68a24c92023-07-25 12:02:16 -0500226 union mbox_regs *req __attribute__((unused)),
227 struct mbox_msg *resp)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100228{
Andrew Jeffery91a87452018-08-07 14:54:14 +0930229 struct protocol_get_flash_info io;
230 int rc;
231
232 rc = context->protocol->get_flash_info(context, &io);
233 if (rc < 0) {
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930234 return rc;
Andrew Jeffery91a87452018-08-07 14:54:14 +0930235 }
236
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100237 switch (context->version) {
238 case API_VERSION_1:
239 /* Both Sizes in Bytes */
Andrew Jeffery91a87452018-08-07 14:54:14 +0930240 put_u32(&resp->args[0], io.resp.v1.flash_size);
241 put_u32(&resp->args[4], io.resp.v1.erase_size);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100242 break;
243 case API_VERSION_2:
244 /* Both Sizes in Block Size */
Andrew Jeffery91a87452018-08-07 14:54:14 +0930245 put_u16(&resp->args[0], io.resp.v2.flash_size);
246 put_u16(&resp->args[2], io.resp.v2.erase_size);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100247 break;
248 default:
249 MSG_ERR("API Version Not Valid - Invalid System State\n");
250 return -MBOX_R_SYSTEM_ERROR;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100251 }
252
253 return 0;
254}
255
256/*
257 * get_lpc_addr_shifted() - Get lpc address of the current window
258 * @context: The mbox context pointer
259 *
260 * Return: The lpc address to access that offset shifted by block size
261 */
262static inline uint16_t get_lpc_addr_shifted(struct mbox_context *context)
263{
264 uint32_t lpc_addr, mem_offset;
265
266 /* Offset of the current window in the reserved memory region */
267 mem_offset = context->current->mem - context->mem;
268 /* Total LPC Address */
269 lpc_addr = context->lpc_base + mem_offset;
270
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000271 MSG_DBG("LPC address of current window: 0x%.8x\n", lpc_addr);
272
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030273 return lpc_addr >> context->backend.block_size_shift;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100274}
275
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930276static int mbox_handle_create_window(struct mbox_context *context, bool ro,
Andrew Jeffery4bcec8e2018-08-07 15:33:41 +0930277 union mbox_regs *req, struct mbox_msg *resp)
278{
279 struct protocol_create_window io;
280 int rc;
281
282 io.req.offset = get_u16(&req->msg.args[0]);
283 io.req.ro = ro;
284
285 rc = context->protocol->create_window(context, &io);
286 if (rc < 0) {
287 return rc;
288 }
289
290 put_u16(&resp->args[0], io.resp.lpc_address);
291 if (context->version >= API_VERSION_2) {
292 put_u16(&resp->args[2], io.resp.size);
293 put_u16(&resp->args[4], io.resp.offset);
294 }
295
296 return 0;
297}
298
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100299/*
300 * Command: CREATE_READ_WINDOW
301 * Opens a read window
302 * First checks if any current window with the requested data, if so we just
303 * point the host to that. Otherwise we read the request data in from flash and
304 * point the host there.
305 *
306 * V1:
307 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
308 *
309 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
310 *
311 * V2:
312 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
313 * ARGS[2:3]: Requested window size (number of blocks)
314 *
315 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
316 * RESP[2:3]: Actual window size that the host can access (number of blocks)
317 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930318static int mbox_handle_read_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100319 union mbox_regs *req, struct mbox_msg *resp)
320{
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930321 return mbox_handle_create_window(context, true, req, resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100322}
323
324/*
325 * Command: CREATE_WRITE_WINDOW
326 * Opens a write window
327 * First checks if any current window with the requested data, if so we just
328 * point the host to that. Otherwise we read the request data in from flash and
329 * point the host there.
330 *
331 * V1:
332 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
333 *
334 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
335 *
336 * V2:
337 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
338 * ARGS[2:3]: Requested window size (number of blocks)
339 *
340 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
341 * RESP[2:3]: Actual window size that was mapped/host can access (n.o. blocks)
342 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930343static int mbox_handle_write_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100344 union mbox_regs *req, struct mbox_msg *resp)
345{
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930346 return mbox_handle_create_window(context, false, req, resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100347}
348
349/*
350 * Commands: MARK_WRITE_DIRTY
351 * Marks a portion of the current (write) window dirty, informing the daemon
352 * that is has been written to and thus must be at some point written to the
353 * backing store
354 * These changes aren't written back to the backing store unless flush is then
355 * called or the window closed
356 *
357 * V1:
358 * ARGS[0:1]: Where within flash to start (number of blocks)
359 * ARGS[2:5]: Number to mark dirty (number of bytes)
360 *
361 * V2:
362 * ARGS[0:1]: Where within window to start (number of blocks)
363 * ARGS[2:3]: Number to mark dirty (number of blocks)
364 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930365static int mbox_handle_dirty_window(struct mbox_context *context,
Patrick Williams68a24c92023-07-25 12:02:16 -0500366 union mbox_regs *req,
367 struct mbox_msg *resp __attribute__((unused)))
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100368{
Andrew Jefferya336e432018-08-07 16:00:40 +0930369 struct protocol_mark_dirty io;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100370
Andrew Jefferya336e432018-08-07 16:00:40 +0930371 if (context->version == API_VERSION_1) {
372 io.req.v1.offset = get_u16(&req->msg.args[0]);
373 io.req.v1.size = get_u32(&req->msg.args[2]);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100374 } else {
Andrew Jefferya336e432018-08-07 16:00:40 +0930375 io.req.v2.offset = get_u16(&req->msg.args[0]);
376 io.req.v2.size = get_u16(&req->msg.args[2]);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100377 }
378
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930379 return context->protocol->mark_dirty(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100380}
381
382/*
383 * Commands: MARK_WRITE_ERASE
384 * Erases a portion of the current window
385 * These changes aren't written back to the backing store unless flush is then
386 * called or the window closed
387 *
388 * V1:
389 * Unimplemented
390 *
391 * V2:
392 * ARGS[0:1]: Where within window to start (number of blocks)
393 * ARGS[2:3]: Number to erase (number of blocks)
394 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930395static int mbox_handle_erase_window(struct mbox_context *context,
Patrick Williams68a24c92023-07-25 12:02:16 -0500396 union mbox_regs *req,
397 struct mbox_msg *resp __attribute__((unused)))
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100398{
Andrew Jeffery62a3daa2018-08-07 22:30:32 +0930399 struct protocol_erase io;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100400
Andrew Jeffery62a3daa2018-08-07 22:30:32 +0930401 io.req.offset = get_u16(&req->msg.args[0]);
402 io.req.size = get_u16(&req->msg.args[2]);
403
404 if (!context->protocol->erase) {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100405 MSG_ERR("Protocol Version invalid for Erase Command\n");
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930406 return -ENOTSUP;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100407 }
408
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930409 return context->protocol->erase(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100410}
411
412/*
413 * Command: WRITE_FLUSH
414 * Flushes any dirty or erased blocks in the current window back to the backing
415 * store
416 * NOTE: For V1 this behaves much the same as the dirty command in that it
417 * takes an offset and number of blocks to dirty, then also performs a flush as
418 * part of the same command. For V2 this will only flush blocks already marked
419 * dirty/erased with the appropriate commands and doesn't take any arguments
420 * directly.
421 *
422 * V1:
423 * ARGS[0:1]: Where within window to start (number of blocks)
424 * ARGS[2:5]: Number to mark dirty (number of bytes)
425 *
426 * V2:
427 * NONE
428 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930429static int mbox_handle_flush_window(struct mbox_context *context,
Patrick Williams68a24c92023-07-25 12:02:16 -0500430 union mbox_regs *req,
431 struct mbox_msg *resp __attribute__((unused)))
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100432{
Andrew Jeffery9b920cf2018-08-07 22:49:19 +0930433 struct protocol_flush io = { 0 };
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100434
Andrew Jeffery9b920cf2018-08-07 22:49:19 +0930435 if (context->version == API_VERSION_1) {
436 io.req.offset = get_u16(&req->msg.args[0]);
437 io.req.size = get_u32(&req->msg.args[2]);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100438 }
439
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930440 return context->protocol->flush(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100441}
442
443/*
444 * Command: CLOSE_WINDOW
445 * Close the current window
446 * NOTE: There is an implicit flush
447 *
448 * V1:
449 * NONE
450 *
451 * V2:
452 * ARGS[0]: FLAGS
453 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930454static int mbox_handle_close_window(struct mbox_context *context,
Patrick Williams68a24c92023-07-25 12:02:16 -0500455 union mbox_regs *req,
456 struct mbox_msg *resp __attribute__((unused)))
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100457{
Andrew Jeffery093eda52018-08-07 23:10:43 +0930458 struct protocol_close io = { 0 };
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100459
Andrew Jeffery093eda52018-08-07 23:10:43 +0930460 if (context->version >= API_VERSION_2) {
461 io.req.flags = req->msg.args[0];
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100462 }
463
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930464 return context->protocol->close(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100465}
466
467/*
468 * Command: BMC_EVENT_ACK
469 * Sent by the host to acknowledge BMC events supplied in mailbox register 15
470 *
471 * ARGS[0]: Bitmap of bits to ack (by clearing)
472 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930473static int mbox_handle_ack(struct mbox_context *context, union mbox_regs *req,
Patrick Williams68a24c92023-07-25 12:02:16 -0500474 struct mbox_msg *resp __attribute__((unused)))
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100475{
Andrew Jefferyc5c83042018-08-07 23:22:05 +0930476 struct protocol_ack io;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100477
Andrew Jefferyc5c83042018-08-07 23:22:05 +0930478 io.req.flags = req->msg.args[0];
479
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930480 return context->protocol->ack(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100481}
482
483/*
Andrew Jeffery55dede62017-04-24 16:13:06 +0930484 * check_req_valid() - Check if the given request is a valid mbox request
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100485 * @context: The mbox context pointer
Andrew Jeffery55dede62017-04-24 16:13:06 +0930486 * @cmd: The request registers
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100487 *
Andrew Jeffery55dede62017-04-24 16:13:06 +0930488 * Return: 0 if request is valid otherwise negative error code
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100489 */
Andrew Jeffery55dede62017-04-24 16:13:06 +0930490static int check_req_valid(struct mbox_context *context, union mbox_regs *req)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100491{
Andrew Jeffery55dede62017-04-24 16:13:06 +0930492 uint8_t cmd = req->msg.command;
493 uint8_t seq = req->msg.seq;
494
495 if (cmd > NUM_MBOX_CMDS) {
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930496 MSG_ERR("Unknown mbox command: %d\n", cmd);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930497 return -ENOTSUP;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100498 }
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930499
Andrew Jeffery55dede62017-04-24 16:13:06 +0930500 if (seq == context->prev_seq && cmd != MBOX_C_GET_MBOX_INFO) {
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000501 MSG_ERR("Invalid sequence number: %d, previous: %d\n", seq,
502 context->prev_seq);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930503 return -EBADMSG;
Andrew Jeffery55dede62017-04-24 16:13:06 +0930504 }
505
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100506 if (context->state & STATE_SUSPENDED) {
507 if (cmd != MBOX_C_GET_MBOX_INFO && cmd != MBOX_C_ACK) {
508 MSG_ERR("Cannot use that cmd while suspended: %d\n",
509 cmd);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930510 return -EBUSY;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100511 }
512 }
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930513
Andrew Jeffery23a48212018-08-10 14:41:48 +0930514 if (context->transport != &transport_mbox_ops) {
515 if (cmd != MBOX_C_RESET_STATE && cmd != MBOX_C_GET_MBOX_INFO) {
516 MSG_ERR("Cannot switch transport with command %d\n",
517 cmd);
518 return -EPROTO;
519 }
520 }
521
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100522 if (!(context->state & MAPS_MEM)) {
523 if (cmd != MBOX_C_RESET_STATE && cmd != MBOX_C_GET_MBOX_INFO
524 && cmd != MBOX_C_ACK) {
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930525 MSG_ERR("Must call GET_MBOX_INFO before %d\n", cmd);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930526 return -EPROTO;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100527 }
528 }
529
530 return 0;
531}
532
Andrew Jeffery5335f092018-08-09 14:56:08 +0930533typedef int (*mboxd_mbox_handler)(struct mbox_context *, union mbox_regs *,
534 struct mbox_msg *);
535
536static const mboxd_mbox_handler transport_mbox_handlers[] = {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100537 mbox_handle_reset,
538 mbox_handle_mbox_info,
539 mbox_handle_flash_info,
540 mbox_handle_read_window,
541 mbox_handle_close_window,
542 mbox_handle_write_window,
543 mbox_handle_dirty_window,
544 mbox_handle_flush_window,
545 mbox_handle_ack,
546 mbox_handle_erase_window
547};
548
549/*
550 * handle_mbox_req() - Handle an incoming mbox command request
551 * @context: The mbox context pointer
552 * @req: The mbox request message
553 *
554 * Return: 0 if handled successfully otherwise negative error code
555 */
556static int handle_mbox_req(struct mbox_context *context, union mbox_regs *req)
557{
Andrew Jeffery23a48212018-08-10 14:41:48 +0930558 const struct transport_ops *old_transport = context->transport;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100559 struct mbox_msg resp = {
560 .command = req->msg.command,
561 .seq = req->msg.seq,
562 .args = { 0 },
563 .response = MBOX_R_SUCCESS
564 };
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000565 int rc = 0, len, i;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100566
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000567 MSG_INFO("Received MBOX command: %u\n", req->msg.command);
Andrew Jeffery23a48212018-08-10 14:41:48 +0930568
Andrew Jeffery55dede62017-04-24 16:13:06 +0930569 rc = check_req_valid(context, req);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930570 if (!rc) {
Andrew Jeffery5335f092018-08-09 14:56:08 +0930571 mboxd_mbox_handler handler;
572
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100573 /* Commands start at 1 so we have to subtract 1 from the cmd */
Andrew Jeffery5335f092018-08-09 14:56:08 +0930574 handler = transport_mbox_handlers[req->msg.command - 1];
575 rc = handler(context, req, &resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100576 if (rc < 0) {
577 MSG_ERR("Error handling mbox cmd: %d\n",
578 req->msg.command);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100579 }
580 }
581
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930582 rc = mbox_xlate_errno(context, rc);
583 resp.response = rc;
Andrew Jeffery55dede62017-04-24 16:13:06 +0930584 context->prev_seq = req->msg.seq;
585
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000586 MSG_DBG("Writing MBOX response:\n");
587 MSG_DBG("MBOX cmd: %u\n", resp.command);
588 MSG_DBG("MBOX seq: %u\n", resp.seq);
589 for (i = 0; i < MBOX_ARGS_BYTES; i++) {
590 MSG_DBG("MBOX arg[%d]: 0x%.2x\n", i, resp.args[i]);
591 }
592 MSG_INFO("Writing MBOX response: %u\n", resp.response);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100593 len = write(context->fds[MBOX_FD].fd, &resp, sizeof(resp));
Patrick Williams68a24c92023-07-25 12:02:16 -0500594 if (len < (ssize_t)sizeof(resp)) {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100595 MSG_ERR("Didn't write the full response\n");
596 rc = -errno;
597 }
598
Andrew Jeffery23a48212018-08-10 14:41:48 +0930599 if (context->transport != old_transport &&
600 context->transport == &transport_mbox_ops) {
Andrew Jeffery0453aa42018-08-21 08:25:46 +0930601 /* A bit messy, but we need the correct event mask */
602 protocol_events_set(context, context->bmc_events);
Andrew Jeffery23a48212018-08-10 14:41:48 +0930603 }
604
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100605 return rc;
606}
607
608/*
609 * get_message() - Read an mbox request message from the mbox registers
610 * @context: The mbox context pointer
611 * @msg: Where to put the received message
612 *
613 * Return: 0 if read successfully otherwise negative error code
614 */
615static int get_message(struct mbox_context *context, union mbox_regs *msg)
616{
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000617 int rc, i;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100618
619 rc = read(context->fds[MBOX_FD].fd, msg, sizeof(msg->raw));
620 if (rc < 0) {
621 MSG_ERR("Couldn't read: %s\n", strerror(errno));
622 return -errno;
Patrick Williams68a24c92023-07-25 12:02:16 -0500623 } else if (rc < (ssize_t)sizeof(msg->raw)) {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100624 MSG_ERR("Short read: %d expecting %zu\n", rc, sizeof(msg->raw));
625 return -1;
626 }
627
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000628 MSG_DBG("Received MBOX request:\n");
629 MSG_DBG("MBOX cmd: %u\n", msg->msg.command);
630 MSG_DBG("MBOX seq: %u\n", msg->msg.seq);
631 for (i = 0; i < MBOX_ARGS_BYTES; i++) {
632 MSG_DBG("MBOX arg[%d]: 0x%.2x\n", i, msg->msg.args[i]);
633 }
634
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100635 return 0;
636}
637
638/*
Andrew Jefferyd86141b2018-08-09 14:58:53 +0930639 * transport_mbox_dispatch() - handle an mbox interrupt
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100640 * @context: The mbox context pointer
641 *
642 * Return: 0 if handled successfully otherwise negative error code
643 */
Andrew Jefferyd86141b2018-08-09 14:58:53 +0930644int transport_mbox_dispatch(struct mbox_context *context)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100645{
646 int rc = 0;
647 union mbox_regs req = { 0 };
648
649 assert(context);
650
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100651 rc = get_message(context, &req);
652 if (rc) {
653 return rc;
654 }
655
656 return handle_mbox_req(context, &req);
657}
658
Andrew Jeffery4b8203d2019-05-06 14:36:16 +0930659int __transport_mbox_init(struct mbox_context *context, const char *path,
660 const struct transport_ops **ops)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100661{
662 int fd;
663
664 /* Open MBOX Device */
Andrew Jeffery913740f2017-04-10 23:51:07 +0930665 fd = open(path, O_RDWR | O_NONBLOCK);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100666 if (fd < 0) {
Andrew Jeffery4b8203d2019-05-06 14:36:16 +0930667 MSG_INFO("Couldn't open %s with flags O_RDWR: %s\n",
Andrew Jeffery913740f2017-04-10 23:51:07 +0930668 path, strerror(errno));
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100669 return -errno;
670 }
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000671 MSG_DBG("Opened mbox dev: %s\n", path);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100672
673 context->fds[MBOX_FD].fd = fd;
674
Andrew Jeffery4b8203d2019-05-06 14:36:16 +0930675 if (ops) {
676 *ops = &transport_mbox_ops;
677 }
678
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100679 return 0;
680}
681
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030682int transport_mbox_init(struct mbox_context *context,
683 const struct transport_ops **ops)
Andrew Jeffery913740f2017-04-10 23:51:07 +0930684{
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030685 int rc;
686
Andrew Jeffery4b8203d2019-05-06 14:36:16 +0930687 rc = __transport_mbox_init(context, MBOX_HOST_PATH, ops);
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030688 if (rc)
689 return rc;
690
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030691 return 0;
Andrew Jeffery913740f2017-04-10 23:51:07 +0930692}
693
Andrew Jeffery55260ce2018-08-09 15:05:59 +0930694void transport_mbox_free(struct mbox_context *context)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100695{
696 close(context->fds[MBOX_FD].fd);
697}
Patrick Williams68a24c92023-07-25 12:02:16 -0500698
699#pragma GCC diagnostic pop