blob: b0e0c0482a53f7a67915e028aebc763208b021e0 [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
27#include "mbox.h"
28#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
Andrew Jeffery1e531af2018-08-07 13:32:57 +093033struct errno_map {
34 int rc;
35 int mbox_errno;
36};
37
38static const struct errno_map errno_map_v1[] = {
39 { 0, MBOX_R_SUCCESS },
40 { EACCES, MBOX_R_PARAM_ERROR },
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093041 { EBADMSG, MBOX_R_PARAM_ERROR },
Andrew Jeffery1e531af2018-08-07 13:32:57 +093042 { EBUSY, MBOX_R_SYSTEM_ERROR },
43 { EINVAL, MBOX_R_PARAM_ERROR },
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093044 { ENOTSUP, MBOX_R_PARAM_ERROR },
Andrew Jeffery1e531af2018-08-07 13:32:57 +093045 { EPERM, MBOX_R_PARAM_ERROR },
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093046 { EPROTO, MBOX_R_PARAM_ERROR },
Andrew Jeffery1e531af2018-08-07 13:32:57 +093047 { ETIMEDOUT, MBOX_R_TIMEOUT },
48 { -1, MBOX_R_SYSTEM_ERROR },
49};
50
51static const struct errno_map errno_map_v2[] = {
52 { 0, MBOX_R_SUCCESS },
Andrew Jefferyc7d19472018-08-08 11:43:08 +093053 { EACCES, MBOX_R_WINDOW_ERROR },
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093054 { EBADMSG, MBOX_R_SEQ_ERROR },
Andrew Jeffery1e531af2018-08-07 13:32:57 +093055 { EBUSY, MBOX_R_BUSY },
56 { EINVAL, MBOX_R_PARAM_ERROR },
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093057 { ENOTSUP, MBOX_R_PARAM_ERROR },
Andrew Jeffery1e531af2018-08-07 13:32:57 +093058 { EPERM, MBOX_R_WINDOW_ERROR },
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093059 { EPROTO, MBOX_R_PARAM_ERROR },
Andrew Jeffery1e531af2018-08-07 13:32:57 +093060 { ETIMEDOUT, MBOX_R_TIMEOUT },
61 { -1, MBOX_R_SYSTEM_ERROR },
62};
63
64static const struct errno_map *errno_maps[] = {
65 [0] = NULL,
66 [1] = errno_map_v1,
67 [2] = errno_map_v2,
68};
69
70static inline int mbox_xlate_errno(struct mbox_context *context,
71 int rc)
72{
73 const struct errno_map *entry;
74
75 rc = -rc;
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093076 MSG_DBG("Translating errno %d: %s\n", rc, strerror(rc));
Andrew Jeffery1e531af2018-08-07 13:32:57 +093077 for(entry = errno_maps[context->version]; entry->rc != -1; entry++) {
78 if (rc == entry->rc) {
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093079 return entry->mbox_errno;
Andrew Jeffery1e531af2018-08-07 13:32:57 +093080 }
81 }
82
Andrew Jeffery2f1477c2018-08-09 23:24:38 +093083 return entry->mbox_errno;
Andrew Jeffery1e531af2018-08-07 13:32:57 +093084}
85
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110086/*
87 * write_bmc_event_reg() - Write to the BMC controlled status register (reg 15)
88 * @context: The mbox context pointer
89 *
90 * Return: 0 on success otherwise negative error code
91 */
92static int write_bmc_event_reg(struct mbox_context *context)
93{
94 int rc;
95
96 /* Seek mbox registers */
97 rc = lseek(context->fds[MBOX_FD].fd, MBOX_BMC_EVENT, SEEK_SET);
98 if (rc != MBOX_BMC_EVENT) {
99 MSG_ERR("Couldn't lseek mbox to byte %d: %s\n", MBOX_BMC_EVENT,
100 strerror(errno));
101 return -MBOX_R_SYSTEM_ERROR;
102 }
103
104 /* Write to mbox status register */
105 rc = write(context->fds[MBOX_FD].fd, &context->bmc_events, 1);
106 if (rc != 1) {
107 MSG_ERR("Couldn't write to BMC status reg: %s\n",
108 strerror(errno));
109 return -MBOX_R_SYSTEM_ERROR;
110 }
111
112 /* Reset to start */
113 rc = lseek(context->fds[MBOX_FD].fd, 0, SEEK_SET);
114 if (rc) {
115 MSG_ERR("Couldn't reset MBOX offset to zero: %s\n",
116 strerror(errno));
117 return -MBOX_R_SYSTEM_ERROR;
118 }
119
120 return 0;
121}
122
123/*
124 * set_bmc_events() - Set BMC events
125 * @context: The mbox context pointer
126 * @bmc_event: The bits to set
127 * @write_back: Whether to write back to the register -> will interrupt host
128 *
129 * Return: 0 on success otherwise negative error code
130 */
131int set_bmc_events(struct mbox_context *context, uint8_t bmc_event,
132 bool write_back)
133{
134 uint8_t mask = 0x00;
135
136 switch (context->version) {
137 case API_VERSION_1:
138 mask = BMC_EVENT_V1_MASK;
139 break;
140 default:
141 mask = BMC_EVENT_V2_MASK;
142 break;
143 }
144
145 context->bmc_events |= (bmc_event & mask);
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000146 MSG_DBG("BMC Events set to: 0x%.2x\n", context->bmc_events);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100147
148 return write_back ? write_bmc_event_reg(context) : 0;
149}
150
151/*
152 * clr_bmc_events() - Clear BMC events
153 * @context: The mbox context pointer
154 * @bmc_event: The bits to clear
155 * @write_back: Whether to write back to the register -> will interrupt host
156 *
157 * Return: 0 on success otherwise negative error code
158 */
159int clr_bmc_events(struct mbox_context *context, uint8_t bmc_event,
160 bool write_back)
161{
162 context->bmc_events &= ~bmc_event;
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000163 MSG_DBG("BMC Events clear to: 0x%.2x\n", context->bmc_events);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100164
165 return write_back ? write_bmc_event_reg(context) : 0;
166}
167
168/* Command Handlers */
169
170/*
171 * Command: RESET_STATE
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500172 * Reset the LPC mapping to point back at the flash, or memory in case we're
173 * using a virtual pnor.
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100174 */
Andrew Jeffery943aba02018-03-26 15:37:33 +1030175int mbox_handle_reset(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100176 union mbox_regs *req, struct mbox_msg *resp)
177{
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930178 return context->protocol->reset(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100179}
180
181/*
182 * Command: GET_MBOX_INFO
183 * Get the API version, default window size and block size
184 * We also set the LPC mapping to point to the reserved memory region here so
185 * this command must be called before any window manipulation
186 *
187 * V1:
188 * ARGS[0]: API Version
189 *
190 * RESP[0]: API Version
191 * RESP[1:2]: Default read window size (number of blocks)
192 * RESP[3:4]: Default write window size (number of blocks)
193 * RESP[5]: Block size (as shift)
194 *
195 * V2:
196 * ARGS[0]: API Version
197 *
198 * RESP[0]: API Version
199 * RESP[1:2]: Default read window size (number of blocks)
200 * RESP[3:4]: Default write window size (number of blocks)
201 * RESP[5]: Block size (as shift)
202 */
Andrew Jeffery943aba02018-03-26 15:37:33 +1030203int mbox_handle_mbox_info(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100204 union mbox_regs *req, struct mbox_msg *resp)
205{
206 uint8_t mbox_api_version = req->msg.args[0];
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930207 struct protocol_get_info io = {
208 .req = { .api_version = mbox_api_version }
209 };
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100210 int rc;
211
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930212 rc = context->protocol->get_info(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100213 if (rc < 0) {
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930214 return rc;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100215 }
216
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930217 resp->args[0] = io.resp.api_version;
218 if (io.resp.api_version == API_VERSION_1) {
219 put_u16(&resp->args[1], io.resp.v1.read_window_size);
220 put_u16(&resp->args[3], io.resp.v1.write_window_size);
221 } else if (io.resp.api_version >= API_VERSION_2) {
222 resp->args[5] = io.resp.v2.block_size_shift;
223 put_u16(&resp->args[6], io.resp.v2.timeout);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100224 }
225
226 return 0;
227}
228
229/*
230 * Command: GET_FLASH_INFO
231 * Get the flash size and erase granularity
232 *
233 * V1:
234 * RESP[0:3]: Flash Size (bytes)
235 * RESP[4:7]: Erase Size (bytes)
236 * V2:
237 * RESP[0:1]: Flash Size (number of blocks)
238 * RESP[2:3]: Erase Size (number of blocks)
239 */
Andrew Jeffery943aba02018-03-26 15:37:33 +1030240int mbox_handle_flash_info(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100241 union mbox_regs *req, struct mbox_msg *resp)
242{
Andrew Jeffery91a87452018-08-07 14:54:14 +0930243 struct protocol_get_flash_info io;
244 int rc;
245
246 rc = context->protocol->get_flash_info(context, &io);
247 if (rc < 0) {
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930248 return rc;
Andrew Jeffery91a87452018-08-07 14:54:14 +0930249 }
250
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100251 switch (context->version) {
252 case API_VERSION_1:
253 /* Both Sizes in Bytes */
Andrew Jeffery91a87452018-08-07 14:54:14 +0930254 put_u32(&resp->args[0], io.resp.v1.flash_size);
255 put_u32(&resp->args[4], io.resp.v1.erase_size);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100256 break;
257 case API_VERSION_2:
258 /* Both Sizes in Block Size */
Andrew Jeffery91a87452018-08-07 14:54:14 +0930259 put_u16(&resp->args[0], io.resp.v2.flash_size);
260 put_u16(&resp->args[2], io.resp.v2.erase_size);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100261 break;
262 default:
263 MSG_ERR("API Version Not Valid - Invalid System State\n");
264 return -MBOX_R_SYSTEM_ERROR;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100265 }
266
267 return 0;
268}
269
270/*
271 * get_lpc_addr_shifted() - Get lpc address of the current window
272 * @context: The mbox context pointer
273 *
274 * Return: The lpc address to access that offset shifted by block size
275 */
276static inline uint16_t get_lpc_addr_shifted(struct mbox_context *context)
277{
278 uint32_t lpc_addr, mem_offset;
279
280 /* Offset of the current window in the reserved memory region */
281 mem_offset = context->current->mem - context->mem;
282 /* Total LPC Address */
283 lpc_addr = context->lpc_base + mem_offset;
284
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000285 MSG_DBG("LPC address of current window: 0x%.8x\n", lpc_addr);
286
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100287 return lpc_addr >> context->block_size_shift;
288}
289
Andrew Jeffery4bcec8e2018-08-07 15:33:41 +0930290int mbox_handle_create_window(struct mbox_context *context, bool ro,
291 union mbox_regs *req, struct mbox_msg *resp)
292{
293 struct protocol_create_window io;
294 int rc;
295
296 io.req.offset = get_u16(&req->msg.args[0]);
297 io.req.ro = ro;
298
299 rc = context->protocol->create_window(context, &io);
300 if (rc < 0) {
301 return rc;
302 }
303
304 put_u16(&resp->args[0], io.resp.lpc_address);
305 if (context->version >= API_VERSION_2) {
306 put_u16(&resp->args[2], io.resp.size);
307 put_u16(&resp->args[4], io.resp.offset);
308 }
309
310 return 0;
311}
312
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100313/*
314 * Command: CREATE_READ_WINDOW
315 * Opens a read window
316 * First checks if any current window with the requested data, if so we just
317 * point the host to that. Otherwise we read the request data in from flash and
318 * point the host there.
319 *
320 * V1:
321 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
322 *
323 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
324 *
325 * V2:
326 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
327 * ARGS[2:3]: Requested window size (number of blocks)
328 *
329 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
330 * RESP[2:3]: Actual window size that the host can access (number of blocks)
331 */
Andrew Jeffery943aba02018-03-26 15:37:33 +1030332int mbox_handle_read_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100333 union mbox_regs *req, struct mbox_msg *resp)
334{
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930335 return mbox_handle_create_window(context, true, req, resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100336}
337
338/*
339 * Command: CREATE_WRITE_WINDOW
340 * Opens a write window
341 * First checks if any current window with the requested data, if so we just
342 * point the host to that. Otherwise we read the request data in from flash and
343 * point the host there.
344 *
345 * V1:
346 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
347 *
348 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
349 *
350 * V2:
351 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
352 * ARGS[2:3]: Requested window size (number of blocks)
353 *
354 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
355 * RESP[2:3]: Actual window size that was mapped/host can access (n.o. blocks)
356 */
Andrew Jeffery943aba02018-03-26 15:37:33 +1030357int mbox_handle_write_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100358 union mbox_regs *req, struct mbox_msg *resp)
359{
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930360 return mbox_handle_create_window(context, false, req, resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100361}
362
363/*
364 * Commands: MARK_WRITE_DIRTY
365 * Marks a portion of the current (write) window dirty, informing the daemon
366 * that is has been written to and thus must be at some point written to the
367 * backing store
368 * These changes aren't written back to the backing store unless flush is then
369 * called or the window closed
370 *
371 * V1:
372 * ARGS[0:1]: Where within flash to start (number of blocks)
373 * ARGS[2:5]: Number to mark dirty (number of bytes)
374 *
375 * V2:
376 * ARGS[0:1]: Where within window to start (number of blocks)
377 * ARGS[2:3]: Number to mark dirty (number of blocks)
378 */
Andrew Jeffery943aba02018-03-26 15:37:33 +1030379int mbox_handle_dirty_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100380 union mbox_regs *req, struct mbox_msg *resp)
381{
Andrew Jefferya336e432018-08-07 16:00:40 +0930382 struct protocol_mark_dirty io;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100383
Andrew Jefferya336e432018-08-07 16:00:40 +0930384 if (context->version == API_VERSION_1) {
385 io.req.v1.offset = get_u16(&req->msg.args[0]);
386 io.req.v1.size = get_u32(&req->msg.args[2]);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100387 } else {
Andrew Jefferya336e432018-08-07 16:00:40 +0930388 io.req.v2.offset = get_u16(&req->msg.args[0]);
389 io.req.v2.size = get_u16(&req->msg.args[2]);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100390 }
391
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930392 return context->protocol->mark_dirty(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100393}
394
395/*
396 * Commands: MARK_WRITE_ERASE
397 * Erases a portion of the current window
398 * These changes aren't written back to the backing store unless flush is then
399 * called or the window closed
400 *
401 * V1:
402 * Unimplemented
403 *
404 * V2:
405 * ARGS[0:1]: Where within window to start (number of blocks)
406 * ARGS[2:3]: Number to erase (number of blocks)
407 */
Andrew Jeffery943aba02018-03-26 15:37:33 +1030408int mbox_handle_erase_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100409 union mbox_regs *req, struct mbox_msg *resp)
410{
Andrew Jeffery62a3daa2018-08-07 22:30:32 +0930411 struct protocol_erase io;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100412
Andrew Jeffery62a3daa2018-08-07 22:30:32 +0930413 io.req.offset = get_u16(&req->msg.args[0]);
414 io.req.size = get_u16(&req->msg.args[2]);
415
416 if (!context->protocol->erase) {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100417 MSG_ERR("Protocol Version invalid for Erase Command\n");
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930418 return -ENOTSUP;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100419 }
420
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930421 return context->protocol->erase(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100422}
423
424/*
425 * Command: WRITE_FLUSH
426 * Flushes any dirty or erased blocks in the current window back to the backing
427 * store
428 * NOTE: For V1 this behaves much the same as the dirty command in that it
429 * takes an offset and number of blocks to dirty, then also performs a flush as
430 * part of the same command. For V2 this will only flush blocks already marked
431 * dirty/erased with the appropriate commands and doesn't take any arguments
432 * directly.
433 *
434 * V1:
435 * ARGS[0:1]: Where within window to start (number of blocks)
436 * ARGS[2:5]: Number to mark dirty (number of bytes)
437 *
438 * V2:
439 * NONE
440 */
Andrew Jeffery943aba02018-03-26 15:37:33 +1030441int mbox_handle_flush_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100442 union mbox_regs *req, struct mbox_msg *resp)
443{
Andrew Jeffery9b920cf2018-08-07 22:49:19 +0930444 struct protocol_flush io = { 0 };
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100445
Andrew Jeffery9b920cf2018-08-07 22:49:19 +0930446 if (context->version == API_VERSION_1) {
447 io.req.offset = get_u16(&req->msg.args[0]);
448 io.req.size = get_u32(&req->msg.args[2]);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100449 }
450
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930451 return context->protocol->flush(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100452}
453
454/*
455 * Command: CLOSE_WINDOW
456 * Close the current window
457 * NOTE: There is an implicit flush
458 *
459 * V1:
460 * NONE
461 *
462 * V2:
463 * ARGS[0]: FLAGS
464 */
Andrew Jeffery943aba02018-03-26 15:37:33 +1030465int mbox_handle_close_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100466 union mbox_regs *req, struct mbox_msg *resp)
467{
Andrew Jeffery093eda52018-08-07 23:10:43 +0930468 struct protocol_close io = { 0 };
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100469
Andrew Jeffery093eda52018-08-07 23:10:43 +0930470 if (context->version >= API_VERSION_2) {
471 io.req.flags = req->msg.args[0];
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100472 }
473
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930474 return context->protocol->close(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100475}
476
477/*
478 * Command: BMC_EVENT_ACK
479 * Sent by the host to acknowledge BMC events supplied in mailbox register 15
480 *
481 * ARGS[0]: Bitmap of bits to ack (by clearing)
482 */
Andrew Jeffery943aba02018-03-26 15:37:33 +1030483int mbox_handle_ack(struct mbox_context *context, union mbox_regs *req,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100484 struct mbox_msg *resp)
485{
Andrew Jefferyc5c83042018-08-07 23:22:05 +0930486 struct protocol_ack io;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100487
Andrew Jefferyc5c83042018-08-07 23:22:05 +0930488 io.req.flags = req->msg.args[0];
489
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930490 return context->protocol->ack(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100491}
492
493/*
Andrew Jeffery55dede62017-04-24 16:13:06 +0930494 * check_req_valid() - Check if the given request is a valid mbox request
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100495 * @context: The mbox context pointer
Andrew Jeffery55dede62017-04-24 16:13:06 +0930496 * @cmd: The request registers
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100497 *
Andrew Jeffery55dede62017-04-24 16:13:06 +0930498 * Return: 0 if request is valid otherwise negative error code
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100499 */
Andrew Jeffery55dede62017-04-24 16:13:06 +0930500static int check_req_valid(struct mbox_context *context, union mbox_regs *req)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100501{
Andrew Jeffery55dede62017-04-24 16:13:06 +0930502 uint8_t cmd = req->msg.command;
503 uint8_t seq = req->msg.seq;
504
505 if (cmd > NUM_MBOX_CMDS) {
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930506 MSG_ERR("Unknown mbox command: %d\n", cmd);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930507 return -ENOTSUP;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100508 }
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930509
Andrew Jeffery55dede62017-04-24 16:13:06 +0930510 if (seq == context->prev_seq && cmd != MBOX_C_GET_MBOX_INFO) {
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000511 MSG_ERR("Invalid sequence number: %d, previous: %d\n", seq,
512 context->prev_seq);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930513 return -EBADMSG;
Andrew Jeffery55dede62017-04-24 16:13:06 +0930514 }
515
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100516 if (context->state & STATE_SUSPENDED) {
517 if (cmd != MBOX_C_GET_MBOX_INFO && cmd != MBOX_C_ACK) {
518 MSG_ERR("Cannot use that cmd while suspended: %d\n",
519 cmd);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930520 return -EBUSY;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100521 }
522 }
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930523
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100524 if (!(context->state & MAPS_MEM)) {
525 if (cmd != MBOX_C_RESET_STATE && cmd != MBOX_C_GET_MBOX_INFO
526 && cmd != MBOX_C_ACK) {
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930527 MSG_ERR("Must call GET_MBOX_INFO before %d\n", cmd);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930528 return -EPROTO;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100529 }
530 }
531
532 return 0;
533}
534
535static const mboxd_mbox_handler mbox_handlers[] = {
536 mbox_handle_reset,
537 mbox_handle_mbox_info,
538 mbox_handle_flash_info,
539 mbox_handle_read_window,
540 mbox_handle_close_window,
541 mbox_handle_write_window,
542 mbox_handle_dirty_window,
543 mbox_handle_flush_window,
544 mbox_handle_ack,
545 mbox_handle_erase_window
546};
547
548/*
549 * handle_mbox_req() - Handle an incoming mbox command request
550 * @context: The mbox context pointer
551 * @req: The mbox request message
552 *
553 * Return: 0 if handled successfully otherwise negative error code
554 */
555static int handle_mbox_req(struct mbox_context *context, union mbox_regs *req)
556{
557 struct mbox_msg resp = {
558 .command = req->msg.command,
559 .seq = req->msg.seq,
560 .args = { 0 },
561 .response = MBOX_R_SUCCESS
562 };
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000563 int rc = 0, len, i;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100564
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000565 MSG_INFO("Received MBOX command: %u\n", req->msg.command);
Andrew Jeffery55dede62017-04-24 16:13:06 +0930566 rc = check_req_valid(context, req);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930567 if (!rc) {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100568 /* Commands start at 1 so we have to subtract 1 from the cmd */
Andrew Jefferyefb09de2018-03-26 14:36:43 +1030569 mboxd_mbox_handler h = context->handlers[req->msg.command - 1];
570 rc = h(context, req, &resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100571 if (rc < 0) {
572 MSG_ERR("Error handling mbox cmd: %d\n",
573 req->msg.command);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100574 }
575 }
576
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930577 rc = mbox_xlate_errno(context, rc);
578 resp.response = rc;
Andrew Jeffery55dede62017-04-24 16:13:06 +0930579 context->prev_seq = req->msg.seq;
580
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000581 MSG_DBG("Writing MBOX response:\n");
582 MSG_DBG("MBOX cmd: %u\n", resp.command);
583 MSG_DBG("MBOX seq: %u\n", resp.seq);
584 for (i = 0; i < MBOX_ARGS_BYTES; i++) {
585 MSG_DBG("MBOX arg[%d]: 0x%.2x\n", i, resp.args[i]);
586 }
587 MSG_INFO("Writing MBOX response: %u\n", resp.response);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100588 len = write(context->fds[MBOX_FD].fd, &resp, sizeof(resp));
589 if (len < sizeof(resp)) {
590 MSG_ERR("Didn't write the full response\n");
591 rc = -errno;
592 }
593
594 return rc;
595}
596
597/*
598 * get_message() - Read an mbox request message from the mbox registers
599 * @context: The mbox context pointer
600 * @msg: Where to put the received message
601 *
602 * Return: 0 if read successfully otherwise negative error code
603 */
604static int get_message(struct mbox_context *context, union mbox_regs *msg)
605{
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000606 int rc, i;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100607
608 rc = read(context->fds[MBOX_FD].fd, msg, sizeof(msg->raw));
609 if (rc < 0) {
610 MSG_ERR("Couldn't read: %s\n", strerror(errno));
611 return -errno;
612 } else if (rc < sizeof(msg->raw)) {
613 MSG_ERR("Short read: %d expecting %zu\n", rc, sizeof(msg->raw));
614 return -1;
615 }
616
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000617 MSG_DBG("Received MBOX request:\n");
618 MSG_DBG("MBOX cmd: %u\n", msg->msg.command);
619 MSG_DBG("MBOX seq: %u\n", msg->msg.seq);
620 for (i = 0; i < MBOX_ARGS_BYTES; i++) {
621 MSG_DBG("MBOX arg[%d]: 0x%.2x\n", i, msg->msg.args[i]);
622 }
623
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100624 return 0;
625}
626
627/*
628 * dispatch_mbox() - handle an mbox interrupt
629 * @context: The mbox context pointer
630 *
631 * Return: 0 if handled successfully otherwise negative error code
632 */
633int dispatch_mbox(struct mbox_context *context)
634{
635 int rc = 0;
636 union mbox_regs req = { 0 };
637
638 assert(context);
639
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100640 rc = get_message(context, &req);
641 if (rc) {
642 return rc;
643 }
644
645 return handle_mbox_req(context, &req);
646}
647
Andrew Jeffery913740f2017-04-10 23:51:07 +0930648int __init_mbox_dev(struct mbox_context *context, const char *path)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100649{
650 int fd;
651
Andrew Jefferyefb09de2018-03-26 14:36:43 +1030652 context->handlers = mbox_handlers;
653
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100654 /* Open MBOX Device */
Andrew Jeffery913740f2017-04-10 23:51:07 +0930655 fd = open(path, O_RDWR | O_NONBLOCK);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100656 if (fd < 0) {
657 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
Andrew Jeffery913740f2017-04-10 23:51:07 +0930658 path, strerror(errno));
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100659 return -errno;
660 }
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000661 MSG_DBG("Opened mbox dev: %s\n", path);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100662
663 context->fds[MBOX_FD].fd = fd;
664
665 return 0;
666}
667
Andrew Jeffery913740f2017-04-10 23:51:07 +0930668int init_mbox_dev(struct mbox_context *context)
669{
670 return __init_mbox_dev(context, MBOX_HOST_PATH);
671}
672
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100673void free_mbox_dev(struct mbox_context *context)
674{
675 close(context->fds[MBOX_FD].fd);
676}