162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Data Object Exchange
462306a36Sopenharmony_ci *	PCIe r6.0, sec 6.30 DOE
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2021 Huawei
762306a36Sopenharmony_ci *	Jonathan Cameron <Jonathan.Cameron@huawei.com>
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Copyright (C) 2022 Intel Corporation
1062306a36Sopenharmony_ci *	Ira Weiny <ira.weiny@intel.com>
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define dev_fmt(fmt) "DOE: " fmt
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/bitfield.h>
1662306a36Sopenharmony_ci#include <linux/delay.h>
1762306a36Sopenharmony_ci#include <linux/jiffies.h>
1862306a36Sopenharmony_ci#include <linux/mutex.h>
1962306a36Sopenharmony_ci#include <linux/pci.h>
2062306a36Sopenharmony_ci#include <linux/pci-doe.h>
2162306a36Sopenharmony_ci#include <linux/workqueue.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "pci.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define PCI_DOE_PROTOCOL_DISCOVERY 0
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* Timeout of 1 second from 6.30.2 Operation, PCI Spec r6.0 */
2862306a36Sopenharmony_ci#define PCI_DOE_TIMEOUT HZ
2962306a36Sopenharmony_ci#define PCI_DOE_POLL_INTERVAL	(PCI_DOE_TIMEOUT / 128)
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define PCI_DOE_FLAG_CANCEL	0
3262306a36Sopenharmony_ci#define PCI_DOE_FLAG_DEAD	1
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Max data object length is 2^18 dwords */
3562306a36Sopenharmony_ci#define PCI_DOE_MAX_LENGTH	(1 << 18)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/**
3862306a36Sopenharmony_ci * struct pci_doe_mb - State for a single DOE mailbox
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * This state is used to manage a single DOE mailbox capability.  All fields
4162306a36Sopenharmony_ci * should be considered opaque to the consumers and the structure passed into
4262306a36Sopenharmony_ci * the helpers below after being created by pci_doe_create_mb().
4362306a36Sopenharmony_ci *
4462306a36Sopenharmony_ci * @pdev: PCI device this mailbox belongs to
4562306a36Sopenharmony_ci * @cap_offset: Capability offset
4662306a36Sopenharmony_ci * @prots: Array of protocols supported (encoded as long values)
4762306a36Sopenharmony_ci * @wq: Wait queue for work item
4862306a36Sopenharmony_ci * @work_queue: Queue of pci_doe_work items
4962306a36Sopenharmony_ci * @flags: Bit array of PCI_DOE_FLAG_* flags
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_cistruct pci_doe_mb {
5262306a36Sopenharmony_ci	struct pci_dev *pdev;
5362306a36Sopenharmony_ci	u16 cap_offset;
5462306a36Sopenharmony_ci	struct xarray prots;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	wait_queue_head_t wq;
5762306a36Sopenharmony_ci	struct workqueue_struct *work_queue;
5862306a36Sopenharmony_ci	unsigned long flags;
5962306a36Sopenharmony_ci};
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistruct pci_doe_protocol {
6262306a36Sopenharmony_ci	u16 vid;
6362306a36Sopenharmony_ci	u8 type;
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci/**
6762306a36Sopenharmony_ci * struct pci_doe_task - represents a single query/response
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci * @prot: DOE Protocol
7062306a36Sopenharmony_ci * @request_pl: The request payload
7162306a36Sopenharmony_ci * @request_pl_sz: Size of the request payload (bytes)
7262306a36Sopenharmony_ci * @response_pl: The response payload
7362306a36Sopenharmony_ci * @response_pl_sz: Size of the response payload (bytes)
7462306a36Sopenharmony_ci * @rv: Return value.  Length of received response or error (bytes)
7562306a36Sopenharmony_ci * @complete: Called when task is complete
7662306a36Sopenharmony_ci * @private: Private data for the consumer
7762306a36Sopenharmony_ci * @work: Used internally by the mailbox
7862306a36Sopenharmony_ci * @doe_mb: Used internally by the mailbox
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_cistruct pci_doe_task {
8162306a36Sopenharmony_ci	struct pci_doe_protocol prot;
8262306a36Sopenharmony_ci	const __le32 *request_pl;
8362306a36Sopenharmony_ci	size_t request_pl_sz;
8462306a36Sopenharmony_ci	__le32 *response_pl;
8562306a36Sopenharmony_ci	size_t response_pl_sz;
8662306a36Sopenharmony_ci	int rv;
8762306a36Sopenharmony_ci	void (*complete)(struct pci_doe_task *task);
8862306a36Sopenharmony_ci	void *private;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* initialized by pci_doe_submit_task() */
9162306a36Sopenharmony_ci	struct work_struct work;
9262306a36Sopenharmony_ci	struct pci_doe_mb *doe_mb;
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic int pci_doe_wait(struct pci_doe_mb *doe_mb, unsigned long timeout)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	if (wait_event_timeout(doe_mb->wq,
9862306a36Sopenharmony_ci			       test_bit(PCI_DOE_FLAG_CANCEL, &doe_mb->flags),
9962306a36Sopenharmony_ci			       timeout))
10062306a36Sopenharmony_ci		return -EIO;
10162306a36Sopenharmony_ci	return 0;
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_cistatic void pci_doe_write_ctrl(struct pci_doe_mb *doe_mb, u32 val)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct pci_dev *pdev = doe_mb->pdev;
10762306a36Sopenharmony_ci	int offset = doe_mb->cap_offset;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	pci_write_config_dword(pdev, offset + PCI_DOE_CTRL, val);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_cistatic int pci_doe_abort(struct pci_doe_mb *doe_mb)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	struct pci_dev *pdev = doe_mb->pdev;
11562306a36Sopenharmony_ci	int offset = doe_mb->cap_offset;
11662306a36Sopenharmony_ci	unsigned long timeout_jiffies;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	pci_dbg(pdev, "[%x] Issuing Abort\n", offset);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	timeout_jiffies = jiffies + PCI_DOE_TIMEOUT;
12162306a36Sopenharmony_ci	pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_ABORT);
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	do {
12462306a36Sopenharmony_ci		int rc;
12562306a36Sopenharmony_ci		u32 val;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci		rc = pci_doe_wait(doe_mb, PCI_DOE_POLL_INTERVAL);
12862306a36Sopenharmony_ci		if (rc)
12962306a36Sopenharmony_ci			return rc;
13062306a36Sopenharmony_ci		pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		/* Abort success! */
13362306a36Sopenharmony_ci		if (!FIELD_GET(PCI_DOE_STATUS_ERROR, val) &&
13462306a36Sopenharmony_ci		    !FIELD_GET(PCI_DOE_STATUS_BUSY, val))
13562306a36Sopenharmony_ci			return 0;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	} while (!time_after(jiffies, timeout_jiffies));
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	/* Abort has timed out and the MB is dead */
14062306a36Sopenharmony_ci	pci_err(pdev, "[%x] ABORT timed out\n", offset);
14162306a36Sopenharmony_ci	return -EIO;
14262306a36Sopenharmony_ci}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_cistatic int pci_doe_send_req(struct pci_doe_mb *doe_mb,
14562306a36Sopenharmony_ci			    struct pci_doe_task *task)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	struct pci_dev *pdev = doe_mb->pdev;
14862306a36Sopenharmony_ci	int offset = doe_mb->cap_offset;
14962306a36Sopenharmony_ci	size_t length, remainder;
15062306a36Sopenharmony_ci	u32 val;
15162306a36Sopenharmony_ci	int i;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/*
15462306a36Sopenharmony_ci	 * Check the DOE busy bit is not set. If it is set, this could indicate
15562306a36Sopenharmony_ci	 * someone other than Linux (e.g. firmware) is using the mailbox. Note
15662306a36Sopenharmony_ci	 * it is expected that firmware and OS will negotiate access rights via
15762306a36Sopenharmony_ci	 * an, as yet to be defined, method.
15862306a36Sopenharmony_ci	 */
15962306a36Sopenharmony_ci	pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
16062306a36Sopenharmony_ci	if (FIELD_GET(PCI_DOE_STATUS_BUSY, val))
16162306a36Sopenharmony_ci		return -EBUSY;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	if (FIELD_GET(PCI_DOE_STATUS_ERROR, val))
16462306a36Sopenharmony_ci		return -EIO;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	/* Length is 2 DW of header + length of payload in DW */
16762306a36Sopenharmony_ci	length = 2 + DIV_ROUND_UP(task->request_pl_sz, sizeof(__le32));
16862306a36Sopenharmony_ci	if (length > PCI_DOE_MAX_LENGTH)
16962306a36Sopenharmony_ci		return -EIO;
17062306a36Sopenharmony_ci	if (length == PCI_DOE_MAX_LENGTH)
17162306a36Sopenharmony_ci		length = 0;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	/* Write DOE Header */
17462306a36Sopenharmony_ci	val = FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_VID, task->prot.vid) |
17562306a36Sopenharmony_ci		FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, task->prot.type);
17662306a36Sopenharmony_ci	pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, val);
17762306a36Sopenharmony_ci	pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
17862306a36Sopenharmony_ci			       FIELD_PREP(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH,
17962306a36Sopenharmony_ci					  length));
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	/* Write payload */
18262306a36Sopenharmony_ci	for (i = 0; i < task->request_pl_sz / sizeof(__le32); i++)
18362306a36Sopenharmony_ci		pci_write_config_dword(pdev, offset + PCI_DOE_WRITE,
18462306a36Sopenharmony_ci				       le32_to_cpu(task->request_pl[i]));
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	/* Write last payload dword */
18762306a36Sopenharmony_ci	remainder = task->request_pl_sz % sizeof(__le32);
18862306a36Sopenharmony_ci	if (remainder) {
18962306a36Sopenharmony_ci		val = 0;
19062306a36Sopenharmony_ci		memcpy(&val, &task->request_pl[i], remainder);
19162306a36Sopenharmony_ci		le32_to_cpus(&val);
19262306a36Sopenharmony_ci		pci_write_config_dword(pdev, offset + PCI_DOE_WRITE, val);
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	pci_doe_write_ctrl(doe_mb, PCI_DOE_CTRL_GO);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	return 0;
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic bool pci_doe_data_obj_ready(struct pci_doe_mb *doe_mb)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct pci_dev *pdev = doe_mb->pdev;
20362306a36Sopenharmony_ci	int offset = doe_mb->cap_offset;
20462306a36Sopenharmony_ci	u32 val;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
20762306a36Sopenharmony_ci	if (FIELD_GET(PCI_DOE_STATUS_DATA_OBJECT_READY, val))
20862306a36Sopenharmony_ci		return true;
20962306a36Sopenharmony_ci	return false;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *task)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	size_t length, payload_length, remainder, received;
21562306a36Sopenharmony_ci	struct pci_dev *pdev = doe_mb->pdev;
21662306a36Sopenharmony_ci	int offset = doe_mb->cap_offset;
21762306a36Sopenharmony_ci	int i = 0;
21862306a36Sopenharmony_ci	u32 val;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/* Read the first dword to get the protocol */
22162306a36Sopenharmony_ci	pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
22262306a36Sopenharmony_ci	if ((FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, val) != task->prot.vid) ||
22362306a36Sopenharmony_ci	    (FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, val) != task->prot.type)) {
22462306a36Sopenharmony_ci		dev_err_ratelimited(&pdev->dev, "[%x] expected [VID, Protocol] = [%04x, %02x], got [%04x, %02x]\n",
22562306a36Sopenharmony_ci				    doe_mb->cap_offset, task->prot.vid, task->prot.type,
22662306a36Sopenharmony_ci				    FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_VID, val),
22762306a36Sopenharmony_ci				    FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_1_TYPE, val));
22862306a36Sopenharmony_ci		return -EIO;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
23262306a36Sopenharmony_ci	/* Read the second dword to get the length */
23362306a36Sopenharmony_ci	pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
23462306a36Sopenharmony_ci	pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	length = FIELD_GET(PCI_DOE_DATA_OBJECT_HEADER_2_LENGTH, val);
23762306a36Sopenharmony_ci	/* A value of 0x0 indicates max data object length */
23862306a36Sopenharmony_ci	if (!length)
23962306a36Sopenharmony_ci		length = PCI_DOE_MAX_LENGTH;
24062306a36Sopenharmony_ci	if (length < 2)
24162306a36Sopenharmony_ci		return -EIO;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	/* First 2 dwords have already been read */
24462306a36Sopenharmony_ci	length -= 2;
24562306a36Sopenharmony_ci	received = task->response_pl_sz;
24662306a36Sopenharmony_ci	payload_length = DIV_ROUND_UP(task->response_pl_sz, sizeof(__le32));
24762306a36Sopenharmony_ci	remainder = task->response_pl_sz % sizeof(__le32);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	/* remainder signifies number of data bytes in last payload dword */
25062306a36Sopenharmony_ci	if (!remainder)
25162306a36Sopenharmony_ci		remainder = sizeof(__le32);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (length < payload_length) {
25462306a36Sopenharmony_ci		received = length * sizeof(__le32);
25562306a36Sopenharmony_ci		payload_length = length;
25662306a36Sopenharmony_ci		remainder = sizeof(__le32);
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (payload_length) {
26062306a36Sopenharmony_ci		/* Read all payload dwords except the last */
26162306a36Sopenharmony_ci		for (; i < payload_length - 1; i++) {
26262306a36Sopenharmony_ci			pci_read_config_dword(pdev, offset + PCI_DOE_READ,
26362306a36Sopenharmony_ci					      &val);
26462306a36Sopenharmony_ci			task->response_pl[i] = cpu_to_le32(val);
26562306a36Sopenharmony_ci			pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
26662306a36Sopenharmony_ci		}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		/* Read last payload dword */
26962306a36Sopenharmony_ci		pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
27062306a36Sopenharmony_ci		cpu_to_le32s(&val);
27162306a36Sopenharmony_ci		memcpy(&task->response_pl[i], &val, remainder);
27262306a36Sopenharmony_ci		/* Prior to the last ack, ensure Data Object Ready */
27362306a36Sopenharmony_ci		if (!pci_doe_data_obj_ready(doe_mb))
27462306a36Sopenharmony_ci			return -EIO;
27562306a36Sopenharmony_ci		pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
27662306a36Sopenharmony_ci		i++;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/* Flush excess length */
28062306a36Sopenharmony_ci	for (; i < length; i++) {
28162306a36Sopenharmony_ci		pci_read_config_dword(pdev, offset + PCI_DOE_READ, &val);
28262306a36Sopenharmony_ci		pci_write_config_dword(pdev, offset + PCI_DOE_READ, 0);
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* Final error check to pick up on any since Data Object Ready */
28662306a36Sopenharmony_ci	pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
28762306a36Sopenharmony_ci	if (FIELD_GET(PCI_DOE_STATUS_ERROR, val))
28862306a36Sopenharmony_ci		return -EIO;
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci	return received;
29162306a36Sopenharmony_ci}
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic void signal_task_complete(struct pci_doe_task *task, int rv)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	task->rv = rv;
29662306a36Sopenharmony_ci	destroy_work_on_stack(&task->work);
29762306a36Sopenharmony_ci	task->complete(task);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic void signal_task_abort(struct pci_doe_task *task, int rv)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	struct pci_doe_mb *doe_mb = task->doe_mb;
30362306a36Sopenharmony_ci	struct pci_dev *pdev = doe_mb->pdev;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (pci_doe_abort(doe_mb)) {
30662306a36Sopenharmony_ci		/*
30762306a36Sopenharmony_ci		 * If the device can't process an abort; set the mailbox dead
30862306a36Sopenharmony_ci		 *	- no more submissions
30962306a36Sopenharmony_ci		 */
31062306a36Sopenharmony_ci		pci_err(pdev, "[%x] Abort failed marking mailbox dead\n",
31162306a36Sopenharmony_ci			doe_mb->cap_offset);
31262306a36Sopenharmony_ci		set_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags);
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci	signal_task_complete(task, rv);
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_cistatic void doe_statemachine_work(struct work_struct *work)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	struct pci_doe_task *task = container_of(work, struct pci_doe_task,
32062306a36Sopenharmony_ci						 work);
32162306a36Sopenharmony_ci	struct pci_doe_mb *doe_mb = task->doe_mb;
32262306a36Sopenharmony_ci	struct pci_dev *pdev = doe_mb->pdev;
32362306a36Sopenharmony_ci	int offset = doe_mb->cap_offset;
32462306a36Sopenharmony_ci	unsigned long timeout_jiffies;
32562306a36Sopenharmony_ci	u32 val;
32662306a36Sopenharmony_ci	int rc;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags)) {
32962306a36Sopenharmony_ci		signal_task_complete(task, -EIO);
33062306a36Sopenharmony_ci		return;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* Send request */
33462306a36Sopenharmony_ci	rc = pci_doe_send_req(doe_mb, task);
33562306a36Sopenharmony_ci	if (rc) {
33662306a36Sopenharmony_ci		/*
33762306a36Sopenharmony_ci		 * The specification does not provide any guidance on how to
33862306a36Sopenharmony_ci		 * resolve conflicting requests from other entities.
33962306a36Sopenharmony_ci		 * Furthermore, it is likely that busy will not be detected
34062306a36Sopenharmony_ci		 * most of the time.  Flag any detection of status busy with an
34162306a36Sopenharmony_ci		 * error.
34262306a36Sopenharmony_ci		 */
34362306a36Sopenharmony_ci		if (rc == -EBUSY)
34462306a36Sopenharmony_ci			dev_err_ratelimited(&pdev->dev, "[%x] busy detected; another entity is sending conflicting requests\n",
34562306a36Sopenharmony_ci					    offset);
34662306a36Sopenharmony_ci		signal_task_abort(task, rc);
34762306a36Sopenharmony_ci		return;
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	timeout_jiffies = jiffies + PCI_DOE_TIMEOUT;
35162306a36Sopenharmony_ci	/* Poll for response */
35262306a36Sopenharmony_ciretry_resp:
35362306a36Sopenharmony_ci	pci_read_config_dword(pdev, offset + PCI_DOE_STATUS, &val);
35462306a36Sopenharmony_ci	if (FIELD_GET(PCI_DOE_STATUS_ERROR, val)) {
35562306a36Sopenharmony_ci		signal_task_abort(task, -EIO);
35662306a36Sopenharmony_ci		return;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (!FIELD_GET(PCI_DOE_STATUS_DATA_OBJECT_READY, val)) {
36062306a36Sopenharmony_ci		if (time_after(jiffies, timeout_jiffies)) {
36162306a36Sopenharmony_ci			signal_task_abort(task, -EIO);
36262306a36Sopenharmony_ci			return;
36362306a36Sopenharmony_ci		}
36462306a36Sopenharmony_ci		rc = pci_doe_wait(doe_mb, PCI_DOE_POLL_INTERVAL);
36562306a36Sopenharmony_ci		if (rc) {
36662306a36Sopenharmony_ci			signal_task_abort(task, rc);
36762306a36Sopenharmony_ci			return;
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci		goto retry_resp;
37062306a36Sopenharmony_ci	}
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	rc  = pci_doe_recv_resp(doe_mb, task);
37362306a36Sopenharmony_ci	if (rc < 0) {
37462306a36Sopenharmony_ci		signal_task_abort(task, rc);
37562306a36Sopenharmony_ci		return;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	signal_task_complete(task, rc);
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic void pci_doe_task_complete(struct pci_doe_task *task)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	complete(task->private);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_cistatic int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 *index, u16 *vid,
38762306a36Sopenharmony_ci			     u8 *protocol)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	u32 request_pl = FIELD_PREP(PCI_DOE_DATA_OBJECT_DISC_REQ_3_INDEX,
39062306a36Sopenharmony_ci				    *index);
39162306a36Sopenharmony_ci	__le32 request_pl_le = cpu_to_le32(request_pl);
39262306a36Sopenharmony_ci	__le32 response_pl_le;
39362306a36Sopenharmony_ci	u32 response_pl;
39462306a36Sopenharmony_ci	int rc;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	rc = pci_doe(doe_mb, PCI_VENDOR_ID_PCI_SIG, PCI_DOE_PROTOCOL_DISCOVERY,
39762306a36Sopenharmony_ci		     &request_pl_le, sizeof(request_pl_le),
39862306a36Sopenharmony_ci		     &response_pl_le, sizeof(response_pl_le));
39962306a36Sopenharmony_ci	if (rc < 0)
40062306a36Sopenharmony_ci		return rc;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if (rc != sizeof(response_pl_le))
40362306a36Sopenharmony_ci		return -EIO;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	response_pl = le32_to_cpu(response_pl_le);
40662306a36Sopenharmony_ci	*vid = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_VID, response_pl);
40762306a36Sopenharmony_ci	*protocol = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_PROTOCOL,
40862306a36Sopenharmony_ci			      response_pl);
40962306a36Sopenharmony_ci	*index = FIELD_GET(PCI_DOE_DATA_OBJECT_DISC_RSP_3_NEXT_INDEX,
41062306a36Sopenharmony_ci			   response_pl);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	return 0;
41362306a36Sopenharmony_ci}
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_cistatic void *pci_doe_xa_prot_entry(u16 vid, u8 prot)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	return xa_mk_value((vid << 8) | prot);
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic int pci_doe_cache_protocols(struct pci_doe_mb *doe_mb)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	u8 index = 0;
42362306a36Sopenharmony_ci	u8 xa_idx = 0;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	do {
42662306a36Sopenharmony_ci		int rc;
42762306a36Sopenharmony_ci		u16 vid;
42862306a36Sopenharmony_ci		u8 prot;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci		rc = pci_doe_discovery(doe_mb, &index, &vid, &prot);
43162306a36Sopenharmony_ci		if (rc)
43262306a36Sopenharmony_ci			return rc;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		pci_dbg(doe_mb->pdev,
43562306a36Sopenharmony_ci			"[%x] Found protocol %d vid: %x prot: %x\n",
43662306a36Sopenharmony_ci			doe_mb->cap_offset, xa_idx, vid, prot);
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci		rc = xa_insert(&doe_mb->prots, xa_idx++,
43962306a36Sopenharmony_ci			       pci_doe_xa_prot_entry(vid, prot), GFP_KERNEL);
44062306a36Sopenharmony_ci		if (rc)
44162306a36Sopenharmony_ci			return rc;
44262306a36Sopenharmony_ci	} while (index);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	return 0;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_cistatic void pci_doe_cancel_tasks(struct pci_doe_mb *doe_mb)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	/* Stop all pending work items from starting */
45062306a36Sopenharmony_ci	set_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags);
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	/* Cancel an in progress work item, if necessary */
45362306a36Sopenharmony_ci	set_bit(PCI_DOE_FLAG_CANCEL, &doe_mb->flags);
45462306a36Sopenharmony_ci	wake_up(&doe_mb->wq);
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci/**
45862306a36Sopenharmony_ci * pci_doe_create_mb() - Create a DOE mailbox object
45962306a36Sopenharmony_ci *
46062306a36Sopenharmony_ci * @pdev: PCI device to create the DOE mailbox for
46162306a36Sopenharmony_ci * @cap_offset: Offset of the DOE mailbox
46262306a36Sopenharmony_ci *
46362306a36Sopenharmony_ci * Create a single mailbox object to manage the mailbox protocol at the
46462306a36Sopenharmony_ci * cap_offset specified.
46562306a36Sopenharmony_ci *
46662306a36Sopenharmony_ci * RETURNS: created mailbox object on success
46762306a36Sopenharmony_ci *	    ERR_PTR(-errno) on failure
46862306a36Sopenharmony_ci */
46962306a36Sopenharmony_cistatic struct pci_doe_mb *pci_doe_create_mb(struct pci_dev *pdev,
47062306a36Sopenharmony_ci					    u16 cap_offset)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	struct pci_doe_mb *doe_mb;
47362306a36Sopenharmony_ci	int rc;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	doe_mb = kzalloc(sizeof(*doe_mb), GFP_KERNEL);
47662306a36Sopenharmony_ci	if (!doe_mb)
47762306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	doe_mb->pdev = pdev;
48062306a36Sopenharmony_ci	doe_mb->cap_offset = cap_offset;
48162306a36Sopenharmony_ci	init_waitqueue_head(&doe_mb->wq);
48262306a36Sopenharmony_ci	xa_init(&doe_mb->prots);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	doe_mb->work_queue = alloc_ordered_workqueue("%s %s DOE [%x]", 0,
48562306a36Sopenharmony_ci						dev_bus_name(&pdev->dev),
48662306a36Sopenharmony_ci						pci_name(pdev),
48762306a36Sopenharmony_ci						doe_mb->cap_offset);
48862306a36Sopenharmony_ci	if (!doe_mb->work_queue) {
48962306a36Sopenharmony_ci		pci_err(pdev, "[%x] failed to allocate work queue\n",
49062306a36Sopenharmony_ci			doe_mb->cap_offset);
49162306a36Sopenharmony_ci		rc = -ENOMEM;
49262306a36Sopenharmony_ci		goto err_free;
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/* Reset the mailbox by issuing an abort */
49662306a36Sopenharmony_ci	rc = pci_doe_abort(doe_mb);
49762306a36Sopenharmony_ci	if (rc) {
49862306a36Sopenharmony_ci		pci_err(pdev, "[%x] failed to reset mailbox with abort command : %d\n",
49962306a36Sopenharmony_ci			doe_mb->cap_offset, rc);
50062306a36Sopenharmony_ci		goto err_destroy_wq;
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	/*
50462306a36Sopenharmony_ci	 * The state machine and the mailbox should be in sync now;
50562306a36Sopenharmony_ci	 * Use the mailbox to query protocols.
50662306a36Sopenharmony_ci	 */
50762306a36Sopenharmony_ci	rc = pci_doe_cache_protocols(doe_mb);
50862306a36Sopenharmony_ci	if (rc) {
50962306a36Sopenharmony_ci		pci_err(pdev, "[%x] failed to cache protocols : %d\n",
51062306a36Sopenharmony_ci			doe_mb->cap_offset, rc);
51162306a36Sopenharmony_ci		goto err_cancel;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	return doe_mb;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_cierr_cancel:
51762306a36Sopenharmony_ci	pci_doe_cancel_tasks(doe_mb);
51862306a36Sopenharmony_ci	xa_destroy(&doe_mb->prots);
51962306a36Sopenharmony_cierr_destroy_wq:
52062306a36Sopenharmony_ci	destroy_workqueue(doe_mb->work_queue);
52162306a36Sopenharmony_cierr_free:
52262306a36Sopenharmony_ci	kfree(doe_mb);
52362306a36Sopenharmony_ci	return ERR_PTR(rc);
52462306a36Sopenharmony_ci}
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci/**
52762306a36Sopenharmony_ci * pci_doe_destroy_mb() - Destroy a DOE mailbox object
52862306a36Sopenharmony_ci *
52962306a36Sopenharmony_ci * @doe_mb: DOE mailbox
53062306a36Sopenharmony_ci *
53162306a36Sopenharmony_ci * Destroy all internal data structures created for the DOE mailbox.
53262306a36Sopenharmony_ci */
53362306a36Sopenharmony_cistatic void pci_doe_destroy_mb(struct pci_doe_mb *doe_mb)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	pci_doe_cancel_tasks(doe_mb);
53662306a36Sopenharmony_ci	xa_destroy(&doe_mb->prots);
53762306a36Sopenharmony_ci	destroy_workqueue(doe_mb->work_queue);
53862306a36Sopenharmony_ci	kfree(doe_mb);
53962306a36Sopenharmony_ci}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci/**
54262306a36Sopenharmony_ci * pci_doe_supports_prot() - Return if the DOE instance supports the given
54362306a36Sopenharmony_ci *			     protocol
54462306a36Sopenharmony_ci * @doe_mb: DOE mailbox capability to query
54562306a36Sopenharmony_ci * @vid: Protocol Vendor ID
54662306a36Sopenharmony_ci * @type: Protocol type
54762306a36Sopenharmony_ci *
54862306a36Sopenharmony_ci * RETURNS: True if the DOE mailbox supports the protocol specified
54962306a36Sopenharmony_ci */
55062306a36Sopenharmony_cistatic bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type)
55162306a36Sopenharmony_ci{
55262306a36Sopenharmony_ci	unsigned long index;
55362306a36Sopenharmony_ci	void *entry;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	/* The discovery protocol must always be supported */
55662306a36Sopenharmony_ci	if (vid == PCI_VENDOR_ID_PCI_SIG && type == PCI_DOE_PROTOCOL_DISCOVERY)
55762306a36Sopenharmony_ci		return true;
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	xa_for_each(&doe_mb->prots, index, entry)
56062306a36Sopenharmony_ci		if (entry == pci_doe_xa_prot_entry(vid, type))
56162306a36Sopenharmony_ci			return true;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	return false;
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci/**
56762306a36Sopenharmony_ci * pci_doe_submit_task() - Submit a task to be processed by the state machine
56862306a36Sopenharmony_ci *
56962306a36Sopenharmony_ci * @doe_mb: DOE mailbox capability to submit to
57062306a36Sopenharmony_ci * @task: task to be queued
57162306a36Sopenharmony_ci *
57262306a36Sopenharmony_ci * Submit a DOE task (request/response) to the DOE mailbox to be processed.
57362306a36Sopenharmony_ci * Returns upon queueing the task object.  If the queue is full this function
57462306a36Sopenharmony_ci * will sleep until there is room in the queue.
57562306a36Sopenharmony_ci *
57662306a36Sopenharmony_ci * task->complete will be called when the state machine is done processing this
57762306a36Sopenharmony_ci * task.
57862306a36Sopenharmony_ci *
57962306a36Sopenharmony_ci * @task must be allocated on the stack.
58062306a36Sopenharmony_ci *
58162306a36Sopenharmony_ci * Excess data will be discarded.
58262306a36Sopenharmony_ci *
58362306a36Sopenharmony_ci * RETURNS: 0 when task has been successfully queued, -ERRNO on error
58462306a36Sopenharmony_ci */
58562306a36Sopenharmony_cistatic int pci_doe_submit_task(struct pci_doe_mb *doe_mb,
58662306a36Sopenharmony_ci			       struct pci_doe_task *task)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	if (!pci_doe_supports_prot(doe_mb, task->prot.vid, task->prot.type))
58962306a36Sopenharmony_ci		return -EINVAL;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	if (test_bit(PCI_DOE_FLAG_DEAD, &doe_mb->flags))
59262306a36Sopenharmony_ci		return -EIO;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	task->doe_mb = doe_mb;
59562306a36Sopenharmony_ci	INIT_WORK_ONSTACK(&task->work, doe_statemachine_work);
59662306a36Sopenharmony_ci	queue_work(doe_mb->work_queue, &task->work);
59762306a36Sopenharmony_ci	return 0;
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci/**
60162306a36Sopenharmony_ci * pci_doe() - Perform Data Object Exchange
60262306a36Sopenharmony_ci *
60362306a36Sopenharmony_ci * @doe_mb: DOE Mailbox
60462306a36Sopenharmony_ci * @vendor: Vendor ID
60562306a36Sopenharmony_ci * @type: Data Object Type
60662306a36Sopenharmony_ci * @request: Request payload
60762306a36Sopenharmony_ci * @request_sz: Size of request payload (bytes)
60862306a36Sopenharmony_ci * @response: Response payload
60962306a36Sopenharmony_ci * @response_sz: Size of response payload (bytes)
61062306a36Sopenharmony_ci *
61162306a36Sopenharmony_ci * Submit @request to @doe_mb and store the @response.
61262306a36Sopenharmony_ci * The DOE exchange is performed synchronously and may therefore sleep.
61362306a36Sopenharmony_ci *
61462306a36Sopenharmony_ci * Payloads are treated as opaque byte streams which are transmitted verbatim,
61562306a36Sopenharmony_ci * without byte-swapping.  If payloads contain little-endian register values,
61662306a36Sopenharmony_ci * the caller is responsible for conversion with cpu_to_le32() / le32_to_cpu().
61762306a36Sopenharmony_ci *
61862306a36Sopenharmony_ci * For convenience, arbitrary payload sizes are allowed even though PCIe r6.0
61962306a36Sopenharmony_ci * sec 6.30.1 specifies the Data Object Header 2 "Length" in dwords.  The last
62062306a36Sopenharmony_ci * (partial) dword is copied with byte granularity and padded with zeroes if
62162306a36Sopenharmony_ci * necessary.  Callers are thus relieved of using dword-sized bounce buffers.
62262306a36Sopenharmony_ci *
62362306a36Sopenharmony_ci * RETURNS: Length of received response or negative errno.
62462306a36Sopenharmony_ci * Received data in excess of @response_sz is discarded.
62562306a36Sopenharmony_ci * The length may be smaller than @response_sz and the caller
62662306a36Sopenharmony_ci * is responsible for checking that.
62762306a36Sopenharmony_ci */
62862306a36Sopenharmony_ciint pci_doe(struct pci_doe_mb *doe_mb, u16 vendor, u8 type,
62962306a36Sopenharmony_ci	    const void *request, size_t request_sz,
63062306a36Sopenharmony_ci	    void *response, size_t response_sz)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	DECLARE_COMPLETION_ONSTACK(c);
63362306a36Sopenharmony_ci	struct pci_doe_task task = {
63462306a36Sopenharmony_ci		.prot.vid = vendor,
63562306a36Sopenharmony_ci		.prot.type = type,
63662306a36Sopenharmony_ci		.request_pl = request,
63762306a36Sopenharmony_ci		.request_pl_sz = request_sz,
63862306a36Sopenharmony_ci		.response_pl = response,
63962306a36Sopenharmony_ci		.response_pl_sz = response_sz,
64062306a36Sopenharmony_ci		.complete = pci_doe_task_complete,
64162306a36Sopenharmony_ci		.private = &c,
64262306a36Sopenharmony_ci	};
64362306a36Sopenharmony_ci	int rc;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	rc = pci_doe_submit_task(doe_mb, &task);
64662306a36Sopenharmony_ci	if (rc)
64762306a36Sopenharmony_ci		return rc;
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	wait_for_completion(&c);
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	return task.rv;
65262306a36Sopenharmony_ci}
65362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_doe);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci/**
65662306a36Sopenharmony_ci * pci_find_doe_mailbox() - Find Data Object Exchange mailbox
65762306a36Sopenharmony_ci *
65862306a36Sopenharmony_ci * @pdev: PCI device
65962306a36Sopenharmony_ci * @vendor: Vendor ID
66062306a36Sopenharmony_ci * @type: Data Object Type
66162306a36Sopenharmony_ci *
66262306a36Sopenharmony_ci * Find first DOE mailbox of a PCI device which supports the given protocol.
66362306a36Sopenharmony_ci *
66462306a36Sopenharmony_ci * RETURNS: Pointer to the DOE mailbox or NULL if none was found.
66562306a36Sopenharmony_ci */
66662306a36Sopenharmony_cistruct pci_doe_mb *pci_find_doe_mailbox(struct pci_dev *pdev, u16 vendor,
66762306a36Sopenharmony_ci					u8 type)
66862306a36Sopenharmony_ci{
66962306a36Sopenharmony_ci	struct pci_doe_mb *doe_mb;
67062306a36Sopenharmony_ci	unsigned long index;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	xa_for_each(&pdev->doe_mbs, index, doe_mb)
67362306a36Sopenharmony_ci		if (pci_doe_supports_prot(doe_mb, vendor, type))
67462306a36Sopenharmony_ci			return doe_mb;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	return NULL;
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_find_doe_mailbox);
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_civoid pci_doe_init(struct pci_dev *pdev)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	struct pci_doe_mb *doe_mb;
68362306a36Sopenharmony_ci	u16 offset = 0;
68462306a36Sopenharmony_ci	int rc;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	xa_init(&pdev->doe_mbs);
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	while ((offset = pci_find_next_ext_capability(pdev, offset,
68962306a36Sopenharmony_ci						      PCI_EXT_CAP_ID_DOE))) {
69062306a36Sopenharmony_ci		doe_mb = pci_doe_create_mb(pdev, offset);
69162306a36Sopenharmony_ci		if (IS_ERR(doe_mb)) {
69262306a36Sopenharmony_ci			pci_err(pdev, "[%x] failed to create mailbox: %ld\n",
69362306a36Sopenharmony_ci				offset, PTR_ERR(doe_mb));
69462306a36Sopenharmony_ci			continue;
69562306a36Sopenharmony_ci		}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci		rc = xa_insert(&pdev->doe_mbs, offset, doe_mb, GFP_KERNEL);
69862306a36Sopenharmony_ci		if (rc) {
69962306a36Sopenharmony_ci			pci_err(pdev, "[%x] failed to insert mailbox: %d\n",
70062306a36Sopenharmony_ci				offset, rc);
70162306a36Sopenharmony_ci			pci_doe_destroy_mb(doe_mb);
70262306a36Sopenharmony_ci		}
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_civoid pci_doe_destroy(struct pci_dev *pdev)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	struct pci_doe_mb *doe_mb;
70962306a36Sopenharmony_ci	unsigned long index;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	xa_for_each(&pdev->doe_mbs, index, doe_mb)
71262306a36Sopenharmony_ci		pci_doe_destroy_mb(doe_mb);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	xa_destroy(&pdev->doe_mbs);
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_civoid pci_doe_disconnected(struct pci_dev *pdev)
71862306a36Sopenharmony_ci{
71962306a36Sopenharmony_ci	struct pci_doe_mb *doe_mb;
72062306a36Sopenharmony_ci	unsigned long index;
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	xa_for_each(&pdev->doe_mbs, index, doe_mb)
72362306a36Sopenharmony_ci		pci_doe_cancel_tasks(doe_mb);
72462306a36Sopenharmony_ci}
725