summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Jeffery <andrew@aj.id.au>2018-08-07 13:32:57 +0930
committerAndrew Jeffery <andrew@aj.id.au>2018-09-12 15:05:51 +0930
commit1e531afd1698c5613004e2bf4e73bda4364fa6d6 (patch)
tree9949340bcc068f8016c45c1422f79793952eab5d
parent457a6e5fa6a7dad50673222b09b2c7fec2ef0a97 (diff)
downloadphosphor-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.am1
-rw-r--r--lpc.c2
-rw-r--r--mbox.h6
-rw-r--r--mboxd.c12
-rw-r--r--protocol.c142
-rw-r--r--protocol.h50
-rw-r--r--test/Makefile.am.include3
-rw-r--r--test/mbox.c3
-rw-r--r--transport_mbox.c131
-rw-r--r--vpnor/test/Makefile.am.include1
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
diff --git a/lpc.c b/lpc.c
index 2c8b00d..4b9d384 100644
--- a/lpc.c
+++ b/lpc.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) */
diff --git a/mbox.h b/mbox.h
index 19d0a3f..3676825 100644
--- a/mbox.h
+++ b/mbox.h
@@ -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;
diff --git a/mboxd.c b/mboxd.c
index 5ed42d6..2382724 100644
--- a/mboxd.c
+++ b/mboxd.c
@@ -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 \
OpenPOWER on IntegriCloud