blob: bd8e53a1a10686697a08f8e05a96bd20a18cf3e7 [file] [log] [blame]
AlexeiFedorov9f0dc012024-09-10 10:22:06 +01001/*
2 * Copyright (c) 2024, Arm Limited or its affiliates. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
Soby Mathew5929bfe2024-11-28 12:28:00 +00008#include <assert.h>
AlexeiFedorov9f0dc012024-09-10 10:22:06 +01009#include <errno.h>
Soby Mathew5929bfe2024-11-28 12:28:00 +000010#include <stdbool.h>
AlexeiFedorov9f2de632024-09-10 11:48:22 +010011#include <stdlib.h>
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010012#include <string.h>
AlexeiFedorov9f2de632024-09-10 11:48:22 +010013
14#include <debug.h>
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010015#include <pcie.h>
16#include <pcie_doe.h>
17#include <tftf_lib.h>
18
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010019static int pcie_doe_wait_ready(uint32_t bdf, uint32_t doe_cap_base)
20{
21 uint32_t value;
22
23 for (unsigned int i = 0; i < PCI_DOE_POLL_LOOP; i++) {
24 value = pcie_read_cfg(bdf, doe_cap_base + DOE_STATUS_REG);
25
26 if ((value & DOE_STATUS_BUSY_BIT) != 0) {
27 ERROR("DOE Busy bit is set\n");
28 return -EBUSY;
29 }
30
31 if ((value & DOE_STATUS_ERROR_BIT) != 0) {
32 ERROR("DOE Error bit is set\n");
33 return -EIO;
34 }
35
36 if ((value & DOE_STATUS_READY_BIT) != 0) {
37 return 0;
38 }
39
40 waitms(PCI_DOE_POLL_TIME);
41 }
42
43 ERROR("DOE Timeout, status 0x%x\n", value);
44 return -ETIMEDOUT;
45}
46
47static const char * const doe_object_type[] = {
48 "DOE Discovery",
49 "CMA-SPDM",
50 "Secured CMA-SPDM",
51 /* PCI Express Base Specification Revision 6.1 */
52 "CMA/SPDM with Connection ID",
53 "Secured CMA/SPDM with Connection ID",
54 "Async Message"
55};
56
57void print_doe_disc(pcie_doe_disc_resp_t *data)
58{
59 uint8_t type = data->data_object_type;
60
61 INFO("Vendor ID: 0x%x, ", data->vendor_id);
62
63 if (type >= ARRAY_SIZE(doe_object_type)) {
Soby Mathew5929bfe2024-11-28 12:28:00 +000064 INFO("Unknown type: 0x%x\n", type);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010065 } else {
Soby Mathew5929bfe2024-11-28 12:28:00 +000066 INFO("%s\n", doe_object_type[type]);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010067 }
68}
69
70static void print_doe_data(uint32_t idx, uint32_t data, bool last)
71{
72 uint32_t j = idx + DOE_HEADER_LENGTH;
73
74 if (last) {
75 if ((j & 7) == 0) {
Soby Mathew5929bfe2024-11-28 12:28:00 +000076 VERBOSE(" %08x\n", data);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010077 } else {
Soby Mathew5929bfe2024-11-28 12:28:00 +000078 VERBOSE(" %08x\n", data);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010079 }
80 } else if ((j & 7) == 0) {
Soby Mathew5929bfe2024-11-28 12:28:00 +000081 VERBOSE(" %08x", data);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010082 } else if ((j & 7) == 7) {
Soby Mathew5929bfe2024-11-28 12:28:00 +000083 VERBOSE(" %08x\n", data);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010084 } else {
Soby Mathew5929bfe2024-11-28 12:28:00 +000085 VERBOSE(" %08x", data);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010086 }
87}
88
89/*
90 * @brief This API sends DOE request to PCI device.
91 * @param bdf - concatenated Bus(8-bits), device(8-bits) & function(8-bits)
92 * @param doe_cap_base - DOE capability base offset
93 * @param *req_addr - DOE request payload buffer
94 * @param req_len - DOE request payload length in bytes
95 *
96 * @return 0 on success, negative code on failure
97 */
98int pcie_doe_send_req(uint32_t header, uint32_t bdf, uint32_t doe_cap_base,
99 uint32_t *req_addr, uint32_t req_len)
100{
101 uint32_t value, i, send_length, rem_length, doe_length;
102
103 value = pcie_read_cfg(bdf, doe_cap_base + DOE_STATUS_REG);
104 if ((value & DOE_STATUS_BUSY_BIT) != 0) {
105 ERROR("DOE Busy bit is set\n");
106 return -EBUSY;
107 }
108
109 if ((value & DOE_STATUS_ERROR_BIT) != 0) {
110 ERROR("DOE Error bit is set\n");
111 return -EIO;
112 }
113
114 send_length = req_len >> 2;
115 rem_length = req_len & 3;
116
117 /* Calculated adjusted data length in DW */
118 doe_length = (rem_length == 0) ? send_length : (send_length + 1);
119
Soby Mathew5929bfe2024-11-28 12:28:00 +0000120 VERBOSE(">%08x", header);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100121
122 pcie_write_cfg(bdf, doe_cap_base + DOE_WRITE_DATA_MAILBOX_REG,
123 header);
Soby Mathew5929bfe2024-11-28 12:28:00 +0000124 VERBOSE(" %08x", doe_length + DOE_HEADER_LENGTH);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100125
126 pcie_write_cfg(bdf, doe_cap_base + DOE_WRITE_DATA_MAILBOX_REG,
127 doe_length + DOE_HEADER_LENGTH);
128 /* Write data */
129 for (i = 0; i < send_length; i++) {
130 print_doe_data(i, req_addr[i], false);
131 pcie_write_cfg(bdf, doe_cap_base + DOE_WRITE_DATA_MAILBOX_REG,
132 req_addr[i]);
133 }
134
135 /* Check for remaining bytes */
136 if (rem_length != 0) {
137 value = 0;
138 (void)memcpy(&value, &req_addr[i], rem_length);
139 print_doe_data(i, value, true);
140 pcie_write_cfg(bdf, doe_cap_base + DOE_WRITE_DATA_MAILBOX_REG, value);
141
142 } else if (((i + DOE_HEADER_LENGTH) & 7) != 0) {
Soby Mathew5929bfe2024-11-28 12:28:00 +0000143 VERBOSE("\n");
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100144 }
145
146 /* Set Go bit */
147 pcie_write_cfg(bdf, doe_cap_base + DOE_CTRL_REG, DOE_CTRL_GO_BIT);
148 return 0;
149}
150
151/*
152 * @brief This API receives DOE response from PCI device.
153 * @param bdf - concatenated Bus(8-bits), device(8-bits) & function(8-bits)
154 * @param doe_cap_base - DOE capability base offset
155 * @param *resp_addr - DOE response payload buffer
156 * @param *resp_len - DOE response payload length in bytes
157 *
158 * @return 0 on success, negative code on failure
159 */
160int pcie_doe_recv_resp(uint32_t bdf, uint32_t doe_cap_base,
161 uint32_t *resp_addr, uint32_t *resp_len)
162{
163 uint32_t i, value, length;
164 int ret;
165
166 /* Wait for Ready bit */
167 ret = pcie_doe_wait_ready(bdf, doe_cap_base);
168 if (ret != 0) {
169 return ret;
170 }
171
172 /*
173 * Reading DOE Header 1:
174 * Vendor ID and Data Object Type
175 */
176 value = pcie_read_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG);
Soby Mathew5929bfe2024-11-28 12:28:00 +0000177 VERBOSE("<%08x", value);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100178
179 /* Indicate a successful transfer of the current data object DW */
180 pcie_write_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG, 0);
181
182 /*
183 * Reading DOE Header 2:
184 * Length in DW
185 */
186 value = pcie_read_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG);
Soby Mathew5929bfe2024-11-28 12:28:00 +0000187 VERBOSE(" %08x", value);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100188
189 pcie_write_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG, 0);
190
191 /* Check value */
192 if ((value & PCI_DOE_RESERVED_MASK) != 0) {
Soby Mathew5929bfe2024-11-28 12:28:00 +0000193 VERBOSE("\n");
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100194 ERROR("DOE Data Object Header 2 error\n");
195 return -EIO;
196 }
197
198 /* Value of 00000h indicates 2^18 DW */
199 length = (value != 0) ? (value - DOE_HEADER_LENGTH) :
200 (PCI_DOE_MAX_LENGTH - DOE_HEADER_LENGTH);
201
202 /* Response payload length in bytes */
203 *resp_len = length << 2;
204
205 for (i = 0; i < length; i++) {
206 value = pcie_read_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG);
207 *resp_addr++ = value;
208 print_doe_data(i, value, false);
209 pcie_write_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG, 0);
210 }
211
212 if (((i + DOE_HEADER_LENGTH) & 7) != 0) {
Soby Mathew5929bfe2024-11-28 12:28:00 +0000213 VERBOSE("\n");
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100214 }
215
216 value = pcie_read_cfg(bdf, doe_cap_base + DOE_STATUS_REG);
217 if ((value & (DOE_STATUS_READY_BIT | DOE_STATUS_ERROR_BIT)) != 0) {
218 ERROR("DOE Receive error, status 0x%x\n", value);
219 return -EIO;
220 }
221
222 return 0;
223}
Soby Mathew5929bfe2024-11-28 12:28:00 +0000224
225int pcie_doe_communicate(uint32_t header, uint32_t bdf, uint32_t doe_cap_base,
226 void *req_buf, size_t req_sz, void *rsp_buf, size_t *rsp_sz)
227{
228 int rc;
229
230 assert(header == DOE_HEADER_0 || header == DOE_HEADER_1 || header == DOE_HEADER_2);
231
232 rc = pcie_doe_send_req(header, bdf, doe_cap_base,
233 (uint32_t *)req_buf, (uint32_t)req_sz);
234 if (rc != 0) {
235 ERROR("PCIe DOE %s failed %d\n", "Request", rc);
236 return rc;
237 }
238
239 rc = pcie_doe_recv_resp(bdf, doe_cap_base, (uint32_t *)rsp_buf,
240 (uint32_t *)rsp_sz);
241 return rc;
242}
243
244int pcie_find_doe_device(uint32_t *bdf_ptr, uint32_t *cap_base_ptr)
245{
246 pcie_device_bdf_table_t *bdf_table_ptr = pcie_get_bdf_table();
247 uint32_t num_bdf = bdf_table_ptr->num_entries;
248
249 INFO("PCI BDF table entries: %u\n", num_bdf);
250
251 /* If no entries in BDF table return error */
252 if (num_bdf == 0) {
253 ERROR("No BDFs entries found\n");
254 return -ENODEV;
255 }
256
257 INFO("PCI BDF table 0x%lx\n", (uintptr_t)bdf_table_ptr);
258
259 while (num_bdf-- != 0) {
260 uint32_t bdf = bdf_table_ptr->device[num_bdf].bdf;
261 uint32_t status, doe_cap_base;
262
263 /* Check for DOE capability */
264 status = pcie_find_capability(bdf, PCIE_ECAP, DOE_CAP_ID, &doe_cap_base);
265 if (status == PCIE_SUCCESS) {
266 INFO("PCIe DOE capability: bdf 0x%x cap_base 0x%x\n", bdf, doe_cap_base);
267 *bdf_ptr = bdf;
268 *cap_base_ptr = doe_cap_base;
269 return 0;
270 }
271 }
272
273 ERROR("No PCIe DOE capability found\n");
274 return -ENODEV;
275}