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 /* 57 * get_suggested_timeout() - get the suggested timeout value in seconds 58 * @context: The mbox context pointer 59 * 60 * Return: Suggested timeout in seconds 61 */ 62 static uint16_t get_suggested_timeout(struct mbox_context *context) 63 { 64 struct window_context *window = windows_find_largest(context); 65 uint32_t max_size_mb = window ? (window->size >> 20) : 0; 66 uint16_t ret; 67 68 ret = align_up(max_size_mb * FLASH_ACCESS_MS_PER_MB, 1000) / 1000; 69 70 MSG_DBG("Suggested Timeout: %us, max window size: %uMB, for %dms/MB\n", 71 ret, max_size_mb, FLASH_ACCESS_MS_PER_MB); 72 return ret; 73 } 74 75 int protocol_v2_get_info(struct mbox_context *context, 76 struct protocol_get_info *io) 77 { 78 uint8_t old_version = context->version; 79 int rc; 80 81 /* Bootstrap protocol version. This may involve {up,down}grading */ 82 rc = protocol_negotiate_version(context, io->req.api_version); 83 if (rc < 0) 84 return rc; 85 86 /* Do the {up,down}grade if necessary*/ 87 if (rc != old_version) { 88 windows_reset_all(context, SET_BMC_EVENT); 89 return context->protocol->get_info(context, io); 90 } 91 92 /* Record the negotiated version for the response */ 93 io->resp.api_version = rc; 94 95 /* Now do all required intialisation for v2 */ 96 context->block_size_shift = log_2(context->mtd_info.erasesize); 97 MSG_INFO("Block Size: 0x%.8x (shift: %u)\n", 98 1 << context->block_size_shift, context->block_size_shift); 99 100 /* Knowing blocksize we can allocate the window dirty_bytemap */ 101 windows_alloc_dirty_bytemap(context); 102 103 io->resp.v2.block_size_shift = context->block_size_shift; 104 io->resp.v2.timeout = get_suggested_timeout(context); 105 106 return lpc_map_memory(context); 107 } 108 109 static const struct protocol_ops protocol_ops_v1 = { 110 .reset = protocol_v1_reset, 111 .get_info = protocol_v1_get_info, 112 }; 113 114 static const struct protocol_ops protocol_ops_v2 = { 115 .reset = protocol_v1_reset, 116 .get_info = protocol_v2_get_info, 117 }; 118 119 static const struct protocol_ops *protocol_ops_map[] = { 120 [0] = NULL, 121 [1] = &protocol_ops_v1, 122 [2] = &protocol_ops_v2, 123 }; 124 125 int protocol_negotiate_version(struct mbox_context *context, 126 uint8_t requested) 127 { 128 /* Check we support the version requested */ 129 if (requested < API_MIN_VERSION) 130 return -EINVAL; 131 132 context->version = (requested > API_MAX_VERSION) ? 133 API_MAX_VERSION : requested; 134 135 context->protocol = protocol_ops_map[context->version]; 136 137 return context->version; 138 } 139 140 int protocol_init(struct mbox_context *context) 141 { 142 context->version = API_MAX_VERSION; 143 context->protocol = protocol_ops_map[context->version]; 144 145 return 0; 146 } 147 148 void protocol_free(struct mbox_context *context) 149 { 150 return; 151 } 152