diff options
author | Andrew Jeffery <andrew@aj.id.au> | 2018-08-07 13:32:57 +0930 |
---|---|---|
committer | Andrew Jeffery <andrew@aj.id.au> | 2018-09-12 15:05:51 +0930 |
commit | 1e531afd1698c5613004e2bf4e73bda4364fa6d6 (patch) | |
tree | 9949340bcc068f8016c45c1422f79793952eab5d | |
parent | 457a6e5fa6a7dad50673222b09b2c7fec2ef0a97 (diff) | |
download | phosphor-mboxbridge-1e531afd1698c5613004e2bf4e73bda4364fa6d6.tar.gz phosphor-mboxbridge-1e531afd1698c5613004e2bf4e73bda4364fa6d6.zip |
protocol: Add get_info
Change-Id: Ie3338714813bb65f5d37fcd046dd5bebc0ba21f0
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | lpc.c | 2 | ||||
-rw-r--r-- | mbox.h | 6 | ||||
-rw-r--r-- | mboxd.c | 12 | ||||
-rw-r--r-- | protocol.c | 142 | ||||
-rw-r--r-- | protocol.h | 50 | ||||
-rw-r--r-- | test/Makefile.am.include | 3 | ||||
-rw-r--r-- | test/mbox.c | 3 | ||||
-rw-r--r-- | transport_mbox.c | 131 | ||||
-rw-r--r-- | vpnor/test/Makefile.am.include | 1 |
10 files changed, 272 insertions, 79 deletions
diff --git a/Makefile.am b/Makefile.am index 97be7e0..102e7c4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -8,6 +8,7 @@ mboxd_SOURCES = \ control_legacy.c \ control_dbus.c \ lpc.c \ + protocol.c \ transport_mbox.c \ windows.c \ mtd.c @@ -170,7 +170,7 @@ int lpc_map_memory(struct mbox_context *context) &map)) { MSG_ERR("Failed to point the LPC BUS to memory: %s\n", strerror(errno)); - return -MBOX_R_SYSTEM_ERROR; + return -errno; } /* LPC now maps memory (keep suspended state) */ @@ -8,6 +8,8 @@ #include <systemd/sd-bus.h> #include <poll.h> #include <stdbool.h> + +#include "protocol.h" #include "vpnor/mboxd_pnor_partition_table.h" enum api_version { @@ -136,9 +138,11 @@ typedef int (*mboxd_mbox_handler)(struct mbox_context *, union mbox_regs *, struct mbox_msg *); struct mbox_context { + enum api_version version; + const struct protocol_ops *protocol; + /* System State */ enum mbox_state state; - enum api_version version; struct pollfd fds[TOTAL_FDS]; sd_bus *bus; bool terminate; @@ -353,6 +353,11 @@ int main(int argc, char **argv) goto finish; } + rc = protocol_init(context); + if (rc) { + goto finish; + } + rc = init_mbox_dev(context); if (rc) { goto finish; @@ -403,14 +408,15 @@ finish: MSG_INFO("Daemon Exiting...\n"); clr_bmc_events(context, BMC_EVENT_DAEMON_READY, SET_BMC_EVENT); +#ifdef VIRTUAL_PNOR_ENABLED + destroy_vpnor(context); +#endif dbus_free(context); flash_dev_free(context); lpc_dev_free(context); free_mbox_dev(context); windows_free(context); -#ifdef VIRTUAL_PNOR_ENABLED - destroy_vpnor(context); -#endif + protocol_free(context); free(context); return rc; diff --git a/protocol.c b/protocol.c new file mode 100644 index 0000000..24a830b --- /dev/null +++ b/protocol.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2018 IBM Corp. +#include "config.h" + +#include <errno.h> +#include <stdint.h> + +#include "mbox.h" +#include "lpc.h" +#include "transport_mbox.h" /* TODO: Remove dependency on transport_mbox.h */ +#include "windows.h" + +int protocol_v1_get_info(struct mbox_context *context, + struct protocol_get_info *io) +{ + uint8_t old_version = context->version; + int rc; + + /* Bootstrap protocol version. This may involve {up,down}grading */ + rc = protocol_negotiate_version(context, io->req.api_version); + if (rc < 0) + return rc; + + /* Do the {up,down}grade if necessary*/ + if (rc != old_version) { + windows_reset_all(context, SET_BMC_EVENT); + return context->protocol->get_info(context, io); + } + + /* Record the negotiated version for the response */ + io->resp.api_version = rc; + + /* Now do all required intialisation for v1 */ + context->block_size_shift = BLOCK_SIZE_SHIFT_V1; + MSG_INFO("Block Size: 0x%.8x (shift: %u)\n", + 1 << context->block_size_shift, context->block_size_shift); + + /* Knowing blocksize we can allocate the window dirty_bytemap */ + windows_alloc_dirty_bytemap(context); + + io->resp.v1.read_window_size = + context->windows.default_size >> context->block_size_shift; + io->resp.v1.write_window_size = + context->windows.default_size >> context->block_size_shift; + + return lpc_map_memory(context); +} + +/* + * get_suggested_timeout() - get the suggested timeout value in seconds + * @context: The mbox context pointer + * + * Return: Suggested timeout in seconds + */ +static uint16_t get_suggested_timeout(struct mbox_context *context) +{ + struct window_context *window = windows_find_largest(context); + uint32_t max_size_mb = window ? (window->size >> 20) : 0; + uint16_t ret; + + ret = align_up(max_size_mb * FLASH_ACCESS_MS_PER_MB, 1000) / 1000; + + MSG_DBG("Suggested Timeout: %us, max window size: %uMB, for %dms/MB\n", + ret, max_size_mb, FLASH_ACCESS_MS_PER_MB); + return ret; +} + +int protocol_v2_get_info(struct mbox_context *context, + struct protocol_get_info *io) +{ + uint8_t old_version = context->version; + int rc; + + /* Bootstrap protocol version. This may involve {up,down}grading */ + rc = protocol_negotiate_version(context, io->req.api_version); + if (rc < 0) + return rc; + + /* Do the {up,down}grade if necessary*/ + if (rc != old_version) { + windows_reset_all(context, SET_BMC_EVENT); + return context->protocol->get_info(context, io); + } + + /* Record the negotiated version for the response */ + io->resp.api_version = rc; + + /* Now do all required intialisation for v2 */ + context->block_size_shift = log_2(context->mtd_info.erasesize); + MSG_INFO("Block Size: 0x%.8x (shift: %u)\n", + 1 << context->block_size_shift, context->block_size_shift); + + /* Knowing blocksize we can allocate the window dirty_bytemap */ + windows_alloc_dirty_bytemap(context); + + io->resp.v2.block_size_shift = context->block_size_shift; + io->resp.v2.timeout = get_suggested_timeout(context); + + return lpc_map_memory(context); +} + +static const struct protocol_ops protocol_ops_v1 = { + .get_info = protocol_v1_get_info, +}; + +static const struct protocol_ops protocol_ops_v2 = { + .get_info = protocol_v2_get_info, +}; + +static const struct protocol_ops *protocol_ops_map[] = { + [0] = NULL, + [1] = &protocol_ops_v1, + [2] = &protocol_ops_v2, +}; + +int protocol_negotiate_version(struct mbox_context *context, + uint8_t requested) +{ + /* Check we support the version requested */ + if (requested < API_MIN_VERSION) + return -EINVAL; + + context->version = (requested > API_MAX_VERSION) ? + API_MAX_VERSION : requested; + + context->protocol = protocol_ops_map[context->version]; + + return context->version; +} + +int protocol_init(struct mbox_context *context) +{ + context->version = API_MAX_VERSION; + context->protocol = protocol_ops_map[context->version]; + + return 0; +} + +void protocol_free(struct mbox_context *context) +{ + return; +} diff --git a/protocol.h b/protocol.h new file mode 100644 index 0000000..c147139 --- /dev/null +++ b/protocol.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: Apache-2.0 */ +/* Copyright (C) 2018 IBM Corp. */ + +#ifndef PROTOCOL_H +#define PROTOCOL_H + +struct mbox_context; + +/* + * The GET_MBOX_INFO command is special as it can change the interface based on + * negotiation. As such we need to accommodate all response types + */ +struct protocol_get_info { + struct { + uint8_t api_version; + } req; + struct { + uint8_t api_version; + union { + struct { + uint16_t read_window_size; + uint16_t write_window_size; + } v1; + struct { + uint8_t block_size_shift; + uint16_t timeout; + } v2; + }; + } resp; +}; + +struct protocol_ops { + int (*get_info)(struct mbox_context *context, + struct protocol_get_info *io); +}; + +int protocol_init(struct mbox_context *context); +void protocol_free(struct mbox_context *context); + +int protocol_negotiate_version(struct mbox_context *context, uint8_t requested); + +/* Protocol v1 */ +int protocol_v1_get_info(struct mbox_context *context, + struct protocol_get_info *io); + +/* Protocol v2 */ +int protocol_v2_get_info(struct mbox_context *context, + struct protocol_get_info *io); + +#endif /* PROTOCOL_H */ diff --git a/test/Makefile.am.include b/test/Makefile.am.include index feb1c97..71fa851 100644 --- a/test/Makefile.am.include +++ b/test/Makefile.am.include @@ -24,7 +24,8 @@ TEST_MBOX_SRCS = \ lpc.c \ lpc_reset.c \ common.c \ - flash.c + flash.c \ + protocol.c TEST_MOCK_SRCS = %reldir%/tmpf.c %reldir%/mbox.c %reldir%/system.c diff --git a/test/mbox.c b/test/mbox.c index dbf2526..a622d6e 100644 --- a/test/mbox.c +++ b/test/mbox.c @@ -231,6 +231,9 @@ struct mbox_context *mbox_create_test_context(int n_windows, size_t len) test.context.windows.num = n_windows; test.context.windows.default_size = len; + rc = protocol_init(&test.context); + assert(rc == 0); + /* * We need to call __init_mbox_dev() to initialise the handler table. * However, afterwards we need to discard the fd of the clearly useless diff --git a/transport_mbox.c b/transport_mbox.c index c14ab27..ec6d601 100644 --- a/transport_mbox.c +++ b/transport_mbox.c @@ -30,6 +30,52 @@ #include "windows.h" #include "lpc.h" +struct errno_map { + int rc; + int mbox_errno; +}; + +static const struct errno_map errno_map_v1[] = { + { 0, MBOX_R_SUCCESS }, + { EACCES, MBOX_R_PARAM_ERROR }, + { EBUSY, MBOX_R_SYSTEM_ERROR }, + { EINVAL, MBOX_R_PARAM_ERROR }, + { EPERM, MBOX_R_PARAM_ERROR }, + { ETIMEDOUT, MBOX_R_TIMEOUT }, + { -1, MBOX_R_SYSTEM_ERROR }, +}; + +static const struct errno_map errno_map_v2[] = { + { 0, MBOX_R_SUCCESS }, + { EACCES, MBOX_R_PARAM_ERROR }, + { EBUSY, MBOX_R_BUSY }, + { EINVAL, MBOX_R_PARAM_ERROR }, + { EPERM, MBOX_R_WINDOW_ERROR }, + { ETIMEDOUT, MBOX_R_TIMEOUT }, + { -1, MBOX_R_SYSTEM_ERROR }, +}; + +static const struct errno_map *errno_maps[] = { + [0] = NULL, + [1] = errno_map_v1, + [2] = errno_map_v2, +}; + +static inline int mbox_xlate_errno(struct mbox_context *context, + int rc) +{ + const struct errno_map *entry; + + rc = -rc; + for(entry = errno_maps[context->version]; entry->rc != -1; entry++) { + if (rc == entry->rc) { + return -entry->mbox_errno; + } + } + + return -entry->mbox_errno; +} + /* * write_bmc_event_reg() - Write to the BMC controlled status register (reg 15) * @context: The mbox context pointer @@ -128,25 +174,6 @@ int mbox_handle_reset(struct mbox_context *context, } /* - * get_suggested_timeout() - get the suggested timeout value in seconds - * @context: The mbox context pointer - * - * Return: Suggested timeout in seconds - */ -static uint16_t get_suggested_timeout(struct mbox_context *context) -{ - struct window_context *window = windows_find_largest(context); - uint32_t max_size_mb = window ? (window->size >> 20) : 0; - uint16_t ret; - - ret = align_up(max_size_mb * FLASH_ACCESS_MS_PER_MB, 1000) / 1000; - - MSG_DBG("Suggested Timeout: %us, max window size: %uMB, for %dms/MB\n", - ret, max_size_mb, FLASH_ACCESS_MS_PER_MB); - return ret; -} - -/* * Command: GET_MBOX_INFO * Get the API version, default window size and block size * We also set the LPC mapping to point to the reserved memory region here so @@ -172,65 +199,23 @@ int mbox_handle_mbox_info(struct mbox_context *context, union mbox_regs *req, struct mbox_msg *resp) { uint8_t mbox_api_version = req->msg.args[0]; - uint8_t old_api_version = context->version; + struct protocol_get_info io = { + .req = { .api_version = mbox_api_version } + }; int rc; - /* Check we support the version requested */ - if (mbox_api_version < API_MIN_VERSION) - return -MBOX_R_PARAM_ERROR; - - if (mbox_api_version > API_MAX_VERSION) - mbox_api_version = API_MAX_VERSION; - - context->version = mbox_api_version; - MSG_INFO("Using Protocol Version: %d\n", context->version); - - /* - * The reset state is currently to have the LPC bus point directly to - * flash, since we got a mbox_info command we know the host can talk - * mbox so point the LPC bus mapping to the reserved memory region now - * so the host can access what we put in it. - */ - rc = lpc_map_memory(context); + rc = context->protocol->get_info(context, &io); if (rc < 0) { - return rc; - } - - switch (context->version) { - case API_VERSION_1: - context->block_size_shift = BLOCK_SIZE_SHIFT_V1; - break; - default: - context->block_size_shift = log_2(context->mtd_info.erasesize); - break; - } - MSG_INFO("Block Size: 0x%.8x (shift: %u)\n", - 1 << context->block_size_shift, context->block_size_shift); - - /* Now we know the blocksize we can allocate the window dirty_bytemap */ - if (mbox_api_version != old_api_version) { - windows_alloc_dirty_bytemap(context); - } - /* Reset if we were V1 since this required exact window mapping */ - if (old_api_version == API_VERSION_1) { - /* - * This will only set the BMC event if there was a current - * window -> In which case we are better off notifying the - * host. - */ - windows_reset_all(context, SET_BMC_EVENT); + return mbox_xlate_errno(context, rc); } - resp->args[0] = mbox_api_version; - if (context->version == API_VERSION_1) { - put_u16(&resp->args[1], context->windows.default_size >> - context->block_size_shift); - put_u16(&resp->args[3], context->windows.default_size >> - context->block_size_shift); - } - if (context->version >= API_VERSION_2) { - resp->args[5] = context->block_size_shift; - put_u16(&resp->args[6], get_suggested_timeout(context)); + resp->args[0] = io.resp.api_version; + if (io.resp.api_version == API_VERSION_1) { + put_u16(&resp->args[1], io.resp.v1.read_window_size); + put_u16(&resp->args[3], io.resp.v1.write_window_size); + } else if (io.resp.api_version >= API_VERSION_2) { + resp->args[5] = io.resp.v2.block_size_shift; + put_u16(&resp->args[6], io.resp.v2.timeout); } return 0; diff --git a/vpnor/test/Makefile.am.include b/vpnor/test/Makefile.am.include index 91666fd..2444606 100644 --- a/vpnor/test/Makefile.am.include +++ b/vpnor/test/Makefile.am.include @@ -5,6 +5,7 @@ TEST_MBOX_VPNOR_SRCS = \ TEST_MBOX_VPNOR_INTEG_SRCS = \ common.c \ + protocol.c \ transport_mbox.c \ windows.c \ lpc.c \ |