Fix a potential buffer overflow that could occur during firmware download by storing buffer address locally instead of inside MHI context. CRs-Fixed: 1109397 Change-Id: If27ba602cdafdc8d25a94fdc0d74e8970bf0b0f4 Signed-off-by: Sujeev Dias <sdias@codeaurora.org>
771 lines
21 KiB
C
771 lines
21 KiB
C
/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#ifndef _H_MHI
|
|
#define _H_MHI
|
|
|
|
#include "mhi_macros.h"
|
|
#include <linux/msm_mhi.h>
|
|
#include <linux/types.h>
|
|
#include <linux/pm.h>
|
|
#include <linux/completion.h>
|
|
#include <linux/atomic.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/cdev.h>
|
|
#include <linux/msm_pcie.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/irqreturn.h>
|
|
#include <linux/list.h>
|
|
#include <linux/dma-mapping.h>
|
|
|
|
struct mhi_device_ctxt;
|
|
|
|
enum MHI_DEBUG_LEVEL {
|
|
MHI_MSG_RAW = 0x1,
|
|
MHI_MSG_VERBOSE = 0x2,
|
|
MHI_MSG_INFO = 0x4,
|
|
MHI_MSG_DBG = 0x8,
|
|
MHI_MSG_WARNING = 0x10,
|
|
MHI_MSG_ERROR = 0x20,
|
|
MHI_MSG_CRITICAL = 0x40,
|
|
MHI_MSG_reserved = 0x80000000
|
|
};
|
|
|
|
struct pcie_core_info {
|
|
u32 dev_id;
|
|
u32 manufact_id;
|
|
u32 mhi_ver;
|
|
void __iomem *bar0_base;
|
|
void __iomem *bar0_end;
|
|
u32 irq_base;
|
|
u32 max_nr_msis;
|
|
u32 domain;
|
|
u32 bus;
|
|
u32 slot;
|
|
struct pci_saved_state *pcie_state;
|
|
bool pci_master;
|
|
};
|
|
|
|
struct firmware_info {
|
|
const char *fw_image;
|
|
size_t max_sbl_len;
|
|
size_t segment_size;
|
|
};
|
|
|
|
struct bhie_mem_info {
|
|
void *pre_aligned;
|
|
void *aligned;
|
|
size_t alloc_size;
|
|
size_t size;
|
|
phys_addr_t phys_addr;
|
|
dma_addr_t dma_handle;
|
|
};
|
|
|
|
struct bhie_vec_table {
|
|
struct scatterlist *sg_list;
|
|
struct bhie_mem_info *bhie_mem_info;
|
|
struct bhi_vec_entry *bhi_vec_entry;
|
|
unsigned segment_count;
|
|
u32 sequence; /* sequence to indicate new xfer */
|
|
};
|
|
|
|
struct bhi_ctxt_t {
|
|
void __iomem *bhi_base;
|
|
dev_t bhi_dev;
|
|
struct cdev cdev;
|
|
struct device *dev;
|
|
u32 alignment;
|
|
u32 poll_timeout;
|
|
/* BHI/E vector table */
|
|
bool manage_boot; /* fw download done by MHI host */
|
|
bool support_rddm;
|
|
struct work_struct fw_load_work;
|
|
struct firmware_info firmware_info;
|
|
struct bhie_vec_table fw_table;
|
|
struct bhie_vec_table rddm_table;
|
|
size_t rddm_size;
|
|
};
|
|
|
|
enum MHI_CHAN_DIR {
|
|
MHI_INVALID = 0x0,
|
|
MHI_OUT = 0x1,
|
|
MHI_IN = 0x2,
|
|
MHI_CHAN_TYPE_reserved = 0x80000000
|
|
};
|
|
|
|
enum MHI_RING_CLASS {
|
|
MHI_RING_INVALID = 0x0,
|
|
MHI_HW_RING = 0x1,
|
|
MHI_SW_RING = 0x2,
|
|
MHI_RING_TYPE_reserved = 0x80000000
|
|
};
|
|
|
|
enum MHI_CHAN_STATE {
|
|
MHI_CHAN_STATE_DISABLED = 0x0,
|
|
MHI_CHAN_STATE_ENABLED = 0x1,
|
|
MHI_CHAN_STATE_RUNNING = 0x2,
|
|
MHI_CHAN_STATE_SUSPENDED = 0x3,
|
|
MHI_CHAN_STATE_STOP = 0x4,
|
|
MHI_CHAN_STATE_ERROR = 0x5,
|
|
MHI_CHAN_STATE_LIMIT = 0x6,
|
|
MHI_CHAN_STATE_reserved = 0x80000000
|
|
};
|
|
|
|
enum MHI_RING_TYPE {
|
|
MHI_RING_TYPE_CMD_RING = 0x0,
|
|
MHI_RING_TYPE_XFER_RING = 0x1,
|
|
MHI_RING_TYPE_EVENT_RING = 0x2,
|
|
MHI_RING_TYPE_MAX = 0x4,
|
|
MHI_RING_reserved = 0x80000000
|
|
};
|
|
|
|
enum MHI_CHAIN {
|
|
MHI_TRE_CHAIN_OFF = 0x0,
|
|
MHI_TRE_CHAIN_ON = 0x1,
|
|
MHI_TRE_CHAIN_LIMIT = 0x2,
|
|
MHI_TRE_CHAIN_reserved = 0x80000000
|
|
};
|
|
|
|
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_BHI = 0x7,
|
|
MHI_STATE_SYS_ERR = 0xFF,
|
|
MHI_STATE_LIMIT,
|
|
};
|
|
|
|
enum MHI_BRSTMODE {
|
|
/* BRST Mode Enable for HW Channels, SW Channel Disabled */
|
|
MHI_BRSTMODE_DEFAULT = 0x0,
|
|
MHI_BRSTMODE_RESERVED = 0x1,
|
|
MHI_BRSTMODE_DISABLE = 0x2,
|
|
MHI_BRSTMODE_ENABLE = 0x3
|
|
};
|
|
|
|
enum MHI_PM_STATE {
|
|
MHI_PM_DISABLE = BIT(0), /* MHI is not enabled */
|
|
MHI_PM_POR = BIT(1), /* Power On Reset State */
|
|
MHI_PM_M0 = BIT(2),
|
|
MHI_PM_M1 = BIT(3),
|
|
MHI_PM_M1_M2_TRANSITION = BIT(4), /* Register access not allowed */
|
|
MHI_PM_M2 = BIT(5),
|
|
MHI_PM_M3_ENTER = BIT(6),
|
|
MHI_PM_M3 = BIT(7),
|
|
MHI_PM_M3_EXIT = BIT(8),
|
|
MHI_PM_SYS_ERR_DETECT = BIT(9),
|
|
MHI_PM_SYS_ERR_PROCESS = BIT(10),
|
|
MHI_PM_SHUTDOWN_PROCESS = BIT(11),
|
|
MHI_PM_LD_ERR_FATAL_DETECT = BIT(12), /* Link not accessible */
|
|
MHI_PM_SSR_PENDING = BIT(13)
|
|
};
|
|
|
|
struct mhi_pm_transitions {
|
|
enum MHI_PM_STATE from_state;
|
|
u32 to_states;
|
|
};
|
|
|
|
#define MHI_DB_ACCESS_VALID(pm_state) (pm_state & (MHI_PM_M0 | MHI_PM_M1))
|
|
#define MHI_WAKE_DB_ACCESS_VALID(pm_state) (pm_state & (MHI_PM_M0 | \
|
|
MHI_PM_M1 | MHI_PM_M2))
|
|
#define MHI_REG_ACCESS_VALID(pm_state) ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \
|
|
MHI_PM_M1 | MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \
|
|
MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \
|
|
MHI_PM_SHUTDOWN_PROCESS)))
|
|
#define MHI_EVENT_ACCESS_INVALID(pm_state) (pm_state == MHI_PM_DISABLE || \
|
|
pm_state >= MHI_PM_SYS_ERR_DETECT)
|
|
struct __packed mhi_event_ctxt {
|
|
u32 mhi_intmodt;
|
|
u32 mhi_event_er_type;
|
|
u32 mhi_msi_vector;
|
|
u64 mhi_event_ring_base_addr;
|
|
u64 mhi_event_ring_len;
|
|
u64 mhi_event_read_ptr;
|
|
u64 mhi_event_write_ptr;
|
|
};
|
|
|
|
struct __packed mhi_chan_ctxt {
|
|
u32 chstate : 8;
|
|
u32 brstmode : 2;
|
|
u32 pollcfg : 6;
|
|
u32 reserved : 16;
|
|
u32 chtype;
|
|
u32 mhi_event_ring_index;
|
|
u64 mhi_trb_ring_base_addr;
|
|
u64 mhi_trb_ring_len;
|
|
u64 mhi_trb_read_ptr;
|
|
u64 mhi_trb_write_ptr;
|
|
};
|
|
|
|
struct __packed mhi_cmd_ctxt {
|
|
u32 mhi_cmd_ctxt_reserved1;
|
|
u32 mhi_cmd_ctxt_reserved2;
|
|
u32 mhi_cmd_ctxt_reserved3;
|
|
u64 mhi_cmd_ring_base_addr;
|
|
u64 mhi_cmd_ring_len;
|
|
u64 mhi_cmd_ring_read_ptr;
|
|
u64 mhi_cmd_ring_write_ptr;
|
|
};
|
|
|
|
enum MHI_COMMAND {
|
|
MHI_COMMAND_NOOP = 0x0,
|
|
MHI_COMMAND_RESET_CHAN = 0x1,
|
|
MHI_COMMAND_STOP_CHAN = 0x2,
|
|
MHI_COMMAND_START_CHAN = 0x3,
|
|
MHI_COMMAND_RESUME_CHAN = 0x4,
|
|
MHI_COMMAND_MAX_NR = 0x5,
|
|
MHI_COMMAND_reserved = 0x80000000
|
|
};
|
|
|
|
enum MHI_PKT_TYPE {
|
|
MHI_PKT_TYPE_RESERVED = 0x0,
|
|
MHI_PKT_TYPE_NOOP_CMD = 0x1,
|
|
MHI_PKT_TYPE_TRANSFER = 0x2,
|
|
MHI_PKT_TYPE_RESET_CHAN_CMD = 0x10,
|
|
MHI_PKT_TYPE_STOP_CHAN_CMD = 0x11,
|
|
MHI_PKT_TYPE_START_CHAN_CMD = 0x12,
|
|
MHI_PKT_TYPE_STATE_CHANGE_EVENT = 0x20,
|
|
MHI_PKT_TYPE_CMD_COMPLETION_EVENT = 0x21,
|
|
MHI_PKT_TYPE_TX_EVENT = 0x22,
|
|
MHI_PKT_TYPE_EE_EVENT = 0x40,
|
|
MHI_PKT_TYPE_STALE_EVENT, /* Internal event */
|
|
};
|
|
|
|
struct __packed mhi_tx_pkt {
|
|
u64 buffer_ptr;
|
|
u32 buf_len;
|
|
u32 info;
|
|
};
|
|
|
|
struct __packed mhi_noop_tx_pkt {
|
|
u64 reserved1;
|
|
u32 reserved2;
|
|
u32 info;
|
|
};
|
|
|
|
struct __packed mhi_noop_cmd_pkt {
|
|
u64 reserved1;
|
|
u32 reserved2;
|
|
u32 info;
|
|
};
|
|
|
|
struct __packed mhi_reset_chan_cmd_pkt {
|
|
u32 reserved1;
|
|
u32 reserved2;
|
|
u32 reserved3;
|
|
u32 info;
|
|
};
|
|
|
|
struct __packed mhi_ee_state_change_event {
|
|
u64 reserved1;
|
|
u32 exec_env;
|
|
u32 info;
|
|
};
|
|
|
|
struct __packed mhi_xfer_event_pkt {
|
|
u64 xfer_ptr;
|
|
u32 xfer_details;
|
|
u32 info;
|
|
};
|
|
|
|
struct __packed mhi_cmd_complete_event_pkt {
|
|
u64 ptr;
|
|
u32 code;
|
|
u32 info;
|
|
};
|
|
|
|
struct __packed mhi_state_change_event_pkt {
|
|
u64 reserved1;
|
|
u32 state;
|
|
u32 info;
|
|
};
|
|
|
|
union __packed mhi_xfer_pkt {
|
|
struct mhi_tx_pkt data_tx_pkt;
|
|
struct mhi_noop_tx_pkt noop_tx_pkt;
|
|
struct mhi_tx_pkt type;
|
|
};
|
|
|
|
union __packed mhi_cmd_pkt {
|
|
struct mhi_reset_chan_cmd_pkt reset_cmd_pkt;
|
|
struct mhi_noop_cmd_pkt noop_cmd_pkt;
|
|
struct mhi_noop_cmd_pkt type;
|
|
};
|
|
|
|
union __packed mhi_event_pkt {
|
|
struct mhi_xfer_event_pkt xfer_event_pkt;
|
|
struct mhi_cmd_complete_event_pkt cmd_complete_event_pkt;
|
|
struct mhi_state_change_event_pkt state_change_event_pkt;
|
|
struct mhi_ee_state_change_event ee_event_pkt;
|
|
struct mhi_xfer_event_pkt type;
|
|
};
|
|
|
|
enum MHI_EVENT_CCS {
|
|
MHI_EVENT_CC_INVALID = 0x0,
|
|
MHI_EVENT_CC_SUCCESS = 0x1,
|
|
MHI_EVENT_CC_EOT = 0x2,
|
|
MHI_EVENT_CC_OVERFLOW = 0x3,
|
|
MHI_EVENT_CC_EOB = 0x4,
|
|
MHI_EVENT_CC_OOB = 0x5,
|
|
MHI_EVENT_CC_DB_MODE = 0x6,
|
|
MHI_EVENT_CC_UNDEFINED_ERR = 0x10,
|
|
MHI_EVENT_CC_BAD_TRE = 0x11,
|
|
};
|
|
|
|
struct db_mode {
|
|
/* if set do not reset DB_Mode during M0 resume */
|
|
u32 preserve_db_state : 1;
|
|
u32 db_mode : 1;
|
|
enum MHI_BRSTMODE brstmode;
|
|
void (*process_db)(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
void __iomem *io_addr, unsigned int chan,
|
|
dma_addr_t val);
|
|
};
|
|
|
|
struct mhi_ring {
|
|
void *base;
|
|
void *wp;
|
|
void *rp;
|
|
void *ack_rp;
|
|
uintptr_t len;
|
|
uintptr_t el_size;
|
|
u32 overwrite_en;
|
|
enum MHI_CHAN_DIR dir;
|
|
enum MHI_CHAN_STATE ch_state;
|
|
struct db_mode db_mode;
|
|
u32 msi_disable_cntr;
|
|
u32 msi_enable_cntr;
|
|
spinlock_t ring_lock;
|
|
struct dma_pool *dma_pool;
|
|
struct tasklet_struct ev_task;
|
|
struct work_struct ev_worker;
|
|
struct mhi_device_ctxt *mhi_dev_ctxt;
|
|
int index;
|
|
};
|
|
|
|
enum MHI_CMD_STATUS {
|
|
MHI_CMD_NOT_PENDING = 0x0,
|
|
MHI_CMD_PENDING = 0x1,
|
|
MHI_CMD_RESET_PENDING = 0x2,
|
|
MHI_CMD_RESERVED = 0x80000000
|
|
};
|
|
|
|
enum MHI_EVENT_RING_TYPE {
|
|
MHI_EVENT_RING_TYPE_INVALID = 0x0,
|
|
MHI_EVENT_RING_TYPE_VALID = 0x1,
|
|
MHI_EVENT_RING_TYPE_reserved = 0x80000000
|
|
};
|
|
|
|
enum MHI_INIT_ERROR_STAGE {
|
|
MHI_INIT_ERROR_STAGE_UNWIND_ALL = 0x1,
|
|
MHI_INIT_ERROR_STAGE_DEVICE_CTRL = 0x2,
|
|
MHI_INIT_ERROR_STAGE_THREADS = 0x3,
|
|
MHI_INIT_ERROR_STAGE_EVENTS = 0x4,
|
|
MHI_INIT_ERROR_STAGE_MEM_ZONES = 0x5,
|
|
MHI_INIT_ERROR_STAGE_SYNC = 0x6,
|
|
MHI_INIT_ERROR_STAGE_THREAD_QUEUES = 0x7,
|
|
MHI_INIT_ERROR_TIMERS = 0x8,
|
|
MHI_INIT_ERROR_STAGE_RESERVED = 0x80000000
|
|
};
|
|
|
|
enum STATE_TRANSITION {
|
|
STATE_TRANSITION_RESET = MHI_STATE_RESET,
|
|
STATE_TRANSITION_READY = MHI_STATE_READY,
|
|
STATE_TRANSITION_M0 = MHI_STATE_M0,
|
|
STATE_TRANSITION_M1 = MHI_STATE_M1,
|
|
STATE_TRANSITION_M2 = MHI_STATE_M2,
|
|
STATE_TRANSITION_M3 = MHI_STATE_M3,
|
|
STATE_TRANSITION_BHI,
|
|
STATE_TRANSITION_SBL,
|
|
STATE_TRANSITION_AMSS,
|
|
STATE_TRANSITION_LINK_DOWN,
|
|
STATE_TRANSITION_WAKE,
|
|
STATE_TRANSITION_BHIE,
|
|
STATE_TRANSITION_RDDM,
|
|
STATE_TRANSITION_SYS_ERR = MHI_STATE_SYS_ERR,
|
|
STATE_TRANSITION_MAX
|
|
};
|
|
|
|
enum MHI_EXEC_ENV {
|
|
MHI_EXEC_ENV_PBL = 0x0,
|
|
MHI_EXEC_ENV_SBL = 0x1,
|
|
MHI_EXEC_ENV_AMSS = 0x2,
|
|
MHI_EXEC_ENV_BHIE = 0x3,
|
|
MHI_EXEC_ENV_RDDM = 0x4,
|
|
MHI_EXEC_ENV_DISABLE_TRANSITION, /* local EE, not related to mhi spec */
|
|
};
|
|
|
|
struct mhi_chan_info {
|
|
u32 chan_nr;
|
|
u32 max_desc;
|
|
u32 ev_ring;
|
|
u32 flags;
|
|
};
|
|
|
|
struct mhi_chan_cfg {
|
|
enum MHI_COMMAND current_cmd;
|
|
struct mutex chan_lock;
|
|
spinlock_t event_lock; /* completion event lock */
|
|
struct completion cmd_complete;
|
|
struct mhi_cmd_complete_event_pkt cmd_event_pkt;
|
|
union mhi_cmd_pkt cmd_pkt;
|
|
};
|
|
|
|
struct mhi_client_config {
|
|
struct mhi_chan_info chan_info;
|
|
struct mhi_device_ctxt *mhi_dev_ctxt;
|
|
struct mhi_client_info_t client_info;
|
|
void *user_data;
|
|
struct mhi_result result;
|
|
u32 device_index;
|
|
u32 msi_vec;
|
|
u32 intmod_t;
|
|
u32 pkt_count;
|
|
int magic;
|
|
int chan_status;
|
|
int event_ring_index;
|
|
};
|
|
|
|
enum MHI_TYPE_EVENT_RING {
|
|
MHI_ER_DATA_TYPE = 0x1,
|
|
MHI_ER_CTRL_TYPE = 0x2,
|
|
MHI_ER_TYPE_RESERVED = 0x80000000
|
|
};
|
|
|
|
struct mhi_state_work_queue {
|
|
spinlock_t *q_lock;
|
|
struct mhi_ring q_info;
|
|
u32 queue_full_cntr;
|
|
enum STATE_TRANSITION buf[MHI_WORK_Q_MAX_SIZE];
|
|
};
|
|
|
|
struct mhi_buf_info {
|
|
dma_addr_t bb_p_addr;
|
|
dma_addr_t pre_alloc_p_addr;
|
|
void *bb_v_addr;
|
|
void *pre_alloc_v_addr;
|
|
void *client_buf;
|
|
size_t buf_len;
|
|
size_t pre_alloc_len;
|
|
size_t filled_size;
|
|
enum dma_data_direction dir;
|
|
int bb_active;
|
|
};
|
|
|
|
struct mhi_counters {
|
|
u32 m0_m1;
|
|
u32 m1_m2;
|
|
u32 m2_m0;
|
|
u32 m0_m3;
|
|
u32 m1_m3;
|
|
u32 m3_m0;
|
|
u32 chan_pkts_xferd[MHI_MAX_CHANNELS];
|
|
u32 bb_used[MHI_MAX_CHANNELS];
|
|
atomic_t device_wake;
|
|
atomic_t outbound_acks;
|
|
u32 *msi_counter;
|
|
u32 mhi_reset_cntr;
|
|
u32 link_down_cntr;
|
|
u32 link_up_cntr;
|
|
};
|
|
|
|
struct mhi_flags {
|
|
bool mhi_initialized;
|
|
u32 link_up;
|
|
bool bb_required;
|
|
};
|
|
|
|
struct mhi_wait_queues {
|
|
wait_queue_head_t *m0_event;
|
|
wait_queue_head_t *m3_event;
|
|
wait_queue_head_t *bhi_event;
|
|
};
|
|
|
|
struct dev_mmio_info {
|
|
void __iomem *mmio_addr;
|
|
void __iomem *chan_db_addr;
|
|
void __iomem *event_db_addr;
|
|
void __iomem *cmd_db_addr;
|
|
u64 mmio_len;
|
|
u32 nr_event_rings;
|
|
u32 nr_hw_event_rings;
|
|
u32 nr_sw_event_rings;
|
|
u32 nr_sw_xfer_rings;
|
|
u32 nr_hw_xfer_rings;
|
|
dma_addr_t dma_ev_ctxt; /* Bus address of ECABAP*/
|
|
};
|
|
|
|
struct mhi_ring_ctxt {
|
|
struct mhi_event_ctxt *ec_list;
|
|
struct mhi_chan_ctxt *cc_list;
|
|
struct mhi_cmd_ctxt *cmd_ctxt;
|
|
dma_addr_t dma_ec_list;
|
|
dma_addr_t dma_cc_list;
|
|
dma_addr_t dma_cmd_ctxt;
|
|
};
|
|
|
|
struct mhi_dev_space {
|
|
void *dev_mem_start;
|
|
dma_addr_t dma_dev_mem_start;
|
|
size_t dev_mem_len;
|
|
struct mhi_ring_ctxt ring_ctxt;
|
|
u64 start_win_addr;
|
|
u64 end_win_addr;
|
|
};
|
|
|
|
struct mhi_device_ctxt {
|
|
struct list_head node;
|
|
struct pcie_core_info core;
|
|
struct msm_pcie_register_event mhi_pci_link_event;
|
|
struct pci_dev *pcie_device;
|
|
struct bhi_ctxt_t bhi_ctxt;
|
|
struct platform_device *plat_dev;
|
|
enum MHI_PM_STATE mhi_pm_state; /* Host driver state */
|
|
enum MHI_STATE mhi_state; /* protocol state */
|
|
enum MHI_EXEC_ENV dev_exec_env;
|
|
|
|
struct mhi_dev_space dev_space;
|
|
struct mhi_ring chan_bb_list[MHI_MAX_CHANNELS];
|
|
struct mhi_ring mhi_local_chan_ctxt[MHI_MAX_CHANNELS];
|
|
|
|
struct mhi_ring *mhi_local_event_ctxt;
|
|
struct mhi_ring mhi_local_cmd_ctxt[NR_OF_CMD_RINGS];
|
|
struct mhi_chan_cfg mhi_chan_cfg[MHI_MAX_CHANNELS];
|
|
|
|
struct mhi_client_handle *client_handle_list[MHI_MAX_CHANNELS];
|
|
struct mhi_event_ring_cfg *ev_ring_props;
|
|
struct work_struct st_thread_worker;
|
|
struct work_struct process_m1_worker;
|
|
struct work_struct process_sys_err_worker;
|
|
struct mhi_wait_queues mhi_ev_wq;
|
|
struct dev_mmio_info mmio_info;
|
|
|
|
struct mhi_state_work_queue state_change_work_item_list;
|
|
|
|
struct mhi_counters counters;
|
|
struct mhi_flags flags;
|
|
|
|
struct hrtimer m1_timer;
|
|
ktime_t m1_timeout;
|
|
u32 poll_reset_timeout_ms;
|
|
|
|
struct notifier_block mhi_ssr_nb;
|
|
struct esoc_desc *esoc_handle;
|
|
void *esoc_ssr_handle;
|
|
|
|
u32 bus_client;
|
|
struct msm_bus_scale_pdata *bus_scale_table;
|
|
struct notifier_block mhi_cpu_notifier;
|
|
|
|
unsigned long esoc_notif;
|
|
enum STATE_TRANSITION base_state;
|
|
|
|
rwlock_t pm_xfer_lock; /* lock to control PM State */
|
|
spinlock_t dev_wake_lock; /* lock to set wake bit */
|
|
struct mutex pm_lock;
|
|
struct wakeup_source w_lock;
|
|
|
|
char *chan_info;
|
|
struct dentry *child;
|
|
struct dentry *parent;
|
|
void *mhi_ipc_log;
|
|
|
|
/* Shadow functions since not all device supports runtime pm */
|
|
int (*bus_master_rt_get)(struct pci_dev *pci_dev);
|
|
void (*bus_master_rt_put)(struct pci_dev *pci_dev);
|
|
void (*runtime_get)(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
void (*runtime_put)(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
void (*assert_wake)(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
bool force_set);
|
|
void (*deassert_wake)(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
void (*status_cb)(enum MHI_CB_REASON, void *priv);
|
|
void *priv_data; /* private data for bus master */
|
|
struct completion cmd_complete;
|
|
};
|
|
|
|
struct mhi_device_driver {
|
|
struct mutex lock;
|
|
struct list_head head;
|
|
struct class *mhi_bhi_class;
|
|
struct dentry *parent;
|
|
};
|
|
|
|
struct mhi_event_ring_cfg {
|
|
u32 nr_desc;
|
|
u32 msi_vec;
|
|
u32 intmod;
|
|
enum MHI_CLIENT_CHANNEL chan;
|
|
u32 flags;
|
|
/*
|
|
* Priority of event handling:
|
|
* 0 = highest, handle events in isr (reserved for future)
|
|
* 1 = handles event using tasklet
|
|
* 2 = handles events using workerthread
|
|
*/
|
|
u32 priority;
|
|
enum MHI_RING_CLASS class;
|
|
irqreturn_t (*mhi_handler_ptr)(int , void *);
|
|
};
|
|
#define MHI_EV_PRIORITY_TASKLET (1)
|
|
|
|
struct mhi_data_buf {
|
|
dma_addr_t bounce_buffer;
|
|
dma_addr_t client_buffer;
|
|
u32 bounce_flag;
|
|
};
|
|
|
|
extern struct mhi_device_driver *mhi_device_drv;
|
|
|
|
irqreturn_t mhi_msi_ipa_handlr(int irq_number, void *dev_id);
|
|
int mhi_reset_all_thread_queues(
|
|
struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_add_elements_to_event_rings(
|
|
struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
enum STATE_TRANSITION new_state);
|
|
int get_nr_avail_ring_elements(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
struct mhi_ring *ring);
|
|
int get_nr_enclosed_el(struct mhi_ring *ring, void *loc_1,
|
|
void *loc_2, u32 *nr_el);
|
|
int mhi_init_mmio(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_init_device_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_init_local_event_ring(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
u32 nr_ev_el, u32 event_ring_index);
|
|
int mhi_send_cmd(struct mhi_device_ctxt *dest_device,
|
|
enum MHI_COMMAND which_cmd, u32 chan);
|
|
int mhi_queue_tx_pkt(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
enum MHI_CLIENT_CHANNEL chan,
|
|
void *payload,
|
|
size_t payload_size);
|
|
int mhi_init_chan_ctxt(struct mhi_chan_ctxt *cc_list,
|
|
uintptr_t trb_list_phy,
|
|
uintptr_t trb_list_virt,
|
|
u64 el_per_ring,
|
|
enum MHI_CHAN_DIR chan_type,
|
|
u32 event_ring,
|
|
struct mhi_ring *ring,
|
|
enum MHI_CHAN_STATE chan_state,
|
|
bool preserve_db_state,
|
|
enum MHI_BRSTMODE brstmode);
|
|
int mhi_populate_event_cfg(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_get_event_ring_for_channel(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
u32 chan);
|
|
int delete_element(struct mhi_ring *ring, void **rp,
|
|
void **wp, void **assigned_addr);
|
|
int ctxt_add_element(struct mhi_ring *ring, void **assigned_addr);
|
|
int ctxt_del_element(struct mhi_ring *ring, void **assigned_addr);
|
|
int get_element_index(struct mhi_ring *ring, void *address,
|
|
uintptr_t *index);
|
|
int recycle_trb_and_ring(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
struct mhi_ring *ring, enum MHI_RING_TYPE ring_type, u32 ring_index);
|
|
int parse_xfer_event(struct mhi_device_ctxt *ctxt,
|
|
union mhi_event_pkt *event, u32 event_id);
|
|
enum MHI_EVENT_CCS get_cmd_pkt(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
union mhi_event_pkt *ev_pkt,
|
|
union mhi_cmd_pkt **cmd_pkt, u32 event_index);
|
|
int parse_cmd_event(struct mhi_device_ctxt *ctxt,
|
|
union mhi_event_pkt *event, u32 event_index);
|
|
int mhi_test_for_device_ready(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_test_for_device_reset(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int validate_ring_el_addr(struct mhi_ring *ring, uintptr_t addr);
|
|
int validate_ev_el_addr(struct mhi_ring *ring, uintptr_t addr);
|
|
void mhi_state_change_worker(struct work_struct *work);
|
|
void mhi_sys_err_worker(struct work_struct *work);
|
|
int mhi_init_state_transition(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
enum STATE_TRANSITION new_state);
|
|
int mhi_wait_for_mdm(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
enum hrtimer_restart mhi_initiate_m1(struct hrtimer *timer);
|
|
int mhi_pci_suspend(struct device *dev);
|
|
int mhi_pci_resume(struct device *dev);
|
|
int mhi_init_pcie_device(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_init_pm_sysfs(struct device *dev);
|
|
void mhi_rem_pm_sysfs(struct device *dev);
|
|
void mhi_pci_remove(struct pci_dev *mhi_device);
|
|
int mhi_ctxt_init(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_get_chan_max_buffers(u32 chan);
|
|
int mhi_esoc_register(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
void mhi_link_state_cb(struct msm_pcie_notify *notify);
|
|
void mhi_notify_clients(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
enum MHI_CB_REASON reason);
|
|
void mhi_notify_client(struct mhi_client_handle *client_handle,
|
|
enum MHI_CB_REASON reason);
|
|
void mhi_master_mode_runtime_get(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
void mhi_master_mode_runtime_put(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
void mhi_slave_mode_runtime_get(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
void mhi_slave_mode_runtime_put(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
void mhi_deassert_device_wake(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
void mhi_assert_device_wake(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
bool force_set);
|
|
int mhi_reg_notifiers(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_cpu_notifier_cb(struct notifier_block *nfb, unsigned long action,
|
|
void *hcpu);
|
|
int init_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_turn_off_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt, bool graceful);
|
|
int mhi_turn_on_pcie_link(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_initiate_m0(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_initiate_m3(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_set_bus_request(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
int index);
|
|
int start_chan_sync(struct mhi_client_handle *client_handle);
|
|
void mhi_process_db_brstmode(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
void __iomem *io_addr, unsigned int chan,
|
|
dma_addr_t val);
|
|
void mhi_process_db_brstmode_disable(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
void __iomem *io_addr, unsigned int chan,
|
|
dma_addr_t val);
|
|
void mhi_process_db(struct mhi_device_ctxt *mhi_dev_ctxt, void __iomem *io_addr,
|
|
unsigned int chan, dma_addr_t val);
|
|
void mhi_reg_write_field(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
void __iomem *io_addr,
|
|
uintptr_t io_offset,
|
|
u32 mask, u32 shift, u32 val);
|
|
void mhi_reg_write(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
void __iomem *io_addr, uintptr_t io_offset, u32 val);
|
|
u32 mhi_reg_read(void __iomem *io_addr, uintptr_t io_offset);
|
|
u32 mhi_reg_read_field(void __iomem *io_addr, uintptr_t io_offset,
|
|
u32 mask, u32 shift);
|
|
void mhi_exit_m2(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int mhi_runtime_suspend(struct device *dev);
|
|
int get_chan_props(struct mhi_device_ctxt *mhi_dev_ctxt, int chan,
|
|
struct mhi_chan_info *chan_info);
|
|
int mhi_runtime_resume(struct device *dev);
|
|
int mhi_runtime_idle(struct device *dev);
|
|
int init_ev_rings(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
enum MHI_TYPE_EVENT_RING type);
|
|
void mhi_reset_ev_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
int index);
|
|
void init_event_ctxt_array(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int create_local_ev_ctxt(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
enum MHI_STATE mhi_get_m_state(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
void process_m1_transition(struct work_struct *work);
|
|
int set_mhi_base_state(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
void mhi_set_m_state(struct mhi_device_ctxt *mhi_dev_ctxt,
|
|
enum MHI_STATE new_state);
|
|
const char *state_transition_str(enum STATE_TRANSITION state);
|
|
void mhi_ev_task(unsigned long data);
|
|
void process_event_ring(struct work_struct *work);
|
|
int process_m0_transition(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
int process_m3_transition(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
enum MHI_PM_STATE __must_check mhi_tryset_pm_state(struct mhi_device_ctxt *,
|
|
enum MHI_PM_STATE);
|
|
void mhi_reset_chan(struct mhi_device_ctxt *mhi_dev_ctxt, int chan);
|
|
void free_tre_ring(struct mhi_device_ctxt *mhi_dev_ctxt, int chan);
|
|
void process_disable_transition(enum MHI_PM_STATE transition_state,
|
|
struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
bool mhi_in_sys_err(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
void bhi_exit(struct mhi_device_ctxt *mhi_dev_ctxt);
|
|
|
|
#endif
|