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