19d24322eSJonathan Cameron // SPDX-License-Identifier: GPL-2.0
29d24322eSJonathan Cameron /*
39d24322eSJonathan Cameron * Data Object Exchange
49d24322eSJonathan Cameron * PCIe r6.0, sec 6.30 DOE
59d24322eSJonathan Cameron *
69d24322eSJonathan Cameron * Copyright (C) 2021 Huawei
79d24322eSJonathan Cameron * Jonathan Cameron <Jonathan.Cameron@huawei.com>
89d24322eSJonathan Cameron *
99d24322eSJonathan Cameron * Copyright (C) 2022 Intel Corporation
109d24322eSJonathan Cameron * Ira Weiny <ira.weiny@intel.com>
119d24322eSJonathan Cameron */
129d24322eSJonathan Cameron
139d24322eSJonathan Cameron #define dev_fmt(fmt) "DOE: " fmt
149d24322eSJonathan Cameron
159d24322eSJonathan Cameron #include <linux/bitfield.h>
169d24322eSJonathan Cameron #include <linux/delay.h>
179d24322eSJonathan Cameron #include <linux/jiffies.h>
189d24322eSJonathan Cameron #include <linux/mutex.h>
199d24322eSJonathan Cameron #include <linux/pci.h>
209d24322eSJonathan Cameron #include <linux/pci-doe.h>
219d24322eSJonathan Cameron #include <linux/workqueue.h>
229d24322eSJonathan Cameron
23ac048403SLukas Wunner #include "pci.h"
24ac048403SLukas Wunner
259d24322eSJonathan Cameron #define PCI_DOE_PROTOCOL_DISCOVERY 0
269d24322eSJonathan Cameron
279d24322eSJonathan Cameron /* Timeout of 1 second from 6.30.2 Operation, PCI Spec r6.0 */
289d24322eSJonathan Cameron #define PCI_DOE_TIMEOUT HZ
299d24322eSJonathan Cameron #define PCI_DOE_POLL_INTERVAL (PCI_DOE_TIMEOUT / 128)
309d24322eSJonathan Cameron
319d24322eSJonathan Cameron #define PCI_DOE_FLAG_CANCEL 0
329d24322eSJonathan Cameron #define PCI_DOE_FLAG_DEAD 1
339d24322eSJonathan Cameron
34a4ff8e7aSLi Ming /* Max data object length is 2^18 dwords */
35a4ff8e7aSLi Ming #define PCI_DOE_MAX_LENGTH (1 << 18)
36a4ff8e7aSLi Ming
379d24322eSJonathan Cameron /**
389d24322eSJonathan Cameron * struct pci_doe_mb - State for a single DOE mailbox
399d24322eSJonathan Cameron *
409d24322eSJonathan Cameron * This state is used to manage a single DOE mailbox capability. All fields
419d24322eSJonathan Cameron * should be considered opaque to the consumers and the structure passed into
42022b66f3SLukas Wunner * the helpers below after being created by pci_doe_create_mb().
439d24322eSJonathan Cameron *
449d24322eSJonathan Cameron * @pdev: PCI device this mailbox belongs to
459d24322eSJonathan Cameron * @cap_offset: Capability offset
469d24322eSJonathan Cameron * @prots: Array of protocols supported (encoded as long values)
479d24322eSJonathan Cameron * @wq: Wait queue for work item
489d24322eSJonathan Cameron * @work_queue: Queue of pci_doe_work items
499d24322eSJonathan Cameron * @flags: Bit array of PCI_DOE_FLAG_* flags
509d24322eSJonathan Cameron */
519d24322eSJonathan Cameron struct pci_doe_mb {
529d24322eSJonathan Cameron struct pci_dev *pdev;
539d24322eSJonathan Cameron u16 cap_offset;
549d24322eSJonathan Cameron struct xarray prots;
559d24322eSJonathan Cameron
569d24322eSJonathan Cameron wait_queue_head_t wq;
579d24322eSJonathan Cameron struct workqueue_struct *work_queue;
589d24322eSJonathan Cameron unsigned long flags;
599d24322eSJonathan Cameron };
609d24322eSJonathan Cameron
610821ff8eSLukas Wunner struct pci_doe_protocol {
620821ff8eSLukas Wunner u16 vid;
630821ff8eSLukas Wunner u8 type;
640821ff8eSLukas Wunner };
650821ff8eSLukas Wunner
660821ff8eSLukas Wunner /**
670821ff8eSLukas Wunner * struct pci_doe_task - represents a single query/response
680821ff8eSLukas Wunner *
690821ff8eSLukas Wunner * @prot: DOE Protocol
700821ff8eSLukas Wunner * @request_pl: The request payload
710821ff8eSLukas Wunner * @request_pl_sz: Size of the request payload (bytes)
720821ff8eSLukas Wunner * @response_pl: The response payload
730821ff8eSLukas Wunner * @response_pl_sz: Size of the response payload (bytes)
740821ff8eSLukas Wunner * @rv: Return value. Length of received response or error (bytes)
750821ff8eSLukas Wunner * @complete: Called when task is complete
760821ff8eSLukas Wunner * @private: Private data for the consumer
770821ff8eSLukas Wunner * @work: Used internally by the mailbox
780821ff8eSLukas Wunner * @doe_mb: Used internally by the mailbox
790821ff8eSLukas Wunner */
800821ff8eSLukas Wunner struct pci_doe_task {
810821ff8eSLukas Wunner struct pci_doe_protocol prot;
820821ff8eSLukas Wunner const __le32 *request_pl;
830821ff8eSLukas Wunner size_t request_pl_sz;
840821ff8eSLukas Wunner __le32 *response_pl;
850821ff8eSLukas Wunner size_t response_pl_sz;
860821ff8eSLukas Wunner int rv;
870821ff8eSLukas Wunner void (*complete)(struct pci_doe_task *task);
880821ff8eSLukas Wunner void *private;
890821ff8eSLukas Wunner
900821ff8eSLukas Wunner /* initialized by pci_doe_submit_task() */
910821ff8eSLukas Wunner struct work_struct work;
920821ff8eSLukas Wunner struct pci_doe_mb *doe_mb;
930821ff8eSLukas Wunner };
940821ff8eSLukas Wunner
pci_doe_wait(struct pci_doe_mb * doe_mb,unsigned long timeout)959d24322eSJonathan Cameron static int pci_doe_wait(struct pci_doe_mb *doe_mb, unsigned long timeout)
969d24322eSJonathan Cameron {
979d24322eSJonathan Cameron if (wait_event_timeout(doe_mb->wq,
989d24322eSJonathan Cameron test_bit(PCI_DOE_FLAG_CANCEL, &doe_mb->flags),
999d24322eSJonathan Cameron timeout))
1009d24322eSJonathan Cameron return -EIO;
1019d24322eSJonathan Cameron return 0;
1029d24322eSJonathan Cameron }
1039d24322eSJonathan Cameron
pci_doe_write_ctrl(struct pci_doe_mb * doe_mb,u32 val)1049d24322eSJonathan Cameron static void pci_doe_write_ctrl(struct pci_doe_mb *doe_mb, u32 val)
1059d24322eSJonathan Cameron {
1069d24322eSJonathan Cameron struct pci_dev *pdev = doe_mb->pdev;
1079d24322eSJonathan Cameron int offset = doe_mb->cap_offset;
1089d24322eSJonathan Cameron
1099d24322eSJonathan Cameron pci_write_config_dword(pdev, offset + PCI_DOE_CTRL, val);
1109d24322eSJonathan Cameron }
1119d24322eSJonathan Cameron
pci_doe_abort(struct pci_doe_mb * doe_mb)1129d24322eSJonathan Cameron static int pci_doe_abort(struct pci_doe_mb *doe_mb)
1139d24322eSJonathan Cameron {
1149d24322eSJonathan Cameron struct pci_dev *pdev = doe_mb->pdev;
1159d24322eSJonathan Cameron int offset = doe_mb->cap_offset;
1169d24322eSJonathan Cameron unsigned long timeout_jiffies;
1179d24322eSJonathan Cameron
1189d24322eSJonathan Cameron pci_dbg(pdev, "[%x] Issuing Abort\n", offset);
1199d24322eSJonathan Cameron
1209d24322eSJonathan Cameron timeout_jiffies = jiffies + PCI_DOE_TIMEOUT;
1219d24322eSJonathan Cameron pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_ABORT);
1229d24322eSJonathan Cameron
1239d24322eSJonathan Cameron do {
1249d24322eSJonathan Cameron int rc;
1259d24322eSJonathan Cameron u32 val;
1269d24322eSJonathan Cameron
1279d24322eSJonathan Cameron rc = pci_doe_wait(doe_mb, PCI_DOE_POLL_INTERVAL);
1289d24322eSJonathan Cameron if (rc)
1299d24322eSJonathan Cameron return rc;
1309d24322eSJonathan Cameron pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
1319d24322eSJonathan Cameron
1329d24322eSJonathan Cameron /* Abort success! */
1339d24322eSJonathan Cameron if (!FIELD_GET(PCI_DOE_STATUS_ERROR, val) &&
1349d24322eSJonathan Cameron !FIELD_GET(PCI_DOE_STATUS_BUSY, val))
1359d24322eSJonathan Cameron return 0;
1369d24322eSJonathan Cameron
1379d24322eSJonathan Cameron } while (!time_after(jiffies, timeout_jiffies));
1389d24322eSJonathan Cameron
1399d24322eSJonathan Cameron /* Abort has timed out and the MB is dead */
1409d24322eSJonathan Cameron pci_err(pdev, "[%x] ABORT timed out\n", offset);
1419d24322eSJonathan Cameron return -EIO;
1429d24322eSJonathan Cameron }
1439d24322eSJonathan Cameron
pci_doe_send_req(struct pci_doe_mb * doe_mb,struct pci_doe_task * task)1449d24322eSJonathan Cameron static int pci_doe_send_req(struct pci_doe_mb *doe_mb,
1459d24322eSJonathan Cameron struct pci_doe_task *task)
1469d24322eSJonathan Cameron {
1479d24322eSJonathan Cameron struct pci_dev *pdev = doe_mb->pdev;
1489d24322eSJonathan Cameron int offset = doe_mb->cap_offset;
149cedf8d8aSLukas Wunner size_t length, remainder;
1509d24322eSJonathan Cameron u32 val;
1519d24322eSJonathan Cameron int i;
1529d24322eSJonathan Cameron
1539d24322eSJonathan Cameron /*
1549d24322eSJonathan Cameron * Check the DOE busy bit is not set. If it is set, this could indicate
1559d24322eSJonathan Cameron * someone other than Linux (e.g. firmware) is using the mailbox. Note
1569d24322eSJonathan Cameron * it is expected that firmware and OS will negotiate access rights via
1579d24322eSJonathan Cameron * an, as yet to be defined, method.
1589d24322eSJonathan Cameron */
1599d24322eSJonathan Cameron pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
1609d24322eSJonathan Cameron if (FIELD_GET(PCI_DOE_STATUS_BUSY, val))
1619d24322eSJonathan Cameron return -EBUSY;
1629d24322eSJonathan Cameron
1639d24322eSJonathan Cameron if (FIELD_GET(PCI_DOE_STATUS_ERROR, val))
1649d24322eSJonathan Cameron return -EIO;
1659d24322eSJonathan Cameron
166a4ff8e7aSLi Ming /* Length is 2 DW of header + length of payload in DW */
167cedf8d8aSLukas Wunner length = 2 + DIV_ROUND_UP(task->request_pl_sz, sizeof(__le32));
168a4ff8e7aSLi Ming if (length > PCI_DOE_MAX_LENGTH)
169a4ff8e7aSLi Ming return -EIO;
170a4ff8e7aSLi Ming if (length == PCI_DOE_MAX_LENGTH)
171a4ff8e7aSLi Ming length = 0;
172a4ff8e7aSLi Ming
1739d24322eSJonathan Cameron /* Write DOE Header */
1749d24322eSJonathan Cameron val = FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_VID, task->prot.vid) |
1759d24322eSJonathan Cameron FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, task->prot.type);
1769d24322eSJonathan Cameron pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, val);
1779d24322eSJonathan Cameron pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
1789d24322eSJonathan Cameron FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH,
179a4ff8e7aSLi Ming length));
180cedf8d8aSLukas Wunner
181cedf8d8aSLukas Wunner /* Write payload */
182fbaa3821SLukas Wunner for (i = 0; i < task->request_pl_sz / sizeof(__le32); i++)
1839d24322eSJonathan Cameron pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
184fbaa3821SLukas Wunner le32_to_cpu(task->request_pl[i]));
1859d24322eSJonathan Cameron
186cedf8d8aSLukas Wunner /* Write last payload dword */
187cedf8d8aSLukas Wunner remainder = task->request_pl_sz % sizeof(__le32);
188cedf8d8aSLukas Wunner if (remainder) {
189cedf8d8aSLukas Wunner val = 0;
190cedf8d8aSLukas Wunner memcpy(&val, &task->request_pl[i], remainder);
191cedf8d8aSLukas Wunner le32_to_cpus(&val);
192cedf8d8aSLukas Wunner pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, val);
193cedf8d8aSLukas Wunner }
194cedf8d8aSLukas Wunner
1959d24322eSJonathan Cameron pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_GO);
1969d24322eSJonathan Cameron
1979d24322eSJonathan Cameron return 0;
1989d24322eSJonathan Cameron }
1999d24322eSJonathan Cameron
pci_doe_data_obj_ready(struct pci_doe_mb * doe_mb)2009d24322eSJonathan Cameron static bool pci_doe_data_obj_ready(struct pci_doe_mb *doe_mb)
2019d24322eSJonathan Cameron {
2029d24322eSJonathan Cameron struct pci_dev *pdev = doe_mb->pdev;
2039d24322eSJonathan Cameron int offset = doe_mb->cap_offset;
2049d24322eSJonathan Cameron u32 val;
2059d24322eSJonathan Cameron
2069d24322eSJonathan Cameron pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
2079d24322eSJonathan Cameron if (FIELD_GET(PCI_DOE_STATUS_DATA_OBJECT_READY, val))
2089d24322eSJonathan Cameron return true;
2099d24322eSJonathan Cameron return false;
2109d24322eSJonathan Cameron }
2119d24322eSJonathan Cameron
pci_doe_recv_resp(struct pci_doe_mb * doe_mb,struct pci_doe_task * task)2129d24322eSJonathan Cameron static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *task)
2139d24322eSJonathan Cameron {
214cedf8d8aSLukas Wunner size_t length, payload_length, remainder, received;
2159d24322eSJonathan Cameron struct pci_dev *pdev = doe_mb->pdev;
2169d24322eSJonathan Cameron int offset = doe_mb->cap_offset;
217cedf8d8aSLukas Wunner int i = 0;
2189d24322eSJonathan Cameron u32 val;
2199d24322eSJonathan Cameron
2209d24322eSJonathan Cameron /* Read the first dword to get the protocol */
2219d24322eSJonathan Cameron pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
2229d24322eSJonathan Cameron if ((FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, val) != task->prot.vid) ||
2239d24322eSJonathan Cameron (FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, val) != task->prot.type)) {
2249d24322eSJonathan Cameron dev_err_ratelimited(&pdev->dev, "[%x] expected [VID, Protocol] = [%04x, %02x], got [%04x, %02x]\n",
2259d24322eSJonathan Cameron doe_mb->cap_offset, task->prot.vid, task->prot.type,
2269d24322eSJonathan Cameron FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, val),
2279d24322eSJonathan Cameron FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, val));
2289d24322eSJonathan Cameron return -EIO;
2299d24322eSJonathan Cameron }
2309d24322eSJonathan Cameron
2319d24322eSJonathan Cameron pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
2329d24322eSJonathan Cameron /* Read the second dword to get the length */
2339d24322eSJonathan Cameron pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
2349d24322eSJonathan Cameron pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
2359d24322eSJonathan Cameron
2369d24322eSJonathan Cameron length = FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, val);
237a4ff8e7aSLi Ming /* A value of 0x0 indicates max data object length */
238a4ff8e7aSLi Ming if (!length)
239a4ff8e7aSLi Ming length = PCI_DOE_MAX_LENGTH;
240a4ff8e7aSLi Ming if (length < 2)
2419d24322eSJonathan Cameron return -EIO;
2429d24322eSJonathan Cameron
2439d24322eSJonathan Cameron /* First 2 dwords have already been read */
2449d24322eSJonathan Cameron length -= 2;
245cedf8d8aSLukas Wunner received = task->response_pl_sz;
246cedf8d8aSLukas Wunner payload_length = DIV_ROUND_UP(task->response_pl_sz, sizeof(__le32));
247cedf8d8aSLukas Wunner remainder = task->response_pl_sz % sizeof(__le32);
248cedf8d8aSLukas Wunner
249cedf8d8aSLukas Wunner /* remainder signifies number of data bytes in last payload dword */
250cedf8d8aSLukas Wunner if (!remainder)
251cedf8d8aSLukas Wunner remainder = sizeof(__le32);
252cedf8d8aSLukas Wunner
253cedf8d8aSLukas Wunner if (length < payload_length) {
254cedf8d8aSLukas Wunner received = length * sizeof(__le32);
255cedf8d8aSLukas Wunner payload_length = length;
256cedf8d8aSLukas Wunner remainder = sizeof(__le32);
257cedf8d8aSLukas Wunner }
258cedf8d8aSLukas Wunner
259cedf8d8aSLukas Wunner if (payload_length) {
260cedf8d8aSLukas Wunner /* Read all payload dwords except the last */
261cedf8d8aSLukas Wunner for (; i < payload_length - 1; i++) {
262cedf8d8aSLukas Wunner pci_read_config_dword(pdev, offset + PCI_DOE_READ,
263cedf8d8aSLukas Wunner &val);
264fbaa3821SLukas Wunner task->response_pl[i] = cpu_to_le32(val);
265cedf8d8aSLukas Wunner pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
266cedf8d8aSLukas Wunner }
267cedf8d8aSLukas Wunner
268cedf8d8aSLukas Wunner /* Read last payload dword */
269cedf8d8aSLukas Wunner pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
270cedf8d8aSLukas Wunner cpu_to_le32s(&val);
271cedf8d8aSLukas Wunner memcpy(&task->response_pl[i], &val, remainder);
2729d24322eSJonathan Cameron /* Prior to the last ack, ensure Data Object Ready */
273cedf8d8aSLukas Wunner if (!pci_doe_data_obj_ready(doe_mb))
2749d24322eSJonathan Cameron return -EIO;
2759d24322eSJonathan Cameron pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
276cedf8d8aSLukas Wunner i++;
2779d24322eSJonathan Cameron }
2789d24322eSJonathan Cameron
2799d24322eSJonathan Cameron /* Flush excess length */
2809d24322eSJonathan Cameron for (; i < length; i++) {
2819d24322eSJonathan Cameron pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
2829d24322eSJonathan Cameron pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
2839d24322eSJonathan Cameron }
2849d24322eSJonathan Cameron
2859d24322eSJonathan Cameron /* Final error check to pick up on any since Data Object Ready */
2869d24322eSJonathan Cameron pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
2879d24322eSJonathan Cameron if (FIELD_GET(PCI_DOE_STATUS_ERROR, val))
2889d24322eSJonathan Cameron return -EIO;
2899d24322eSJonathan Cameron
290cedf8d8aSLukas Wunner return received;
2919d24322eSJonathan Cameron }
2929d24322eSJonathan Cameron
signal_task_complete(struct pci_doe_task * task,int rv)2939d24322eSJonathan Cameron static void signal_task_complete(struct pci_doe_task *task, int rv)
2949d24322eSJonathan Cameron {
2959d24322eSJonathan Cameron task->rv = rv;
296abf04be0SLukas Wunner destroy_work_on_stack(&task->work);
297*e3a3a097SIra Weiny task->complete(task);
2989d24322eSJonathan Cameron }
2999d24322eSJonathan Cameron
signal_task_abort(struct pci_doe_task * task,int rv)3009d24322eSJonathan Cameron static void signal_task_abort(struct pci_doe_task *task, int rv)
3019d24322eSJonathan Cameron {
3029d24322eSJonathan Cameron struct pci_doe_mb *doe_mb = task->doe_mb;
3039d24322eSJonathan Cameron struct pci_dev *pdev = doe_mb->pdev;
3049d24322eSJonathan Cameron
3059d24322eSJonathan Cameron if (pci_doe_abort(doe_mb)) {
3069d24322eSJonathan Cameron /*
3079d24322eSJonathan Cameron * If the device can't process an abort; set the mailbox dead
3089d24322eSJonathan Cameron * - no more submissions
3099d24322eSJonathan Cameron */
3109d24322eSJonathan Cameron pci_err(pdev, "[%x] Abort failed marking mailbox dead\n",
3119d24322eSJonathan Cameron doe_mb->cap_offset);
3129d24322eSJonathan Cameron set_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags);
3139d24322eSJonathan Cameron }
3149d24322eSJonathan Cameron signal_task_complete(task, rv);
3159d24322eSJonathan Cameron }
3169d24322eSJonathan Cameron
doe_statemachine_work(struct work_struct * work)3179d24322eSJonathan Cameron static void doe_statemachine_work(struct work_struct *work)
3189d24322eSJonathan Cameron {
3199d24322eSJonathan Cameron struct pci_doe_task *task = container_of(work, struct pci_doe_task,
3209d24322eSJonathan Cameron work);
3219d24322eSJonathan Cameron struct pci_doe_mb *doe_mb = task->doe_mb;
3229d24322eSJonathan Cameron struct pci_dev *pdev = doe_mb->pdev;
3239d24322eSJonathan Cameron int offset = doe_mb->cap_offset;
3249d24322eSJonathan Cameron unsigned long timeout_jiffies;
3259d24322eSJonathan Cameron u32 val;
3269d24322eSJonathan Cameron int rc;
3279d24322eSJonathan Cameron
3289d24322eSJonathan Cameron if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags)) {
3299d24322eSJonathan Cameron signal_task_complete(task, -EIO);
3309d24322eSJonathan Cameron return;
3319d24322eSJonathan Cameron }
3329d24322eSJonathan Cameron
3339d24322eSJonathan Cameron /* Send request */
3349d24322eSJonathan Cameron rc = pci_doe_send_req(doe_mb, task);
3359d24322eSJonathan Cameron if (rc) {
3369d24322eSJonathan Cameron /*
3379d24322eSJonathan Cameron * The specification does not provide any guidance on how to
3389d24322eSJonathan Cameron * resolve conflicting requests from other entities.
3399d24322eSJonathan Cameron * Furthermore, it is likely that busy will not be detected
3409d24322eSJonathan Cameron * most of the time. Flag any detection of status busy with an
3419d24322eSJonathan Cameron * error.
3429d24322eSJonathan Cameron */
3439d24322eSJonathan Cameron if (rc == -EBUSY)
3449d24322eSJonathan Cameron dev_err_ratelimited(&pdev->dev, "[%x] busy detected; another entity is sending conflicting requests\n",
3459d24322eSJonathan Cameron offset);
3469d24322eSJonathan Cameron signal_task_abort(task, rc);
3479d24322eSJonathan Cameron return;
3489d24322eSJonathan Cameron }
3499d24322eSJonathan Cameron
3509d24322eSJonathan Cameron timeout_jiffies = jiffies + PCI_DOE_TIMEOUT;
3519d24322eSJonathan Cameron /* Poll for response */
3529d24322eSJonathan Cameron retry_resp:
3539d24322eSJonathan Cameron pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
3549d24322eSJonathan Cameron if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) {
3559d24322eSJonathan Cameron signal_task_abort(task, -EIO);
3569d24322eSJonathan Cameron return;
3579d24322eSJonathan Cameron }
3589d24322eSJonathan Cameron
3599d24322eSJonathan Cameron if (!FIELD_GET(PCI_DOE_STATUS_DATA_OBJECT_READY, val)) {
3609d24322eSJonathan Cameron if (time_after(jiffies, timeout_jiffies)) {
3619d24322eSJonathan Cameron signal_task_abort(task, -EIO);
3629d24322eSJonathan Cameron return;
3639d24322eSJonathan Cameron }
3649d24322eSJonathan Cameron rc = pci_doe_wait(doe_mb, PCI_DOE_POLL_INTERVAL);
3659d24322eSJonathan Cameron if (rc) {
3669d24322eSJonathan Cameron signal_task_abort(task, rc);
3679d24322eSJonathan Cameron return;
3689d24322eSJonathan Cameron }
3699d24322eSJonathan Cameron goto retry_resp;
3709d24322eSJonathan Cameron }
3719d24322eSJonathan Cameron
3729d24322eSJonathan Cameron rc = pci_doe_recv_resp(doe_mb, task);
3739d24322eSJonathan Cameron if (rc < 0) {
3749d24322eSJonathan Cameron signal_task_abort(task, rc);
3759d24322eSJonathan Cameron return;
3769d24322eSJonathan Cameron }
3779d24322eSJonathan Cameron
3789d24322eSJonathan Cameron signal_task_complete(task, rc);
3799d24322eSJonathan Cameron }
3809d24322eSJonathan Cameron
pci_doe_task_complete(struct pci_doe_task * task)3819d24322eSJonathan Cameron static void pci_doe_task_complete(struct pci_doe_task *task)
3829d24322eSJonathan Cameron {
3839d24322eSJonathan Cameron complete(task->private);
3849d24322eSJonathan Cameron }
3859d24322eSJonathan Cameron
pci_doe_discovery(struct pci_doe_mb * doe_mb,u8 * index,u16 * vid,u8 * protocol)3869d24322eSJonathan Cameron static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 *index, u16 *vid,
3879d24322eSJonathan Cameron u8 *protocol)
3889d24322eSJonathan Cameron {
3899d24322eSJonathan Cameron u32 request_pl = FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX,
3909d24322eSJonathan Cameron *index);
391fbaa3821SLukas Wunner __le32 request_pl_le = cpu_to_le32(request_pl);
392fbaa3821SLukas Wunner __le32 response_pl_le;
3939d24322eSJonathan Cameron u32 response_pl;
3949d24322eSJonathan Cameron int rc;
3959d24322eSJonathan Cameron
39662e8b17fSLukas Wunner rc = pci_doe(doe_mb, PCI_VENDOR_ID_PCI_SIG, PCI_DOE_PROTOCOL_DISCOVERY,
39762e8b17fSLukas Wunner &request_pl_le, sizeof(request_pl_le),
39862e8b17fSLukas Wunner &response_pl_le, sizeof(response_pl_le));
3999d24322eSJonathan Cameron if (rc < 0)
4009d24322eSJonathan Cameron return rc;
4019d24322eSJonathan Cameron
40262e8b17fSLukas Wunner if (rc != sizeof(response_pl_le))
4039d24322eSJonathan Cameron return -EIO;
4049d24322eSJonathan Cameron
405fbaa3821SLukas Wunner response_pl = le32_to_cpu(response_pl_le);
4069d24322eSJonathan Cameron *vid = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID, response_pl);
4079d24322eSJonathan Cameron *protocol = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL,
4089d24322eSJonathan Cameron response_pl);
4099d24322eSJonathan Cameron *index = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX,
4109d24322eSJonathan Cameron response_pl);
4119d24322eSJonathan Cameron
4129d24322eSJonathan Cameron return 0;
4139d24322eSJonathan Cameron }
4149d24322eSJonathan Cameron
pci_doe_xa_prot_entry(u16 vid,u8 prot)4159d24322eSJonathan Cameron static void *pci_doe_xa_prot_entry(u16 vid, u8 prot)
4169d24322eSJonathan Cameron {
4179d24322eSJonathan Cameron return xa_mk_value((vid << 8) | prot);
4189d24322eSJonathan Cameron }
4199d24322eSJonathan Cameron
pci_doe_cache_protocols(struct pci_doe_mb * doe_mb)4209d24322eSJonathan Cameron static int pci_doe_cache_protocols(struct pci_doe_mb *doe_mb)
4219d24322eSJonathan Cameron {
4229d24322eSJonathan Cameron u8 index = 0;
4239d24322eSJonathan Cameron u8 xa_idx = 0;
4249d24322eSJonathan Cameron
4259d24322eSJonathan Cameron do {
4269d24322eSJonathan Cameron int rc;
4279d24322eSJonathan Cameron u16 vid;
4289d24322eSJonathan Cameron u8 prot;
4299d24322eSJonathan Cameron
4309d24322eSJonathan Cameron rc = pci_doe_discovery(doe_mb, &index, &vid, &prot);
4319d24322eSJonathan Cameron if (rc)
4329d24322eSJonathan Cameron return rc;
4339d24322eSJonathan Cameron
4349d24322eSJonathan Cameron pci_dbg(doe_mb->pdev,
4359d24322eSJonathan Cameron "[%x] Found protocol %d vid: %x prot: %x\n",
4369d24322eSJonathan Cameron doe_mb->cap_offset, xa_idx, vid, prot);
4379d24322eSJonathan Cameron
4389d24322eSJonathan Cameron rc = xa_insert(&doe_mb->prots, xa_idx++,
4399d24322eSJonathan Cameron pci_doe_xa_prot_entry(vid, prot), GFP_KERNEL);
4409d24322eSJonathan Cameron if (rc)
4419d24322eSJonathan Cameron return rc;
4429d24322eSJonathan Cameron } while (index);
4439d24322eSJonathan Cameron
4449d24322eSJonathan Cameron return 0;
4459d24322eSJonathan Cameron }
4469d24322eSJonathan Cameron
pci_doe_cancel_tasks(struct pci_doe_mb * doe_mb)447022b66f3SLukas Wunner static void pci_doe_cancel_tasks(struct pci_doe_mb *doe_mb)
4489d24322eSJonathan Cameron {
4499d24322eSJonathan Cameron /* Stop all pending work items from starting */
4509d24322eSJonathan Cameron set_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags);
4519d24322eSJonathan Cameron
4529d24322eSJonathan Cameron /* Cancel an in progress work item, if necessary */
4539d24322eSJonathan Cameron set_bit(PCI_DOE_FLAG_CANCEL, &doe_mb->flags);
4549d24322eSJonathan Cameron wake_up(&doe_mb->wq);
4559d24322eSJonathan Cameron }
4569d24322eSJonathan Cameron
4579d24322eSJonathan Cameron /**
458022b66f3SLukas Wunner * pci_doe_create_mb() - Create a DOE mailbox object
4599d24322eSJonathan Cameron *
4609d24322eSJonathan Cameron * @pdev: PCI device to create the DOE mailbox for
4619d24322eSJonathan Cameron * @cap_offset: Offset of the DOE mailbox
4629d24322eSJonathan Cameron *
4639d24322eSJonathan Cameron * Create a single mailbox object to manage the mailbox protocol at the
4649d24322eSJonathan Cameron * cap_offset specified.
4659d24322eSJonathan Cameron *
4669d24322eSJonathan Cameron * RETURNS: created mailbox object on success
4679d24322eSJonathan Cameron * ERR_PTR(-errno) on failure
4689d24322eSJonathan Cameron */
pci_doe_create_mb(struct pci_dev * pdev,u16 cap_offset)469022b66f3SLukas Wunner static struct pci_doe_mb *pci_doe_create_mb(struct pci_dev *pdev,
470022b66f3SLukas Wunner u16 cap_offset)
4719d24322eSJonathan Cameron {
4729d24322eSJonathan Cameron struct pci_doe_mb *doe_mb;
4739d24322eSJonathan Cameron int rc;
4749d24322eSJonathan Cameron
475022b66f3SLukas Wunner doe_mb = kzalloc(sizeof(*doe_mb), GFP_KERNEL);
4769d24322eSJonathan Cameron if (!doe_mb)
4779d24322eSJonathan Cameron return ERR_PTR(-ENOMEM);
4789d24322eSJonathan Cameron
4799d24322eSJonathan Cameron doe_mb->pdev = pdev;
4809d24322eSJonathan Cameron doe_mb->cap_offset = cap_offset;
4819d24322eSJonathan Cameron init_waitqueue_head(&doe_mb->wq);
4829d24322eSJonathan Cameron xa_init(&doe_mb->prots);
4839d24322eSJonathan Cameron
4849d24322eSJonathan Cameron doe_mb->work_queue = alloc_ordered_workqueue("%s %s DOE [%x]", 0,
48574e491e5SLukas Wunner dev_bus_name(&pdev->dev),
4869d24322eSJonathan Cameron pci_name(pdev),
4879d24322eSJonathan Cameron doe_mb->cap_offset);
4889d24322eSJonathan Cameron if (!doe_mb->work_queue) {
4899d24322eSJonathan Cameron pci_err(pdev, "[%x] failed to allocate work queue\n",
4909d24322eSJonathan Cameron doe_mb->cap_offset);
491022b66f3SLukas Wunner rc = -ENOMEM;
492022b66f3SLukas Wunner goto err_free;
4939d24322eSJonathan Cameron }
4949d24322eSJonathan Cameron
4959d24322eSJonathan Cameron /* Reset the mailbox by issuing an abort */
4969d24322eSJonathan Cameron rc = pci_doe_abort(doe_mb);
4979d24322eSJonathan Cameron if (rc) {
4989d24322eSJonathan Cameron pci_err(pdev, "[%x] failed to reset mailbox with abort command : %d\n",
4999d24322eSJonathan Cameron doe_mb->cap_offset, rc);
500022b66f3SLukas Wunner goto err_destroy_wq;
5019d24322eSJonathan Cameron }
5029d24322eSJonathan Cameron
5039d24322eSJonathan Cameron /*
5049d24322eSJonathan Cameron * The state machine and the mailbox should be in sync now;
505022b66f3SLukas Wunner * Use the mailbox to query protocols.
5069d24322eSJonathan Cameron */
5079d24322eSJonathan Cameron rc = pci_doe_cache_protocols(doe_mb);
5089d24322eSJonathan Cameron if (rc) {
5099d24322eSJonathan Cameron pci_err(pdev, "[%x] failed to cache protocols : %d\n",
5109d24322eSJonathan Cameron doe_mb->cap_offset, rc);
511022b66f3SLukas Wunner goto err_cancel;
512022b66f3SLukas Wunner }
513022b66f3SLukas Wunner
514022b66f3SLukas Wunner return doe_mb;
515022b66f3SLukas Wunner
516022b66f3SLukas Wunner err_cancel:
517022b66f3SLukas Wunner pci_doe_cancel_tasks(doe_mb);
518022b66f3SLukas Wunner xa_destroy(&doe_mb->prots);
519022b66f3SLukas Wunner err_destroy_wq:
520022b66f3SLukas Wunner destroy_workqueue(doe_mb->work_queue);
521022b66f3SLukas Wunner err_free:
522022b66f3SLukas Wunner kfree(doe_mb);
5239d24322eSJonathan Cameron return ERR_PTR(rc);
5249d24322eSJonathan Cameron }
5259d24322eSJonathan Cameron
526022b66f3SLukas Wunner /**
527022b66f3SLukas Wunner * pci_doe_destroy_mb() - Destroy a DOE mailbox object
528022b66f3SLukas Wunner *
52974e491e5SLukas Wunner * @doe_mb: DOE mailbox
530022b66f3SLukas Wunner *
531022b66f3SLukas Wunner * Destroy all internal data structures created for the DOE mailbox.
532022b66f3SLukas Wunner */
pci_doe_destroy_mb(struct pci_doe_mb * doe_mb)53374e491e5SLukas Wunner static void pci_doe_destroy_mb(struct pci_doe_mb *doe_mb)
534022b66f3SLukas Wunner {
535022b66f3SLukas Wunner pci_doe_cancel_tasks(doe_mb);
536022b66f3SLukas Wunner xa_destroy(&doe_mb->prots);
537022b66f3SLukas Wunner destroy_workqueue(doe_mb->work_queue);
538022b66f3SLukas Wunner kfree(doe_mb);
539022b66f3SLukas Wunner }
540022b66f3SLukas Wunner
541022b66f3SLukas Wunner /**
5429d24322eSJonathan Cameron * pci_doe_supports_prot() - Return if the DOE instance supports the given
5439d24322eSJonathan Cameron * protocol
5449d24322eSJonathan Cameron * @doe_mb: DOE mailbox capability to query
5459d24322eSJonathan Cameron * @vid: Protocol Vendor ID
5469d24322eSJonathan Cameron * @type: Protocol type
5479d24322eSJonathan Cameron *
5489d24322eSJonathan Cameron * RETURNS: True if the DOE mailbox supports the protocol specified
5499d24322eSJonathan Cameron */
pci_doe_supports_prot(struct pci_doe_mb * doe_mb,u16 vid,u8 type)55074e491e5SLukas Wunner static bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type)
5519d24322eSJonathan Cameron {
5529d24322eSJonathan Cameron unsigned long index;
5539d24322eSJonathan Cameron void *entry;
5549d24322eSJonathan Cameron
5559d24322eSJonathan Cameron /* The discovery protocol must always be supported */
5569d24322eSJonathan Cameron if (vid == PCI_VENDOR_ID_PCI_SIG && type == PCI_DOE_PROTOCOL_DISCOVERY)
5579d24322eSJonathan Cameron return true;
5589d24322eSJonathan Cameron
5599d24322eSJonathan Cameron xa_for_each(&doe_mb->prots, index, entry)
5609d24322eSJonathan Cameron if (entry == pci_doe_xa_prot_entry(vid, type))
5619d24322eSJonathan Cameron return true;
5629d24322eSJonathan Cameron
5639d24322eSJonathan Cameron return false;
5649d24322eSJonathan Cameron }
5659d24322eSJonathan Cameron
5669d24322eSJonathan Cameron /**
5679d24322eSJonathan Cameron * pci_doe_submit_task() - Submit a task to be processed by the state machine
5689d24322eSJonathan Cameron *
5699d24322eSJonathan Cameron * @doe_mb: DOE mailbox capability to submit to
5709d24322eSJonathan Cameron * @task: task to be queued
5719d24322eSJonathan Cameron *
5729d24322eSJonathan Cameron * Submit a DOE task (request/response) to the DOE mailbox to be processed.
5739d24322eSJonathan Cameron * Returns upon queueing the task object. If the queue is full this function
5749d24322eSJonathan Cameron * will sleep until there is room in the queue.
5759d24322eSJonathan Cameron *
5769d24322eSJonathan Cameron * task->complete will be called when the state machine is done processing this
5779d24322eSJonathan Cameron * task.
5789d24322eSJonathan Cameron *
57992dc899cSLukas Wunner * @task must be allocated on the stack.
58092dc899cSLukas Wunner *
5819d24322eSJonathan Cameron * Excess data will be discarded.
5829d24322eSJonathan Cameron *
5839d24322eSJonathan Cameron * RETURNS: 0 when task has been successfully queued, -ERRNO on error
5849d24322eSJonathan Cameron */
pci_doe_submit_task(struct pci_doe_mb * doe_mb,struct pci_doe_task * task)5850821ff8eSLukas Wunner static int pci_doe_submit_task(struct pci_doe_mb *doe_mb,
5860821ff8eSLukas Wunner struct pci_doe_task *task)
5879d24322eSJonathan Cameron {
5889d24322eSJonathan Cameron if (!pci_doe_supports_prot(doe_mb, task->prot.vid, task->prot.type))
5899d24322eSJonathan Cameron return -EINVAL;
5909d24322eSJonathan Cameron
5919d24322eSJonathan Cameron if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags))
5929d24322eSJonathan Cameron return -EIO;
5939d24322eSJonathan Cameron
5949d24322eSJonathan Cameron task->doe_mb = doe_mb;
59592dc899cSLukas Wunner INIT_WORK_ONSTACK(&task->work, doe_statemachine_work);
5969d24322eSJonathan Cameron queue_work(doe_mb->work_queue, &task->work);
5979d24322eSJonathan Cameron return 0;
5989d24322eSJonathan Cameron }
59962e8b17fSLukas Wunner
60062e8b17fSLukas Wunner /**
60162e8b17fSLukas Wunner * pci_doe() - Perform Data Object Exchange
60262e8b17fSLukas Wunner *
60362e8b17fSLukas Wunner * @doe_mb: DOE Mailbox
60462e8b17fSLukas Wunner * @vendor: Vendor ID
60562e8b17fSLukas Wunner * @type: Data Object Type
60662e8b17fSLukas Wunner * @request: Request payload
60762e8b17fSLukas Wunner * @request_sz: Size of request payload (bytes)
60862e8b17fSLukas Wunner * @response: Response payload
60962e8b17fSLukas Wunner * @response_sz: Size of response payload (bytes)
61062e8b17fSLukas Wunner *
61162e8b17fSLukas Wunner * Submit @request to @doe_mb and store the @response.
61262e8b17fSLukas Wunner * The DOE exchange is performed synchronously and may therefore sleep.
61362e8b17fSLukas Wunner *
61462e8b17fSLukas Wunner * Payloads are treated as opaque byte streams which are transmitted verbatim,
61562e8b17fSLukas Wunner * without byte-swapping. If payloads contain little-endian register values,
61662e8b17fSLukas Wunner * the caller is responsible for conversion with cpu_to_le32() / le32_to_cpu().
61762e8b17fSLukas Wunner *
618cedf8d8aSLukas Wunner * For convenience, arbitrary payload sizes are allowed even though PCIe r6.0
619cedf8d8aSLukas Wunner * sec 6.30.1 specifies the Data Object Header 2 "Length" in dwords. The last
620cedf8d8aSLukas Wunner * (partial) dword is copied with byte granularity and padded with zeroes if
621cedf8d8aSLukas Wunner * necessary. Callers are thus relieved of using dword-sized bounce buffers.
622cedf8d8aSLukas Wunner *
62362e8b17fSLukas Wunner * RETURNS: Length of received response or negative errno.
62462e8b17fSLukas Wunner * Received data in excess of @response_sz is discarded.
62562e8b17fSLukas Wunner * The length may be smaller than @response_sz and the caller
62662e8b17fSLukas Wunner * is responsible for checking that.
62762e8b17fSLukas Wunner */
pci_doe(struct pci_doe_mb * doe_mb,u16 vendor,u8 type,const void * request,size_t request_sz,void * response,size_t response_sz)62862e8b17fSLukas Wunner int pci_doe(struct pci_doe_mb *doe_mb, u16 vendor, u8 type,
62962e8b17fSLukas Wunner const void *request, size_t request_sz,
63062e8b17fSLukas Wunner void *response, size_t response_sz)
63162e8b17fSLukas Wunner {
63262e8b17fSLukas Wunner DECLARE_COMPLETION_ONSTACK(c);
63362e8b17fSLukas Wunner struct pci_doe_task task = {
63462e8b17fSLukas Wunner .prot.vid = vendor,
63562e8b17fSLukas Wunner .prot.type = type,
63662e8b17fSLukas Wunner .request_pl = request,
63762e8b17fSLukas Wunner .request_pl_sz = request_sz,
63862e8b17fSLukas Wunner .response_pl = response,
63962e8b17fSLukas Wunner .response_pl_sz = response_sz,
64062e8b17fSLukas Wunner .complete = pci_doe_task_complete,
64162e8b17fSLukas Wunner .private = &c,
64262e8b17fSLukas Wunner };
64362e8b17fSLukas Wunner int rc;
64462e8b17fSLukas Wunner
64562e8b17fSLukas Wunner rc = pci_doe_submit_task(doe_mb, &task);
64662e8b17fSLukas Wunner if (rc)
64762e8b17fSLukas Wunner return rc;
64862e8b17fSLukas Wunner
64962e8b17fSLukas Wunner wait_for_completion(&c);
65062e8b17fSLukas Wunner
65162e8b17fSLukas Wunner return task.rv;
65262e8b17fSLukas Wunner }
65362e8b17fSLukas Wunner EXPORT_SYMBOL_GPL(pci_doe);
654ac048403SLukas Wunner
655ac048403SLukas Wunner /**
656ac048403SLukas Wunner * pci_find_doe_mailbox() - Find Data Object Exchange mailbox
657ac048403SLukas Wunner *
658ac048403SLukas Wunner * @pdev: PCI device
659ac048403SLukas Wunner * @vendor: Vendor ID
660ac048403SLukas Wunner * @type: Data Object Type
661ac048403SLukas Wunner *
662ac048403SLukas Wunner * Find first DOE mailbox of a PCI device which supports the given protocol.
663ac048403SLukas Wunner *
664ac048403SLukas Wunner * RETURNS: Pointer to the DOE mailbox or NULL if none was found.
665ac048403SLukas Wunner */
pci_find_doe_mailbox(struct pci_dev * pdev,u16 vendor,u8 type)666ac048403SLukas Wunner struct pci_doe_mb *pci_find_doe_mailbox(struct pci_dev *pdev, u16 vendor,
667ac048403SLukas Wunner u8 type)
668ac048403SLukas Wunner {
669ac048403SLukas Wunner struct pci_doe_mb *doe_mb;
670ac048403SLukas Wunner unsigned long index;
671ac048403SLukas Wunner
672ac048403SLukas Wunner xa_for_each(&pdev->doe_mbs, index, doe_mb)
673ac048403SLukas Wunner if (pci_doe_supports_prot(doe_mb, vendor, type))
674ac048403SLukas Wunner return doe_mb;
675ac048403SLukas Wunner
676ac048403SLukas Wunner return NULL;
677ac048403SLukas Wunner }
678ac048403SLukas Wunner EXPORT_SYMBOL_GPL(pci_find_doe_mailbox);
679ac048403SLukas Wunner
pci_doe_init(struct pci_dev * pdev)680ac048403SLukas Wunner void pci_doe_init(struct pci_dev *pdev)
681ac048403SLukas Wunner {
682ac048403SLukas Wunner struct pci_doe_mb *doe_mb;
683ac048403SLukas Wunner u16 offset = 0;
684ac048403SLukas Wunner int rc;
685ac048403SLukas Wunner
686ac048403SLukas Wunner xa_init(&pdev->doe_mbs);
687ac048403SLukas Wunner
688ac048403SLukas Wunner while ((offset = pci_find_next_ext_capability(pdev, offset,
689ac048403SLukas Wunner PCI_EXT_CAP_ID_DOE))) {
690ac048403SLukas Wunner doe_mb = pci_doe_create_mb(pdev, offset);
691ac048403SLukas Wunner if (IS_ERR(doe_mb)) {
692ac048403SLukas Wunner pci_err(pdev, "[%x] failed to create mailbox: %ld\n",
693ac048403SLukas Wunner offset, PTR_ERR(doe_mb));
694ac048403SLukas Wunner continue;
695ac048403SLukas Wunner }
696ac048403SLukas Wunner
697ac048403SLukas Wunner rc = xa_insert(&pdev->doe_mbs, offset, doe_mb, GFP_KERNEL);
698ac048403SLukas Wunner if (rc) {
699ac048403SLukas Wunner pci_err(pdev, "[%x] failed to insert mailbox: %d\n",
700ac048403SLukas Wunner offset, rc);
701ac048403SLukas Wunner pci_doe_destroy_mb(doe_mb);
702ac048403SLukas Wunner }
703ac048403SLukas Wunner }
704ac048403SLukas Wunner }
705ac048403SLukas Wunner
pci_doe_destroy(struct pci_dev * pdev)706ac048403SLukas Wunner void pci_doe_destroy(struct pci_dev *pdev)
707ac048403SLukas Wunner {
708ac048403SLukas Wunner struct pci_doe_mb *doe_mb;
709ac048403SLukas Wunner unsigned long index;
710ac048403SLukas Wunner
711ac048403SLukas Wunner xa_for_each(&pdev->doe_mbs, index, doe_mb)
712ac048403SLukas Wunner pci_doe_destroy_mb(doe_mb);
713ac048403SLukas Wunner
714ac048403SLukas Wunner xa_destroy(&pdev->doe_mbs);
715ac048403SLukas Wunner }
716ac048403SLukas Wunner
pci_doe_disconnected(struct pci_dev * pdev)717ac048403SLukas Wunner void pci_doe_disconnected(struct pci_dev *pdev)
718ac048403SLukas Wunner {
719ac048403SLukas Wunner struct pci_doe_mb *doe_mb;
720ac048403SLukas Wunner unsigned long index;
721ac048403SLukas Wunner
722ac048403SLukas Wunner xa_for_each(&pdev->doe_mbs, index, doe_mb)
723ac048403SLukas Wunner pci_doe_cancel_tasks(doe_mb);
724ac048403SLukas Wunner }
725