// SPDX-License-Identifier: GPL-2.0 /* * Data Object Exchange * PCIe r6.0, sec 6.30 DOE * * Copyright (C) 2021 Huawei * Jonathan Cameron <[email protected]> * * Copyright (C) 2022 Intel Corporation * Ira Weiny <[email protected]> */ #define dev_fmt(fmt) … #include <linux/bitfield.h> #include <linux/delay.h> #include <linux/jiffies.h> #include <linux/mutex.h> #include <linux/pci.h> #include <linux/pci-doe.h> #include <linux/workqueue.h> #include "pci.h" #define PCI_DOE_PROTOCOL_DISCOVERY … /* Timeout of 1 second from 6.30.2 Operation, PCI Spec r6.0 */ #define PCI_DOE_TIMEOUT … #define PCI_DOE_POLL_INTERVAL … #define PCI_DOE_FLAG_CANCEL … #define PCI_DOE_FLAG_DEAD … /* Max data object length is 2^18 dwords */ #define PCI_DOE_MAX_LENGTH … /** * struct pci_doe_mb - State for a single DOE mailbox * * This state is used to manage a single DOE mailbox capability. All fields * should be considered opaque to the consumers and the structure passed into * the helpers below after being created by pci_doe_create_mb(). * * @pdev: PCI device this mailbox belongs to * @cap_offset: Capability offset * @prots: Array of protocols supported (encoded as long values) * @wq: Wait queue for work item * @work_queue: Queue of pci_doe_work items * @flags: Bit array of PCI_DOE_FLAG_* flags */ struct pci_doe_mb { … }; struct pci_doe_protocol { … }; /** * struct pci_doe_task - represents a single query/response * * @prot: DOE Protocol * @request_pl: The request payload * @request_pl_sz: Size of the request payload (bytes) * @response_pl: The response payload * @response_pl_sz: Size of the response payload (bytes) * @rv: Return value. Length of received response or error (bytes) * @complete: Called when task is complete * @private: Private data for the consumer * @work: Used internally by the mailbox * @doe_mb: Used internally by the mailbox */ struct pci_doe_task { … }; static int pci_doe_wait(struct pci_doe_mb *doe_mb, unsigned long timeout) { … } static void pci_doe_write_ctrl(struct pci_doe_mb *doe_mb, u32 val) { … } static int pci_doe_abort(struct pci_doe_mb *doe_mb) { … } static int pci_doe_send_req(struct pci_doe_mb *doe_mb, struct pci_doe_task *task) { … } static bool pci_doe_data_obj_ready(struct pci_doe_mb *doe_mb) { … } static int pci_doe_recv_resp(struct pci_doe_mb *doe_mb, struct pci_doe_task *task) { … } static void signal_task_complete(struct pci_doe_task *task, int rv) { … } static void signal_task_abort(struct pci_doe_task *task, int rv) { … } static void doe_statemachine_work(struct work_struct *work) { … } static void pci_doe_task_complete(struct pci_doe_task *task) { … } static int pci_doe_discovery(struct pci_doe_mb *doe_mb, u8 capver, u8 *index, u16 *vid, u8 *protocol) { … } static void *pci_doe_xa_prot_entry(u16 vid, u8 prot) { … } static int pci_doe_cache_protocols(struct pci_doe_mb *doe_mb) { … } static void pci_doe_cancel_tasks(struct pci_doe_mb *doe_mb) { … } /** * pci_doe_create_mb() - Create a DOE mailbox object * * @pdev: PCI device to create the DOE mailbox for * @cap_offset: Offset of the DOE mailbox * * Create a single mailbox object to manage the mailbox protocol at the * cap_offset specified. * * RETURNS: created mailbox object on success * ERR_PTR(-errno) on failure */ static struct pci_doe_mb *pci_doe_create_mb(struct pci_dev *pdev, u16 cap_offset) { … } /** * pci_doe_destroy_mb() - Destroy a DOE mailbox object * * @doe_mb: DOE mailbox * * Destroy all internal data structures created for the DOE mailbox. */ static void pci_doe_destroy_mb(struct pci_doe_mb *doe_mb) { … } /** * pci_doe_supports_prot() - Return if the DOE instance supports the given * protocol * @doe_mb: DOE mailbox capability to query * @vid: Protocol Vendor ID * @type: Protocol type * * RETURNS: True if the DOE mailbox supports the protocol specified */ static bool pci_doe_supports_prot(struct pci_doe_mb *doe_mb, u16 vid, u8 type) { … } /** * pci_doe_submit_task() - Submit a task to be processed by the state machine * * @doe_mb: DOE mailbox capability to submit to * @task: task to be queued * * Submit a DOE task (request/response) to the DOE mailbox to be processed. * Returns upon queueing the task object. If the queue is full this function * will sleep until there is room in the queue. * * task->complete will be called when the state machine is done processing this * task. * * @task must be allocated on the stack. * * Excess data will be discarded. * * RETURNS: 0 when task has been successfully queued, -ERRNO on error */ static int pci_doe_submit_task(struct pci_doe_mb *doe_mb, struct pci_doe_task *task) { … } /** * pci_doe() - Perform Data Object Exchange * * @doe_mb: DOE Mailbox * @vendor: Vendor ID * @type: Data Object Type * @request: Request payload * @request_sz: Size of request payload (bytes) * @response: Response payload * @response_sz: Size of response payload (bytes) * * Submit @request to @doe_mb and store the @response. * The DOE exchange is performed synchronously and may therefore sleep. * * Payloads are treated as opaque byte streams which are transmitted verbatim, * without byte-swapping. If payloads contain little-endian register values, * the caller is responsible for conversion with cpu_to_le32() / le32_to_cpu(). * * For convenience, arbitrary payload sizes are allowed even though PCIe r6.0 * sec 6.30.1 specifies the Data Object Header 2 "Length" in dwords. The last * (partial) dword is copied with byte granularity and padded with zeroes if * necessary. Callers are thus relieved of using dword-sized bounce buffers. * * RETURNS: Length of received response or negative errno. * Received data in excess of @response_sz is discarded. * The length may be smaller than @response_sz and the caller * is responsible for checking that. */ int 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) { … } EXPORT_SYMBOL_GPL(…); /** * pci_find_doe_mailbox() - Find Data Object Exchange mailbox * * @pdev: PCI device * @vendor: Vendor ID * @type: Data Object Type * * Find first DOE mailbox of a PCI device which supports the given protocol. * * RETURNS: Pointer to the DOE mailbox or NULL if none was found. */ struct pci_doe_mb *pci_find_doe_mailbox(struct pci_dev *pdev, u16 vendor, u8 type) { … } EXPORT_SYMBOL_GPL(…); void pci_doe_init(struct pci_dev *pdev) { … } void pci_doe_destroy(struct pci_dev *pdev) { … } void pci_doe_disconnected(struct pci_dev *pdev) { … }