diff options
author | Victor Hsu <hsuvictor@google.com> | 2021-11-10 14:01:16 +0800 |
---|---|---|
committer | Victor Hsu <hsuvictor@google.com> | 2021-12-13 13:34:17 +0800 |
commit | c972edc5cac0526943caaa390ddd0faf2ecb18db (patch) | |
tree | 653bbcbe5021b5cac251e2da2ac41583c6b0868d /inc | |
parent | 11b8045bbc3a20844fd6abeb460df31dcd70bbb4 (diff) | |
download | cnss2-c972edc5cac0526943caaa390ddd0faf2ecb18db.tar.gz |
wcn6740: Build mhi/qmi/qrtr out of kernel tree
Bug: 203725513
Signed-off-by: Victor Hsu <hsuvictor@google.com>
Change-Id: Ie484ffaf1bde124d141e8e87adf9e3beb5cf7174
Diffstat (limited to 'inc')
-rw-r--r-- | inc/ipc_logging.h | 287 | ||||
-rw-r--r-- | inc/mhi.h | 843 | ||||
-rw-r--r-- | inc/mhi_misc.h | 562 | ||||
-rw-r--r-- | inc/soc/qcom/qmi.h | 272 |
4 files changed, 1964 insertions, 0 deletions
diff --git a/inc/ipc_logging.h b/inc/ipc_logging.h new file mode 100644 index 0000000..e60492f --- /dev/null +++ b/inc/ipc_logging.h @@ -0,0 +1,287 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2012-2015,2017,2020 The Linux Foundation. All rights reserved. + */ + +#ifndef _IPC_LOGGING_H +#define _IPC_LOGGING_H + +#include <linux/errno.h> +#include <linux/types.h> + +#define MAX_MSG_SIZE 255 + +enum { + TSV_TYPE_MSG_START = 1, + TSV_TYPE_SKB = TSV_TYPE_MSG_START, + TSV_TYPE_STRING, + TSV_TYPE_MSG_END = TSV_TYPE_STRING, +}; + +struct tsv_header { + unsigned char type; + unsigned char size; /* size of data field */ +}; + +struct encode_context { + struct tsv_header hdr; + char buff[MAX_MSG_SIZE]; + int offset; +}; + +struct decode_context { + int output_format; /* 0 = debugfs */ + char *buff; /* output buffer */ + int size; /* size of output buffer */ +}; + +#if IS_ENABLED(CONFIG_IPC_LOGGING) +/* + * ipc_log_context_create: Create a debug log context + * Should not be called from atomic context + * + * @max_num_pages: Number of pages of logging space required (max. 10) + * @mod_name : Name of the directory entry under DEBUGFS + * @feature_version : First 16 bit for version number of user-defined message + * formats and next 16 bit for enabling minidump + * + * returns context id on success, NULL on failure + */ +void *ipc_log_context_create(int max_num_pages, const char *modname, + uint32_t feature_version); + +/* + * msg_encode_start: Start encoding a log message + * + * @ectxt: Temporary storage to hold the encoded message + * @type: Root event type defined by the module which is logging + */ +void msg_encode_start(struct encode_context *ectxt, uint32_t type); + +/* + * tsv_timestamp_write: Writes the current timestamp count + * + * @ectxt: Context initialized by calling msg_encode_start() + */ +int tsv_timestamp_write(struct encode_context *ectxt); + +/* + * tsv_qtimer_write: Writes the current QTimer timestamp count + * + * @ectxt: Context initialized by calling msg_encode_start() + */ +int tsv_qtimer_write(struct encode_context *ectxt); + +/* + * tsv_pointer_write: Writes a data pointer + * + * @ectxt: Context initialized by calling msg_encode_start() + * @pointer: Pointer value to write + */ +int tsv_pointer_write(struct encode_context *ectxt, void *pointer); + +/* + * tsv_int32_write: Writes a 32-bit integer value + * + * @ectxt: Context initialized by calling msg_encode_start() + * @n: Integer to write + */ +int tsv_int32_write(struct encode_context *ectxt, int32_t n); + +/* + * tsv_byte_array_write: Writes a byte array + * + * @ectxt: Context initialized by calling msg_encode_start() + * @data: Pointer to byte array + * @data_size: Size of byte array + */ +int tsv_byte_array_write(struct encode_context *ectxt, + void *data, int data_size); + +/* + * msg_encode_end: Complete the message encode process + * + * @ectxt: Temporary storage which holds the encoded message + */ +void msg_encode_end(struct encode_context *ectxt); + +/* + * ipc_log_write: Commits message to logging ring buffer + * + * @ctxt: Logging context + * @ectxt: Temporary storage which holds the encoded message + */ +void ipc_log_write(void *ctxt, struct encode_context *ectxt); + +/* + * ipc_log_string: Helper function to log a string + * + * @ilctxt: Debug Log Context created using ipc_log_context_create() + * @fmt: Data specified using format specifiers + */ +int ipc_log_string(void *ilctxt, const char *fmt, ...) __printf(2, 3); + +/** + * ipc_log_extract - Reads and deserializes log + * + * @ilctxt: logging context + * @buff: buffer to receive the data + * @size: size of the buffer + * @returns: 0 if no data read; >0 number of bytes read; < 0 error + * + * If no data is available to be read, then the ilctxt::read_avail + * completion is reinitialized. This allows clients to block + * until new log data is save. + */ +int ipc_log_extract(void *ilctxt, char *buff, int size); + +/* + * Print a string to decode context. + * @dctxt Decode context + * @args printf args + */ +#define IPC_SPRINTF_DECODE(dctxt, args...) \ +do { \ + int i; \ + i = scnprintf(dctxt->buff, dctxt->size, args); \ + dctxt->buff += i; \ + dctxt->size -= i; \ +} while (0) + +/* + * tsv_timestamp_read: Reads a timestamp + * + * @ectxt: Context retrieved by reading from log space + * @dctxt: Temporary storage to hold the decoded message + * @format: Output format while dumping through DEBUGFS + */ +void tsv_timestamp_read(struct encode_context *ectxt, + struct decode_context *dctxt, const char *format); + +/* + * tsv_qtimer_read: Reads a QTimer timestamp + * + * @ectxt: Context retrieved by reading from log space + * @dctxt: Temporary storage to hold the decoded message + * @format: Output format while dumping through DEBUGFS + */ +void tsv_qtimer_read(struct encode_context *ectxt, + struct decode_context *dctxt, const char *format); + +/* + * tsv_pointer_read: Reads a data pointer + * + * @ectxt: Context retrieved by reading from log space + * @dctxt: Temporary storage to hold the decoded message + * @format: Output format while dumping through DEBUGFS + */ +void tsv_pointer_read(struct encode_context *ectxt, + struct decode_context *dctxt, const char *format); + +/* + * tsv_int32_read: Reads a 32-bit integer value + * + * @ectxt: Context retrieved by reading from log space + * @dctxt: Temporary storage to hold the decoded message + * @format: Output format while dumping through DEBUGFS + */ +int32_t tsv_int32_read(struct encode_context *ectxt, + struct decode_context *dctxt, const char *format); + +/* + * tsv_byte_array_read: Reads a byte array + * + * @ectxt: Context retrieved by reading from log space + * @dctxt: Temporary storage to hold the decoded message + * @format: Output format while dumping through DEBUGFS + */ +void tsv_byte_array_read(struct encode_context *ectxt, + struct decode_context *dctxt, const char *format); + +/* + * add_deserialization_func: Register a deserialization function to + * to unpack the subevents of a main event + * + * @ctxt: Debug log context to which the deserialization function has + * to be registered + * @type: Main/Root event, defined by the module which is logging, to + * which this deserialization function has to be registered. + * @dfune: Deserialization function to be registered + * + * return 0 on success, -ve value on FAILURE + */ +int add_deserialization_func(void *ctxt, int type, + void (*dfunc)(struct encode_context *, + struct decode_context *)); + +/* + * ipc_log_context_destroy: Destroy debug log context + * + * @ctxt: debug log context created by calling ipc_log_context_create API. + */ +int ipc_log_context_destroy(void *ctxt); + +#else + +static inline void *ipc_log_context_create(int max_num_pages, + const char *modname, uint32_t feature_version) +{ return NULL; } + +static inline void msg_encode_start(struct encode_context *ectxt, + uint32_t type) { } + +static inline int tsv_timestamp_write(struct encode_context *ectxt) +{ return -EINVAL; } + +static inline int tsv_qtimer_write(struct encode_context *ectxt) +{ return -EINVAL; } + +static inline int tsv_pointer_write(struct encode_context *ectxt, void *pointer) +{ return -EINVAL; } + +static inline int tsv_int32_write(struct encode_context *ectxt, int32_t n) +{ return -EINVAL; } + +static inline int tsv_byte_array_write(struct encode_context *ectxt, + void *data, int data_size) +{ return -EINVAL; } + +static inline void msg_encode_end(struct encode_context *ectxt) { } + +static inline void ipc_log_write(void *ctxt, struct encode_context *ectxt) { } + +static inline int ipc_log_string(void *ilctxt, const char *fmt, ...) +{ return -EINVAL; } + +static inline int ipc_log_extract(void *ilctxt, char *buff, int size) +{ return -EINVAL; } + +#define IPC_SPRINTF_DECODE(dctxt, args...) do { } while (0) + +static inline void tsv_timestamp_read(struct encode_context *ectxt, + struct decode_context *dctxt, const char *format) { } + +static inline void tsv_qtimer_read(struct encode_context *ectxt, + struct decode_context *dctxt, const char *format) { } + +static inline void tsv_pointer_read(struct encode_context *ectxt, + struct decode_context *dctxt, const char *format) { } + +static inline int32_t tsv_int32_read(struct encode_context *ectxt, + struct decode_context *dctxt, const char *format) +{ return 0; } + +static inline void tsv_byte_array_read(struct encode_context *ectxt, + struct decode_context *dctxt, const char *format) { } + +static inline int add_deserialization_func(void *ctxt, int type, + void (*dfunc)(struct encode_context *, + struct decode_context *)) +{ return 0; } + +static inline int ipc_log_context_destroy(void *ctxt) +{ return 0; } + +#endif + +#endif diff --git a/inc/mhi.h b/inc/mhi.h new file mode 100644 index 0000000..50e4935 --- /dev/null +++ b/inc/mhi.h @@ -0,0 +1,843 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * + */ +#ifndef _MHI_H_ +#define _MHI_H_ + +#include <linux/device.h> +#include <linux/dma-direction.h> +#include <linux/mutex.h> +#include <linux/skbuff.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/wait.h> +#include <linux/workqueue.h> + +/* MHI client drivers to set this upper bound for tx buffer */ +#define MHI_MAX_MTU 0xffff + +#define MHI_MAX_OEM_PK_HASH_SEGMENTS 16 + +struct mhi_chan; +struct mhi_event; +struct mhi_ctxt; +struct mhi_cmd; +struct mhi_buf_info; + +/** + * enum mhi_callback - MHI callback + * @MHI_CB_IDLE: MHI entered idle state + * @MHI_CB_PENDING_DATA: New data available for client to process + * @MHI_CB_LPM_ENTER: MHI host entered low power mode + * @MHI_CB_LPM_EXIT: MHI host about to exit low power mode + * @MHI_CB_EE_RDDM: MHI device entered RDDM exec env + * @MHI_CB_EE_MISSION_MODE: MHI device entered Mission Mode exec env + * @MHI_CB_SYS_ERROR: MHI device entered error state (may recover) + * @MHI_CB_FATAL_ERROR: MHI device entered fatal error state + * @MHI_CB_BW_REQ: Received a bandwidth switch request from device + * @MHI_CB_FALLBACK_IMG: MHI device was loaded with the provided fallback image + * @MHI_CB_DTR_SIGNAL: DTR signaling update + */ +enum mhi_callback { + MHI_CB_IDLE, + MHI_CB_PENDING_DATA, + MHI_CB_LPM_ENTER, + MHI_CB_LPM_EXIT, + MHI_CB_EE_RDDM, + MHI_CB_EE_MISSION_MODE, + MHI_CB_SYS_ERROR, + MHI_CB_FATAL_ERROR, + MHI_CB_BW_REQ, + MHI_CB_FALLBACK_IMG, + MHI_CB_DTR_SIGNAL, +}; + +/** + * enum mhi_flags - Transfer flags + * @MHI_EOB: End of buffer for bulk transfer + * @MHI_EOT: End of transfer + * @MHI_CHAIN: Linked transfer + */ +enum mhi_flags { + MHI_EOB = BIT(0), + MHI_EOT = BIT(1), + MHI_CHAIN = BIT(2), +}; + +/** + * enum mhi_device_type - Device types + * @MHI_DEVICE_XFER: Handles data transfer + * @MHI_DEVICE_CONTROLLER: Control device + */ +enum mhi_device_type { + MHI_DEVICE_XFER, + MHI_DEVICE_CONTROLLER, +}; + +/** + * enum mhi_ch_type - Channel types + * @MHI_CH_TYPE_INVALID: Invalid channel type + * @MHI_CH_TYPE_OUTBOUND: Outbound channel to the device + * @MHI_CH_TYPE_INBOUND: Inbound channel from the device + * @MHI_CH_TYPE_INBOUND_COALESCED: Coalesced channel for the device to combine + * multiple packets and send them as a single + * large packet to reduce CPU consumption + */ +enum mhi_ch_type { + MHI_CH_TYPE_INVALID = 0, + MHI_CH_TYPE_OUTBOUND = DMA_TO_DEVICE, + MHI_CH_TYPE_INBOUND = DMA_FROM_DEVICE, + MHI_CH_TYPE_INBOUND_COALESCED = 3, +}; + +/** + * struct image_info - Firmware and RDDM table + * @mhi_buf: Buffer for firmware and RDDM table + * @entries: # of entries in table + */ +struct image_info { + struct mhi_buf *mhi_buf; + /* private: from internal.h */ + struct bhi_vec_entry *bhi_vec; + /* public: */ + u32 entries; +}; + +/** + * struct mhi_link_info - BW requirement + * target_link_speed - Link speed as defined by TLS bits in LinkControl reg + * target_link_width - Link width as defined by NLW bits in LinkStatus reg + * sequence_num - used by device to track bw requests sent to host + */ +struct mhi_link_info { + unsigned int target_link_speed; + unsigned int target_link_width; + int sequence_num; +}; + +/** + * enum mhi_ee_type - Execution environment types + * @MHI_EE_PBL: Primary Bootloader + * @MHI_EE_SBL: Secondary Bootloader + * @MHI_EE_AMSS: Modem, aka the primary runtime EE + * @MHI_EE_RDDM: Ram dump download mode + * @MHI_EE_WFW: WLAN firmware mode + * @MHI_EE_PTHRU: Passthrough + * @MHI_EE_EDL: Embedded downloader + */ +enum mhi_ee_type { + MHI_EE_PBL, + MHI_EE_SBL, + MHI_EE_AMSS, + MHI_EE_RDDM, + MHI_EE_WFW, + MHI_EE_PTHRU, + MHI_EE_EDL, + MHI_EE_MAX_SUPPORTED = MHI_EE_EDL, + MHI_EE_DISABLE_TRANSITION, /* local EE, not related to mhi spec */ + MHI_EE_NOT_SUPPORTED, + MHI_EE_MAX, +}; + +/** + * enum mhi_state - MHI states + * @MHI_STATE_RESET: Reset state + * @MHI_STATE_READY: Ready state + * @MHI_STATE_M0: M0 state + * @MHI_STATE_M1: M1 state + * @MHI_STATE_M2: M2 state + * @MHI_STATE_M3: M3 state + * @MHI_STATE_M3_FAST: M3 Fast state + * @MHI_STATE_BHI: BHI state + * @MHI_STATE_SYS_ERR: System Error state + */ +enum mhi_state { + MHI_STATE_RESET = 0x0, + MHI_STATE_READY = 0x1, + MHI_STATE_M0 = 0x2, + MHI_STATE_M1 = 0x3, + MHI_STATE_M2 = 0x4, + MHI_STATE_M3 = 0x5, + MHI_STATE_M3_FAST = 0x6, + MHI_STATE_BHI = 0x7, + MHI_STATE_SYS_ERR = 0xFF, + MHI_STATE_MAX, +}; + +/** + * enum mhi_ch_ee_mask - Execution environment mask for channel + * @MHI_CH_EE_PBL: Allow channel to be used in PBL EE + * @MHI_CH_EE_SBL: Allow channel to be used in SBL EE + * @MHI_CH_EE_AMSS: Allow channel to be used in AMSS EE + * @MHI_CH_EE_RDDM: Allow channel to be used in RDDM EE + * @MHI_CH_EE_PTHRU: Allow channel to be used in PTHRU EE + * @MHI_CH_EE_WFW: Allow channel to be used in WFW EE + * @MHI_CH_EE_EDL: Allow channel to be used in EDL EE + */ +enum mhi_ch_ee_mask { + MHI_CH_EE_PBL = BIT(MHI_EE_PBL), + MHI_CH_EE_SBL = BIT(MHI_EE_SBL), + MHI_CH_EE_AMSS = BIT(MHI_EE_AMSS), + MHI_CH_EE_RDDM = BIT(MHI_EE_RDDM), + MHI_CH_EE_PTHRU = BIT(MHI_EE_PTHRU), + MHI_CH_EE_WFW = BIT(MHI_EE_WFW), + MHI_CH_EE_EDL = BIT(MHI_EE_EDL), +}; + +/** + * enum mhi_er_data_type - Event ring data types + * @MHI_ER_DATA: Only client data over this ring + * @MHI_ER_CTRL: MHI control data and client data + * @MHI_ER_BW_SCALE: MHI controller bandwidth scale functionality + * @MHI_ER_TIMESYNC: MHI controller time synchronization DB mode functionality + */ +enum mhi_er_data_type { + MHI_ER_DATA, + MHI_ER_CTRL, + MHI_ER_BW_SCALE, + MHI_ER_TIMESYNC, +}; + +/** + * enum mhi_er_priority - Event ring processing priority + * @MHI_ER_PRIORITY_DEFAULT_NOSLEEP: processed by tasklet + * @MHI_ER_PRIORITY_HI_NOSLEEP: processed by hi-priority tasklet + * @MHI_ER_PRIORITY_HI_SLEEP: processed by hi-priority wq + */ +enum mhi_er_priority { + MHI_ER_PRIORITY_DEFAULT_NOSLEEP, + MHI_ER_PRIORITY_HI_NOSLEEP, + MHI_ER_PRIORITY_HI_SLEEP, +}; + +/** + * enum mhi_db_brst_mode - Doorbell mode + * @MHI_DB_BRST_DISABLE: Burst mode disable + * @MHI_DB_BRST_ENABLE: Burst mode enable + */ +enum mhi_db_brst_mode { + MHI_DB_BRST_DISABLE = 0x2, + MHI_DB_BRST_ENABLE = 0x3, +}; + +/** + * struct mhi_channel_config - Channel configuration structure for controller + * @name: The name of this channel + * @num: The number assigned to this channel + * @num_elements: The number of elements that can be queued to this channel + * @local_elements: The local ring length of the channel + * @event_ring: The event rung index that services this channel + * @dir: Direction that data may flow on this channel + * @type: Channel type + * @ee_mask: Execution Environment mask for this channel + * @pollcfg: Polling configuration for burst mode. 0 is default. milliseconds + for UL channels, multiple of 8 ring elements for DL channels + * @doorbell: Doorbell mode + * @lpm_notify: The channel master requires low power mode notifications + * @offload_channel: The client manages the channel completely + * @doorbell_mode_switch: Channel switches to doorbell mode on M0 transition + * @auto_queue: Framework will automatically queue buffers for DL traffic + * @wake-capable: Channel capable of waking up the system + */ +struct mhi_channel_config { + char *name; + u32 num; + u32 num_elements; + u32 local_elements; + u32 event_ring; + enum dma_data_direction dir; + enum mhi_ch_type type; + u32 ee_mask; + u32 pollcfg; + enum mhi_db_brst_mode doorbell; + bool lpm_notify; + bool offload_channel; + bool doorbell_mode_switch; + bool auto_queue; + bool wake_capable; +}; + +/** + * struct mhi_event_config - Event ring configuration structure for controller + * @num_elements: The number of elements that can be queued to this ring + * @irq_moderation_ms: Delay irq for additional events to be aggregated + * @irq: IRQ associated with this ring + * @channel: Dedicated channel number. U32_MAX indicates a non-dedicated ring + * @priority: Processing priority of this ring. + * @mode: Doorbell mode + * @data_type: Type of data this ring will process + * @hardware_event: This ring is associated with hardware channels + * @client_managed: This ring is client managed + * @offload_channel: This ring is associated with an offloaded channel + */ +struct mhi_event_config { + u32 num_elements; + u32 irq_moderation_ms; + u32 irq; + u32 channel; + u32 priority; + enum mhi_db_brst_mode mode; + enum mhi_er_data_type data_type; + bool hardware_event; + bool client_managed; + bool offload_channel; +}; + +/** + * struct mhi_controller_config - Root MHI controller configuration + * @max_channels: Maximum number of channels supported + * @timeout_ms: Timeout value for operations. 0 means use default + * @buf_len: Size of automatically allocated buffers. 0 means use default + * @num_channels: Number of channels defined in @ch_cfg + * @ch_cfg: Array of defined channels + * @num_events: Number of event rings defined in @event_cfg + * @event_cfg: Array of defined event rings + * @use_bounce_buf: Use a bounce buffer pool due to limited DDR access + * @m2_no_db: Host is not allowed to ring DB in M2 state + */ +struct mhi_controller_config { + u32 max_channels; + u32 timeout_ms; + u32 buf_len; + u32 num_channels; + const struct mhi_channel_config *ch_cfg; + u32 num_events; + const struct mhi_event_config *event_cfg; + bool use_bounce_buf; + bool m2_no_db; +}; + +/** + * struct mhi_controller - Master MHI controller structure + * @cntrl_dev: Pointer to the struct device of physical bus acting as the MHI + * controller (required) + * @mhi_dev: MHI device instance for the controller + * @debugfs_dentry: MHI controller debugfs directory + * @regs: Base address of MHI MMIO register space (required) + * @reg_len: Length of the MHI MMIO region (required) + * @bhi: Points to base of MHI BHI register space + * @bhie: Points to base of MHI BHIe register space + * @wake_db: MHI WAKE doorbell register address + * @iova_start: IOMMU starting address for data (required) + * @iova_stop: IOMMU stop address for data (required) + * @fw_image: Firmware image name for normal booting (required) + * @fallback_fw_image: Fallback firmware image name for backup boot (optional) + * @edl_image: Firmware image name for emergency download mode (optional) + * @rddm_size: RAM dump size that host should allocate for debugging purpose + * @sbl_size: SBL image size downloaded through BHIe (optional) + * @seg_len: BHIe vector size (optional) + * @fbc_image: Points to firmware image buffer + * @rddm_image: Points to RAM dump buffer + * @mhi_chan: Points to the channel configuration table + * @lpm_chans: List of channels that require LPM notifications + * @irq: base irq # to request (required) + * @max_chan: Maximum number of channels the controller supports + * @total_ev_rings: Total # of event rings allocated + * @hw_ev_rings: Number of hardware event rings + * @sw_ev_rings: Number of software event rings + * @nr_irqs: Number of IRQ allocated by bus master (required) + * @family_number: MHI controller family number + * @device_number: MHI controller device number + * @major_version: MHI controller major revision number + * @minor_version: MHI controller minor revision number + * @serial_number: MHI controller serial number obtained from BHI + * @oem_pk_hash: MHI controller OEM PK Hash obtained from BHI + * @mhi_event: MHI event ring configurations table + * @mhi_cmd: MHI command ring configurations table + * @mhi_ctxt: MHI device context, shared memory between host and device + * @pm_mutex: Mutex for suspend/resume operation + * @pm_lock: Lock for protecting MHI power management state + * @timeout_ms: Timeout in ms for state transitions + * @pm_state: MHI power management state + * @db_access: DB access states + * @ee: MHI device execution environment + * @dev_state: MHI device state + * @dev_wake: Device wakeup count + * @pending_pkts: Pending packets for the controller + * @M0, M2, M3, M3_fast: Counters to track number of device MHI state changes + * @transition_list: List of MHI state transitions + * @transition_lock: Lock for protecting MHI state transition list + * @wlock: Lock for protecting device wakeup + * @mhi_link_info: Device bandwidth info + * @st_worker: State transition worker + * @hiprio_wq: High priority workqueue for MHI work such as state transitions + * @state_event: State change event + * @status_cb: CB function to notify power states of the device (required) + * @wake_get: CB function to assert device wake (optional) + * @wake_put: CB function to de-assert device wake (optional) + * @wake_toggle: CB function to assert and de-assert device wake (optional) + * @runtime_get: CB function to controller runtime resume (required) + * @runtime_put: CB function to decrement pm usage (required) + * @map_single: CB function to create TRE buffer + * @unmap_single: CB function to destroy TRE buffer + * @read_reg: Read a MHI register via the physical link (required) + * @write_reg: Write a MHI register via the physical link (required) + * @reset: Controller specific reset function (optional) + * @buffer_len: Bounce buffer length + * @index: Index of the MHI controller instance + * @img_pre_alloc: allocate rddm and fbc image buffers one time + * @bounce_buf: Use of bounce buffer + * @fbc_download: MHI host needs to do complete image transfer (optional) + * @wake_set: Device wakeup set flag + * + * Fields marked as (required) need to be populated by the controller driver + * before calling mhi_register_controller(). For the fields marked as (optional) + * they can be populated depending on the usecase. + * + * The following fields are present for the purpose of implementing any device + * specific quirks or customizations for specific MHI revisions used in device + * by the controller drivers. The MHI stack will just populate these fields + * during mhi_register_controller(): + * family_number + * device_number + * major_version + * minor_version + */ +struct mhi_controller { + struct device *cntrl_dev; + struct mhi_device *mhi_dev; + struct dentry *debugfs_dentry; + void __iomem *regs; + size_t reg_len; + void __iomem *bhi; + void __iomem *bhie; + void __iomem *wake_db; + + dma_addr_t iova_start; + dma_addr_t iova_stop; + const char *fw_image; + const char *fallback_fw_image; + const char *edl_image; + size_t rddm_size; + size_t sbl_size; + size_t seg_len; + struct image_info *fbc_image; + struct image_info *rddm_image; + struct mhi_chan *mhi_chan; + struct list_head lpm_chans; + int *irq; + u32 max_chan; + u32 total_ev_rings; + u32 hw_ev_rings; + u32 sw_ev_rings; + u32 nr_irqs; + u32 family_number; + u32 device_number; + u32 major_version; + u32 minor_version; + u32 serial_number; + u32 oem_pk_hash[MHI_MAX_OEM_PK_HASH_SEGMENTS]; + u32 session_id; + + struct mhi_event *mhi_event; + struct mhi_cmd *mhi_cmd; + struct mhi_ctxt *mhi_ctxt; + + struct mutex pm_mutex; + rwlock_t pm_lock; + u32 timeout_ms; + u32 pm_state; + u32 db_access; + enum mhi_ee_type ee; + enum mhi_state dev_state; + atomic_t dev_wake; + atomic_t pending_pkts; + u32 M0, M2, M3, M3_fast; + struct list_head transition_list; + spinlock_t transition_lock; + spinlock_t wlock; + struct mhi_link_info mhi_link_info; + struct work_struct st_worker; + struct workqueue_struct *hiprio_wq; + wait_queue_head_t state_event; + + void (*status_cb)(struct mhi_controller *mhi_cntrl, + enum mhi_callback cb); + void (*wake_get)(struct mhi_controller *mhi_cntrl, bool override); + void (*wake_put)(struct mhi_controller *mhi_cntrl, bool override); + void (*wake_toggle)(struct mhi_controller *mhi_cntrl); + int (*runtime_get)(struct mhi_controller *mhi_cntrl); + void (*runtime_put)(struct mhi_controller *mhi_cntrl); + int (*map_single)(struct mhi_controller *mhi_cntrl, + struct mhi_buf_info *buf); + void (*unmap_single)(struct mhi_controller *mhi_cntrl, + struct mhi_buf_info *buf); + int (*read_reg)(struct mhi_controller *mhi_cntrl, void __iomem *addr, + u32 *out); + void (*write_reg)(struct mhi_controller *mhi_cntrl, void __iomem *addr, + u32 val); + void (*reset)(struct mhi_controller *mhi_cntrl); + + size_t buffer_len; + int index; + bool img_pre_alloc; + bool bounce_buf; + bool fbc_download; + bool wake_set; +}; + +/** + * struct mhi_device - Structure representing an MHI device which binds + * to channels or is associated with controllers + * @id: Pointer to MHI device ID struct + * @name: Name of the associated MHI device + * @mhi_cntrl: Controller the device belongs to + * @ul_chan: UL channel for the device + * @dl_chan: DL channel for the device + * @dev: Driver model device node for the MHI device + * @dev_type: MHI device type + * @ul_chan_id: MHI channel id for UL transfer + * @ul_event_id: MHI event ring id for UL transfer + * @dl_chan_id: MHI channel id for DL transfer + * @ul_event_id: MHI event ring id for DL transfer + * @dev_wake: Device wakeup counter + * @tiocm: Device current terminal settings + */ +struct mhi_device { + const struct mhi_device_id *id; + const char *name; + struct mhi_controller *mhi_cntrl; + struct mhi_chan *ul_chan; + struct mhi_chan *dl_chan; + struct device dev; + enum mhi_device_type dev_type; + int ul_chan_id; + int ul_event_id; + int dl_chan_id; + int dl_event_id; + u32 dev_wake; + u32 tiocm; +}; + +/** + * struct mhi_result - Completed buffer information + * @buf_addr: Address of data buffer + * @bytes_xferd: # of bytes transferred + * @dir: Channel direction + * @transaction_status: Status of last transaction + */ +struct mhi_result { + void *buf_addr; + size_t bytes_xferd; + enum dma_data_direction dir; + int transaction_status; +}; + +/** + * struct mhi_buf - MHI Buffer description + * @buf: Virtual address of the buffer + * @name: Buffer label. For offload channel, configurations name must be: + * ECA - Event context array data + * CCA - Channel context array data + * @dma_addr: IOMMU address of the buffer + * @len: # of bytes + */ +struct mhi_buf { + void *buf; + const char *name; + dma_addr_t dma_addr; + size_t len; +}; + +/** + * struct mhi_driver - Structure representing a MHI client driver + * @probe: CB function for client driver probe function + * @remove: CB function for client driver remove function + * @ul_xfer_cb: CB function for UL data transfer + * @dl_xfer_cb: CB function for DL data transfer + * @status_cb: CB functions for asynchronous status + * @driver: Device driver model driver + */ +struct mhi_driver { + const struct mhi_device_id *id_table; + int (*probe)(struct mhi_device *mhi_dev, + const struct mhi_device_id *id); + void (*remove)(struct mhi_device *mhi_dev); + void (*ul_xfer_cb)(struct mhi_device *mhi_dev, + struct mhi_result *result); + void (*dl_xfer_cb)(struct mhi_device *mhi_dev, + struct mhi_result *result); + void (*status_cb)(struct mhi_device *mhi_dev, enum mhi_callback mhi_cb); + struct device_driver driver; +}; + +#define to_mhi_driver(drv) container_of(drv, struct mhi_driver, driver) +#define to_mhi_device(dev) container_of(dev, struct mhi_device, dev) + +/** + * mhi_alloc_controller - Allocate the MHI Controller structure + * Allocate the mhi_controller structure using zero initialized memory + */ +struct mhi_controller *mhi_alloc_controller(void); + +/** + * mhi_free_controller - Free the MHI Controller structure + * Free the mhi_controller structure which was previously allocated + */ +void mhi_free_controller(struct mhi_controller *mhi_cntrl); + +/** + * mhi_register_controller - Register MHI controller + * @mhi_cntrl: MHI controller to register + * @config: Configuration to use for the controller + */ +int mhi_register_controller(struct mhi_controller *mhi_cntrl, + const struct mhi_controller_config *config); + +/** + * mhi_unregister_controller - Unregister MHI controller + * @mhi_cntrl: MHI controller to unregister + */ +void mhi_unregister_controller(struct mhi_controller *mhi_cntrl); + +/* + * module_mhi_driver() - Helper macro for drivers that don't do + * anything special other than using default mhi_driver_register() and + * mhi_driver_unregister(). This eliminates a lot of boilerplate. + * Each module may only use this macro once. + */ +#define module_mhi_driver(mhi_drv) \ + module_driver(mhi_drv, mhi_driver_register, \ + mhi_driver_unregister) + +/* + * Macro to avoid include chaining to get THIS_MODULE + */ +#define mhi_driver_register(mhi_drv) \ + __mhi_driver_register(mhi_drv, THIS_MODULE) + +/** + * __mhi_driver_register - Register driver with MHI framework + * @mhi_drv: Driver associated with the device + * @owner: The module owner + */ +int __mhi_driver_register(struct mhi_driver *mhi_drv, struct module *owner); + +/** + * mhi_driver_unregister - Unregister a driver for mhi_devices + * @mhi_drv: Driver associated with the device + */ +void mhi_driver_unregister(struct mhi_driver *mhi_drv); + +/** + * mhi_set_mhi_state - Set MHI device state + * @mhi_cntrl: MHI controller + * @state: State to set + */ +void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, + enum mhi_state state); + +/** + * mhi_notify - Notify the MHI client driver about client device status + * @mhi_dev: MHI device instance + * @cb_reason: MHI callback reason + */ +void mhi_notify(struct mhi_device *mhi_dev, enum mhi_callback cb_reason); + +/** + * mhi_get_free_desc_count - Get transfer ring length + * Get # of TD available to queue buffers + * @mhi_dev: Device associated with the channels + * @dir: Direction of the channel + */ +int mhi_get_free_desc_count(struct mhi_device *mhi_dev, + enum dma_data_direction dir); + +/** + * mhi_prepare_for_power_up - Do pre-initialization before power up. + * This is optional, call this before power up if + * the controller does not want bus framework to + * automatically free any allocated memory during + * shutdown process. + * @mhi_cntrl: MHI controller + */ +int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl); + +/** + * mhi_async_power_up - Start MHI power up sequence + * @mhi_cntrl: MHI controller + */ +int mhi_async_power_up(struct mhi_controller *mhi_cntrl); + +/** + * mhi_sync_power_up - Start MHI power up sequence and wait till the device + * enters valid EE state + * @mhi_cntrl: MHI controller + */ +int mhi_sync_power_up(struct mhi_controller *mhi_cntrl); + +/** + * mhi_power_down - Start MHI power down sequence + * @mhi_cntrl: MHI controller + * @graceful: Link is still accessible, so do a graceful shutdown process + */ +void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful); + +/** + * mhi_unprepare_after_power_down - Free any allocated memory after power down + * @mhi_cntrl: MHI controller + */ +void mhi_unprepare_after_power_down(struct mhi_controller *mhi_cntrl); + +/** + * mhi_pm_suspend - Move MHI into a suspended state + * @mhi_cntrl: MHI controller + */ +int mhi_pm_suspend(struct mhi_controller *mhi_cntrl); + +/** + * mhi_pm_resume - Resume MHI from suspended state + * @mhi_cntrl: MHI controller + */ +int mhi_pm_resume(struct mhi_controller *mhi_cntrl); + +/** + * mhi_download_rddm_image - Download ramdump image from device for + * debugging purpose. + * @mhi_cntrl: MHI controller + * @in_panic: Download rddm image during kernel panic + */ +int mhi_download_rddm_image(struct mhi_controller *mhi_cntrl, bool in_panic); + +/** + * mhi_force_rddm_mode - Force device into rddm mode + * @mhi_cntrl: MHI controller + */ +int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl); + +/** + * mhi_get_exec_env - Get BHI execution environment of the device + * @mhi_cntrl: MHI controller + */ +enum mhi_ee_type mhi_get_exec_env(struct mhi_controller *mhi_cntrl); + +/** + * mhi_get_mhi_state - Get MHI state of the device + * @mhi_cntrl: MHI controller + */ +enum mhi_state mhi_get_mhi_state(struct mhi_controller *mhi_cntrl); + +/** + * mhi_soc_reset - Trigger a device reset. This can be used as a last resort + * to reset and recover a device. + * @mhi_cntrl: MHI controller + */ +void mhi_soc_reset(struct mhi_controller *mhi_cntrl); + +/** + * mhi_device_get - Disable device low power mode + * @mhi_dev: Device associated with the channel + */ +void mhi_device_get(struct mhi_device *mhi_dev); + +/** + * mhi_device_get_sync - Disable device low power mode. Synchronously + * take the controller out of suspended state + * @mhi_dev: Device associated with the channel + */ +int mhi_device_get_sync(struct mhi_device *mhi_dev); + +/** + * mhi_device_put - Re-enable device low power mode + * @mhi_dev: Device associated with the channel + */ +void mhi_device_put(struct mhi_device *mhi_dev); + +/** + * mhi_prepare_for_transfer - Setup UL and DL channels for data transfer. + * Allocate and initialize the channel context and + * also issue the START channel command to both + * channels. Channels can be started only if both + * host and device execution environments match and + * channels are in a DISABLED state. Calling the + * mhi_start_transfer() function is not required + * afterwards as channels are already started. This + * function also initializes the channel context + * whereas mhi_start_transfer() can only be used to + * issue the start channel command once the context + * is setup. + * @mhi_dev: Device associated with the channels + */ +int mhi_prepare_for_transfer(struct mhi_device *mhi_dev); + +/** + * mhi_unprepare_from_transfer - Reset UL and DL channels for data transfer. + * Issue the RESET channel command and let the + * device clean-up the context so no incoming + * transfers are seen on the host. Free memory + * associated with the context on host. If device + * is unresponsive, only perform a host side + * clean-up. Channels can be reset only if both + * host and device execution environments match + * and channels are in an ENABLED, STOPPED or + * SUSPENDED state. Calling mhi_stop_transfer() is + * not required before calling this function as it + * will only stop transfers, not reset channels. + * @mhi_dev: Device associated with the channels + */ +void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev); + +/** + * mhi_stop_transfer - Pauses ongoing channel activity by issuing the STOP + * channel command to both UL and DL channels. This command + * does not reset the channel context and the client drivers + * can issue mhi_start_transfer to resume activity. + * @mhi_dev: Device associated with the channels + */ +int mhi_stop_transfer(struct mhi_device *mhi_dev); + +/** + * mhi_start_transfer - Resumes channel activity by issuing the START channel + * command to both UL and DL channels. This command assumes + * the channel context is already setup and the client + * drivers can issue mhi_stop_transfer to pause activity if + * required. + * @mhi_dev: Device associated with the channels + */ +int mhi_start_transfer(struct mhi_device *mhi_dev); + +/** + * mhi_poll - Poll for any available data in DL direction + * @mhi_dev: Device associated with the channels + * @budget: # of events to process + */ +int mhi_poll(struct mhi_device *mhi_dev, u32 budget); + +/** + * mhi_queue_dma - Send or receive DMA mapped buffers from client device + * over MHI channel + * @mhi_dev: Device associated with the channels + * @dir: DMA direction for the channel + * @mhi_buf: Buffer for holding the DMA mapped data + * @len: Buffer length + * @mflags: MHI transfer flags used for the transfer + */ +int mhi_queue_dma(struct mhi_device *mhi_dev, enum dma_data_direction dir, + struct mhi_buf *mhi_buf, size_t len, enum mhi_flags mflags); + +/** + * mhi_queue_buf - Send or receive raw buffers from client device over MHI + * channel + * @mhi_dev: Device associated with the channels + * @dir: DMA direction for the channel + * @buf: Buffer for holding the data + * @len: Buffer length + * @mflags: MHI transfer flags used for the transfer + */ +int mhi_queue_buf(struct mhi_device *mhi_dev, enum dma_data_direction dir, + void *buf, size_t len, enum mhi_flags mflags); + +/** + * mhi_queue_skb - Send or receive SKBs from client device over MHI channel + * @mhi_dev: Device associated with the channels + * @dir: DMA direction for the channel + * @skb: Buffer for holding SKBs + * @len: Buffer length + * @mflags: MHI transfer flags used for the transfer + */ +int mhi_queue_skb(struct mhi_device *mhi_dev, enum dma_data_direction dir, + struct sk_buff *skb, size_t len, enum mhi_flags mflags); + +#endif /* _MHI_H_ */ diff --git a/inc/mhi_misc.h b/inc/mhi_misc.h new file mode 100644 index 0000000..b8ff0ff --- /dev/null +++ b/inc/mhi_misc.h @@ -0,0 +1,562 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. + * + */ + +#ifndef _MHI_MISC_H_ +#define _MHI_MISC_H_ + +#include <linux/mhi.h> +#include <linux/ipc_logging.h> + +/** + * enum MHI_DEBUG_LEVEL - various debugging levels + */ +enum MHI_DEBUG_LEVEL { + MHI_MSG_LVL_VERBOSE, + MHI_MSG_LVL_INFO, + MHI_MSG_LVL_ERROR, + MHI_MSG_LVL_CRITICAL, + MHI_MSG_LVL_MASK_ALL, + MHI_MSG_LVL_MAX, +}; + +#ifdef CONFIG_MHI_BUS_MISC + +/** + * mhi_report_error - Can be used by controller to signal error condition to the + * MHI core driver in case of any need to halt processing or incoming sideband + * signal detects an error on endpoint + * @mhi_cntrl: MHI controller + * + * Returns: + * 0 if success in reporting the error condition to MHI core + * error code on failure + */ +int mhi_report_error(struct mhi_controller *mhi_cntrl); + +/** + * mhi_controller_set_privdata - Set private data for MHI controller + * @mhi_cntrl: MHI controller + * @priv: pointer to data + */ +void mhi_controller_set_privdata(struct mhi_controller *mhi_cntrl, void *priv); + +/** + * mhi_controller_get_privdata - Get private data from MHI controller + * @mhi_cntrl: MHI controller + */ +void *mhi_controller_get_privdata(struct mhi_controller *mhi_cntrl); + +/** + * mhi_bdf_to_controller - Get controller associated with given BDF values + * @domain: Domain or root complex of PCIe port + * @bus: Bus number + * @slot: PCI slot or function number + * @dev_id: Device ID of the endpoint + * + * Returns: + * MHI controller structure pointer if BDF match is found + * NULL if cookie is not found + */ +struct mhi_controller *mhi_bdf_to_controller(u32 domain, u32 bus, u32 slot, u32 dev_id); + +/** + * mhi_set_m2_timeout_ms - Set M2 timeout in milliseconds to wait before a + * fast/silent suspend + * @mhi_cntrl: MHI controller + * @timeout: timeout in ms + */ +void mhi_set_m2_timeout_ms(struct mhi_controller *mhi_cntrl, u32 timeout); + +/** + * mhi_pm_fast_resume - Resume MHI from a fast/silent suspended state + * @mhi_cntrl: MHI controller + * @notify_clients: if true, clients will be notified of the resume transition + */ +int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_clients); + +/** + * mhi_pm_fast_suspend - Move MHI into a fast/silent suspended state + * @mhi_cntrl: MHI controller + * @notify_clients: if true, clients will be notified of the suspend transition + */ +int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_clients); + +/** + * mhi_debug_reg_dump - dump MHI registers for debug purpose + * @mhi_cntrl: MHI controller + */ +void mhi_debug_reg_dump(struct mhi_controller *mhi_cntrl); + +/** + * mhi_dump_sfr - Print SFR string from RDDM table. + * @mhi_cntrl: MHI controller + */ +void mhi_dump_sfr(struct mhi_controller *mhi_cntrl); + +/** + * mhi_device_configure - Allow devices with offload channels to setup their own + * channel and event ring context. + * @mhi_dev: MHI device + * @dir: direction associated with the channel needed to configure + * @cfg_tbl: Buffer with ECA/CCA information and data needed to setup context + * @elements: Number of items to iterate over from the configuration table + */ +int mhi_device_configure(struct mhi_device *mhi_dev, + enum dma_data_direction dir, + struct mhi_buf *cfg_tbl, + int elements); + +/** + * mhi_scan_rddm_cookie - Look for supplied cookie value in the BHI debug + * registers set by device to indicate rddm readiness for debugging purposes. + * @mhi_cntrl: MHI controller + * @cookie: cookie/pattern value to match + * + * Returns: + * true if cookie is found + * false if cookie is not found + */ +bool mhi_scan_rddm_cookie(struct mhi_controller *mhi_cntrl, u32 cookie); + +/** + * mhi_device_get_sync_atomic - Asserts device_wait and moves device to M0 + * @mhi_dev: Device associated with the channels + * @timeout_us: timeout, in micro-seconds + * @in_panic: If requested while kernel is in panic state and no ISRs expected + * + * The device_wake is asserted to keep device in M0 or bring it to M0. + * If device is not in M0 state, then this function will wait for device to + * move to M0, until @timeout_us elapses. + * However, if device's M1 state-change event races with this function + * then there is a possiblity of device moving from M0 to M2 and back + * to M0. That can't be avoided as host must transition device from M1 to M2 + * as per the spec. + * Clients can ignore that transition after this function returns as the device + * is expected to immediately move from M2 to M0 as wake is asserted and + * wouldn't enter low power state. + * If in_panic boolean is set, no ISRs are expected, hence this API will have to + * resort to reading the MHI status register and poll on M0 state change. + * + * Returns: + * 0 if operation was successful (however, M0 -> M2 -> M0 is possible later) as + * mentioned above. + * -ETIMEDOUT is device faled to move to M0 before @timeout_us elapsed + * -EIO if the MHI state is one of the ERROR states. + */ +int mhi_device_get_sync_atomic(struct mhi_device *mhi_dev, int timeout_us, + bool in_panic); + +/** + * mhi_controller_set_bw_scale_cb - Set the BW scale callback for MHI controller + * @mhi_cntrl: MHI controller + * @cb_func: Callback to set for the MHI controller to receive BW scale requests + */ +void mhi_controller_set_bw_scale_cb(struct mhi_controller *mhi_cntrl, + int (*cb_func)(struct mhi_controller *mhi_cntrl, + struct mhi_link_info *link_info)); +/** + * mhi_controller_set_base - Set the controller base / resource start address + * @mhi_cntrl: MHI controller + * @base: Physical address to be set for future reference + */ +void mhi_controller_set_base(struct mhi_controller *mhi_cntrl, + phys_addr_t base); + +/** + * mhi_get_channel_db_base - retrieve the channel doorbell base address + * @mhi_dev: Device associated with the channels + * @value: Pointer to an address value which will be populated + */ +int mhi_get_channel_db_base(struct mhi_device *mhi_dev, phys_addr_t *value); + +/** + * mhi_get_event_ring_db_base - retrieve the event ring doorbell base address + * @mhi_dev: Device associated with the channels + * @value: Pointer to an address value which will be populated + */ +int mhi_get_event_ring_db_base(struct mhi_device *mhi_dev, phys_addr_t *value); + +/** + * mhi_get_device_for_channel - get the MHI device for a specific channel number + * @mhi_cntrl: MHI controller + * @channel - channel number + * + * Returns: + * Pointer to the MHI device associated with the channel + */ +struct mhi_device *mhi_get_device_for_channel(struct mhi_controller *mhi_cntrl, + u32 channel); + +/** + * mhi_device_ioctl - user space IOCTL support for MHI channels + * Native support for setting TIOCM + * @mhi_dev: Device associated with the channels + * @cmd: IOCTL cmd + * @arg: Optional parameter, iotcl cmd specific + */ +long mhi_device_ioctl(struct mhi_device *mhi_dev, unsigned int cmd, + unsigned long arg); + +/** + * mhi_controller_set_sfr_support - Set support for subsystem failure reason + * @mhi_cntrl: MHI controller + * + * Returns: + * 0 for success, error code for failure + */ +int mhi_controller_set_sfr_support(struct mhi_controller *mhi_cntrl, + size_t len); + +/** + * mhi_controller_setup_timesync - Set support for time synchronization feature + * @mhi_cntrl: MHI controller + * @time_get: Callback to set for the MHI controller to receive host time + * @lpm_disable: Callback to set for the MHI controller to disable link LPM + * @lpm_enable: Callback to set for the MHI controller to enable link LPM + * + * Returns: + * 0 for success, error code for failure + */ +int mhi_controller_setup_timesync(struct mhi_controller *mhi_cntrl, + u64 (*time_get)(struct mhi_controller *c), + int (*lpm_disable)(struct mhi_controller *c), + int (*lpm_enable)(struct mhi_controller *c)); + +/** + * mhi_get_remote_time_sync - Get external soc time relative to local soc time + * using MMIO method. + * @mhi_dev: Device associated with the channels + * @t_host: Pointer to output local soc time + * @t_dev: Pointer to output remote soc time + * + * Returns: + * 0 for success, error code for failure + */ +int mhi_get_remote_time_sync(struct mhi_device *mhi_dev, + u64 *t_host, + u64 *t_dev); + +/** + * mhi_get_remote_time - Get external modem time relative to host time + * Trigger event to capture modem time, also capture host time so client + * can do a relative drift comparision. + * Recommended only tsync device calls this method and do not call this + * from atomic context + * @mhi_dev: Device associated with the channels + * @sequence:unique sequence id track event + * @cb_func: callback function to call back + * + * Returns: + * 0 for success, error code for failure + */ +int mhi_get_remote_time(struct mhi_device *mhi_dev, + u32 sequence, + void (*cb_func)(struct mhi_device *mhi_dev, + u32 sequence, + u64 local_time, + u64 remote_time)); + +#else + +/** + * mhi_report_error - Can be used by controller to signal error condition to the + * MHI core driver in case of any need to halt processing or incoming sideband + * signal detects an error on endpoint + * @mhi_cntrl: MHI controller + * + * Returns: + * 0 if success in reporting the error condition to MHI core + * error code on failure + */ +static inline int mhi_report_error(struct mhi_controller *mhi_cntrl) +{ + return -EPERM; +} + +/** + * mhi_controller_set_privdata - Set private data for MHI controller + * @mhi_cntrl: MHI controller + * @priv: pointer to data + */ +void mhi_controller_set_privdata(struct mhi_controller *mhi_cntrl, void *priv) +{ +} + +/** + * mhi_controller_get_privdata - Get private data from MHI controller + * @mhi_cntrl: MHI controller + */ +void *mhi_controller_get_privdata(struct mhi_controller *mhi_cntrl) +{ + return ERR_PTR(-EINVAL); +} + +/** + * mhi_bdf_to_controller - Get controller associated with given BDF values + * @domain: Domain or root complex of PCIe port + * @bus: Bus number + * @slot: PCI slot or function number + * @dev_id: Device ID of the endpoint + * + * Returns: + * MHI controller structure pointer if BDF match is found + * NULL if cookie is not found + */ +struct mhi_controller *mhi_bdf_to_controller(u32 domain, u32 bus, u32 slot, u32 dev_id) +{ + return ERR_PTR(-EINVAL); +} + +/** + * mhi_set_m2_timeout_ms - Set M2 timeout in milliseconds to wait before a + * fast/silent suspend + * @mhi_cntrl: MHI controller + * @timeout: timeout in ms + */ +void mhi_set_m2_timeout_ms(struct mhi_controller *mhi_cntrl, u32 timeout) +{ +} + +/** + * mhi_pm_fast_resume - Resume MHI from a fast/silent suspended state + * @mhi_cntrl: MHI controller + * @notify_clients: if true, clients will be notified of the resume transition + */ +int mhi_pm_fast_resume(struct mhi_controller *mhi_cntrl, bool notify_clients) +{ + return -EPERM; +} + +/** + * mhi_pm_fast_suspend - Move MHI into a fast/silent suspended state + * @mhi_cntrl: MHI controller + * @notify_clients: if true, clients will be notified of the suspend transition + */ +int mhi_pm_fast_suspend(struct mhi_controller *mhi_cntrl, bool notify_clients) +{ + return -EPERM; +} + +/** + * mhi_debug_reg_dump - dump MHI registers for debug purpose + * @mhi_cntrl: MHI controller + */ +void mhi_debug_reg_dump(struct mhi_controller *mhi_cntrl) +{ +} + +/** + * mhi_dump_sfr - Print SFR string from RDDM table. + * @mhi_cntrl: MHI controller + */ +void mhi_dump_sfr(struct mhi_controller *mhi_cntrl) +{ +} + +/** + * mhi_device_configure - Allow devices with offload channels to setup their own + * channel and event ring context. + * @mhi_dev: MHI device + * @dir: direction associated with the channel needed to configure + * @cfg_tbl: Buffer with ECA/CCA information and data needed to setup context + * @elements: Number of items to iterate over from the configuration table + */ +int mhi_device_configure(struct mhi_device *mhi_dev, + enum dma_data_direction dir, + struct mhi_buf *cfg_tbl, + int elements) +{ + return -EPERM; +} + +/** + * mhi_scan_rddm_cookie - Look for supplied cookie value in the BHI debug + * registers set by device to indicate rddm readiness for debugging purposes. + * @mhi_cntrl: MHI controller + * @cookie: cookie/pattern value to match + * + * Returns: + * true if cookie is found + * false if cookie is not found + */ +bool mhi_scan_rddm_cookie(struct mhi_controller *mhi_cntrl, u32 cookie) +{ + return false; +} + +/** + * mhi_device_get_sync_atomic - Asserts device_wait and moves device to M0 + * @mhi_dev: Device associated with the channels + * @timeout_us: timeout, in micro-seconds + * @in_panic: If requested while kernel is in panic state and no ISRs expected + * + * The device_wake is asserted to keep device in M0 or bring it to M0. + * If device is not in M0 state, then this function will wait for device to + * move to M0, until @timeout_us elapses. + * However, if device's M1 state-change event races with this function + * then there is a possiblity of device moving from M0 to M2 and back + * to M0. That can't be avoided as host must transition device from M1 to M2 + * as per the spec. + * Clients can ignore that transition after this function returns as the device + * is expected to immediately move from M2 to M0 as wake is asserted and + * wouldn't enter low power state. + * If in_panic boolean is set, no ISRs are expected, hence this API will have to + * resort to reading the MHI status register and poll on M0 state change. + * + * Returns: + * 0 if operation was successful (however, M0 -> M2 -> M0 is possible later) as + * mentioned above. + * -ETIMEDOUT is device faled to move to M0 before @timeout_us elapsed + * -EIO if the MHI state is one of the ERROR states. + */ +int mhi_device_get_sync_atomic(struct mhi_device *mhi_dev, int timeout_us, + bool in_panic) +{ + return -EPERM; +} + +/** + * mhi_controller_set_bw_scale_cb - Set the BW scale callback for MHI controller + * @mhi_cntrl: MHI controller + * @cb_func: Callback to set for the MHI controller to receive BW scale requests + */ +void mhi_controller_set_bw_scale_cb(struct mhi_controller *mhi_cntrl, + int (*cb_func)(struct mhi_controller *mhi_cntrl, + struct mhi_link_info *link_info)) +{ +} + +/** + * mhi_controller_set_base - Set the controller base / resource start address + * @mhi_cntrl: MHI controller + * @base: Physical address to be set for future reference + */ +void mhi_controller_set_base(struct mhi_controller *mhi_cntrl, + phys_addr_t base) +{ +} + +/** + * mhi_get_channel_db_base - retrieve the channel doorbell base address + * @mhi_dev: Device associated with the channels + * @value: Pointer to an address value which will be populated + */ +int mhi_get_channel_db_base(struct mhi_device *mhi_dev, phys_addr_t *value) +{ + return -EPERM; +} + +/** + * mhi_get_event_ring_db_base - retrieve the event ring doorbell base address + * @mhi_dev: Device associated with the channels + * @value: Pointer to an address value which will be populated + */ +int mhi_get_event_ring_db_base(struct mhi_device *mhi_dev, phys_addr_t *value) +{ + return -EPERM; +} + +/** + * mhi_get_device_for_channel - get the MHI device for a specific channel number + * @mhi_cntrl: MHI controller + * @channel - channel number + * + * Returns: + * Pointer to the MHI device associated with the channel + */ +struct mhi_device *mhi_get_device_for_channel(struct mhi_controller *mhi_cntrl, + u32 channel) +{ + return ERR_PTR(-EINVAL); +} + +/** + * mhi_device_ioctl - user space IOCTL support for MHI channels + * Native support for setting TIOCM + * @mhi_dev: Device associated with the channels + * @cmd: IOCTL cmd + * @arg: Optional parameter, iotcl cmd specific + */ +long mhi_device_ioctl(struct mhi_device *mhi_dev, unsigned int cmd, + unsigned long arg) +{ + return -EPERM; +} + +/** + * mhi_controller_set_sfr_support - Set support for subsystem failure reason + * @mhi_cntrl: MHI controller + * + * Returns: + * 0 for success, error code for failure + */ +int mhi_controller_set_sfr_support(struct mhi_controller *mhi_cntrl, + size_t len) +{ + return -EPERM; +} + +/** + * mhi_controller_setup_timesync - Set support for time synchronization feature + * @mhi_cntrl: MHI controller + * @time_get: Callback to set for the MHI controller to receive host time + * @lpm_disable: Callback to set for the MHI controller to disable link LPM + * @lpm_enable: Callback to set for the MHI controller to enable link LPM + * + * Returns: + * 0 for success, error code for failure + */ +int mhi_controller_setup_timesync(struct mhi_controller *mhi_cntrl, + u64 (*time_get)(struct mhi_controller *c), + int (*lpm_disable)(struct mhi_controller *c), + int (*lpm_enable)(struct mhi_controller *c)) +{ + return -EPERM; +} + +/** + * mhi_get_remote_time_sync - Get external soc time relative to local soc time + * using MMIO method. + * @mhi_dev: Device associated with the channels + * @t_host: Pointer to output local soc time + * @t_dev: Pointer to output remote soc time + * + * Returns: + * 0 for success, error code for failure + */ +int mhi_get_remote_time_sync(struct mhi_device *mhi_dev, + u64 *t_host, + u64 *t_dev) +{ + return -EPERM; +} + +/** + * mhi_get_remote_time - Get external modem time relative to host time + * Trigger event to capture modem time, also capture host time so client + * can do a relative drift comparision. + * Recommended only tsync device calls this method and do not call this + * from atomic context + * @mhi_dev: Device associated with the channels + * @sequence:unique sequence id track event + * @cb_func: callback function to call back + * + * Returns: + * 0 for success, error code for failure + */ +int mhi_get_remote_time(struct mhi_device *mhi_dev, + u32 sequence, + void (*cb_func)(struct mhi_device *mhi_dev, + u32 sequence, + u64 local_time, + u64 remote_time)) +{ + return -EPERM; +} + +#endif /* CONFIG_MHI_BUS_MISC */ + +#endif /* _MHI_MISC_H_ */ diff --git a/inc/soc/qcom/qmi.h b/inc/soc/qcom/qmi.h new file mode 100644 index 0000000..e712f94 --- /dev/null +++ b/inc/soc/qcom/qmi.h @@ -0,0 +1,272 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. + * Copyright (c) 2017, Linaro Ltd. + */ +#ifndef __QMI_HELPERS_H__ +#define __QMI_HELPERS_H__ + +#include <linux/completion.h> +#include <linux/idr.h> +#include <linux/list.h> +#include <linux/qrtr.h> +#include <linux/types.h> +#include <linux/workqueue.h> + +struct socket; + +/** + * qmi_header - wireformat header of QMI messages + * @type: type of message + * @txn_id: transaction id + * @msg_id: message id + * @msg_len: length of message payload following header + */ +struct qmi_header { + u8 type; + u16 txn_id; + u16 msg_id; + u16 msg_len; +} __packed; + +#define QMI_REQUEST 0 +#define QMI_RESPONSE 2 +#define QMI_INDICATION 4 + +#define QMI_COMMON_TLV_TYPE 0 + +enum qmi_elem_type { + QMI_EOTI, + QMI_OPT_FLAG, + QMI_DATA_LEN, + QMI_UNSIGNED_1_BYTE, + QMI_UNSIGNED_2_BYTE, + QMI_UNSIGNED_4_BYTE, + QMI_UNSIGNED_8_BYTE, + QMI_SIGNED_2_BYTE_ENUM, + QMI_SIGNED_4_BYTE_ENUM, + QMI_STRUCT, + QMI_STRING, +}; + +enum qmi_array_type { + NO_ARRAY, + STATIC_ARRAY, + VAR_LEN_ARRAY, +}; + +/** + * struct qmi_elem_info - describes how to encode a single QMI element + * @data_type: Data type of this element. + * @elem_len: Array length of this element, if an array. + * @elem_size: Size of a single instance of this data type. + * @array_type: Array type of this element. + * @tlv_type: QMI message specific type to identify which element + * is present in an incoming message. + * @offset: Specifies the offset of the first instance of this + * element in the data structure. + * @ei_array: Null-terminated array of @qmi_elem_info to describe nested + * structures. + */ +struct qmi_elem_info { + enum qmi_elem_type data_type; + u32 elem_len; + u32 elem_size; + enum qmi_array_type array_type; + u8 tlv_type; + u32 offset; + struct qmi_elem_info *ei_array; +}; + +#define QMI_RESULT_SUCCESS_V01 0 +#define QMI_RESULT_FAILURE_V01 1 + +#define QMI_ERR_NONE_V01 0 +#define QMI_ERR_MALFORMED_MSG_V01 1 +#define QMI_ERR_NO_MEMORY_V01 2 +#define QMI_ERR_INTERNAL_V01 3 +#define QMI_ERR_CLIENT_IDS_EXHAUSTED_V01 5 +#define QMI_ERR_INVALID_ID_V01 41 +#define QMI_ERR_ENCODING_V01 58 +#define QMI_ERR_DISABLED_V01 69 +#define QMI_ERR_INCOMPATIBLE_STATE_V01 90 +#define QMI_ERR_NOT_SUPPORTED_V01 94 + +/** + * qmi_response_type_v01 - common response header (decoded) + * @result: result of the transaction + * @error: error value, when @result is QMI_RESULT_FAILURE_V01 + */ +struct qmi_response_type_v01 { + u16 result; + u16 error; +}; + +extern struct qmi_elem_info qmi_response_type_v01_ei[]; + +/** + * struct qmi_service - context to track lookup-results + * @service: service type + * @version: version of the @service + * @instance: instance id of the @service + * @node: node of the service + * @port: port of the service + * @priv: handle for client's use + * @list_node: list_head for house keeping + */ +struct qmi_service { + unsigned int service; + unsigned int version; + unsigned int instance; + + unsigned int node; + unsigned int port; + + void *priv; + struct list_head list_node; +}; + +struct qmi_handle; + +/** + * struct qmi_ops - callbacks for qmi_handle + * @new_server: inform client of a new_server lookup-result, returning + * successfully from this call causes the library to call + * @del_server as the service is removed from the + * lookup-result. @priv of the qmi_service can be used by + * the client + * @del_server: inform client of a del_server lookup-result + * @net_reset: inform client that the name service was restarted and + * that and any state needs to be released + * @msg_handler: invoked for incoming messages, allows a client to + * override the usual QMI message handler + * @bye: inform a client that all clients from a node are gone + * @del_client: inform a client that a particular client is gone + */ +struct qmi_ops { + int (*new_server)(struct qmi_handle *qmi, struct qmi_service *svc); + void (*del_server)(struct qmi_handle *qmi, struct qmi_service *svc); + void (*net_reset)(struct qmi_handle *qmi); + void (*msg_handler)(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, + const void *data, size_t count); + void (*bye)(struct qmi_handle *qmi, unsigned int node); + void (*del_client)(struct qmi_handle *qmi, + unsigned int node, unsigned int port); +}; + +/** + * struct qmi_txn - transaction context + * @qmi: QMI handle this transaction is associated with + * @id: transaction id + * @lock: for synchronization between handler and waiter of messages + * @completion: completion object as the transaction receives a response + * @result: result code for the completed transaction + * @ei: description of the QMI encoded response (optional) + * @dest: destination buffer to decode message into (optional) + */ +struct qmi_txn { + struct qmi_handle *qmi; + + u16 id; + + struct mutex lock; + struct completion completion; + int result; + + struct qmi_elem_info *ei; + void *dest; +}; + +/** + * struct qmi_msg_handler - description of QMI message handler + * @type: type of message + * @msg_id: message id + * @ei: description of the QMI encoded message + * @decoded_size: size of the decoded object + * @fn: function to invoke as the message is decoded + */ +struct qmi_msg_handler { + unsigned int type; + unsigned int msg_id; + + struct qmi_elem_info *ei; + + size_t decoded_size; + void (*fn)(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, + struct qmi_txn *txn, const void *decoded); +}; + +/** + * struct qmi_handle - QMI context + * @sock: socket handle + * @sock_lock: synchronization of @sock modifications + * @sq: sockaddr of @sock + * @work: work for handling incoming messages + * @wq: workqueue to post @work on + * @recv_buf: scratch buffer for handling incoming messages + * @recv_buf_size: size of @recv_buf + * @lookups: list of registered lookup requests + * @lookup_results: list of lookup-results advertised to the client + * @services: list of registered services (by this client) + * @ops: reference to callbacks + * @txns: outstanding transactions + * @txn_lock: lock for modifications of @txns + * @handlers: list of handlers for incoming messages + */ +struct qmi_handle { + struct socket *sock; + struct mutex sock_lock; + + struct sockaddr_qrtr sq; + + struct work_struct work; + struct workqueue_struct *wq; + + void *recv_buf; + size_t recv_buf_size; + + struct list_head lookups; + struct list_head lookup_results; + struct list_head services; + + struct qmi_ops ops; + + struct idr txns; + struct mutex txn_lock; + + const struct qmi_msg_handler *handlers; +}; + +int qmi_add_lookup(struct qmi_handle *qmi, unsigned int service, + unsigned int version, unsigned int instance); +int qmi_add_server(struct qmi_handle *qmi, unsigned int service, + unsigned int version, unsigned int instance); + +int qmi_handle_init(struct qmi_handle *qmi, size_t max_msg_len, + const struct qmi_ops *ops, + const struct qmi_msg_handler *handlers); +void qmi_handle_release(struct qmi_handle *qmi); + +ssize_t qmi_send_request(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, + struct qmi_txn *txn, int msg_id, size_t len, + struct qmi_elem_info *ei, const void *c_struct); +ssize_t qmi_send_response(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, + struct qmi_txn *txn, int msg_id, size_t len, + struct qmi_elem_info *ei, const void *c_struct); +ssize_t qmi_send_indication(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, + int msg_id, size_t len, struct qmi_elem_info *ei, + const void *c_struct); + +void *qmi_encode_message(int type, unsigned int msg_id, size_t *len, + unsigned int txn_id, struct qmi_elem_info *ei, + const void *c_struct); + +int qmi_decode_message(const void *buf, size_t len, + struct qmi_elem_info *ei, void *c_struct); + +int qmi_txn_init(struct qmi_handle *qmi, struct qmi_txn *txn, + struct qmi_elem_info *ei, void *c_struct); +int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout); +void qmi_txn_cancel(struct qmi_txn *txn); + +#endif |