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