blob: 3d718208175eeb2a450fe56a4f2e429e8b86824d [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 Jefferyf62601b2018-11-01 13:44:25 +103093static int transport_mbox_flush_events(struct mbox_context *context, uint8_t events)
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 */
Andrew Jefferyf62601b2018-11-01 13:44:25 +1030106 rc = write(context->fds[MBOX_FD].fd, &events, 1);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100107 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 Jefferyfe0c9e82018-11-01 14:02:17 +1030124static int transport_mbox_put_events(struct mbox_context *context,
125 uint8_t mask)
Andrew Jeffery4414fb82018-08-20 12:13:09 +0930126{
Andrew Jefferyf62601b2018-11-01 13:44:25 +1030127 return transport_mbox_flush_events(context, context->bmc_events & mask);
Andrew Jeffery4414fb82018-08-20 12:13:09 +0930128}
129
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030130static int transport_mbox_update_events(struct mbox_context *context,
131 uint8_t events, uint8_t mask)
Andrew Jeffery4414fb82018-08-20 12:13:09 +0930132{
Andrew Jefferyf62601b2018-11-01 13:44:25 +1030133 return transport_mbox_flush_events(context, context->bmc_events & mask);
Andrew Jeffery4414fb82018-08-20 12:13:09 +0930134}
135
Andrew Jeffery23a48212018-08-10 14:41:48 +0930136static const struct transport_ops transport_mbox_ops = {
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030137 .put_events = transport_mbox_put_events,
138 .set_events = transport_mbox_update_events,
139 .clear_events = transport_mbox_update_events,
Andrew Jeffery23a48212018-08-10 14:41:48 +0930140};
141
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100142/* Command Handlers */
143
144/*
145 * Command: RESET_STATE
Deepak Kodihalli017e45c2017-07-12 01:06:30 -0500146 * Reset the LPC mapping to point back at the flash, or memory in case we're
147 * using a virtual pnor.
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100148 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930149static int mbox_handle_reset(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100150 union mbox_regs *req, struct mbox_msg *resp)
151{
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930152 return context->protocol->reset(context);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100153}
154
155/*
156 * Command: GET_MBOX_INFO
157 * Get the API version, default window size and block size
158 * We also set the LPC mapping to point to the reserved memory region here so
159 * this command must be called before any window manipulation
160 *
161 * V1:
162 * ARGS[0]: API Version
163 *
164 * RESP[0]: API Version
165 * RESP[1:2]: Default read window size (number of blocks)
166 * RESP[3:4]: Default write window size (number of blocks)
167 * RESP[5]: Block size (as shift)
168 *
169 * V2:
170 * ARGS[0]: API Version
171 *
172 * RESP[0]: API Version
173 * RESP[1:2]: Default read window size (number of blocks)
174 * RESP[3:4]: Default write window size (number of blocks)
175 * RESP[5]: Block size (as shift)
176 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930177static int mbox_handle_mbox_info(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100178 union mbox_regs *req, struct mbox_msg *resp)
179{
180 uint8_t mbox_api_version = req->msg.args[0];
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930181 struct protocol_get_info io = {
182 .req = { .api_version = mbox_api_version }
183 };
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100184 int rc;
185
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930186 rc = context->protocol->get_info(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100187 if (rc < 0) {
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930188 return rc;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100189 }
190
Andrew Jeffery23a48212018-08-10 14:41:48 +0930191 /*
192 * Switch transport to mbox, however we need to delay flushing the
193 * event state until after the command is processed.
194 */
195 context->transport = &transport_mbox_ops;
196
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930197 resp->args[0] = io.resp.api_version;
198 if (io.resp.api_version == API_VERSION_1) {
199 put_u16(&resp->args[1], io.resp.v1.read_window_size);
200 put_u16(&resp->args[3], io.resp.v1.write_window_size);
201 } else if (io.resp.api_version >= API_VERSION_2) {
202 resp->args[5] = io.resp.v2.block_size_shift;
203 put_u16(&resp->args[6], io.resp.v2.timeout);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100204 }
205
206 return 0;
207}
208
209/*
210 * Command: GET_FLASH_INFO
211 * Get the flash size and erase granularity
212 *
213 * V1:
214 * RESP[0:3]: Flash Size (bytes)
215 * RESP[4:7]: Erase Size (bytes)
216 * V2:
217 * RESP[0:1]: Flash Size (number of blocks)
218 * RESP[2:3]: Erase Size (number of blocks)
219 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930220static int mbox_handle_flash_info(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100221 union mbox_regs *req, struct mbox_msg *resp)
222{
Andrew Jeffery91a87452018-08-07 14:54:14 +0930223 struct protocol_get_flash_info io;
224 int rc;
225
226 rc = context->protocol->get_flash_info(context, &io);
227 if (rc < 0) {
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930228 return rc;
Andrew Jeffery91a87452018-08-07 14:54:14 +0930229 }
230
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100231 switch (context->version) {
232 case API_VERSION_1:
233 /* Both Sizes in Bytes */
Andrew Jeffery91a87452018-08-07 14:54:14 +0930234 put_u32(&resp->args[0], io.resp.v1.flash_size);
235 put_u32(&resp->args[4], io.resp.v1.erase_size);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100236 break;
237 case API_VERSION_2:
238 /* Both Sizes in Block Size */
Andrew Jeffery91a87452018-08-07 14:54:14 +0930239 put_u16(&resp->args[0], io.resp.v2.flash_size);
240 put_u16(&resp->args[2], io.resp.v2.erase_size);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100241 break;
242 default:
243 MSG_ERR("API Version Not Valid - Invalid System State\n");
244 return -MBOX_R_SYSTEM_ERROR;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100245 }
246
247 return 0;
248}
249
250/*
251 * get_lpc_addr_shifted() - Get lpc address of the current window
252 * @context: The mbox context pointer
253 *
254 * Return: The lpc address to access that offset shifted by block size
255 */
256static inline uint16_t get_lpc_addr_shifted(struct mbox_context *context)
257{
258 uint32_t lpc_addr, mem_offset;
259
260 /* Offset of the current window in the reserved memory region */
261 mem_offset = context->current->mem - context->mem;
262 /* Total LPC Address */
263 lpc_addr = context->lpc_base + mem_offset;
264
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000265 MSG_DBG("LPC address of current window: 0x%.8x\n", lpc_addr);
266
Evan Lojewskif1e547c2019-03-14 14:34:33 +1030267 return lpc_addr >> context->backend.block_size_shift;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100268}
269
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930270static int mbox_handle_create_window(struct mbox_context *context, bool ro,
Andrew Jeffery4bcec8e2018-08-07 15:33:41 +0930271 union mbox_regs *req, struct mbox_msg *resp)
272{
273 struct protocol_create_window io;
274 int rc;
275
276 io.req.offset = get_u16(&req->msg.args[0]);
277 io.req.ro = ro;
278
279 rc = context->protocol->create_window(context, &io);
280 if (rc < 0) {
281 return rc;
282 }
283
284 put_u16(&resp->args[0], io.resp.lpc_address);
285 if (context->version >= API_VERSION_2) {
286 put_u16(&resp->args[2], io.resp.size);
287 put_u16(&resp->args[4], io.resp.offset);
288 }
289
290 return 0;
291}
292
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100293/*
294 * Command: CREATE_READ_WINDOW
295 * Opens a read window
296 * First checks if any current window with the requested data, if so we just
297 * point the host to that. Otherwise we read the request data in from flash and
298 * point the host there.
299 *
300 * V1:
301 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
302 *
303 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
304 *
305 * V2:
306 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
307 * ARGS[2:3]: Requested window size (number of blocks)
308 *
309 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
310 * RESP[2:3]: Actual window size that the host can access (number of blocks)
311 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930312static int mbox_handle_read_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100313 union mbox_regs *req, struct mbox_msg *resp)
314{
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930315 return mbox_handle_create_window(context, true, req, resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100316}
317
318/*
319 * Command: CREATE_WRITE_WINDOW
320 * Opens a write window
321 * First checks if any current window with the requested data, if so we just
322 * point the host to that. Otherwise we read the request data in from flash and
323 * point the host there.
324 *
325 * V1:
326 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
327 *
328 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
329 *
330 * V2:
331 * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
332 * ARGS[2:3]: Requested window size (number of blocks)
333 *
334 * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
335 * RESP[2:3]: Actual window size that was mapped/host can access (n.o. blocks)
336 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930337static int mbox_handle_write_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100338 union mbox_regs *req, struct mbox_msg *resp)
339{
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930340 return mbox_handle_create_window(context, false, req, resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100341}
342
343/*
344 * Commands: MARK_WRITE_DIRTY
345 * Marks a portion of the current (write) window dirty, informing the daemon
346 * that is has been written to and thus must be at some point written to the
347 * backing store
348 * These changes aren't written back to the backing store unless flush is then
349 * called or the window closed
350 *
351 * V1:
352 * ARGS[0:1]: Where within flash to start (number of blocks)
353 * ARGS[2:5]: Number to mark dirty (number of bytes)
354 *
355 * V2:
356 * ARGS[0:1]: Where within window to start (number of blocks)
357 * ARGS[2:3]: Number to mark dirty (number of blocks)
358 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930359static int mbox_handle_dirty_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100360 union mbox_regs *req, struct mbox_msg *resp)
361{
Andrew Jefferya336e432018-08-07 16:00:40 +0930362 struct protocol_mark_dirty io;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100363
Andrew Jefferya336e432018-08-07 16:00:40 +0930364 if (context->version == API_VERSION_1) {
365 io.req.v1.offset = get_u16(&req->msg.args[0]);
366 io.req.v1.size = get_u32(&req->msg.args[2]);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100367 } else {
Andrew Jefferya336e432018-08-07 16:00:40 +0930368 io.req.v2.offset = get_u16(&req->msg.args[0]);
369 io.req.v2.size = get_u16(&req->msg.args[2]);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100370 }
371
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930372 return context->protocol->mark_dirty(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100373}
374
375/*
376 * Commands: MARK_WRITE_ERASE
377 * Erases a portion of the current window
378 * These changes aren't written back to the backing store unless flush is then
379 * called or the window closed
380 *
381 * V1:
382 * Unimplemented
383 *
384 * V2:
385 * ARGS[0:1]: Where within window to start (number of blocks)
386 * ARGS[2:3]: Number to erase (number of blocks)
387 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930388static int mbox_handle_erase_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100389 union mbox_regs *req, struct mbox_msg *resp)
390{
Andrew Jeffery62a3daa2018-08-07 22:30:32 +0930391 struct protocol_erase io;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100392
Andrew Jeffery62a3daa2018-08-07 22:30:32 +0930393 io.req.offset = get_u16(&req->msg.args[0]);
394 io.req.size = get_u16(&req->msg.args[2]);
395
396 if (!context->protocol->erase) {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100397 MSG_ERR("Protocol Version invalid for Erase Command\n");
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930398 return -ENOTSUP;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100399 }
400
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930401 return context->protocol->erase(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100402}
403
404/*
405 * Command: WRITE_FLUSH
406 * Flushes any dirty or erased blocks in the current window back to the backing
407 * store
408 * NOTE: For V1 this behaves much the same as the dirty command in that it
409 * takes an offset and number of blocks to dirty, then also performs a flush as
410 * part of the same command. For V2 this will only flush blocks already marked
411 * dirty/erased with the appropriate commands and doesn't take any arguments
412 * directly.
413 *
414 * V1:
415 * ARGS[0:1]: Where within window to start (number of blocks)
416 * ARGS[2:5]: Number to mark dirty (number of bytes)
417 *
418 * V2:
419 * NONE
420 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930421static int mbox_handle_flush_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100422 union mbox_regs *req, struct mbox_msg *resp)
423{
Andrew Jeffery9b920cf2018-08-07 22:49:19 +0930424 struct protocol_flush io = { 0 };
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100425
Andrew Jeffery9b920cf2018-08-07 22:49:19 +0930426 if (context->version == API_VERSION_1) {
427 io.req.offset = get_u16(&req->msg.args[0]);
428 io.req.size = get_u32(&req->msg.args[2]);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100429 }
430
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930431 return context->protocol->flush(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100432}
433
434/*
435 * Command: CLOSE_WINDOW
436 * Close the current window
437 * NOTE: There is an implicit flush
438 *
439 * V1:
440 * NONE
441 *
442 * V2:
443 * ARGS[0]: FLAGS
444 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930445static int mbox_handle_close_window(struct mbox_context *context,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100446 union mbox_regs *req, struct mbox_msg *resp)
447{
Andrew Jeffery093eda52018-08-07 23:10:43 +0930448 struct protocol_close io = { 0 };
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100449
Andrew Jeffery093eda52018-08-07 23:10:43 +0930450 if (context->version >= API_VERSION_2) {
451 io.req.flags = req->msg.args[0];
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100452 }
453
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930454 return context->protocol->close(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100455}
456
457/*
458 * Command: BMC_EVENT_ACK
459 * Sent by the host to acknowledge BMC events supplied in mailbox register 15
460 *
461 * ARGS[0]: Bitmap of bits to ack (by clearing)
462 */
Andrew Jefferyf21c81c2018-08-09 13:57:46 +0930463static int mbox_handle_ack(struct mbox_context *context, union mbox_regs *req,
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100464 struct mbox_msg *resp)
465{
Andrew Jefferyc5c83042018-08-07 23:22:05 +0930466 struct protocol_ack io;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100467
Andrew Jefferyc5c83042018-08-07 23:22:05 +0930468 io.req.flags = req->msg.args[0];
469
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930470 return context->protocol->ack(context, &io);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100471}
472
473/*
Andrew Jeffery55dede62017-04-24 16:13:06 +0930474 * check_req_valid() - Check if the given request is a valid mbox request
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100475 * @context: The mbox context pointer
Andrew Jeffery55dede62017-04-24 16:13:06 +0930476 * @cmd: The request registers
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100477 *
Andrew Jeffery55dede62017-04-24 16:13:06 +0930478 * Return: 0 if request is valid otherwise negative error code
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100479 */
Andrew Jeffery55dede62017-04-24 16:13:06 +0930480static int check_req_valid(struct mbox_context *context, union mbox_regs *req)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100481{
Andrew Jeffery55dede62017-04-24 16:13:06 +0930482 uint8_t cmd = req->msg.command;
483 uint8_t seq = req->msg.seq;
484
485 if (cmd > NUM_MBOX_CMDS) {
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930486 MSG_ERR("Unknown mbox command: %d\n", cmd);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930487 return -ENOTSUP;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100488 }
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930489
Andrew Jeffery55dede62017-04-24 16:13:06 +0930490 if (seq == context->prev_seq && cmd != MBOX_C_GET_MBOX_INFO) {
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000491 MSG_ERR("Invalid sequence number: %d, previous: %d\n", seq,
492 context->prev_seq);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930493 return -EBADMSG;
Andrew Jeffery55dede62017-04-24 16:13:06 +0930494 }
495
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100496 if (context->state & STATE_SUSPENDED) {
497 if (cmd != MBOX_C_GET_MBOX_INFO && cmd != MBOX_C_ACK) {
498 MSG_ERR("Cannot use that cmd while suspended: %d\n",
499 cmd);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930500 return -EBUSY;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100501 }
502 }
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930503
Andrew Jeffery23a48212018-08-10 14:41:48 +0930504 if (context->transport != &transport_mbox_ops) {
505 if (cmd != MBOX_C_RESET_STATE && cmd != MBOX_C_GET_MBOX_INFO) {
506 MSG_ERR("Cannot switch transport with command %d\n",
507 cmd);
508 return -EPROTO;
509 }
510 }
511
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100512 if (!(context->state & MAPS_MEM)) {
513 if (cmd != MBOX_C_RESET_STATE && cmd != MBOX_C_GET_MBOX_INFO
514 && cmd != MBOX_C_ACK) {
Andrew Jeffery121dc0d2017-04-24 16:15:06 +0930515 MSG_ERR("Must call GET_MBOX_INFO before %d\n", cmd);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930516 return -EPROTO;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100517 }
518 }
519
520 return 0;
521}
522
Andrew Jeffery5335f092018-08-09 14:56:08 +0930523typedef int (*mboxd_mbox_handler)(struct mbox_context *, union mbox_regs *,
524 struct mbox_msg *);
525
526static const mboxd_mbox_handler transport_mbox_handlers[] = {
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100527 mbox_handle_reset,
528 mbox_handle_mbox_info,
529 mbox_handle_flash_info,
530 mbox_handle_read_window,
531 mbox_handle_close_window,
532 mbox_handle_write_window,
533 mbox_handle_dirty_window,
534 mbox_handle_flush_window,
535 mbox_handle_ack,
536 mbox_handle_erase_window
537};
538
539/*
540 * handle_mbox_req() - Handle an incoming mbox command request
541 * @context: The mbox context pointer
542 * @req: The mbox request message
543 *
544 * Return: 0 if handled successfully otherwise negative error code
545 */
546static int handle_mbox_req(struct mbox_context *context, union mbox_regs *req)
547{
Andrew Jeffery23a48212018-08-10 14:41:48 +0930548 const struct transport_ops *old_transport = context->transport;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100549 struct mbox_msg resp = {
550 .command = req->msg.command,
551 .seq = req->msg.seq,
552 .args = { 0 },
553 .response = MBOX_R_SUCCESS
554 };
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000555 int rc = 0, len, i;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100556
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000557 MSG_INFO("Received MBOX command: %u\n", req->msg.command);
Andrew Jeffery23a48212018-08-10 14:41:48 +0930558
Andrew Jeffery55dede62017-04-24 16:13:06 +0930559 rc = check_req_valid(context, req);
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930560 if (!rc) {
Andrew Jeffery5335f092018-08-09 14:56:08 +0930561 mboxd_mbox_handler handler;
562
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100563 /* Commands start at 1 so we have to subtract 1 from the cmd */
Andrew Jeffery5335f092018-08-09 14:56:08 +0930564 handler = transport_mbox_handlers[req->msg.command - 1];
565 rc = handler(context, req, &resp);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100566 if (rc < 0) {
567 MSG_ERR("Error handling mbox cmd: %d\n",
568 req->msg.command);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100569 }
570 }
571
Andrew Jeffery2f1477c2018-08-09 23:24:38 +0930572 rc = mbox_xlate_errno(context, rc);
573 resp.response = rc;
Andrew Jeffery55dede62017-04-24 16:13:06 +0930574 context->prev_seq = req->msg.seq;
575
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000576 MSG_DBG("Writing MBOX response:\n");
577 MSG_DBG("MBOX cmd: %u\n", resp.command);
578 MSG_DBG("MBOX seq: %u\n", resp.seq);
579 for (i = 0; i < MBOX_ARGS_BYTES; i++) {
580 MSG_DBG("MBOX arg[%d]: 0x%.2x\n", i, resp.args[i]);
581 }
582 MSG_INFO("Writing MBOX response: %u\n", resp.response);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100583 len = write(context->fds[MBOX_FD].fd, &resp, sizeof(resp));
584 if (len < sizeof(resp)) {
585 MSG_ERR("Didn't write the full response\n");
586 rc = -errno;
587 }
588
Andrew Jeffery23a48212018-08-10 14:41:48 +0930589 if (context->transport != old_transport &&
590 context->transport == &transport_mbox_ops) {
Andrew Jeffery0453aa42018-08-21 08:25:46 +0930591 /* A bit messy, but we need the correct event mask */
592 protocol_events_set(context, context->bmc_events);
Andrew Jeffery23a48212018-08-10 14:41:48 +0930593 }
594
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100595 return rc;
596}
597
598/*
599 * get_message() - Read an mbox request message from the mbox registers
600 * @context: The mbox context pointer
601 * @msg: Where to put the received message
602 *
603 * Return: 0 if read successfully otherwise negative error code
604 */
605static int get_message(struct mbox_context *context, union mbox_regs *msg)
606{
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000607 int rc, i;
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100608
609 rc = read(context->fds[MBOX_FD].fd, msg, sizeof(msg->raw));
610 if (rc < 0) {
611 MSG_ERR("Couldn't read: %s\n", strerror(errno));
612 return -errno;
613 } else if (rc < sizeof(msg->raw)) {
614 MSG_ERR("Short read: %d expecting %zu\n", rc, sizeof(msg->raw));
615 return -1;
616 }
617
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000618 MSG_DBG("Received MBOX request:\n");
619 MSG_DBG("MBOX cmd: %u\n", msg->msg.command);
620 MSG_DBG("MBOX seq: %u\n", msg->msg.seq);
621 for (i = 0; i < MBOX_ARGS_BYTES; i++) {
622 MSG_DBG("MBOX arg[%d]: 0x%.2x\n", i, msg->msg.args[i]);
623 }
624
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100625 return 0;
626}
627
628/*
Andrew Jefferyd86141b2018-08-09 14:58:53 +0930629 * transport_mbox_dispatch() - handle an mbox interrupt
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100630 * @context: The mbox context pointer
631 *
632 * Return: 0 if handled successfully otherwise negative error code
633 */
Andrew Jefferyd86141b2018-08-09 14:58:53 +0930634int transport_mbox_dispatch(struct mbox_context *context)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100635{
636 int rc = 0;
637 union mbox_regs req = { 0 };
638
639 assert(context);
640
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100641 rc = get_message(context, &req);
642 if (rc) {
643 return rc;
644 }
645
646 return handle_mbox_req(context, &req);
647}
648
Andrew Jefferyb2466ee2018-08-09 15:03:27 +0930649int __transport_mbox_init(struct mbox_context *context, const char *path)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100650{
651 int fd;
652
Andrew Jeffery5335f092018-08-09 14:56:08 +0930653 context->transport = &transport_mbox_ops;
Andrew Jefferyefb09de2018-03-26 14:36:43 +1030654
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100655 /* Open MBOX Device */
Andrew Jeffery913740f2017-04-10 23:51:07 +0930656 fd = open(path, O_RDWR | O_NONBLOCK);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100657 if (fd < 0) {
658 MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
Andrew Jeffery913740f2017-04-10 23:51:07 +0930659 path, strerror(errno));
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100660 return -errno;
661 }
Suraj Jitindar Singh28519592017-04-27 14:48:58 +1000662 MSG_DBG("Opened mbox dev: %s\n", path);
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100663
664 context->fds[MBOX_FD].fd = fd;
665
666 return 0;
667}
668
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030669int transport_mbox_init(struct mbox_context *context,
670 const struct transport_ops **ops)
Andrew Jeffery913740f2017-04-10 23:51:07 +0930671{
Andrew Jefferyfe0c9e82018-11-01 14:02:17 +1030672 int rc;
673
674 rc = __transport_mbox_init(context, MBOX_HOST_PATH);
675 if (rc)
676 return rc;
677
678 if (ops) {
679 *ops = &transport_mbox_ops;
680 }
681
682 return 0;
Andrew Jeffery913740f2017-04-10 23:51:07 +0930683}
684
Andrew Jeffery55260ce2018-08-09 15:05:59 +0930685void transport_mbox_free(struct mbox_context *context)
Suraj Jitindar Singhe39c9162017-03-28 10:47:43 +1100686{
687 close(context->fds[MBOX_FD].fd);
688}