blob: 671e1c4a74f92b0cef148c52953f834cc2e63d5c [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
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/*
Andrew Jeffery5335f092018-08-09 14:56:08 +093087 * transport_mbox_flush_events() - Write to the BMC controlled status register
88 * (reg 15)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110089 * @context: The mbox context pointer
90 *
91 * Return: 0 on success otherwise negative error code
92 */
Andrew Jeffery5335f092018-08-09 14:56:08 +093093static int transport_mbox_flush_events(struct mbox_context *context)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +110094{
95 int rc;
96
97 /* Seek mbox registers */
98 rc = lseek(context->fds[MBOX_FD].fd, MBOX_BMC_EVENT, SEEK_SET);
99 if (rc != MBOX_BMC_EVENT) {
100 MSG_ERR("Couldn't lseek mbox to byte %d: %s\n", MBOX_BMC_EVENT,
101 strerror(errno));
Andrew Jeffery5335f092018-08-09 14:56:08 +0930102 return -errno;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100103 }
104
105 /* Write to mbox status register */
106 rc = write(context->fds[MBOX_FD].fd, &context->bmc_events, 1);
107 if (rc != 1) {
108 MSG_ERR("Couldn't write to BMC status reg: %s\n",
109 strerror(errno));
Andrew Jeffery5335f092018-08-09 14:56:08 +0930110 return -errno;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100111 }
112
113 /* Reset to start */
114 rc = lseek(context->fds[MBOX_FD].fd, 0, SEEK_SET);
115 if (rc) {
116 MSG_ERR("Couldn't reset MBOX offset to zero: %s\n",
117 strerror(errno));
Andrew Jeffery5335f092018-08-09 14:56:08 +0930118 return -errno;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100119 }
120
121 return 0;
122}
123
Andrew Jeffery4414fb82018-08-20 12:13:09 +0930124static int transport_mbox_set_events(struct mbox_context *context,
125 uint8_t events)
126{
127 context->bmc_events |= events;
128
129 return transport_mbox_flush_events(context);
130}
131
132static int transport_mbox_clear_events(struct mbox_context *context,
133 uint8_t events)
134{
135 context->bmc_events &= ~events;
136
137 return transport_mbox_flush_events(context);
138}
139
Andrew Jeffery23a48212018-08-10 14:41:48 +0930140static const struct transport_ops transport_mbox_ops = {
Andrew Jeffery4414fb82018-08-20 12:13:09 +0930141 .set_events = transport_mbox_set_events,
142 .clear_events = transport_mbox_clear_events,
Andrew Jeffery23a48212018-08-10 14:41:48 +0930143};
144
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100145/* Command Handlers */
146
147/*
148 * Command: RESET_STATE
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500149 * Reset the LPC mapping to point back at the flash, or memory in case we're
150 * using a virtual pnor.
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100151 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930152static int mbox_handle_reset(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100153 union mbox_regs *req, struct mbox_msg *resp)
154{
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930155 return context->protocol->reset(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100156}
157
158/*
159 * Command: GET_MBOX_INFO
160 * Get the API version, default window size and block size
161 * We also set the LPC mapping to point to the reserved memory region here so
162 * this command must be called before any window manipulation
163 *
164 * V1:
165 * ARGS[0]: API Version
166 *
167 * RESP[0]: API Version
168 * RESP[1:2]: Default read window size (number of blocks)
169 * RESP[3:4]: Default write window size (number of blocks)
170 * RESP[5]: Block size (as shift)
171 *
172 * V2:
173 * ARGS[0]: API Version
174 *
175 * RESP[0]: API Version
176 * RESP[1:2]: Default read window size (number of blocks)
177 * RESP[3:4]: Default write window size (number of blocks)
178 * RESP[5]: Block size (as shift)
179 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930180static int mbox_handle_mbox_info(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100181 union mbox_regs *req, struct mbox_msg *resp)
182{
183 uint8_t mbox_api_version = req->msg.args[0];
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930184 struct protocol_get_info io = {
185 .req = { .api_version = mbox_api_version }
186 };
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100187 int rc;
188
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930189 rc = context->protocol->get_info(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100190 if (rc < 0) {
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930191 return rc;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100192 }
193
Andrew Jeffery23a48212018-08-10 14:41:48 +0930194 /*
195 * Switch transport to mbox, however we need to delay flushing the
196 * event state until after the command is processed.
197 */
198 context->transport = &transport_mbox_ops;
199
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930200 resp->args[0] = io.resp.api_version;
201 if (io.resp.api_version == API_VERSION_1) {
202 put_u16(&resp->args[1], io.resp.v1.read_window_size);
203 put_u16(&resp->args[3], io.resp.v1.write_window_size);
204 } else if (io.resp.api_version >= API_VERSION_2) {
205 resp->args[5] = io.resp.v2.block_size_shift;
206 put_u16(&resp->args[6], io.resp.v2.timeout);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100207 }
208
209 return 0;
210}
211
212/*
213 * Command: GET_FLASH_INFO
214 * Get the flash size and erase granularity
215 *
216 * V1:
217 * RESP[0:3]: Flash Size (bytes)
218 * RESP[4:7]: Erase Size (bytes)
219 * V2:
220 * RESP[0:1]: Flash Size (number of blocks)
221 * RESP[2:3]: Erase Size (number of blocks)
222 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930223static int mbox_handle_flash_info(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100224 union mbox_regs *req, struct mbox_msg *resp)
225{
Andrew Jeffery91a87452018-08-07 14:54:14 +0930226 struct protocol_get_flash_info io;
227 int rc;
228
229 rc = context->protocol->get_flash_info(context, &io);
230 if (rc < 0) {
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930231 return rc;
Andrew Jeffery91a87452018-08-07 14:54:14 +0930232 }
233
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100234 switch (context->version) {
235 case API_VERSION_1:
236 /* Both Sizes in Bytes */
Andrew Jeffery91a87452018-08-07 14:54:14 +0930237 put_u32(&resp->args[0], io.resp.v1.flash_size);
238 put_u32(&resp->args[4], io.resp.v1.erase_size);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100239 break;
240 case API_VERSION_2:
241 /* Both Sizes in Block Size */
Andrew Jeffery91a87452018-08-07 14:54:14 +0930242 put_u16(&resp->args[0], io.resp.v2.flash_size);
243 put_u16(&resp->args[2], io.resp.v2.erase_size);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100244 break;
245 default:
246 MSG_ERR("API Version Not Valid - Invalid System State\n");
247 return -MBOX_R_SYSTEM_ERROR;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100248 }
249
250 return 0;
251}
252
253/*
254 * get_lpc_addr_shifted() - Get lpc address of the current window
255 * @context: The mbox context pointer
256 *
257 * Return: The lpc address to access that offset shifted by block size
258 */
259static inline uint16_t get_lpc_addr_shifted(struct mbox_context *context)
260{
261 uint32_t lpc_addr, mem_offset;
262
263 /* Offset of the current window in the reserved memory region */
264 mem_offset = context->current->mem - context->mem;
265 /* Total LPC Address */
266 lpc_addr = context->lpc_base + mem_offset;
267
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000268 MSG_DBG("LPC address of current window: 0x%.8x\n", lpc_addr);
269
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100270 return lpc_addr >> context->block_size_shift;
271}
272
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930273static int mbox_handle_create_window(struct mbox_context *context, bool ro,
Andrew Jeffery4bcec8e2018-08-07 15:33:41 +0930274 union mbox_regs *req, struct mbox_msg *resp)
275{
276 struct protocol_create_window io;
277 int rc;
278
279 io.req.offset = get_u16(&req->msg.args[0]);
280 io.req.ro = ro;
281
282 rc = context->protocol->create_window(context, &io);
283 if (rc < 0) {
284 return rc;
285 }
286
287 put_u16(&resp->args[0], io.resp.lpc_address);
288 if (context->version >= API_VERSION_2) {
289 put_u16(&resp->args[2], io.resp.size);
290 put_u16(&resp->args[4], io.resp.offset);
291 }
292
293 return 0;
294}
295
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100296/*
297 * Command: CREATE_READ_WINDOW
298 * Opens a read window
299 * First checks if any current window with the requested data, if so we just
300 * point the host to that. Otherwise we read the request data in from flash and
301 * point the host there.
302 *
303 * V1:
304 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
305 *
306 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
307 *
308 * V2:
309 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
310 * ARGS[2:3]: Requested window size (number of blocks)
311 *
312 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
313 * RESP[2:3]: Actual window size that the host can access (number of blocks)
314 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930315static int mbox_handle_read_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100316 union mbox_regs *req, struct mbox_msg *resp)
317{
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930318 return mbox_handle_create_window(context, true, req, resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100319}
320
321/*
322 * Command: CREATE_WRITE_WINDOW
323 * Opens a write window
324 * First checks if any current window with the requested data, if so we just
325 * point the host to that. Otherwise we read the request data in from flash and
326 * point the host there.
327 *
328 * V1:
329 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
330 *
331 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
332 *
333 * V2:
334 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
335 * ARGS[2:3]: Requested window size (number of blocks)
336 *
337 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
338 * RESP[2:3]: Actual window size that was mapped/host can access (n.o. blocks)
339 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930340static int mbox_handle_write_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100341 union mbox_regs *req, struct mbox_msg *resp)
342{
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930343 return mbox_handle_create_window(context, false, req, resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100344}
345
346/*
347 * Commands: MARK_WRITE_DIRTY
348 * Marks a portion of the current (write) window dirty, informing the daemon
349 * that is has been written to and thus must be at some point written to the
350 * backing store
351 * These changes aren't written back to the backing store unless flush is then
352 * called or the window closed
353 *
354 * V1:
355 * ARGS[0:1]: Where within flash to start (number of blocks)
356 * ARGS[2:5]: Number to mark dirty (number of bytes)
357 *
358 * V2:
359 * ARGS[0:1]: Where within window to start (number of blocks)
360 * ARGS[2:3]: Number to mark dirty (number of blocks)
361 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930362static int mbox_handle_dirty_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100363 union mbox_regs *req, struct mbox_msg *resp)
364{
Andrew Jefferya336e432018-08-07 16:00:40 +0930365 struct protocol_mark_dirty io;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100366
Andrew Jefferya336e432018-08-07 16:00:40 +0930367 if (context->version == API_VERSION_1) {
368 io.req.v1.offset = get_u16(&req->msg.args[0]);
369 io.req.v1.size = get_u32(&req->msg.args[2]);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100370 } else {
Andrew Jefferya336e432018-08-07 16:00:40 +0930371 io.req.v2.offset = get_u16(&req->msg.args[0]);
372 io.req.v2.size = get_u16(&req->msg.args[2]);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100373 }
374
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930375 return context->protocol->mark_dirty(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100376}
377
378/*
379 * Commands: MARK_WRITE_ERASE
380 * Erases a portion of the current window
381 * These changes aren't written back to the backing store unless flush is then
382 * called or the window closed
383 *
384 * V1:
385 * Unimplemented
386 *
387 * V2:
388 * ARGS[0:1]: Where within window to start (number of blocks)
389 * ARGS[2:3]: Number to erase (number of blocks)
390 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930391static int mbox_handle_erase_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100392 union mbox_regs *req, struct mbox_msg *resp)
393{
Andrew Jeffery62a3daa2018-08-07 22:30:32 +0930394 struct protocol_erase io;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100395
Andrew Jeffery62a3daa2018-08-07 22:30:32 +0930396 io.req.offset = get_u16(&req->msg.args[0]);
397 io.req.size = get_u16(&req->msg.args[2]);
398
399 if (!context->protocol->erase) {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100400 MSG_ERR("Protocol Version invalid for Erase Command\n");
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930401 return -ENOTSUP;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100402 }
403
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930404 return context->protocol->erase(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100405}
406
407/*
408 * Command: WRITE_FLUSH
409 * Flushes any dirty or erased blocks in the current window back to the backing
410 * store
411 * NOTE: For V1 this behaves much the same as the dirty command in that it
412 * takes an offset and number of blocks to dirty, then also performs a flush as
413 * part of the same command. For V2 this will only flush blocks already marked
414 * dirty/erased with the appropriate commands and doesn't take any arguments
415 * directly.
416 *
417 * V1:
418 * ARGS[0:1]: Where within window to start (number of blocks)
419 * ARGS[2:5]: Number to mark dirty (number of bytes)
420 *
421 * V2:
422 * NONE
423 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930424static int mbox_handle_flush_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100425 union mbox_regs *req, struct mbox_msg *resp)
426{
Andrew Jeffery9b920cf2018-08-07 22:49:19 +0930427 struct protocol_flush io = { 0 };
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100428
Andrew Jeffery9b920cf2018-08-07 22:49:19 +0930429 if (context->version == API_VERSION_1) {
430 io.req.offset = get_u16(&req->msg.args[0]);
431 io.req.size = get_u32(&req->msg.args[2]);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100432 }
433
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930434 return context->protocol->flush(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100435}
436
437/*
438 * Command: CLOSE_WINDOW
439 * Close the current window
440 * NOTE: There is an implicit flush
441 *
442 * V1:
443 * NONE
444 *
445 * V2:
446 * ARGS[0]: FLAGS
447 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930448static int mbox_handle_close_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100449 union mbox_regs *req, struct mbox_msg *resp)
450{
Andrew Jeffery093eda52018-08-07 23:10:43 +0930451 struct protocol_close io = { 0 };
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100452
Andrew Jeffery093eda52018-08-07 23:10:43 +0930453 if (context->version >= API_VERSION_2) {
454 io.req.flags = req->msg.args[0];
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100455 }
456
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930457 return context->protocol->close(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100458}
459
460/*
461 * Command: BMC_EVENT_ACK
462 * Sent by the host to acknowledge BMC events supplied in mailbox register 15
463 *
464 * ARGS[0]: Bitmap of bits to ack (by clearing)
465 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930466static int mbox_handle_ack(struct mbox_context *context, union mbox_regs *req,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100467 struct mbox_msg *resp)
468{
Andrew Jefferyc5c83042018-08-07 23:22:05 +0930469 struct protocol_ack io;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100470
Andrew Jefferyc5c83042018-08-07 23:22:05 +0930471 io.req.flags = req->msg.args[0];
472
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930473 return context->protocol->ack(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100474}
475
476/*
Andrew Jeffery55dede62017-04-24 16:13:06 +0930477 * check_req_valid() - Check if the given request is a valid mbox request
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100478 * @context: The mbox context pointer
Andrew Jeffery55dede62017-04-24 16:13:06 +0930479 * @cmd: The request registers
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100480 *
Andrew Jeffery55dede62017-04-24 16:13:06 +0930481 * Return: 0 if request is valid otherwise negative error code
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100482 */
Andrew Jeffery55dede62017-04-24 16:13:06 +0930483static int check_req_valid(struct mbox_context *context, union mbox_regs *req)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100484{
Andrew Jeffery55dede62017-04-24 16:13:06 +0930485 uint8_t cmd = req->msg.command;
486 uint8_t seq = req->msg.seq;
487
488 if (cmd > NUM_MBOX_CMDS) {
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930489 MSG_ERR("Unknown mbox command: %d\n", cmd);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930490 return -ENOTSUP;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100491 }
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930492
Andrew Jeffery55dede62017-04-24 16:13:06 +0930493 if (seq == context->prev_seq && cmd != MBOX_C_GET_MBOX_INFO) {
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000494 MSG_ERR("Invalid sequence number: %d, previous: %d\n", seq,
495 context->prev_seq);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930496 return -EBADMSG;
Andrew Jeffery55dede62017-04-24 16:13:06 +0930497 }
498
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100499 if (context->state & STATE_SUSPENDED) {
500 if (cmd != MBOX_C_GET_MBOX_INFO && cmd != MBOX_C_ACK) {
501 MSG_ERR("Cannot use that cmd while suspended: %d\n",
502 cmd);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930503 return -EBUSY;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100504 }
505 }
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930506
Andrew Jeffery23a48212018-08-10 14:41:48 +0930507 if (context->transport != &transport_mbox_ops) {
508 if (cmd != MBOX_C_RESET_STATE && cmd != MBOX_C_GET_MBOX_INFO) {
509 MSG_ERR("Cannot switch transport with command %d\n",
510 cmd);
511 return -EPROTO;
512 }
513 }
514
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100515 if (!(context->state & MAPS_MEM)) {
516 if (cmd != MBOX_C_RESET_STATE && cmd != MBOX_C_GET_MBOX_INFO
517 && cmd != MBOX_C_ACK) {
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930518 MSG_ERR("Must call GET_MBOX_INFO before %d\n", cmd);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930519 return -EPROTO;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100520 }
521 }
522
523 return 0;
524}
525
Andrew Jeffery5335f092018-08-09 14:56:08 +0930526typedef int (*mboxd_mbox_handler)(struct mbox_context *, union mbox_regs *,
527 struct mbox_msg *);
528
529static const mboxd_mbox_handler transport_mbox_handlers[] = {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100530 mbox_handle_reset,
531 mbox_handle_mbox_info,
532 mbox_handle_flash_info,
533 mbox_handle_read_window,
534 mbox_handle_close_window,
535 mbox_handle_write_window,
536 mbox_handle_dirty_window,
537 mbox_handle_flush_window,
538 mbox_handle_ack,
539 mbox_handle_erase_window
540};
541
542/*
543 * handle_mbox_req() - Handle an incoming mbox command request
544 * @context: The mbox context pointer
545 * @req: The mbox request message
546 *
547 * Return: 0 if handled successfully otherwise negative error code
548 */
549static int handle_mbox_req(struct mbox_context *context, union mbox_regs *req)
550{
Andrew Jeffery23a48212018-08-10 14:41:48 +0930551 const struct transport_ops *old_transport = context->transport;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100552 struct mbox_msg resp = {
553 .command = req->msg.command,
554 .seq = req->msg.seq,
555 .args = { 0 },
556 .response = MBOX_R_SUCCESS
557 };
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000558 int rc = 0, len, i;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100559
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000560 MSG_INFO("Received MBOX command: %u\n", req->msg.command);
Andrew Jeffery23a48212018-08-10 14:41:48 +0930561
Andrew Jeffery55dede62017-04-24 16:13:06 +0930562 rc = check_req_valid(context, req);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930563 if (!rc) {
Andrew Jeffery5335f092018-08-09 14:56:08 +0930564 mboxd_mbox_handler handler;
565
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100566 /* Commands start at 1 so we have to subtract 1 from the cmd */
Andrew Jeffery5335f092018-08-09 14:56:08 +0930567 handler = transport_mbox_handlers[req->msg.command - 1];
568 rc = handler(context, req, &resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100569 if (rc < 0) {
570 MSG_ERR("Error handling mbox cmd: %d\n",
571 req->msg.command);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100572 }
573 }
574
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930575 rc = mbox_xlate_errno(context, rc);
576 resp.response = rc;
Andrew Jeffery55dede62017-04-24 16:13:06 +0930577 context->prev_seq = req->msg.seq;
578
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000579 MSG_DBG("Writing MBOX response:\n");
580 MSG_DBG("MBOX cmd: %u\n", resp.command);
581 MSG_DBG("MBOX seq: %u\n", resp.seq);
582 for (i = 0; i < MBOX_ARGS_BYTES; i++) {
583 MSG_DBG("MBOX arg[%d]: 0x%.2x\n", i, resp.args[i]);
584 }
585 MSG_INFO("Writing MBOX response: %u\n", resp.response);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100586 len = write(context->fds[MBOX_FD].fd, &resp, sizeof(resp));
587 if (len < sizeof(resp)) {
588 MSG_ERR("Didn't write the full response\n");
589 rc = -errno;
590 }
591
Andrew Jeffery23a48212018-08-10 14:41:48 +0930592 if (context->transport != old_transport &&
593 context->transport == &transport_mbox_ops) {
594 transport_mbox_flush_events(context);
595 }
596
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100597 return rc;
598}
599
600/*
601 * get_message() - Read an mbox request message from the mbox registers
602 * @context: The mbox context pointer
603 * @msg: Where to put the received message
604 *
605 * Return: 0 if read successfully otherwise negative error code
606 */
607static int get_message(struct mbox_context *context, union mbox_regs *msg)
608{
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000609 int rc, i;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100610
611 rc = read(context->fds[MBOX_FD].fd, msg, sizeof(msg->raw));
612 if (rc < 0) {
613 MSG_ERR("Couldn't read: %s\n", strerror(errno));
614 return -errno;
615 } else if (rc < sizeof(msg->raw)) {
616 MSG_ERR("Short read: %d expecting %zu\n", rc, sizeof(msg->raw));
617 return -1;
618 }
619
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000620 MSG_DBG("Received MBOX request:\n");
621 MSG_DBG("MBOX cmd: %u\n", msg->msg.command);
622 MSG_DBG("MBOX seq: %u\n", msg->msg.seq);
623 for (i = 0; i < MBOX_ARGS_BYTES; i++) {
624 MSG_DBG("MBOX arg[%d]: 0x%.2x\n", i, msg->msg.args[i]);
625 }
626
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100627 return 0;
628}
629
630/*
Andrew Jefferyd86141b2018-08-09 14:58:53 +0930631 * transport_mbox_dispatch() - handle an mbox interrupt
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100632 * @context: The mbox context pointer
633 *
634 * Return: 0 if handled successfully otherwise negative error code
635 */
Andrew Jefferyd86141b2018-08-09 14:58:53 +0930636int transport_mbox_dispatch(struct mbox_context *context)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100637{
638 int rc = 0;
639 union mbox_regs req = { 0 };
640
641 assert(context);
642
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100643 rc = get_message(context, &req);
644 if (rc) {
645 return rc;
646 }
647
648 return handle_mbox_req(context, &req);
649}
650
Andrew Jefferyb2466ee2018-08-09 15:03:27 +0930651int __transport_mbox_init(struct mbox_context *context, const char *path)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100652{
653 int fd;
654
Andrew Jeffery5335f092018-08-09 14:56:08 +0930655 context->transport = &transport_mbox_ops;
Andrew Jefferyefb09de2018-03-26 14:36:43 +1030656
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100657 /* Open MBOX Device */
Andrew Jeffery913740f2017-04-10 23:51:07 +0930658 fd = open(path, O_RDWR | O_NONBLOCK);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100659 if (fd < 0) {
660 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
Andrew Jeffery913740f2017-04-10 23:51:07 +0930661 path, strerror(errno));
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100662 return -errno;
663 }
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000664 MSG_DBG("Opened mbox dev: %s\n", path);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100665
666 context->fds[MBOX_FD].fd = fd;
667
668 return 0;
669}
670
Andrew Jefferyb2466ee2018-08-09 15:03:27 +0930671int transport_mbox_init(struct mbox_context *context)
Andrew Jeffery913740f2017-04-10 23:51:07 +0930672{
Andrew Jefferyb2466ee2018-08-09 15:03:27 +0930673 return __transport_mbox_init(context, MBOX_HOST_PATH);
Andrew Jeffery913740f2017-04-10 23:51:07 +0930674}
675
Andrew Jeffery55260ce2018-08-09 15:05:59 +0930676void transport_mbox_free(struct mbox_context *context)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100677{
678 close(context->fds[MBOX_FD].fd);
679}