xref: /openbmc/hiomapd/protocol.c (revision 68a24c9ea5ce11c87fab22a3f4648c7d88c98fee)
11e531afdSAndrew Jeffery // SPDX-License-Identifier: Apache-2.0
21e531afdSAndrew Jeffery // Copyright (C) 2018 IBM Corp.
31e531afdSAndrew Jeffery #include "config.h"
41e531afdSAndrew Jeffery 
51e531afdSAndrew Jeffery #include <errno.h>
61e531afdSAndrew Jeffery #include <stdint.h>
7f1e547c7SEvan Lojewski #include <stdio.h>
8ef0c8360SStewart Smith #include <unistd.h>
91e531afdSAndrew Jeffery 
10f1e547c7SEvan Lojewski #include "backend.h"
115335f093SAndrew Jeffery #include "common.h"
121e531afdSAndrew Jeffery #include "lpc.h"
13cb93504eSAndrew Jeffery #include "mboxd.h"
14cb93504eSAndrew Jeffery #include "protocol.h"
151e531afdSAndrew Jeffery #include "windows.h"
161e531afdSAndrew Jeffery 
17*68a24c9eSPatrick Williams #pragma GCC diagnostic push
18*68a24c9eSPatrick Williams #pragma GCC diagnostic ignored "-Wpointer-arith"
19*68a24c9eSPatrick Williams #pragma GCC diagnostic ignored "-Wunused-result"
20ef0c8360SStewart Smith 
2126558dbbSAndrew Jeffery #define BLOCK_SIZE_SHIFT_V1		12 /* 4K */
2226558dbbSAndrew Jeffery 
protocol_get_bmc_event_mask(struct mbox_context * context)230453aa4cSAndrew Jeffery static inline uint8_t protocol_get_bmc_event_mask(struct mbox_context *context)
240453aa4cSAndrew Jeffery {
250453aa4cSAndrew Jeffery 	if (context->version == API_VERSION_1) {
260453aa4cSAndrew Jeffery 		return BMC_EVENT_V1_MASK;
270453aa4cSAndrew Jeffery 	}
280453aa4cSAndrew Jeffery 
290453aa4cSAndrew Jeffery 	return BMC_EVENT_V2_MASK;
300453aa4cSAndrew Jeffery }
310453aa4cSAndrew Jeffery 
325335f093SAndrew Jeffery /*
33fe0c9e86SAndrew Jeffery  * protocol_events_put() - Push the full set/cleared state of BMC events on the
34fe0c9e86SAndrew Jeffery  * 			   provided transport
35fe0c9e86SAndrew Jeffery  * @context:    The mbox context pointer
36fe0c9e86SAndrew Jeffery  * @ops:	The operations struct for the transport of interest
37fe0c9e86SAndrew Jeffery  *
38fe0c9e86SAndrew Jeffery  * Return:      0 on success otherwise negative error code
39fe0c9e86SAndrew Jeffery  */
protocol_events_put(struct mbox_context * context,const struct transport_ops * ops)40fe0c9e86SAndrew Jeffery int protocol_events_put(struct mbox_context *context,
41fe0c9e86SAndrew Jeffery 			const struct transport_ops *ops)
42fe0c9e86SAndrew Jeffery {
43fe0c9e86SAndrew Jeffery 	const uint8_t mask = protocol_get_bmc_event_mask(context);
44fe0c9e86SAndrew Jeffery 
45fe0c9e86SAndrew Jeffery 	return ops->put_events(context, mask);
46fe0c9e86SAndrew Jeffery }
47fe0c9e86SAndrew Jeffery 
48fe0c9e86SAndrew Jeffery /*
49fe0c9e86SAndrew Jeffery  * protocol_events_set() - Update the set BMC events on the active transport
505335f093SAndrew Jeffery  * @context:	The mbox context pointer
515335f093SAndrew Jeffery  * @bmc_event:	The bits to set
525335f093SAndrew Jeffery  *
535335f093SAndrew Jeffery  * Return:	0 on success otherwise negative error code
545335f093SAndrew Jeffery  */
protocol_events_set(struct mbox_context * context,uint8_t bmc_event)552ebfd20fSAndrew Jeffery int protocol_events_set(struct mbox_context *context, uint8_t bmc_event)
565335f093SAndrew Jeffery {
570453aa4cSAndrew Jeffery 	const uint8_t mask = protocol_get_bmc_event_mask(context);
585335f093SAndrew Jeffery 
590453aa4cSAndrew Jeffery 	/*
600453aa4cSAndrew Jeffery 	 * Store the raw value, as we may up- or down- grade the protocol
610453aa4cSAndrew Jeffery 	 * version and subsequently need to flush the appropriate set. Instead
620453aa4cSAndrew Jeffery 	 * we pass the masked value through to the transport
630453aa4cSAndrew Jeffery 	 */
640453aa4cSAndrew Jeffery 	context->bmc_events |= bmc_event;
655335f093SAndrew Jeffery 
66f62601b8SAndrew Jeffery 	return context->transport->set_events(context, bmc_event, mask);
675335f093SAndrew Jeffery }
685335f093SAndrew Jeffery 
695335f093SAndrew Jeffery /*
70fe0c9e86SAndrew Jeffery  * protocol_events_clear() - Update the cleared BMC events on the active
71fe0c9e86SAndrew Jeffery  *                           transport
725335f093SAndrew Jeffery  * @context:	The mbox context pointer
735335f093SAndrew Jeffery  * @bmc_event:	The bits to clear
745335f093SAndrew Jeffery  *
755335f093SAndrew Jeffery  * Return:	0 on success otherwise negative error code
765335f093SAndrew Jeffery  */
protocol_events_clear(struct mbox_context * context,uint8_t bmc_event)772ebfd20fSAndrew Jeffery int protocol_events_clear(struct mbox_context *context, uint8_t bmc_event)
785335f093SAndrew Jeffery {
790453aa4cSAndrew Jeffery 	const uint8_t mask = protocol_get_bmc_event_mask(context);
800453aa4cSAndrew Jeffery 
810453aa4cSAndrew Jeffery 	context->bmc_events &= ~bmc_event;
820453aa4cSAndrew Jeffery 
83f62601b8SAndrew Jeffery 	return context->transport->clear_events(context, bmc_event, mask);
845335f093SAndrew Jeffery }
855335f093SAndrew Jeffery 
86f1e547c7SEvan Lojewski static int protocol_negotiate_version(struct mbox_context *context,
87f1e547c7SEvan Lojewski 				      uint8_t requested);
88f1e547c7SEvan Lojewski 
protocol_v1_reset(struct mbox_context * context)89cb93504eSAndrew Jeffery static int protocol_v1_reset(struct mbox_context *context)
90ab666a57SAndrew Jeffery {
91f1e547c7SEvan Lojewski 	return __protocol_reset(context);
92ab666a57SAndrew Jeffery }
93ab666a57SAndrew Jeffery 
94cb93504eSAndrew Jeffery static int protocol_negotiate_version(struct mbox_context *context,
95cb93504eSAndrew Jeffery 				      uint8_t requested);
96cb93504eSAndrew Jeffery 
protocol_v1_get_info(struct mbox_context * context,struct protocol_get_info * io)97cb93504eSAndrew Jeffery static int protocol_v1_get_info(struct mbox_context *context,
981e531afdSAndrew Jeffery 				struct protocol_get_info *io)
991e531afdSAndrew Jeffery {
1001e531afdSAndrew Jeffery 	uint8_t old_version = context->version;
1011e531afdSAndrew Jeffery 	int rc;
1021e531afdSAndrew Jeffery 
1031e531afdSAndrew Jeffery 	/* Bootstrap protocol version. This may involve {up,down}grading */
1041e531afdSAndrew Jeffery 	rc = protocol_negotiate_version(context, io->req.api_version);
1051e531afdSAndrew Jeffery 	if (rc < 0)
1061e531afdSAndrew Jeffery 		return rc;
1071e531afdSAndrew Jeffery 
1081e531afdSAndrew Jeffery 	/* Do the {up,down}grade if necessary*/
1091e531afdSAndrew Jeffery 	if (rc != old_version) {
1102ebfd20fSAndrew Jeffery 		/* Doing version negotiation, don't alert host to reset */
1112ebfd20fSAndrew Jeffery 		windows_reset_all(context);
1121e531afdSAndrew Jeffery 		return context->protocol->get_info(context, io);
1131e531afdSAndrew Jeffery 	}
1141e531afdSAndrew Jeffery 
1151e531afdSAndrew Jeffery 	/* Record the negotiated version for the response */
1161e531afdSAndrew Jeffery 	io->resp.api_version = rc;
1171e531afdSAndrew Jeffery 
1181e531afdSAndrew Jeffery 	/* Now do all required intialisation for v1 */
119f1e547c7SEvan Lojewski 	context->backend.block_size_shift = BLOCK_SIZE_SHIFT_V1;
1201e531afdSAndrew Jeffery 	MSG_INFO("Block Size: 0x%.8x (shift: %u)\n",
121f1e547c7SEvan Lojewski 		 1 << context->backend.block_size_shift, context->backend.block_size_shift);
1221e531afdSAndrew Jeffery 
1231e531afdSAndrew Jeffery 	/* Knowing blocksize we can allocate the window dirty_bytemap */
1241e531afdSAndrew Jeffery 	windows_alloc_dirty_bytemap(context);
1251e531afdSAndrew Jeffery 
1261e531afdSAndrew Jeffery 	io->resp.v1.read_window_size =
127f1e547c7SEvan Lojewski 		context->windows.default_size >> context->backend.block_size_shift;
1281e531afdSAndrew Jeffery 	io->resp.v1.write_window_size =
129f1e547c7SEvan Lojewski 		context->windows.default_size >> context->backend.block_size_shift;
1301e531afdSAndrew Jeffery 
1311e531afdSAndrew Jeffery 	return lpc_map_memory(context);
1321e531afdSAndrew Jeffery }
1331e531afdSAndrew Jeffery 
protocol_v1_get_flash_info(struct mbox_context * context,struct protocol_get_flash_info * io)134cb93504eSAndrew Jeffery static int protocol_v1_get_flash_info(struct mbox_context *context,
13591a87454SAndrew Jeffery 				      struct protocol_get_flash_info *io)
13691a87454SAndrew Jeffery {
137f1e547c7SEvan Lojewski 	io->resp.v1.flash_size = context->backend.flash_size;
138f1e547c7SEvan Lojewski 	io->resp.v1.erase_size = 1 << context->backend.erase_size_shift;
13991a87454SAndrew Jeffery 
14091a87454SAndrew Jeffery 	return 0;
14191a87454SAndrew Jeffery }
14291a87454SAndrew Jeffery 
1431e531afdSAndrew Jeffery /*
14422fa5009SAndrew Jeffery  * get_lpc_addr_shifted() - Get lpc address of the current window
14522fa5009SAndrew Jeffery  * @context:		The mbox context pointer
14622fa5009SAndrew Jeffery  *
14722fa5009SAndrew Jeffery  * Return:	The lpc address to access that offset shifted by block size
14822fa5009SAndrew Jeffery  */
get_lpc_addr_shifted(struct mbox_context * context)14922fa5009SAndrew Jeffery static inline uint16_t get_lpc_addr_shifted(struct mbox_context *context)
15022fa5009SAndrew Jeffery {
15122fa5009SAndrew Jeffery 	uint32_t lpc_addr, mem_offset;
15222fa5009SAndrew Jeffery 
15322fa5009SAndrew Jeffery 	/* Offset of the current window in the reserved memory region */
15422fa5009SAndrew Jeffery 	mem_offset = context->current->mem - context->mem;
15522fa5009SAndrew Jeffery 	/* Total LPC Address */
15622fa5009SAndrew Jeffery 	lpc_addr = context->lpc_base + mem_offset;
15722fa5009SAndrew Jeffery 
15822fa5009SAndrew Jeffery 	MSG_DBG("LPC address of current window: 0x%.8x\n", lpc_addr);
15922fa5009SAndrew Jeffery 
160f1e547c7SEvan Lojewski 	return lpc_addr >> context->backend.block_size_shift;
16122fa5009SAndrew Jeffery }
16222fa5009SAndrew Jeffery 
blktrace_gettime(void)163ef0c8360SStewart Smith static inline int64_t blktrace_gettime(void)
164ef0c8360SStewart Smith {
165ef0c8360SStewart Smith 	struct timespec ts;
166ef0c8360SStewart Smith 	int64_t n;
167ef0c8360SStewart Smith 
168ef0c8360SStewart Smith 	clock_gettime(CLOCK_REALTIME, &ts);
169ef0c8360SStewart Smith 	n = (int64_t)(ts.tv_sec) * (int64_t)1000000000 + (int64_t)(ts.tv_nsec);
170ef0c8360SStewart Smith 
171ef0c8360SStewart Smith 	return n;
172ef0c8360SStewart Smith }
173ef0c8360SStewart Smith 
blktrace_flush_start(struct mbox_context * context)174ef0c8360SStewart Smith static void blktrace_flush_start(struct mbox_context *context)
175ef0c8360SStewart Smith {
176ef0c8360SStewart Smith 	struct blk_io_trace *trace = &context->trace;
177ef0c8360SStewart Smith 	struct timespec now;
178ef0c8360SStewart Smith 
179ef0c8360SStewart Smith 	if (!context->blktracefd)
180ef0c8360SStewart Smith 		return;
181ef0c8360SStewart Smith 
182ef0c8360SStewart Smith 	if (!context->blktrace_start) {
183ef0c8360SStewart Smith 		clock_gettime(CLOCK_REALTIME, &now);
184ef0c8360SStewart Smith 		context->blktrace_start = blktrace_gettime();
185ef0c8360SStewart Smith 	}
186ef0c8360SStewart Smith 
187ef0c8360SStewart Smith 	trace->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION;
188ef0c8360SStewart Smith 	trace->sequence++;
189ef0c8360SStewart Smith 	trace->time = blktrace_gettime() - context->blktrace_start;
190ef0c8360SStewart Smith 	trace->sector = context->current->flash_offset / 512;
191ef0c8360SStewart Smith 	trace->bytes = context->current->size;
192ef0c8360SStewart Smith 	if (context->current_is_write)
193ef0c8360SStewart Smith 		trace->action = BLK_TA_QUEUE | BLK_TC_ACT(BLK_TC_WRITE);
194ef0c8360SStewart Smith 	else
195ef0c8360SStewart Smith 		trace->action = BLK_TA_QUEUE | BLK_TC_ACT(BLK_TC_READ);
196ef0c8360SStewart Smith 	trace->pid = 0;
197ef0c8360SStewart Smith 	trace->device = 0;
198ef0c8360SStewart Smith 	trace->cpu = 0;
199ef0c8360SStewart Smith 	trace->error = 0;
200ef0c8360SStewart Smith 	trace->pdu_len = 0;
201ef0c8360SStewart Smith 	write(context->blktracefd, trace, sizeof(*trace));
202ef0c8360SStewart Smith 	trace->sequence++;
203ef0c8360SStewart Smith 	trace->time = blktrace_gettime() - context->blktrace_start;
204ef0c8360SStewart Smith 	trace->action &= ~BLK_TA_QUEUE;
205ef0c8360SStewart Smith 	trace->action |= BLK_TA_ISSUE;
206ef0c8360SStewart Smith 	write(context->blktracefd, trace, sizeof(*trace));
207ef0c8360SStewart Smith }
208ef0c8360SStewart Smith 
blktrace_flush_done(struct mbox_context * context)209ef0c8360SStewart Smith static void blktrace_flush_done(struct mbox_context *context)
210ef0c8360SStewart Smith {
211ef0c8360SStewart Smith 	struct blk_io_trace *trace = &context->trace;
212ef0c8360SStewart Smith 
213ef0c8360SStewart Smith 	if (!context->blktracefd)
214ef0c8360SStewart Smith 		return;
215ef0c8360SStewart Smith 
216ef0c8360SStewart Smith 	trace->sequence++;
217ef0c8360SStewart Smith 	trace->time = blktrace_gettime() - context->blktrace_start;
218ef0c8360SStewart Smith 	trace->action &= ~BLK_TA_ISSUE;
219ef0c8360SStewart Smith 	trace->action |= BLK_TA_COMPLETE;
220ef0c8360SStewart Smith 	write(context->blktracefd, trace, sizeof(*trace));
221ef0c8360SStewart Smith }
222ef0c8360SStewart Smith 
blktrace_window_start(struct mbox_context * context)223ef0c8360SStewart Smith static void blktrace_window_start(struct mbox_context *context)
224ef0c8360SStewart Smith {
225ef0c8360SStewart Smith 	struct blk_io_trace *trace = &context->trace;
226ef0c8360SStewart Smith 
227ef0c8360SStewart Smith 	if (!context->blktracefd)
228ef0c8360SStewart Smith 		return;
229ef0c8360SStewart Smith 
230ef0c8360SStewart Smith 	if (!context->blktrace_start)
231ef0c8360SStewart Smith 		context->blktrace_start = blktrace_gettime();
232ef0c8360SStewart Smith 
233ef0c8360SStewart Smith 	trace->magic = BLK_IO_TRACE_MAGIC | BLK_IO_TRACE_VERSION;
234ef0c8360SStewart Smith 	trace->sequence++;
235ef0c8360SStewart Smith 	trace->time = blktrace_gettime() - context->blktrace_start;
236ef0c8360SStewart Smith 	trace->action = BLK_TA_QUEUE | BLK_TC_ACT(BLK_TC_READ);
237ef0c8360SStewart Smith 	trace->pid = 0;
238ef0c8360SStewart Smith 	trace->device = 0;
239ef0c8360SStewart Smith 	trace->cpu = 0;
240ef0c8360SStewart Smith 	trace->error = 0;
241ef0c8360SStewart Smith 	trace->pdu_len = 0;
242ef0c8360SStewart Smith }
243ef0c8360SStewart Smith 
blktrace_window_done(struct mbox_context * context)244ef0c8360SStewart Smith static void blktrace_window_done(struct mbox_context *context)
245ef0c8360SStewart Smith {
246ef0c8360SStewart Smith 	struct blk_io_trace *trace = &context->trace;
247ef0c8360SStewart Smith 
248ef0c8360SStewart Smith 	if (!context->blktracefd)
249ef0c8360SStewart Smith 		return;
250ef0c8360SStewart Smith 
251ef0c8360SStewart Smith 	trace->sector = context->current->flash_offset / 512;
252ef0c8360SStewart Smith 	trace->bytes = context->current->size;
253ef0c8360SStewart Smith 	write(context->blktracefd, trace, sizeof(*trace));
254ef0c8360SStewart Smith 	trace->sequence++;
255ef0c8360SStewart Smith 	trace->action &= ~BLK_TA_QUEUE;
256ef0c8360SStewart Smith 	trace->action |= BLK_TA_ISSUE;
257ef0c8360SStewart Smith 	write(context->blktracefd, trace, sizeof(*trace));
258ef0c8360SStewart Smith 
259ef0c8360SStewart Smith 	trace->sequence++;
260ef0c8360SStewart Smith 	trace->time = blktrace_gettime() - context->blktrace_start;
261ef0c8360SStewart Smith 	trace->action &= ~BLK_TA_ISSUE;
262ef0c8360SStewart Smith 	trace->action |= BLK_TA_COMPLETE;
263ef0c8360SStewart Smith 	write(context->blktracefd, trace, sizeof(*trace));
264ef0c8360SStewart Smith }
265ef0c8360SStewart Smith 
protocol_v1_create_window(struct mbox_context * context,struct protocol_create_window * io)266cb93504eSAndrew Jeffery static int protocol_v1_create_window(struct mbox_context *context,
26722fa5009SAndrew Jeffery 				     struct protocol_create_window *io)
26822fa5009SAndrew Jeffery {
269f1e547c7SEvan Lojewski 	struct backend *backend = &context->backend;
270f1e547c7SEvan Lojewski 	uint32_t offset;
271f1e547c7SEvan Lojewski 	uint32_t size;
272cb93504eSAndrew Jeffery 	int rc;
273cb93504eSAndrew Jeffery 
274f1e547c7SEvan Lojewski 	offset = io->req.offset << backend->block_size_shift;
275f1e547c7SEvan Lojewski 	size = io->req.size << backend->block_size_shift;
276f1e547c7SEvan Lojewski 	rc = backend_validate(backend, offset, size, io->req.ro);
277cb93504eSAndrew Jeffery 	if (rc < 0) {
278cb93504eSAndrew Jeffery 		/* Backend does not allow window to be created. */
279cb93504eSAndrew Jeffery 		return rc;
280cb93504eSAndrew Jeffery 	}
28122fa5009SAndrew Jeffery 
28222fa5009SAndrew Jeffery 	/* Close the current window if there is one */
28322fa5009SAndrew Jeffery 	if (context->current) {
284f21c81c7SAndrew Jeffery 		/* There is an implicit flush if it was a write window
285f21c81c7SAndrew Jeffery 		 *
286f21c81c7SAndrew Jeffery 		 * protocol_v2_create_window() calls
287f21c81c7SAndrew Jeffery 		 * protocol_v1_create_window(), so use indirect call to
288f21c81c7SAndrew Jeffery 		 * write_flush() to make sure we pick the right one.
289f21c81c7SAndrew Jeffery 		 */
29022fa5009SAndrew Jeffery 		if (context->current_is_write) {
291ef0c8360SStewart Smith 			blktrace_flush_start(context);
292f21c81c7SAndrew Jeffery 			rc = context->protocol->flush(context, NULL);
293ef0c8360SStewart Smith 			blktrace_flush_done(context);
29422fa5009SAndrew Jeffery 			if (rc < 0) {
29522fa5009SAndrew Jeffery 				MSG_ERR("Couldn't Flush Write Window\n");
29622fa5009SAndrew Jeffery 				return rc;
29722fa5009SAndrew Jeffery 			}
29822fa5009SAndrew Jeffery 		}
2992ebfd20fSAndrew Jeffery 		windows_close_current(context, FLAGS_NONE);
30022fa5009SAndrew Jeffery 	}
30122fa5009SAndrew Jeffery 
30222fa5009SAndrew Jeffery 	/* Offset the host has requested */
30322fa5009SAndrew Jeffery 	MSG_INFO("Host requested flash @ 0x%.8x\n", offset);
30422fa5009SAndrew Jeffery 	/* Check if we have an existing window */
305ef0c8360SStewart Smith 	blktrace_window_start(context);
30622fa5009SAndrew Jeffery 	context->current = windows_search(context, offset,
30722fa5009SAndrew Jeffery 					  context->version == API_VERSION_1);
30822fa5009SAndrew Jeffery 
30922fa5009SAndrew Jeffery 	if (!context->current) { /* No existing window */
31022fa5009SAndrew Jeffery 		MSG_DBG("No existing window which maps that flash offset\n");
31122fa5009SAndrew Jeffery 		rc = windows_create_map(context, &context->current,
31222fa5009SAndrew Jeffery 				       offset,
31322fa5009SAndrew Jeffery 				       context->version == API_VERSION_1);
31422fa5009SAndrew Jeffery 		if (rc < 0) { /* Unable to map offset */
31522fa5009SAndrew Jeffery 			MSG_ERR("Couldn't create window mapping for offset 0x%.8x\n",
3164bcec8efSAndrew Jeffery 				offset);
31722fa5009SAndrew Jeffery 			return rc;
31822fa5009SAndrew Jeffery 		}
31922fa5009SAndrew Jeffery 	}
320ef0c8360SStewart Smith 	blktrace_window_done(context);
32122fa5009SAndrew Jeffery 
3224bcec8efSAndrew Jeffery 	context->current_is_write = !io->req.ro;
3234bcec8efSAndrew Jeffery 
32422fa5009SAndrew Jeffery 	MSG_INFO("Window @ %p for size 0x%.8x maps flash offset 0x%.8x\n",
32522fa5009SAndrew Jeffery 		 context->current->mem, context->current->size,
32622fa5009SAndrew Jeffery 		 context->current->flash_offset);
32722fa5009SAndrew Jeffery 
32822fa5009SAndrew Jeffery 	io->resp.lpc_address = get_lpc_addr_shifted(context);
32922fa5009SAndrew Jeffery 
33022fa5009SAndrew Jeffery 	return 0;
33122fa5009SAndrew Jeffery }
33222fa5009SAndrew Jeffery 
protocol_v1_mark_dirty(struct mbox_context * context,struct protocol_mark_dirty * io)333cb93504eSAndrew Jeffery static int protocol_v1_mark_dirty(struct mbox_context *context,
334a336e43aSAndrew Jeffery 				  struct protocol_mark_dirty *io)
335a336e43aSAndrew Jeffery {
336a336e43aSAndrew Jeffery 	uint32_t offset = io->req.v1.offset;
337a336e43aSAndrew Jeffery 	uint32_t size = io->req.v1.size;
338a336e43aSAndrew Jeffery 	uint32_t off;
339a336e43aSAndrew Jeffery 
340a336e43aSAndrew Jeffery 	if (!(context->current && context->current_is_write)) {
341a336e43aSAndrew Jeffery 		MSG_ERR("Tried to call mark dirty without open write window\n");
342a336e43aSAndrew Jeffery 		return -EPERM;
343a336e43aSAndrew Jeffery 	}
344a336e43aSAndrew Jeffery 
345a336e43aSAndrew Jeffery 	/* For V1 offset given relative to flash - we want the window */
346a336e43aSAndrew Jeffery 	off = offset - ((context->current->flash_offset) >>
347f1e547c7SEvan Lojewski 			context->backend.block_size_shift);
348a336e43aSAndrew Jeffery 	if (off > offset) { /* Underflow - before current window */
349a336e43aSAndrew Jeffery 		MSG_ERR("Tried to mark dirty before start of window\n");
350a336e43aSAndrew Jeffery 		MSG_ERR("requested offset: 0x%x window start: 0x%x\n",
351f1e547c7SEvan Lojewski 				offset << context->backend.block_size_shift,
352a336e43aSAndrew Jeffery 				context->current->flash_offset);
353a336e43aSAndrew Jeffery 		return -EINVAL;
354a336e43aSAndrew Jeffery 	}
355a336e43aSAndrew Jeffery 	offset = off;
356a336e43aSAndrew Jeffery 	/*
357a336e43aSAndrew Jeffery 	 * We only track dirty at the block level.
358a336e43aSAndrew Jeffery 	 * For protocol V1 we can get away with just marking the whole
359a336e43aSAndrew Jeffery 	 * block dirty.
360a336e43aSAndrew Jeffery 	 */
361f1e547c7SEvan Lojewski 	size = align_up(size, 1 << context->backend.block_size_shift);
362f1e547c7SEvan Lojewski 	size >>= context->backend.block_size_shift;
363a336e43aSAndrew Jeffery 
364a336e43aSAndrew Jeffery 	MSG_INFO("Dirty window @ 0x%.8x for 0x%.8x\n",
365f1e547c7SEvan Lojewski 		 offset << context->backend.block_size_shift,
366f1e547c7SEvan Lojewski 		 size << context->backend.block_size_shift);
367a336e43aSAndrew Jeffery 
368a336e43aSAndrew Jeffery 	return window_set_bytemap(context, context->current, offset, size,
369a336e43aSAndrew Jeffery 				  WINDOW_DIRTY);
370a336e43aSAndrew Jeffery }
371a336e43aSAndrew Jeffery 
generic_flush(struct mbox_context * context)3729b920cf4SAndrew Jeffery static int generic_flush(struct mbox_context *context)
3739b920cf4SAndrew Jeffery {
374*68a24c9eSPatrick Williams 	int rc, offset, count;
3759b920cf4SAndrew Jeffery 	uint8_t prev;
376*68a24c9eSPatrick Williams 	size_t i;
3779b920cf4SAndrew Jeffery 
3789b920cf4SAndrew Jeffery 	offset = 0;
3799b920cf4SAndrew Jeffery 	count = 0;
3809b920cf4SAndrew Jeffery 	prev = WINDOW_CLEAN;
3819b920cf4SAndrew Jeffery 
3829b920cf4SAndrew Jeffery 	MSG_INFO("Flush window @ %p for size 0x%.8x which maps flash @ 0x%.8x\n",
3839b920cf4SAndrew Jeffery 		 context->current->mem, context->current->size,
3849b920cf4SAndrew Jeffery 		 context->current->flash_offset);
3859b920cf4SAndrew Jeffery 
3869b920cf4SAndrew Jeffery 	/*
3879b920cf4SAndrew Jeffery 	 * We look for streaks of the same type and keep a count, when the type
3889b920cf4SAndrew Jeffery 	 * (dirty/erased) changes we perform the required action on the backing
3899b920cf4SAndrew Jeffery 	 * store and update the current streak-type
3909b920cf4SAndrew Jeffery 	 */
391f1e547c7SEvan Lojewski 	for (i = 0; i < (context->current->size >> context->backend.block_size_shift);
3929b920cf4SAndrew Jeffery 			i++) {
3939b920cf4SAndrew Jeffery 		uint8_t cur = context->current->dirty_bmap[i];
3949b920cf4SAndrew Jeffery 		if (cur != WINDOW_CLEAN) {
3959b920cf4SAndrew Jeffery 			if (cur == prev) { /* Same as previous block, incrmnt */
3969b920cf4SAndrew Jeffery 				count++;
3979b920cf4SAndrew Jeffery 			} else if (prev == WINDOW_CLEAN) { /* Start of run */
3989b920cf4SAndrew Jeffery 				offset = i;
3999b920cf4SAndrew Jeffery 				count++;
4009b920cf4SAndrew Jeffery 			} else { /* Change in streak type */
4019b920cf4SAndrew Jeffery 				rc = window_flush(context, offset, count,
4029b920cf4SAndrew Jeffery 						       prev);
4039b920cf4SAndrew Jeffery 				if (rc < 0) {
4049b920cf4SAndrew Jeffery 					return rc;
4059b920cf4SAndrew Jeffery 				}
4069b920cf4SAndrew Jeffery 				offset = i;
4079b920cf4SAndrew Jeffery 				count = 1;
4089b920cf4SAndrew Jeffery 			}
4099b920cf4SAndrew Jeffery 		} else {
4109b920cf4SAndrew Jeffery 			if (prev != WINDOW_CLEAN) { /* End of a streak */
4119b920cf4SAndrew Jeffery 				rc = window_flush(context, offset, count,
4129b920cf4SAndrew Jeffery 						       prev);
4139b920cf4SAndrew Jeffery 				if (rc < 0) {
4149b920cf4SAndrew Jeffery 					return rc;
4159b920cf4SAndrew Jeffery 				}
4169b920cf4SAndrew Jeffery 				offset = 0;
4179b920cf4SAndrew Jeffery 				count = 0;
4189b920cf4SAndrew Jeffery 			}
4199b920cf4SAndrew Jeffery 		}
4209b920cf4SAndrew Jeffery 		prev = cur;
4219b920cf4SAndrew Jeffery 	}
4229b920cf4SAndrew Jeffery 
4239b920cf4SAndrew Jeffery 	if (prev != WINDOW_CLEAN) { /* Still the last streak to write */
4249b920cf4SAndrew Jeffery 		rc = window_flush(context, offset, count, prev);
4259b920cf4SAndrew Jeffery 		if (rc < 0) {
4269b920cf4SAndrew Jeffery 			return rc;
4279b920cf4SAndrew Jeffery 		}
4289b920cf4SAndrew Jeffery 	}
4299b920cf4SAndrew Jeffery 
4309b920cf4SAndrew Jeffery 	/* Clear the dirty bytemap since we have written back all changes */
4319b920cf4SAndrew Jeffery 	return window_set_bytemap(context, context->current, 0,
4329b920cf4SAndrew Jeffery 				  context->current->size >>
433f1e547c7SEvan Lojewski 				  context->backend.block_size_shift,
4349b920cf4SAndrew Jeffery 				  WINDOW_CLEAN);
4359b920cf4SAndrew Jeffery }
4369b920cf4SAndrew Jeffery 
protocol_v1_flush(struct mbox_context * context,struct protocol_flush * io)437cb93504eSAndrew Jeffery static int protocol_v1_flush(struct mbox_context *context,
438cb93504eSAndrew Jeffery 			     struct protocol_flush *io)
4399b920cf4SAndrew Jeffery {
4409b920cf4SAndrew Jeffery 	int rc;
4419b920cf4SAndrew Jeffery 
4429b920cf4SAndrew Jeffery 	if (!(context->current && context->current_is_write)) {
4439b920cf4SAndrew Jeffery 		MSG_ERR("Tried to call flush without open write window\n");
4449b920cf4SAndrew Jeffery 		return -EPERM;
4459b920cf4SAndrew Jeffery 	}
4469b920cf4SAndrew Jeffery 
4479b920cf4SAndrew Jeffery 	/*
4489b920cf4SAndrew Jeffery 	 * For V1 the Flush command acts much the same as the dirty command
4499b920cf4SAndrew Jeffery 	 * except with a flush as well. Only do this on an actual flush
4509b920cf4SAndrew Jeffery 	 * command not when we call flush because we've implicitly closed a
4519b920cf4SAndrew Jeffery 	 * window because we might not have the required args in req.
4529b920cf4SAndrew Jeffery 	 */
453093eda5cSAndrew Jeffery 	if (io) {
454093eda5cSAndrew Jeffery 		struct protocol_mark_dirty *mdio = (void *)io;
455093eda5cSAndrew Jeffery 		rc = protocol_v1_mark_dirty(context, mdio);
4569b920cf4SAndrew Jeffery 		if (rc < 0) {
4579b920cf4SAndrew Jeffery 			return rc;
4589b920cf4SAndrew Jeffery 		}
459093eda5cSAndrew Jeffery 	}
4609b920cf4SAndrew Jeffery 
4619b920cf4SAndrew Jeffery 	return generic_flush(context);
4629b920cf4SAndrew Jeffery }
4639b920cf4SAndrew Jeffery 
protocol_v1_close(struct mbox_context * context,struct protocol_close * io)464cb93504eSAndrew Jeffery static int protocol_v1_close(struct mbox_context *context,
465cb93504eSAndrew Jeffery 			     struct protocol_close *io)
466093eda5cSAndrew Jeffery {
467093eda5cSAndrew Jeffery 	int rc;
468093eda5cSAndrew Jeffery 
469093eda5cSAndrew Jeffery 	/* Close the current window if there is one */
470093eda5cSAndrew Jeffery 	if (!context->current) {
471093eda5cSAndrew Jeffery 		return 0;
472093eda5cSAndrew Jeffery 	}
473093eda5cSAndrew Jeffery 
474093eda5cSAndrew Jeffery 	/* There is an implicit flush if it was a write window */
475093eda5cSAndrew Jeffery 	if (context->current_is_write) {
476093eda5cSAndrew Jeffery 		rc = protocol_v1_flush(context, NULL);
477093eda5cSAndrew Jeffery 		if (rc < 0) {
478093eda5cSAndrew Jeffery 			MSG_ERR("Couldn't Flush Write Window\n");
479093eda5cSAndrew Jeffery 			return rc;
480093eda5cSAndrew Jeffery 		}
481093eda5cSAndrew Jeffery 	}
482093eda5cSAndrew Jeffery 
483093eda5cSAndrew Jeffery 	/* Host asked for it -> Don't set the BMC Event */
4842ebfd20fSAndrew Jeffery 	windows_close_current(context, io->req.flags);
485093eda5cSAndrew Jeffery 
486093eda5cSAndrew Jeffery 	return 0;
487093eda5cSAndrew Jeffery }
488093eda5cSAndrew Jeffery 
protocol_v1_ack(struct mbox_context * context,struct protocol_ack * io)489cb93504eSAndrew Jeffery static int protocol_v1_ack(struct mbox_context *context,
490cb93504eSAndrew Jeffery 			   struct protocol_ack *io)
491c5c83048SAndrew Jeffery {
4922ebfd20fSAndrew Jeffery 	return protocol_events_clear(context,
4932ebfd20fSAndrew Jeffery 				     (io->req.flags & BMC_EVENT_ACK_MASK));
494c5c83048SAndrew Jeffery }
495c5c83048SAndrew Jeffery 
49622fa5009SAndrew Jeffery /*
4971e531afdSAndrew Jeffery  * get_suggested_timeout() - get the suggested timeout value in seconds
4981e531afdSAndrew Jeffery  * @context:	The mbox context pointer
4991e531afdSAndrew Jeffery  *
5001e531afdSAndrew Jeffery  * Return:	Suggested timeout in seconds
5011e531afdSAndrew Jeffery  */
get_suggested_timeout(struct mbox_context * context)5021e531afdSAndrew Jeffery static uint16_t get_suggested_timeout(struct mbox_context *context)
5031e531afdSAndrew Jeffery {
5041e531afdSAndrew Jeffery 	struct window_context *window = windows_find_largest(context);
5051e531afdSAndrew Jeffery 	uint32_t max_size_mb = window ? (window->size >> 20) : 0;
5061e531afdSAndrew Jeffery 	uint16_t ret;
5071e531afdSAndrew Jeffery 
5081e531afdSAndrew Jeffery 	ret = align_up(max_size_mb * FLASH_ACCESS_MS_PER_MB, 1000) / 1000;
5091e531afdSAndrew Jeffery 
5101e531afdSAndrew Jeffery 	MSG_DBG("Suggested Timeout: %us, max window size: %uMB, for %dms/MB\n",
5111e531afdSAndrew Jeffery 		ret, max_size_mb, FLASH_ACCESS_MS_PER_MB);
5121e531afdSAndrew Jeffery 	return ret;
5131e531afdSAndrew Jeffery }
5141e531afdSAndrew Jeffery 
protocol_v2_get_info(struct mbox_context * context,struct protocol_get_info * io)515cb93504eSAndrew Jeffery static int protocol_v2_get_info(struct mbox_context *context,
5161e531afdSAndrew Jeffery 				struct protocol_get_info *io)
5171e531afdSAndrew Jeffery {
5181e531afdSAndrew Jeffery 	uint8_t old_version = context->version;
5191e531afdSAndrew Jeffery 	int rc;
5201e531afdSAndrew Jeffery 
5211e531afdSAndrew Jeffery 	/* Bootstrap protocol version. This may involve {up,down}grading */
5221e531afdSAndrew Jeffery 	rc = protocol_negotiate_version(context, io->req.api_version);
5231e531afdSAndrew Jeffery 	if (rc < 0)
5241e531afdSAndrew Jeffery 		return rc;
5251e531afdSAndrew Jeffery 
5261e531afdSAndrew Jeffery 	/* Do the {up,down}grade if necessary*/
5271e531afdSAndrew Jeffery 	if (rc != old_version) {
5282ebfd20fSAndrew Jeffery 		/* Doing version negotiation, don't alert host to reset */
5292ebfd20fSAndrew Jeffery 		windows_reset_all(context);
5301e531afdSAndrew Jeffery 		return context->protocol->get_info(context, io);
5311e531afdSAndrew Jeffery 	}
5321e531afdSAndrew Jeffery 
5331e531afdSAndrew Jeffery 	/* Record the negotiated version for the response */
5341e531afdSAndrew Jeffery 	io->resp.api_version = rc;
5351e531afdSAndrew Jeffery 
5361e531afdSAndrew Jeffery 	/* Now do all required intialisation for v2 */
5371e531afdSAndrew Jeffery 
5381e531afdSAndrew Jeffery 	/* Knowing blocksize we can allocate the window dirty_bytemap */
5391e531afdSAndrew Jeffery 	windows_alloc_dirty_bytemap(context);
5401e531afdSAndrew Jeffery 
541f1e547c7SEvan Lojewski 	io->resp.v2.block_size_shift = context->backend.block_size_shift;
542f1e547c7SEvan Lojewski 	MSG_INFO("Block Size: 0x%.8x (shift: %u)\n",
543f1e547c7SEvan Lojewski 		 1 << context->backend.block_size_shift, context->backend.block_size_shift);
544f1e547c7SEvan Lojewski 
5451e531afdSAndrew Jeffery 	io->resp.v2.timeout = get_suggested_timeout(context);
5461e531afdSAndrew Jeffery 
5471e531afdSAndrew Jeffery 	return lpc_map_memory(context);
5481e531afdSAndrew Jeffery }
5491e531afdSAndrew Jeffery 
protocol_v2_get_flash_info(struct mbox_context * context,struct protocol_get_flash_info * io)550cb93504eSAndrew Jeffery static int protocol_v2_get_flash_info(struct mbox_context *context,
55191a87454SAndrew Jeffery 				      struct protocol_get_flash_info *io)
55291a87454SAndrew Jeffery {
553f1e547c7SEvan Lojewski 	struct backend *backend = &context->backend;
554f1e547c7SEvan Lojewski 
55591a87454SAndrew Jeffery 	io->resp.v2.flash_size =
556f1e547c7SEvan Lojewski 		backend->flash_size >> backend->block_size_shift;
55791a87454SAndrew Jeffery 	io->resp.v2.erase_size =
558f1e547c7SEvan Lojewski 		((1 << backend->erase_size_shift) >> backend->block_size_shift);
55991a87454SAndrew Jeffery 
56091a87454SAndrew Jeffery 	return 0;
56191a87454SAndrew Jeffery }
56291a87454SAndrew Jeffery 
protocol_v2_create_window(struct mbox_context * context,struct protocol_create_window * io)563cb93504eSAndrew Jeffery static int protocol_v2_create_window(struct mbox_context *context,
56422fa5009SAndrew Jeffery 				     struct protocol_create_window *io)
56522fa5009SAndrew Jeffery {
56622fa5009SAndrew Jeffery 	int rc;
56722fa5009SAndrew Jeffery 
5684bcec8efSAndrew Jeffery 	rc = protocol_v1_create_window(context, io);
56922fa5009SAndrew Jeffery 	if (rc < 0)
57022fa5009SAndrew Jeffery 		return rc;
57122fa5009SAndrew Jeffery 
572f1e547c7SEvan Lojewski 	io->resp.size = context->current->size >> context->backend.block_size_shift;
57322fa5009SAndrew Jeffery 	io->resp.offset = context->current->flash_offset >>
574f1e547c7SEvan Lojewski 					context->backend.block_size_shift;
57522fa5009SAndrew Jeffery 
57622fa5009SAndrew Jeffery 	return 0;
57722fa5009SAndrew Jeffery }
57822fa5009SAndrew Jeffery 
protocol_v2_mark_dirty(struct mbox_context * context,struct protocol_mark_dirty * io)579cb93504eSAndrew Jeffery static int protocol_v2_mark_dirty(struct mbox_context *context,
580a336e43aSAndrew Jeffery 				  struct protocol_mark_dirty *io)
581a336e43aSAndrew Jeffery {
582a336e43aSAndrew Jeffery 	if (!(context->current && context->current_is_write)) {
583a336e43aSAndrew Jeffery 		MSG_ERR("Tried to call mark dirty without open write window\n");
584a336e43aSAndrew Jeffery 		return -EPERM;
585a336e43aSAndrew Jeffery 	}
586a336e43aSAndrew Jeffery 
587a336e43aSAndrew Jeffery 	MSG_INFO("Dirty window @ 0x%.8x for 0x%.8x\n",
588f1e547c7SEvan Lojewski 		 io->req.v2.offset << context->backend.block_size_shift,
589f1e547c7SEvan Lojewski 		 io->req.v2.size << context->backend.block_size_shift);
590a336e43aSAndrew Jeffery 
591a336e43aSAndrew Jeffery 	return window_set_bytemap(context, context->current, io->req.v2.offset,
592a336e43aSAndrew Jeffery 				  io->req.v2.size, WINDOW_DIRTY);
593a336e43aSAndrew Jeffery }
594a336e43aSAndrew Jeffery 
protocol_v2_erase(struct mbox_context * context,struct protocol_erase * io)595cb93504eSAndrew Jeffery static int protocol_v2_erase(struct mbox_context *context,
59662a3daaeSAndrew Jeffery 			     struct protocol_erase *io)
59762a3daaeSAndrew Jeffery {
59862a3daaeSAndrew Jeffery 	size_t start, len;
59962a3daaeSAndrew Jeffery 	int rc;
60062a3daaeSAndrew Jeffery 
60162a3daaeSAndrew Jeffery 	if (!(context->current && context->current_is_write)) {
60262a3daaeSAndrew Jeffery 		MSG_ERR("Tried to call erase without open write window\n");
60362a3daaeSAndrew Jeffery 		return -EPERM;
60462a3daaeSAndrew Jeffery 	}
60562a3daaeSAndrew Jeffery 
60662a3daaeSAndrew Jeffery 	MSG_INFO("Erase window @ 0x%.8x for 0x%.8x\n",
607f1e547c7SEvan Lojewski 		 io->req.offset << context->backend.block_size_shift,
608f1e547c7SEvan Lojewski 		 io->req.size << context->backend.block_size_shift);
60962a3daaeSAndrew Jeffery 
61062a3daaeSAndrew Jeffery 	rc = window_set_bytemap(context, context->current, io->req.offset,
61162a3daaeSAndrew Jeffery 				io->req.size, WINDOW_ERASED);
61262a3daaeSAndrew Jeffery 	if (rc < 0) {
61362a3daaeSAndrew Jeffery 		return rc;
61462a3daaeSAndrew Jeffery 	}
61562a3daaeSAndrew Jeffery 
61662a3daaeSAndrew Jeffery 	/* Write 0xFF to mem -> This ensures consistency between flash & ram */
617f1e547c7SEvan Lojewski 	start = io->req.offset << context->backend.block_size_shift;
618f1e547c7SEvan Lojewski 	len = io->req.size << context->backend.block_size_shift;
61962a3daaeSAndrew Jeffery 	memset(context->current->mem + start, 0xFF, len);
62062a3daaeSAndrew Jeffery 
62162a3daaeSAndrew Jeffery 	return 0;
62262a3daaeSAndrew Jeffery }
62362a3daaeSAndrew Jeffery 
protocol_v2_flush(struct mbox_context * context,struct protocol_flush * io)624*68a24c9eSPatrick Williams static int protocol_v2_flush(struct mbox_context *context __attribute__((unused)),
625*68a24c9eSPatrick Williams 			     struct protocol_flush *io __attribute__((unused)))
6269b920cf4SAndrew Jeffery {
6279b920cf4SAndrew Jeffery 	if (!(context->current && context->current_is_write)) {
6289b920cf4SAndrew Jeffery 		MSG_ERR("Tried to call flush without open write window\n");
6299b920cf4SAndrew Jeffery 		return -EPERM;
6309b920cf4SAndrew Jeffery 	}
6319b920cf4SAndrew Jeffery 
6329b920cf4SAndrew Jeffery 	return generic_flush(context);
6339b920cf4SAndrew Jeffery }
6349b920cf4SAndrew Jeffery 
protocol_v2_close(struct mbox_context * context,struct protocol_close * io)635cb93504eSAndrew Jeffery static int protocol_v2_close(struct mbox_context *context,
636cb93504eSAndrew Jeffery 			     struct protocol_close *io)
637093eda5cSAndrew Jeffery {
638093eda5cSAndrew Jeffery 	int rc;
639093eda5cSAndrew Jeffery 
640093eda5cSAndrew Jeffery 	/* Close the current window if there is one */
641093eda5cSAndrew Jeffery 	if (!context->current) {
642093eda5cSAndrew Jeffery 		return 0;
643093eda5cSAndrew Jeffery 	}
644093eda5cSAndrew Jeffery 
645093eda5cSAndrew Jeffery 	/* There is an implicit flush if it was a write window */
646093eda5cSAndrew Jeffery 	if (context->current_is_write) {
647093eda5cSAndrew Jeffery 		rc = protocol_v2_flush(context, NULL);
648093eda5cSAndrew Jeffery 		if (rc < 0) {
649093eda5cSAndrew Jeffery 			MSG_ERR("Couldn't Flush Write Window\n");
650093eda5cSAndrew Jeffery 			return rc;
651093eda5cSAndrew Jeffery 		}
652093eda5cSAndrew Jeffery 	}
653093eda5cSAndrew Jeffery 
654093eda5cSAndrew Jeffery 	/* Host asked for it -> Don't set the BMC Event */
6552ebfd20fSAndrew Jeffery 	windows_close_current(context, io->req.flags);
656093eda5cSAndrew Jeffery 
657093eda5cSAndrew Jeffery 	return 0;
658093eda5cSAndrew Jeffery }
659093eda5cSAndrew Jeffery 
660cb93504eSAndrew Jeffery static const struct protocol_ops protocol_ops_v1 = {
661cb93504eSAndrew Jeffery 	.reset = protocol_v1_reset,
662cb93504eSAndrew Jeffery 	.get_info = protocol_v1_get_info,
663cb93504eSAndrew Jeffery 	.get_flash_info = protocol_v1_get_flash_info,
664cb93504eSAndrew Jeffery 	.create_window = protocol_v1_create_window,
665cb93504eSAndrew Jeffery 	.mark_dirty = protocol_v1_mark_dirty,
666cb93504eSAndrew Jeffery 	.erase = NULL,
667cb93504eSAndrew Jeffery 	.flush = protocol_v1_flush,
668cb93504eSAndrew Jeffery 	.close = protocol_v1_close,
669cb93504eSAndrew Jeffery 	.ack = protocol_v1_ack,
670cb93504eSAndrew Jeffery };
671cb93504eSAndrew Jeffery 
672cb93504eSAndrew Jeffery static const struct protocol_ops protocol_ops_v2 = {
673cb93504eSAndrew Jeffery 	.reset = protocol_v1_reset,
674cb93504eSAndrew Jeffery 	.get_info = protocol_v2_get_info,
675cb93504eSAndrew Jeffery 	.get_flash_info = protocol_v2_get_flash_info,
676cb93504eSAndrew Jeffery 	.create_window = protocol_v2_create_window,
677cb93504eSAndrew Jeffery 	.mark_dirty = protocol_v2_mark_dirty,
678cb93504eSAndrew Jeffery 	.erase = protocol_v2_erase,
679cb93504eSAndrew Jeffery 	.flush = protocol_v2_flush,
680cb93504eSAndrew Jeffery 	.close = protocol_v2_close,
681cb93504eSAndrew Jeffery 	.ack = protocol_v1_ack,
682cb93504eSAndrew Jeffery };
683cb93504eSAndrew Jeffery 
684cb93504eSAndrew Jeffery static const struct protocol_ops *protocol_ops_map[] = {
685cb93504eSAndrew Jeffery 	[0] = NULL,
686cb93504eSAndrew Jeffery 	[1] = &protocol_ops_v1,
687cb93504eSAndrew Jeffery 	[2] = &protocol_ops_v2,
688cb93504eSAndrew Jeffery };
689cb93504eSAndrew Jeffery 
protocol_negotiate_version(struct mbox_context * context,uint8_t requested)690cb93504eSAndrew Jeffery static int protocol_negotiate_version(struct mbox_context *context,
691cb93504eSAndrew Jeffery 				      uint8_t requested)
692cb93504eSAndrew Jeffery {
693cb93504eSAndrew Jeffery 	/* Check we support the version requested */
694cb93504eSAndrew Jeffery 	if (requested < API_MIN_VERSION)
695cb93504eSAndrew Jeffery 		return -EINVAL;
696cb93504eSAndrew Jeffery 
697cb93504eSAndrew Jeffery 	context->version = (requested > API_MAX_VERSION) ?
698cb93504eSAndrew Jeffery 				API_MAX_VERSION : requested;
699cb93504eSAndrew Jeffery 
700cb93504eSAndrew Jeffery 	context->protocol = protocol_ops_map[context->version];
701cb93504eSAndrew Jeffery 
702cb93504eSAndrew Jeffery 	return context->version;
703cb93504eSAndrew Jeffery }
704cb93504eSAndrew Jeffery 
protocol_init(struct mbox_context * context)7051e531afdSAndrew Jeffery int protocol_init(struct mbox_context *context)
7061e531afdSAndrew Jeffery {
707c7d1947eSAndrew Jeffery 	protocol_negotiate_version(context, API_MAX_VERSION);
7081e531afdSAndrew Jeffery 
7091e531afdSAndrew Jeffery 	return 0;
7101e531afdSAndrew Jeffery }
7111e531afdSAndrew Jeffery 
protocol_free(struct mbox_context * context)712*68a24c9eSPatrick Williams void protocol_free(struct mbox_context *context __attribute__((unused)))
7131e531afdSAndrew Jeffery {
7141e531afdSAndrew Jeffery 	return;
7151e531afdSAndrew Jeffery }
716f69760daSAndrew Jeffery 
717f69760daSAndrew Jeffery /* Don't do any state manipulation, just perform the reset */
__protocol_reset(struct mbox_context * context)718f69760daSAndrew Jeffery int __protocol_reset(struct mbox_context *context)
719f69760daSAndrew Jeffery {
720f1e547c7SEvan Lojewski 	enum backend_reset_mode mode;
721f1e547c7SEvan Lojewski 	int rc;
722f1e547c7SEvan Lojewski 
723f69760daSAndrew Jeffery 	windows_reset_all(context);
724f69760daSAndrew Jeffery 
725f1e547c7SEvan Lojewski 	rc = backend_reset(&context->backend, context->mem, context->mem_size);
726f1e547c7SEvan Lojewski 	if (rc < 0)
727f1e547c7SEvan Lojewski 		return rc;
728f1e547c7SEvan Lojewski 
729f1e547c7SEvan Lojewski 	mode = rc;
730f1e547c7SEvan Lojewski 	if (!(mode == reset_lpc_flash || mode == reset_lpc_memory))
731f1e547c7SEvan Lojewski 		return -EINVAL;
732f1e547c7SEvan Lojewski 
733f1e547c7SEvan Lojewski 	if (mode == reset_lpc_flash)
734f1e547c7SEvan Lojewski 		return lpc_map_flash(context);
735f1e547c7SEvan Lojewski 
736f1e547c7SEvan Lojewski 	assert(mode == reset_lpc_memory);
737f1e547c7SEvan Lojewski 	return lpc_map_memory(context);
738f69760daSAndrew Jeffery }
739f69760daSAndrew Jeffery 
740f69760daSAndrew Jeffery /* Prevent the host from performing actions whilst reset takes place */
protocol_reset(struct mbox_context * context)741f69760daSAndrew Jeffery int protocol_reset(struct mbox_context *context)
742f69760daSAndrew Jeffery {
743f69760daSAndrew Jeffery 	int rc;
744f69760daSAndrew Jeffery 
745f69760daSAndrew Jeffery 	rc = protocol_events_clear(context, BMC_EVENT_DAEMON_READY);
746f69760daSAndrew Jeffery 	if (rc < 0) {
747f69760daSAndrew Jeffery 		MSG_ERR("Failed to clear daemon ready state, reset failed\n");
748f69760daSAndrew Jeffery 		return rc;
749f69760daSAndrew Jeffery 	}
750f69760daSAndrew Jeffery 
751f69760daSAndrew Jeffery 	rc = __protocol_reset(context);
752f69760daSAndrew Jeffery 	if (rc < 0) {
753f69760daSAndrew Jeffery 		MSG_ERR("Failed to reset protocol, daemon remains not ready\n");
754f69760daSAndrew Jeffery 		return rc;
755f69760daSAndrew Jeffery 	}
756f69760daSAndrew Jeffery 
757f69760daSAndrew Jeffery 	rc = protocol_events_set(context,
758f69760daSAndrew Jeffery 			BMC_EVENT_DAEMON_READY | BMC_EVENT_PROTOCOL_RESET);
759f69760daSAndrew Jeffery 	if (rc < 0) {
760f69760daSAndrew Jeffery 		MSG_ERR("Failed to set daemon ready state, daemon remains not ready\n");
761f69760daSAndrew Jeffery 		return rc;
762f69760daSAndrew Jeffery 	}
763f69760daSAndrew Jeffery 
764f69760daSAndrew Jeffery 	return 0;
765f69760daSAndrew Jeffery }
766*68a24c9eSPatrick Williams 
767*68a24c9eSPatrick Williams #pragma GCC diagnostic pop
768