protocol: Add flush

Change-Id: Ic5be69f534c9ff277cc3f7e5a85a0eae5bc41716
Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
diff --git a/protocol.c b/protocol.c
index 88e91b2..6622cd4 100644
--- a/protocol.c
+++ b/protocol.c
@@ -169,6 +169,93 @@
 				  WINDOW_DIRTY);
 }
 
+static int generic_flush(struct mbox_context *context)
+{
+	int rc, i, offset, count;
+	uint8_t prev;
+
+	offset = 0;
+	count = 0;
+	prev = WINDOW_CLEAN;
+
+	MSG_INFO("Flush window @ %p for size 0x%.8x which maps flash @ 0x%.8x\n",
+		 context->current->mem, context->current->size,
+		 context->current->flash_offset);
+
+	/*
+	 * We look for streaks of the same type and keep a count, when the type
+	 * (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);
+			i++) {
+		uint8_t cur = context->current->dirty_bmap[i];
+		if (cur != WINDOW_CLEAN) {
+			if (cur == prev) { /* Same as previous block, incrmnt */
+				count++;
+			} else if (prev == WINDOW_CLEAN) { /* Start of run */
+				offset = i;
+				count++;
+			} else { /* Change in streak type */
+				rc = window_flush(context, offset, count,
+						       prev);
+				if (rc < 0) {
+					return rc;
+				}
+				offset = i;
+				count = 1;
+			}
+		} else {
+			if (prev != WINDOW_CLEAN) { /* End of a streak */
+				rc = window_flush(context, offset, count,
+						       prev);
+				if (rc < 0) {
+					return rc;
+				}
+				offset = 0;
+				count = 0;
+			}
+		}
+		prev = cur;
+	}
+
+	if (prev != WINDOW_CLEAN) { /* Still the last streak to write */
+		rc = window_flush(context, offset, count, prev);
+		if (rc < 0) {
+			return rc;
+		}
+	}
+
+	/* 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,
+				  WINDOW_CLEAN);
+}
+
+int protocol_v1_flush(struct mbox_context *context, struct protocol_flush *io)
+{
+	int rc;
+
+	if (!(context->current && context->current_is_write)) {
+		MSG_ERR("Tried to call flush without open write window\n");
+		return -EPERM;
+	}
+
+	/*
+	 * For V1 the Flush command acts much the same as the dirty command
+	 * except with a flush as well. Only do this on an actual flush
+	 * command not when we call flush because we've implicitly closed a
+	 * window because we might not have the required args in req.
+	 */
+	rc = protocol_v1_mark_dirty(context, (struct protocol_mark_dirty *)io);
+	if (rc < 0) {
+		return rc;
+	}
+
+	return generic_flush(context);
+}
+
 /*
  * get_suggested_timeout() - get the suggested timeout value in seconds
  * @context:	The mbox context pointer
@@ -294,6 +381,16 @@
 	return 0;
 }
 
+int protocol_v2_flush(struct mbox_context *context, struct protocol_flush *io)
+{
+	if (!(context->current && context->current_is_write)) {
+		MSG_ERR("Tried to call flush without open write window\n");
+		return -EPERM;
+	}
+
+	return generic_flush(context);
+}
+
 static const struct protocol_ops protocol_ops_v1 = {
 	.reset = protocol_v1_reset,
 	.get_info = protocol_v1_get_info,
@@ -301,6 +398,7 @@
 	.create_window = protocol_v1_create_window,
 	.mark_dirty = protocol_v1_mark_dirty,
 	.erase = NULL,
+	.flush = protocol_v1_flush,
 };
 
 static const struct protocol_ops protocol_ops_v2 = {
@@ -310,6 +408,7 @@
 	.create_window = protocol_v2_create_window,
 	.mark_dirty = protocol_v2_mark_dirty,
 	.erase = protocol_v2_erase,
+	.flush = protocol_v2_flush,
 };
 
 static const struct protocol_ops *protocol_ops_map[] = {
diff --git a/protocol.h b/protocol.h
index 9b652ef..c22f94b 100644
--- a/protocol.h
+++ b/protocol.h
@@ -80,6 +80,12 @@
 	} req;
 };
 
+struct protocol_flush {
+	struct {
+		uint16_t offset;
+		uint32_t size;
+	} req;
+};
 
 struct protocol_ops {
 	int (*reset)(struct mbox_context *context);
@@ -92,6 +98,7 @@
 	int (*mark_dirty)(struct mbox_context *context,
 			  struct protocol_mark_dirty *io);
 	int (*erase)(struct mbox_context *context, struct protocol_erase *io);
+	int (*flush)(struct mbox_context *context, struct protocol_flush *io);
 };
 
 int protocol_init(struct mbox_context *context);
@@ -109,6 +116,7 @@
 			      struct protocol_create_window *io);
 int protocol_v1_mark_dirty(struct mbox_context *context,
 			   struct protocol_mark_dirty *io);
+int protocol_v1_flush(struct mbox_context *context, struct protocol_flush *io);
 
 /* Protocol v2 */
 int protocol_v2_get_info(struct mbox_context *context,
@@ -121,5 +129,6 @@
 			   struct protocol_mark_dirty *io);
 int protocol_v2_erase(struct mbox_context *context,
 		      struct protocol_erase *io);
+int protocol_v2_flush(struct mbox_context *context, struct protocol_flush *io);
 
 #endif /* PROTOCOL_H */
diff --git a/transport_mbox.c b/transport_mbox.c
index 92b3609..825fed7 100644
--- a/transport_mbox.c
+++ b/transport_mbox.c
@@ -461,89 +461,17 @@
 int mbox_handle_flush_window(struct mbox_context *context,
 				    union mbox_regs *req, struct mbox_msg *resp)
 {
-	int rc, i, offset, count;
-	uint8_t prev;
+	struct protocol_flush io = { 0 };
+	int rc;
 
-	if (!(context->current && context->current_is_write)) {
-		MSG_ERR("Tried to call flush without open write window\n");
-		return context->version >= API_VERSION_2 ? -MBOX_R_WINDOW_ERROR
-							 : -MBOX_R_PARAM_ERROR;
+	if (context->version == API_VERSION_1) {
+		io.req.offset = get_u16(&req->msg.args[0]);
+		io.req.size = get_u32(&req->msg.args[2]);
 	}
 
-	/*
-	 * For V1 the Flush command acts much the same as the dirty command
-	 * except with a flush as well. Only do this on an actual flush
-	 * command not when we call flush because we've implicitly closed a
-	 * window because we might not have the required args in req.
-	 */
-	if (context->version == API_VERSION_1 && req &&
-			req->msg.command == MBOX_C_WRITE_FLUSH) {
-		rc = mbox_handle_dirty_window(context, req, NULL);
-		if (rc < 0) {
-			return rc;
-		}
-	}
-
-	offset = 0;
-	count = 0;
-	prev = WINDOW_CLEAN;
-
-	MSG_INFO("Flush window @ %p for size 0x%.8x which maps flash @ 0x%.8x\n",
-		 context->current->mem, context->current->size,
-		 context->current->flash_offset);
-
-	/*
-	 * We look for streaks of the same type and keep a count, when the type
-	 * (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);
-			i++) {
-		uint8_t cur = context->current->dirty_bmap[i];
-		if (cur != WINDOW_CLEAN) {
-			if (cur == prev) { /* Same as previous block, incrmnt */
-				count++;
-			} else if (prev == WINDOW_CLEAN) { /* Start of run */
-				offset = i;
-				count++;
-			} else { /* Change in streak type */
-				rc = window_flush(context, offset, count,
-						       prev);
-				if (rc < 0) {
-					return rc;
-				}
-				offset = i;
-				count = 1;
-			}
-		} else {
-			if (prev != WINDOW_CLEAN) { /* End of a streak */
-				rc = window_flush(context, offset, count,
-						       prev);
-				if (rc < 0) {
-					return rc;
-				}
-				offset = 0;
-				count = 0;
-			}
-		}
-		prev = cur;
-	}
-
-	if (prev != WINDOW_CLEAN) { /* Still the last streak to write */
-		rc = window_flush(context, offset, count, prev);
-		if (rc < 0) {
-			return rc;
-		}
-	}
-
-	/* Clear the dirty bytemap since we have written back all changes */
-	rc = window_set_bytemap(context, context->current, 0,
-				  context->current->size >>
-				  context->block_size_shift,
-				  WINDOW_CLEAN);
+	rc = context->protocol->flush(context, &io);
 	if (rc < 0) {
-		return (rc == -EACCES) ? -MBOX_R_PARAM_ERROR
-				       : -MBOX_R_SYSTEM_ERROR;
+		return mbox_xlate_errno(context, rc);
 	}
 
 	return rc;