blob: 96c804f3c32699e1051f6eaf0808e5d9bcbc36e1 [file] [log] [blame]
Andrew Jeffery1e531af2018-08-07 13:32:57 +09301// 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
Andrew Jefferyab666a52018-08-07 14:28:09 +093013int 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
Andrew Jeffery1e531af2018-08-07 13:32:57 +093020int 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
Andrew Jeffery91a87452018-08-07 14:54:14 +093056int protocol_v1_get_flash_info(struct mbox_context *context,
57 struct protocol_get_flash_info *io)
58{
59 io->resp.v1.flash_size = context->flash_size;
60 io->resp.v1.erase_size = context->mtd_info.erasesize;
61
62 return 0;
63}
64
Andrew Jeffery1e531af2018-08-07 13:32:57 +093065/*
Andrew Jeffery22fa5002018-08-07 15:22:50 +093066 * get_lpc_addr_shifted() - Get lpc address of the current window
67 * @context: The mbox context pointer
68 *
69 * Return: The lpc address to access that offset shifted by block size
70 */
71static inline uint16_t get_lpc_addr_shifted(struct mbox_context *context)
72{
73 uint32_t lpc_addr, mem_offset;
74
75 /* Offset of the current window in the reserved memory region */
76 mem_offset = context->current->mem - context->mem;
77 /* Total LPC Address */
78 lpc_addr = context->lpc_base + mem_offset;
79
80 MSG_DBG("LPC address of current window: 0x%.8x\n", lpc_addr);
81
82 return lpc_addr >> context->block_size_shift;
83}
84
85int protocol_v1_create_read_window(struct mbox_context *context,
86 struct protocol_create_window *io)
87{
88 int rc;
89 uint32_t offset = io->req.offset << context->block_size_shift;
90
91 /* Close the current window if there is one */
92 if (context->current) {
93 /* There is an implicit flush if it was a write window */
94 if (context->current_is_write) {
95 rc = mbox_handle_flush_window(context, NULL, NULL);
96 if (rc < 0) {
97 MSG_ERR("Couldn't Flush Write Window\n");
98 return rc;
99 }
100 }
101 windows_close_current(context, NO_BMC_EVENT, FLAGS_NONE);
102 }
103
104 /* Offset the host has requested */
105 MSG_INFO("Host requested flash @ 0x%.8x\n", offset);
106 /* Check if we have an existing window */
107 context->current = windows_search(context, offset,
108 context->version == API_VERSION_1);
109
110 if (!context->current) { /* No existing window */
111 MSG_DBG("No existing window which maps that flash offset\n");
112 rc = windows_create_map(context, &context->current,
113 offset,
114 context->version == API_VERSION_1);
115 if (rc < 0) { /* Unable to map offset */
116 MSG_ERR("Couldn't create window mapping for offset 0x%.8x\n",
117 io->req.offset);
118 return rc;
119 }
120 }
121
122 MSG_INFO("Window @ %p for size 0x%.8x maps flash offset 0x%.8x\n",
123 context->current->mem, context->current->size,
124 context->current->flash_offset);
125
126 io->resp.lpc_address = get_lpc_addr_shifted(context);
127
128 return 0;
129}
130
131/*
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930132 * get_suggested_timeout() - get the suggested timeout value in seconds
133 * @context: The mbox context pointer
134 *
135 * Return: Suggested timeout in seconds
136 */
137static uint16_t get_suggested_timeout(struct mbox_context *context)
138{
139 struct window_context *window = windows_find_largest(context);
140 uint32_t max_size_mb = window ? (window->size >> 20) : 0;
141 uint16_t ret;
142
143 ret = align_up(max_size_mb * FLASH_ACCESS_MS_PER_MB, 1000) / 1000;
144
145 MSG_DBG("Suggested Timeout: %us, max window size: %uMB, for %dms/MB\n",
146 ret, max_size_mb, FLASH_ACCESS_MS_PER_MB);
147 return ret;
148}
149
150int protocol_v2_get_info(struct mbox_context *context,
151 struct protocol_get_info *io)
152{
153 uint8_t old_version = context->version;
154 int rc;
155
156 /* Bootstrap protocol version. This may involve {up,down}grading */
157 rc = protocol_negotiate_version(context, io->req.api_version);
158 if (rc < 0)
159 return rc;
160
161 /* Do the {up,down}grade if necessary*/
162 if (rc != old_version) {
163 windows_reset_all(context, SET_BMC_EVENT);
164 return context->protocol->get_info(context, io);
165 }
166
167 /* Record the negotiated version for the response */
168 io->resp.api_version = rc;
169
170 /* Now do all required intialisation for v2 */
171 context->block_size_shift = log_2(context->mtd_info.erasesize);
172 MSG_INFO("Block Size: 0x%.8x (shift: %u)\n",
173 1 << context->block_size_shift, context->block_size_shift);
174
175 /* Knowing blocksize we can allocate the window dirty_bytemap */
176 windows_alloc_dirty_bytemap(context);
177
178 io->resp.v2.block_size_shift = context->block_size_shift;
179 io->resp.v2.timeout = get_suggested_timeout(context);
180
181 return lpc_map_memory(context);
182}
183
Andrew Jeffery91a87452018-08-07 14:54:14 +0930184int protocol_v2_get_flash_info(struct mbox_context *context,
185 struct protocol_get_flash_info *io)
186{
187 io->resp.v2.flash_size =
188 context->flash_size >> context->block_size_shift;
189 io->resp.v2.erase_size =
190 context->mtd_info.erasesize >> context->block_size_shift;
191
192 return 0;
193}
194
Andrew Jeffery22fa5002018-08-07 15:22:50 +0930195int protocol_v2_create_read_window(struct mbox_context *context,
196 struct protocol_create_window *io)
197{
198 int rc;
199
200 rc = protocol_v1_create_read_window(context, io);
201 if (rc < 0)
202 return rc;
203
204 io->resp.size = context->current->size >> context->block_size_shift;
205 io->resp.offset = context->current->flash_offset >>
206 context->block_size_shift;
207
208 return 0;
209}
210
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930211static const struct protocol_ops protocol_ops_v1 = {
Andrew Jefferyab666a52018-08-07 14:28:09 +0930212 .reset = protocol_v1_reset,
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930213 .get_info = protocol_v1_get_info,
Andrew Jeffery91a87452018-08-07 14:54:14 +0930214 .get_flash_info = protocol_v1_get_flash_info,
Andrew Jeffery22fa5002018-08-07 15:22:50 +0930215 .create_read_window = protocol_v1_create_read_window,
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930216};
217
218static const struct protocol_ops protocol_ops_v2 = {
Andrew Jefferyab666a52018-08-07 14:28:09 +0930219 .reset = protocol_v1_reset,
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930220 .get_info = protocol_v2_get_info,
Andrew Jeffery91a87452018-08-07 14:54:14 +0930221 .get_flash_info = protocol_v2_get_flash_info,
Andrew Jeffery22fa5002018-08-07 15:22:50 +0930222 .create_read_window = protocol_v2_create_read_window,
223
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930224};
225
226static const struct protocol_ops *protocol_ops_map[] = {
227 [0] = NULL,
228 [1] = &protocol_ops_v1,
229 [2] = &protocol_ops_v2,
230};
231
232int protocol_negotiate_version(struct mbox_context *context,
233 uint8_t requested)
234{
235 /* Check we support the version requested */
236 if (requested < API_MIN_VERSION)
237 return -EINVAL;
238
239 context->version = (requested > API_MAX_VERSION) ?
240 API_MAX_VERSION : requested;
241
242 context->protocol = protocol_ops_map[context->version];
243
244 return context->version;
245}
246
247int protocol_init(struct mbox_context *context)
248{
249 context->version = API_MAX_VERSION;
250 context->protocol = protocol_ops_map[context->version];
251
252 return 0;
253}
254
255void protocol_free(struct mbox_context *context)
256{
257 return;
258}