xref: /openbmc/hiomapd/protocol.c (revision cb93504ed0fefa23186415accca6c0812174f274)
1 // SPDX-License-Identifier: Apache-2.0
2 // Copyright (C) 2018 IBM Corp.
3 #include "config.h"
4 
5 #include <errno.h>
6 #include <stdint.h>
7 
8 #include "common.h"
9 #include "flash.h"
10 #include "lpc.h"
11 #include "mboxd.h"
12 #include "protocol.h"
13 #include "windows.h"
14 
15 #define BLOCK_SIZE_SHIFT_V1		12 /* 4K */
16 
17 static inline uint8_t protocol_get_bmc_event_mask(struct mbox_context *context)
18 {
19 	if (context->version == API_VERSION_1) {
20 		return BMC_EVENT_V1_MASK;
21 	}
22 
23 	return BMC_EVENT_V2_MASK;
24 }
25 
26 /*
27  * protocol_events_put() - Push the full set/cleared state of BMC events on the
28  * 			   provided transport
29  * @context:    The mbox context pointer
30  * @ops:	The operations struct for the transport of interest
31  *
32  * Return:      0 on success otherwise negative error code
33  */
34 int protocol_events_put(struct mbox_context *context,
35 			const struct transport_ops *ops)
36 {
37 	const uint8_t mask = protocol_get_bmc_event_mask(context);
38 
39 	return ops->put_events(context, mask);
40 }
41 
42 /*
43  * protocol_events_set() - Update the set BMC events on the active transport
44  * @context:	The mbox context pointer
45  * @bmc_event:	The bits to set
46  *
47  * Return:	0 on success otherwise negative error code
48  */
49 int protocol_events_set(struct mbox_context *context, uint8_t bmc_event)
50 {
51 	const uint8_t mask = protocol_get_bmc_event_mask(context);
52 
53 	/*
54 	 * Store the raw value, as we may up- or down- grade the protocol
55 	 * version and subsequently need to flush the appropriate set. Instead
56 	 * we pass the masked value through to the transport
57 	 */
58 	context->bmc_events |= bmc_event;
59 
60 	return context->transport->set_events(context, bmc_event, mask);
61 }
62 
63 /*
64  * protocol_events_clear() - Update the cleared BMC events on the active
65  *                           transport
66  * @context:	The mbox context pointer
67  * @bmc_event:	The bits to clear
68  *
69  * Return:	0 on success otherwise negative error code
70  */
71 int protocol_events_clear(struct mbox_context *context, uint8_t bmc_event)
72 {
73 	const uint8_t mask = protocol_get_bmc_event_mask(context);
74 
75 	context->bmc_events &= ~bmc_event;
76 
77 	return context->transport->clear_events(context, bmc_event, mask);
78 }
79 
80 static int protocol_v1_reset(struct mbox_context *context)
81 {
82 	/* Host requested it -> No BMC Event */
83 	windows_reset_all(context);
84 	return lpc_reset(context);
85 }
86 
87 static int protocol_negotiate_version(struct mbox_context *context,
88 				      uint8_t requested);
89 
90 static int protocol_v1_get_info(struct mbox_context *context,
91 				struct protocol_get_info *io)
92 {
93 	uint8_t old_version = context->version;
94 	int rc;
95 
96 	/* Bootstrap protocol version. This may involve {up,down}grading */
97 	rc = protocol_negotiate_version(context, io->req.api_version);
98 	if (rc < 0)
99 		return rc;
100 
101 	/* Do the {up,down}grade if necessary*/
102 	if (rc != old_version) {
103 		/* Doing version negotiation, don't alert host to reset */
104 		windows_reset_all(context);
105 		return context->protocol->get_info(context, io);
106 	}
107 
108 	/* Record the negotiated version for the response */
109 	io->resp.api_version = rc;
110 
111 	/* Now do all required intialisation for v1 */
112 	context->block_size_shift = BLOCK_SIZE_SHIFT_V1;
113 	MSG_INFO("Block Size: 0x%.8x (shift: %u)\n",
114 		 1 << context->block_size_shift, context->block_size_shift);
115 
116 	/* Knowing blocksize we can allocate the window dirty_bytemap */
117 	windows_alloc_dirty_bytemap(context);
118 
119 	io->resp.v1.read_window_size =
120 		context->windows.default_size >> context->block_size_shift;
121 	io->resp.v1.write_window_size =
122 		context->windows.default_size >> context->block_size_shift;
123 
124 	return lpc_map_memory(context);
125 }
126 
127 static int protocol_v1_get_flash_info(struct mbox_context *context,
128 			       struct protocol_get_flash_info *io)
129 {
130 	io->resp.v1.flash_size = context->flash_size;
131 	io->resp.v1.erase_size = context->mtd_info.erasesize;
132 
133 	return 0;
134 }
135 
136 /*
137  * get_lpc_addr_shifted() - Get lpc address of the current window
138  * @context:		The mbox context pointer
139  *
140  * Return:	The lpc address to access that offset shifted by block size
141  */
142 static inline uint16_t get_lpc_addr_shifted(struct mbox_context *context)
143 {
144 	uint32_t lpc_addr, mem_offset;
145 
146 	/* Offset of the current window in the reserved memory region */
147 	mem_offset = context->current->mem - context->mem;
148 	/* Total LPC Address */
149 	lpc_addr = context->lpc_base + mem_offset;
150 
151 	MSG_DBG("LPC address of current window: 0x%.8x\n", lpc_addr);
152 
153 	return lpc_addr >> context->block_size_shift;
154 }
155 
156 static int protocol_v1_create_window(struct mbox_context *context,
157 				     struct protocol_create_window *io)
158 {
159 	uint32_t offset = io->req.offset << context->block_size_shift;
160 	uint32_t size = io->req.size << context->block_size_shift;
161 	int rc;
162 
163 	rc = flash_validate(context, offset, size, io->req.ro);
164 	if (rc < 0) {
165 		/* Backend does not allow window to be created. */
166 		return rc;
167 	}
168 
169 	/* Close the current window if there is one */
170 	if (context->current) {
171 		/* There is an implicit flush if it was a write window
172 		 *
173 		 * protocol_v2_create_window() calls
174 		 * protocol_v1_create_window(), so use indirect call to
175 		 * write_flush() to make sure we pick the right one.
176 		 */
177 		if (context->current_is_write) {
178 			rc = context->protocol->flush(context, NULL);
179 			if (rc < 0) {
180 				MSG_ERR("Couldn't Flush Write Window\n");
181 				return rc;
182 			}
183 		}
184 		windows_close_current(context, FLAGS_NONE);
185 	}
186 
187 	/* Offset the host has requested */
188 	MSG_INFO("Host requested flash @ 0x%.8x\n", offset);
189 	/* Check if we have an existing window */
190 	context->current = windows_search(context, offset,
191 					  context->version == API_VERSION_1);
192 
193 	if (!context->current) { /* No existing window */
194 		MSG_DBG("No existing window which maps that flash offset\n");
195 		rc = windows_create_map(context, &context->current,
196 				       offset,
197 				       context->version == API_VERSION_1);
198 		if (rc < 0) { /* Unable to map offset */
199 			MSG_ERR("Couldn't create window mapping for offset 0x%.8x\n",
200 				offset);
201 			return rc;
202 		}
203 	}
204 
205 	context->current_is_write = !io->req.ro;
206 
207 	MSG_INFO("Window @ %p for size 0x%.8x maps flash offset 0x%.8x\n",
208 		 context->current->mem, context->current->size,
209 		 context->current->flash_offset);
210 
211 	io->resp.lpc_address = get_lpc_addr_shifted(context);
212 
213 	return 0;
214 }
215 
216 static int protocol_v1_mark_dirty(struct mbox_context *context,
217 				  struct protocol_mark_dirty *io)
218 {
219 	uint32_t offset = io->req.v1.offset;
220 	uint32_t size = io->req.v1.size;
221 	uint32_t off;
222 
223 	if (!(context->current && context->current_is_write)) {
224 		MSG_ERR("Tried to call mark dirty without open write window\n");
225 		return -EPERM;
226 	}
227 
228 	/* For V1 offset given relative to flash - we want the window */
229 	off = offset - ((context->current->flash_offset) >>
230 			context->block_size_shift);
231 	if (off > offset) { /* Underflow - before current window */
232 		MSG_ERR("Tried to mark dirty before start of window\n");
233 		MSG_ERR("requested offset: 0x%x window start: 0x%x\n",
234 				offset << context->block_size_shift,
235 				context->current->flash_offset);
236 		return -EINVAL;
237 	}
238 	offset = off;
239 	/*
240 	 * We only track dirty at the block level.
241 	 * For protocol V1 we can get away with just marking the whole
242 	 * block dirty.
243 	 */
244 	size = align_up(size, 1 << context->block_size_shift);
245 	size >>= context->block_size_shift;
246 
247 	MSG_INFO("Dirty window @ 0x%.8x for 0x%.8x\n",
248 		 offset << context->block_size_shift,
249 		 size << context->block_size_shift);
250 
251 	return window_set_bytemap(context, context->current, offset, size,
252 				  WINDOW_DIRTY);
253 }
254 
255 static int generic_flush(struct mbox_context *context)
256 {
257 	int rc, i, offset, count;
258 	uint8_t prev;
259 
260 	offset = 0;
261 	count = 0;
262 	prev = WINDOW_CLEAN;
263 
264 	MSG_INFO("Flush window @ %p for size 0x%.8x which maps flash @ 0x%.8x\n",
265 		 context->current->mem, context->current->size,
266 		 context->current->flash_offset);
267 
268 	/*
269 	 * We look for streaks of the same type and keep a count, when the type
270 	 * (dirty/erased) changes we perform the required action on the backing
271 	 * store and update the current streak-type
272 	 */
273 	for (i = 0; i < (context->current->size >> context->block_size_shift);
274 			i++) {
275 		uint8_t cur = context->current->dirty_bmap[i];
276 		if (cur != WINDOW_CLEAN) {
277 			if (cur == prev) { /* Same as previous block, incrmnt */
278 				count++;
279 			} else if (prev == WINDOW_CLEAN) { /* Start of run */
280 				offset = i;
281 				count++;
282 			} else { /* Change in streak type */
283 				rc = window_flush(context, offset, count,
284 						       prev);
285 				if (rc < 0) {
286 					return rc;
287 				}
288 				offset = i;
289 				count = 1;
290 			}
291 		} else {
292 			if (prev != WINDOW_CLEAN) { /* End of a streak */
293 				rc = window_flush(context, offset, count,
294 						       prev);
295 				if (rc < 0) {
296 					return rc;
297 				}
298 				offset = 0;
299 				count = 0;
300 			}
301 		}
302 		prev = cur;
303 	}
304 
305 	if (prev != WINDOW_CLEAN) { /* Still the last streak to write */
306 		rc = window_flush(context, offset, count, prev);
307 		if (rc < 0) {
308 			return rc;
309 		}
310 	}
311 
312 	/* Clear the dirty bytemap since we have written back all changes */
313 	return window_set_bytemap(context, context->current, 0,
314 				  context->current->size >>
315 				  context->block_size_shift,
316 				  WINDOW_CLEAN);
317 }
318 
319 static int protocol_v1_flush(struct mbox_context *context,
320 			     struct protocol_flush *io)
321 {
322 	int rc;
323 
324 	if (!(context->current && context->current_is_write)) {
325 		MSG_ERR("Tried to call flush without open write window\n");
326 		return -EPERM;
327 	}
328 
329 	/*
330 	 * For V1 the Flush command acts much the same as the dirty command
331 	 * except with a flush as well. Only do this on an actual flush
332 	 * command not when we call flush because we've implicitly closed a
333 	 * window because we might not have the required args in req.
334 	 */
335 	if (io) {
336 		struct protocol_mark_dirty *mdio = (void *)io;
337 		rc = protocol_v1_mark_dirty(context, mdio);
338 		if (rc < 0) {
339 			return rc;
340 		}
341 	}
342 
343 	return generic_flush(context);
344 }
345 
346 static int protocol_v1_close(struct mbox_context *context,
347 			     struct protocol_close *io)
348 {
349 	int rc;
350 
351 	/* Close the current window if there is one */
352 	if (!context->current) {
353 		return 0;
354 	}
355 
356 	/* There is an implicit flush if it was a write window */
357 	if (context->current_is_write) {
358 		rc = protocol_v1_flush(context, NULL);
359 		if (rc < 0) {
360 			MSG_ERR("Couldn't Flush Write Window\n");
361 			return rc;
362 		}
363 	}
364 
365 	/* Host asked for it -> Don't set the BMC Event */
366 	windows_close_current(context, io->req.flags);
367 
368 	return 0;
369 }
370 
371 static int protocol_v1_ack(struct mbox_context *context,
372 			   struct protocol_ack *io)
373 {
374 	return protocol_events_clear(context,
375 				     (io->req.flags & BMC_EVENT_ACK_MASK));
376 }
377 
378 /*
379  * get_suggested_timeout() - get the suggested timeout value in seconds
380  * @context:	The mbox context pointer
381  *
382  * Return:	Suggested timeout in seconds
383  */
384 static uint16_t get_suggested_timeout(struct mbox_context *context)
385 {
386 	struct window_context *window = windows_find_largest(context);
387 	uint32_t max_size_mb = window ? (window->size >> 20) : 0;
388 	uint16_t ret;
389 
390 	ret = align_up(max_size_mb * FLASH_ACCESS_MS_PER_MB, 1000) / 1000;
391 
392 	MSG_DBG("Suggested Timeout: %us, max window size: %uMB, for %dms/MB\n",
393 		ret, max_size_mb, FLASH_ACCESS_MS_PER_MB);
394 	return ret;
395 }
396 
397 static int protocol_v2_get_info(struct mbox_context *context,
398 				struct protocol_get_info *io)
399 {
400 	uint8_t old_version = context->version;
401 	int rc;
402 
403 	/* Bootstrap protocol version. This may involve {up,down}grading */
404 	rc = protocol_negotiate_version(context, io->req.api_version);
405 	if (rc < 0)
406 		return rc;
407 
408 	/* Do the {up,down}grade if necessary*/
409 	if (rc != old_version) {
410 		/* Doing version negotiation, don't alert host to reset */
411 		windows_reset_all(context);
412 		return context->protocol->get_info(context, io);
413 	}
414 
415 	/* Record the negotiated version for the response */
416 	io->resp.api_version = rc;
417 
418 	/* Now do all required intialisation for v2 */
419 	context->block_size_shift = log_2(context->mtd_info.erasesize);
420 	MSG_INFO("Block Size: 0x%.8x (shift: %u)\n",
421 		 1 << context->block_size_shift, context->block_size_shift);
422 
423 	/* Knowing blocksize we can allocate the window dirty_bytemap */
424 	windows_alloc_dirty_bytemap(context);
425 
426 	io->resp.v2.block_size_shift = context->block_size_shift;
427 	io->resp.v2.timeout = get_suggested_timeout(context);
428 
429 	return lpc_map_memory(context);
430 }
431 
432 static int protocol_v2_get_flash_info(struct mbox_context *context,
433 				      struct protocol_get_flash_info *io)
434 {
435 	io->resp.v2.flash_size =
436 		context->flash_size >> context->block_size_shift;
437 	io->resp.v2.erase_size =
438 		context->mtd_info.erasesize >> context->block_size_shift;
439 
440 	return 0;
441 }
442 
443 static int protocol_v2_create_window(struct mbox_context *context,
444 				     struct protocol_create_window *io)
445 {
446 	int rc;
447 
448 	rc = protocol_v1_create_window(context, io);
449 	if (rc < 0)
450 		return rc;
451 
452 	io->resp.size = context->current->size >> context->block_size_shift;
453 	io->resp.offset = context->current->flash_offset >>
454 					context->block_size_shift;
455 
456 	return 0;
457 }
458 
459 static int protocol_v2_mark_dirty(struct mbox_context *context,
460 				  struct protocol_mark_dirty *io)
461 {
462 	if (!(context->current && context->current_is_write)) {
463 		MSG_ERR("Tried to call mark dirty without open write window\n");
464 		return -EPERM;
465 	}
466 
467 	MSG_INFO("Dirty window @ 0x%.8x for 0x%.8x\n",
468 		 io->req.v2.offset << context->block_size_shift,
469 		 io->req.v2.size << context->block_size_shift);
470 
471 	return window_set_bytemap(context, context->current, io->req.v2.offset,
472 				  io->req.v2.size, WINDOW_DIRTY);
473 }
474 
475 static int protocol_v2_erase(struct mbox_context *context,
476 			     struct protocol_erase *io)
477 {
478 	size_t start, len;
479 	int rc;
480 
481 	if (!(context->current && context->current_is_write)) {
482 		MSG_ERR("Tried to call erase without open write window\n");
483 		return -EPERM;
484 	}
485 
486 	MSG_INFO("Erase window @ 0x%.8x for 0x%.8x\n",
487 		 io->req.offset << context->block_size_shift,
488 		 io->req.size << context->block_size_shift);
489 
490 	rc = window_set_bytemap(context, context->current, io->req.offset,
491 				io->req.size, WINDOW_ERASED);
492 	if (rc < 0) {
493 		return rc;
494 	}
495 
496 	/* Write 0xFF to mem -> This ensures consistency between flash & ram */
497 	start = io->req.offset << context->block_size_shift;
498 	len = io->req.size << context->block_size_shift;
499 	memset(context->current->mem + start, 0xFF, len);
500 
501 	return 0;
502 }
503 
504 static int protocol_v2_flush(struct mbox_context *context,
505 			     struct protocol_flush *io)
506 {
507 	if (!(context->current && context->current_is_write)) {
508 		MSG_ERR("Tried to call flush without open write window\n");
509 		return -EPERM;
510 	}
511 
512 	return generic_flush(context);
513 }
514 
515 static int protocol_v2_close(struct mbox_context *context,
516 			     struct protocol_close *io)
517 {
518 	int rc;
519 
520 	/* Close the current window if there is one */
521 	if (!context->current) {
522 		return 0;
523 	}
524 
525 	/* There is an implicit flush if it was a write window */
526 	if (context->current_is_write) {
527 		rc = protocol_v2_flush(context, NULL);
528 		if (rc < 0) {
529 			MSG_ERR("Couldn't Flush Write Window\n");
530 			return rc;
531 		}
532 	}
533 
534 	/* Host asked for it -> Don't set the BMC Event */
535 	windows_close_current(context, io->req.flags);
536 
537 	return 0;
538 }
539 
540 static const struct protocol_ops protocol_ops_v1 = {
541 	.reset = protocol_v1_reset,
542 	.get_info = protocol_v1_get_info,
543 	.get_flash_info = protocol_v1_get_flash_info,
544 	.create_window = protocol_v1_create_window,
545 	.mark_dirty = protocol_v1_mark_dirty,
546 	.erase = NULL,
547 	.flush = protocol_v1_flush,
548 	.close = protocol_v1_close,
549 	.ack = protocol_v1_ack,
550 };
551 
552 static const struct protocol_ops protocol_ops_v2 = {
553 	.reset = protocol_v1_reset,
554 	.get_info = protocol_v2_get_info,
555 	.get_flash_info = protocol_v2_get_flash_info,
556 	.create_window = protocol_v2_create_window,
557 	.mark_dirty = protocol_v2_mark_dirty,
558 	.erase = protocol_v2_erase,
559 	.flush = protocol_v2_flush,
560 	.close = protocol_v2_close,
561 	.ack = protocol_v1_ack,
562 };
563 
564 static const struct protocol_ops *protocol_ops_map[] = {
565 	[0] = NULL,
566 	[1] = &protocol_ops_v1,
567 	[2] = &protocol_ops_v2,
568 };
569 
570 static int protocol_negotiate_version(struct mbox_context *context,
571 				      uint8_t requested)
572 {
573 	/* Check we support the version requested */
574 	if (requested < API_MIN_VERSION)
575 		return -EINVAL;
576 
577 	context->version = (requested > API_MAX_VERSION) ?
578 				API_MAX_VERSION : requested;
579 
580 	context->protocol = protocol_ops_map[context->version];
581 
582 	return context->version;
583 }
584 
585 int protocol_init(struct mbox_context *context)
586 {
587 	protocol_negotiate_version(context, API_MAX_VERSION);
588 
589 	return 0;
590 }
591 
592 void protocol_free(struct mbox_context *context)
593 {
594 	return;
595 }
596 
597 /* Don't do any state manipulation, just perform the reset */
598 int __protocol_reset(struct mbox_context *context)
599 {
600 	windows_reset_all(context);
601 
602 	return lpc_reset(context);
603 }
604 
605 /* Prevent the host from performing actions whilst reset takes place */
606 int protocol_reset(struct mbox_context *context)
607 {
608 	int rc;
609 
610 	rc = protocol_events_clear(context, BMC_EVENT_DAEMON_READY);
611 	if (rc < 0) {
612 		MSG_ERR("Failed to clear daemon ready state, reset failed\n");
613 		return rc;
614 	}
615 
616 	rc = __protocol_reset(context);
617 	if (rc < 0) {
618 		MSG_ERR("Failed to reset protocol, daemon remains not ready\n");
619 		return rc;
620 	}
621 
622 	rc = protocol_events_set(context,
623 			BMC_EVENT_DAEMON_READY | BMC_EVENT_PROTOCOL_RESET);
624 	if (rc < 0) {
625 		MSG_ERR("Failed to set daemon ready state, daemon remains not ready\n");
626 		return rc;
627 	}
628 
629 	return 0;
630 }
631