xref: /openbmc/hiomapd/protocol.c (revision 1e531afd)
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 "mbox.h"
9 #include "lpc.h"
10 #include "transport_mbox.h" /* TODO: Remove dependency on transport_mbox.h */
11 #include "windows.h"
12 
13 int protocol_v1_get_info(struct mbox_context *context,
14 			 struct protocol_get_info *io)
15 {
16 	uint8_t old_version = context->version;
17 	int rc;
18 
19 	/* Bootstrap protocol version. This may involve {up,down}grading */
20 	rc = protocol_negotiate_version(context, io->req.api_version);
21 	if (rc < 0)
22 		return rc;
23 
24 	/* Do the {up,down}grade if necessary*/
25 	if (rc != old_version) {
26 		windows_reset_all(context, SET_BMC_EVENT);
27 		return context->protocol->get_info(context, io);
28 	}
29 
30 	/* Record the negotiated version for the response */
31 	io->resp.api_version = rc;
32 
33 	/* Now do all required intialisation for v1 */
34 	context->block_size_shift = BLOCK_SIZE_SHIFT_V1;
35 	MSG_INFO("Block Size: 0x%.8x (shift: %u)\n",
36 		 1 << context->block_size_shift, context->block_size_shift);
37 
38 	/* Knowing blocksize we can allocate the window dirty_bytemap */
39 	windows_alloc_dirty_bytemap(context);
40 
41 	io->resp.v1.read_window_size =
42 		context->windows.default_size >> context->block_size_shift;
43 	io->resp.v1.write_window_size =
44 		context->windows.default_size >> context->block_size_shift;
45 
46 	return lpc_map_memory(context);
47 }
48 
49 /*
50  * get_suggested_timeout() - get the suggested timeout value in seconds
51  * @context:	The mbox context pointer
52  *
53  * Return:	Suggested timeout in seconds
54  */
55 static uint16_t get_suggested_timeout(struct mbox_context *context)
56 {
57 	struct window_context *window = windows_find_largest(context);
58 	uint32_t max_size_mb = window ? (window->size >> 20) : 0;
59 	uint16_t ret;
60 
61 	ret = align_up(max_size_mb * FLASH_ACCESS_MS_PER_MB, 1000) / 1000;
62 
63 	MSG_DBG("Suggested Timeout: %us, max window size: %uMB, for %dms/MB\n",
64 		ret, max_size_mb, FLASH_ACCESS_MS_PER_MB);
65 	return ret;
66 }
67 
68 int protocol_v2_get_info(struct mbox_context *context,
69 			 struct protocol_get_info *io)
70 {
71 	uint8_t old_version = context->version;
72 	int rc;
73 
74 	/* Bootstrap protocol version. This may involve {up,down}grading */
75 	rc = protocol_negotiate_version(context, io->req.api_version);
76 	if (rc < 0)
77 		return rc;
78 
79 	/* Do the {up,down}grade if necessary*/
80 	if (rc != old_version) {
81 		windows_reset_all(context, SET_BMC_EVENT);
82 		return context->protocol->get_info(context, io);
83 	}
84 
85 	/* Record the negotiated version for the response */
86 	io->resp.api_version = rc;
87 
88 	/* Now do all required intialisation for v2 */
89 	context->block_size_shift = log_2(context->mtd_info.erasesize);
90 	MSG_INFO("Block Size: 0x%.8x (shift: %u)\n",
91 		 1 << context->block_size_shift, context->block_size_shift);
92 
93 	/* Knowing blocksize we can allocate the window dirty_bytemap */
94 	windows_alloc_dirty_bytemap(context);
95 
96 	io->resp.v2.block_size_shift = context->block_size_shift;
97 	io->resp.v2.timeout = get_suggested_timeout(context);
98 
99 	return lpc_map_memory(context);
100 }
101 
102 static const struct protocol_ops protocol_ops_v1 = {
103 	.get_info = protocol_v1_get_info,
104 };
105 
106 static const struct protocol_ops protocol_ops_v2 = {
107 	.get_info = protocol_v2_get_info,
108 };
109 
110 static const struct protocol_ops *protocol_ops_map[] = {
111 	[0] = NULL,
112 	[1] = &protocol_ops_v1,
113 	[2] = &protocol_ops_v2,
114 };
115 
116 int protocol_negotiate_version(struct mbox_context *context,
117 				   uint8_t requested)
118 {
119 	/* Check we support the version requested */
120 	if (requested < API_MIN_VERSION)
121 		return -EINVAL;
122 
123 	context->version = (requested > API_MAX_VERSION) ?
124 				API_MAX_VERSION : requested;
125 
126 	context->protocol = protocol_ops_map[context->version];
127 
128 	return context->version;
129 }
130 
131 int protocol_init(struct mbox_context *context)
132 {
133 	context->version = API_MAX_VERSION;
134 	context->protocol = protocol_ops_map[context->version];
135 
136 	return 0;
137 }
138 
139 void protocol_free(struct mbox_context *context)
140 {
141 	return;
142 }
143