blob: 066c5b2bc3b286bc5120497d9d977118b079607e [file] [log] [blame]
Andrew Jeffery1e531af2018-08-07 13:32:57 +09301// 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
Andrew Jefferyab666a52018-08-07 14:28:09 +093013int 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
Andrew Jeffery1e531af2018-08-07 13:32:57 +093020int 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
Andrew Jeffery91a87452018-08-07 14:54:14 +093056int 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
Andrew Jeffery1e531af2018-08-07 13:32:57 +093065/*
66 * get_suggested_timeout() - get the suggested timeout value in seconds
67 * @context: The mbox context pointer
68 *
69 * Return: Suggested timeout in seconds
70 */
71static uint16_t get_suggested_timeout(struct mbox_context *context)
72{
73 struct window_context *window = windows_find_largest(context);
74 uint32_t max_size_mb = window ? (window->size >> 20) : 0;
75 uint16_t ret;
76
77 ret = align_up(max_size_mb * FLASH_ACCESS_MS_PER_MB, 1000) / 1000;
78
79 MSG_DBG("Suggested Timeout: %us, max window size: %uMB, for %dms/MB\n",
80 ret, max_size_mb, FLASH_ACCESS_MS_PER_MB);
81 return ret;
82}
83
84int protocol_v2_get_info(struct mbox_context *context,
85 struct protocol_get_info *io)
86{
87 uint8_t old_version = context->version;
88 int rc;
89
90 /* Bootstrap protocol version. This may involve {up,down}grading */
91 rc = protocol_negotiate_version(context, io->req.api_version);
92 if (rc < 0)
93 return rc;
94
95 /* Do the {up,down}grade if necessary*/
96 if (rc != old_version) {
97 windows_reset_all(context, SET_BMC_EVENT);
98 return context->protocol->get_info(context, io);
99 }
100
101 /* Record the negotiated version for the response */
102 io->resp.api_version = rc;
103
104 /* Now do all required intialisation for v2 */
105 context->block_size_shift = log_2(context->mtd_info.erasesize);
106 MSG_INFO("Block Size: 0x%.8x (shift: %u)\n",
107 1 << context->block_size_shift, context->block_size_shift);
108
109 /* Knowing blocksize we can allocate the window dirty_bytemap */
110 windows_alloc_dirty_bytemap(context);
111
112 io->resp.v2.block_size_shift = context->block_size_shift;
113 io->resp.v2.timeout = get_suggested_timeout(context);
114
115 return lpc_map_memory(context);
116}
117
Andrew Jeffery91a87452018-08-07 14:54:14 +0930118int protocol_v2_get_flash_info(struct mbox_context *context,
119 struct protocol_get_flash_info *io)
120{
121 io->resp.v2.flash_size =
122 context->flash_size >> context->block_size_shift;
123 io->resp.v2.erase_size =
124 context->mtd_info.erasesize >> context->block_size_shift;
125
126 return 0;
127}
128
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930129static const struct protocol_ops protocol_ops_v1 = {
Andrew Jefferyab666a52018-08-07 14:28:09 +0930130 .reset = protocol_v1_reset,
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930131 .get_info = protocol_v1_get_info,
Andrew Jeffery91a87452018-08-07 14:54:14 +0930132 .get_flash_info = protocol_v1_get_flash_info,
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930133};
134
135static const struct protocol_ops protocol_ops_v2 = {
Andrew Jefferyab666a52018-08-07 14:28:09 +0930136 .reset = protocol_v1_reset,
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930137 .get_info = protocol_v2_get_info,
Andrew Jeffery91a87452018-08-07 14:54:14 +0930138 .get_flash_info = protocol_v2_get_flash_info,
Andrew Jeffery1e531af2018-08-07 13:32:57 +0930139};
140
141static const struct protocol_ops *protocol_ops_map[] = {
142 [0] = NULL,
143 [1] = &protocol_ops_v1,
144 [2] = &protocol_ops_v2,
145};
146
147int protocol_negotiate_version(struct mbox_context *context,
148 uint8_t requested)
149{
150 /* Check we support the version requested */
151 if (requested < API_MIN_VERSION)
152 return -EINVAL;
153
154 context->version = (requested > API_MAX_VERSION) ?
155 API_MAX_VERSION : requested;
156
157 context->protocol = protocol_ops_map[context->version];
158
159 return context->version;
160}
161
162int protocol_init(struct mbox_context *context)
163{
164 context->version = API_MAX_VERSION;
165 context->protocol = protocol_ops_map[context->version];
166
167 return 0;
168}
169
170void protocol_free(struct mbox_context *context)
171{
172 return;
173}