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