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 int 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 65 /* 66 * 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 */ 71 static 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 85 int protocol_v1_create_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 offset); 118 return rc; 119 } 120 } 121 122 context->current_is_write = !io->req.ro; 123 124 MSG_INFO("Window @ %p for size 0x%.8x maps flash offset 0x%.8x\n", 125 context->current->mem, context->current->size, 126 context->current->flash_offset); 127 128 io->resp.lpc_address = get_lpc_addr_shifted(context); 129 130 return 0; 131 } 132 133 int protocol_v1_mark_dirty(struct mbox_context *context, 134 struct protocol_mark_dirty *io) 135 { 136 uint32_t offset = io->req.v1.offset; 137 uint32_t size = io->req.v1.size; 138 uint32_t off; 139 140 if (!(context->current && context->current_is_write)) { 141 MSG_ERR("Tried to call mark dirty without open write window\n"); 142 return -EPERM; 143 } 144 145 /* For V1 offset given relative to flash - we want the window */ 146 off = offset - ((context->current->flash_offset) >> 147 context->block_size_shift); 148 if (off > offset) { /* Underflow - before current window */ 149 MSG_ERR("Tried to mark dirty before start of window\n"); 150 MSG_ERR("requested offset: 0x%x window start: 0x%x\n", 151 offset << context->block_size_shift, 152 context->current->flash_offset); 153 return -EINVAL; 154 } 155 offset = off; 156 /* 157 * We only track dirty at the block level. 158 * For protocol V1 we can get away with just marking the whole 159 * block dirty. 160 */ 161 size = align_up(size, 1 << context->block_size_shift); 162 size >>= context->block_size_shift; 163 164 MSG_INFO("Dirty window @ 0x%.8x for 0x%.8x\n", 165 offset << context->block_size_shift, 166 size << context->block_size_shift); 167 168 return window_set_bytemap(context, context->current, offset, size, 169 WINDOW_DIRTY); 170 } 171 172 static int generic_flush(struct mbox_context *context) 173 { 174 int rc, i, offset, count; 175 uint8_t prev; 176 177 offset = 0; 178 count = 0; 179 prev = WINDOW_CLEAN; 180 181 MSG_INFO("Flush window @ %p for size 0x%.8x which maps flash @ 0x%.8x\n", 182 context->current->mem, context->current->size, 183 context->current->flash_offset); 184 185 /* 186 * We look for streaks of the same type and keep a count, when the type 187 * (dirty/erased) changes we perform the required action on the backing 188 * store and update the current streak-type 189 */ 190 for (i = 0; i < (context->current->size >> context->block_size_shift); 191 i++) { 192 uint8_t cur = context->current->dirty_bmap[i]; 193 if (cur != WINDOW_CLEAN) { 194 if (cur == prev) { /* Same as previous block, incrmnt */ 195 count++; 196 } else if (prev == WINDOW_CLEAN) { /* Start of run */ 197 offset = i; 198 count++; 199 } else { /* Change in streak type */ 200 rc = window_flush(context, offset, count, 201 prev); 202 if (rc < 0) { 203 return rc; 204 } 205 offset = i; 206 count = 1; 207 } 208 } else { 209 if (prev != WINDOW_CLEAN) { /* End of a streak */ 210 rc = window_flush(context, offset, count, 211 prev); 212 if (rc < 0) { 213 return rc; 214 } 215 offset = 0; 216 count = 0; 217 } 218 } 219 prev = cur; 220 } 221 222 if (prev != WINDOW_CLEAN) { /* Still the last streak to write */ 223 rc = window_flush(context, offset, count, prev); 224 if (rc < 0) { 225 return rc; 226 } 227 } 228 229 /* Clear the dirty bytemap since we have written back all changes */ 230 return window_set_bytemap(context, context->current, 0, 231 context->current->size >> 232 context->block_size_shift, 233 WINDOW_CLEAN); 234 } 235 236 int protocol_v1_flush(struct mbox_context *context, struct protocol_flush *io) 237 { 238 int rc; 239 240 if (!(context->current && context->current_is_write)) { 241 MSG_ERR("Tried to call flush without open write window\n"); 242 return -EPERM; 243 } 244 245 /* 246 * For V1 the Flush command acts much the same as the dirty command 247 * except with a flush as well. Only do this on an actual flush 248 * command not when we call flush because we've implicitly closed a 249 * window because we might not have the required args in req. 250 */ 251 rc = protocol_v1_mark_dirty(context, (struct protocol_mark_dirty *)io); 252 if (rc < 0) { 253 return rc; 254 } 255 256 return generic_flush(context); 257 } 258 259 /* 260 * get_suggested_timeout() - get the suggested timeout value in seconds 261 * @context: The mbox context pointer 262 * 263 * Return: Suggested timeout in seconds 264 */ 265 static uint16_t get_suggested_timeout(struct mbox_context *context) 266 { 267 struct window_context *window = windows_find_largest(context); 268 uint32_t max_size_mb = window ? (window->size >> 20) : 0; 269 uint16_t ret; 270 271 ret = align_up(max_size_mb * FLASH_ACCESS_MS_PER_MB, 1000) / 1000; 272 273 MSG_DBG("Suggested Timeout: %us, max window size: %uMB, for %dms/MB\n", 274 ret, max_size_mb, FLASH_ACCESS_MS_PER_MB); 275 return ret; 276 } 277 278 int protocol_v2_get_info(struct mbox_context *context, 279 struct protocol_get_info *io) 280 { 281 uint8_t old_version = context->version; 282 int rc; 283 284 /* Bootstrap protocol version. This may involve {up,down}grading */ 285 rc = protocol_negotiate_version(context, io->req.api_version); 286 if (rc < 0) 287 return rc; 288 289 /* Do the {up,down}grade if necessary*/ 290 if (rc != old_version) { 291 windows_reset_all(context, SET_BMC_EVENT); 292 return context->protocol->get_info(context, io); 293 } 294 295 /* Record the negotiated version for the response */ 296 io->resp.api_version = rc; 297 298 /* Now do all required intialisation for v2 */ 299 context->block_size_shift = log_2(context->mtd_info.erasesize); 300 MSG_INFO("Block Size: 0x%.8x (shift: %u)\n", 301 1 << context->block_size_shift, context->block_size_shift); 302 303 /* Knowing blocksize we can allocate the window dirty_bytemap */ 304 windows_alloc_dirty_bytemap(context); 305 306 io->resp.v2.block_size_shift = context->block_size_shift; 307 io->resp.v2.timeout = get_suggested_timeout(context); 308 309 return lpc_map_memory(context); 310 } 311 312 int protocol_v2_get_flash_info(struct mbox_context *context, 313 struct protocol_get_flash_info *io) 314 { 315 io->resp.v2.flash_size = 316 context->flash_size >> context->block_size_shift; 317 io->resp.v2.erase_size = 318 context->mtd_info.erasesize >> context->block_size_shift; 319 320 return 0; 321 } 322 323 int protocol_v2_create_window(struct mbox_context *context, 324 struct protocol_create_window *io) 325 { 326 int rc; 327 328 rc = protocol_v1_create_window(context, io); 329 if (rc < 0) 330 return rc; 331 332 io->resp.size = context->current->size >> context->block_size_shift; 333 io->resp.offset = context->current->flash_offset >> 334 context->block_size_shift; 335 336 return 0; 337 } 338 339 int protocol_v2_mark_dirty(struct mbox_context *context, 340 struct protocol_mark_dirty *io) 341 { 342 if (!(context->current && context->current_is_write)) { 343 MSG_ERR("Tried to call mark dirty without open write window\n"); 344 return -EPERM; 345 } 346 347 MSG_INFO("Dirty window @ 0x%.8x for 0x%.8x\n", 348 io->req.v2.offset << context->block_size_shift, 349 io->req.v2.size << context->block_size_shift); 350 351 return window_set_bytemap(context, context->current, io->req.v2.offset, 352 io->req.v2.size, WINDOW_DIRTY); 353 } 354 355 int protocol_v2_erase(struct mbox_context *context, 356 struct protocol_erase *io) 357 { 358 size_t start, len; 359 int rc; 360 361 if (!(context->current && context->current_is_write)) { 362 MSG_ERR("Tried to call erase without open write window\n"); 363 return -EPERM; 364 } 365 366 MSG_INFO("Erase window @ 0x%.8x for 0x%.8x\n", 367 io->req.offset << context->block_size_shift, 368 io->req.size << context->block_size_shift); 369 370 rc = window_set_bytemap(context, context->current, io->req.offset, 371 io->req.size, WINDOW_ERASED); 372 if (rc < 0) { 373 return rc; 374 } 375 376 /* Write 0xFF to mem -> This ensures consistency between flash & ram */ 377 start = io->req.offset << context->block_size_shift; 378 len = io->req.size << context->block_size_shift; 379 memset(context->current->mem + start, 0xFF, len); 380 381 return 0; 382 } 383 384 int protocol_v2_flush(struct mbox_context *context, struct protocol_flush *io) 385 { 386 if (!(context->current && context->current_is_write)) { 387 MSG_ERR("Tried to call flush without open write window\n"); 388 return -EPERM; 389 } 390 391 return generic_flush(context); 392 } 393 394 static const struct protocol_ops protocol_ops_v1 = { 395 .reset = protocol_v1_reset, 396 .get_info = protocol_v1_get_info, 397 .get_flash_info = protocol_v1_get_flash_info, 398 .create_window = protocol_v1_create_window, 399 .mark_dirty = protocol_v1_mark_dirty, 400 .erase = NULL, 401 .flush = protocol_v1_flush, 402 }; 403 404 static const struct protocol_ops protocol_ops_v2 = { 405 .reset = protocol_v1_reset, 406 .get_info = protocol_v2_get_info, 407 .get_flash_info = protocol_v2_get_flash_info, 408 .create_window = protocol_v2_create_window, 409 .mark_dirty = protocol_v2_mark_dirty, 410 .erase = protocol_v2_erase, 411 .flush = protocol_v2_flush, 412 }; 413 414 static const struct protocol_ops *protocol_ops_map[] = { 415 [0] = NULL, 416 [1] = &protocol_ops_v1, 417 [2] = &protocol_ops_v2, 418 }; 419 420 int protocol_negotiate_version(struct mbox_context *context, 421 uint8_t requested) 422 { 423 /* Check we support the version requested */ 424 if (requested < API_MIN_VERSION) 425 return -EINVAL; 426 427 context->version = (requested > API_MAX_VERSION) ? 428 API_MAX_VERSION : requested; 429 430 context->protocol = protocol_ops_map[context->version]; 431 432 return context->version; 433 } 434 435 int protocol_init(struct mbox_context *context) 436 { 437 context->version = API_MAX_VERSION; 438 context->protocol = protocol_ops_map[context->version]; 439 440 return 0; 441 } 442 443 void protocol_free(struct mbox_context *context) 444 { 445 return; 446 } 447