blob: 3c6819cb3272cf8e366ac0527572f4da758cb4ec [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
AlexeiFedorov9f0dc012024-09-10 10:22:06 +01008#include <errno.h>
AlexeiFedorov9f2de632024-09-10 11:48:22 +01009#include <stdlib.h>
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010010#include <string.h>
AlexeiFedorov9f2de632024-09-10 11:48:22 +010011
12#include <debug.h>
AlexeiFedorov9f0dc012024-09-10 10:22:06 +010013#include <pcie.h>
14#include <pcie_doe.h>
15#include <tftf_lib.h>
16
17#if LOG_LEVEL >= LOG_LEVEL_INFO
18#define DOE_INFO(...) mp_printf(__VA_ARGS__)
19#else
20#define DOE_INFO(...)
21#endif
22
23static int pcie_doe_wait_ready(uint32_t bdf, uint32_t doe_cap_base)
24{
25 uint32_t value;
26
27 for (unsigned int i = 0; i < PCI_DOE_POLL_LOOP; i++) {
28 value = pcie_read_cfg(bdf, doe_cap_base + DOE_STATUS_REG);
29
30 if ((value & DOE_STATUS_BUSY_BIT) != 0) {
31 ERROR("DOE Busy bit is set\n");
32 return -EBUSY;
33 }
34
35 if ((value & DOE_STATUS_ERROR_BIT) != 0) {
36 ERROR("DOE Error bit is set\n");
37 return -EIO;
38 }
39
40 if ((value & DOE_STATUS_READY_BIT) != 0) {
41 return 0;
42 }
43
44 waitms(PCI_DOE_POLL_TIME);
45 }
46
47 ERROR("DOE Timeout, status 0x%x\n", value);
48 return -ETIMEDOUT;
49}
50
51static const char * const doe_object_type[] = {
52 "DOE Discovery",
53 "CMA-SPDM",
54 "Secured CMA-SPDM",
55 /* PCI Express Base Specification Revision 6.1 */
56 "CMA/SPDM with Connection ID",
57 "Secured CMA/SPDM with Connection ID",
58 "Async Message"
59};
60
61void print_doe_disc(pcie_doe_disc_resp_t *data)
62{
63 uint8_t type = data->data_object_type;
64
65 INFO("Vendor ID: 0x%x, ", data->vendor_id);
66
67 if (type >= ARRAY_SIZE(doe_object_type)) {
68 DOE_INFO("Unknown type: 0x%x\n", type);
69 } else {
70 DOE_INFO("%s\n", doe_object_type[type]);
71 }
72}
73
74static void print_doe_data(uint32_t idx, uint32_t data, bool last)
75{
76 uint32_t j = idx + DOE_HEADER_LENGTH;
77
78 if (last) {
79 if ((j & 7) == 0) {
80 INFO(" %08x\n", data);
81 } else {
82 DOE_INFO(" %08x\n", data);
83 }
84 } else if ((j & 7) == 0) {
85 INFO(" %08x", data);
86 } else if ((j & 7) == 7) {
87 DOE_INFO(" %08x\n", data);
88 } else {
89 DOE_INFO(" %08x", data);
90 }
91}
92
93/*
94 * @brief This API sends DOE request to PCI device.
95 * @param bdf - concatenated Bus(8-bits), device(8-bits) & function(8-bits)
96 * @param doe_cap_base - DOE capability base offset
97 * @param *req_addr - DOE request payload buffer
98 * @param req_len - DOE request payload length in bytes
99 *
100 * @return 0 on success, negative code on failure
101 */
102int pcie_doe_send_req(uint32_t header, uint32_t bdf, uint32_t doe_cap_base,
103 uint32_t *req_addr, uint32_t req_len)
104{
105 uint32_t value, i, send_length, rem_length, doe_length;
106
107 value = pcie_read_cfg(bdf, doe_cap_base + DOE_STATUS_REG);
108 if ((value & DOE_STATUS_BUSY_BIT) != 0) {
109 ERROR("DOE Busy bit is set\n");
110 return -EBUSY;
111 }
112
113 if ((value & DOE_STATUS_ERROR_BIT) != 0) {
114 ERROR("DOE Error bit is set\n");
115 return -EIO;
116 }
117
118 send_length = req_len >> 2;
119 rem_length = req_len & 3;
120
121 /* Calculated adjusted data length in DW */
122 doe_length = (rem_length == 0) ? send_length : (send_length + 1);
123
124 INFO(">%08x", header);
125
126 pcie_write_cfg(bdf, doe_cap_base + DOE_WRITE_DATA_MAILBOX_REG,
127 header);
128 DOE_INFO(" %08x", doe_length + DOE_HEADER_LENGTH);
129
130 pcie_write_cfg(bdf, doe_cap_base + DOE_WRITE_DATA_MAILBOX_REG,
131 doe_length + DOE_HEADER_LENGTH);
132 /* Write data */
133 for (i = 0; i < send_length; i++) {
134 print_doe_data(i, req_addr[i], false);
135 pcie_write_cfg(bdf, doe_cap_base + DOE_WRITE_DATA_MAILBOX_REG,
136 req_addr[i]);
137 }
138
139 /* Check for remaining bytes */
140 if (rem_length != 0) {
141 value = 0;
142 (void)memcpy(&value, &req_addr[i], rem_length);
143 print_doe_data(i, value, true);
144 pcie_write_cfg(bdf, doe_cap_base + DOE_WRITE_DATA_MAILBOX_REG, value);
145
146 } else if (((i + DOE_HEADER_LENGTH) & 7) != 0) {
147 DOE_INFO("\n");
148 }
149
150 /* Set Go bit */
151 pcie_write_cfg(bdf, doe_cap_base + DOE_CTRL_REG, DOE_CTRL_GO_BIT);
152 return 0;
153}
154
155/*
156 * @brief This API receives DOE response from PCI device.
157 * @param bdf - concatenated Bus(8-bits), device(8-bits) & function(8-bits)
158 * @param doe_cap_base - DOE capability base offset
159 * @param *resp_addr - DOE response payload buffer
160 * @param *resp_len - DOE response payload length in bytes
161 *
162 * @return 0 on success, negative code on failure
163 */
164int pcie_doe_recv_resp(uint32_t bdf, uint32_t doe_cap_base,
165 uint32_t *resp_addr, uint32_t *resp_len)
166{
167 uint32_t i, value, length;
168 int ret;
169
170 /* Wait for Ready bit */
171 ret = pcie_doe_wait_ready(bdf, doe_cap_base);
172 if (ret != 0) {
173 return ret;
174 }
175
176 /*
177 * Reading DOE Header 1:
178 * Vendor ID and Data Object Type
179 */
180 value = pcie_read_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG);
181 INFO("<%08x", value);
182
183 /* Indicate a successful transfer of the current data object DW */
184 pcie_write_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG, 0);
185
186 /*
187 * Reading DOE Header 2:
188 * Length in DW
189 */
190 value = pcie_read_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG);
191 DOE_INFO(" %08x", value);
192
193 pcie_write_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG, 0);
194
195 /* Check value */
196 if ((value & PCI_DOE_RESERVED_MASK) != 0) {
197 DOE_INFO("\n");
198 ERROR("DOE Data Object Header 2 error\n");
199 return -EIO;
200 }
201
202 /* Value of 00000h indicates 2^18 DW */
203 length = (value != 0) ? (value - DOE_HEADER_LENGTH) :
204 (PCI_DOE_MAX_LENGTH - DOE_HEADER_LENGTH);
205
206 /* Response payload length in bytes */
207 *resp_len = length << 2;
208
209 for (i = 0; i < length; i++) {
210 value = pcie_read_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG);
211 *resp_addr++ = value;
212 print_doe_data(i, value, false);
213 pcie_write_cfg(bdf, doe_cap_base + DOE_READ_DATA_MAILBOX_REG, 0);
214 }
215
216 if (((i + DOE_HEADER_LENGTH) & 7) != 0) {
217 DOE_INFO("\n");
218 }
219
220 value = pcie_read_cfg(bdf, doe_cap_base + DOE_STATUS_REG);
221 if ((value & (DOE_STATUS_READY_BIT | DOE_STATUS_ERROR_BIT)) != 0) {
222 ERROR("DOE Receive error, status 0x%x\n", value);
223 return -EIO;
224 }
225
226 return 0;
227}