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