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