Merge tag 'pull-loongarch-20241016' of https://gitlab.com/gaosong/qemu into staging
[qemu/armbru.git] / hw / pci / pcie_doe.c
blob2210f8696812b290dd858d64611dc1ea22a8095a
1 /*
2 * PCIe Data Object Exchange
4 * Copyright (C) 2021 Avery Design Systems, Inc.
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
8 */
10 #include "qemu/osdep.h"
11 #include "qemu/log.h"
12 #include "qemu/error-report.h"
13 #include "qapi/error.h"
14 #include "qemu/range.h"
15 #include "hw/pci/pci.h"
16 #include "hw/pci/pcie.h"
17 #include "hw/pci/pcie_doe.h"
18 #include "hw/pci/msi.h"
19 #include "hw/pci/msix.h"
21 #define DWORD_BYTE 4
23 typedef struct DoeDiscoveryReq {
24 DOEHeader header;
25 uint8_t index;
26 uint8_t reserved[3];
27 } QEMU_PACKED DoeDiscoveryReq;
29 typedef struct DoeDiscoveryRsp {
30 DOEHeader header;
31 uint16_t vendor_id;
32 uint8_t data_obj_type;
33 uint8_t next_index;
34 } QEMU_PACKED DoeDiscoveryRsp;
36 static bool pcie_doe_discovery(DOECap *doe_cap)
38 DoeDiscoveryReq *req = pcie_doe_get_write_mbox_ptr(doe_cap);
39 DoeDiscoveryRsp rsp;
40 uint8_t index = req->index;
41 DOEProtocol *prot;
43 /* Discard request if length does not match DoeDiscoveryReq */
44 if (pcie_doe_get_obj_len(req) <
45 DIV_ROUND_UP(sizeof(DoeDiscoveryReq), DWORD_BYTE)) {
46 return false;
49 rsp.header = (DOEHeader) {
50 .vendor_id = PCI_VENDOR_ID_PCI_SIG,
51 .data_obj_type = PCI_SIG_DOE_DISCOVERY,
52 .length = DIV_ROUND_UP(sizeof(DoeDiscoveryRsp), DWORD_BYTE),
55 /* Point to the requested protocol, index 0 must be Discovery */
56 if (index == 0) {
57 rsp.vendor_id = PCI_VENDOR_ID_PCI_SIG;
58 rsp.data_obj_type = PCI_SIG_DOE_DISCOVERY;
59 } else {
60 if (index < doe_cap->protocol_num) {
61 prot = &doe_cap->protocols[index - 1];
62 rsp.vendor_id = prot->vendor_id;
63 rsp.data_obj_type = prot->data_obj_type;
64 } else {
65 rsp.vendor_id = 0xFFFF;
66 rsp.data_obj_type = 0xFF;
70 if (index + 1 == doe_cap->protocol_num) {
71 rsp.next_index = 0;
72 } else {
73 rsp.next_index = index + 1;
76 pcie_doe_set_rsp(doe_cap, &rsp);
78 return true;
81 static void pcie_doe_reset_mbox(DOECap *st)
83 st->read_mbox_idx = 0;
84 st->read_mbox_len = 0;
85 st->write_mbox_len = 0;
87 memset(st->read_mbox, 0, PCI_DOE_DW_SIZE_MAX * DWORD_BYTE);
88 memset(st->write_mbox, 0, PCI_DOE_DW_SIZE_MAX * DWORD_BYTE);
91 void pcie_doe_init(PCIDevice *dev, DOECap *doe_cap, uint16_t offset,
92 DOEProtocol *protocols, bool intr, uint16_t vec)
94 pcie_add_capability(dev, PCI_EXT_CAP_ID_DOE, 0x1, offset,
95 PCI_DOE_SIZEOF);
97 doe_cap->pdev = dev;
98 doe_cap->offset = offset;
100 if (intr && (msi_present(dev) || msix_present(dev))) {
101 doe_cap->cap.intr = intr;
102 doe_cap->cap.vec = vec;
105 doe_cap->write_mbox = g_malloc0(PCI_DOE_DW_SIZE_MAX * DWORD_BYTE);
106 doe_cap->read_mbox = g_malloc0(PCI_DOE_DW_SIZE_MAX * DWORD_BYTE);
108 pcie_doe_reset_mbox(doe_cap);
110 doe_cap->protocols = protocols;
111 for (; protocols->vendor_id; protocols++) {
112 doe_cap->protocol_num++;
114 assert(doe_cap->protocol_num < PCI_DOE_PROTOCOL_NUM_MAX);
116 /* Increment to allow for the discovery protocol */
117 doe_cap->protocol_num++;
120 void pcie_doe_fini(DOECap *doe_cap)
122 g_free(doe_cap->read_mbox);
123 g_free(doe_cap->write_mbox);
124 g_free(doe_cap);
127 uint32_t pcie_doe_build_protocol(DOEProtocol *p)
129 return DATA_OBJ_BUILD_HEADER1(p->vendor_id, p->data_obj_type);
132 void *pcie_doe_get_write_mbox_ptr(DOECap *doe_cap)
134 return doe_cap->write_mbox;
138 * Copy the response to read mailbox buffer
139 * This might be called in self-defined handle_request() if a DOE response is
140 * required in the corresponding protocol
142 void pcie_doe_set_rsp(DOECap *doe_cap, void *rsp)
144 uint32_t len = pcie_doe_get_obj_len(rsp);
146 memcpy(doe_cap->read_mbox + doe_cap->read_mbox_len, rsp, len * DWORD_BYTE);
147 doe_cap->read_mbox_len += len;
150 uint32_t pcie_doe_get_obj_len(void *obj)
152 uint32_t len;
154 if (!obj) {
155 return 0;
158 /* Only lower 18 bits are valid */
159 len = DATA_OBJ_LEN_MASK(((DOEHeader *)obj)->length);
161 /* PCIe r6.0 Table 6.29: a value of 00000h indicates 2^18 DW */
162 return (len) ? len : PCI_DOE_DW_SIZE_MAX;
165 static void pcie_doe_irq_assert(DOECap *doe_cap)
167 PCIDevice *dev = doe_cap->pdev;
169 if (doe_cap->cap.intr && doe_cap->ctrl.intr) {
170 if (doe_cap->status.intr) {
171 return;
173 doe_cap->status.intr = 1;
175 if (msix_enabled(dev)) {
176 msix_notify(dev, doe_cap->cap.vec);
177 } else if (msi_enabled(dev)) {
178 msi_notify(dev, doe_cap->cap.vec);
183 static void pcie_doe_set_ready(DOECap *doe_cap, bool rdy)
185 doe_cap->status.ready = rdy;
187 if (rdy) {
188 pcie_doe_irq_assert(doe_cap);
192 static void pcie_doe_set_error(DOECap *doe_cap, bool err)
194 doe_cap->status.error = err;
196 if (err) {
197 pcie_doe_irq_assert(doe_cap);
202 * Check incoming request in write_mbox for protocol format
204 static void pcie_doe_prepare_rsp(DOECap *doe_cap)
206 bool success = false;
207 int p;
208 bool (*handle_request)(DOECap *) = NULL;
210 if (doe_cap->status.error) {
211 return;
214 if (doe_cap->write_mbox[0] ==
215 DATA_OBJ_BUILD_HEADER1(PCI_VENDOR_ID_PCI_SIG, PCI_SIG_DOE_DISCOVERY)) {
216 handle_request = pcie_doe_discovery;
217 } else {
218 for (p = 0; p < doe_cap->protocol_num - 1; p++) {
219 if (doe_cap->write_mbox[0] ==
220 pcie_doe_build_protocol(&doe_cap->protocols[p])) {
221 handle_request = doe_cap->protocols[p].handle_request;
222 break;
228 * PCIe r6 DOE 6.30.1:
229 * If the number of DW transferred does not match the
230 * indicated Length for a data object, then the
231 * data object must be silently discarded.
233 if (handle_request && (doe_cap->write_mbox_len ==
234 pcie_doe_get_obj_len(pcie_doe_get_write_mbox_ptr(doe_cap)))) {
235 success = handle_request(doe_cap);
238 if (success) {
239 pcie_doe_set_ready(doe_cap, 1);
240 } else {
241 pcie_doe_reset_mbox(doe_cap);
246 * Read from DOE config space.
247 * Return false if the address not within DOE_CAP range.
249 bool pcie_doe_read_config(DOECap *doe_cap, uint32_t addr, int size,
250 uint32_t *buf)
252 uint32_t shift;
253 uint16_t doe_offset = doe_cap->offset;
255 if (!range_covers_byte(doe_offset + PCI_EXP_DOE_CAP,
256 PCI_DOE_SIZEOF - 4, addr)) {
257 return false;
260 addr -= doe_offset;
261 *buf = 0;
263 if (range_covers_byte(PCI_EXP_DOE_CAP, DWORD_BYTE, addr)) {
264 *buf = FIELD_DP32(*buf, PCI_DOE_CAP_REG, INTR_SUPP,
265 doe_cap->cap.intr);
266 *buf = FIELD_DP32(*buf, PCI_DOE_CAP_REG, DOE_INTR_MSG_NUM,
267 doe_cap->cap.vec);
268 } else if (range_covers_byte(PCI_EXP_DOE_CTRL, DWORD_BYTE, addr)) {
269 /* Must return ABORT=0 and GO=0 */
270 *buf = FIELD_DP32(*buf, PCI_DOE_CAP_CONTROL, DOE_INTR_EN,
271 doe_cap->ctrl.intr);
272 } else if (range_covers_byte(PCI_EXP_DOE_STATUS, DWORD_BYTE, addr)) {
273 *buf = FIELD_DP32(*buf, PCI_DOE_CAP_STATUS, DOE_BUSY,
274 doe_cap->status.busy);
275 *buf = FIELD_DP32(*buf, PCI_DOE_CAP_STATUS, DOE_INTR_STATUS,
276 doe_cap->status.intr);
277 *buf = FIELD_DP32(*buf, PCI_DOE_CAP_STATUS, DOE_ERROR,
278 doe_cap->status.error);
279 *buf = FIELD_DP32(*buf, PCI_DOE_CAP_STATUS, DATA_OBJ_RDY,
280 doe_cap->status.ready);
281 /* Mailbox should be DW accessed */
282 } else if (addr == PCI_EXP_DOE_RD_DATA_MBOX && size == DWORD_BYTE) {
283 if (doe_cap->status.ready && !doe_cap->status.error) {
284 *buf = doe_cap->read_mbox[doe_cap->read_mbox_idx];
288 /* Process Alignment */
289 shift = addr % DWORD_BYTE;
290 *buf = extract32(*buf, shift * 8, size * 8);
292 return true;
296 * Write to DOE config space.
297 * Return if the address not within DOE_CAP range or receives an abort
299 void pcie_doe_write_config(DOECap *doe_cap,
300 uint32_t addr, uint32_t val, int size)
302 uint16_t doe_offset = doe_cap->offset;
303 uint32_t shift;
305 if (!range_covers_byte(doe_offset + PCI_EXP_DOE_CAP,
306 PCI_DOE_SIZEOF - 4, addr)) {
307 return;
310 /* Process Alignment */
311 shift = addr % DWORD_BYTE;
312 addr -= (doe_offset + shift);
313 val = deposit32(val, shift * 8, size * 8, val);
315 switch (addr) {
316 case PCI_EXP_DOE_CTRL:
317 if (FIELD_EX32(val, PCI_DOE_CAP_CONTROL, DOE_ABORT)) {
318 pcie_doe_set_ready(doe_cap, 0);
319 pcie_doe_set_error(doe_cap, 0);
320 pcie_doe_reset_mbox(doe_cap);
321 return;
324 if (FIELD_EX32(val, PCI_DOE_CAP_CONTROL, DOE_GO)) {
325 pcie_doe_prepare_rsp(doe_cap);
328 if (FIELD_EX32(val, PCI_DOE_CAP_CONTROL, DOE_INTR_EN)) {
329 doe_cap->ctrl.intr = 1;
330 /* Clear interrupt bit located within the first byte */
331 } else if (shift == 0) {
332 doe_cap->ctrl.intr = 0;
334 break;
335 case PCI_EXP_DOE_STATUS:
336 if (FIELD_EX32(val, PCI_DOE_CAP_STATUS, DOE_INTR_STATUS)) {
337 doe_cap->status.intr = 0;
339 break;
340 case PCI_EXP_DOE_RD_DATA_MBOX:
341 /* Mailbox should be DW accessed */
342 if (size != DWORD_BYTE) {
343 return;
345 doe_cap->read_mbox_idx++;
346 if (doe_cap->read_mbox_idx == doe_cap->read_mbox_len) {
347 pcie_doe_reset_mbox(doe_cap);
348 pcie_doe_set_ready(doe_cap, 0);
349 } else if (doe_cap->read_mbox_idx > doe_cap->read_mbox_len) {
350 /* Underflow */
351 pcie_doe_set_error(doe_cap, 1);
353 break;
354 case PCI_EXP_DOE_WR_DATA_MBOX:
355 /* Mailbox should be DW accessed */
356 if (size != DWORD_BYTE) {
357 return;
359 doe_cap->write_mbox[doe_cap->write_mbox_len] = val;
360 doe_cap->write_mbox_len++;
361 break;
362 case PCI_EXP_DOE_CAP:
363 /* fallthrough */
364 default:
365 break;