blob: e1d644949dac7eb425fd161b4f930fa5d7c54cea [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>
Arunachalam Ganapathy73005a62025-07-01 10:37:15 +010016#include <pcie_spec.h>
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010017#include <pcie_doe.h>
18#include <tftf_lib.h>
19
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010020static int pcie_doe_wait_ready(uint32_t bdf, uint32_t doe_cap_base)
21{
22 uint32_t value;
23
24 for (unsigned int i = 0; i < PCI_DOE_POLL_LOOP; i++) {
25 value = pcie_read_cfg(bdf, doe_cap_base + DOE_STATUS_REG);
26
27 if ((value & DOE_STATUS_BUSY_BIT) != 0) {
28 ERROR("DOE Busy bit is set\n");
29 return -EBUSY;
30 }
31
32 if ((value & DOE_STATUS_ERROR_BIT) != 0) {
33 ERROR("DOE Error bit is set\n");
34 return -EIO;
35 }
36
37 if ((value & DOE_STATUS_READY_BIT) != 0) {
38 return 0;
39 }
40
41 waitms(PCI_DOE_POLL_TIME);
42 }
43
44 ERROR("DOE Timeout, status 0x%x\n", value);
45 return -ETIMEDOUT;
46}
47
48static const char * const doe_object_type[] = {
49 "DOE Discovery",
50 "CMA-SPDM",
51 "Secured CMA-SPDM",
52 /* PCI Express Base Specification Revision 6.1 */
53 "CMA/SPDM with Connection ID",
54 "Secured CMA/SPDM with Connection ID",
55 "Async Message"
56};
57
58void print_doe_disc(pcie_doe_disc_resp_t *data)
59{
60 uint8_t type = data->data_object_type;
61
62 INFO("Vendor ID: 0x%x, ", data->vendor_id);
63
64 if (type >= ARRAY_SIZE(doe_object_type)) {
Soby Mathew5929bfe2024-11-28 12:28:00 +000065 INFO("Unknown type: 0x%x\n", type);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010066 } else {
Soby Mathew5929bfe2024-11-28 12:28:00 +000067 INFO("%s\n", doe_object_type[type]);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010068 }
69}
70
71static void print_doe_data(uint32_t idx, uint32_t data, bool last)
72{
73 uint32_t j = idx + DOE_HEADER_LENGTH;
74
75 if (last) {
76 if ((j & 7) == 0) {
Soby Mathew5929bfe2024-11-28 12:28:00 +000077 VERBOSE(" %08x\n", data);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010078 } else {
Soby Mathew5929bfe2024-11-28 12:28:00 +000079 VERBOSE(" %08x\n", data);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010080 }
81 } else if ((j & 7) == 0) {
Soby Mathew5929bfe2024-11-28 12:28:00 +000082 VERBOSE(" %08x", data);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010083 } else if ((j & 7) == 7) {
Soby Mathew5929bfe2024-11-28 12:28:00 +000084 VERBOSE(" %08x\n", data);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010085 } else {
Soby Mathew5929bfe2024-11-28 12:28:00 +000086 VERBOSE(" %08x", data);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010087 }
88}
89
90/*
91 * @brief This API sends DOE request to PCI device.
92 * @param bdf - concatenated Bus(8-bits), device(8-bits) & function(8-bits)
93 * @param doe_cap_base - DOE capability base offset
94 * @param *req_addr - DOE request payload buffer
95 * @param req_len - DOE request payload length in bytes
96 *
97 * @return 0 on success, negative code on failure
98 */
99int pcie_doe_send_req(uint32_t header, uint32_t bdf, uint32_t doe_cap_base,
100 uint32_t *req_addr, uint32_t req_len)
101{
102 uint32_t value, i, send_length, rem_length, doe_length;
103
104 value = pcie_read_cfg(bdf, doe_cap_base + DOE_STATUS_REG);
105 if ((value & DOE_STATUS_BUSY_BIT) != 0) {
106 ERROR("DOE Busy bit is set\n");
107 return -EBUSY;
108 }
109
110 if ((value & DOE_STATUS_ERROR_BIT) != 0) {
111 ERROR("DOE Error bit is set\n");
112 return -EIO;
113 }
114
115 send_length = req_len >> 2;
116 rem_length = req_len & 3;
117
118 /* Calculated adjusted data length in DW */
119 doe_length = (rem_length == 0) ? send_length : (send_length + 1);
120
Soby Mathew5929bfe2024-11-28 12:28:00 +0000121 VERBOSE(">%08x", header);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100122
123 pcie_write_cfg(bdf, doe_cap_base + DOE_WRITE_DATA_MAILBOX_REG,
124 header);
Soby Mathew5929bfe2024-11-28 12:28:00 +0000125 VERBOSE(" %08x", doe_length + DOE_HEADER_LENGTH);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100126
127 pcie_write_cfg(bdf, doe_cap_base + DOE_WRITE_DATA_MAILBOX_REG,
128 doe_length + DOE_HEADER_LENGTH);
129 /* Write data */
130 for (i = 0; i < send_length; i++) {
131 print_doe_data(i, req_addr[i], false);
132 pcie_write_cfg(bdf, doe_cap_base + DOE_WRITE_DATA_MAILBOX_REG,
133 req_addr[i]);
134 }
135
136 /* Check for remaining bytes */
137 if (rem_length != 0) {
138 value = 0;
139 (void)memcpy(&value, &req_addr[i], rem_length);
140 print_doe_data(i, value, true);
141 pcie_write_cfg(bdf, doe_cap_base + DOE_WRITE_DATA_MAILBOX_REG, value);
142
143 } else if (((i + DOE_HEADER_LENGTH) & 7) != 0) {
Soby Mathew5929bfe2024-11-28 12:28:00 +0000144 VERBOSE("\n");
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100145 }
146
147 /* Set Go bit */
148 pcie_write_cfg(bdf, doe_cap_base + DOE_CTRL_REG, DOE_CTRL_GO_BIT);
149 return 0;
150}
151
152/*
153 * @brief This API receives DOE response from PCI device.
154 * @param bdf - concatenated Bus(8-bits), device(8-bits) & function(8-bits)
155 * @param doe_cap_base - DOE capability base offset
156 * @param *resp_addr - DOE response payload buffer
157 * @param *resp_len - DOE response payload length in bytes
158 *
159 * @return 0 on success, negative code on failure
160 */
161int pcie_doe_recv_resp(uint32_t bdf, uint32_t doe_cap_base,
162 uint32_t *resp_addr, uint32_t *resp_len)
163{
164 uint32_t i, value, length;
165 int ret;
166
167 /* Wait for Ready bit */
168 ret = pcie_doe_wait_ready(bdf, doe_cap_base);
169 if (ret != 0) {
170 return ret;
171 }
172
173 /*
174 * Reading DOE Header 1:
175 * Vendor ID and Data Object Type
176 */
177 value = pcie_read_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG);
Soby Mathew5929bfe2024-11-28 12:28:00 +0000178 VERBOSE("<%08x", value);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100179
180 /* Indicate a successful transfer of the current data object DW */
181 pcie_write_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG, 0);
182
183 /*
184 * Reading DOE Header 2:
185 * Length in DW
186 */
187 value = pcie_read_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG);
Soby Mathew5929bfe2024-11-28 12:28:00 +0000188 VERBOSE(" %08x", value);
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100189
190 pcie_write_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG, 0);
191
192 /* Check value */
193 if ((value & PCI_DOE_RESERVED_MASK) != 0) {
Soby Mathew5929bfe2024-11-28 12:28:00 +0000194 VERBOSE("\n");
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100195 ERROR("DOE Data Object Header 2 error\n");
196 return -EIO;
197 }
198
199 /* Value of 00000h indicates 2^18 DW */
200 length = (value != 0) ? (value - DOE_HEADER_LENGTH) :
201 (PCI_DOE_MAX_LENGTH - DOE_HEADER_LENGTH);
202
203 /* Response payload length in bytes */
204 *resp_len = length << 2;
205
206 for (i = 0; i < length; i++) {
207 value = pcie_read_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG);
208 *resp_addr++ = value;
209 print_doe_data(i, value, false);
210 pcie_write_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG, 0);
211 }
212
213 if (((i + DOE_HEADER_LENGTH) & 7) != 0) {
Soby Mathew5929bfe2024-11-28 12:28:00 +0000214 VERBOSE("\n");
AlexeiFedorov9f0dc012024-09-10 10:22:06 +0100215 }
216
217 value = pcie_read_cfg(bdf, doe_cap_base + DOE_STATUS_REG);
218 if ((value & (DOE_STATUS_READY_BIT | DOE_STATUS_ERROR_BIT)) != 0) {
219 ERROR("DOE Receive error, status 0x%x\n", value);
220 return -EIO;
221 }
222
223 return 0;
224}
Soby Mathew5929bfe2024-11-28 12:28:00 +0000225
226int pcie_doe_communicate(uint32_t header, uint32_t bdf, uint32_t doe_cap_base,
227 void *req_buf, size_t req_sz, void *rsp_buf, size_t *rsp_sz)
228{
229 int rc;
230
231 assert(header == DOE_HEADER_0 || header == DOE_HEADER_1 || header == DOE_HEADER_2);
232
233 rc = pcie_doe_send_req(header, bdf, doe_cap_base,
234 (uint32_t *)req_buf, (uint32_t)req_sz);
235 if (rc != 0) {
236 ERROR("PCIe DOE %s failed %d\n", "Request", rc);
237 return rc;
238 }
239
240 rc = pcie_doe_recv_resp(bdf, doe_cap_base, (uint32_t *)rsp_buf,
241 (uint32_t *)rsp_sz);
242 return rc;
243}
244
Arunachalam Ganapathy73005a62025-07-01 10:37:15 +0100245/* TODO: add an iterator interface to get next eligible device */
Soby Mathew5929bfe2024-11-28 12:28:00 +0000246int pcie_find_doe_device(uint32_t *bdf_ptr, uint32_t *cap_base_ptr)
247{
248 pcie_device_bdf_table_t *bdf_table_ptr = pcie_get_bdf_table();
249 uint32_t num_bdf = bdf_table_ptr->num_entries;
Arunachalam Ganapathy73005a62025-07-01 10:37:15 +0100250 pcie_dev_t *dev;
Soby Mathew5929bfe2024-11-28 12:28:00 +0000251
252 INFO("PCI BDF table entries: %u\n", num_bdf);
253
254 /* If no entries in BDF table return error */
255 if (num_bdf == 0) {
256 ERROR("No BDFs entries found\n");
257 return -ENODEV;
258 }
259
260 INFO("PCI BDF table 0x%lx\n", (uintptr_t)bdf_table_ptr);
261
262 while (num_bdf-- != 0) {
Arunachalam Ganapathy73005a62025-07-01 10:37:15 +0100263 dev = &bdf_table_ptr->device[num_bdf];
Soby Mathew5929bfe2024-11-28 12:28:00 +0000264
Arunachalam Ganapathy73005a62025-07-01 10:37:15 +0100265 if ((dev->dp_type == EP) && (pcie_dev_has_doe(dev))) {
266 INFO("PCIe DOE capability: bdf 0x%x cap_base 0x%x\n",
267 dev->bdf, dev->doe_cap_base);
268 *bdf_ptr = dev->bdf;
269 *cap_base_ptr = dev->doe_cap_base;
Soby Mathew5929bfe2024-11-28 12:28:00 +0000270 return 0;
271 }
272 }
273
274 ERROR("No PCIe DOE capability found\n");
275 return -ENODEV;
276}