mboxd: Add a backend abstraction layer to mboxd.

Introduce a backend abstraction, enabling multiple implementations to be
compiled in at once. This change formally abstracts the two existing
backends, mtd and vpnor.

With the backend abstraction in place, subsequent backends are easier to
implement.

This change is based of Evan's work and he retains authorship credit. I
(AJ) have reworked the patch to pass the vpnor tests, refactored some
parts to enable broader use of const structures and others to clarify
the initialisation sequences.

Due to the existing lack of abstraction the patch has unfortunately
wide-ranging impacts. I've whittled it down as much as I consider
reasonable.

Change-Id: I29984a36dae4ea86ec00b853d2a756f0b9afb3ec
Signed-off-by: Evan Lojewski <github@meklort.com>
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/protocol.c b/protocol.c
index 76bc6ea..7158bfc 100644
--- a/protocol.c
+++ b/protocol.c
@@ -4,9 +4,10 @@
 
 #include <errno.h>
 #include <stdint.h>
+#include <stdio.h>
 
+#include "backend.h"
 #include "common.h"
-#include "flash.h"
 #include "lpc.h"
 #include "mboxd.h"
 #include "protocol.h"
@@ -77,11 +78,12 @@
 	return context->transport->clear_events(context, bmc_event, mask);
 }
 
+static int protocol_negotiate_version(struct mbox_context *context,
+				      uint8_t requested);
+
 static int protocol_v1_reset(struct mbox_context *context)
 {
-	/* Host requested it -> No BMC Event */
-	windows_reset_all(context);
-	return lpc_reset(context);
+	return __protocol_reset(context);
 }
 
 static int protocol_negotiate_version(struct mbox_context *context,
@@ -109,26 +111,26 @@
 	io->resp.api_version = rc;
 
 	/* Now do all required intialisation for v1 */
-	context->block_size_shift = BLOCK_SIZE_SHIFT_V1;
+	context->backend.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);
+		 1 << context->backend.block_size_shift, context->backend.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;
+		context->windows.default_size >> context->backend.block_size_shift;
 	io->resp.v1.write_window_size =
-		context->windows.default_size >> context->block_size_shift;
+		context->windows.default_size >> context->backend.block_size_shift;
 
 	return lpc_map_memory(context);
 }
 
 static int protocol_v1_get_flash_info(struct mbox_context *context,
-			       struct protocol_get_flash_info *io)
+				      struct protocol_get_flash_info *io)
 {
-	io->resp.v1.flash_size = context->flash_size;
-	io->resp.v1.erase_size = context->mtd_info.erasesize;
+	io->resp.v1.flash_size = context->backend.flash_size;
+	io->resp.v1.erase_size = 1 << context->backend.erase_size_shift;
 
 	return 0;
 }
@@ -150,17 +152,20 @@
 
 	MSG_DBG("LPC address of current window: 0x%.8x\n", lpc_addr);
 
-	return lpc_addr >> context->block_size_shift;
+	return lpc_addr >> context->backend.block_size_shift;
 }
 
 static int protocol_v1_create_window(struct mbox_context *context,
 				     struct protocol_create_window *io)
 {
-	uint32_t offset = io->req.offset << context->block_size_shift;
-	uint32_t size = io->req.size << context->block_size_shift;
+	struct backend *backend = &context->backend;
+	uint32_t offset;
+	uint32_t size;
 	int rc;
 
-	rc = flash_validate(context, offset, size, io->req.ro);
+	offset = io->req.offset << backend->block_size_shift;
+	size = io->req.size << backend->block_size_shift;
+	rc = backend_validate(backend, offset, size, io->req.ro);
 	if (rc < 0) {
 		/* Backend does not allow window to be created. */
 		return rc;
@@ -227,11 +232,11 @@
 
 	/* For V1 offset given relative to flash - we want the window */
 	off = offset - ((context->current->flash_offset) >>
-			context->block_size_shift);
+			context->backend.block_size_shift);
 	if (off > offset) { /* Underflow - before current window */
 		MSG_ERR("Tried to mark dirty before start of window\n");
 		MSG_ERR("requested offset: 0x%x window start: 0x%x\n",
-				offset << context->block_size_shift,
+				offset << context->backend.block_size_shift,
 				context->current->flash_offset);
 		return -EINVAL;
 	}
@@ -241,12 +246,12 @@
 	 * For protocol V1 we can get away with just marking the whole
 	 * block dirty.
 	 */
-	size = align_up(size, 1 << context->block_size_shift);
-	size >>= context->block_size_shift;
+	size = align_up(size, 1 << context->backend.block_size_shift);
+	size >>= context->backend.block_size_shift;
 
 	MSG_INFO("Dirty window @ 0x%.8x for 0x%.8x\n",
-		 offset << context->block_size_shift,
-		 size << context->block_size_shift);
+		 offset << context->backend.block_size_shift,
+		 size << context->backend.block_size_shift);
 
 	return window_set_bytemap(context, context->current, offset, size,
 				  WINDOW_DIRTY);
@@ -270,7 +275,7 @@
 	 * (dirty/erased) changes we perform the required action on the backing
 	 * store and update the current streak-type
 	 */
-	for (i = 0; i < (context->current->size >> context->block_size_shift);
+	for (i = 0; i < (context->current->size >> context->backend.block_size_shift);
 			i++) {
 		uint8_t cur = context->current->dirty_bmap[i];
 		if (cur != WINDOW_CLEAN) {
@@ -312,7 +317,7 @@
 	/* Clear the dirty bytemap since we have written back all changes */
 	return window_set_bytemap(context, context->current, 0,
 				  context->current->size >>
-				  context->block_size_shift,
+				  context->backend.block_size_shift,
 				  WINDOW_CLEAN);
 }
 
@@ -416,14 +421,14 @@
 	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.block_size_shift = context->backend.block_size_shift;
+	MSG_INFO("Block Size: 0x%.8x (shift: %u)\n",
+		 1 << context->backend.block_size_shift, context->backend.block_size_shift);
+
 	io->resp.v2.timeout = get_suggested_timeout(context);
 
 	return lpc_map_memory(context);
@@ -432,10 +437,12 @@
 static int protocol_v2_get_flash_info(struct mbox_context *context,
 				      struct protocol_get_flash_info *io)
 {
+	struct backend *backend = &context->backend;
+
 	io->resp.v2.flash_size =
-		context->flash_size >> context->block_size_shift;
+		backend->flash_size >> backend->block_size_shift;
 	io->resp.v2.erase_size =
-		context->mtd_info.erasesize >> context->block_size_shift;
+		((1 << backend->erase_size_shift) >> backend->block_size_shift);
 
 	return 0;
 }
@@ -449,9 +456,9 @@
 	if (rc < 0)
 		return rc;
 
-	io->resp.size = context->current->size >> context->block_size_shift;
+	io->resp.size = context->current->size >> context->backend.block_size_shift;
 	io->resp.offset = context->current->flash_offset >>
-					context->block_size_shift;
+					context->backend.block_size_shift;
 
 	return 0;
 }
@@ -465,8 +472,8 @@
 	}
 
 	MSG_INFO("Dirty window @ 0x%.8x for 0x%.8x\n",
-		 io->req.v2.offset << context->block_size_shift,
-		 io->req.v2.size << context->block_size_shift);
+		 io->req.v2.offset << context->backend.block_size_shift,
+		 io->req.v2.size << context->backend.block_size_shift);
 
 	return window_set_bytemap(context, context->current, io->req.v2.offset,
 				  io->req.v2.size, WINDOW_DIRTY);
@@ -484,8 +491,8 @@
 	}
 
 	MSG_INFO("Erase window @ 0x%.8x for 0x%.8x\n",
-		 io->req.offset << context->block_size_shift,
-		 io->req.size << context->block_size_shift);
+		 io->req.offset << context->backend.block_size_shift,
+		 io->req.size << context->backend.block_size_shift);
 
 	rc = window_set_bytemap(context, context->current, io->req.offset,
 				io->req.size, WINDOW_ERASED);
@@ -494,8 +501,8 @@
 	}
 
 	/* Write 0xFF to mem -> This ensures consistency between flash & ram */
-	start = io->req.offset << context->block_size_shift;
-	len = io->req.size << context->block_size_shift;
+	start = io->req.offset << context->backend.block_size_shift;
+	len = io->req.size << context->backend.block_size_shift;
 	memset(context->current->mem + start, 0xFF, len);
 
 	return 0;
@@ -597,9 +604,24 @@
 /* Don't do any state manipulation, just perform the reset */
 int __protocol_reset(struct mbox_context *context)
 {
+	enum backend_reset_mode mode;
+	int rc;
+
 	windows_reset_all(context);
 
-	return lpc_reset(context);
+	rc = backend_reset(&context->backend, context->mem, context->mem_size);
+	if (rc < 0)
+		return rc;
+
+	mode = rc;
+	if (!(mode == reset_lpc_flash || mode == reset_lpc_memory))
+		return -EINVAL;
+
+	if (mode == reset_lpc_flash)
+		return lpc_map_flash(context);
+
+	assert(mode == reset_lpc_memory);
+	return lpc_map_memory(context);
 }
 
 /* Prevent the host from performing actions whilst reset takes place */