xref: /openbmc/hiomapd/transport_mbox.c (revision 68a24c9e)
1457a6e5fSAndrew Jeffery // SPDX-License-Identifier: Apache-2.0
2457a6e5fSAndrew Jeffery // Copyright (C) 2018 IBM Corp.
3457a6e5fSAndrew Jeffery 
4457a6e5fSAndrew Jeffery #define _GNU_SOURCE
5457a6e5fSAndrew Jeffery #include <assert.h>
6457a6e5fSAndrew Jeffery #include <errno.h>
7457a6e5fSAndrew Jeffery #include <fcntl.h>
8457a6e5fSAndrew Jeffery #include <getopt.h>
9457a6e5fSAndrew Jeffery #include <limits.h>
10457a6e5fSAndrew Jeffery #include <poll.h>
11457a6e5fSAndrew Jeffery #include <stdbool.h>
12457a6e5fSAndrew Jeffery #include <stdint.h>
13457a6e5fSAndrew Jeffery #include <stdio.h>
14457a6e5fSAndrew Jeffery #include <stdlib.h>
15457a6e5fSAndrew Jeffery #include <string.h>
16457a6e5fSAndrew Jeffery #include <syslog.h>
17457a6e5fSAndrew Jeffery #include <signal.h>
18457a6e5fSAndrew Jeffery #include <sys/ioctl.h>
19457a6e5fSAndrew Jeffery #include <sys/mman.h>
20457a6e5fSAndrew Jeffery #include <sys/stat.h>
21457a6e5fSAndrew Jeffery #include <sys/timerfd.h>
22457a6e5fSAndrew Jeffery #include <sys/types.h>
23457a6e5fSAndrew Jeffery #include <time.h>
24457a6e5fSAndrew Jeffery #include <unistd.h>
25457a6e5fSAndrew Jeffery #include <inttypes.h>
26457a6e5fSAndrew Jeffery 
2726558dbbSAndrew Jeffery #include "mboxd.h"
28457a6e5fSAndrew Jeffery #include "common.h"
29457a6e5fSAndrew Jeffery #include "transport_mbox.h"
30457a6e5fSAndrew Jeffery #include "windows.h"
31457a6e5fSAndrew Jeffery #include "lpc.h"
32457a6e5fSAndrew Jeffery 
33*68a24c9eSPatrick Williams #pragma GCC diagnostic push
34*68a24c9eSPatrick Williams #pragma GCC diagnostic ignored "-Wpointer-arith"
35*68a24c9eSPatrick Williams 
361e531afdSAndrew Jeffery struct errno_map {
371e531afdSAndrew Jeffery 	int rc;
381e531afdSAndrew Jeffery 	int mbox_errno;
391e531afdSAndrew Jeffery };
401e531afdSAndrew Jeffery 
411e531afdSAndrew Jeffery static const struct errno_map errno_map_v1[] = {
421e531afdSAndrew Jeffery 	{ 0, MBOX_R_SUCCESS },
431e531afdSAndrew Jeffery 	{ EACCES, MBOX_R_PARAM_ERROR },
442f1477c4SAndrew Jeffery 	{ EBADMSG, MBOX_R_PARAM_ERROR },
451e531afdSAndrew Jeffery 	{ EBUSY, MBOX_R_SYSTEM_ERROR },
461e531afdSAndrew Jeffery 	{ EINVAL, MBOX_R_PARAM_ERROR },
472f1477c4SAndrew Jeffery 	{ ENOTSUP, MBOX_R_PARAM_ERROR },
481e531afdSAndrew Jeffery 	{ EPERM, MBOX_R_PARAM_ERROR },
492f1477c4SAndrew Jeffery 	{ EPROTO, MBOX_R_PARAM_ERROR },
501e531afdSAndrew Jeffery 	{ ETIMEDOUT, MBOX_R_TIMEOUT },
511e531afdSAndrew Jeffery 	{ -1, MBOX_R_SYSTEM_ERROR },
521e531afdSAndrew Jeffery };
531e531afdSAndrew Jeffery 
541e531afdSAndrew Jeffery static const struct errno_map errno_map_v2[] = {
551e531afdSAndrew Jeffery 	{ 0, MBOX_R_SUCCESS },
56c7d1947eSAndrew Jeffery 	{ EACCES, MBOX_R_WINDOW_ERROR },
572f1477c4SAndrew Jeffery 	{ EBADMSG, MBOX_R_SEQ_ERROR },
581e531afdSAndrew Jeffery 	{ EBUSY, MBOX_R_BUSY },
591e531afdSAndrew Jeffery 	{ EINVAL, MBOX_R_PARAM_ERROR },
602f1477c4SAndrew Jeffery 	{ ENOTSUP, MBOX_R_PARAM_ERROR },
611e531afdSAndrew Jeffery 	{ EPERM, MBOX_R_WINDOW_ERROR },
622f1477c4SAndrew Jeffery 	{ EPROTO, MBOX_R_PARAM_ERROR },
631e531afdSAndrew Jeffery 	{ ETIMEDOUT, MBOX_R_TIMEOUT },
641e531afdSAndrew Jeffery 	{ -1, MBOX_R_SYSTEM_ERROR },
651e531afdSAndrew Jeffery };
661e531afdSAndrew Jeffery 
671e531afdSAndrew Jeffery static const struct errno_map *errno_maps[] = {
681e531afdSAndrew Jeffery 	[0] = NULL,
691e531afdSAndrew Jeffery 	[1] = errno_map_v1,
701e531afdSAndrew Jeffery 	[2] = errno_map_v2,
711e531afdSAndrew Jeffery };
721e531afdSAndrew Jeffery 
mbox_xlate_errno(struct mbox_context * context,int rc)731e531afdSAndrew Jeffery static inline int mbox_xlate_errno(struct mbox_context *context,
741e531afdSAndrew Jeffery 					     int rc)
751e531afdSAndrew Jeffery {
761e531afdSAndrew Jeffery 	const struct errno_map *entry;
771e531afdSAndrew Jeffery 
781e531afdSAndrew Jeffery 	rc = -rc;
792f1477c4SAndrew Jeffery 	MSG_DBG("Translating errno %d: %s\n", rc, strerror(rc));
801e531afdSAndrew Jeffery 	for(entry = errno_maps[context->version]; entry->rc != -1; entry++) {
811e531afdSAndrew Jeffery 		if (rc == entry->rc) {
822f1477c4SAndrew Jeffery 			return entry->mbox_errno;
831e531afdSAndrew Jeffery 		}
841e531afdSAndrew Jeffery 	}
851e531afdSAndrew Jeffery 
862f1477c4SAndrew Jeffery 	return entry->mbox_errno;
871e531afdSAndrew Jeffery }
881e531afdSAndrew Jeffery 
89457a6e5fSAndrew Jeffery /*
905335f093SAndrew Jeffery  * transport_mbox_flush_events() - Write to the BMC controlled status register
915335f093SAndrew Jeffery  * 				   (reg 15)
92457a6e5fSAndrew Jeffery  * @context:	The mbox context pointer
93457a6e5fSAndrew Jeffery  *
94457a6e5fSAndrew Jeffery  * Return:	0 on success otherwise negative error code
95457a6e5fSAndrew Jeffery  */
transport_mbox_flush_events(struct mbox_context * context,uint8_t events)96f62601b8SAndrew Jeffery static int transport_mbox_flush_events(struct mbox_context *context, uint8_t events)
97457a6e5fSAndrew Jeffery {
98457a6e5fSAndrew Jeffery 	int rc;
99457a6e5fSAndrew Jeffery 
100457a6e5fSAndrew Jeffery 	/* Seek mbox registers */
101457a6e5fSAndrew Jeffery 	rc = lseek(context->fds[MBOX_FD].fd, MBOX_BMC_EVENT, SEEK_SET);
102457a6e5fSAndrew Jeffery 	if (rc != MBOX_BMC_EVENT) {
103457a6e5fSAndrew Jeffery 		MSG_ERR("Couldn't lseek mbox to byte %d: %s\n", MBOX_BMC_EVENT,
104457a6e5fSAndrew Jeffery 				strerror(errno));
1055335f093SAndrew Jeffery 		return -errno;
106457a6e5fSAndrew Jeffery 	}
107457a6e5fSAndrew Jeffery 
108457a6e5fSAndrew Jeffery 	/* Write to mbox status register */
109f62601b8SAndrew Jeffery 	rc = write(context->fds[MBOX_FD].fd, &events, 1);
110457a6e5fSAndrew Jeffery 	if (rc != 1) {
111457a6e5fSAndrew Jeffery 		MSG_ERR("Couldn't write to BMC status reg: %s\n",
112457a6e5fSAndrew Jeffery 				strerror(errno));
1135335f093SAndrew Jeffery 		return -errno;
114457a6e5fSAndrew Jeffery 	}
115457a6e5fSAndrew Jeffery 
116457a6e5fSAndrew Jeffery 	/* Reset to start */
117457a6e5fSAndrew Jeffery 	rc = lseek(context->fds[MBOX_FD].fd, 0, SEEK_SET);
118457a6e5fSAndrew Jeffery 	if (rc) {
119457a6e5fSAndrew Jeffery 		MSG_ERR("Couldn't reset MBOX offset to zero: %s\n",
120457a6e5fSAndrew Jeffery 				strerror(errno));
1215335f093SAndrew Jeffery 		return -errno;
122457a6e5fSAndrew Jeffery 	}
123457a6e5fSAndrew Jeffery 
124457a6e5fSAndrew Jeffery 	return 0;
125457a6e5fSAndrew Jeffery }
126457a6e5fSAndrew Jeffery 
transport_mbox_put_events(struct mbox_context * context,uint8_t mask)127fe0c9e86SAndrew Jeffery static int transport_mbox_put_events(struct mbox_context *context,
128fe0c9e86SAndrew Jeffery 					uint8_t mask)
1294414fb8dSAndrew Jeffery {
130f62601b8SAndrew Jeffery 	return transport_mbox_flush_events(context, context->bmc_events & mask);
1314414fb8dSAndrew Jeffery }
1324414fb8dSAndrew Jeffery 
transport_mbox_update_events(struct mbox_context * context,uint8_t events,uint8_t mask)133fe0c9e86SAndrew Jeffery static int transport_mbox_update_events(struct mbox_context *context,
134*68a24c9eSPatrick Williams 					uint8_t events __attribute__((unused)),
135*68a24c9eSPatrick Williams 					uint8_t mask)
1364414fb8dSAndrew Jeffery {
137f62601b8SAndrew Jeffery 	return transport_mbox_flush_events(context, context->bmc_events & mask);
1384414fb8dSAndrew Jeffery }
1394414fb8dSAndrew Jeffery 
14023a48212SAndrew Jeffery static const struct transport_ops transport_mbox_ops = {
141fe0c9e86SAndrew Jeffery 	.put_events = transport_mbox_put_events,
142fe0c9e86SAndrew Jeffery 	.set_events = transport_mbox_update_events,
143fe0c9e86SAndrew Jeffery 	.clear_events = transport_mbox_update_events,
14423a48212SAndrew Jeffery };
14523a48212SAndrew Jeffery 
146457a6e5fSAndrew Jeffery /* Command Handlers */
147457a6e5fSAndrew Jeffery 
148457a6e5fSAndrew Jeffery /*
149457a6e5fSAndrew Jeffery  * Command: RESET_STATE
150457a6e5fSAndrew Jeffery  * Reset the LPC mapping to point back at the flash, or memory in case we're
151457a6e5fSAndrew Jeffery  * using a virtual pnor.
152457a6e5fSAndrew Jeffery  */
mbox_handle_reset(struct mbox_context * context,union mbox_regs * req,struct mbox_msg * resp)153f21c81c7SAndrew Jeffery static int mbox_handle_reset(struct mbox_context *context,
154*68a24c9eSPatrick Williams 			     union mbox_regs *req __attribute__((unused)),
155*68a24c9eSPatrick Williams 			     struct mbox_msg *resp __attribute__((unused)))
156457a6e5fSAndrew Jeffery {
1572f1477c4SAndrew Jeffery 	return context->protocol->reset(context);
158457a6e5fSAndrew Jeffery }
159457a6e5fSAndrew Jeffery 
160457a6e5fSAndrew Jeffery /*
161457a6e5fSAndrew Jeffery  * Command: GET_MBOX_INFO
162457a6e5fSAndrew Jeffery  * Get the API version, default window size and block size
163457a6e5fSAndrew Jeffery  * We also set the LPC mapping to point to the reserved memory region here so
164457a6e5fSAndrew Jeffery  * this command must be called before any window manipulation
165457a6e5fSAndrew Jeffery  *
166457a6e5fSAndrew Jeffery  * V1:
167457a6e5fSAndrew Jeffery  * ARGS[0]: API Version
168457a6e5fSAndrew Jeffery  *
169457a6e5fSAndrew Jeffery  * RESP[0]: API Version
170457a6e5fSAndrew Jeffery  * RESP[1:2]: Default read window size (number of blocks)
171457a6e5fSAndrew Jeffery  * RESP[3:4]: Default write window size (number of blocks)
172457a6e5fSAndrew Jeffery  * RESP[5]: Block size (as shift)
173457a6e5fSAndrew Jeffery  *
174457a6e5fSAndrew Jeffery  * V2:
175457a6e5fSAndrew Jeffery  * ARGS[0]: API Version
176457a6e5fSAndrew Jeffery  *
177457a6e5fSAndrew Jeffery  * RESP[0]: API Version
178457a6e5fSAndrew Jeffery  * RESP[1:2]: Default read window size (number of blocks)
179457a6e5fSAndrew Jeffery  * RESP[3:4]: Default write window size (number of blocks)
180457a6e5fSAndrew Jeffery  * RESP[5]: Block size (as shift)
181457a6e5fSAndrew Jeffery  */
mbox_handle_mbox_info(struct mbox_context * context,union mbox_regs * req,struct mbox_msg * resp)182f21c81c7SAndrew Jeffery static int mbox_handle_mbox_info(struct mbox_context *context,
183457a6e5fSAndrew Jeffery 				 union mbox_regs *req, struct mbox_msg *resp)
184457a6e5fSAndrew Jeffery {
185457a6e5fSAndrew Jeffery 	uint8_t mbox_api_version = req->msg.args[0];
1861e531afdSAndrew Jeffery 	struct protocol_get_info io = {
1871e531afdSAndrew Jeffery 		.req = { .api_version = mbox_api_version }
1881e531afdSAndrew Jeffery 	};
189457a6e5fSAndrew Jeffery 	int rc;
190457a6e5fSAndrew Jeffery 
1911e531afdSAndrew Jeffery 	rc = context->protocol->get_info(context, &io);
192457a6e5fSAndrew Jeffery 	if (rc < 0) {
1932f1477c4SAndrew Jeffery 		return rc;
194457a6e5fSAndrew Jeffery 	}
195457a6e5fSAndrew Jeffery 
19623a48212SAndrew Jeffery 	/*
19723a48212SAndrew Jeffery 	 * Switch transport to mbox, however we need to delay flushing the
19823a48212SAndrew Jeffery 	 * event state until after the command is processed.
19923a48212SAndrew Jeffery 	 */
20023a48212SAndrew Jeffery 	context->transport = &transport_mbox_ops;
20123a48212SAndrew Jeffery 
2021e531afdSAndrew Jeffery 	resp->args[0] = io.resp.api_version;
2031e531afdSAndrew Jeffery 	if (io.resp.api_version == API_VERSION_1) {
2041e531afdSAndrew Jeffery 		put_u16(&resp->args[1], io.resp.v1.read_window_size);
2051e531afdSAndrew Jeffery 		put_u16(&resp->args[3], io.resp.v1.write_window_size);
2061e531afdSAndrew Jeffery 	} else if (io.resp.api_version >= API_VERSION_2) {
2071e531afdSAndrew Jeffery 		resp->args[5] = io.resp.v2.block_size_shift;
2081e531afdSAndrew Jeffery 		put_u16(&resp->args[6], io.resp.v2.timeout);
209457a6e5fSAndrew Jeffery 	}
210457a6e5fSAndrew Jeffery 
211457a6e5fSAndrew Jeffery 	return 0;
212457a6e5fSAndrew Jeffery }
213457a6e5fSAndrew Jeffery 
214457a6e5fSAndrew Jeffery /*
215457a6e5fSAndrew Jeffery  * Command: GET_FLASH_INFO
216457a6e5fSAndrew Jeffery  * Get the flash size and erase granularity
217457a6e5fSAndrew Jeffery  *
218457a6e5fSAndrew Jeffery  * V1:
219457a6e5fSAndrew Jeffery  * RESP[0:3]: Flash Size (bytes)
220457a6e5fSAndrew Jeffery  * RESP[4:7]: Erase Size (bytes)
221457a6e5fSAndrew Jeffery  * V2:
222457a6e5fSAndrew Jeffery  * RESP[0:1]: Flash Size (number of blocks)
223457a6e5fSAndrew Jeffery  * RESP[2:3]: Erase Size (number of blocks)
224457a6e5fSAndrew Jeffery  */
mbox_handle_flash_info(struct mbox_context * context,union mbox_regs * req,struct mbox_msg * resp)225f21c81c7SAndrew Jeffery static int mbox_handle_flash_info(struct mbox_context *context,
226*68a24c9eSPatrick Williams 				  union mbox_regs *req __attribute__((unused)),
227*68a24c9eSPatrick Williams 				  struct mbox_msg *resp)
228457a6e5fSAndrew Jeffery {
22991a87454SAndrew Jeffery 	struct protocol_get_flash_info io;
23091a87454SAndrew Jeffery 	int rc;
23191a87454SAndrew Jeffery 
23291a87454SAndrew Jeffery 	rc = context->protocol->get_flash_info(context, &io);
23391a87454SAndrew Jeffery 	if (rc < 0) {
2342f1477c4SAndrew Jeffery 		return rc;
23591a87454SAndrew Jeffery 	}
23691a87454SAndrew Jeffery 
237457a6e5fSAndrew Jeffery 	switch (context->version) {
238457a6e5fSAndrew Jeffery 	case API_VERSION_1:
239457a6e5fSAndrew Jeffery 		/* Both Sizes in Bytes */
24091a87454SAndrew Jeffery 		put_u32(&resp->args[0], io.resp.v1.flash_size);
24191a87454SAndrew Jeffery 		put_u32(&resp->args[4], io.resp.v1.erase_size);
242457a6e5fSAndrew Jeffery 		break;
243457a6e5fSAndrew Jeffery 	case API_VERSION_2:
244457a6e5fSAndrew Jeffery 		/* Both Sizes in Block Size */
24591a87454SAndrew Jeffery 		put_u16(&resp->args[0], io.resp.v2.flash_size);
24691a87454SAndrew Jeffery 		put_u16(&resp->args[2], io.resp.v2.erase_size);
247457a6e5fSAndrew Jeffery 		break;
248457a6e5fSAndrew Jeffery 	default:
249457a6e5fSAndrew Jeffery 		MSG_ERR("API Version Not Valid - Invalid System State\n");
250457a6e5fSAndrew Jeffery 		return -MBOX_R_SYSTEM_ERROR;
251457a6e5fSAndrew Jeffery 	}
252457a6e5fSAndrew Jeffery 
253457a6e5fSAndrew Jeffery 	return 0;
254457a6e5fSAndrew Jeffery }
255457a6e5fSAndrew Jeffery 
256457a6e5fSAndrew Jeffery /*
257457a6e5fSAndrew Jeffery  * get_lpc_addr_shifted() - Get lpc address of the current window
258457a6e5fSAndrew Jeffery  * @context:		The mbox context pointer
259457a6e5fSAndrew Jeffery  *
260457a6e5fSAndrew Jeffery  * Return:	The lpc address to access that offset shifted by block size
261457a6e5fSAndrew Jeffery  */
get_lpc_addr_shifted(struct mbox_context * context)262457a6e5fSAndrew Jeffery static inline uint16_t get_lpc_addr_shifted(struct mbox_context *context)
263457a6e5fSAndrew Jeffery {
264457a6e5fSAndrew Jeffery 	uint32_t lpc_addr, mem_offset;
265457a6e5fSAndrew Jeffery 
266457a6e5fSAndrew Jeffery 	/* Offset of the current window in the reserved memory region */
267457a6e5fSAndrew Jeffery 	mem_offset = context->current->mem - context->mem;
268457a6e5fSAndrew Jeffery 	/* Total LPC Address */
269457a6e5fSAndrew Jeffery 	lpc_addr = context->lpc_base + mem_offset;
270457a6e5fSAndrew Jeffery 
271457a6e5fSAndrew Jeffery 	MSG_DBG("LPC address of current window: 0x%.8x\n", lpc_addr);
272457a6e5fSAndrew Jeffery 
273f1e547c7SEvan Lojewski 	return lpc_addr >> context->backend.block_size_shift;
274457a6e5fSAndrew Jeffery }
275457a6e5fSAndrew Jeffery 
mbox_handle_create_window(struct mbox_context * context,bool ro,union mbox_regs * req,struct mbox_msg * resp)276f21c81c7SAndrew Jeffery static int mbox_handle_create_window(struct mbox_context *context, bool ro,
2774bcec8efSAndrew Jeffery 			      union mbox_regs *req, struct mbox_msg *resp)
2784bcec8efSAndrew Jeffery {
2794bcec8efSAndrew Jeffery 	struct protocol_create_window io;
2804bcec8efSAndrew Jeffery 	int rc;
2814bcec8efSAndrew Jeffery 
2824bcec8efSAndrew Jeffery 	io.req.offset = get_u16(&req->msg.args[0]);
2834bcec8efSAndrew Jeffery 	io.req.ro = ro;
2844bcec8efSAndrew Jeffery 
2854bcec8efSAndrew Jeffery 	rc = context->protocol->create_window(context, &io);
2864bcec8efSAndrew Jeffery 	if (rc < 0) {
2874bcec8efSAndrew Jeffery 		return rc;
2884bcec8efSAndrew Jeffery 	}
2894bcec8efSAndrew Jeffery 
2904bcec8efSAndrew Jeffery 	put_u16(&resp->args[0], io.resp.lpc_address);
2914bcec8efSAndrew Jeffery 	if (context->version >= API_VERSION_2) {
2924bcec8efSAndrew Jeffery 		put_u16(&resp->args[2], io.resp.size);
2934bcec8efSAndrew Jeffery 		put_u16(&resp->args[4], io.resp.offset);
2944bcec8efSAndrew Jeffery 	}
2954bcec8efSAndrew Jeffery 
2964bcec8efSAndrew Jeffery 	return 0;
2974bcec8efSAndrew Jeffery }
2984bcec8efSAndrew Jeffery 
299457a6e5fSAndrew Jeffery /*
300457a6e5fSAndrew Jeffery  * Command: CREATE_READ_WINDOW
301457a6e5fSAndrew Jeffery  * Opens a read window
302457a6e5fSAndrew Jeffery  * First checks if any current window with the requested data, if so we just
303457a6e5fSAndrew Jeffery  * point the host to that. Otherwise we read the request data in from flash and
304457a6e5fSAndrew Jeffery  * point the host there.
305457a6e5fSAndrew Jeffery  *
306457a6e5fSAndrew Jeffery  * V1:
307457a6e5fSAndrew Jeffery  * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
308457a6e5fSAndrew Jeffery  *
309457a6e5fSAndrew Jeffery  * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
310457a6e5fSAndrew Jeffery  *
311457a6e5fSAndrew Jeffery  * V2:
312457a6e5fSAndrew Jeffery  * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
313457a6e5fSAndrew Jeffery  * ARGS[2:3]: Requested window size (number of blocks)
314457a6e5fSAndrew Jeffery  *
315457a6e5fSAndrew Jeffery  * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
316457a6e5fSAndrew Jeffery  * RESP[2:3]: Actual window size that the host can access (number of blocks)
317457a6e5fSAndrew Jeffery  */
mbox_handle_read_window(struct mbox_context * context,union mbox_regs * req,struct mbox_msg * resp)318f21c81c7SAndrew Jeffery static int mbox_handle_read_window(struct mbox_context *context,
319457a6e5fSAndrew Jeffery 				   union mbox_regs *req, struct mbox_msg *resp)
320457a6e5fSAndrew Jeffery {
3212f1477c4SAndrew Jeffery 	return mbox_handle_create_window(context, true, req, resp);
322457a6e5fSAndrew Jeffery }
323457a6e5fSAndrew Jeffery 
324457a6e5fSAndrew Jeffery /*
325457a6e5fSAndrew Jeffery  * Command: CREATE_WRITE_WINDOW
326457a6e5fSAndrew Jeffery  * Opens a write window
327457a6e5fSAndrew Jeffery  * First checks if any current window with the requested data, if so we just
328457a6e5fSAndrew Jeffery  * point the host to that. Otherwise we read the request data in from flash and
329457a6e5fSAndrew Jeffery  * point the host there.
330457a6e5fSAndrew Jeffery  *
331457a6e5fSAndrew Jeffery  * V1:
332457a6e5fSAndrew Jeffery  * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
333457a6e5fSAndrew Jeffery  *
334457a6e5fSAndrew Jeffery  * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
335457a6e5fSAndrew Jeffery  *
336457a6e5fSAndrew Jeffery  * V2:
337457a6e5fSAndrew Jeffery  * ARGS[0:1]: Window Location as Offset into Flash (number of blocks)
338457a6e5fSAndrew Jeffery  * ARGS[2:3]: Requested window size (number of blocks)
339457a6e5fSAndrew Jeffery  *
340457a6e5fSAndrew Jeffery  * RESP[0:1]: LPC bus address for host to access this window (number of blocks)
341457a6e5fSAndrew Jeffery  * RESP[2:3]: Actual window size that was mapped/host can access (n.o. blocks)
342457a6e5fSAndrew Jeffery  */
mbox_handle_write_window(struct mbox_context * context,union mbox_regs * req,struct mbox_msg * resp)343f21c81c7SAndrew Jeffery static int mbox_handle_write_window(struct mbox_context *context,
344457a6e5fSAndrew Jeffery 				    union mbox_regs *req, struct mbox_msg *resp)
345457a6e5fSAndrew Jeffery {
3462f1477c4SAndrew Jeffery 	return mbox_handle_create_window(context, false, req, resp);
347457a6e5fSAndrew Jeffery }
348457a6e5fSAndrew Jeffery 
349457a6e5fSAndrew Jeffery /*
350457a6e5fSAndrew Jeffery  * Commands: MARK_WRITE_DIRTY
351457a6e5fSAndrew Jeffery  * Marks a portion of the current (write) window dirty, informing the daemon
352457a6e5fSAndrew Jeffery  * that is has been written to and thus must be at some point written to the
353457a6e5fSAndrew Jeffery  * backing store
354457a6e5fSAndrew Jeffery  * These changes aren't written back to the backing store unless flush is then
355457a6e5fSAndrew Jeffery  * called or the window closed
356457a6e5fSAndrew Jeffery  *
357457a6e5fSAndrew Jeffery  * V1:
358457a6e5fSAndrew Jeffery  * ARGS[0:1]: Where within flash to start (number of blocks)
359457a6e5fSAndrew Jeffery  * ARGS[2:5]: Number to mark dirty (number of bytes)
360457a6e5fSAndrew Jeffery  *
361457a6e5fSAndrew Jeffery  * V2:
362457a6e5fSAndrew Jeffery  * ARGS[0:1]: Where within window to start (number of blocks)
363457a6e5fSAndrew Jeffery  * ARGS[2:3]: Number to mark dirty (number of blocks)
364457a6e5fSAndrew Jeffery  */
mbox_handle_dirty_window(struct mbox_context * context,union mbox_regs * req,struct mbox_msg * resp)365f21c81c7SAndrew Jeffery static int mbox_handle_dirty_window(struct mbox_context *context,
366*68a24c9eSPatrick Williams 				    union mbox_regs *req,
367*68a24c9eSPatrick Williams 				    struct mbox_msg *resp __attribute__((unused)))
368457a6e5fSAndrew Jeffery {
369a336e43aSAndrew Jeffery 	struct protocol_mark_dirty io;
370457a6e5fSAndrew Jeffery 
371a336e43aSAndrew Jeffery 	if (context->version == API_VERSION_1) {
372a336e43aSAndrew Jeffery 		io.req.v1.offset = get_u16(&req->msg.args[0]);
373a336e43aSAndrew Jeffery 		io.req.v1.size = get_u32(&req->msg.args[2]);
374457a6e5fSAndrew Jeffery 	} else {
375a336e43aSAndrew Jeffery 		io.req.v2.offset = get_u16(&req->msg.args[0]);
376a336e43aSAndrew Jeffery 		io.req.v2.size = get_u16(&req->msg.args[2]);
377457a6e5fSAndrew Jeffery 	}
378457a6e5fSAndrew Jeffery 
3792f1477c4SAndrew Jeffery 	return context->protocol->mark_dirty(context, &io);
380457a6e5fSAndrew Jeffery }
381457a6e5fSAndrew Jeffery 
382457a6e5fSAndrew Jeffery /*
383457a6e5fSAndrew Jeffery  * Commands: MARK_WRITE_ERASE
384457a6e5fSAndrew Jeffery  * Erases a portion of the current window
385457a6e5fSAndrew Jeffery  * These changes aren't written back to the backing store unless flush is then
386457a6e5fSAndrew Jeffery  * called or the window closed
387457a6e5fSAndrew Jeffery  *
388457a6e5fSAndrew Jeffery  * V1:
389457a6e5fSAndrew Jeffery  * Unimplemented
390457a6e5fSAndrew Jeffery  *
391457a6e5fSAndrew Jeffery  * V2:
392457a6e5fSAndrew Jeffery  * ARGS[0:1]: Where within window to start (number of blocks)
393457a6e5fSAndrew Jeffery  * ARGS[2:3]: Number to erase (number of blocks)
394457a6e5fSAndrew Jeffery  */
mbox_handle_erase_window(struct mbox_context * context,union mbox_regs * req,struct mbox_msg * resp)395f21c81c7SAndrew Jeffery static int mbox_handle_erase_window(struct mbox_context *context,
396*68a24c9eSPatrick Williams 				    union mbox_regs *req,
397*68a24c9eSPatrick Williams 				    struct mbox_msg *resp __attribute__((unused)))
398457a6e5fSAndrew Jeffery {
39962a3daaeSAndrew Jeffery 	struct protocol_erase io;
400457a6e5fSAndrew Jeffery 
40162a3daaeSAndrew Jeffery 	io.req.offset = get_u16(&req->msg.args[0]);
40262a3daaeSAndrew Jeffery 	io.req.size = get_u16(&req->msg.args[2]);
40362a3daaeSAndrew Jeffery 
40462a3daaeSAndrew Jeffery 	if (!context->protocol->erase) {
405457a6e5fSAndrew Jeffery 		MSG_ERR("Protocol Version invalid for Erase Command\n");
4062f1477c4SAndrew Jeffery 		return -ENOTSUP;
407457a6e5fSAndrew Jeffery 	}
408457a6e5fSAndrew Jeffery 
4092f1477c4SAndrew Jeffery 	return context->protocol->erase(context, &io);
410457a6e5fSAndrew Jeffery }
411457a6e5fSAndrew Jeffery 
412457a6e5fSAndrew Jeffery /*
413457a6e5fSAndrew Jeffery  * Command: WRITE_FLUSH
414457a6e5fSAndrew Jeffery  * Flushes any dirty or erased blocks in the current window back to the backing
415457a6e5fSAndrew Jeffery  * store
416457a6e5fSAndrew Jeffery  * NOTE: For V1 this behaves much the same as the dirty command in that it
417457a6e5fSAndrew Jeffery  * takes an offset and number of blocks to dirty, then also performs a flush as
418457a6e5fSAndrew Jeffery  * part of the same command. For V2 this will only flush blocks already marked
419457a6e5fSAndrew Jeffery  * dirty/erased with the appropriate commands and doesn't take any arguments
420457a6e5fSAndrew Jeffery  * directly.
421457a6e5fSAndrew Jeffery  *
422457a6e5fSAndrew Jeffery  * V1:
423457a6e5fSAndrew Jeffery  * ARGS[0:1]: Where within window to start (number of blocks)
424457a6e5fSAndrew Jeffery  * ARGS[2:5]: Number to mark dirty (number of bytes)
425457a6e5fSAndrew Jeffery  *
426457a6e5fSAndrew Jeffery  * V2:
427457a6e5fSAndrew Jeffery  * NONE
428457a6e5fSAndrew Jeffery  */
mbox_handle_flush_window(struct mbox_context * context,union mbox_regs * req,struct mbox_msg * resp)429f21c81c7SAndrew Jeffery static int mbox_handle_flush_window(struct mbox_context *context,
430*68a24c9eSPatrick Williams 				    union mbox_regs *req,
431*68a24c9eSPatrick Williams 				    struct mbox_msg *resp __attribute__((unused)))
432457a6e5fSAndrew Jeffery {
4339b920cf4SAndrew Jeffery 	struct protocol_flush io = { 0 };
434457a6e5fSAndrew Jeffery 
4359b920cf4SAndrew Jeffery 	if (context->version == API_VERSION_1) {
4369b920cf4SAndrew Jeffery 		io.req.offset = get_u16(&req->msg.args[0]);
4379b920cf4SAndrew Jeffery 		io.req.size = get_u32(&req->msg.args[2]);
438457a6e5fSAndrew Jeffery 	}
439457a6e5fSAndrew Jeffery 
4402f1477c4SAndrew Jeffery 	return context->protocol->flush(context, &io);
441457a6e5fSAndrew Jeffery }
442457a6e5fSAndrew Jeffery 
443457a6e5fSAndrew Jeffery /*
444457a6e5fSAndrew Jeffery  * Command: CLOSE_WINDOW
445457a6e5fSAndrew Jeffery  * Close the current window
446457a6e5fSAndrew Jeffery  * NOTE: There is an implicit flush
447457a6e5fSAndrew Jeffery  *
448457a6e5fSAndrew Jeffery  * V1:
449457a6e5fSAndrew Jeffery  * NONE
450457a6e5fSAndrew Jeffery  *
451457a6e5fSAndrew Jeffery  * V2:
452457a6e5fSAndrew Jeffery  * ARGS[0]: FLAGS
453457a6e5fSAndrew Jeffery  */
mbox_handle_close_window(struct mbox_context * context,union mbox_regs * req,struct mbox_msg * resp)454f21c81c7SAndrew Jeffery static int mbox_handle_close_window(struct mbox_context *context,
455*68a24c9eSPatrick Williams 				    union mbox_regs *req,
456*68a24c9eSPatrick Williams 				    struct mbox_msg *resp __attribute__((unused)))
457457a6e5fSAndrew Jeffery {
458093eda5cSAndrew Jeffery 	struct protocol_close io = { 0 };
459457a6e5fSAndrew Jeffery 
460457a6e5fSAndrew Jeffery 	if (context->version >= API_VERSION_2) {
461093eda5cSAndrew Jeffery 		io.req.flags = req->msg.args[0];
462457a6e5fSAndrew Jeffery 	}
463457a6e5fSAndrew Jeffery 
4642f1477c4SAndrew Jeffery 	return context->protocol->close(context, &io);
465457a6e5fSAndrew Jeffery }
466457a6e5fSAndrew Jeffery 
467457a6e5fSAndrew Jeffery /*
468457a6e5fSAndrew Jeffery  * Command: BMC_EVENT_ACK
469457a6e5fSAndrew Jeffery  * Sent by the host to acknowledge BMC events supplied in mailbox register 15
470457a6e5fSAndrew Jeffery  *
471457a6e5fSAndrew Jeffery  * ARGS[0]: Bitmap of bits to ack (by clearing)
472457a6e5fSAndrew Jeffery  */
mbox_handle_ack(struct mbox_context * context,union mbox_regs * req,struct mbox_msg * resp)473f21c81c7SAndrew Jeffery static int mbox_handle_ack(struct mbox_context *context, union mbox_regs *req,
474*68a24c9eSPatrick Williams 			   struct mbox_msg *resp __attribute__((unused)))
475457a6e5fSAndrew Jeffery {
476c5c83048SAndrew Jeffery 	struct protocol_ack io;
477457a6e5fSAndrew Jeffery 
478c5c83048SAndrew Jeffery 	io.req.flags = req->msg.args[0];
479c5c83048SAndrew Jeffery 
4802f1477c4SAndrew Jeffery 	return context->protocol->ack(context, &io);
481457a6e5fSAndrew Jeffery }
482457a6e5fSAndrew Jeffery 
483457a6e5fSAndrew Jeffery /*
484457a6e5fSAndrew Jeffery  * check_req_valid() - Check if the given request is a valid mbox request
485457a6e5fSAndrew Jeffery  * @context:	The mbox context pointer
486457a6e5fSAndrew Jeffery  * @cmd:	The request registers
487457a6e5fSAndrew Jeffery  *
488457a6e5fSAndrew Jeffery  * Return:	0 if request is valid otherwise negative error code
489457a6e5fSAndrew Jeffery  */
check_req_valid(struct mbox_context * context,union mbox_regs * req)490457a6e5fSAndrew Jeffery static int check_req_valid(struct mbox_context *context, union mbox_regs *req)
491457a6e5fSAndrew Jeffery {
492457a6e5fSAndrew Jeffery 	uint8_t cmd = req->msg.command;
493457a6e5fSAndrew Jeffery 	uint8_t seq = req->msg.seq;
494457a6e5fSAndrew Jeffery 
495457a6e5fSAndrew Jeffery 	if (cmd > NUM_MBOX_CMDS) {
496457a6e5fSAndrew Jeffery 		MSG_ERR("Unknown mbox command: %d\n", cmd);
4972f1477c4SAndrew Jeffery 		return -ENOTSUP;
498457a6e5fSAndrew Jeffery 	}
499457a6e5fSAndrew Jeffery 
500457a6e5fSAndrew Jeffery 	if (seq == context->prev_seq && cmd != MBOX_C_GET_MBOX_INFO) {
501457a6e5fSAndrew Jeffery 		MSG_ERR("Invalid sequence number: %d, previous: %d\n", seq,
502457a6e5fSAndrew Jeffery 			context->prev_seq);
5032f1477c4SAndrew Jeffery 		return -EBADMSG;
504457a6e5fSAndrew Jeffery 	}
505457a6e5fSAndrew Jeffery 
506457a6e5fSAndrew Jeffery 	if (context->state & STATE_SUSPENDED) {
507457a6e5fSAndrew Jeffery 		if (cmd != MBOX_C_GET_MBOX_INFO && cmd != MBOX_C_ACK) {
508457a6e5fSAndrew Jeffery 			MSG_ERR("Cannot use that cmd while suspended: %d\n",
509457a6e5fSAndrew Jeffery 				cmd);
5102f1477c4SAndrew Jeffery 			return -EBUSY;
511457a6e5fSAndrew Jeffery 		}
512457a6e5fSAndrew Jeffery 	}
513457a6e5fSAndrew Jeffery 
51423a48212SAndrew Jeffery 	if (context->transport != &transport_mbox_ops) {
51523a48212SAndrew Jeffery 		if (cmd != MBOX_C_RESET_STATE && cmd != MBOX_C_GET_MBOX_INFO) {
51623a48212SAndrew Jeffery 			MSG_ERR("Cannot switch transport with command %d\n",
51723a48212SAndrew Jeffery 				cmd);
51823a48212SAndrew Jeffery 			return -EPROTO;
51923a48212SAndrew Jeffery 		}
52023a48212SAndrew Jeffery 	}
52123a48212SAndrew Jeffery 
522457a6e5fSAndrew Jeffery 	if (!(context->state & MAPS_MEM)) {
523457a6e5fSAndrew Jeffery 		if (cmd != MBOX_C_RESET_STATE && cmd != MBOX_C_GET_MBOX_INFO
524457a6e5fSAndrew Jeffery 					      && cmd != MBOX_C_ACK) {
525457a6e5fSAndrew Jeffery 			MSG_ERR("Must call GET_MBOX_INFO before %d\n", cmd);
5262f1477c4SAndrew Jeffery 			return -EPROTO;
527457a6e5fSAndrew Jeffery 		}
528457a6e5fSAndrew Jeffery 	}
529457a6e5fSAndrew Jeffery 
530457a6e5fSAndrew Jeffery 	return 0;
531457a6e5fSAndrew Jeffery }
532457a6e5fSAndrew Jeffery 
5335335f093SAndrew Jeffery typedef int (*mboxd_mbox_handler)(struct mbox_context *, union mbox_regs *,
5345335f093SAndrew Jeffery 				  struct mbox_msg *);
5355335f093SAndrew Jeffery 
5365335f093SAndrew Jeffery static const mboxd_mbox_handler transport_mbox_handlers[] = {
537457a6e5fSAndrew Jeffery 	mbox_handle_reset,
538457a6e5fSAndrew Jeffery 	mbox_handle_mbox_info,
539457a6e5fSAndrew Jeffery 	mbox_handle_flash_info,
540457a6e5fSAndrew Jeffery 	mbox_handle_read_window,
541457a6e5fSAndrew Jeffery 	mbox_handle_close_window,
542457a6e5fSAndrew Jeffery 	mbox_handle_write_window,
543457a6e5fSAndrew Jeffery 	mbox_handle_dirty_window,
544457a6e5fSAndrew Jeffery 	mbox_handle_flush_window,
545457a6e5fSAndrew Jeffery 	mbox_handle_ack,
546457a6e5fSAndrew Jeffery 	mbox_handle_erase_window
547457a6e5fSAndrew Jeffery };
548457a6e5fSAndrew Jeffery 
549457a6e5fSAndrew Jeffery /*
550457a6e5fSAndrew Jeffery  * handle_mbox_req() - Handle an incoming mbox command request
551457a6e5fSAndrew Jeffery  * @context:	The mbox context pointer
552457a6e5fSAndrew Jeffery  * @req:	The mbox request message
553457a6e5fSAndrew Jeffery  *
554457a6e5fSAndrew Jeffery  * Return:	0 if handled successfully otherwise negative error code
555457a6e5fSAndrew Jeffery  */
handle_mbox_req(struct mbox_context * context,union mbox_regs * req)556457a6e5fSAndrew Jeffery static int handle_mbox_req(struct mbox_context *context, union mbox_regs *req)
557457a6e5fSAndrew Jeffery {
55823a48212SAndrew Jeffery 	const struct transport_ops *old_transport = context->transport;
559457a6e5fSAndrew Jeffery 	struct mbox_msg resp = {
560457a6e5fSAndrew Jeffery 		.command = req->msg.command,
561457a6e5fSAndrew Jeffery 		.seq = req->msg.seq,
562457a6e5fSAndrew Jeffery 		.args = { 0 },
563457a6e5fSAndrew Jeffery 		.response = MBOX_R_SUCCESS
564457a6e5fSAndrew Jeffery 	};
565457a6e5fSAndrew Jeffery 	int rc = 0, len, i;
566457a6e5fSAndrew Jeffery 
567457a6e5fSAndrew Jeffery 	MSG_INFO("Received MBOX command: %u\n", req->msg.command);
56823a48212SAndrew Jeffery 
569457a6e5fSAndrew Jeffery 	rc = check_req_valid(context, req);
5702f1477c4SAndrew Jeffery 	if (!rc) {
5715335f093SAndrew Jeffery 		mboxd_mbox_handler handler;
5725335f093SAndrew Jeffery 
573457a6e5fSAndrew Jeffery 		/* Commands start at 1 so we have to subtract 1 from the cmd */
5745335f093SAndrew Jeffery 		handler = transport_mbox_handlers[req->msg.command - 1];
5755335f093SAndrew Jeffery 		rc = handler(context, req, &resp);
576457a6e5fSAndrew Jeffery 		if (rc < 0) {
577457a6e5fSAndrew Jeffery 			MSG_ERR("Error handling mbox cmd: %d\n",
578457a6e5fSAndrew Jeffery 				req->msg.command);
579457a6e5fSAndrew Jeffery 		}
580457a6e5fSAndrew Jeffery 	}
581457a6e5fSAndrew Jeffery 
5822f1477c4SAndrew Jeffery 	rc = mbox_xlate_errno(context, rc);
5832f1477c4SAndrew Jeffery 	resp.response = rc;
584457a6e5fSAndrew Jeffery 	context->prev_seq = req->msg.seq;
585457a6e5fSAndrew Jeffery 
586457a6e5fSAndrew Jeffery 	MSG_DBG("Writing MBOX response:\n");
587457a6e5fSAndrew Jeffery 	MSG_DBG("MBOX cmd: %u\n", resp.command);
588457a6e5fSAndrew Jeffery 	MSG_DBG("MBOX seq: %u\n", resp.seq);
589457a6e5fSAndrew Jeffery 	for (i = 0; i < MBOX_ARGS_BYTES; i++) {
590457a6e5fSAndrew Jeffery 		MSG_DBG("MBOX arg[%d]: 0x%.2x\n", i, resp.args[i]);
591457a6e5fSAndrew Jeffery 	}
592457a6e5fSAndrew Jeffery 	MSG_INFO("Writing MBOX response: %u\n", resp.response);
593457a6e5fSAndrew Jeffery 	len = write(context->fds[MBOX_FD].fd, &resp, sizeof(resp));
594*68a24c9eSPatrick Williams 	if (len < (ssize_t)sizeof(resp)) {
595457a6e5fSAndrew Jeffery 		MSG_ERR("Didn't write the full response\n");
596457a6e5fSAndrew Jeffery 		rc = -errno;
597457a6e5fSAndrew Jeffery 	}
598457a6e5fSAndrew Jeffery 
59923a48212SAndrew Jeffery 	if (context->transport != old_transport &&
60023a48212SAndrew Jeffery 			context->transport == &transport_mbox_ops) {
6010453aa4cSAndrew Jeffery 		/* A bit messy, but we need the correct event mask */
6020453aa4cSAndrew Jeffery 		protocol_events_set(context, context->bmc_events);
60323a48212SAndrew Jeffery 	}
60423a48212SAndrew Jeffery 
605457a6e5fSAndrew Jeffery 	return rc;
606457a6e5fSAndrew Jeffery }
607457a6e5fSAndrew Jeffery 
608457a6e5fSAndrew Jeffery /*
609457a6e5fSAndrew Jeffery  * get_message() - Read an mbox request message from the mbox registers
610457a6e5fSAndrew Jeffery  * @context:	The mbox context pointer
611457a6e5fSAndrew Jeffery  * @msg:	Where to put the received message
612457a6e5fSAndrew Jeffery  *
613457a6e5fSAndrew Jeffery  * Return:	0 if read successfully otherwise negative error code
614457a6e5fSAndrew Jeffery  */
get_message(struct mbox_context * context,union mbox_regs * msg)615457a6e5fSAndrew Jeffery static int get_message(struct mbox_context *context, union mbox_regs *msg)
616457a6e5fSAndrew Jeffery {
617457a6e5fSAndrew Jeffery 	int rc, i;
618457a6e5fSAndrew Jeffery 
619457a6e5fSAndrew Jeffery 	rc = read(context->fds[MBOX_FD].fd, msg, sizeof(msg->raw));
620457a6e5fSAndrew Jeffery 	if (rc < 0) {
621457a6e5fSAndrew Jeffery 		MSG_ERR("Couldn't read: %s\n", strerror(errno));
622457a6e5fSAndrew Jeffery 		return -errno;
623*68a24c9eSPatrick Williams 	} else if (rc < (ssize_t)sizeof(msg->raw)) {
624457a6e5fSAndrew Jeffery 		MSG_ERR("Short read: %d expecting %zu\n", rc, sizeof(msg->raw));
625457a6e5fSAndrew Jeffery 		return -1;
626457a6e5fSAndrew Jeffery 	}
627457a6e5fSAndrew Jeffery 
628457a6e5fSAndrew Jeffery 	MSG_DBG("Received MBOX request:\n");
629457a6e5fSAndrew Jeffery 	MSG_DBG("MBOX cmd: %u\n", msg->msg.command);
630457a6e5fSAndrew Jeffery 	MSG_DBG("MBOX seq: %u\n", msg->msg.seq);
631457a6e5fSAndrew Jeffery 	for (i = 0; i < MBOX_ARGS_BYTES; i++) {
632457a6e5fSAndrew Jeffery 		MSG_DBG("MBOX arg[%d]: 0x%.2x\n", i, msg->msg.args[i]);
633457a6e5fSAndrew Jeffery 	}
634457a6e5fSAndrew Jeffery 
635457a6e5fSAndrew Jeffery 	return 0;
636457a6e5fSAndrew Jeffery }
637457a6e5fSAndrew Jeffery 
638457a6e5fSAndrew Jeffery /*
639d86141b6SAndrew Jeffery  * transport_mbox_dispatch() - handle an mbox interrupt
640457a6e5fSAndrew Jeffery  * @context:	The mbox context pointer
641457a6e5fSAndrew Jeffery  *
642457a6e5fSAndrew Jeffery  * Return:	0 if handled successfully otherwise negative error code
643457a6e5fSAndrew Jeffery  */
transport_mbox_dispatch(struct mbox_context * context)644d86141b6SAndrew Jeffery int transport_mbox_dispatch(struct mbox_context *context)
645457a6e5fSAndrew Jeffery {
646457a6e5fSAndrew Jeffery 	int rc = 0;
647457a6e5fSAndrew Jeffery 	union mbox_regs req = { 0 };
648457a6e5fSAndrew Jeffery 
649457a6e5fSAndrew Jeffery 	assert(context);
650457a6e5fSAndrew Jeffery 
651457a6e5fSAndrew Jeffery 	rc = get_message(context, &req);
652457a6e5fSAndrew Jeffery 	if (rc) {
653457a6e5fSAndrew Jeffery 		return rc;
654457a6e5fSAndrew Jeffery 	}
655457a6e5fSAndrew Jeffery 
656457a6e5fSAndrew Jeffery 	return handle_mbox_req(context, &req);
657457a6e5fSAndrew Jeffery }
658457a6e5fSAndrew Jeffery 
__transport_mbox_init(struct mbox_context * context,const char * path,const struct transport_ops ** ops)6594b8203d7SAndrew Jeffery int __transport_mbox_init(struct mbox_context *context, const char *path,
6604b8203d7SAndrew Jeffery 			  const struct transport_ops **ops)
661457a6e5fSAndrew Jeffery {
662457a6e5fSAndrew Jeffery 	int fd;
663457a6e5fSAndrew Jeffery 
664457a6e5fSAndrew Jeffery 	/* Open MBOX Device */
665457a6e5fSAndrew Jeffery 	fd = open(path, O_RDWR | O_NONBLOCK);
666457a6e5fSAndrew Jeffery 	if (fd < 0) {
6674b8203d7SAndrew Jeffery 		MSG_INFO("Couldn't open %s with flags O_RDWR: %s\n",
668457a6e5fSAndrew Jeffery 			path, strerror(errno));
669457a6e5fSAndrew Jeffery 		return -errno;
670457a6e5fSAndrew Jeffery 	}
671457a6e5fSAndrew Jeffery 	MSG_DBG("Opened mbox dev: %s\n", path);
672457a6e5fSAndrew Jeffery 
673457a6e5fSAndrew Jeffery 	context->fds[MBOX_FD].fd = fd;
674457a6e5fSAndrew Jeffery 
6754b8203d7SAndrew Jeffery 	if (ops) {
6764b8203d7SAndrew Jeffery 		*ops = &transport_mbox_ops;
6774b8203d7SAndrew Jeffery 	}
6784b8203d7SAndrew Jeffery 
679457a6e5fSAndrew Jeffery 	return 0;
680457a6e5fSAndrew Jeffery }
681457a6e5fSAndrew Jeffery 
transport_mbox_init(struct mbox_context * context,const struct transport_ops ** ops)682fe0c9e86SAndrew Jeffery int transport_mbox_init(struct mbox_context *context,
683fe0c9e86SAndrew Jeffery 			const struct transport_ops **ops)
684457a6e5fSAndrew Jeffery {
685fe0c9e86SAndrew Jeffery 	int rc;
686fe0c9e86SAndrew Jeffery 
6874b8203d7SAndrew Jeffery 	rc = __transport_mbox_init(context, MBOX_HOST_PATH, ops);
688fe0c9e86SAndrew Jeffery 	if (rc)
689fe0c9e86SAndrew Jeffery 		return rc;
690fe0c9e86SAndrew Jeffery 
691fe0c9e86SAndrew Jeffery 	return 0;
692457a6e5fSAndrew Jeffery }
693457a6e5fSAndrew Jeffery 
transport_mbox_free(struct mbox_context * context)69455260cefSAndrew Jeffery void transport_mbox_free(struct mbox_context *context)
695457a6e5fSAndrew Jeffery {
696457a6e5fSAndrew Jeffery 	close(context->fds[MBOX_FD].fd);
697457a6e5fSAndrew Jeffery }
698*68a24c9eSPatrick Williams 
699*68a24c9eSPatrick Williams #pragma GCC diagnostic pop
700