1d434743eSManivannan Sadhasivam /* SPDX-License-Identifier: GPL-2.0 */ 2d434743eSManivannan Sadhasivam /* 3d434743eSManivannan Sadhasivam * Copyright (c) 2022, Linaro Ltd. 4d434743eSManivannan Sadhasivam * 5d434743eSManivannan Sadhasivam */ 6d434743eSManivannan Sadhasivam #ifndef _MHI_EP_H_ 7d434743eSManivannan Sadhasivam #define _MHI_EP_H_ 8d434743eSManivannan Sadhasivam 9d434743eSManivannan Sadhasivam #include <linux/dma-direction.h> 10d434743eSManivannan Sadhasivam #include <linux/mhi.h> 11d434743eSManivannan Sadhasivam 12d434743eSManivannan Sadhasivam #define MHI_EP_DEFAULT_MTU 0x8000 13d434743eSManivannan Sadhasivam 14d434743eSManivannan Sadhasivam /** 15d434743eSManivannan Sadhasivam * struct mhi_ep_channel_config - Channel configuration structure for controller 16d434743eSManivannan Sadhasivam * @name: The name of this channel 17d434743eSManivannan Sadhasivam * @num: The number assigned to this channel 18d434743eSManivannan Sadhasivam * @num_elements: The number of elements that can be queued to this channel 19d434743eSManivannan Sadhasivam * @dir: Direction that data may flow on this channel 20d434743eSManivannan Sadhasivam */ 21d434743eSManivannan Sadhasivam struct mhi_ep_channel_config { 22d434743eSManivannan Sadhasivam char *name; 23d434743eSManivannan Sadhasivam u32 num; 24d434743eSManivannan Sadhasivam u32 num_elements; 25d434743eSManivannan Sadhasivam enum dma_data_direction dir; 26d434743eSManivannan Sadhasivam }; 27d434743eSManivannan Sadhasivam 28d434743eSManivannan Sadhasivam /** 29d434743eSManivannan Sadhasivam * struct mhi_ep_cntrl_config - MHI Endpoint controller configuration 30d434743eSManivannan Sadhasivam * @mhi_version: MHI spec version supported by the controller 31d434743eSManivannan Sadhasivam * @max_channels: Maximum number of channels supported 32d434743eSManivannan Sadhasivam * @num_channels: Number of channels defined in @ch_cfg 33d434743eSManivannan Sadhasivam * @ch_cfg: Array of defined channels 34d434743eSManivannan Sadhasivam */ 35d434743eSManivannan Sadhasivam struct mhi_ep_cntrl_config { 36d434743eSManivannan Sadhasivam u32 mhi_version; 37d434743eSManivannan Sadhasivam u32 max_channels; 38d434743eSManivannan Sadhasivam u32 num_channels; 39d434743eSManivannan Sadhasivam const struct mhi_ep_channel_config *ch_cfg; 40d434743eSManivannan Sadhasivam }; 41d434743eSManivannan Sadhasivam 42d434743eSManivannan Sadhasivam /** 43d434743eSManivannan Sadhasivam * struct mhi_ep_db_info - MHI Endpoint doorbell info 44d434743eSManivannan Sadhasivam * @mask: Mask of the doorbell interrupt 45d434743eSManivannan Sadhasivam * @status: Status of the doorbell interrupt 46d434743eSManivannan Sadhasivam */ 47d434743eSManivannan Sadhasivam struct mhi_ep_db_info { 48d434743eSManivannan Sadhasivam u32 mask; 49d434743eSManivannan Sadhasivam u32 status; 50d434743eSManivannan Sadhasivam }; 51d434743eSManivannan Sadhasivam 52d434743eSManivannan Sadhasivam /** 53*ad671dfcSManivannan Sadhasivam * struct mhi_ep_buf_info - MHI Endpoint transfer buffer info 54*ad671dfcSManivannan Sadhasivam * @dev_addr: Address of the buffer in endpoint 55*ad671dfcSManivannan Sadhasivam * @host_addr: Address of the bufffer in host 56*ad671dfcSManivannan Sadhasivam * @size: Size of the buffer 57*ad671dfcSManivannan Sadhasivam */ 58*ad671dfcSManivannan Sadhasivam struct mhi_ep_buf_info { 59*ad671dfcSManivannan Sadhasivam void *dev_addr; 60*ad671dfcSManivannan Sadhasivam u64 host_addr; 61*ad671dfcSManivannan Sadhasivam size_t size; 62*ad671dfcSManivannan Sadhasivam }; 63*ad671dfcSManivannan Sadhasivam 64*ad671dfcSManivannan Sadhasivam /** 65d434743eSManivannan Sadhasivam * struct mhi_ep_cntrl - MHI Endpoint controller structure 66d434743eSManivannan Sadhasivam * @cntrl_dev: Pointer to the struct device of physical bus acting as the MHI 67d434743eSManivannan Sadhasivam * Endpoint controller 68d434743eSManivannan Sadhasivam * @mhi_dev: MHI Endpoint device instance for the controller 69d434743eSManivannan Sadhasivam * @mmio: MMIO region containing the MHI registers 70d434743eSManivannan Sadhasivam * @mhi_chan: Points to the channel configuration table 71d434743eSManivannan Sadhasivam * @mhi_event: Points to the event ring configurations table 72d434743eSManivannan Sadhasivam * @mhi_cmd: Points to the command ring configurations table 73d434743eSManivannan Sadhasivam * @sm: MHI Endpoint state machine 74961aeb68SManivannan Sadhasivam * @ch_ctx_cache: Cache of host channel context data structure 75961aeb68SManivannan Sadhasivam * @ev_ctx_cache: Cache of host event context data structure 76961aeb68SManivannan Sadhasivam * @cmd_ctx_cache: Cache of host command context data structure 77e9e4da23SManivannan Sadhasivam * @ch_ctx_host_pa: Physical address of host channel context data structure 78e9e4da23SManivannan Sadhasivam * @ev_ctx_host_pa: Physical address of host event context data structure 79e9e4da23SManivannan Sadhasivam * @cmd_ctx_host_pa: Physical address of host command context data structure 80fb3a26b7SManivannan Sadhasivam * @ch_ctx_cache_phys: Physical address of the host channel context cache 81fb3a26b7SManivannan Sadhasivam * @ev_ctx_cache_phys: Physical address of the host event context cache 82fb3a26b7SManivannan Sadhasivam * @cmd_ctx_cache_phys: Physical address of the host command context cache 83e9e4da23SManivannan Sadhasivam * @chdb: Array of channel doorbell interrupt info 84961aeb68SManivannan Sadhasivam * @event_lock: Lock for protecting event rings 85f9baa4f7SManivannan Sadhasivam * @state_lock: Lock for protecting state transitions 861ddc7618SManivannan Sadhasivam * @list_lock: Lock for protecting state transition and channel doorbell lists 87f9baa4f7SManivannan Sadhasivam * @st_transition_list: List of state transitions 884799e71bSManivannan Sadhasivam * @ch_db_list: List of queued channel doorbells 89f9baa4f7SManivannan Sadhasivam * @wq: Dedicated workqueue for handling rings and state changes 90f9baa4f7SManivannan Sadhasivam * @state_work: State transition worker 917a97b6b4SManivannan Sadhasivam * @reset_work: Worker for MHI Endpoint reset 92e8275690SManivannan Sadhasivam * @cmd_ring_work: Worker for processing command rings 9303c0bb8eSManivannan Sadhasivam * @ch_ring_work: Worker for processing channel rings 94d434743eSManivannan Sadhasivam * @raise_irq: CB function for raising IRQ to the host 95d434743eSManivannan Sadhasivam * @alloc_map: CB function for allocating memory in endpoint for storing host context and mapping it 96d434743eSManivannan Sadhasivam * @unmap_free: CB function to unmap and free the allocated memory in endpoint for storing host context 97d434743eSManivannan Sadhasivam * @read_from_host: CB function for reading from host memory from endpoint 98d434743eSManivannan Sadhasivam * @write_to_host: CB function for writing to host memory from endpoint 99d434743eSManivannan Sadhasivam * @mhi_state: MHI Endpoint state 100d434743eSManivannan Sadhasivam * @max_chan: Maximum channels supported by the endpoint controller 101d434743eSManivannan Sadhasivam * @mru: MRU (Maximum Receive Unit) value of the endpoint controller 102e9e4da23SManivannan Sadhasivam * @event_rings: Number of event rings supported by the endpoint controller 103e9e4da23SManivannan Sadhasivam * @hw_event_rings: Number of hardware event rings supported by the endpoint controller 104e9e4da23SManivannan Sadhasivam * @chdb_offset: Channel doorbell offset set by the host 105e9e4da23SManivannan Sadhasivam * @erdb_offset: Event ring doorbell offset set by the host 106d434743eSManivannan Sadhasivam * @index: MHI Endpoint controller index 1074799e71bSManivannan Sadhasivam * @irq: IRQ used by the endpoint controller 108fb3a26b7SManivannan Sadhasivam * @enabled: Check if the endpoint controller is enabled or not 109d434743eSManivannan Sadhasivam */ 110d434743eSManivannan Sadhasivam struct mhi_ep_cntrl { 111d434743eSManivannan Sadhasivam struct device *cntrl_dev; 112d434743eSManivannan Sadhasivam struct mhi_ep_device *mhi_dev; 113d434743eSManivannan Sadhasivam void __iomem *mmio; 114d434743eSManivannan Sadhasivam 115d434743eSManivannan Sadhasivam struct mhi_ep_chan *mhi_chan; 116d434743eSManivannan Sadhasivam struct mhi_ep_event *mhi_event; 117d434743eSManivannan Sadhasivam struct mhi_ep_cmd *mhi_cmd; 118d434743eSManivannan Sadhasivam struct mhi_ep_sm *sm; 119d434743eSManivannan Sadhasivam 120961aeb68SManivannan Sadhasivam struct mhi_chan_ctxt *ch_ctx_cache; 121961aeb68SManivannan Sadhasivam struct mhi_event_ctxt *ev_ctx_cache; 122961aeb68SManivannan Sadhasivam struct mhi_cmd_ctxt *cmd_ctx_cache; 123e9e4da23SManivannan Sadhasivam u64 ch_ctx_host_pa; 124e9e4da23SManivannan Sadhasivam u64 ev_ctx_host_pa; 125e9e4da23SManivannan Sadhasivam u64 cmd_ctx_host_pa; 126fb3a26b7SManivannan Sadhasivam phys_addr_t ch_ctx_cache_phys; 127fb3a26b7SManivannan Sadhasivam phys_addr_t ev_ctx_cache_phys; 128fb3a26b7SManivannan Sadhasivam phys_addr_t cmd_ctx_cache_phys; 129e9e4da23SManivannan Sadhasivam 130e9e4da23SManivannan Sadhasivam struct mhi_ep_db_info chdb[4]; 131961aeb68SManivannan Sadhasivam struct mutex event_lock; 1321ddc7618SManivannan Sadhasivam struct mutex state_lock; 133f9baa4f7SManivannan Sadhasivam spinlock_t list_lock; 134f9baa4f7SManivannan Sadhasivam 135f9baa4f7SManivannan Sadhasivam struct list_head st_transition_list; 1364799e71bSManivannan Sadhasivam struct list_head ch_db_list; 137f9baa4f7SManivannan Sadhasivam 138f9baa4f7SManivannan Sadhasivam struct workqueue_struct *wq; 139f9baa4f7SManivannan Sadhasivam struct work_struct state_work; 1407a97b6b4SManivannan Sadhasivam struct work_struct reset_work; 141e8275690SManivannan Sadhasivam struct work_struct cmd_ring_work; 14203c0bb8eSManivannan Sadhasivam struct work_struct ch_ring_work; 143bd4f6f1fSManivannan Sadhasivam struct kmem_cache *ring_item_cache; 144bd4f6f1fSManivannan Sadhasivam struct kmem_cache *ev_ring_el_cache; 145bd4f6f1fSManivannan Sadhasivam struct kmem_cache *tre_buf_cache; 146e9e4da23SManivannan Sadhasivam 147d434743eSManivannan Sadhasivam void (*raise_irq)(struct mhi_ep_cntrl *mhi_cntrl, u32 vector); 148d434743eSManivannan Sadhasivam int (*alloc_map)(struct mhi_ep_cntrl *mhi_cntrl, u64 pci_addr, phys_addr_t *phys_ptr, 149d434743eSManivannan Sadhasivam void __iomem **virt, size_t size); 150d434743eSManivannan Sadhasivam void (*unmap_free)(struct mhi_ep_cntrl *mhi_cntrl, u64 pci_addr, phys_addr_t phys, 151d434743eSManivannan Sadhasivam void __iomem *virt, size_t size); 152*ad671dfcSManivannan Sadhasivam int (*read_from_host)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info); 153*ad671dfcSManivannan Sadhasivam int (*write_to_host)(struct mhi_ep_cntrl *mhi_cntrl, struct mhi_ep_buf_info *buf_info); 154d434743eSManivannan Sadhasivam 155d434743eSManivannan Sadhasivam enum mhi_state mhi_state; 156d434743eSManivannan Sadhasivam 157d434743eSManivannan Sadhasivam u32 max_chan; 158d434743eSManivannan Sadhasivam u32 mru; 159e9e4da23SManivannan Sadhasivam u32 event_rings; 160e9e4da23SManivannan Sadhasivam u32 hw_event_rings; 161e9e4da23SManivannan Sadhasivam u32 chdb_offset; 162e9e4da23SManivannan Sadhasivam u32 erdb_offset; 163d434743eSManivannan Sadhasivam u32 index; 1644799e71bSManivannan Sadhasivam int irq; 165fb3a26b7SManivannan Sadhasivam bool enabled; 166d434743eSManivannan Sadhasivam }; 167d434743eSManivannan Sadhasivam 168d434743eSManivannan Sadhasivam /** 169d434743eSManivannan Sadhasivam * struct mhi_ep_device - Structure representing an MHI Endpoint device that binds 170d434743eSManivannan Sadhasivam * to channels or is associated with controllers 171d434743eSManivannan Sadhasivam * @dev: Driver model device node for the MHI Endpoint device 172d434743eSManivannan Sadhasivam * @mhi_cntrl: Controller the device belongs to 173d434743eSManivannan Sadhasivam * @id: Pointer to MHI Endpoint device ID struct 174d434743eSManivannan Sadhasivam * @name: Name of the associated MHI Endpoint device 175ee0360b2SManivannan Sadhasivam * @ul_chan: UL (from host to endpoint) channel for the device 176ee0360b2SManivannan Sadhasivam * @dl_chan: DL (from endpoint to host) channel for the device 177d434743eSManivannan Sadhasivam * @dev_type: MHI device type 178d434743eSManivannan Sadhasivam */ 179d434743eSManivannan Sadhasivam struct mhi_ep_device { 180d434743eSManivannan Sadhasivam struct device dev; 181d434743eSManivannan Sadhasivam struct mhi_ep_cntrl *mhi_cntrl; 182d434743eSManivannan Sadhasivam const struct mhi_device_id *id; 183d434743eSManivannan Sadhasivam const char *name; 184d434743eSManivannan Sadhasivam struct mhi_ep_chan *ul_chan; 185d434743eSManivannan Sadhasivam struct mhi_ep_chan *dl_chan; 186d434743eSManivannan Sadhasivam enum mhi_device_type dev_type; 187d434743eSManivannan Sadhasivam }; 188d434743eSManivannan Sadhasivam 189ee0360b2SManivannan Sadhasivam /** 190ee0360b2SManivannan Sadhasivam * struct mhi_ep_driver - Structure representing a MHI Endpoint client driver 191ee0360b2SManivannan Sadhasivam * @id_table: Pointer to MHI Endpoint device ID table 192ee0360b2SManivannan Sadhasivam * @driver: Device driver model driver 193ee0360b2SManivannan Sadhasivam * @probe: CB function for client driver probe function 194ee0360b2SManivannan Sadhasivam * @remove: CB function for client driver remove function 195ee0360b2SManivannan Sadhasivam * @ul_xfer_cb: CB function for UL (from host to endpoint) data transfer 196ee0360b2SManivannan Sadhasivam * @dl_xfer_cb: CB function for DL (from endpoint to host) data transfer 197ee0360b2SManivannan Sadhasivam */ 198ee0360b2SManivannan Sadhasivam struct mhi_ep_driver { 199ee0360b2SManivannan Sadhasivam const struct mhi_device_id *id_table; 200ee0360b2SManivannan Sadhasivam struct device_driver driver; 201ee0360b2SManivannan Sadhasivam int (*probe)(struct mhi_ep_device *mhi_ep, 202ee0360b2SManivannan Sadhasivam const struct mhi_device_id *id); 203ee0360b2SManivannan Sadhasivam void (*remove)(struct mhi_ep_device *mhi_ep); 204ee0360b2SManivannan Sadhasivam void (*ul_xfer_cb)(struct mhi_ep_device *mhi_dev, 205ee0360b2SManivannan Sadhasivam struct mhi_result *result); 206ee0360b2SManivannan Sadhasivam void (*dl_xfer_cb)(struct mhi_ep_device *mhi_dev, 207ee0360b2SManivannan Sadhasivam struct mhi_result *result); 208ee0360b2SManivannan Sadhasivam }; 209ee0360b2SManivannan Sadhasivam 210d434743eSManivannan Sadhasivam #define to_mhi_ep_device(dev) container_of(dev, struct mhi_ep_device, dev) 211ee0360b2SManivannan Sadhasivam #define to_mhi_ep_driver(drv) container_of(drv, struct mhi_ep_driver, driver) 212ee0360b2SManivannan Sadhasivam 213ee0360b2SManivannan Sadhasivam /* 214ee0360b2SManivannan Sadhasivam * module_mhi_ep_driver() - Helper macro for drivers that don't do 215ee0360b2SManivannan Sadhasivam * anything special other than using default mhi_ep_driver_register() and 216ee0360b2SManivannan Sadhasivam * mhi_ep_driver_unregister(). This eliminates a lot of boilerplate. 217ee0360b2SManivannan Sadhasivam * Each module may only use this macro once. 218ee0360b2SManivannan Sadhasivam */ 219ee0360b2SManivannan Sadhasivam #define module_mhi_ep_driver(mhi_drv) \ 220ee0360b2SManivannan Sadhasivam module_driver(mhi_drv, mhi_ep_driver_register, \ 221ee0360b2SManivannan Sadhasivam mhi_ep_driver_unregister) 222ee0360b2SManivannan Sadhasivam 223ee0360b2SManivannan Sadhasivam /* 224ee0360b2SManivannan Sadhasivam * Macro to avoid include chaining to get THIS_MODULE 225ee0360b2SManivannan Sadhasivam */ 226ee0360b2SManivannan Sadhasivam #define mhi_ep_driver_register(mhi_drv) \ 227ee0360b2SManivannan Sadhasivam __mhi_ep_driver_register(mhi_drv, THIS_MODULE) 228ee0360b2SManivannan Sadhasivam 229ee0360b2SManivannan Sadhasivam /** 230ee0360b2SManivannan Sadhasivam * __mhi_ep_driver_register - Register a driver with MHI Endpoint bus 231ee0360b2SManivannan Sadhasivam * @mhi_drv: Driver to be associated with the device 232ee0360b2SManivannan Sadhasivam * @owner: The module owner 233ee0360b2SManivannan Sadhasivam * 234ee0360b2SManivannan Sadhasivam * Return: 0 if driver registrations succeeds, a negative error code otherwise. 235ee0360b2SManivannan Sadhasivam */ 236ee0360b2SManivannan Sadhasivam int __mhi_ep_driver_register(struct mhi_ep_driver *mhi_drv, struct module *owner); 237ee0360b2SManivannan Sadhasivam 238ee0360b2SManivannan Sadhasivam /** 239ee0360b2SManivannan Sadhasivam * mhi_ep_driver_unregister - Unregister a driver from MHI Endpoint bus 240ee0360b2SManivannan Sadhasivam * @mhi_drv: Driver associated with the device 241ee0360b2SManivannan Sadhasivam */ 242ee0360b2SManivannan Sadhasivam void mhi_ep_driver_unregister(struct mhi_ep_driver *mhi_drv); 243d434743eSManivannan Sadhasivam 244d434743eSManivannan Sadhasivam /** 245d434743eSManivannan Sadhasivam * mhi_ep_register_controller - Register MHI Endpoint controller 246d434743eSManivannan Sadhasivam * @mhi_cntrl: MHI Endpoint controller to register 247d434743eSManivannan Sadhasivam * @config: Configuration to use for the controller 248d434743eSManivannan Sadhasivam * 249d434743eSManivannan Sadhasivam * Return: 0 if controller registrations succeeds, a negative error code otherwise. 250d434743eSManivannan Sadhasivam */ 251d434743eSManivannan Sadhasivam int mhi_ep_register_controller(struct mhi_ep_cntrl *mhi_cntrl, 252d434743eSManivannan Sadhasivam const struct mhi_ep_cntrl_config *config); 253d434743eSManivannan Sadhasivam 254d434743eSManivannan Sadhasivam /** 255d434743eSManivannan Sadhasivam * mhi_ep_unregister_controller - Unregister MHI Endpoint controller 256d434743eSManivannan Sadhasivam * @mhi_cntrl: MHI Endpoint controller to unregister 257d434743eSManivannan Sadhasivam */ 258d434743eSManivannan Sadhasivam void mhi_ep_unregister_controller(struct mhi_ep_cntrl *mhi_cntrl); 259d434743eSManivannan Sadhasivam 260fb3a26b7SManivannan Sadhasivam /** 261fb3a26b7SManivannan Sadhasivam * mhi_ep_power_up - Power up the MHI endpoint stack 262fb3a26b7SManivannan Sadhasivam * @mhi_cntrl: MHI Endpoint controller 263fb3a26b7SManivannan Sadhasivam * 264fb3a26b7SManivannan Sadhasivam * Return: 0 if power up succeeds, a negative error code otherwise. 265fb3a26b7SManivannan Sadhasivam */ 266fb3a26b7SManivannan Sadhasivam int mhi_ep_power_up(struct mhi_ep_cntrl *mhi_cntrl); 267fb3a26b7SManivannan Sadhasivam 2685d507ee0SManivannan Sadhasivam /** 2695d507ee0SManivannan Sadhasivam * mhi_ep_power_down - Power down the MHI endpoint stack 2705d507ee0SManivannan Sadhasivam * @mhi_cntrl: MHI controller 2715d507ee0SManivannan Sadhasivam */ 2725d507ee0SManivannan Sadhasivam void mhi_ep_power_down(struct mhi_ep_cntrl *mhi_cntrl); 2735d507ee0SManivannan Sadhasivam 27453012588SManivannan Sadhasivam /** 27553012588SManivannan Sadhasivam * mhi_ep_queue_is_empty - Determine whether the transfer queue is empty 27653012588SManivannan Sadhasivam * @mhi_dev: Device associated with the channels 27753012588SManivannan Sadhasivam * @dir: DMA direction for the channel 27853012588SManivannan Sadhasivam * 27953012588SManivannan Sadhasivam * Return: true if the queue is empty, false otherwise. 28053012588SManivannan Sadhasivam */ 28153012588SManivannan Sadhasivam bool mhi_ep_queue_is_empty(struct mhi_ep_device *mhi_dev, enum dma_data_direction dir); 28253012588SManivannan Sadhasivam 2832d945a39SManivannan Sadhasivam /** 2842d945a39SManivannan Sadhasivam * mhi_ep_queue_skb - Send SKBs to host over MHI Endpoint 2852d945a39SManivannan Sadhasivam * @mhi_dev: Device associated with the DL channel 2862d945a39SManivannan Sadhasivam * @skb: SKBs to be queued 2872d945a39SManivannan Sadhasivam * 2882d945a39SManivannan Sadhasivam * Return: 0 if the SKBs has been sent successfully, a negative error code otherwise. 2892d945a39SManivannan Sadhasivam */ 2902d945a39SManivannan Sadhasivam int mhi_ep_queue_skb(struct mhi_ep_device *mhi_dev, struct sk_buff *skb); 2912d945a39SManivannan Sadhasivam 292d434743eSManivannan Sadhasivam #endif 293