162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci * 362306a36Sopenharmony_ci * Copyright (c) 2019-2021, The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#ifndef _QAIC_H_ 862306a36Sopenharmony_ci#define _QAIC_H_ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci#include <linux/kref.h> 1262306a36Sopenharmony_ci#include <linux/mhi.h> 1362306a36Sopenharmony_ci#include <linux/mutex.h> 1462306a36Sopenharmony_ci#include <linux/pci.h> 1562306a36Sopenharmony_ci#include <linux/spinlock.h> 1662306a36Sopenharmony_ci#include <linux/srcu.h> 1762306a36Sopenharmony_ci#include <linux/wait.h> 1862306a36Sopenharmony_ci#include <linux/workqueue.h> 1962306a36Sopenharmony_ci#include <drm/drm_device.h> 2062306a36Sopenharmony_ci#include <drm/drm_gem.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define QAIC_DBC_BASE SZ_128K 2362306a36Sopenharmony_ci#define QAIC_DBC_SIZE SZ_4K 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define QAIC_NO_PARTITION -1 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define QAIC_DBC_OFF(i) ((i) * QAIC_DBC_SIZE + QAIC_DBC_BASE) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define to_qaic_bo(obj) container_of(obj, struct qaic_bo, base) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ciextern bool datapath_polling; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistruct qaic_user { 3462306a36Sopenharmony_ci /* Uniquely identifies this user for the device */ 3562306a36Sopenharmony_ci int handle; 3662306a36Sopenharmony_ci struct kref ref_count; 3762306a36Sopenharmony_ci /* Char device opened by this user */ 3862306a36Sopenharmony_ci struct qaic_drm_device *qddev; 3962306a36Sopenharmony_ci /* Node in list of users that opened this drm device */ 4062306a36Sopenharmony_ci struct list_head node; 4162306a36Sopenharmony_ci /* SRCU used to synchronize this user during cleanup */ 4262306a36Sopenharmony_ci struct srcu_struct qddev_lock; 4362306a36Sopenharmony_ci atomic_t chunk_id; 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistruct dma_bridge_chan { 4762306a36Sopenharmony_ci /* Pointer to device strcut maintained by driver */ 4862306a36Sopenharmony_ci struct qaic_device *qdev; 4962306a36Sopenharmony_ci /* ID of this DMA bridge channel(DBC) */ 5062306a36Sopenharmony_ci unsigned int id; 5162306a36Sopenharmony_ci /* Synchronizes access to xfer_list */ 5262306a36Sopenharmony_ci spinlock_t xfer_lock; 5362306a36Sopenharmony_ci /* Base address of request queue */ 5462306a36Sopenharmony_ci void *req_q_base; 5562306a36Sopenharmony_ci /* Base address of response queue */ 5662306a36Sopenharmony_ci void *rsp_q_base; 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * Base bus address of request queue. Response queue bus address can be 5962306a36Sopenharmony_ci * calculated by adding request queue size to this variable 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_ci dma_addr_t dma_addr; 6262306a36Sopenharmony_ci /* Total size of request and response queue in byte */ 6362306a36Sopenharmony_ci u32 total_size; 6462306a36Sopenharmony_ci /* Capacity of request/response queue */ 6562306a36Sopenharmony_ci u32 nelem; 6662306a36Sopenharmony_ci /* The user that opened this DBC */ 6762306a36Sopenharmony_ci struct qaic_user *usr; 6862306a36Sopenharmony_ci /* 6962306a36Sopenharmony_ci * Request ID of next memory handle that goes in request queue. One 7062306a36Sopenharmony_ci * memory handle can enqueue more than one request elements, all 7162306a36Sopenharmony_ci * this requests that belong to same memory handle have same request ID 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci u16 next_req_id; 7462306a36Sopenharmony_ci /* true: DBC is in use; false: DBC not in use */ 7562306a36Sopenharmony_ci bool in_use; 7662306a36Sopenharmony_ci /* 7762306a36Sopenharmony_ci * Base address of device registers. Used to read/write request and 7862306a36Sopenharmony_ci * response queue's head and tail pointer of this DBC. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci void __iomem *dbc_base; 8162306a36Sopenharmony_ci /* Head of list where each node is a memory handle queued in request queue */ 8262306a36Sopenharmony_ci struct list_head xfer_list; 8362306a36Sopenharmony_ci /* Synchronizes DBC readers during cleanup */ 8462306a36Sopenharmony_ci struct srcu_struct ch_lock; 8562306a36Sopenharmony_ci /* 8662306a36Sopenharmony_ci * When this DBC is released, any thread waiting on this wait queue is 8762306a36Sopenharmony_ci * woken up 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci wait_queue_head_t dbc_release; 9062306a36Sopenharmony_ci /* Head of list where each node is a bo associated with this DBC */ 9162306a36Sopenharmony_ci struct list_head bo_lists; 9262306a36Sopenharmony_ci /* The irq line for this DBC. Used for polling */ 9362306a36Sopenharmony_ci unsigned int irq; 9462306a36Sopenharmony_ci /* Polling work item to simulate interrupts */ 9562306a36Sopenharmony_ci struct work_struct poll_work; 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistruct qaic_device { 9962306a36Sopenharmony_ci /* Pointer to base PCI device struct of our physical device */ 10062306a36Sopenharmony_ci struct pci_dev *pdev; 10162306a36Sopenharmony_ci /* Req. ID of request that will be queued next in MHI control device */ 10262306a36Sopenharmony_ci u32 next_seq_num; 10362306a36Sopenharmony_ci /* Base address of bar 0 */ 10462306a36Sopenharmony_ci void __iomem *bar_0; 10562306a36Sopenharmony_ci /* Base address of bar 2 */ 10662306a36Sopenharmony_ci void __iomem *bar_2; 10762306a36Sopenharmony_ci /* Controller structure for MHI devices */ 10862306a36Sopenharmony_ci struct mhi_controller *mhi_cntrl; 10962306a36Sopenharmony_ci /* MHI control channel device */ 11062306a36Sopenharmony_ci struct mhi_device *cntl_ch; 11162306a36Sopenharmony_ci /* List of requests queued in MHI control device */ 11262306a36Sopenharmony_ci struct list_head cntl_xfer_list; 11362306a36Sopenharmony_ci /* Synchronizes MHI control device transactions and its xfer list */ 11462306a36Sopenharmony_ci struct mutex cntl_mutex; 11562306a36Sopenharmony_ci /* Array of DBC struct of this device */ 11662306a36Sopenharmony_ci struct dma_bridge_chan *dbc; 11762306a36Sopenharmony_ci /* Work queue for tasks related to MHI control device */ 11862306a36Sopenharmony_ci struct workqueue_struct *cntl_wq; 11962306a36Sopenharmony_ci /* Synchronizes all the users of device during cleanup */ 12062306a36Sopenharmony_ci struct srcu_struct dev_lock; 12162306a36Sopenharmony_ci /* true: Device under reset; false: Device not under reset */ 12262306a36Sopenharmony_ci bool in_reset; 12362306a36Sopenharmony_ci /* 12462306a36Sopenharmony_ci * true: A tx MHI transaction has failed and a rx buffer is still queued 12562306a36Sopenharmony_ci * in control device. Such a buffer is considered lost rx buffer 12662306a36Sopenharmony_ci * false: No rx buffer is lost in control device 12762306a36Sopenharmony_ci */ 12862306a36Sopenharmony_ci bool cntl_lost_buf; 12962306a36Sopenharmony_ci /* Maximum number of DBC supported by this device */ 13062306a36Sopenharmony_ci u32 num_dbc; 13162306a36Sopenharmony_ci /* Reference to the drm_device for this device when it is created */ 13262306a36Sopenharmony_ci struct qaic_drm_device *qddev; 13362306a36Sopenharmony_ci /* Generate the CRC of a control message */ 13462306a36Sopenharmony_ci u32 (*gen_crc)(void *msg); 13562306a36Sopenharmony_ci /* Validate the CRC of a control message */ 13662306a36Sopenharmony_ci bool (*valid_crc)(void *msg); 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistruct qaic_drm_device { 14062306a36Sopenharmony_ci /* Pointer to the root device struct driven by this driver */ 14162306a36Sopenharmony_ci struct qaic_device *qdev; 14262306a36Sopenharmony_ci /* 14362306a36Sopenharmony_ci * The physical device can be partition in number of logical devices. 14462306a36Sopenharmony_ci * And each logical device is given a partition id. This member stores 14562306a36Sopenharmony_ci * that id. QAIC_NO_PARTITION is a sentinel used to mark that this drm 14662306a36Sopenharmony_ci * device is the actual physical device 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci s32 partition_id; 14962306a36Sopenharmony_ci /* Pointer to the drm device struct of this drm device */ 15062306a36Sopenharmony_ci struct drm_device *ddev; 15162306a36Sopenharmony_ci /* Head in list of users who have opened this drm device */ 15262306a36Sopenharmony_ci struct list_head users; 15362306a36Sopenharmony_ci /* Synchronizes access to users list */ 15462306a36Sopenharmony_ci struct mutex users_mutex; 15562306a36Sopenharmony_ci}; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistruct qaic_bo { 15862306a36Sopenharmony_ci struct drm_gem_object base; 15962306a36Sopenharmony_ci /* Scatter/gather table for allocate/imported BO */ 16062306a36Sopenharmony_ci struct sg_table *sgt; 16162306a36Sopenharmony_ci /* BO size requested by user. GEM object might be bigger in size. */ 16262306a36Sopenharmony_ci u64 size; 16362306a36Sopenharmony_ci /* Head in list of slices of this BO */ 16462306a36Sopenharmony_ci struct list_head slices; 16562306a36Sopenharmony_ci /* Total nents, for all slices of this BO */ 16662306a36Sopenharmony_ci int total_slice_nents; 16762306a36Sopenharmony_ci /* 16862306a36Sopenharmony_ci * Direction of transfer. It can assume only two value DMA_TO_DEVICE and 16962306a36Sopenharmony_ci * DMA_FROM_DEVICE. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_ci int dir; 17262306a36Sopenharmony_ci /* The pointer of the DBC which operates on this BO */ 17362306a36Sopenharmony_ci struct dma_bridge_chan *dbc; 17462306a36Sopenharmony_ci /* Number of slice that belongs to this buffer */ 17562306a36Sopenharmony_ci u32 nr_slice; 17662306a36Sopenharmony_ci /* Number of slice that have been transferred by DMA engine */ 17762306a36Sopenharmony_ci u32 nr_slice_xfer_done; 17862306a36Sopenharmony_ci /* true = BO is queued for execution, true = BO is not queued */ 17962306a36Sopenharmony_ci bool queued; 18062306a36Sopenharmony_ci /* 18162306a36Sopenharmony_ci * If true then user has attached slicing information to this BO by 18262306a36Sopenharmony_ci * calling DRM_IOCTL_QAIC_ATTACH_SLICE_BO ioctl. 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_ci bool sliced; 18562306a36Sopenharmony_ci /* Request ID of this BO if it is queued for execution */ 18662306a36Sopenharmony_ci u16 req_id; 18762306a36Sopenharmony_ci /* Handle assigned to this BO */ 18862306a36Sopenharmony_ci u32 handle; 18962306a36Sopenharmony_ci /* Wait on this for completion of DMA transfer of this BO */ 19062306a36Sopenharmony_ci struct completion xfer_done; 19162306a36Sopenharmony_ci /* 19262306a36Sopenharmony_ci * Node in linked list where head is dbc->xfer_list. 19362306a36Sopenharmony_ci * This link list contain BO's that are queued for DMA transfer. 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ci struct list_head xfer_list; 19662306a36Sopenharmony_ci /* 19762306a36Sopenharmony_ci * Node in linked list where head is dbc->bo_lists. 19862306a36Sopenharmony_ci * This link list contain BO's that are associated with the DBC it is 19962306a36Sopenharmony_ci * linked to. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci struct list_head bo_list; 20262306a36Sopenharmony_ci struct { 20362306a36Sopenharmony_ci /* 20462306a36Sopenharmony_ci * Latest timestamp(ns) at which kernel received a request to 20562306a36Sopenharmony_ci * execute this BO 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_ci u64 req_received_ts; 20862306a36Sopenharmony_ci /* 20962306a36Sopenharmony_ci * Latest timestamp(ns) at which kernel enqueued requests of 21062306a36Sopenharmony_ci * this BO for execution in DMA queue 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci u64 req_submit_ts; 21362306a36Sopenharmony_ci /* 21462306a36Sopenharmony_ci * Latest timestamp(ns) at which kernel received a completion 21562306a36Sopenharmony_ci * interrupt for requests of this BO 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ci u64 req_processed_ts; 21862306a36Sopenharmony_ci /* 21962306a36Sopenharmony_ci * Number of elements already enqueued in DMA queue before 22062306a36Sopenharmony_ci * enqueuing requests of this BO 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci u32 queue_level_before; 22362306a36Sopenharmony_ci } perf_stats; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci}; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistruct bo_slice { 22862306a36Sopenharmony_ci /* Mapped pages */ 22962306a36Sopenharmony_ci struct sg_table *sgt; 23062306a36Sopenharmony_ci /* Number of requests required to queue in DMA queue */ 23162306a36Sopenharmony_ci int nents; 23262306a36Sopenharmony_ci /* See enum dma_data_direction */ 23362306a36Sopenharmony_ci int dir; 23462306a36Sopenharmony_ci /* Actual requests that will be copied in DMA queue */ 23562306a36Sopenharmony_ci struct dbc_req *reqs; 23662306a36Sopenharmony_ci struct kref ref_count; 23762306a36Sopenharmony_ci /* true: No DMA transfer required */ 23862306a36Sopenharmony_ci bool no_xfer; 23962306a36Sopenharmony_ci /* Pointer to the parent BO handle */ 24062306a36Sopenharmony_ci struct qaic_bo *bo; 24162306a36Sopenharmony_ci /* Node in list of slices maintained by parent BO */ 24262306a36Sopenharmony_ci struct list_head slice; 24362306a36Sopenharmony_ci /* Size of this slice in bytes */ 24462306a36Sopenharmony_ci u64 size; 24562306a36Sopenharmony_ci /* Offset of this slice in buffer */ 24662306a36Sopenharmony_ci u64 offset; 24762306a36Sopenharmony_ci}; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ciint get_dbc_req_elem_size(void); 25062306a36Sopenharmony_ciint get_dbc_rsp_elem_size(void); 25162306a36Sopenharmony_ciint get_cntl_version(struct qaic_device *qdev, struct qaic_user *usr, u16 *major, u16 *minor); 25262306a36Sopenharmony_ciint qaic_manage_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); 25362306a36Sopenharmony_civoid qaic_mhi_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_civoid qaic_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ciint qaic_control_open(struct qaic_device *qdev); 25862306a36Sopenharmony_civoid qaic_control_close(struct qaic_device *qdev); 25962306a36Sopenharmony_civoid qaic_release_usr(struct qaic_device *qdev, struct qaic_user *usr); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ciirqreturn_t dbc_irq_threaded_fn(int irq, void *data); 26262306a36Sopenharmony_ciirqreturn_t dbc_irq_handler(int irq, void *data); 26362306a36Sopenharmony_ciint disable_dbc(struct qaic_device *qdev, u32 dbc_id, struct qaic_user *usr); 26462306a36Sopenharmony_civoid enable_dbc(struct qaic_device *qdev, u32 dbc_id, struct qaic_user *usr); 26562306a36Sopenharmony_civoid wakeup_dbc(struct qaic_device *qdev, u32 dbc_id); 26662306a36Sopenharmony_civoid release_dbc(struct qaic_device *qdev, u32 dbc_id); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_civoid wake_all_cntl(struct qaic_device *qdev); 26962306a36Sopenharmony_civoid qaic_dev_reset_clean_local_state(struct qaic_device *qdev, bool exit_reset); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistruct drm_gem_object *qaic_gem_prime_import(struct drm_device *dev, struct dma_buf *dma_buf); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ciint qaic_create_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); 27462306a36Sopenharmony_ciint qaic_mmap_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); 27562306a36Sopenharmony_ciint qaic_attach_slice_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); 27662306a36Sopenharmony_ciint qaic_execute_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); 27762306a36Sopenharmony_ciint qaic_partial_execute_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); 27862306a36Sopenharmony_ciint qaic_wait_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); 27962306a36Sopenharmony_ciint qaic_perf_stats_bo_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); 28062306a36Sopenharmony_civoid irq_polling_work(struct work_struct *work); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci#endif /* _QAIC_H_ */ 283