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