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 if (io) { 252 struct protocol_mark_dirty *mdio = (void *)io; 253 rc = protocol_v1_mark_dirty(context, mdio); 254 if (rc < 0) { 255 return rc; 256 } 257 } 258 259 return generic_flush(context); 260 } 261 262 int protocol_v1_close(struct mbox_context *context, struct protocol_close *io) 263 { 264 int rc; 265 266 /* Close the current window if there is one */ 267 if (!context->current) { 268 return 0; 269 } 270 271 /* There is an implicit flush if it was a write window */ 272 if (context->current_is_write) { 273 rc = protocol_v1_flush(context, NULL); 274 if (rc < 0) { 275 MSG_ERR("Couldn't Flush Write Window\n"); 276 return rc; 277 } 278 } 279 280 /* Host asked for it -> Don't set the BMC Event */ 281 windows_close_current(context, NO_BMC_EVENT, io->req.flags); 282 283 return 0; 284 } 285 286 int protocol_v1_ack(struct mbox_context *context, struct protocol_ack *io) 287 { 288 return clr_bmc_events(context, (io->req.flags & BMC_EVENT_ACK_MASK), 289 SET_BMC_EVENT); 290 } 291 292 /* 293 * get_suggested_timeout() - get the suggested timeout value in seconds 294 * @context: The mbox context pointer 295 * 296 * Return: Suggested timeout in seconds 297 */ 298 static uint16_t get_suggested_timeout(struct mbox_context *context) 299 { 300 struct window_context *window = windows_find_largest(context); 301 uint32_t max_size_mb = window ? (window->size >> 20) : 0; 302 uint16_t ret; 303 304 ret = align_up(max_size_mb * FLASH_ACCESS_MS_PER_MB, 1000) / 1000; 305 306 MSG_DBG("Suggested Timeout: %us, max window size: %uMB, for %dms/MB\n", 307 ret, max_size_mb, FLASH_ACCESS_MS_PER_MB); 308 return ret; 309 } 310 311 int protocol_v2_get_info(struct mbox_context *context, 312 struct protocol_get_info *io) 313 { 314 uint8_t old_version = context->version; 315 int rc; 316 317 /* Bootstrap protocol version. This may involve {up,down}grading */ 318 rc = protocol_negotiate_version(context, io->req.api_version); 319 if (rc < 0) 320 return rc; 321 322 /* Do the {up,down}grade if necessary*/ 323 if (rc != old_version) { 324 windows_reset_all(context, SET_BMC_EVENT); 325 return context->protocol->get_info(context, io); 326 } 327 328 /* Record the negotiated version for the response */ 329 io->resp.api_version = rc; 330 331 /* Now do all required intialisation for v2 */ 332 context->block_size_shift = log_2(context->mtd_info.erasesize); 333 MSG_INFO("Block Size: 0x%.8x (shift: %u)\n", 334 1 << context->block_size_shift, context->block_size_shift); 335 336 /* Knowing blocksize we can allocate the window dirty_bytemap */ 337 windows_alloc_dirty_bytemap(context); 338 339 io->resp.v2.block_size_shift = context->block_size_shift; 340 io->resp.v2.timeout = get_suggested_timeout(context); 341 342 return lpc_map_memory(context); 343 } 344 345 int protocol_v2_get_flash_info(struct mbox_context *context, 346 struct protocol_get_flash_info *io) 347 { 348 io->resp.v2.flash_size = 349 context->flash_size >> context->block_size_shift; 350 io->resp.v2.erase_size = 351 context->mtd_info.erasesize >> context->block_size_shift; 352 353 return 0; 354 } 355 356 int protocol_v2_create_window(struct mbox_context *context, 357 struct protocol_create_window *io) 358 { 359 int rc; 360 361 rc = protocol_v1_create_window(context, io); 362 if (rc < 0) 363 return rc; 364 365 io->resp.size = context->current->size >> context->block_size_shift; 366 io->resp.offset = context->current->flash_offset >> 367 context->block_size_shift; 368 369 return 0; 370 } 371 372 int protocol_v2_mark_dirty(struct mbox_context *context, 373 struct protocol_mark_dirty *io) 374 { 375 if (!(context->current && context->current_is_write)) { 376 MSG_ERR("Tried to call mark dirty without open write window\n"); 377 return -EPERM; 378 } 379 380 MSG_INFO("Dirty window @ 0x%.8x for 0x%.8x\n", 381 io->req.v2.offset << context->block_size_shift, 382 io->req.v2.size << context->block_size_shift); 383 384 return window_set_bytemap(context, context->current, io->req.v2.offset, 385 io->req.v2.size, WINDOW_DIRTY); 386 } 387 388 int protocol_v2_erase(struct mbox_context *context, 389 struct protocol_erase *io) 390 { 391 size_t start, len; 392 int rc; 393 394 if (!(context->current && context->current_is_write)) { 395 MSG_ERR("Tried to call erase without open write window\n"); 396 return -EPERM; 397 } 398 399 MSG_INFO("Erase window @ 0x%.8x for 0x%.8x\n", 400 io->req.offset << context->block_size_shift, 401 io->req.size << context->block_size_shift); 402 403 rc = window_set_bytemap(context, context->current, io->req.offset, 404 io->req.size, WINDOW_ERASED); 405 if (rc < 0) { 406 return rc; 407 } 408 409 /* Write 0xFF to mem -> This ensures consistency between flash & ram */ 410 start = io->req.offset << context->block_size_shift; 411 len = io->req.size << context->block_size_shift; 412 memset(context->current->mem + start, 0xFF, len); 413 414 return 0; 415 } 416 417 int protocol_v2_flush(struct mbox_context *context, struct protocol_flush *io) 418 { 419 if (!(context->current && context->current_is_write)) { 420 MSG_ERR("Tried to call flush without open write window\n"); 421 return -EPERM; 422 } 423 424 return generic_flush(context); 425 } 426 427 int protocol_v2_close(struct mbox_context *context, struct protocol_close *io) 428 { 429 int rc; 430 431 /* Close the current window if there is one */ 432 if (!context->current) { 433 return 0; 434 } 435 436 /* There is an implicit flush if it was a write window */ 437 if (context->current_is_write) { 438 rc = protocol_v2_flush(context, NULL); 439 if (rc < 0) { 440 MSG_ERR("Couldn't Flush Write Window\n"); 441 return rc; 442 } 443 } 444 445 /* Host asked for it -> Don't set the BMC Event */ 446 windows_close_current(context, NO_BMC_EVENT, io->req.flags); 447 448 return 0; 449 } 450 451 int protocol_init(struct mbox_context *context) 452 { 453 protocol_negotiate_version(context, API_MAX_VERSION); 454 455 return 0; 456 } 457 458 void protocol_free(struct mbox_context *context) 459 { 460 return; 461 } 462