OSDN Git Service

msm: ipa3: add ipa_mhi to ipa_clients
authorAmir Levy <alevy@codeaurora.org>
Tue, 24 May 2016 17:19:07 +0000 (20:19 +0300)
committerKyle Yan <kyan@codeaurora.org>
Wed, 25 May 2016 00:57:55 +0000 (17:57 -0700)
As part of of IPA driver refactoring a separation has been made
between IPA core driver and the IPA clients.
MHI specific code in ipa_mhi.c has been transferred to a new file
called ipa_mhi_client.c.
IPA clients drivers are the interface between IPA core driver
and external drivers. Specifically, ipa_mhi driver is the
interface between the MHI driver and IPA core.

CRs-fixed: 989505
Change-Id: Iebcde6d233ff8580aa83b1885f1e8a01644dd1f4
Signed-off-by: Amir Levy <alevy@codeaurora.org>
30 files changed:
drivers/platform/msm/ipa/ipa_api.c
drivers/platform/msm/ipa/ipa_api.h
drivers/platform/msm/ipa/ipa_clients/Makefile
drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c [new file with mode: 0644]
drivers/platform/msm/ipa/ipa_common_i.h
drivers/platform/msm/ipa/ipa_v2/ipa_i.h
drivers/platform/msm/ipa/ipa_v2/ipa_mhi.c
drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c
drivers/platform/msm/ipa/ipa_v2/ipa_uc.c
drivers/platform/msm/ipa/ipa_v2/ipa_uc_mhi.c
drivers/platform/msm/ipa/ipa_v2/ipa_uc_wdi.c
drivers/platform/msm/ipa/ipa_v2/ipa_utils.c
drivers/platform/msm/ipa/ipa_v3/ipa.c
drivers/platform/msm/ipa/ipa_v3/ipa_client.c
drivers/platform/msm/ipa/ipa_v3/ipa_dma.c
drivers/platform/msm/ipa/ipa_v3/ipa_dp.c
drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c
drivers/platform/msm/ipa/ipa_v3/ipa_i.h
drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c
drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c
drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
drivers/platform/msm/ipa/ipa_v3/ipa_uc.c
drivers/platform/msm/ipa/ipa_v3/ipa_uc_mhi.c
drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c
drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
drivers/platform/msm/mhi_dev/mhi.c
drivers/platform/msm/mhi_dev/mhi_sm.c
include/linux/ipa.h
include/linux/ipa_mhi.h [new file with mode: 0644]

index e16ca74..72249ca 100644 (file)
                } \
        } while (0)
 
+#define IPA_API_DISPATCH_RETURN_BOOL(api, p...) \
+       do { \
+               if (!ipa_api_ctrl) { \
+                       pr_err("IPA HW is not supported on this target\n"); \
+                       ret = false; \
+               } \
+               else { \
+                       if (ipa_api_ctrl->api) { \
+                               ret = ipa_api_ctrl->api(p); \
+                       } else { \
+                               pr_err("%s not implemented for IPA ver %d\n", \
+                                               __func__, ipa_api_hw_type); \
+                               WARN_ON(1); \
+                               ret = false; \
+                       } \
+               } \
+       } while (0)
+
 static enum ipa_hw_type ipa_api_hw_type;
 static struct ipa_api_controller *ipa_api_ctrl;
 
@@ -1778,63 +1796,23 @@ void ipa_dma_destroy(void)
 }
 EXPORT_SYMBOL(ipa_dma_destroy);
 
-/**
- * ipa_mhi_init() - Initialize IPA MHI driver
- * @params: initialization params
- *
- * This function is called by MHI client driver on boot to initialize IPA MHI
- * Driver. When this function returns device can move to READY state.
- * This function is doing the following:
- *     - Initialize MHI IPA internal data structures
- *     - Create IPA RM resources
- *     - Initialize debugfs
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa_mhi_init(struct ipa_mhi_init_params *params)
+int ipa_mhi_init_engine(struct ipa_mhi_init_engine *params)
 {
        int ret;
 
-       IPA_API_DISPATCH_RETURN(ipa_mhi_init, params);
+       IPA_API_DISPATCH_RETURN(ipa_mhi_init_engine, params);
 
        return ret;
 }
-EXPORT_SYMBOL(ipa_mhi_init);
+EXPORT_SYMBOL(ipa_mhi_init_engine);
 
 /**
- * ipa_mhi_start() - Start IPA MHI engine
- * @params: pcie addresses for MHI
- *
- * This function is called by MHI client driver on MHI engine start for
- * handling MHI accelerated channels. This function is called after
- * ipa_mhi_init() was called and can be called after MHI reset to restart MHI
- * engine. When this function returns device can move to M0 state.
- * This function is doing the following:
- *     - Send command to uC for initialization of MHI engine
- *     - Add dependencies to IPA RM
- *     - Request MHI_PROD in IPA RM
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa_mhi_start(struct ipa_mhi_start_params *params)
-{
-       int ret;
-
-       IPA_API_DISPATCH_RETURN(ipa_mhi_start, params);
-
-       return ret;
-}
-EXPORT_SYMBOL(ipa_mhi_start);
-
-/**
- * ipa_mhi_connect_pipe() - Connect pipe to IPA and start corresponding
+ * ipa_connect_mhi_pipe() - Connect pipe to IPA and start corresponding
  * MHI channel
  * @in: connect parameters
  * @clnt_hdl: [out] client handle for this pipe
  *
- * This function is called by MHI client driver on MHI channel start.
+ * This function is called by IPA MHI client driver on MHI channel start.
  * This function is called after MHI engine was started.
  * This function is doing the following:
  *     - Send command to uC to start corresponding MHI channel
@@ -1843,23 +1821,24 @@ EXPORT_SYMBOL(ipa_mhi_start);
  * Return codes: 0       : success
  *              negative : error
  */
-int ipa_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl)
+int ipa_connect_mhi_pipe(struct ipa_mhi_connect_params_internal *in,
+               u32 *clnt_hdl)
 {
        int ret;
 
-       IPA_API_DISPATCH_RETURN(ipa_mhi_connect_pipe, in, clnt_hdl);
+       IPA_API_DISPATCH_RETURN(ipa_connect_mhi_pipe, in, clnt_hdl);
 
        return ret;
 }
-EXPORT_SYMBOL(ipa_mhi_connect_pipe);
+EXPORT_SYMBOL(ipa_connect_mhi_pipe);
 
 /**
- * ipa_mhi_disconnect_pipe() - Disconnect pipe from IPA and reset corresponding
+ * ipa_disconnect_mhi_pipe() - Disconnect pipe from IPA and reset corresponding
  * MHI channel
  * @in: connect parameters
  * @clnt_hdl: [out] client handle for this pipe
  *
- * This function is called by MHI client driver on MHI channel reset.
+ * This function is called by IPA MHI client driver on MHI channel reset.
  * This function is called after MHI channel was started.
  * This function is doing the following:
  *     - Send command to uC to reset corresponding MHI channel
@@ -1868,81 +1847,218 @@ EXPORT_SYMBOL(ipa_mhi_connect_pipe);
  * Return codes: 0       : success
  *              negative : error
  */
-int ipa_mhi_disconnect_pipe(u32 clnt_hdl)
+int ipa_disconnect_mhi_pipe(u32 clnt_hdl)
 {
        int ret;
 
-       IPA_API_DISPATCH_RETURN(ipa_mhi_disconnect_pipe, clnt_hdl);
+       IPA_API_DISPATCH_RETURN(ipa_disconnect_mhi_pipe, clnt_hdl);
 
        return ret;
 }
-EXPORT_SYMBOL(ipa_mhi_disconnect_pipe);
+EXPORT_SYMBOL(ipa_disconnect_mhi_pipe);
 
-/**
- * ipa_mhi_suspend() - Suspend MHI accelerated channels
- * @force:
- *     false: in case of data pending in IPA, MHI channels will not be
- *             suspended and function will fail.
- *     true:  in case of data pending in IPA, make sure no further access from
- *             IPA to PCIe is possible. In this case suspend cannot fail.
- *
- * This function is called by MHI client driver on MHI suspend.
- * This function is called after MHI channel was started.
- * When this function returns device can move to M1/M2/M3/D3cold state.
- * This function is doing the following:
- *     - Send command to uC to suspend corresponding MHI channel
- *     - Make sure no further access is possible from IPA to PCIe
- *     - Release MHI_PROD in IPA RM
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa_mhi_suspend(bool force)
+bool ipa_mhi_stop_gsi_channel(enum ipa_client_type client)
+{
+       bool ret;
+
+       IPA_API_DISPATCH_RETURN_BOOL(ipa_mhi_stop_gsi_channel, client);
+
+       return ret;
+}
+
+int ipa_uc_mhi_reset_channel(int channelHandle)
 {
        int ret;
 
-       IPA_API_DISPATCH_RETURN(ipa_mhi_suspend, force);
+       IPA_API_DISPATCH_RETURN(ipa_uc_mhi_reset_channel, channelHandle);
 
        return ret;
 }
-EXPORT_SYMBOL(ipa_mhi_suspend);
 
-/**
- * ipa_mhi_resume() - Resume MHI accelerated channels
- *
- * This function is called by MHI client driver on MHI resume.
- * This function is called after MHI channel was suspended.
- * When this function returns device can move to M0 state.
- * This function is doing the following:
- *     - Send command to uC to resume corresponding MHI channel
- *     - Request MHI_PROD in IPA RM
- *     - Resume data to IPA
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa_mhi_resume(void)
+bool ipa_mhi_sps_channel_empty(enum ipa_client_type client)
+{
+       bool ret;
+
+       IPA_API_DISPATCH_RETURN_BOOL(ipa_mhi_sps_channel_empty, client);
+
+       return ret;
+}
+
+int ipa_qmi_enable_force_clear_datapath_send(
+       struct ipa_enable_force_clear_datapath_req_msg_v01 *req)
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_qmi_enable_force_clear_datapath_send, req);
+
+       return ret;
+}
+
+int ipa_qmi_disable_force_clear_datapath_send(
+       struct ipa_disable_force_clear_datapath_req_msg_v01 *req)
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_qmi_disable_force_clear_datapath_send, req);
+
+       return ret;
+}
+
+int ipa_generate_tag_process(void)
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_generate_tag_process);
+
+       return ret;
+}
+
+int ipa_disable_sps_pipe(enum ipa_client_type client)
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_disable_sps_pipe, client);
+
+       return ret;
+}
+
+int ipa_mhi_reset_channel_internal(enum ipa_client_type client)
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_mhi_reset_channel_internal, client);
+
+       return ret;
+}
+
+int ipa_mhi_start_channel_internal(enum ipa_client_type client)
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_mhi_start_channel_internal, client);
+
+       return ret;
+}
+
+void ipa_get_holb(int ep_idx, struct ipa_ep_cfg_holb *holb)
+{
+       IPA_API_DISPATCH(ipa_get_holb, ep_idx, holb);
+}
+
+void ipa_set_tag_process_before_gating(bool val)
+{
+       IPA_API_DISPATCH(ipa_set_tag_process_before_gating, val);
+}
+
+int ipa_mhi_query_ch_info(enum ipa_client_type client,
+               struct gsi_chan_info *ch_info)
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_mhi_query_ch_info, client, ch_info);
+
+       return ret;
+}
+
+int ipa_uc_mhi_suspend_channel(int channelHandle)
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_uc_mhi_suspend_channel, channelHandle);
+
+       return ret;
+}
+
+int ipa_uc_mhi_stop_event_update_channel(int channelHandle)
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_uc_mhi_stop_event_update_channel,
+                       channelHandle);
+
+       return ret;
+}
+
+bool ipa_has_open_aggr_frame(enum ipa_client_type client)
+{
+       bool ret;
+
+       IPA_API_DISPATCH_RETURN_BOOL(ipa_has_open_aggr_frame, client);
+
+       return ret;
+}
+
+int ipa_mhi_resume_channels_internal(enum ipa_client_type client,
+               bool LPTransitionRejected, bool brstmode_enabled,
+               union __packed gsi_channel_scratch ch_scratch, u8 index)
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_mhi_resume_channels_internal, client,
+                       LPTransitionRejected, brstmode_enabled, ch_scratch,
+                       index);
+
+       return ret;
+}
+
+int ipa_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t *cmd)
 {
        int ret;
 
-       IPA_API_DISPATCH_RETURN(ipa_mhi_resume);
+       IPA_API_DISPATCH_RETURN(ipa_uc_mhi_send_dl_ul_sync_info,
+                       cmd);
+
+       return ret;
+}
+
+int ipa_mhi_destroy_channel(enum ipa_client_type client)
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_mhi_destroy_channel, client);
+
+       return ret;
+}
+
+int ipa_uc_mhi_init(void (*ready_cb)(void),
+               void (*wakeup_request_cb)(void))
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_uc_mhi_init, ready_cb, wakeup_request_cb);
+
+       return ret;
+}
+
+void ipa_uc_mhi_cleanup(void)
+{
+       IPA_API_DISPATCH(ipa_uc_mhi_cleanup);
+}
+
+int ipa_uc_mhi_print_stats(char *dbg_buff, int size)
+{
+       int ret;
+
+       IPA_API_DISPATCH_RETURN(ipa_uc_mhi_print_stats, dbg_buff, size);
 
        return ret;
 }
-EXPORT_SYMBOL(ipa_mhi_resume);
 
 /**
- * ipa_mhi_destroy() - Destroy MHI IPA
+ * ipa_uc_state_check() - Check the status of the uC interface
  *
- * This function is called by MHI client driver on MHI reset to destroy all IPA
- * MHI resources.
+ * Return value: 0 if the uC is loaded, interface is initialized
+ *               and there was no recent failure in one of the commands.
+ *               A negative value is returned otherwise.
  */
-void ipa_mhi_destroy(void)
+int ipa_uc_state_check(void)
 {
-       IPA_API_DISPATCH(ipa_mhi_destroy);
+       int ret;
 
+       IPA_API_DISPATCH_RETURN(ipa_uc_state_check);
+
+       return ret;
 }
-EXPORT_SYMBOL(ipa_mhi_destroy);
 
 int ipa_write_qmap_id(struct ipa_ioc_write_qmapid *param_in)
 {
index 054b365..e3fa414 100644 (file)
@@ -10,6 +10,7 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/ipa_mhi.h>
 #include "ipa_common_i.h"
 
 #ifndef _IPA_API_H_
@@ -214,20 +215,68 @@ struct ipa_api_controller {
 
        void (*ipa_dma_destroy)(void);
 
-       int (*ipa_mhi_init)(struct ipa_mhi_init_params *params);
+       bool (*ipa_has_open_aggr_frame)(enum ipa_client_type client);
 
-       int (*ipa_mhi_start)(struct ipa_mhi_start_params *params);
+       int (*ipa_generate_tag_process)(void);
 
-       int (*ipa_mhi_connect_pipe)(struct ipa_mhi_connect_params *in,
+       int (*ipa_disable_sps_pipe)(enum ipa_client_type client);
+
+       void (*ipa_set_tag_process_before_gating)(bool val);
+
+       int (*ipa_mhi_init_engine)(struct ipa_mhi_init_engine *params);
+
+       int (*ipa_connect_mhi_pipe)(struct ipa_mhi_connect_params_internal *in,
                u32 *clnt_hdl);
 
-       int (*ipa_mhi_disconnect_pipe)(u32 clnt_hdl);
+       int (*ipa_disconnect_mhi_pipe)(u32 clnt_hdl);
+
+       bool (*ipa_mhi_stop_gsi_channel)(enum ipa_client_type client);
+
+       int (*ipa_qmi_disable_force_clear)(u32 request_id);
+
+       int (*ipa_qmi_enable_force_clear_datapath_send)(
+               struct ipa_enable_force_clear_datapath_req_msg_v01 *req);
+
+       int (*ipa_qmi_disable_force_clear_datapath_send)(
+               struct ipa_disable_force_clear_datapath_req_msg_v01 *req);
+
+       bool (*ipa_mhi_sps_channel_empty)(enum ipa_client_type client);
+
+       int (*ipa_mhi_reset_channel_internal)(enum ipa_client_type client);
+
+       int (*ipa_mhi_start_channel_internal)(enum ipa_client_type client);
+
+       void (*ipa_get_holb)(int ep_idx, struct ipa_ep_cfg_holb *holb);
+
+       int (*ipa_mhi_query_ch_info)(enum ipa_client_type client,
+                       struct gsi_chan_info *ch_info);
+
+       int (*ipa_mhi_resume_channels_internal)(
+                       enum ipa_client_type client,
+                       bool LPTransitionRejected,
+                       bool brstmode_enabled,
+                       union __packed gsi_channel_scratch ch_scratch,
+                       u8 index);
+
+       int  (*ipa_mhi_destroy_channel)(enum ipa_client_type client);
+
+       int (*ipa_uc_mhi_send_dl_ul_sync_info)
+               (union IpaHwMhiDlUlSyncCmdData_t *cmd);
+
+       int (*ipa_uc_mhi_init)
+               (void (*ready_cb)(void), void (*wakeup_request_cb)(void));
+
+       void (*ipa_uc_mhi_cleanup)(void);
+
+       int (*ipa_uc_mhi_print_stats)(char *dbg_buff, int size);
+
+       int (*ipa_uc_mhi_reset_channel)(int channelHandle);
 
-       int (*ipa_mhi_suspend)(bool force);
+       int (*ipa_uc_mhi_suspend_channel)(int channelHandle);
 
-       int (*ipa_mhi_resume)(void);
+       int (*ipa_uc_mhi_stop_event_update_channel)(int channelHandle);
 
-       void (*ipa_mhi_destroy)(void);
+       int (*ipa_uc_state_check)(void);
 
        int (*ipa_write_qmap_id)(struct ipa_ioc_write_qmapid *param_in);
 
index 26b45a6..aac473f 100644 (file)
@@ -1,2 +1,2 @@
-obj-$(CONFIG_IPA3) += ipa_usb.o odu_bridge.o
-obj-$(CONFIG_IPA) += odu_bridge.o
\ No newline at end of file
+obj-$(CONFIG_IPA3) += ipa_usb.o odu_bridge.o ipa_mhi_client.o
+obj-$(CONFIG_IPA) += odu_bridge.o ipa_mhi_client.o
\ No newline at end of file
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c
new file mode 100644 (file)
index 0000000..b5f84bd
--- /dev/null
@@ -0,0 +1,2589 @@
+/* Copyright (c) 2015, 2016 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.
+ */
+#include <linux/debugfs.h>
+#include <linux/export.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/ipa.h>
+#include <linux/msm_gsi.h>
+#include <linux/ipa_qmi_service_v01.h>
+#include <linux/ipa_mhi.h>
+#include "../ipa_common_i.h"
+
+#define IPA_MHI_DRV_NAME "ipa_mhi_client"
+#define IPA_MHI_DBG(fmt, args...) \
+       pr_debug(IPA_MHI_DRV_NAME " %s:%d " fmt, \
+                __func__, __LINE__, ## args)
+#define IPA_MHI_ERR(fmt, args...) \
+       pr_err(IPA_MHI_DRV_NAME " %s:%d " fmt, __func__, __LINE__, ## args)
+#define IPA_MHI_FUNC_ENTRY() \
+       IPA_MHI_DBG("ENTRY\n")
+#define IPA_MHI_FUNC_EXIT() \
+       IPA_MHI_DBG("EXIT\n")
+
+#define IPA_MHI_RM_TIMEOUT_MSEC 10000
+#define IPA_MHI_CH_EMPTY_TIMEOUT_MSEC 10
+
+#define IPA_MHI_SUSPEND_SLEEP_MIN 900
+#define IPA_MHI_SUSPEND_SLEEP_MAX 1100
+
+#define IPA_MHI_MAX_UL_CHANNELS 1
+#define IPA_MHI_MAX_DL_CHANNELS 1
+
+#define IPA_MHI_GSI_ER_START 10
+#define IPA_MHI_GSI_ER_END 16
+
+#if (IPA_MHI_MAX_UL_CHANNELS + IPA_MHI_MAX_DL_CHANNELS) > \
+       (IPA_MHI_GSI_ER_END - IPA_MHI_GSI_ER_START)
+#error not enought event rings for MHI
+#endif
+
+/* bit #40 in address should be asserted for MHI transfers over pcie */
+#define IPA_MHI_CLIENT_HOST_ADDR_COND(addr) \
+       ((ipa_mhi_client_ctx->assert_bit40)?(IPA_MHI_HOST_ADDR(addr)):(addr))
+
+enum ipa_mhi_rm_state {
+       IPA_MHI_RM_STATE_RELEASED,
+       IPA_MHI_RM_STATE_REQUESTED,
+       IPA_MHI_RM_STATE_GRANTED,
+       IPA_MHI_RM_STATE_MAX
+};
+
+enum ipa_mhi_state {
+       IPA_MHI_STATE_INITIALIZED,
+       IPA_MHI_STATE_READY,
+       IPA_MHI_STATE_STARTED,
+       IPA_MHI_STATE_SUSPEND_IN_PROGRESS,
+       IPA_MHI_STATE_SUSPENDED,
+       IPA_MHI_STATE_RESUME_IN_PROGRESS,
+       IPA_MHI_STATE_MAX
+};
+
+static char *ipa_mhi_state_str[] = {
+       __stringify(IPA_MHI_STATE_INITIALIZED),
+       __stringify(IPA_MHI_STATE_READY),
+       __stringify(IPA_MHI_STATE_STARTED),
+       __stringify(IPA_MHI_STATE_SUSPEND_IN_PROGRESS),
+       __stringify(IPA_MHI_STATE_SUSPENDED),
+       __stringify(IPA_MHI_STATE_RESUME_IN_PROGRESS),
+};
+
+#define MHI_STATE_STR(state) \
+       (((state) >= 0 && (state) < IPA_MHI_STATE_MAX) ? \
+               ipa_mhi_state_str[(state)] : \
+               "INVALID")
+
+enum ipa_mhi_dma_dir {
+       IPA_MHI_DMA_TO_HOST,
+       IPA_MHI_DMA_FROM_HOST,
+};
+
+/**
+ * struct ipa_mhi_channel_ctx - MHI Channel context
+ * @valid: entry is valid
+ * @id: MHI channel ID
+ * @hdl: channel handle for uC
+ * @client: IPA Client
+ * @state: Channel state
+ */
+struct ipa_mhi_channel_ctx {
+       bool valid;
+       u8 id;
+       u8 index;
+       enum ipa_client_type client;
+       enum ipa_hw_mhi_channel_states state;
+       bool stop_in_proc;
+       struct gsi_chan_info ch_info;
+       u64 channel_context_addr;
+       struct ipa_mhi_ch_ctx ch_ctx_host;
+       u64 event_context_addr;
+       struct ipa_mhi_ev_ctx ev_ctx_host;
+       bool brstmode_enabled;
+       union __packed gsi_channel_scratch ch_scratch;
+       unsigned long cached_gsi_evt_ring_hdl;
+};
+
+struct ipa_mhi_client_ctx {
+       enum ipa_mhi_state state;
+       spinlock_t state_lock;
+       mhi_client_cb cb_notify;
+       void *cb_priv;
+       struct completion rm_prod_granted_comp;
+       enum ipa_mhi_rm_state rm_cons_state;
+       struct completion rm_cons_comp;
+       bool trigger_wakeup;
+       bool wakeup_notified;
+       struct workqueue_struct *wq;
+       struct ipa_mhi_channel_ctx ul_channels[IPA_MHI_MAX_UL_CHANNELS];
+       struct ipa_mhi_channel_ctx dl_channels[IPA_MHI_MAX_DL_CHANNELS];
+       u32 total_channels;
+       struct ipa_mhi_msi_info msi;
+       u32 mmio_addr;
+       u32 first_ch_idx;
+       u32 first_er_idx;
+       u32 host_ctrl_addr;
+       u32 host_data_addr;
+       u64 channel_context_array_addr;
+       u64 event_context_array_addr;
+       u32 qmi_req_id;
+       u32 use_ipadma;
+       bool assert_bit40;
+       bool test_mode;
+};
+
+static struct ipa_mhi_client_ctx *ipa_mhi_client_ctx;
+
+#ifdef CONFIG_DEBUG_FS
+#define IPA_MHI_MAX_MSG_LEN 512
+static char dbg_buff[IPA_MHI_MAX_MSG_LEN];
+static struct dentry *dent;
+
+static char *ipa_mhi_channel_state_str[] = {
+       __stringify(IPA_HW_MHI_CHANNEL_STATE_DISABLE),
+       __stringify(IPA_HW_MHI_CHANNEL_STATE_ENABLE),
+       __stringify(IPA_HW_MHI_CHANNEL_STATE_RUN),
+       __stringify(IPA_HW_MHI_CHANNEL_STATE_SUSPEND),
+       __stringify(IPA_HW_MHI_CHANNEL_STATE_STOP),
+       __stringify(IPA_HW_MHI_CHANNEL_STATE_ERROR),
+};
+
+#define MHI_CH_STATE_STR(state) \
+       (((state) >= 0 && (state) <= IPA_HW_MHI_CHANNEL_STATE_ERROR) ? \
+       ipa_mhi_channel_state_str[(state)] : \
+       "INVALID")
+
+static int ipa_mhi_read_write_host(enum ipa_mhi_dma_dir dir, void *dev_addr,
+       u64 host_addr, int size)
+{
+       struct ipa_mem_buffer mem;
+       int res;
+       struct device *pdev;
+
+       IPA_MHI_FUNC_ENTRY();
+
+       if (ipa_mhi_client_ctx->use_ipadma) {
+               pdev = ipa_get_dma_dev();
+               host_addr = IPA_MHI_CLIENT_HOST_ADDR_COND(host_addr);
+
+               mem.size = size;
+               mem.base = dma_alloc_coherent(pdev, mem.size,
+                       &mem.phys_base, GFP_KERNEL);
+               if (!mem.base) {
+                       IPA_MHI_ERR(
+                               "dma_alloc_coherent failed, DMA buff size %d\n"
+                                       , mem.size);
+                       return -ENOMEM;
+               }
+
+               if (dir == IPA_MHI_DMA_FROM_HOST) {
+                       res = ipa_dma_sync_memcpy(mem.phys_base, host_addr,
+                               size);
+                       if (res) {
+                               IPA_MHI_ERR(
+                                       "ipa_dma_sync_memcpy from host fail%d\n"
+                                       , res);
+                               goto fail_memcopy;
+                       }
+                       memcpy(dev_addr, mem.base, size);
+               } else {
+                       memcpy(mem.base, dev_addr, size);
+                       res = ipa_dma_sync_memcpy(host_addr, mem.phys_base,
+                               size);
+                       if (res) {
+                               IPA_MHI_ERR(
+                                       "ipa_dma_sync_memcpy to host fail %d\n"
+                                       , res);
+                               goto fail_memcopy;
+                       }
+               }
+               dma_free_coherent(pdev, mem.size, mem.base,
+                       mem.phys_base);
+       } else {
+               void *host_ptr;
+
+               if (!ipa_mhi_client_ctx->test_mode)
+                       host_ptr = ioremap(host_addr, size);
+               else
+                       host_ptr = phys_to_virt(host_addr);
+               if (!host_ptr) {
+                       IPA_MHI_ERR("ioremap failed for 0x%llx\n", host_addr);
+                       return -EFAULT;
+               }
+               if (dir == IPA_MHI_DMA_FROM_HOST)
+                       memcpy(dev_addr, host_ptr, size);
+               else
+                       memcpy(host_ptr, dev_addr, size);
+               if (!ipa_mhi_client_ctx->test_mode)
+                       iounmap(host_ptr);
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+
+fail_memcopy:
+       dma_free_coherent(ipa_get_dma_dev(), mem.size, mem.base,
+                       mem.phys_base);
+       return res;
+}
+
+static int ipa_mhi_print_channel_info(struct ipa_mhi_channel_ctx *channel,
+       char *buff, int len)
+{
+       int nbytes = 0;
+
+       if (channel->valid) {
+               nbytes += scnprintf(&buff[nbytes],
+                       len - nbytes,
+                       "channel idx=%d ch_id=%d client=%d state=%s\n",
+                       channel->index, channel->id, channel->client,
+                       MHI_CH_STATE_STR(channel->state));
+
+               nbytes += scnprintf(&buff[nbytes],
+                       len - nbytes,
+                       "       ch_ctx=%llx\n",
+                       channel->channel_context_addr);
+
+               nbytes += scnprintf(&buff[nbytes],
+                       len - nbytes,
+                       "       gsi_evt_ring_hdl=%ld ev_ctx=%llx\n",
+                       channel->cached_gsi_evt_ring_hdl,
+                       channel->event_context_addr);
+       }
+       return nbytes;
+}
+
+static int ipa_mhi_print_host_channel_ctx_info(
+               struct ipa_mhi_channel_ctx *channel, char *buff, int len)
+{
+       int res, nbytes = 0;
+       struct ipa_mhi_ch_ctx ch_ctx_host;
+
+       memset(&ch_ctx_host, 0, sizeof(ch_ctx_host));
+
+       /* reading ch context from host */
+       res = ipa_mhi_read_write_host(IPA_MHI_DMA_FROM_HOST,
+               &ch_ctx_host, channel->channel_context_addr,
+               sizeof(ch_ctx_host));
+       if (res) {
+               nbytes += scnprintf(&buff[nbytes], len - nbytes,
+                       "Failed to read from host %d\n", res);
+               return nbytes;
+       }
+
+       nbytes += scnprintf(&buff[nbytes], len - nbytes,
+               "ch_id: %d\n", channel->id);
+       nbytes += scnprintf(&buff[nbytes], len - nbytes,
+               "chstate: 0x%x\n", ch_ctx_host.chstate);
+       nbytes += scnprintf(&buff[nbytes], len - nbytes,
+               "brstmode: 0x%x\n", ch_ctx_host.brstmode);
+       nbytes += scnprintf(&buff[nbytes], len - nbytes,
+               "chtype: 0x%x\n", ch_ctx_host.chtype);
+       nbytes += scnprintf(&buff[nbytes], len - nbytes,
+               "erindex: 0x%x\n", ch_ctx_host.erindex);
+       nbytes += scnprintf(&buff[nbytes], len - nbytes,
+               "rbase: 0x%llx\n", ch_ctx_host.rbase);
+       nbytes += scnprintf(&buff[nbytes], len - nbytes,
+               "rlen: 0x%llx\n", ch_ctx_host.rlen);
+       nbytes += scnprintf(&buff[nbytes], len - nbytes,
+               "rp: 0x%llx\n", ch_ctx_host.rp);
+       nbytes += scnprintf(&buff[nbytes], len - nbytes,
+               "wp: 0x%llx\n", ch_ctx_host.wp);
+
+       return nbytes;
+}
+
+static ssize_t ipa_mhi_debugfs_stats(struct file *file,
+       char __user *ubuf,
+       size_t count,
+       loff_t *ppos)
+{
+       int nbytes = 0;
+       int i;
+       struct ipa_mhi_channel_ctx *channel;
+
+       nbytes += scnprintf(&dbg_buff[nbytes],
+               IPA_MHI_MAX_MSG_LEN - nbytes,
+               "IPA MHI state: %s\n",
+               MHI_STATE_STR(ipa_mhi_client_ctx->state));
+
+       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
+               channel = &ipa_mhi_client_ctx->ul_channels[i];
+               nbytes += ipa_mhi_print_channel_info(channel,
+                       &dbg_buff[nbytes], IPA_MHI_MAX_MSG_LEN - nbytes);
+       }
+
+       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
+               channel = &ipa_mhi_client_ctx->dl_channels[i];
+               nbytes += ipa_mhi_print_channel_info(channel,
+                       &dbg_buff[nbytes], IPA_MHI_MAX_MSG_LEN - nbytes);
+       }
+
+       return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t ipa_mhi_debugfs_uc_stats(struct file *file,
+       char __user *ubuf,
+       size_t count,
+       loff_t *ppos)
+{
+       int nbytes = 0;
+
+       nbytes += ipa_uc_mhi_print_stats(dbg_buff, IPA_MHI_MAX_MSG_LEN);
+       return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+static ssize_t ipa_mhi_debugfs_dump_host_ch_ctx_arr(struct file *file,
+       char __user *ubuf,
+       size_t count,
+       loff_t *ppos)
+{
+       int i, nbytes = 0;
+       struct ipa_mhi_channel_ctx *channel;
+
+       if (ipa_mhi_client_ctx->state == IPA_MHI_STATE_INITIALIZED ||
+           ipa_mhi_client_ctx->state == IPA_MHI_STATE_READY) {
+               nbytes += scnprintf(&dbg_buff[nbytes],
+               IPA_MHI_MAX_MSG_LEN - nbytes,
+                       "Cannot dump host channel context ");
+               nbytes += scnprintf(&dbg_buff[nbytes],
+                               IPA_MHI_MAX_MSG_LEN - nbytes,
+                               "before IPA MHI was STARTED\n");
+               return simple_read_from_buffer(ubuf, count, ppos,
+                       dbg_buff, nbytes);
+       }
+       if (ipa_mhi_client_ctx->state == IPA_MHI_STATE_SUSPENDED) {
+               nbytes += scnprintf(&dbg_buff[nbytes],
+                       IPA_MHI_MAX_MSG_LEN - nbytes,
+                       "IPA MHI is suspended, cannot dump channel ctx array");
+               nbytes += scnprintf(&dbg_buff[nbytes],
+                       IPA_MHI_MAX_MSG_LEN - nbytes,
+                       " from host -PCIe can be in D3 state\n");
+               return simple_read_from_buffer(ubuf, count, ppos,
+                       dbg_buff, nbytes);
+       }
+
+       nbytes += scnprintf(&dbg_buff[nbytes],
+                       IPA_MHI_MAX_MSG_LEN - nbytes,
+                       "channel contex array - dump from host\n");
+       nbytes += scnprintf(&dbg_buff[nbytes],
+                       IPA_MHI_MAX_MSG_LEN - nbytes,
+                       "***** UL channels *******\n");
+
+       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
+               channel = &ipa_mhi_client_ctx->ul_channels[i];
+               if (!channel->valid)
+                       continue;
+               nbytes += ipa_mhi_print_host_channel_ctx_info(channel,
+                       &dbg_buff[nbytes],
+                       IPA_MHI_MAX_MSG_LEN - nbytes);
+       }
+
+       nbytes += scnprintf(&dbg_buff[nbytes],
+                       IPA_MHI_MAX_MSG_LEN - nbytes,
+                       "\n***** DL channels *******\n");
+
+       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
+               channel = &ipa_mhi_client_ctx->dl_channels[i];
+               if (!channel->valid)
+                       continue;
+               nbytes += ipa_mhi_print_host_channel_ctx_info(channel,
+                       &dbg_buff[nbytes], IPA_MHI_MAX_MSG_LEN - nbytes);
+       }
+
+       return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+}
+
+const struct file_operations ipa_mhi_stats_ops = {
+       .read = ipa_mhi_debugfs_stats,
+};
+
+const struct file_operations ipa_mhi_uc_stats_ops = {
+       .read = ipa_mhi_debugfs_uc_stats,
+};
+
+const struct file_operations ipa_mhi_dump_host_ch_ctx_ops = {
+       .read = ipa_mhi_debugfs_dump_host_ch_ctx_arr,
+};
+
+
+static void ipa_mhi_debugfs_init(void)
+{
+       const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
+       const mode_t read_write_mode = S_IRUSR | S_IRGRP | S_IROTH |
+               S_IWUSR | S_IWGRP;
+       struct dentry *file;
+
+       IPA_MHI_FUNC_ENTRY();
+
+       dent = debugfs_create_dir("ipa_mhi", 0);
+       if (IS_ERR(dent)) {
+               IPA_MHI_ERR("fail to create folder ipa_mhi\n");
+               return;
+       }
+
+       file = debugfs_create_file("stats", read_only_mode, dent,
+               0, &ipa_mhi_stats_ops);
+       if (!file || IS_ERR(file)) {
+               IPA_MHI_ERR("fail to create file stats\n");
+               goto fail;
+       }
+
+       file = debugfs_create_file("uc_stats", read_only_mode, dent,
+               0, &ipa_mhi_uc_stats_ops);
+       if (!file || IS_ERR(file)) {
+               IPA_MHI_ERR("fail to create file uc_stats\n");
+               goto fail;
+       }
+
+       file = debugfs_create_u32("use_ipadma", read_write_mode, dent,
+               &ipa_mhi_client_ctx->use_ipadma);
+       if (!file || IS_ERR(file)) {
+               IPA_MHI_ERR("fail to create file use_ipadma\n");
+               goto fail;
+       }
+
+       file = debugfs_create_file("dump_host_channel_ctx_array",
+               read_only_mode, dent, 0, &ipa_mhi_dump_host_ch_ctx_ops);
+       if (!file || IS_ERR(file)) {
+               IPA_MHI_ERR("fail to create file dump_host_channel_ctx_arr\n");
+               goto fail;
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return;
+fail:
+       debugfs_remove_recursive(dent);
+}
+
+#else
+static void ipa_mhi_debugfs_init(void) {}
+static void ipa_mhi_debugfs_destroy(void) {}
+#endif /* CONFIG_DEBUG_FS */
+
+static union IpaHwMhiDlUlSyncCmdData_t ipa_cached_dl_ul_sync_info;
+
+static void ipa_mhi_wq_notify_wakeup(struct work_struct *work);
+static DECLARE_WORK(ipa_mhi_notify_wakeup_work, ipa_mhi_wq_notify_wakeup);
+
+static void ipa_mhi_wq_notify_ready(struct work_struct *work);
+static DECLARE_WORK(ipa_mhi_notify_ready_work, ipa_mhi_wq_notify_ready);
+
+/**
+ * ipa_mhi_notify_wakeup() - Schedule work to notify data available
+ *
+ * This function will schedule a work to notify data available event.
+ * In case this function is called more than once, only one notification will
+ * be sent to MHI client driver. No further notifications will be sent until
+ * IPA MHI state will become STARTED.
+ */
+static void ipa_mhi_notify_wakeup(void)
+{
+       IPA_MHI_FUNC_ENTRY();
+       if (ipa_mhi_client_ctx->wakeup_notified) {
+               IPA_MHI_DBG("wakeup already called\n");
+               return;
+       }
+       queue_work(ipa_mhi_client_ctx->wq, &ipa_mhi_notify_wakeup_work);
+       ipa_mhi_client_ctx->wakeup_notified = true;
+       IPA_MHI_FUNC_EXIT();
+}
+
+/**
+ * ipa_mhi_rm_cons_request() - callback function for IPA RM request resource
+ *
+ * In case IPA MHI is not suspended, MHI CONS will be granted immediately.
+ * In case IPA MHI is suspended, MHI CONS will be granted after resume.
+ */
+static int ipa_mhi_rm_cons_request(void)
+{
+       unsigned long flags;
+       int res;
+
+       IPA_MHI_FUNC_ENTRY();
+
+       IPA_MHI_DBG("%s\n", MHI_STATE_STR(ipa_mhi_client_ctx->state));
+       spin_lock_irqsave(&ipa_mhi_client_ctx->state_lock, flags);
+       ipa_mhi_client_ctx->rm_cons_state = IPA_MHI_RM_STATE_REQUESTED;
+       if (ipa_mhi_client_ctx->state == IPA_MHI_STATE_STARTED) {
+               ipa_mhi_client_ctx->rm_cons_state = IPA_MHI_RM_STATE_GRANTED;
+               res = 0;
+       } else if (ipa_mhi_client_ctx->state == IPA_MHI_STATE_SUSPENDED) {
+               ipa_mhi_notify_wakeup();
+               res = -EINPROGRESS;
+       } else if (ipa_mhi_client_ctx->state ==
+                       IPA_MHI_STATE_SUSPEND_IN_PROGRESS) {
+               /* wakeup event will be trigger after suspend finishes */
+               ipa_mhi_client_ctx->trigger_wakeup = true;
+               res = -EINPROGRESS;
+       } else {
+               res = -EINPROGRESS;
+       }
+
+       spin_unlock_irqrestore(&ipa_mhi_client_ctx->state_lock, flags);
+       IPA_MHI_DBG("EXIT with %d\n", res);
+       return res;
+}
+
+static int ipa_mhi_rm_cons_release(void)
+{
+       unsigned long flags;
+
+       IPA_MHI_FUNC_ENTRY();
+
+       spin_lock_irqsave(&ipa_mhi_client_ctx->state_lock, flags);
+       ipa_mhi_client_ctx->rm_cons_state = IPA_MHI_RM_STATE_RELEASED;
+       complete_all(&ipa_mhi_client_ctx->rm_cons_comp);
+       spin_unlock_irqrestore(&ipa_mhi_client_ctx->state_lock, flags);
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
+
+static void ipa_mhi_rm_prod_notify(void *user_data, enum ipa_rm_event event,
+       unsigned long data)
+{
+       IPA_MHI_FUNC_ENTRY();
+
+       switch (event) {
+       case IPA_RM_RESOURCE_GRANTED:
+               IPA_MHI_DBG("IPA_RM_RESOURCE_GRANTED\n");
+               complete_all(&ipa_mhi_client_ctx->rm_prod_granted_comp);
+               break;
+
+       case IPA_RM_RESOURCE_RELEASED:
+               IPA_MHI_DBG("IPA_RM_RESOURCE_RELEASED\n");
+               break;
+
+       default:
+               IPA_MHI_ERR("unexpected event %d\n", event);
+               WARN_ON(1);
+               break;
+       }
+
+       IPA_MHI_FUNC_EXIT();
+}
+
+/**
+ * ipa_mhi_wq_notify_wakeup() - Notify MHI client on data available
+ *
+ * This function is called from IPA MHI workqueue to notify
+ * MHI client driver on data available event.
+ */
+static void ipa_mhi_wq_notify_wakeup(struct work_struct *work)
+{
+       IPA_MHI_FUNC_ENTRY();
+       ipa_mhi_client_ctx->cb_notify(ipa_mhi_client_ctx->cb_priv,
+               IPA_MHI_EVENT_DATA_AVAILABLE, 0);
+       IPA_MHI_FUNC_EXIT();
+}
+
+/**
+ * ipa_mhi_wq_notify_ready() - Notify MHI client on ready
+ *
+ * This function is called from IPA MHI workqueue to notify
+ * MHI client driver on ready event when IPA uC is loaded
+ */
+static void ipa_mhi_wq_notify_ready(struct work_struct *work)
+{
+       IPA_MHI_FUNC_ENTRY();
+       ipa_mhi_client_ctx->cb_notify(ipa_mhi_client_ctx->cb_priv,
+               IPA_MHI_EVENT_READY, 0);
+       IPA_MHI_FUNC_EXIT();
+}
+
+/**
+ * ipa_mhi_notify_ready() - Schedule work to notify ready
+ *
+ * This function will schedule a work to notify ready event.
+ */
+static void ipa_mhi_notify_ready(void)
+{
+       IPA_MHI_FUNC_ENTRY();
+       queue_work(ipa_mhi_client_ctx->wq, &ipa_mhi_notify_ready_work);
+       IPA_MHI_FUNC_EXIT();
+}
+
+/**
+ * ipa_mhi_set_state() - Set new state to IPA MHI
+ * @state: new state
+ *
+ * Sets a new state to IPA MHI if possible according to IPA MHI state machine.
+ * In some state transitions a wakeup request will be triggered.
+ *
+ * Returns: 0 on success, -1 otherwise
+ */
+static int ipa_mhi_set_state(enum ipa_mhi_state new_state)
+{
+       unsigned long flags;
+       int res = -EPERM;
+
+       spin_lock_irqsave(&ipa_mhi_client_ctx->state_lock, flags);
+       IPA_MHI_DBG("Current state: %s\n",
+                       MHI_STATE_STR(ipa_mhi_client_ctx->state));
+
+       switch (ipa_mhi_client_ctx->state) {
+       case IPA_MHI_STATE_INITIALIZED:
+               if (new_state == IPA_MHI_STATE_READY) {
+                       ipa_mhi_notify_ready();
+                       res = 0;
+               }
+               break;
+
+       case IPA_MHI_STATE_READY:
+               if (new_state == IPA_MHI_STATE_READY)
+                       res = 0;
+               if (new_state == IPA_MHI_STATE_STARTED)
+                       res = 0;
+               break;
+
+       case IPA_MHI_STATE_STARTED:
+               if (new_state == IPA_MHI_STATE_INITIALIZED)
+                       res = 0;
+               else if (new_state == IPA_MHI_STATE_SUSPEND_IN_PROGRESS)
+                       res = 0;
+               break;
+
+       case IPA_MHI_STATE_SUSPEND_IN_PROGRESS:
+               if (new_state == IPA_MHI_STATE_SUSPENDED) {
+                       if (ipa_mhi_client_ctx->trigger_wakeup) {
+                               ipa_mhi_client_ctx->trigger_wakeup = false;
+                               ipa_mhi_notify_wakeup();
+                       }
+                       res = 0;
+               } else if (new_state == IPA_MHI_STATE_STARTED) {
+                       ipa_mhi_client_ctx->wakeup_notified = false;
+                       ipa_mhi_client_ctx->trigger_wakeup = false;
+                       if (ipa_mhi_client_ctx->rm_cons_state ==
+                               IPA_MHI_RM_STATE_REQUESTED) {
+                               ipa_rm_notify_completion(
+                                       IPA_RM_RESOURCE_GRANTED,
+                                       IPA_RM_RESOURCE_MHI_CONS);
+                               ipa_mhi_client_ctx->rm_cons_state =
+                                       IPA_MHI_RM_STATE_GRANTED;
+                       }
+                       res = 0;
+               }
+               break;
+
+       case IPA_MHI_STATE_SUSPENDED:
+               if (new_state == IPA_MHI_STATE_RESUME_IN_PROGRESS)
+                       res = 0;
+               break;
+
+       case IPA_MHI_STATE_RESUME_IN_PROGRESS:
+               if (new_state == IPA_MHI_STATE_SUSPENDED) {
+                       if (ipa_mhi_client_ctx->trigger_wakeup) {
+                               ipa_mhi_client_ctx->trigger_wakeup = false;
+                               ipa_mhi_notify_wakeup();
+                       }
+                       res = 0;
+               } else if (new_state == IPA_MHI_STATE_STARTED) {
+                       ipa_mhi_client_ctx->trigger_wakeup = false;
+                       ipa_mhi_client_ctx->wakeup_notified = false;
+                       if (ipa_mhi_client_ctx->rm_cons_state ==
+                               IPA_MHI_RM_STATE_REQUESTED) {
+                               ipa_rm_notify_completion(
+                                       IPA_RM_RESOURCE_GRANTED,
+                                       IPA_RM_RESOURCE_MHI_CONS);
+                               ipa_mhi_client_ctx->rm_cons_state =
+                                       IPA_MHI_RM_STATE_GRANTED;
+                       }
+                       res = 0;
+               }
+               break;
+
+       default:
+               IPA_MHI_ERR("Invalid state %d\n", ipa_mhi_client_ctx->state);
+               WARN_ON(1);
+       }
+
+       if (res)
+               IPA_MHI_ERR("Invalid state change to %s\n",
+                                               MHI_STATE_STR(new_state));
+       else {
+               IPA_MHI_DBG("New state change to %s\n",
+                                               MHI_STATE_STR(new_state));
+               ipa_mhi_client_ctx->state = new_state;
+       }
+       spin_unlock_irqrestore(&ipa_mhi_client_ctx->state_lock, flags);
+       return res;
+}
+
+static void ipa_mhi_uc_ready_cb(void)
+{
+       IPA_MHI_FUNC_ENTRY();
+       ipa_mhi_set_state(IPA_MHI_STATE_READY);
+       IPA_MHI_FUNC_EXIT();
+}
+
+static void ipa_mhi_uc_wakeup_request_cb(void)
+{
+       unsigned long flags;
+
+       IPA_MHI_FUNC_ENTRY();
+       IPA_MHI_DBG("MHI state: %s\n",
+                       MHI_STATE_STR(ipa_mhi_client_ctx->state));
+       spin_lock_irqsave(&ipa_mhi_client_ctx->state_lock, flags);
+       if (ipa_mhi_client_ctx->state == IPA_MHI_STATE_SUSPENDED)
+               ipa_mhi_notify_wakeup();
+       else if (ipa_mhi_client_ctx->state ==
+                       IPA_MHI_STATE_SUSPEND_IN_PROGRESS)
+               /* wakeup event will be triggered after suspend finishes */
+               ipa_mhi_client_ctx->trigger_wakeup = true;
+
+       spin_unlock_irqrestore(&ipa_mhi_client_ctx->state_lock, flags);
+       IPA_MHI_FUNC_EXIT();
+}
+
+static int ipa_mhi_request_prod(void)
+{
+       int res;
+
+       IPA_MHI_FUNC_ENTRY();
+
+       reinit_completion(&ipa_mhi_client_ctx->rm_prod_granted_comp);
+       IPA_MHI_DBG("requesting mhi prod\n");
+       res = ipa_rm_request_resource(IPA_RM_RESOURCE_MHI_PROD);
+       if (res) {
+               if (res != -EINPROGRESS) {
+                       IPA_MHI_ERR("failed to request mhi prod %d\n", res);
+                       return res;
+               }
+               res = wait_for_completion_timeout(
+                       &ipa_mhi_client_ctx->rm_prod_granted_comp,
+                       msecs_to_jiffies(IPA_MHI_RM_TIMEOUT_MSEC));
+               if (res == 0) {
+                       IPA_MHI_ERR("timeout request mhi prod\n");
+                       return -ETIME;
+               }
+       }
+
+       IPA_MHI_DBG("mhi prod granted\n");
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+
+}
+
+static int ipa_mhi_release_prod(void)
+{
+       int res;
+
+       IPA_MHI_FUNC_ENTRY();
+
+       res = ipa_rm_release_resource(IPA_RM_RESOURCE_MHI_PROD);
+
+       IPA_MHI_FUNC_EXIT();
+       return res;
+
+}
+
+/**
+ * ipa_mhi_start() - Start IPA MHI engine
+ * @params: pcie addresses for MHI
+ *
+ * This function is called by MHI client driver on MHI engine start for
+ * handling MHI accelerated channels. This function is called after
+ * ipa_mhi_init() was called and can be called after MHI reset to restart MHI
+ * engine. When this function returns device can move to M0 state.
+ *
+ * Return codes: 0       : success
+ *              negative : error
+ */
+int ipa_mhi_start(struct ipa_mhi_start_params *params)
+{
+       int res;
+       struct ipa_mhi_init_engine init_params;
+
+       IPA_MHI_FUNC_ENTRY();
+
+       if (!params) {
+               IPA_MHI_ERR("null args\n");
+               return -EINVAL;
+       }
+
+       if (!ipa_mhi_client_ctx) {
+               IPA_MHI_ERR("not initialized\n");
+               return -EPERM;
+       }
+
+       res = ipa_mhi_set_state(IPA_MHI_STATE_STARTED);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_set_state %d\n", res);
+               return res;
+       }
+
+       ipa_mhi_client_ctx->host_ctrl_addr = params->host_ctrl_addr;
+       ipa_mhi_client_ctx->host_data_addr = params->host_data_addr;
+       ipa_mhi_client_ctx->channel_context_array_addr =
+               params->channel_context_array_addr;
+       ipa_mhi_client_ctx->event_context_array_addr =
+               params->event_context_array_addr;
+       IPA_MHI_DBG("host_ctrl_addr 0x%x\n",
+                       ipa_mhi_client_ctx->host_ctrl_addr);
+       IPA_MHI_DBG("host_data_addr 0x%x\n",
+                       ipa_mhi_client_ctx->host_data_addr);
+       IPA_MHI_DBG("channel_context_array_addr 0x%llx\n",
+               ipa_mhi_client_ctx->channel_context_array_addr);
+       IPA_MHI_DBG("event_context_array_addr 0x%llx\n",
+               ipa_mhi_client_ctx->event_context_array_addr);
+
+       /* Add MHI <-> Q6 dependencies to IPA RM */
+       res = ipa_rm_add_dependency(IPA_RM_RESOURCE_MHI_PROD,
+               IPA_RM_RESOURCE_Q6_CONS);
+       if (res && res != -EINPROGRESS) {
+               IPA_MHI_ERR("failed to add dependency %d\n", res);
+               goto fail_add_mhi_q6_dep;
+       }
+
+       res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
+               IPA_RM_RESOURCE_MHI_CONS);
+       if (res && res != -EINPROGRESS) {
+               IPA_MHI_ERR("failed to add dependency %d\n", res);
+               goto fail_add_q6_mhi_dep;
+       }
+
+       res = ipa_mhi_request_prod();
+       if (res) {
+               IPA_MHI_ERR("failed request prod %d\n", res);
+               goto fail_request_prod;
+       }
+
+       /* gsi params */
+       init_params.gsi.first_ch_idx =
+                       ipa_mhi_client_ctx->first_ch_idx;
+       /* uC params */
+       init_params.uC.first_ch_idx =
+                       ipa_mhi_client_ctx->first_ch_idx;
+       init_params.uC.first_er_idx =
+                       ipa_mhi_client_ctx->first_er_idx;
+       init_params.uC.host_ctrl_addr = params->host_ctrl_addr;
+       init_params.uC.host_data_addr = params->host_data_addr;
+       init_params.uC.mmio_addr = ipa_mhi_client_ctx->mmio_addr;
+       init_params.uC.msi = &ipa_mhi_client_ctx->msi;
+       init_params.uC.ipa_cached_dl_ul_sync_info =
+                       &ipa_cached_dl_ul_sync_info;
+
+       res = ipa_mhi_init_engine(&init_params);
+       if (res) {
+               IPA_MHI_ERR("IPA core failed to start MHI %d\n", res);
+               goto fail_init_engine;
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+
+fail_init_engine:
+       ipa_mhi_release_prod();
+fail_request_prod:
+       ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+               IPA_RM_RESOURCE_MHI_CONS);
+fail_add_q6_mhi_dep:
+       ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
+               IPA_RM_RESOURCE_Q6_CONS);
+fail_add_mhi_q6_dep:
+       ipa_mhi_set_state(IPA_MHI_STATE_INITIALIZED);
+       return res;
+}
+
+/**
+ * ipa_mhi_get_channel_context() - Get corresponding channel context
+ * @ep: IPA ep
+ * @channel_id: Channel ID
+ *
+ * This function will return the corresponding channel context or allocate new
+ * one in case channel context for channel does not exist.
+ */
+static struct ipa_mhi_channel_ctx *ipa_mhi_get_channel_context(
+       enum ipa_client_type client, u8 channel_id)
+{
+       int ch_idx;
+       struct ipa_mhi_channel_ctx *channels;
+       int max_channels;
+
+       if (IPA_CLIENT_IS_PROD(client)) {
+               channels = ipa_mhi_client_ctx->ul_channels;
+               max_channels = IPA_MHI_MAX_UL_CHANNELS;
+       } else {
+               channels = ipa_mhi_client_ctx->dl_channels;
+               max_channels = IPA_MHI_MAX_DL_CHANNELS;
+       }
+
+       /* find the channel context according to channel id */
+       for (ch_idx = 0; ch_idx < max_channels; ch_idx++) {
+               if (channels[ch_idx].valid &&
+                   channels[ch_idx].id == channel_id)
+                       return &channels[ch_idx];
+       }
+
+       /* channel context does not exists, allocate a new one */
+       for (ch_idx = 0; ch_idx < max_channels; ch_idx++) {
+               if (!channels[ch_idx].valid)
+                       break;
+       }
+
+       if (ch_idx == max_channels) {
+               IPA_MHI_ERR("no more channels available\n");
+               return NULL;
+       }
+
+       channels[ch_idx].valid = true;
+       channels[ch_idx].id = channel_id;
+       channels[ch_idx].index = ipa_mhi_client_ctx->total_channels++;
+       channels[ch_idx].client = client;
+       channels[ch_idx].state = IPA_HW_MHI_CHANNEL_STATE_INVALID;
+
+       return &channels[ch_idx];
+}
+
+/**
+ * ipa_mhi_get_channel_context_by_clnt_hdl() - Get corresponding channel
+ * context
+ * @clnt_hdl: client handle as provided in ipa_mhi_connect_pipe()
+ *
+ * This function will return the corresponding channel context or NULL in case
+ * that channel does not exist.
+ */
+static struct ipa_mhi_channel_ctx *ipa_mhi_get_channel_context_by_clnt_hdl(
+       u32 clnt_hdl)
+{
+       int ch_idx;
+
+       for (ch_idx = 0; ch_idx < IPA_MHI_MAX_UL_CHANNELS; ch_idx++) {
+               if (ipa_mhi_client_ctx->ul_channels[ch_idx].valid &&
+               ipa_get_ep_mapping(
+                       ipa_mhi_client_ctx->ul_channels[ch_idx].client)
+                               == clnt_hdl)
+                       return &ipa_mhi_client_ctx->ul_channels[ch_idx];
+       }
+
+       for (ch_idx = 0; ch_idx < IPA_MHI_MAX_DL_CHANNELS; ch_idx++) {
+               if (ipa_mhi_client_ctx->dl_channels[ch_idx].valid &&
+               ipa_get_ep_mapping(
+                       ipa_mhi_client_ctx->dl_channels[ch_idx].client)
+                               == clnt_hdl)
+                       return &ipa_mhi_client_ctx->dl_channels[ch_idx];
+       }
+
+       return NULL;
+}
+
+static void ipa_mhi_dump_ch_ctx(struct ipa_mhi_channel_ctx *channel)
+{
+       IPA_MHI_DBG("ch_id %d\n", channel->id);
+       IPA_MHI_DBG("chstate 0x%x\n", channel->ch_ctx_host.chstate);
+       IPA_MHI_DBG("brstmode 0x%x\n", channel->ch_ctx_host.brstmode);
+       IPA_MHI_DBG("pollcfg 0x%x\n", channel->ch_ctx_host.pollcfg);
+       IPA_MHI_DBG("chtype 0x%x\n", channel->ch_ctx_host.chtype);
+       IPA_MHI_DBG("erindex 0x%x\n", channel->ch_ctx_host.erindex);
+       IPA_MHI_DBG("rbase 0x%llx\n", channel->ch_ctx_host.rbase);
+       IPA_MHI_DBG("rlen 0x%llx\n", channel->ch_ctx_host.rlen);
+       IPA_MHI_DBG("rp 0x%llx\n", channel->ch_ctx_host.rp);
+       IPA_MHI_DBG("wp 0x%llx\n", channel->ch_ctx_host.wp);
+}
+
+static void ipa_mhi_dump_ev_ctx(struct ipa_mhi_channel_ctx *channel)
+{
+       IPA_MHI_DBG("ch_id %d event id %d\n", channel->id,
+               channel->ch_ctx_host.erindex);
+
+       IPA_MHI_DBG("intmodc 0x%x\n", channel->ev_ctx_host.intmodc);
+       IPA_MHI_DBG("intmodt 0x%x\n", channel->ev_ctx_host.intmodt);
+       IPA_MHI_DBG("ertype 0x%x\n", channel->ev_ctx_host.ertype);
+       IPA_MHI_DBG("msivec 0x%x\n", channel->ev_ctx_host.msivec);
+       IPA_MHI_DBG("rbase 0x%llx\n", channel->ev_ctx_host.rbase);
+       IPA_MHI_DBG("rlen 0x%llx\n", channel->ev_ctx_host.rlen);
+       IPA_MHI_DBG("rp 0x%llx\n", channel->ev_ctx_host.rp);
+       IPA_MHI_DBG("wp 0x%llx\n", channel->ev_ctx_host.wp);
+}
+
+static int ipa_mhi_read_ch_ctx(struct ipa_mhi_channel_ctx *channel)
+{
+       int res;
+
+       res = ipa_mhi_read_write_host(IPA_MHI_DMA_FROM_HOST,
+               &channel->ch_ctx_host, channel->channel_context_addr,
+               sizeof(channel->ch_ctx_host));
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_read_write_host failed %d\n", res);
+               return res;
+
+       }
+       ipa_mhi_dump_ch_ctx(channel);
+
+       channel->event_context_addr =
+               ipa_mhi_client_ctx->event_context_array_addr +
+               channel->ch_ctx_host.erindex * sizeof(struct ipa_mhi_ev_ctx);
+       IPA_MHI_DBG("ch %d event_context_addr 0x%llx\n", channel->id,
+               channel->event_context_addr);
+
+       res = ipa_mhi_read_write_host(IPA_MHI_DMA_FROM_HOST,
+               &channel->ev_ctx_host, channel->event_context_addr,
+               sizeof(channel->ev_ctx_host));
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_read_write_host failed %d\n", res);
+               return res;
+
+       }
+       ipa_mhi_dump_ev_ctx(channel);
+
+       return 0;
+}
+
+static void ipa_mhi_gsi_ev_err_cb(struct gsi_evt_err_notify *notify)
+{
+       struct ipa_mhi_channel_ctx *channel = notify->user_data;
+
+       IPA_MHI_ERR("channel id=%d client=%d state=%d\n",
+               channel->id, channel->client, channel->state);
+       switch (notify->evt_id) {
+       case GSI_EVT_OUT_OF_BUFFERS_ERR:
+               IPA_MHI_ERR("Received GSI_EVT_OUT_OF_BUFFERS_ERR\n");
+               break;
+       case GSI_EVT_OUT_OF_RESOURCES_ERR:
+               IPA_MHI_ERR("Received GSI_EVT_OUT_OF_RESOURCES_ERR\n");
+               break;
+       case GSI_EVT_UNSUPPORTED_INTER_EE_OP_ERR:
+               IPA_MHI_ERR("Received GSI_EVT_UNSUPPORTED_INTER_EE_OP_ERR\n");
+               break;
+       case GSI_EVT_EVT_RING_EMPTY_ERR:
+               IPA_MHI_ERR("Received GSI_EVT_EVT_RING_EMPTY_ERR\n");
+               break;
+       default:
+               IPA_MHI_ERR("Unexpected err evt: %d\n", notify->evt_id);
+       }
+       IPA_MHI_ERR("err_desc=0x%x\n", notify->err_desc);
+}
+
+static void ipa_mhi_gsi_ch_err_cb(struct gsi_chan_err_notify *notify)
+{
+       struct ipa_mhi_channel_ctx *channel = notify->chan_user_data;
+
+       IPA_MHI_ERR("channel id=%d client=%d state=%d\n",
+               channel->id, channel->client, channel->state);
+       switch (notify->evt_id) {
+       case GSI_CHAN_INVALID_TRE_ERR:
+               IPA_MHI_ERR("Received GSI_CHAN_INVALID_TRE_ERR\n");
+               break;
+       case GSI_CHAN_NON_ALLOCATED_EVT_ACCESS_ERR:
+               IPA_MHI_ERR("Received GSI_CHAN_NON_ALLOCATED_EVT_ACCESS_ERR\n");
+               break;
+       case GSI_CHAN_OUT_OF_BUFFERS_ERR:
+               IPA_MHI_ERR("Received GSI_CHAN_OUT_OF_BUFFERS_ERR\n");
+               break;
+       case GSI_CHAN_OUT_OF_RESOURCES_ERR:
+               IPA_MHI_ERR("Received GSI_CHAN_OUT_OF_RESOURCES_ERR\n");
+               break;
+       case GSI_CHAN_UNSUPPORTED_INTER_EE_OP_ERR:
+               IPA_MHI_ERR("Received GSI_CHAN_UNSUPPORTED_INTER_EE_OP_ERR\n");
+               break;
+       case GSI_CHAN_HWO_1_ERR:
+               IPA_MHI_ERR("Received GSI_CHAN_HWO_1_ERR\n");
+               break;
+       default:
+               IPA_MHI_ERR("Unexpected err evt: %d\n", notify->evt_id);
+       }
+       IPA_MHI_ERR("err_desc=0x%x\n", notify->err_desc);
+}
+
+
+static bool ipa_mhi_gsi_channel_empty(struct ipa_mhi_channel_ctx *channel)
+{
+       IPA_MHI_FUNC_ENTRY();
+
+       if (!channel->stop_in_proc) {
+               IPA_MHI_DBG("Channel is not in STOP_IN_PROC\n");
+               return true;
+       }
+
+       if (ipa_mhi_stop_gsi_channel(channel->client) == true) {
+               channel->stop_in_proc = false;
+               return true;
+       }
+
+       return false;
+}
+
+/**
+ * ipa_mhi_wait_for_ul_empty_timeout() - wait for pending packets in uplink
+ * @msecs: timeout to wait
+ *
+ * This function will poll until there are no packets pending in uplink channels
+ * or timeout occurred.
+ *
+ * Return code: true - no pending packets in uplink channels
+ *             false - timeout occurred
+ */
+static bool ipa_mhi_wait_for_ul_empty_timeout(unsigned int msecs)
+{
+       unsigned long jiffies_timeout = msecs_to_jiffies(msecs);
+       unsigned long jiffies_start = jiffies;
+       bool empty = false;
+       int i;
+
+       IPA_MHI_FUNC_ENTRY();
+       while (!empty) {
+               empty = true;
+               for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
+                       if (!ipa_mhi_client_ctx->ul_channels[i].valid)
+                               continue;
+                       if (ipa_get_transport_type() ==
+                           IPA_TRANSPORT_TYPE_GSI)
+                               empty &= ipa_mhi_gsi_channel_empty(
+                                       &ipa_mhi_client_ctx->ul_channels[i]);
+                       else
+                               empty &= ipa_mhi_sps_channel_empty(
+                               ipa_mhi_client_ctx->ul_channels[i].client);
+               }
+
+               if (time_after(jiffies, jiffies_start + jiffies_timeout)) {
+                       IPA_MHI_DBG("finished waiting for UL empty\n");
+                       break;
+               }
+
+               if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI &&
+                   IPA_MHI_MAX_UL_CHANNELS == 1)
+                       usleep_range(IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC,
+                       IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC);
+       }
+
+       IPA_MHI_DBG("IPA UL is %s\n", (empty) ? "empty" : "not empty");
+
+       IPA_MHI_FUNC_EXIT();
+       return empty;
+}
+
+static int ipa_mhi_enable_force_clear(u32 request_id, bool throttle_source)
+{
+       struct ipa_enable_force_clear_datapath_req_msg_v01 req;
+       int i;
+       int res;
+
+       IPA_MHI_FUNC_ENTRY();
+       memset(&req, 0, sizeof(req));
+       req.request_id = request_id;
+       req.source_pipe_bitmask = 0;
+       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
+               if (!ipa_mhi_client_ctx->ul_channels[i].valid)
+                       continue;
+               req.source_pipe_bitmask |= 1 << ipa_get_ep_mapping(
+                               ipa_mhi_client_ctx->ul_channels[i].client);
+       }
+       if (throttle_source) {
+               req.throttle_source_valid = 1;
+               req.throttle_source = 1;
+       }
+       IPA_MHI_DBG("req_id=0x%x src_pipe_btmk=0x%x throt_src=%d\n",
+               req.request_id, req.source_pipe_bitmask,
+               req.throttle_source);
+       res = ipa_qmi_enable_force_clear_datapath_send(&req);
+       if (res) {
+               IPA_MHI_ERR(
+                       "ipa_qmi_enable_force_clear_datapath_send failed %d\n"
+                               , res);
+               return res;
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
+
+static int ipa_mhi_disable_force_clear(u32 request_id)
+{
+       struct ipa_disable_force_clear_datapath_req_msg_v01 req;
+       int res;
+
+       IPA_MHI_FUNC_ENTRY();
+       memset(&req, 0, sizeof(req));
+       req.request_id = request_id;
+       IPA_MHI_DBG("req_id=0x%x\n", req.request_id);
+       res = ipa_qmi_disable_force_clear_datapath_send(&req);
+       if (res) {
+               IPA_MHI_ERR(
+                       "ipa_qmi_disable_force_clear_datapath_send failed %d\n"
+                               , res);
+               return res;
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
+
+static void ipa_mhi_set_holb_on_dl_channels(bool enable,
+       struct ipa_ep_cfg_holb old_holb[])
+{
+       int i;
+       struct ipa_ep_cfg_holb ep_holb;
+       int ep_idx;
+       int res;
+
+       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
+               if (!ipa_mhi_client_ctx->dl_channels[i].valid)
+                       continue;
+               if (ipa_mhi_client_ctx->dl_channels[i].state ==
+                       IPA_HW_MHI_CHANNEL_STATE_INVALID)
+                       continue;
+               ep_idx = ipa_get_ep_mapping(
+                       ipa_mhi_client_ctx->dl_channels[i].client);
+               if (-1 == ep_idx) {
+                       IPA_MHI_ERR("Client %u is not mapped\n",
+                               ipa_mhi_client_ctx->dl_channels[i].client);
+                       ipa_assert();
+                       return;
+               }
+               memset(&ep_holb, 0, sizeof(ep_holb));
+               if (enable) {
+                       ipa_get_holb(ep_idx, &old_holb[i]);
+                       ep_holb.en = 1;
+                       ep_holb.tmr_val = 0;
+               } else {
+                       ep_holb = old_holb[i];
+               }
+               res = ipa_cfg_ep_holb(ep_idx, &ep_holb);
+               if (res) {
+                       IPA_MHI_ERR("ipa_cfg_ep_holb failed %d\n", res);
+                       ipa_assert();
+                       return;
+               }
+       }
+}
+
+static int ipa_mhi_suspend_gsi_channel(struct ipa_mhi_channel_ctx *channel)
+{
+       int clnt_hdl;
+       int res;
+
+       IPA_MHI_FUNC_ENTRY();
+       clnt_hdl = ipa_get_ep_mapping(channel->client);
+       if (clnt_hdl < 0)
+               return -EFAULT;
+
+       res = ipa_stop_gsi_channel(clnt_hdl);
+       if (res != 0 && res != -GSI_STATUS_AGAIN &&
+           res != -GSI_STATUS_TIMED_OUT) {
+               IPA_MHI_ERR("GSI stop channel failed %d\n", res);
+               return -EFAULT;
+       }
+
+       /* check if channel was stopped completely */
+       if (res)
+               channel->stop_in_proc = true;
+
+       IPA_MHI_DBG("GSI channel is %s\n", (channel->stop_in_proc) ?
+               "STOP_IN_PROC" : "STOP");
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
+
+static int ipa_mhi_reset_ul_channel(struct ipa_mhi_channel_ctx *channel)
+{
+       int res;
+       bool empty;
+       struct ipa_ep_cfg_holb old_ep_holb[IPA_MHI_MAX_DL_CHANNELS];
+
+       IPA_MHI_FUNC_ENTRY();
+       if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI) {
+               res = ipa_mhi_suspend_gsi_channel(channel);
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_suspend_gsi_channel failed %d\n",
+                                res);
+                       return res;
+               }
+       } else {
+               res = ipa_uc_mhi_reset_channel(channel->index);
+               if (res) {
+                       IPA_MHI_ERR("ipa_uc_mhi_reset_channel failed %d\n",
+                               res);
+                       return res;
+               }
+       }
+
+       empty = ipa_mhi_wait_for_ul_empty_timeout(
+                       IPA_MHI_CH_EMPTY_TIMEOUT_MSEC);
+       if (!empty) {
+               IPA_MHI_DBG("%s not empty\n",
+                       (ipa_get_transport_type() ==
+                               IPA_TRANSPORT_TYPE_GSI) ? "GSI" : "BAM");
+               res = ipa_mhi_enable_force_clear(
+                               ipa_mhi_client_ctx->qmi_req_id, false);
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_enable_force_clear failed %d\n",
+                               res);
+                       ipa_assert();
+                       return res;
+               }
+
+               if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI) {
+                       empty = ipa_mhi_wait_for_ul_empty_timeout(
+                               IPA_MHI_CH_EMPTY_TIMEOUT_MSEC);
+
+                       IPA_MHI_DBG("empty=%d\n", empty);
+               } else {
+                       /* enable packet drop on all DL channels */
+                       ipa_mhi_set_holb_on_dl_channels(true, old_ep_holb);
+                       ipa_generate_tag_process();
+                       /* disable packet drop on all DL channels */
+                       ipa_mhi_set_holb_on_dl_channels(false, old_ep_holb);
+
+                       res = ipa_disable_sps_pipe(channel->client);
+                       if (res) {
+                               IPA_MHI_ERR("sps_pipe_disable fail %d\n", res);
+                               ipa_assert();
+                               return res;
+                       }
+               }
+
+               res =
+               ipa_mhi_disable_force_clear(ipa_mhi_client_ctx->qmi_req_id);
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_disable_force_clear failed %d\n",
+                               res);
+                       ipa_assert();
+                       return res;
+               }
+               ipa_mhi_client_ctx->qmi_req_id++;
+       }
+
+       res = ipa_mhi_reset_channel_internal(channel->client);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_reset_ul_channel_internal failed %d\n"
+                               , res);
+               return res;
+       }
+
+       IPA_MHI_FUNC_EXIT();
+
+       return 0;
+}
+
+static int ipa_mhi_reset_dl_channel(struct ipa_mhi_channel_ctx *channel)
+{
+       int res;
+
+       IPA_MHI_FUNC_ENTRY();
+       if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI) {
+               res = ipa_mhi_suspend_gsi_channel(channel);
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_suspend_gsi_channel failed %d\n"
+                                       , res);
+                       return res;
+               }
+
+               res = ipa_mhi_reset_channel_internal(channel->client);
+               if (res) {
+                       IPA_MHI_ERR(
+                               "ipa_mhi_reset_ul_channel_internal failed %d\n"
+                               , res);
+                       return res;
+               }
+       } else {
+               res = ipa_mhi_reset_channel_internal(channel->client);
+               if (res) {
+                       IPA_MHI_ERR(
+                               "ipa_mhi_reset_ul_channel_internal failed %d\n"
+                               , res);
+                       return res;
+               }
+
+               res = ipa_uc_mhi_reset_channel(channel->index);
+               if (res) {
+                       IPA_MHI_ERR("ipa_uc_mhi_reset_channel failed %d\n",
+                               res);
+                       ipa_mhi_start_channel_internal(channel->client);
+                       return res;
+               }
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
+
+static int ipa_mhi_reset_channel(struct ipa_mhi_channel_ctx *channel)
+{
+       int res;
+
+       IPA_MHI_FUNC_ENTRY();
+       if (IPA_CLIENT_IS_PROD(channel->client))
+               res = ipa_mhi_reset_ul_channel(channel);
+       else
+               res = ipa_mhi_reset_dl_channel(channel);
+       if (res) {
+               IPA_MHI_ERR("failed to reset channel error %d\n", res);
+               return res;
+       }
+
+       channel->state = IPA_HW_MHI_CHANNEL_STATE_DISABLE;
+
+       if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI) {
+               res = ipa_mhi_read_write_host(IPA_MHI_DMA_TO_HOST,
+                       &channel->state, channel->channel_context_addr +
+                               offsetof(struct ipa_mhi_ch_ctx, chstate),
+                               sizeof(((struct ipa_mhi_ch_ctx *)0)->chstate));
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_read_write_host failed %d\n", res);
+                       return res;
+               }
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
+
+/**
+ * ipa_mhi_connect_pipe() - Connect pipe to IPA and start corresponding
+ * MHI channel
+ * @in: connect parameters
+ * @clnt_hdl: [out] client handle for this pipe
+ *
+ * This function is called by MHI client driver on MHI channel start.
+ * This function is called after MHI engine was started.
+ *
+ * Return codes: 0       : success
+ *              negative : error
+ */
+int ipa_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl)
+{
+       int res;
+       unsigned long flags;
+       struct ipa_mhi_channel_ctx *channel = NULL;
+
+       IPA_MHI_FUNC_ENTRY();
+
+       if (!in || !clnt_hdl) {
+               IPA_MHI_ERR("NULL args\n");
+               return -EINVAL;
+       }
+
+       if (in->sys.client >= IPA_CLIENT_MAX) {
+               IPA_MHI_ERR("bad param client:%d\n", in->sys.client);
+               return -EINVAL;
+       }
+
+       if (!IPA_CLIENT_IS_MHI(in->sys.client)) {
+               IPA_MHI_ERR(
+                       "Invalid MHI client, client: %d\n", in->sys.client);
+               return -EINVAL;
+       }
+
+       IPA_MHI_DBG("channel=%d\n", in->channel_id);
+
+       spin_lock_irqsave(&ipa_mhi_client_ctx->state_lock, flags);
+       if (!ipa_mhi_client_ctx ||
+                       ipa_mhi_client_ctx->state != IPA_MHI_STATE_STARTED) {
+               IPA_MHI_ERR("IPA MHI was not started\n");
+               spin_unlock_irqrestore(&ipa_mhi_client_ctx->state_lock, flags);
+               return -EINVAL;
+       }
+       spin_unlock_irqrestore(&ipa_mhi_client_ctx->state_lock, flags);
+
+       channel = ipa_mhi_get_channel_context(in->sys.client, in->channel_id);
+       if (!channel) {
+               IPA_MHI_ERR("ipa_mhi_get_channel_context failed\n");
+               return -EINVAL;
+       }
+
+       if (channel->state != IPA_HW_MHI_CHANNEL_STATE_INVALID &&
+           channel->state != IPA_HW_MHI_CHANNEL_STATE_DISABLE) {
+               IPA_MHI_ERR("Invalid channel state %d\n", channel->state);
+               return -EFAULT;
+       }
+
+       channel->channel_context_addr =
+               ipa_mhi_client_ctx->channel_context_array_addr +
+                       channel->id * sizeof(struct ipa_mhi_ch_ctx);
+
+       /* for event context address index needs to read from host */
+
+       IPA_MHI_DBG("client %d channelHandle %d channelIndex %d, state %d\n",
+               channel->client, channel->index, channel->id, channel->state);
+       IPA_MHI_DBG("channel_context_addr 0x%llx\n",
+               channel->channel_context_addr);
+
+       IPA_ACTIVE_CLIENTS_INC_EP(in->sys.client);
+
+       if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI) {
+               struct ipa_mhi_connect_params_internal internal;
+
+               IPA_MHI_DBG("reading ch/ev context from host\n");
+               res = ipa_mhi_read_ch_ctx(channel);
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_read_ch_ctx failed %d\n", res);
+                       goto fail_start_channel;
+               }
+
+               internal.channel_id = in->channel_id;
+               internal.sys = &in->sys;
+               internal.start.gsi.state = channel->state;
+               internal.start.gsi.msi = &ipa_mhi_client_ctx->msi;
+               internal.start.gsi.ev_ctx_host = &channel->ev_ctx_host;
+               internal.start.gsi.event_context_addr =
+                               channel->event_context_addr;
+               internal.start.gsi.ch_ctx_host = &channel->ch_ctx_host;
+               internal.start.gsi.channel_context_addr =
+                               channel->channel_context_addr;
+               internal.start.gsi.ch_err_cb = ipa_mhi_gsi_ch_err_cb;
+               internal.start.gsi.channel = (void *)channel;
+               internal.start.gsi.ev_err_cb = ipa_mhi_gsi_ev_err_cb;
+               internal.start.gsi.assert_bit40 =
+                               ipa_mhi_client_ctx->assert_bit40;
+               internal.start.gsi.mhi = &channel->ch_scratch.mhi;
+               internal.start.gsi.cached_gsi_evt_ring_hdl =
+                               &channel->cached_gsi_evt_ring_hdl;
+               internal.start.gsi.evchid =
+                               channel->index + IPA_MHI_GSI_ER_START;
+
+               res = ipa_connect_mhi_pipe(&internal, clnt_hdl);
+               if (res) {
+                       IPA_MHI_ERR("ipa_connect_mhi_pipe failed %d\n", res);
+                       goto fail_connect_pipe;
+               }
+               channel->state = IPA_HW_MHI_CHANNEL_STATE_RUN;
+               channel->brstmode_enabled =
+                               channel->ch_scratch.mhi.burst_mode_enabled;
+
+               res = ipa_mhi_read_write_host(IPA_MHI_DMA_TO_HOST,
+                       &channel->state, channel->channel_context_addr +
+                               offsetof(struct ipa_mhi_ch_ctx, chstate),
+                               sizeof(channel->state));
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_read_write_host failed\n");
+                       return res;
+
+               }
+       } else {
+               struct ipa_mhi_connect_params_internal internal;
+
+               internal.channel_id = in->channel_id;
+               internal.sys = &in->sys;
+               internal.start.uC.index = channel->index;
+               internal.start.uC.id = channel->id;
+               internal.start.uC.state = channel->state;
+               res = ipa_connect_mhi_pipe(&internal, clnt_hdl);
+               if (res) {
+                       IPA_MHI_ERR("ipa_connect_mhi_pipe failed %d\n", res);
+                       goto fail_connect_pipe;
+               }
+               channel->state = IPA_HW_MHI_CHANNEL_STATE_RUN;
+       }
+
+       if (!in->sys.keep_ipa_awake)
+               IPA_ACTIVE_CLIENTS_DEC_EP(in->sys.client);
+
+       IPA_MHI_FUNC_EXIT();
+
+       return 0;
+fail_connect_pipe:
+       ipa_mhi_reset_channel(channel);
+fail_start_channel:
+       IPA_ACTIVE_CLIENTS_DEC_EP(in->sys.client);
+       return -EPERM;
+}
+
+/**
+ * ipa_mhi_disconnect_pipe() - Disconnect pipe from IPA and reset corresponding
+ * MHI channel
+ * @clnt_hdl: client handle for this pipe
+ *
+ * This function is called by MHI client driver on MHI channel reset.
+ * This function is called after MHI channel was started.
+ * This function is doing the following:
+ *     - Send command to uC/GSI to reset corresponding MHI channel
+ *     - Configure IPA EP control
+ *
+ * Return codes: 0       : success
+ *              negative : error
+ */
+int ipa_mhi_disconnect_pipe(u32 clnt_hdl)
+{
+       int res;
+       enum ipa_client_type client;
+       static struct ipa_mhi_channel_ctx *channel;
+
+       IPA_MHI_FUNC_ENTRY();
+
+       if (!ipa_mhi_client_ctx) {
+               IPA_MHI_ERR("IPA MHI was not initialized\n");
+               return -EINVAL;
+       }
+
+       client = ipa_get_client_mapping(clnt_hdl);
+
+       if (!IPA_CLIENT_IS_MHI(client)) {
+               IPA_MHI_ERR("invalid IPA MHI client, client: %d\n", client);
+               return -EINVAL;
+       }
+
+       channel = ipa_mhi_get_channel_context_by_clnt_hdl(clnt_hdl);
+       if (!channel) {
+               IPA_MHI_ERR("invalid clnt index\n");
+               return -EINVAL;
+       }
+
+       IPA_ACTIVE_CLIENTS_INC_EP(ipa_get_client_mapping(clnt_hdl));
+
+       res = ipa_mhi_reset_channel(channel);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_reset_channel failed %d\n", res);
+               goto fail_reset_channel;
+       }
+
+       res = ipa_disconnect_mhi_pipe(clnt_hdl);
+       if (res) {
+               IPA_MHI_ERR(
+                       "IPA core driver failed to disconnect the pipe hdl %d, res %d"
+                               , clnt_hdl, res);
+               return res;
+       }
+
+       IPA_ACTIVE_CLIENTS_DEC_EP(ipa_get_client_mapping(clnt_hdl));
+
+       IPA_MHI_DBG("client (ep: %d) disconnected\n", clnt_hdl);
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+fail_reset_channel:
+       IPA_ACTIVE_CLIENTS_DEC_EP(ipa_get_client_mapping(clnt_hdl));
+       return res;
+}
+
+static int ipa_mhi_wait_for_cons_release(void)
+{
+       unsigned long flags;
+       int res;
+
+       IPA_MHI_FUNC_ENTRY();
+       reinit_completion(&ipa_mhi_client_ctx->rm_cons_comp);
+       spin_lock_irqsave(&ipa_mhi_client_ctx->state_lock, flags);
+       if (ipa_mhi_client_ctx->rm_cons_state != IPA_MHI_RM_STATE_GRANTED) {
+               spin_unlock_irqrestore(&ipa_mhi_client_ctx->state_lock, flags);
+               return 0;
+       }
+       spin_unlock_irqrestore(&ipa_mhi_client_ctx->state_lock, flags);
+
+       res = wait_for_completion_timeout(
+               &ipa_mhi_client_ctx->rm_cons_comp,
+               msecs_to_jiffies(IPA_MHI_RM_TIMEOUT_MSEC));
+       if (res == 0) {
+               IPA_MHI_ERR("timeout release mhi cons\n");
+               return -ETIME;
+       }
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
+
+static int ipa_mhi_suspend_channels(struct ipa_mhi_channel_ctx *channels)
+{
+       int i;
+       int res;
+
+       IPA_MHI_FUNC_ENTRY();
+       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
+               if (!channels[i].valid)
+                       continue;
+               if (channels[i].state !=
+                   IPA_HW_MHI_CHANNEL_STATE_RUN)
+                       continue;
+               IPA_MHI_DBG("suspending channel %d\n",
+                       channels[i].id);
+
+               if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI)
+                       res = ipa_mhi_suspend_gsi_channel(
+                               &channels[i]);
+               else
+                       res = ipa_uc_mhi_suspend_channel(
+                               channels[i].index);
+
+               if (res) {
+                       IPA_MHI_ERR("failed to suspend channel %d error %d\n",
+                               i, res);
+                       return res;
+               }
+               channels[i].state =
+                       IPA_HW_MHI_CHANNEL_STATE_SUSPEND;
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
+
+static int ipa_mhi_stop_event_update_channels(
+               struct ipa_mhi_channel_ctx *channels)
+{
+       int i;
+       int res;
+
+       if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI)
+               return 0;
+
+       IPA_MHI_FUNC_ENTRY();
+       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
+               if (!channels[i].valid)
+                       continue;
+               if (channels[i].state !=
+                   IPA_HW_MHI_CHANNEL_STATE_SUSPEND)
+                       continue;
+               IPA_MHI_DBG("stop update event channel %d\n",
+                       channels[i].id);
+               res = ipa_uc_mhi_stop_event_update_channel(
+                       channels[i].index);
+               if (res) {
+                       IPA_MHI_ERR("failed stop event channel %d error %d\n",
+                               i, res);
+                       return res;
+               }
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
+
+static bool ipa_mhi_check_pending_packets_from_host(void)
+{
+       int i;
+       int res;
+       struct ipa_mhi_channel_ctx *channel;
+
+       IPA_MHI_FUNC_ENTRY();
+       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
+               channel = &ipa_mhi_client_ctx->ul_channels[i];
+               if (!channel->valid)
+                       continue;
+
+               res = ipa_mhi_query_ch_info(channel->client,
+                               &channel->ch_info);
+               if (res) {
+                       IPA_MHI_ERR("gsi_query_channel_info failed\n");
+                       return true;
+               }
+               res = ipa_mhi_read_ch_ctx(channel);
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_read_ch_ctx failed %d\n", res);
+                       return true;
+               }
+
+               if (channel->ch_info.rp != channel->ch_ctx_host.wp) {
+                       IPA_MHI_DBG("There are pending packets from host\n");
+                       IPA_MHI_DBG("device rp 0x%llx host 0x%llx\n",
+                               channel->ch_info.rp, channel->ch_ctx_host.wp);
+
+                       return true;
+               }
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return false;
+}
+
+static int ipa_mhi_resume_channels(bool LPTransitionRejected,
+               struct ipa_mhi_channel_ctx *channels)
+{
+       int i;
+       int res;
+       struct ipa_mhi_channel_ctx *channel;
+
+       IPA_MHI_FUNC_ENTRY();
+       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
+               if (!channels[i].valid)
+                       continue;
+               if (channels[i].state !=
+                   IPA_HW_MHI_CHANNEL_STATE_SUSPEND)
+                       continue;
+               channel = &channels[i];
+               IPA_MHI_DBG("resuming channel %d\n", channel->id);
+
+               res = ipa_mhi_resume_channels_internal(channel->client,
+                       LPTransitionRejected, channel->brstmode_enabled,
+                       channel->ch_scratch, channel->index);
+
+               if (res) {
+                       IPA_MHI_ERR("failed to resume channel %d error %d\n",
+                               i, res);
+                       return res;
+               }
+
+               channel->stop_in_proc = false;
+               channel->state = IPA_HW_MHI_CHANNEL_STATE_RUN;
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
+
+/**
+ * ipa_mhi_suspend_ul() - Suspend MHI accelerated up link channels
+ * @force:
+ *     false: in case of data pending in IPA, MHI channels will not be
+ *             suspended and function will fail.
+ *     true:  in case of data pending in IPA, make sure no further access from
+ *             IPA to PCIe is possible. In this case suspend cannot fail.
+ *
+ *
+ * This function is called by MHI client driver on MHI suspend.
+ * This function is called after MHI channel was started.
+ * When this function returns device can move to M1/M2/M3/D3cold state.
+ *
+ * Return codes: 0       : success
+ *              negative : error
+ */
+static int ipa_mhi_suspend_ul(bool force, bool *empty, bool *force_clear)
+{
+       int res;
+
+       *force_clear = false;
+
+       res = ipa_mhi_suspend_channels(ipa_mhi_client_ctx->ul_channels);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_suspend_ul_channels failed %d\n", res);
+               goto fail_suspend_ul_channel;
+       }
+
+       *empty = ipa_mhi_wait_for_ul_empty_timeout(
+                       IPA_MHI_CH_EMPTY_TIMEOUT_MSEC);
+
+       if (!*empty) {
+               if (force) {
+                       res = ipa_mhi_enable_force_clear(
+                               ipa_mhi_client_ctx->qmi_req_id, false);
+                       if (res) {
+                               IPA_MHI_ERR("failed to enable force clear\n");
+                               ipa_assert();
+                               return res;
+                       }
+                       *force_clear = true;
+                       IPA_MHI_DBG("force clear datapath enabled\n");
+
+                       *empty = ipa_mhi_wait_for_ul_empty_timeout(
+                               IPA_MHI_CH_EMPTY_TIMEOUT_MSEC);
+                       IPA_MHI_DBG("empty=%d\n", *empty);
+                       if (!*empty && ipa_get_transport_type()
+                               == IPA_TRANSPORT_TYPE_GSI) {
+                               IPA_MHI_ERR("Failed to suspend UL channels\n");
+                               if (ipa_mhi_client_ctx->test_mode) {
+                                       res = -EAGAIN;
+                                       goto fail_suspend_ul_channel;
+                               }
+
+                               ipa_assert();
+                       }
+               } else {
+                       IPA_MHI_DBG("IPA not empty\n");
+                       res = -EAGAIN;
+                       goto fail_suspend_ul_channel;
+               }
+       }
+
+       if (*force_clear) {
+               res =
+               ipa_mhi_disable_force_clear(ipa_mhi_client_ctx->qmi_req_id);
+               if (res) {
+                       IPA_MHI_ERR("failed to disable force clear\n");
+                       ipa_assert();
+                       return res;
+               }
+               IPA_MHI_DBG("force clear datapath disabled\n");
+               ipa_mhi_client_ctx->qmi_req_id++;
+       }
+
+       if (!force && ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI) {
+               if (ipa_mhi_check_pending_packets_from_host()) {
+                       res = -EAGAIN;
+                       goto fail_suspend_ul_channel;
+               }
+       }
+
+       res = ipa_mhi_stop_event_update_channels(
+               ipa_mhi_client_ctx->ul_channels);
+       if (res) {
+               IPA_MHI_ERR(
+                       "ipa_mhi_stop_event_update_ul_channels failed %d\n",
+                       res);
+               goto fail_suspend_ul_channel;
+       }
+
+       return 0;
+
+fail_suspend_ul_channel:
+       return res;
+}
+
+static bool ipa_mhi_has_open_aggr_frame(void)
+{
+       struct ipa_mhi_channel_ctx *channel;
+       int i;
+
+       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
+               channel = &ipa_mhi_client_ctx->dl_channels[i];
+
+               if (!channel->valid)
+                       continue;
+
+               if (ipa_has_open_aggr_frame(channel->client))
+                       return true;
+       }
+
+       return false;
+}
+
+static void ipa_mhi_update_host_ch_state(bool update_rp)
+{
+       int i;
+       int res;
+       struct ipa_mhi_channel_ctx *channel;
+
+       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
+               channel = &ipa_mhi_client_ctx->ul_channels[i];
+               if (!channel->valid)
+                       continue;
+
+               if (update_rp) {
+                       res = ipa_mhi_query_ch_info(channel->client,
+                               &channel->ch_info);
+                       if (res) {
+                               IPA_MHI_ERR("gsi_query_channel_info failed\n");
+                               ipa_assert();
+                               return;
+                       }
+
+                       res = ipa_mhi_read_write_host(IPA_MHI_DMA_TO_HOST,
+                               &channel->ch_info.rp,
+                               channel->channel_context_addr +
+                                       offsetof(struct ipa_mhi_ch_ctx, rp),
+                               sizeof(channel->ch_info.rp));
+                       if (res) {
+                               IPA_MHI_ERR("ipa_mhi_read_write_host failed\n");
+                               ipa_assert();
+                               return;
+                       }
+               }
+
+               res = ipa_mhi_read_write_host(IPA_MHI_DMA_TO_HOST,
+                       &channel->state, channel->channel_context_addr +
+                               offsetof(struct ipa_mhi_ch_ctx, chstate),
+                       sizeof(((struct ipa_mhi_ch_ctx *)0)->chstate));
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_read_write_host failed\n");
+                       ipa_assert();
+                       return;
+               }
+       }
+
+       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
+               channel = &ipa_mhi_client_ctx->dl_channels[i];
+               if (!channel->valid)
+                       continue;
+
+               if (update_rp) {
+                       res = ipa_mhi_query_ch_info(channel->client,
+                               &channel->ch_info);
+                       if (res) {
+                               IPA_MHI_ERR("gsi_query_channel_info failed\n");
+                               ipa_assert();
+                               return;
+                       }
+
+                       res = ipa_mhi_read_write_host(IPA_MHI_DMA_TO_HOST,
+                               &channel->ch_info.rp,
+                               channel->channel_context_addr +
+                                       offsetof(struct ipa_mhi_ch_ctx, rp),
+                               sizeof(channel->ch_info.rp));
+                       if (res) {
+                               IPA_MHI_ERR("ipa_mhi_read_write_host failed\n");
+                               ipa_assert();
+                               return;
+                       }
+               }
+
+               res = ipa_mhi_read_write_host(IPA_MHI_DMA_TO_HOST,
+                       &channel->state, channel->channel_context_addr +
+                       offsetof(struct ipa_mhi_ch_ctx, chstate),
+                       sizeof(((struct ipa_mhi_ch_ctx *)0)->chstate));
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_read_write_host failed\n");
+                       ipa_assert();
+               }
+       }
+}
+
+static int ipa_mhi_suspend_dl(bool force)
+{
+       int res;
+
+       res = ipa_mhi_suspend_channels(ipa_mhi_client_ctx->dl_channels);
+       if (res) {
+               IPA_MHI_ERR(
+                       "ipa_mhi_suspend_channels for dl failed %d\n", res);
+               goto fail_suspend_dl_channel;
+       }
+
+       res = ipa_mhi_stop_event_update_channels
+                       (ipa_mhi_client_ctx->dl_channels);
+       if (res) {
+               IPA_MHI_ERR("failed to stop event update on DL %d\n", res);
+               goto fail_stop_event_update_dl_channel;
+       }
+
+       if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI) {
+               if (ipa_mhi_has_open_aggr_frame()) {
+                       IPA_MHI_DBG("There is an open aggr frame\n");
+                       if (force) {
+                               ipa_mhi_client_ctx->trigger_wakeup = true;
+                       } else {
+                               res = -EAGAIN;
+                               goto fail_stop_event_update_dl_channel;
+                       }
+               }
+       }
+
+       if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI)
+               ipa_mhi_update_host_ch_state(true);
+
+fail_stop_event_update_dl_channel:
+               ipa_mhi_resume_channels(true,
+                               ipa_mhi_client_ctx->dl_channels);
+fail_suspend_dl_channel:
+               return res;
+}
+
+/**
+ * ipa_mhi_suspend() - Suspend MHI accelerated channels
+ * @force:
+ *     false: in case of data pending in IPA, MHI channels will not be
+ *             suspended and function will fail.
+ *     true:  in case of data pending in IPA, make sure no further access from
+ *             IPA to PCIe is possible. In this case suspend cannot fail.
+ *
+ * This function is called by MHI client driver on MHI suspend.
+ * This function is called after MHI channel was started.
+ * When this function returns device can move to M1/M2/M3/D3cold state.
+ *
+ * Return codes: 0       : success
+ *              negative : error
+ */
+int ipa_mhi_suspend(bool force)
+{
+       int res;
+       bool empty;
+       bool force_clear;
+
+       IPA_MHI_FUNC_ENTRY();
+
+       res = ipa_mhi_set_state(IPA_MHI_STATE_SUSPEND_IN_PROGRESS);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_set_state failed %d\n", res);
+               return res;
+       }
+       res = ipa_mhi_suspend_ul(force, &empty, &force_clear);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_suspend_ul failed %d\n", res);
+               goto fail_suspend_ul_channel;
+       }
+
+       /*
+        * hold IPA clocks and release them after all
+        * IPA RM resource are released to make sure tag process will not start
+        */
+       IPA_ACTIVE_CLIENTS_INC_SIMPLE();
+
+       IPA_MHI_DBG("release prod\n");
+       res = ipa_mhi_release_prod();
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n", res);
+               goto fail_release_prod;
+       }
+
+       IPA_MHI_DBG("wait for cons release\n");
+       res = ipa_mhi_wait_for_cons_release();
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_wait_for_cons_release failed %d\n", res);
+               goto fail_release_cons;
+       }
+
+       usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX);
+
+       res = ipa_mhi_suspend_dl(force);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_suspend_dl failed %d\n", res);
+               goto fail_suspend_dl_channel;
+       }
+
+       if (!empty)
+               ipa_set_tag_process_before_gating(false);
+
+       res = ipa_mhi_set_state(IPA_MHI_STATE_SUSPENDED);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_set_state failed %d\n", res);
+               goto fail_release_cons;
+       }
+
+       IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+
+fail_suspend_dl_channel:
+fail_release_cons:
+       ipa_mhi_request_prod();
+fail_release_prod:
+       IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
+fail_suspend_ul_channel:
+       ipa_mhi_resume_channels(true, ipa_mhi_client_ctx->ul_channels);
+       ipa_mhi_set_state(IPA_MHI_STATE_STARTED);
+       if (force_clear) {
+               if (
+               ipa_mhi_disable_force_clear(ipa_mhi_client_ctx->qmi_req_id)) {
+                       IPA_MHI_ERR("failed to disable force clear\n");
+                       ipa_assert();
+               }
+               IPA_MHI_DBG("force clear datapath disabled\n");
+               ipa_mhi_client_ctx->qmi_req_id++;
+       }
+       return res;
+}
+
+/**
+ * ipa_mhi_resume() - Resume MHI accelerated channels
+ *
+ * This function is called by MHI client driver on MHI resume.
+ * This function is called after MHI channel was suspended.
+ * When this function returns device can move to M0 state.
+ * This function is doing the following:
+ *     - Send command to uC/GSI to resume corresponding MHI channel
+ *     - Request MHI_PROD in IPA RM
+ *     - Resume data to IPA
+ *
+ * Return codes: 0       : success
+ *              negative : error
+ */
+int ipa_mhi_resume(void)
+{
+       int res;
+       bool dl_channel_resumed = false;
+
+       IPA_MHI_FUNC_ENTRY();
+
+       res = ipa_mhi_set_state(IPA_MHI_STATE_RESUME_IN_PROGRESS);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_set_state failed %d\n", res);
+               return res;
+       }
+
+       if (ipa_mhi_client_ctx->rm_cons_state == IPA_MHI_RM_STATE_REQUESTED) {
+               /* resume all DL channels */
+               res = ipa_mhi_resume_channels(false,
+                               ipa_mhi_client_ctx->dl_channels);
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_resume_dl_channels failed %d\n",
+                               res);
+                       goto fail_resume_dl_channels;
+               }
+               dl_channel_resumed = true;
+
+               ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
+                       IPA_RM_RESOURCE_MHI_CONS);
+               ipa_mhi_client_ctx->rm_cons_state = IPA_MHI_RM_STATE_GRANTED;
+       }
+
+       res = ipa_mhi_request_prod();
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_request_prod failed %d\n", res);
+               goto fail_request_prod;
+       }
+
+       /* resume all UL channels */
+       res = ipa_mhi_resume_channels(false,
+                                       ipa_mhi_client_ctx->ul_channels);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_resume_ul_channels failed %d\n", res);
+               goto fail_resume_ul_channels;
+       }
+
+       if (!dl_channel_resumed) {
+               res = ipa_mhi_resume_channels(false,
+                                       ipa_mhi_client_ctx->dl_channels);
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_resume_dl_channels failed %d\n",
+                               res);
+                       goto fail_resume_dl_channels2;
+               }
+       }
+
+       if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI)
+               ipa_mhi_update_host_ch_state(false);
+
+       res = ipa_mhi_set_state(IPA_MHI_STATE_STARTED);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_set_state failed %d\n", res);
+               goto fail_set_state;
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+
+fail_set_state:
+       ipa_mhi_suspend_channels(ipa_mhi_client_ctx->dl_channels);
+fail_resume_dl_channels2:
+       ipa_mhi_suspend_channels(ipa_mhi_client_ctx->ul_channels);
+fail_resume_ul_channels:
+       ipa_mhi_release_prod();
+fail_request_prod:
+       ipa_mhi_suspend_channels(ipa_mhi_client_ctx->dl_channels);
+fail_resume_dl_channels:
+       ipa_mhi_set_state(IPA_MHI_STATE_SUSPENDED);
+       return res;
+}
+
+
+static int  ipa_mhi_destroy_channels(struct ipa_mhi_channel_ctx *channels,
+       int num_of_channels)
+{
+       struct ipa_mhi_channel_ctx *channel;
+       int i, res;
+       u32 clnt_hdl;
+
+       for (i = 0; i < num_of_channels; i++) {
+               channel = &channels[i];
+               if (!channel->valid)
+                       continue;
+               if (channel->state == IPA_HW_MHI_CHANNEL_STATE_INVALID)
+                       continue;
+               if (channel->state != IPA_HW_MHI_CHANNEL_STATE_DISABLE) {
+                       clnt_hdl = ipa_get_ep_mapping(channel->client);
+                       IPA_MHI_DBG("disconnect pipe (ep: %d)\n", clnt_hdl);
+                       res = ipa_mhi_disconnect_pipe(clnt_hdl);
+                       if (res) {
+                               IPA_MHI_ERR(
+                                       "failed to disconnect pipe %d, err %d\n"
+                                       , clnt_hdl, res);
+                               goto fail;
+                       }
+               }
+               res = ipa_mhi_destroy_channel(channel->client);
+               if (res) {
+                       IPA_MHI_ERR(
+                               "ipa_mhi_destroy_channel failed %d"
+                                       , res);
+                       goto fail;
+               }
+       }
+       return 0;
+fail:
+       return res;
+}
+
+/**
+ * ipa_mhi_destroy_all_channels() - Destroy MHI IPA channels
+ *
+ * This function is called by IPA MHI client driver on MHI reset to destroy all
+ * IPA MHI channels.
+ */
+int ipa_mhi_destroy_all_channels(void)
+{
+       int res;
+
+       IPA_MHI_FUNC_ENTRY();
+       /* reset all UL and DL acc channels and its accociated event rings */
+       res = ipa_mhi_destroy_channels(ipa_mhi_client_ctx->ul_channels,
+               IPA_MHI_MAX_UL_CHANNELS);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_destroy_channels(ul_channels) failed %d\n",
+                       res);
+               return -EPERM;
+       }
+       IPA_MHI_DBG("All UL channels are disconnected\n");
+
+       res = ipa_mhi_destroy_channels(ipa_mhi_client_ctx->dl_channels,
+               IPA_MHI_MAX_DL_CHANNELS);
+       if (res) {
+               IPA_MHI_ERR("ipa_mhi_destroy_channels(dl_channels) failed %d\n",
+                       res);
+               return -EPERM;
+       }
+       IPA_MHI_DBG("All DL channels are disconnected\n");
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
+
+static void ipa_mhi_debugfs_destroy(void)
+{
+       debugfs_remove_recursive(dent);
+}
+
+/**
+ * ipa_mhi_destroy() - Destroy MHI IPA
+ *
+ * This function is called by MHI client driver on MHI reset to destroy all IPA
+ * MHI resources.
+ * When this function returns ipa_mhi can re-initialize.
+ */
+void ipa_mhi_destroy(void)
+{
+       int res;
+
+       IPA_MHI_FUNC_ENTRY();
+       if (!ipa_mhi_client_ctx) {
+               IPA_MHI_DBG("IPA MHI was not initialized, already destroyed\n");
+               return;
+       }
+       /* reset all UL and DL acc channels and its accociated event rings */
+       if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_GSI) {
+               res = ipa_mhi_destroy_all_channels();
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_destroy_all_channels failed %d\n",
+                               res);
+                       goto fail;
+               }
+       }
+       IPA_MHI_DBG("All channels are disconnected\n");
+
+       if (ipa_get_transport_type() == IPA_TRANSPORT_TYPE_SPS) {
+               IPA_MHI_DBG("cleanup uC MHI\n");
+               ipa_uc_mhi_cleanup();
+       }
+
+
+       if (ipa_mhi_client_ctx->state != IPA_MHI_STATE_INITIALIZED  &&
+                       ipa_mhi_client_ctx->state != IPA_MHI_STATE_READY) {
+               IPA_MHI_DBG("release prod\n");
+               res = ipa_mhi_release_prod();
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n", res);
+                       goto fail;
+               }
+               IPA_MHI_DBG("wait for cons release\n");
+               res = ipa_mhi_wait_for_cons_release();
+               if (res) {
+                       IPA_MHI_ERR("ipa_mhi_wait_for_cons_release failed %d\n",
+                               res);
+                       goto fail;
+               }
+               usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN,
+                               IPA_MHI_SUSPEND_SLEEP_MAX);
+
+               IPA_MHI_DBG("deleate dependency Q6_PROD->MHI_CONS\n");
+               res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
+                       IPA_RM_RESOURCE_MHI_CONS);
+               if (res) {
+                       IPA_MHI_ERR(
+                               "Error deleting dependency %d->%d, res=%d\n"
+                               , IPA_RM_RESOURCE_Q6_PROD,
+                               IPA_RM_RESOURCE_MHI_CONS,
+                               res);
+                       goto fail;
+               }
+               IPA_MHI_DBG("deleate dependency MHI_PROD->Q6_CONS\n");
+               res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
+                       IPA_RM_RESOURCE_Q6_CONS);
+               if (res) {
+                       IPA_MHI_ERR(
+                               "Error deleting dependency %d->%d, res=%d\n",
+                       IPA_RM_RESOURCE_MHI_PROD,
+                       IPA_RM_RESOURCE_Q6_CONS,
+                       res);
+                       goto fail;
+               }
+       }
+
+       res = ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
+       if (res) {
+               IPA_MHI_ERR("Error deleting resource %d, res=%d\n",
+                       IPA_RM_RESOURCE_MHI_PROD, res);
+               goto fail;
+       }
+
+       res = ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS);
+       if (res) {
+               IPA_MHI_ERR("Error deleting resource %d, res=%d\n",
+                       IPA_RM_RESOURCE_MHI_CONS, res);
+               goto fail;
+       }
+
+       ipa_mhi_debugfs_destroy();
+       destroy_workqueue(ipa_mhi_client_ctx->wq);
+       kfree(ipa_mhi_client_ctx);
+       ipa_mhi_client_ctx = NULL;
+       IPA_MHI_DBG("IPA MHI was reset, ready for re-init\n");
+
+       IPA_MHI_FUNC_EXIT();
+       return;
+fail:
+       ipa_assert();
+}
+
+/**
+ * ipa_mhi_init() - Initialize IPA MHI driver
+ * @params: initialization params
+ *
+ * This function is called by MHI client driver on boot to initialize IPA MHI
+ * Driver. When this function returns device can move to READY state.
+ * This function is doing the following:
+ *     - Initialize MHI IPA internal data structures
+ *     - Create IPA RM resources
+ *     - Initialize debugfs
+ *
+ * Return codes: 0       : success
+ *              negative : error
+ */
+int ipa_mhi_init(struct ipa_mhi_init_params *params)
+{
+       int res;
+       struct ipa_rm_create_params mhi_prod_params;
+       struct ipa_rm_create_params mhi_cons_params;
+
+       IPA_MHI_FUNC_ENTRY();
+
+       if (!params) {
+               IPA_MHI_ERR("null args\n");
+               return -EINVAL;
+       }
+
+       if (!params->notify) {
+               IPA_MHI_ERR("null notify function\n");
+               return -EINVAL;
+       }
+
+       if (ipa_mhi_client_ctx) {
+               IPA_MHI_ERR("already initialized\n");
+               return -EPERM;
+       }
+
+       IPA_MHI_DBG("notify = %pF priv = %p\n", params->notify, params->priv);
+       IPA_MHI_DBG("msi: addr_lo = 0x%x addr_hi = 0x%x\n",
+               params->msi.addr_low, params->msi.addr_hi);
+       IPA_MHI_DBG("msi: data = 0x%x mask = 0x%x\n",
+               params->msi.data, params->msi.mask);
+       IPA_MHI_DBG("mmio_addr = 0x%x\n", params->mmio_addr);
+       IPA_MHI_DBG("first_ch_idx = 0x%x\n", params->first_ch_idx);
+       IPA_MHI_DBG("first_er_idx = 0x%x\n", params->first_er_idx);
+       IPA_MHI_DBG("assert_bit40=%d\n", params->assert_bit40);
+       IPA_MHI_DBG("test_mode=%d\n", params->test_mode);
+
+       /* Initialize context */
+       ipa_mhi_client_ctx = kzalloc(sizeof(*ipa_mhi_client_ctx), GFP_KERNEL);
+       if (!ipa_mhi_client_ctx) {
+               IPA_MHI_ERR("no memory\n");
+               res = -EFAULT;
+               goto fail_alloc_ctx;
+       }
+
+       ipa_mhi_client_ctx->state = IPA_MHI_STATE_INITIALIZED;
+       ipa_mhi_client_ctx->cb_notify = params->notify;
+       ipa_mhi_client_ctx->cb_priv = params->priv;
+       ipa_mhi_client_ctx->rm_cons_state = IPA_MHI_RM_STATE_RELEASED;
+       init_completion(&ipa_mhi_client_ctx->rm_prod_granted_comp);
+       spin_lock_init(&ipa_mhi_client_ctx->state_lock);
+       init_completion(&ipa_mhi_client_ctx->rm_cons_comp);
+       ipa_mhi_client_ctx->msi = params->msi;
+       ipa_mhi_client_ctx->mmio_addr = params->mmio_addr;
+       ipa_mhi_client_ctx->first_ch_idx = params->first_ch_idx;
+       ipa_mhi_client_ctx->first_er_idx = params->first_er_idx;
+       ipa_mhi_client_ctx->qmi_req_id = 0;
+       ipa_mhi_client_ctx->use_ipadma = true;
+       ipa_mhi_client_ctx->assert_bit40 = !!params->assert_bit40;
+       ipa_mhi_client_ctx->test_mode = params->test_mode;
+
+       ipa_mhi_client_ctx->wq = create_singlethread_workqueue("ipa_mhi_wq");
+       if (!ipa_mhi_client_ctx->wq) {
+               IPA_MHI_ERR("failed to create workqueue\n");
+               res = -EFAULT;
+               goto fail_create_wq;
+       }
+
+       /* Create PROD in IPA RM */
+       memset(&mhi_prod_params, 0, sizeof(mhi_prod_params));
+       mhi_prod_params.name = IPA_RM_RESOURCE_MHI_PROD;
+       mhi_prod_params.floor_voltage = IPA_VOLTAGE_SVS;
+       mhi_prod_params.reg_params.notify_cb = ipa_mhi_rm_prod_notify;
+       res = ipa_rm_create_resource(&mhi_prod_params);
+       if (res) {
+               IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_PROD\n");
+               goto fail_create_rm_prod;
+       }
+
+       /* Create CONS in IPA RM */
+       memset(&mhi_cons_params, 0, sizeof(mhi_cons_params));
+       mhi_cons_params.name = IPA_RM_RESOURCE_MHI_CONS;
+       mhi_cons_params.floor_voltage = IPA_VOLTAGE_SVS;
+       mhi_cons_params.request_resource = ipa_mhi_rm_cons_request;
+       mhi_cons_params.release_resource = ipa_mhi_rm_cons_release;
+       res = ipa_rm_create_resource(&mhi_cons_params);
+       if (res) {
+               IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_CONS\n");
+               goto fail_create_rm_cons;
+       }
+
+       /* Initialize uC interface */
+       ipa_uc_mhi_init(ipa_mhi_uc_ready_cb,
+               ipa_mhi_uc_wakeup_request_cb);
+       if (ipa_uc_state_check() == 0)
+               ipa_mhi_set_state(IPA_MHI_STATE_READY);
+
+       /* Initialize debugfs */
+       ipa_mhi_debugfs_init();
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+
+fail_create_rm_cons:
+       ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
+fail_create_rm_prod:
+       destroy_workqueue(ipa_mhi_client_ctx->wq);
+fail_create_wq:
+       kfree(ipa_mhi_client_ctx);
+       ipa_mhi_client_ctx = NULL;
+fail_alloc_ctx:
+       return res;
+}
+
+static void ipa_mhi_cache_dl_ul_sync_info(
+       struct ipa_config_req_msg_v01 *config_req)
+{
+       ipa_cached_dl_ul_sync_info.params.isDlUlSyncEnabled = true;
+       ipa_cached_dl_ul_sync_info.params.UlAccmVal =
+               (config_req->ul_accumulation_time_limit_valid) ?
+               config_req->ul_accumulation_time_limit : 0;
+       ipa_cached_dl_ul_sync_info.params.ulMsiEventThreshold =
+               (config_req->ul_msi_event_threshold_valid) ?
+               config_req->ul_msi_event_threshold : 0;
+       ipa_cached_dl_ul_sync_info.params.dlMsiEventThreshold =
+               (config_req->dl_msi_event_threshold_valid) ?
+               config_req->dl_msi_event_threshold : 0;
+}
+
+/**
+ * ipa_mhi_handle_ipa_config_req() - hanle IPA CONFIG QMI message
+ *
+ * This function is called by by IPA QMI service to indicate that IPA CONFIG
+ * message was sent from modem. IPA MHI will update this information to IPA uC
+ * or will cache it until IPA MHI will be initialized.
+ *
+ * Return codes: 0       : success
+ *              negative : error
+ */
+int ipa_mhi_handle_ipa_config_req(struct ipa_config_req_msg_v01 *config_req)
+{
+       IPA_MHI_FUNC_ENTRY();
+
+       if (ipa_get_transport_type() != IPA_TRANSPORT_TYPE_GSI) {
+               ipa_mhi_cache_dl_ul_sync_info(config_req);
+               if (ipa_mhi_client_ctx &&
+                               ipa_mhi_client_ctx->state !=
+                                               IPA_MHI_STATE_INITIALIZED)
+                       ipa_uc_mhi_send_dl_ul_sync_info(
+                               &ipa_cached_dl_ul_sync_info);
+       }
+
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("IPA MHI client driver");
index fcab2a0..b7e291c 100644 (file)
@@ -10,6 +10,9 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/ipa_mhi.h>
+#include <linux/ipa_qmi_service_v01.h>
+
 #ifndef _IPA_COMMON_I_H_
 #define _IPA_COMMON_I_H_
 #include <linux/ipc_logging.h>
@@ -103,6 +106,12 @@ do {\
                ipa_assert();\
 } while (0)
 
+#define IPA_CLIENT_IS_PROD(x) (x >= IPA_CLIENT_PROD && x < IPA_CLIENT_CONS)
+#define IPA_CLIENT_IS_CONS(x) (x >= IPA_CLIENT_CONS && x < IPA_CLIENT_MAX)
+
+#define IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC (1000)
+#define IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC (2000)
+
 enum ipa_active_client_log_type {
        EP,
        SIMPLE,
@@ -118,6 +127,146 @@ struct ipa_active_client_logging_info {
        enum ipa_active_client_log_type type;
 };
 
+/**
+ * struct ipa_mem_buffer - IPA memory buffer
+ * @base: base
+ * @phys_base: physical base address
+ * @size: size of memory buffer
+ */
+struct ipa_mem_buffer {
+       void *base;
+       dma_addr_t phys_base;
+       u32 size;
+};
+
+/**
+ * enum ipa_hw_mhi_channel_states - MHI channel state machine
+ *
+ * Values are according to MHI specification
+ * @IPA_HW_MHI_CHANNEL_STATE_DISABLE: Channel is disabled and not processed by
+ *     the host or device.
+ * @IPA_HW_MHI_CHANNEL_STATE_ENABLE: A channel is enabled after being
+ *     initialized and configured by host, including its channel context and
+ *     associated transfer ring. While this state, the channel is not active
+ *     and the device does not process transfer.
+ * @IPA_HW_MHI_CHANNEL_STATE_RUN: The device processes transfers and doorbell
+ *     for channels.
+ * @IPA_HW_MHI_CHANNEL_STATE_SUSPEND: Used to halt operations on the channel.
+ *     The device does not process transfers for the channel in this state.
+ *     This state is typically used to synchronize the transition to low power
+ *     modes.
+ * @IPA_HW_MHI_CHANNEL_STATE_STOP: Used to halt operations on the channel.
+ *     The device does not process transfers for the channel in this state.
+ * @IPA_HW_MHI_CHANNEL_STATE_ERROR: The device detected an error in an element
+ *     from the transfer ring associated with the channel.
+ * @IPA_HW_MHI_CHANNEL_STATE_INVALID: Invalid state. Shall not be in use in
+ *     operational scenario.
+ */
+enum ipa_hw_mhi_channel_states {
+       IPA_HW_MHI_CHANNEL_STATE_DISABLE        = 0,
+       IPA_HW_MHI_CHANNEL_STATE_ENABLE         = 1,
+       IPA_HW_MHI_CHANNEL_STATE_RUN            = 2,
+       IPA_HW_MHI_CHANNEL_STATE_SUSPEND        = 3,
+       IPA_HW_MHI_CHANNEL_STATE_STOP           = 4,
+       IPA_HW_MHI_CHANNEL_STATE_ERROR          = 5,
+       IPA_HW_MHI_CHANNEL_STATE_INVALID        = 0xFF
+};
+
+/**
+ * Structure holding the parameters for IPA_CPU_2_HW_CMD_MHI_DL_UL_SYNC_INFO
+ * command. Parameters are sent as 32b immediate parameters.
+ * @isDlUlSyncEnabled: Flag to indicate if DL UL Syncronization is enabled
+ * @UlAccmVal: UL Timer Accumulation value (Period after which device will poll
+ *     for UL data)
+ * @ulMsiEventThreshold: Threshold at which HW fires MSI to host for UL events
+ * @dlMsiEventThreshold: Threshold at which HW fires MSI to host for DL events
+ */
+union IpaHwMhiDlUlSyncCmdData_t {
+       struct IpaHwMhiDlUlSyncCmdParams_t {
+               u32 isDlUlSyncEnabled:8;
+               u32 UlAccmVal:8;
+               u32 ulMsiEventThreshold:8;
+               u32 dlMsiEventThreshold:8;
+       } params;
+       u32 raw32b;
+};
+
+struct ipa_mhi_ch_ctx {
+       u8 chstate;/*0-7*/
+       u8 brstmode:2;/*8-9*/
+       u8 pollcfg:6;/*10-15*/
+       u16 rsvd;/*16-31*/
+       u32 chtype;
+       u32 erindex;
+       u64 rbase;
+       u64 rlen;
+       u64 rp;
+       u64 wp;
+} __packed;
+
+struct ipa_mhi_ev_ctx {
+       u32 intmodc:16;
+       u32 intmodt:16;
+       u32 ertype;
+       u32 msivec;
+       u64 rbase;
+       u64 rlen;
+       u64 rp;
+       u64 wp;
+} __packed;
+
+struct ipa_mhi_init_uc_engine {
+       struct ipa_mhi_msi_info *msi;
+       u32 mmio_addr;
+       u32 host_ctrl_addr;
+       u32 host_data_addr;
+       u32 first_ch_idx;
+       u32 first_er_idx;
+       union IpaHwMhiDlUlSyncCmdData_t *ipa_cached_dl_ul_sync_info;
+};
+
+struct ipa_mhi_init_gsi_engine {
+       u32 first_ch_idx;
+};
+
+struct ipa_mhi_init_engine {
+       struct ipa_mhi_init_uc_engine uC;
+       struct ipa_mhi_init_gsi_engine gsi;
+};
+
+struct start_gsi_channel {
+       enum ipa_hw_mhi_channel_states state;
+       struct ipa_mhi_msi_info *msi;
+       struct ipa_mhi_ev_ctx *ev_ctx_host;
+       u64 event_context_addr;
+       struct ipa_mhi_ch_ctx *ch_ctx_host;
+       u64 channel_context_addr;
+       void (*ch_err_cb)(struct gsi_chan_err_notify *notify);
+       void (*ev_err_cb)(struct gsi_evt_err_notify *notify);
+       void *channel;
+       bool assert_bit40;
+       struct gsi_mhi_channel_scratch *mhi;
+       unsigned long *cached_gsi_evt_ring_hdl;
+       uint8_t evchid;
+};
+
+struct start_uc_channel {
+       enum ipa_hw_mhi_channel_states state;
+       u8 index;
+       u8 id;
+};
+
+struct start_mhi_channel {
+       struct start_uc_channel uC;
+       struct start_gsi_channel gsi;
+};
+
+struct ipa_mhi_connect_params_internal {
+       struct ipa_sys_connect_params *sys;
+       u8 channel_id;
+       struct start_mhi_channel start;
+};
+
 extern const char *ipa_clients_strings[];
 
 #define IPA_IPC_LOGGING(buf, fmt, args...) \
@@ -140,5 +289,45 @@ void *ipa_get_ipc_logbuf(void);
 void *ipa_get_ipc_logbuf_low(void);
 void ipa_assert(void);
 
+/* MHI */
+int ipa_mhi_init_engine(struct ipa_mhi_init_engine *params);
+int ipa_connect_mhi_pipe(struct ipa_mhi_connect_params_internal *in,
+               u32 *clnt_hdl);
+int ipa_disconnect_mhi_pipe(u32 clnt_hdl);
+bool ipa_mhi_stop_gsi_channel(enum ipa_client_type client);
+int ipa_qmi_enable_force_clear_datapath_send(
+       struct ipa_enable_force_clear_datapath_req_msg_v01 *req);
+int ipa_qmi_disable_force_clear_datapath_send(
+       struct ipa_disable_force_clear_datapath_req_msg_v01 *req);
+int ipa_generate_tag_process(void);
+int ipa_disable_sps_pipe(enum ipa_client_type client);
+int ipa_mhi_reset_channel_internal(enum ipa_client_type client);
+int ipa_mhi_start_channel_internal(enum ipa_client_type client);
+bool ipa_mhi_sps_channel_empty(enum ipa_client_type client);
+int ipa_mhi_resume_channels_internal(enum ipa_client_type client,
+               bool LPTransitionRejected, bool brstmode_enabled,
+               union __packed gsi_channel_scratch ch_scratch, u8 index);
+int ipa_mhi_handle_ipa_config_req(struct ipa_config_req_msg_v01 *config_req);
+int ipa_mhi_query_ch_info(enum ipa_client_type client,
+               struct gsi_chan_info *ch_info);
+int ipa_mhi_destroy_channel(enum ipa_client_type client);
+
+/* MHI uC */
+int ipa_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t *cmd);
+int ipa_uc_mhi_init
+       (void (*ready_cb)(void), void (*wakeup_request_cb)(void));
+void ipa_uc_mhi_cleanup(void);
+int ipa_uc_mhi_reset_channel(int channelHandle);
+int ipa_uc_mhi_suspend_channel(int channelHandle);
+int ipa_uc_mhi_stop_event_update_channel(int channelHandle);
+int ipa_uc_mhi_print_stats(char *dbg_buff, int size);
+
+/* uC */
+int ipa_uc_state_check(void);
+
+/* general */
+void ipa_get_holb(int ep_idx, struct ipa_ep_cfg_holb *holb);
+void ipa_set_tag_process_before_gating(bool val);
+bool ipa_has_open_aggr_frame(enum ipa_client_type client);
 
 #endif /* _IPA_COMMON_I_H_ */
index 7d5daf2..178ca5a 100644 (file)
 #define IPA_LAN_RX_HDR_NAME "ipa_lan_hdr"
 #define IPA_INVALID_L4_PROTOCOL 0xFF
 
-#define IPA_CLIENT_IS_PROD(x) (x >= IPA_CLIENT_PROD && x < IPA_CLIENT_CONS)
-#define IPA_CLIENT_IS_CONS(x) (x >= IPA_CLIENT_CONS && x < IPA_CLIENT_MAX)
 #define IPA_SETFIELD(val, shift, mask) (((val) << (shift)) & (mask))
 #define IPA_SETFIELD_IN_REG(reg, val, shift, mask) \
                        (reg |= ((val) << (shift)) & (mask))
@@ -186,18 +184,6 @@ struct ipa_smmu_cb_ctx {
 };
 
 /**
- * struct ipa_mem_buffer - IPA memory buffer
- * @base: base
- * @phys_base: physical base address
- * @size: size of memory buffer
- */
-struct ipa_mem_buffer {
-       void *base;
-       dma_addr_t phys_base;
-       u32 size;
-};
-
-/**
  * struct ipa_flt_entry - IPA filtering table entry
  * @link: entry's link in global filtering enrties list
  * @rule: filter rule
@@ -1012,58 +998,6 @@ enum ipa_hw_flags {
 };
 
 /**
- * enum ipa_hw_mhi_channel_states - MHI channel state machine
- *
- * Values are according to MHI specification
- * @IPA_HW_MHI_CHANNEL_STATE_DISABLE: Channel is disabled and not processed by
- *     the host or device.
- * @IPA_HW_MHI_CHANNEL_STATE_ENABLE: A channel is enabled after being
- *     initialized and configured by host, including its channel context and
- *     associated transfer ring. While this state, the channel is not active
- *     and the device does not process transfer.
- * @IPA_HW_MHI_CHANNEL_STATE_RUN: The device processes transfers and doorbell
- *     for channels.
- * @IPA_HW_MHI_CHANNEL_STATE_SUSPEND: Used to halt operations on the channel.
- *     The device does not process transfers for the channel in this state.
- *     This state is typically used to synchronize the transition to low power
- *     modes.
- * @IPA_HW_MHI_CHANNEL_STATE_STOP: Used to halt operations on the channel.
- *     The device does not process transfers for the channel in this state.
- * @IPA_HW_MHI_CHANNEL_STATE_ERROR: The device detected an error in an element
- *     from the transfer ring associated with the channel.
- * @IPA_HW_MHI_CHANNEL_STATE_INVALID: Invalid state. Shall not be in use in
- *     operational scenario.
- */
-enum ipa_hw_mhi_channel_states {
-       IPA_HW_MHI_CHANNEL_STATE_DISABLE        = 0,
-       IPA_HW_MHI_CHANNEL_STATE_ENABLE         = 1,
-       IPA_HW_MHI_CHANNEL_STATE_RUN            = 2,
-       IPA_HW_MHI_CHANNEL_STATE_SUSPEND        = 3,
-       IPA_HW_MHI_CHANNEL_STATE_STOP           = 4,
-       IPA_HW_MHI_CHANNEL_STATE_ERROR          = 5,
-       IPA_HW_MHI_CHANNEL_STATE_INVALID        = 0xFF
-};
-
-/**
- * Structure holding the parameters for IPA_CPU_2_HW_CMD_MHI_DL_UL_SYNC_INFO
- * command. Parameters are sent as 32b immediate parameters.
- * @isDlUlSyncEnabled: Flag to indicate if DL UL Syncronization is enabled
- * @UlAccmVal: UL Timer Accumulation value (Period after which device will poll
- *     for UL data)
- * @ulMsiEventThreshold: Threshold at which HW fires MSI to host for UL events
- * @dlMsiEventThreshold: Threshold at which HW fires MSI to host for DL events
- */
-union IpaHwMhiDlUlSyncCmdData_t {
-       struct IpaHwMhiDlUlSyncCmdParams_t {
-               u32 isDlUlSyncEnabled:8;
-               u32 UlAccmVal:8;
-               u32 ulMsiEventThreshold:8;
-               u32 dlMsiEventThreshold:8;
-       } params;
-       u32 raw32b;
-};
-
-/**
  * struct ipa_uc_ctx - IPA uC context
  * @uc_inited: Indicates if uC interface has been initialized
  * @uc_loaded: Indicates if uC has loaded
@@ -1720,21 +1654,30 @@ int ipa2_dma_uc_memcpy(phys_addr_t dest, phys_addr_t src, int len);
 void ipa2_dma_destroy(void);
 
 /*
- * MHI
+ * MHI APIs for IPA MHI client driver
  */
-int ipa2_mhi_init(struct ipa_mhi_init_params *params);
+int ipa2_init_mhi(struct ipa_mhi_init_params *params);
 
-int ipa2_mhi_start(struct ipa_mhi_start_params *params);
+int ipa2_mhi_init_engine(struct ipa_mhi_init_engine *params);
 
-int ipa2_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl);
+int ipa2_connect_mhi_pipe(struct ipa_mhi_connect_params_internal *in,
+               u32 *clnt_hdl);
 
-int ipa2_mhi_disconnect_pipe(u32 clnt_hdl);
+int ipa2_disconnect_mhi_pipe(u32 clnt_hdl);
 
-int ipa2_mhi_suspend(bool force);
+bool ipa2_mhi_sps_channel_empty(enum ipa_client_type client);
 
-int ipa2_mhi_resume(void);
+int ipa2_disable_sps_pipe(enum ipa_client_type client);
 
-void ipa2_mhi_destroy(void);
+int ipa2_mhi_reset_channel_internal(enum ipa_client_type client);
+
+int ipa2_mhi_start_channel_internal(enum ipa_client_type client);
+
+int ipa2_mhi_suspend_ul_channels(void);
+
+int ipa2_mhi_resume_channels_internal(enum ipa_client_type client,
+               bool LPTransitionRejected, bool brstmode_enabled,
+               union __packed gsi_channel_scratch ch_scratch, u8 index);
 
 /*
  * mux id
@@ -1947,12 +1890,10 @@ int ipa_q6_monitor_holb_mitigation(bool enable);
 int ipa_sps_connect_safe(struct sps_pipe *h, struct sps_connect *connect,
                         enum ipa_client_type ipa_client);
 
-int ipa_mhi_handle_ipa_config_req(struct ipa_config_req_msg_v01 *config_req);
-
 int ipa_uc_interface_init(void);
 int ipa_uc_reset_pipe(enum ipa_client_type ipa_client);
 int ipa_uc_monitor_holb(enum ipa_client_type ipa_client, bool enable);
-int ipa_uc_state_check(void);
+int ipa2_uc_state_check(void);
 int ipa_uc_loaded_check(void);
 int ipa_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status,
                    bool polling_mode, unsigned long timeout_jiffies);
@@ -1966,18 +1907,19 @@ void ipa_dma_async_memcpy_notify_cb(void *priv,
 
 int ipa_uc_update_hw_flags(u32 flags);
 
-int ipa_uc_mhi_init(void (*ready_cb)(void), void (*wakeup_request_cb)(void));
-int ipa_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t cmd);
+int ipa2_uc_mhi_init(void (*ready_cb)(void), void (*wakeup_request_cb)(void));
+void ipa2_uc_mhi_cleanup(void);
+int ipa2_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t *cmd);
 int ipa_uc_mhi_init_engine(struct ipa_mhi_msi_info *msi, u32 mmio_addr,
        u32 host_ctrl_addr, u32 host_data_addr, u32 first_ch_idx,
        u32 first_evt_idx);
 int ipa_uc_mhi_init_channel(int ipa_ep_idx, int channelHandle,
        int contexArrayIndex, int channelDirection);
-int ipa_uc_mhi_reset_channel(int channelHandle);
-int ipa_uc_mhi_suspend_channel(int channelHandle);
+int ipa2_uc_mhi_reset_channel(int channelHandle);
+int ipa2_uc_mhi_suspend_channel(int channelHandle);
 int ipa_uc_mhi_resume_channel(int channelHandle, bool LPTransitionRejected);
-int ipa_uc_mhi_stop_event_update_channel(int channelHandle);
-int ipa_uc_mhi_print_stats(char *dbg_buff, int size);
+int ipa2_uc_mhi_stop_event_update_channel(int channelHandle);
+int ipa2_uc_mhi_print_stats(char *dbg_buff, int size);
 int ipa_uc_memcpy(phys_addr_t dest, phys_addr_t src, int len);
 u32 ipa_get_num_pipes(void);
 u32 ipa_get_sys_yellow_wm(void);
index ab86bac..7c10c4c 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/ipa.h>
+#include <linux/ipa_mhi.h>
 #include "ipa_i.h"
 #include "ipa_qmi_service.h"
 
 #define IPA_MHI_FUNC_EXIT() \
        IPA_MHI_DBG("EXIT\n")
 
-#define IPA_MHI_RM_TIMEOUT_MSEC 10000
-
-#define IPA_MHI_BAM_EMPTY_TIMEOUT_MSEC 5
-
-#define IPA_MHI_MAX_UL_CHANNELS 1
-#define IPA_MHI_MAX_DL_CHANNELS 1
-
-#define IPA_MHI_SUSPEND_SLEEP_MIN 900
-#define IPA_MHI_SUSPEND_SLEEP_MAX 1100
-
-enum ipa_mhi_state {
-       IPA_MHI_STATE_INITIALIZED,
-       IPA_MHI_STATE_READY,
-       IPA_MHI_STATE_STARTED,
-       IPA_MHI_STATE_SUSPEND_IN_PROGRESS,
-       IPA_MHI_STATE_SUSPENDED,
-       IPA_MHI_STATE_RESUME_IN_PROGRESS,
-       IPA_MHI_STATE_MAX
-};
-
-static char *ipa_mhi_state_str[] = {
-       __stringify(IPA_MHI_STATE_INITIALIZED),
-       __stringify(IPA_MHI_STATE_READY),
-       __stringify(IPA_MHI_STATE_STARTED),
-       __stringify(IPA_MHI_STATE_SUSPEND_IN_PROGRESS),
-       __stringify(IPA_MHI_STATE_SUSPENDED),
-       __stringify(IPA_MHI_STATE_RESUME_IN_PROGRESS),
-};
-
-#define MHI_STATE_STR(state) \
-       (((state) >= 0 && (state) < IPA_MHI_STATE_MAX) ? \
-               ipa_mhi_state_str[(state)] : \
-               "INVALID")
-
-/**
- * struct ipa_mhi_channel_ctx - MHI Channel context
- * @valid: entry is valid
- * @id: MHI channel ID
- * @hdl: channel handle for uC
- * @client: IPA Client
- * @state: Channel state
- */
-struct ipa_mhi_channel_ctx {
-       bool valid;
-       u8 id;
-       u8 hdl;
-       enum ipa_client_type client;
-       enum ipa_hw_mhi_channel_states state;
-};
-
-enum ipa_mhi_rm_state {
-       IPA_MHI_RM_STATE_RELEASED,
-       IPA_MHI_RM_STATE_REQUESTED,
-       IPA_MHI_RM_STATE_GRANTED,
-       IPA_MHI_RM_STATE_MAX
-};
-
-/**
- * struct ipa_mhi_ctx - IPA MHI context
- * @state: IPA MHI state
- * @state_lock: lock for state read/write operations
- * @msi: Message Signaled Interrupts parameters
- * @mmio_addr: MHI MMIO physical address
- * @first_ch_idx: First channel ID for hardware accelerated channels.
- * @first_er_idx: First event ring ID for hardware accelerated channels.
- * @host_ctrl_addr: Base address of MHI control data structures
- * @host_data_addr: Base address of MHI data buffers
- * @cb_notify: client callback
- * @cb_priv: client private data to be provided in client callback
- * @ul_channels: IPA MHI uplink channel contexts
- * @dl_channels: IPA MHI downlink channel contexts
- * @total_channels: Total number of channels ever connected to IPA MHI
- * @rm_prod_granted_comp: Completion object for MHI producer resource in IPA RM
- * @rm_cons_state: MHI consumer resource state in IPA RM
- * @rm_cons_comp: Completion object for MHI consumer resource in IPA RM
- * @trigger_wakeup: trigger wakeup callback ?
- * @wakeup_notified: MHI Client wakeup function was called
- * @wq: workqueue for wakeup event
- * @qmi_req_id: QMI request unique id
- */
-struct ipa_mhi_ctx {
-       enum ipa_mhi_state state;
-       spinlock_t state_lock;
-       struct ipa_mhi_msi_info msi;
-       u32 mmio_addr;
-       u32 first_ch_idx;
-       u32 first_er_idx;
-       u32 host_ctrl_addr;
-       u32 host_data_addr;
-       mhi_client_cb cb_notify;
-       void *cb_priv;
-       struct ipa_mhi_channel_ctx ul_channels[IPA_MHI_MAX_UL_CHANNELS];
-       struct ipa_mhi_channel_ctx dl_channels[IPA_MHI_MAX_DL_CHANNELS];
-       u32 total_channels;
-       struct completion rm_prod_granted_comp;
-       enum ipa_mhi_rm_state rm_cons_state;
-       struct completion rm_cons_comp;
-       bool trigger_wakeup;
-       bool wakeup_notified;
-       struct workqueue_struct *wq;
-       u32 qmi_req_id;
-};
-
-static struct ipa_mhi_ctx *ipa_mhi_ctx;
-
-static void ipa_mhi_wq_notify_wakeup(struct work_struct *work);
-static DECLARE_WORK(ipa_mhi_notify_wakeup_work, ipa_mhi_wq_notify_wakeup);
-
-static void ipa_mhi_wq_notify_ready(struct work_struct *work);
-static DECLARE_WORK(ipa_mhi_notify_ready_work, ipa_mhi_wq_notify_ready);
-
-static union IpaHwMhiDlUlSyncCmdData_t cached_dl_ul_sync_info;
-
-#ifdef CONFIG_DEBUG_FS
-#define IPA_MHI_MAX_MSG_LEN 512
-static char dbg_buff[IPA_MHI_MAX_MSG_LEN];
-static struct dentry *dent;
-
-static char *ipa_mhi_channel_state_str[] = {
-       __stringify(IPA_HW_MHI_CHANNEL_STATE_DISABLE),
-       __stringify(IPA_HW_MHI_CHANNEL_STATE_ENABLE),
-       __stringify(IPA_HW_MHI_CHANNEL_STATE_RUN),
-       __stringify(IPA_HW_MHI_CHANNEL_STATE_SUSPEND),
-       __stringify(IPA_HW_MHI_CHANNEL_STATE_STOP),
-       __stringify(IPA_HW_MHI_CHANNEL_STATE_ERROR),
-};
-
-#define MHI_CH_STATE_STR(state) \
-       (((state) >= 0 && (state) <= IPA_HW_MHI_CHANNEL_STATE_ERROR) ? \
-       ipa_mhi_channel_state_str[(state)] : \
-       "INVALID")
-
-static ssize_t ipa_mhi_debugfs_stats(struct file *file,
-       char __user *ubuf,
-       size_t count,
-       loff_t *ppos)
-{
-       int nbytes = 0;
-       int i;
-       struct ipa_mhi_channel_ctx *channel;
-
-       nbytes += scnprintf(&dbg_buff[nbytes],
-               IPA_MHI_MAX_MSG_LEN - nbytes,
-               "IPA MHI state: %s\n", MHI_STATE_STR(ipa_mhi_ctx->state));
-
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               channel = &ipa_mhi_ctx->ul_channels[i];
-               nbytes += scnprintf(&dbg_buff[nbytes],
-                       IPA_MHI_MAX_MSG_LEN - nbytes,
-                       "channel %d: ", i);
-               if (channel->valid) {
-                       nbytes += scnprintf(&dbg_buff[nbytes],
-                               IPA_MHI_MAX_MSG_LEN - nbytes,
-                               "ch_id=%d client=%d state=%s",
-                               channel->id, channel->client,
-                               MHI_CH_STATE_STR(channel->state));
-               } else {
-                       nbytes += scnprintf(&dbg_buff[nbytes],
-                               IPA_MHI_MAX_MSG_LEN - nbytes,
-                               "never connected");
-               }
-
-               nbytes += scnprintf(&dbg_buff[nbytes],
-                       IPA_MHI_MAX_MSG_LEN - nbytes, "\n");
-       }
-
-       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-               channel = &ipa_mhi_ctx->dl_channels[i];
-               nbytes += scnprintf(&dbg_buff[nbytes],
-                       IPA_MHI_MAX_MSG_LEN - nbytes,
-                       "channel %d: ", i);
-               if (channel->valid) {
-                       nbytes += scnprintf(&dbg_buff[nbytes],
-                               IPA_MHI_MAX_MSG_LEN - nbytes,
-                               "ch_id=%d client=%d state=%s",
-                               channel->id, channel->client,
-                               MHI_CH_STATE_STR(channel->state));
-               } else {
-                       nbytes += scnprintf(&dbg_buff[nbytes],
-                               IPA_MHI_MAX_MSG_LEN - nbytes,
-                               "never connected");
-               }
-
-               nbytes += scnprintf(&dbg_buff[nbytes],
-                       IPA_MHI_MAX_MSG_LEN - nbytes, "\n");
-       }
-
-       return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
-}
-
-static ssize_t ipa_mhi_debugfs_uc_stats(struct file *file,
-       char __user *ubuf,
-       size_t count,
-       loff_t *ppos)
-{
-       int nbytes = 0;
-
-       nbytes += ipa_uc_mhi_print_stats(dbg_buff, IPA_MHI_MAX_MSG_LEN);
-
-       return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
-}
-
-const struct file_operations ipa_mhi_stats_ops = {
-       .read = ipa_mhi_debugfs_stats,
-};
-
-const struct file_operations ipa_mhi_uc_stats_ops = {
-       .read = ipa_mhi_debugfs_uc_stats,
-};
-
-static void ipa_mhi_debugfs_init(void)
+bool ipa2_mhi_sps_channel_empty(enum ipa_client_type client)
 {
-       const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
-       struct dentry *file;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       dent = debugfs_create_dir("ipa_mhi", 0);
-       if (IS_ERR(dent)) {
-               IPA_MHI_ERR("fail to create folder ipa_mhi\n");
-               return;
-       }
-
-       file = debugfs_create_file("stats", read_only_mode, dent,
-               0, &ipa_mhi_stats_ops);
-       if (!file || IS_ERR(file)) {
-               IPA_MHI_ERR("fail to create file stats\n");
-               goto fail;
-       }
-
-       file = debugfs_create_file("uc_stats", read_only_mode, dent,
-               0, &ipa_mhi_uc_stats_ops);
-       if (!file || IS_ERR(file)) {
-               IPA_MHI_ERR("fail to create file stats\n");
-               goto fail;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return;
-fail:
-       debugfs_remove_recursive(dent);
-}
-
-static void ipa_mhi_debugfs_destroy(void)
-{
-       debugfs_remove_recursive(dent);
-}
-
-#else
-static void ipa_mhi_debugfs_init(void) {}
-static void ipa_mhi_debugfs_destroy(void) {}
-#endif /* CONFIG_DEBUG_FS */
-
-
-static void ipa_mhi_cache_dl_ul_sync_info(
-       struct ipa_config_req_msg_v01 *config_req)
-{
-       cached_dl_ul_sync_info.params.isDlUlSyncEnabled = true;
-       cached_dl_ul_sync_info.params.UlAccmVal =
-               (config_req->ul_accumulation_time_limit_valid) ?
-               config_req->ul_accumulation_time_limit : 0;
-       cached_dl_ul_sync_info.params.ulMsiEventThreshold =
-               (config_req->ul_msi_event_threshold_valid) ?
-               config_req->ul_msi_event_threshold : 0;
-       cached_dl_ul_sync_info.params.dlMsiEventThreshold =
-               (config_req->dl_msi_event_threshold_valid) ?
-               config_req->dl_msi_event_threshold : 0;
-}
-
-/**
- * ipa_mhi_wq_notify_wakeup() - Notify MHI client on data available
- *
- * This function is called from IPA MHI workqueue to notify
- * MHI client driver on data available event.
- */
-static void ipa_mhi_wq_notify_wakeup(struct work_struct *work)
-{
-       IPA_MHI_FUNC_ENTRY();
-       ipa_mhi_ctx->cb_notify(ipa_mhi_ctx->cb_priv,
-               IPA_MHI_EVENT_DATA_AVAILABLE, 0);
-       IPA_MHI_FUNC_EXIT();
-}
-
-/**
- * ipa_mhi_notify_wakeup() - Schedule work to notify data available
- *
- * This function will schedule a work to notify data available event.
- * In case this function is called more than once, only one notification will
- * be sent to MHI client driver. No further notifications will be sent until
- * IPA MHI state will become STARTED.
- */
-static void ipa_mhi_notify_wakeup(void)
-{
-       IPA_MHI_FUNC_ENTRY();
-       if (ipa_mhi_ctx->wakeup_notified) {
-               IPADBG("wakeup already called\n");
-               return;
-       }
-       queue_work(ipa_mhi_ctx->wq, &ipa_mhi_notify_wakeup_work);
-       ipa_mhi_ctx->wakeup_notified = true;
-       IPA_MHI_FUNC_EXIT();
-}
-
-/**
- * ipa_mhi_wq_notify_ready() - Notify MHI client on ready
- *
- * This function is called from IPA MHI workqueue to notify
- * MHI client driver on ready event when IPA uC is loaded
- */
-static void ipa_mhi_wq_notify_ready(struct work_struct *work)
-{
-       IPA_MHI_FUNC_ENTRY();
-       ipa_mhi_ctx->cb_notify(ipa_mhi_ctx->cb_priv,
-               IPA_MHI_EVENT_READY, 0);
-       IPA_MHI_FUNC_EXIT();
-}
-
-/**
- * ipa_mhi_notify_ready() - Schedule work to notify ready
- *
- * This function will schedule a work to notify ready event.
- */
-static void ipa_mhi_notify_ready(void)
-{
-       IPA_MHI_FUNC_ENTRY();
-       queue_work(ipa_mhi_ctx->wq, &ipa_mhi_notify_ready_work);
-       IPA_MHI_FUNC_EXIT();
-}
-
-/**
- * ipa_mhi_set_state() - Set new state to IPA MHI
- * @state: new state
- *
- * Sets a new state to IPA MHI if possible according to IPA MHI state machine.
- * In some state transitions a wakeup request will be triggered.
- *
- * Returns: 0 on success, -1 otherwise
- */
-static int ipa_mhi_set_state(enum ipa_mhi_state new_state)
-{
-       unsigned long flags;
-       int res = -EPERM;
-
-       spin_lock_irqsave(&ipa_mhi_ctx->state_lock, flags);
-       IPA_MHI_DBG("Current state: %s\n", MHI_STATE_STR(ipa_mhi_ctx->state));
-
-       switch (ipa_mhi_ctx->state) {
-       case IPA_MHI_STATE_INITIALIZED:
-               if (new_state == IPA_MHI_STATE_READY) {
-                       ipa_mhi_notify_ready();
-                       res = 0;
-               }
-               break;
-
-       case IPA_MHI_STATE_READY:
-               if (new_state == IPA_MHI_STATE_READY)
-                       res = 0;
-               if (new_state == IPA_MHI_STATE_STARTED)
-                       res = 0;
-               break;
-
-       case IPA_MHI_STATE_STARTED:
-               if (new_state == IPA_MHI_STATE_INITIALIZED)
-                       res = 0;
-               else if (new_state == IPA_MHI_STATE_SUSPEND_IN_PROGRESS)
-                       res = 0;
-               break;
-
-       case IPA_MHI_STATE_SUSPEND_IN_PROGRESS:
-               if (new_state == IPA_MHI_STATE_SUSPENDED) {
-                       if (ipa_mhi_ctx->trigger_wakeup) {
-                               ipa_mhi_ctx->trigger_wakeup = false;
-                               ipa_mhi_notify_wakeup();
-                       }
-                       res = 0;
-               } else if (new_state == IPA_MHI_STATE_STARTED) {
-                       ipa_mhi_ctx->wakeup_notified = false;
-                       if (ipa_mhi_ctx->rm_cons_state ==
-                               IPA_MHI_RM_STATE_REQUESTED) {
-                               ipa_rm_notify_completion(
-                                       IPA_RM_RESOURCE_GRANTED,
-                                       IPA_RM_RESOURCE_MHI_CONS);
-                               ipa_mhi_ctx->rm_cons_state =
-                                       IPA_MHI_RM_STATE_GRANTED;
-                       }
-                       res = 0;
-               }
-               break;
-
-       case IPA_MHI_STATE_SUSPENDED:
-               if (new_state == IPA_MHI_STATE_RESUME_IN_PROGRESS)
-                       res = 0;
-               break;
-
-       case IPA_MHI_STATE_RESUME_IN_PROGRESS:
-               if (new_state == IPA_MHI_STATE_SUSPENDED) {
-                       if (ipa_mhi_ctx->trigger_wakeup) {
-                               ipa_mhi_ctx->trigger_wakeup = false;
-                               ipa_mhi_notify_wakeup();
-                       }
-                       res = 0;
-               } else if (new_state == IPA_MHI_STATE_STARTED) {
-                       ipa_mhi_ctx->wakeup_notified = false;
-                       if (ipa_mhi_ctx->rm_cons_state ==
-                               IPA_MHI_RM_STATE_REQUESTED) {
-                               ipa_rm_notify_completion(
-                                       IPA_RM_RESOURCE_GRANTED,
-                                       IPA_RM_RESOURCE_MHI_CONS);
-                               ipa_mhi_ctx->rm_cons_state =
-                                       IPA_MHI_RM_STATE_GRANTED;
-                       }
-                       res = 0;
-               }
-               break;
-
-       default:
-               IPA_MHI_ERR("invalied state %d\n", ipa_mhi_ctx->state);
-               WARN_ON(1);
-       }
-
-       if (res)
-               IPA_MHI_ERR("Invalid state change to %s\n",
-                                               MHI_STATE_STR(new_state));
-       else {
-               IPA_MHI_DBG("New state change to %s\n",
-                                               MHI_STATE_STR(new_state));
-               ipa_mhi_ctx->state = new_state;
-       }
-       spin_unlock_irqrestore(&ipa_mhi_ctx->state_lock, flags);
-       return res;
-}
-
-static void ipa_mhi_rm_prod_notify(void *user_data, enum ipa_rm_event event,
-       unsigned long data)
-{
-       IPA_MHI_FUNC_ENTRY();
-
-       switch (event) {
-       case IPA_RM_RESOURCE_GRANTED:
-               IPA_MHI_DBG("IPA_RM_RESOURCE_GRANTED\n");
-               complete_all(&ipa_mhi_ctx->rm_prod_granted_comp);
-               break;
-
-       case IPA_RM_RESOURCE_RELEASED:
-               IPA_MHI_DBG("IPA_RM_RESOURCE_RELEASED\n");
-               break;
+       u32 pipe_idx;
+       bool pending;
 
-       default:
-               IPA_MHI_ERR("unexpected event %d\n", event);
+       pipe_idx = ipa2_get_ep_mapping(client);
+       if (sps_pipe_pending_desc(ipa_ctx->bam_handle,
+               pipe_idx, &pending)) {
+               IPA_MHI_ERR("sps_pipe_pending_desc failed\n");
                WARN_ON(1);
-               break;
+               return false;
        }
 
-       IPA_MHI_FUNC_EXIT();
+       return !pending;
 }
 
-static void ipa_mhi_uc_ready_cb(void)
+int ipa2_disable_sps_pipe(enum ipa_client_type client)
 {
-       IPA_MHI_FUNC_ENTRY();
-       ipa_mhi_set_state(IPA_MHI_STATE_READY);
-       IPA_MHI_FUNC_EXIT();
-}
-
-static void ipa_mhi_uc_wakeup_request_cb(void)
-{
-       unsigned long flags;
-
-       IPA_MHI_FUNC_ENTRY();
-       IPA_MHI_DBG("MHI state: %s\n", MHI_STATE_STR(ipa_mhi_ctx->state));
-       spin_lock_irqsave(&ipa_mhi_ctx->state_lock, flags);
-       if (ipa_mhi_ctx->state == IPA_MHI_STATE_SUSPENDED) {
-               ipa_mhi_notify_wakeup();
-       } else if (ipa_mhi_ctx->state == IPA_MHI_STATE_SUSPEND_IN_PROGRESS) {
-               /* wakeup event will be triggered after suspend finishes */
-               ipa_mhi_ctx->trigger_wakeup = true;
-       }
-       spin_unlock_irqrestore(&ipa_mhi_ctx->state_lock, flags);
-       IPA_MHI_FUNC_EXIT();
-}
-
-/**
- * ipa_mhi_rm_cons_request() - callback function for IPA RM request resource
- *
- * In case IPA MHI is not suspended, MHI CONS will be granted immediately.
- * In case IPA MHI is suspended, MHI CONS will be granted after resume.
- */
-static int ipa_mhi_rm_cons_request(void)
-{
-       unsigned long flags;
+       int ipa_ep_index;
        int res;
 
-       IPA_MHI_FUNC_ENTRY();
-
-       IPA_MHI_DBG("%s\n", MHI_STATE_STR(ipa_mhi_ctx->state));
-       spin_lock_irqsave(&ipa_mhi_ctx->state_lock, flags);
-       ipa_mhi_ctx->rm_cons_state = IPA_MHI_RM_STATE_REQUESTED;
-       if (ipa_mhi_ctx->state == IPA_MHI_STATE_STARTED) {
-               ipa_mhi_ctx->rm_cons_state = IPA_MHI_RM_STATE_GRANTED;
-               res = 0;
-       } else if (ipa_mhi_ctx->state == IPA_MHI_STATE_SUSPENDED) {
-               ipa_mhi_notify_wakeup();
-               res = -EINPROGRESS;
-       } else if (ipa_mhi_ctx->state == IPA_MHI_STATE_SUSPEND_IN_PROGRESS) {
-               /* wakeup event will be trigger after suspend finishes */
-               ipa_mhi_ctx->trigger_wakeup = true;
-               res = -EINPROGRESS;
-       } else {
-               res = -EINPROGRESS;
-       }
-
-       spin_unlock_irqrestore(&ipa_mhi_ctx->state_lock, flags);
-       IPA_MHI_DBG("EXIT with %d\n", res);
-       return res;
-}
+       ipa_ep_index = ipa2_get_ep_mapping(client);
 
-static int ipa_mhi_rm_cons_release(void)
-{
-       unsigned long flags;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       spin_lock_irqsave(&ipa_mhi_ctx->state_lock, flags);
-       ipa_mhi_ctx->rm_cons_state = IPA_MHI_RM_STATE_RELEASED;
-       complete_all(&ipa_mhi_ctx->rm_cons_comp);
-       spin_unlock_irqrestore(&ipa_mhi_ctx->state_lock, flags);
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa_mhi_wait_for_cons_release(void)
-{
-       unsigned long flags;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       reinit_completion(&ipa_mhi_ctx->rm_cons_comp);
-       spin_lock_irqsave(&ipa_mhi_ctx->state_lock, flags);
-       if (ipa_mhi_ctx->rm_cons_state != IPA_MHI_RM_STATE_GRANTED) {
-               spin_unlock_irqrestore(&ipa_mhi_ctx->state_lock, flags);
-               return 0;
-       }
-       spin_unlock_irqrestore(&ipa_mhi_ctx->state_lock, flags);
-
-       res = wait_for_completion_timeout(
-               &ipa_mhi_ctx->rm_cons_comp,
-               msecs_to_jiffies(IPA_MHI_RM_TIMEOUT_MSEC));
-       if (res == 0) {
-               IPA_MHI_ERR("timeout release mhi cons\n");
-               return -ETIME;
-       }
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa_mhi_request_prod(void)
-{
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       reinit_completion(&ipa_mhi_ctx->rm_prod_granted_comp);
-       IPA_MHI_DBG("requesting mhi prod\n");
-       res = ipa_rm_request_resource(IPA_RM_RESOURCE_MHI_PROD);
+       res = sps_pipe_disable(ipa_ctx->bam_handle, ipa_ep_index);
        if (res) {
-               if (res != -EINPROGRESS) {
-                       IPA_MHI_ERR("failed to request mhi prod %d\n", res);
-                       return res;
-               }
-               res = wait_for_completion_timeout(
-                       &ipa_mhi_ctx->rm_prod_granted_comp,
-                       msecs_to_jiffies(IPA_MHI_RM_TIMEOUT_MSEC));
-               if (res == 0) {
-                       IPA_MHI_ERR("timeout request mhi prod\n");
-                       return -ETIME;
-               }
-       }
-
-       IPA_MHI_DBG("mhi prod granted\n");
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-
-}
-
-static int ipa_mhi_release_prod(void)
-{
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       res = ipa_rm_release_resource(IPA_RM_RESOURCE_MHI_PROD);
-
-       IPA_MHI_FUNC_EXIT();
-       return res;
-
-}
-
-/**
- * ipa_mhi_get_channel_context() - Get corresponding channel context
- * @client: IPA client
- * @channel_id: Channel ID
- *
- * This function will return the corresponding channel context or allocate new
- * one in case channel context for channel does not exist.
- */
-static struct ipa_mhi_channel_ctx *ipa_mhi_get_channel_context(
-       enum ipa_client_type client, u8 channel_id)
-{
-       int ch_idx;
-       struct ipa_mhi_channel_ctx *channels;
-       int max_channels;
-
-       if (IPA_CLIENT_IS_PROD(client)) {
-               channels = ipa_mhi_ctx->ul_channels;
-               max_channels = IPA_MHI_MAX_UL_CHANNELS;
-       } else {
-               channels = ipa_mhi_ctx->dl_channels;
-               max_channels = IPA_MHI_MAX_DL_CHANNELS;
-       }
-
-       /* find the channel context according to channel id */
-       for (ch_idx = 0; ch_idx < max_channels; ch_idx++) {
-               if (channels[ch_idx].valid &&
-                   channels[ch_idx].id == channel_id)
-                       return &channels[ch_idx];
-       }
-
-       /* channel context does not exists, allocate a new one */
-       for (ch_idx = 0; ch_idx < max_channels; ch_idx++) {
-               if (!channels[ch_idx].valid)
-                       break;
-       }
-
-       if (ch_idx == max_channels) {
-               IPA_MHI_ERR("no more channels available\n");
-               return NULL;
-       }
-
-       channels[ch_idx].valid = true;
-       channels[ch_idx].id = channel_id;
-       channels[ch_idx].hdl = ipa_mhi_ctx->total_channels++;
-       channels[ch_idx].client = client;
-       channels[ch_idx].state = IPA_HW_MHI_CHANNEL_STATE_INVALID;
-
-       return &channels[ch_idx];
-}
-
-/**
- * ipa_mhi_get_channel_context_by_clnt_hdl() - Get corresponding channel context
- * @clnt_hdl: client handle as provided in ipa2_mhi_connect_pipe()
- *
- * This function will return the corresponding channel context or NULL in case
- * that channel does not exist.
- */
-static struct ipa_mhi_channel_ctx *ipa_mhi_get_channel_context_by_clnt_hdl(
-       u32 clnt_hdl)
-{
-       int ch_idx;
-
-       for (ch_idx = 0; ch_idx < IPA_MHI_MAX_UL_CHANNELS; ch_idx++) {
-               if (ipa_mhi_ctx->ul_channels[ch_idx].valid &&
-                   ipa2_get_ep_mapping(
-                   ipa_mhi_ctx->ul_channels[ch_idx].client) == clnt_hdl)
-                       return &ipa_mhi_ctx->ul_channels[ch_idx];
-       }
-
-       for (ch_idx = 0; ch_idx < IPA_MHI_MAX_DL_CHANNELS; ch_idx++) {
-               if (ipa_mhi_ctx->dl_channels[ch_idx].valid &&
-                   ipa2_get_ep_mapping(
-                   ipa_mhi_ctx->dl_channels[ch_idx].client) == clnt_hdl)
-                       return &ipa_mhi_ctx->dl_channels[ch_idx];
-       }
-
-       return NULL;
-}
-
-static int ipa_mhi_enable_force_clear(u32 request_id, bool throttle_source)
-{
-       struct ipa_enable_force_clear_datapath_req_msg_v01 req;
-       int i;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       memset(&req, 0, sizeof(req));
-       req.request_id = request_id;
-       req.source_pipe_bitmask = 0;
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               if (!ipa_mhi_ctx->ul_channels[i].valid)
-                       continue;
-               req.source_pipe_bitmask |= 1 << ipa2_get_ep_mapping(
-                                       ipa_mhi_ctx->ul_channels[i].client);
-       }
-       if (throttle_source) {
-               req.throttle_source_valid = 1;
-               req.throttle_source = 1;
-       }
-       IPA_MHI_DBG("req_id=0x%x src_pipe_btmk=0x%x throt_src=%d\n",
-               req.request_id, req.source_pipe_bitmask,
-               req.throttle_source);
-       res = qmi_enable_force_clear_datapath_send(&req);
-       if (res) {
-               IPA_MHI_ERR("qmi_enable_force_clear_datapath_send failed %d\n",
-                       res);
+               IPA_MHI_ERR("sps_pipe_disable fail %d\n", res);
                return res;
        }
 
-       IPA_MHI_FUNC_EXIT();
        return 0;
 }
 
-static int ipa_mhi_disable_force_clear(u32 request_id)
-{
-       struct ipa_disable_force_clear_datapath_req_msg_v01 req;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       memset(&req, 0, sizeof(req));
-       req.request_id = request_id;
-       IPA_MHI_DBG("req_id=0x%x\n", req.request_id);
-       res = qmi_disable_force_clear_datapath_send(&req);
-       if (res) {
-               IPA_MHI_ERR("qmi_disable_force_clear_datapath_send failed %d\n",
-                       res);
-               return res;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-/**
- * ipa_mhi_wait_for_bam_empty_timeout() - wait for pending packets in uplink
- * @msecs: timeout to wait
- *
- * This function will poll until there are no packets pending in uplink channels
- * or timeout occurred.
- *
- * Return code: true - no pending packets in uplink channels
- *             false - timeout occurred
- */
-static bool ipa_mhi_wait_for_bam_empty_timeout(unsigned int msecs)
-{
-       unsigned long jiffies_timeout = msecs_to_jiffies(msecs);
-       unsigned long jiffies_start = jiffies;
-       bool empty = false;
-       bool pending;
-       int i;
-       u32 pipe_idx;
-
-       IPA_MHI_FUNC_ENTRY();
-       while (!empty) {
-               empty = true;
-               for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-                       if (!ipa_mhi_ctx->ul_channels[i].valid)
-                               continue;
-                       pipe_idx = ipa2_get_ep_mapping(
-                               ipa_mhi_ctx->ul_channels[i].client);
-                       if (sps_pipe_pending_desc(ipa_ctx->bam_handle,
-                                               pipe_idx, &pending)) {
-                               IPA_MHI_ERR("sps_pipe_pending_desc failed\n");
-                               WARN_ON(1);
-                               return false;
-                       }
-                       empty &= !pending;
-               }
-
-               if (time_after(jiffies, jiffies_start + jiffies_timeout)) {
-                       IPA_MHI_DBG("timeout waiting for BAM empty\n");
-                       break;
-               }
-       }
-       IPA_MHI_DBG("Bam is %s\n", (empty) ? "empty" : "not empty");
-       IPA_MHI_FUNC_EXIT();
-       return empty;
-}
-
-static int ipa_mhi_reset_ul_channel(struct ipa_mhi_channel_ctx *channel)
+int ipa2_mhi_reset_channel_internal(enum ipa_client_type client)
 {
        int res;
-       int i;
-       int ep_idx;
-       struct ipa_ep_cfg_holb ep_holb;
-       struct ipa_ep_cfg_holb old_ep_holb[IPA_MHI_MAX_DL_CHANNELS];
-       bool empty;
 
        IPA_MHI_FUNC_ENTRY();
-       res = ipa_uc_mhi_reset_channel(channel->hdl);
-       if (res) {
-               IPA_MHI_ERR("ipa_uc_mhi_reset_channel failed %d\n", res);
-               return res;
-       }
-       empty = ipa_mhi_wait_for_bam_empty_timeout(
-               IPA_MHI_BAM_EMPTY_TIMEOUT_MSEC);
-       if (!empty) {
-               IPA_MHI_DBG("BAM not empty\n");
-               res = ipa_mhi_enable_force_clear(ipa_mhi_ctx->qmi_req_id,
-                       true);
-               if (res) {
-                       IPA_MHI_ERR("ipa_mhi_enable_force_clear failed %d\n",
-                               res);
-                       BUG();
-                       return res;
-               }
-
-               /* enable packet drop on all DL channels */
-               for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-                       if (!ipa_mhi_ctx->dl_channels[i].valid)
-                               continue;
-                       if (ipa_mhi_ctx->dl_channels[i].state ==
-                           IPA_HW_MHI_CHANNEL_STATE_INVALID)
-                               continue;
-                       ep_idx = ipa2_get_ep_mapping(
-                               ipa_mhi_ctx->dl_channels[i].client);
-                       if (-1 == ep_idx) {
-                               IPA_MHI_ERR("Client %u is not mapped\n",
-                                       ipa_mhi_ctx->dl_channels[i].client);
-                               BUG();
-                               return -EFAULT;
-                       }
-                       memset(&ep_holb, 0, sizeof(ep_holb));
-                       ep_holb.en = 1;
-                       ep_holb.tmr_val = 0;
-                       old_ep_holb[i] = ipa_ctx->ep[ep_idx].holb;
-                       res = ipa2_cfg_ep_holb(ep_idx, &ep_holb);
-                       if (res) {
-                               IPA_MHI_ERR("ipa2_cfg_ep_holb failed %d\n",
-                                               res);
-                               BUG();
-                               return res;
-                       }
-               }
-
-               res = ipa_tag_process(NULL, 0, HZ);
-               if (res)
-                       IPAERR("TAG process failed\n");
-
-               /* disable packet drop on all DL channels */
-               for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-                       if (!ipa_mhi_ctx->dl_channels[i].valid)
-                               continue;
-                       if (ipa_mhi_ctx->dl_channels[i].state ==
-                               IPA_HW_MHI_CHANNEL_STATE_INVALID)
-                               continue;
-                       ep_idx = ipa2_get_ep_mapping(
-                               ipa_mhi_ctx->dl_channels[i].client);
-                       res = ipa2_cfg_ep_holb(ep_idx, &old_ep_holb[i]);
-                       if (res) {
-                               IPA_MHI_ERR("ipa2_cfg_ep_holb failed %d\n",
-                                               res);
-                               BUG();
-                               return res;
-                       }
-               }
-
-               res = sps_pipe_disable(ipa_ctx->bam_handle,
-                       ipa2_get_ep_mapping(channel->client));
-               if (res) {
-                       IPA_MHI_ERR("sps_pipe_disable failed %d\n", res);
-                       BUG();
-                       return res;
-               }
 
-               res = ipa_mhi_disable_force_clear(ipa_mhi_ctx->qmi_req_id);
-               if (res) {
-                       IPA_MHI_ERR("ipa_mhi_disable_force_clear failed %d\n",
-                               res);
-                       BUG();
-                       return res;
-               }
-               ipa_mhi_ctx->qmi_req_id++;
-       }
-
-       res = ipa_disable_data_path(ipa2_get_ep_mapping(channel->client));
+       res = ipa_disable_data_path(ipa2_get_ep_mapping(client));
        if (res) {
                IPA_MHI_ERR("ipa_disable_data_path failed %d\n", res);
                return res;
@@ -911,187 +79,23 @@ static int ipa_mhi_reset_ul_channel(struct ipa_mhi_channel_ctx *channel)
        return 0;
 }
 
-static int ipa_mhi_reset_dl_channel(struct ipa_mhi_channel_ctx *channel)
-{
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       res = ipa_disable_data_path(ipa2_get_ep_mapping(channel->client));
-       if (res) {
-               IPA_MHI_ERR("ipa_disable_data_path failed %d\n", res);
-               return res;
-       }
-
-       res = ipa_uc_mhi_reset_channel(channel->hdl);
-       if (res) {
-               IPA_MHI_ERR("ipa_uc_mhi_reset_channel failed %d\n", res);
-               goto fail_reset_channel;
-       }
-       IPA_MHI_FUNC_EXIT();
-
-       return 0;
-
-fail_reset_channel:
-       ipa_enable_data_path(ipa2_get_ep_mapping(channel->client));
-       return res;
-}
-
-static int ipa_mhi_reset_channel(struct ipa_mhi_channel_ctx *channel)
-{
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       if (IPA_CLIENT_IS_PROD(channel->client))
-               res = ipa_mhi_reset_ul_channel(channel);
-       else
-               res = ipa_mhi_reset_dl_channel(channel);
-       if (res) {
-               IPA_MHI_ERR("failed to reset channel error %d\n", res);
-               return res;
-       }
-
-       channel->state = IPA_HW_MHI_CHANNEL_STATE_DISABLE;
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-/**
- * ipa2_mhi_init() - Initialize IPA MHI driver
- * @params: initialization params
- *
- * This function is called by MHI client driver on boot to initialize IPA MHI
- * Driver. When this function returns device can move to READY state.
- * This function is doing the following:
- *     - Initialize MHI IPA internal data structures
- *     - Create IPA RM resources
- *     - Initialize debugfs
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa2_mhi_init(struct ipa_mhi_init_params *params)
-{
-       int res;
-       struct ipa_rm_create_params mhi_prod_params;
-       struct ipa_rm_create_params mhi_cons_params;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       if (!params) {
-               IPA_MHI_ERR("null args\n");
-               return -EINVAL;
-       }
-
-       if (!params->notify) {
-               IPA_MHI_ERR("null notify function\n");
-               return -EINVAL;
-       }
-
-       if (ipa_mhi_ctx) {
-               IPA_MHI_ERR("already initialized\n");
-               return -EPERM;
-       }
-
-       IPA_MHI_DBG("msi: addr_lo = 0x%x addr_hi = 0x%x\n",
-               params->msi.addr_low, params->msi.addr_hi);
-       IPA_MHI_DBG("msi: data = 0x%x mask = 0x%x\n",
-               params->msi.data, params->msi.mask);
-       IPA_MHI_DBG("mmio_addr = 0x%x\n", params->mmio_addr);
-       IPA_MHI_DBG("first_ch_idx = 0x%x\n", params->first_ch_idx);
-       IPA_MHI_DBG("first_er_idx = 0x%x\n", params->first_er_idx);
-       IPA_MHI_DBG("notify = %pF priv = %p\n", params->notify, params->priv);
-
-       /* Initialize context */
-       ipa_mhi_ctx = kzalloc(sizeof(*ipa_mhi_ctx), GFP_KERNEL);
-       if (!ipa_mhi_ctx) {
-               IPA_MHI_ERR("no memory\n");
-               res = -EFAULT;
-               goto fail_alloc_ctx;
-       }
-
-       ipa_mhi_ctx->state = IPA_MHI_STATE_INITIALIZED;
-       ipa_mhi_ctx->msi = params->msi;
-       ipa_mhi_ctx->mmio_addr = params->mmio_addr;
-       ipa_mhi_ctx->first_ch_idx = params->first_ch_idx;
-       ipa_mhi_ctx->first_er_idx = params->first_er_idx;
-       ipa_mhi_ctx->cb_notify = params->notify;
-       ipa_mhi_ctx->cb_priv = params->priv;
-       ipa_mhi_ctx->rm_cons_state = IPA_MHI_RM_STATE_RELEASED;
-       ipa_mhi_ctx->qmi_req_id = 0;
-       init_completion(&ipa_mhi_ctx->rm_prod_granted_comp);
-       spin_lock_init(&ipa_mhi_ctx->state_lock);
-       init_completion(&ipa_mhi_ctx->rm_cons_comp);
-
-       ipa_mhi_ctx->wq = create_singlethread_workqueue("ipa_mhi_wq");
-       if (!ipa_mhi_ctx->wq) {
-               IPA_MHI_ERR("failed to create workqueue\n");
-               res = -EFAULT;
-               goto fail_create_wq;
-       }
-
-       /* Initialize debugfs */
-       ipa_mhi_debugfs_init();
+int ipa2_mhi_start_channel_internal(enum ipa_client_type client)
+{
+       int res;
 
-       /* Create PROD in IPA RM */
-       memset(&mhi_prod_params, 0, sizeof(mhi_prod_params));
-       mhi_prod_params.name = IPA_RM_RESOURCE_MHI_PROD;
-       mhi_prod_params.floor_voltage = IPA_VOLTAGE_SVS;
-       mhi_prod_params.reg_params.notify_cb = ipa_mhi_rm_prod_notify;
-       res = ipa_rm_create_resource(&mhi_prod_params);
-       if (res) {
-               IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_PROD\n");
-               goto fail_create_rm_prod;
-       }
+       IPA_MHI_FUNC_ENTRY();
 
-       /* Create CONS in IPA RM */
-       memset(&mhi_cons_params, 0, sizeof(mhi_cons_params));
-       mhi_cons_params.name = IPA_RM_RESOURCE_MHI_CONS;
-       mhi_cons_params.floor_voltage = IPA_VOLTAGE_SVS;
-       mhi_cons_params.request_resource = ipa_mhi_rm_cons_request;
-       mhi_cons_params.release_resource = ipa_mhi_rm_cons_release;
-       res = ipa_rm_create_resource(&mhi_cons_params);
+       res = ipa_enable_data_path(ipa2_get_ep_mapping(client));
        if (res) {
-               IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_CONS\n");
-               goto fail_create_rm_cons;
+               IPA_MHI_ERR("ipa_enable_data_path failed %d\n", res);
+               return res;
        }
-
-       /* Initialize uC interface */
-       ipa_uc_mhi_init(ipa_mhi_uc_ready_cb, ipa_mhi_uc_wakeup_request_cb);
-       if (ipa_uc_state_check() == 0)
-               ipa_mhi_set_state(IPA_MHI_STATE_READY);
-
        IPA_MHI_FUNC_EXIT();
 
        return 0;
-
-fail_create_rm_cons:
-       ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
-fail_create_rm_prod:
-       destroy_workqueue(ipa_mhi_ctx->wq);
-fail_create_wq:
-       kfree(ipa_mhi_ctx);
-       ipa_mhi_ctx = NULL;
-fail_alloc_ctx:
-       return res;
 }
 
-/**
- * ipa2_mhi_start() - Start IPA MHI engine
- * @params: pcie addresses for MHI
- *
- * This function is called by MHI client driver on MHI engine start for
- * handling MHI accelerated channels. This function is called after
- * ipa2_mhi_init() was called and can be called after MHI reset to restart MHI
- * engine. When this function returns device can move to M0 state.
- * This function is doing the following:
- *     - Send command to uC for initialization of MHI engine
- *     - Add dependencies to IPA RM
- *     - Request MHI_PROD in IPA RM
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa2_mhi_start(struct ipa_mhi_start_params *params)
+int ipa2_mhi_init_engine(struct ipa_mhi_init_engine *params)
 {
        int res;
 
@@ -1102,57 +106,23 @@ int ipa2_mhi_start(struct ipa_mhi_start_params *params)
                return -EINVAL;
        }
 
-       if (unlikely(!ipa_mhi_ctx)) {
-               IPA_MHI_ERR("IPA MHI was not initialized\n");
-               return -EINVAL;
-       }
-
-       if (ipa_uc_state_check()) {
+       if (ipa2_uc_state_check()) {
                IPA_MHI_ERR("IPA uc is not loaded\n");
                return -EAGAIN;
        }
 
-       res = ipa_mhi_set_state(IPA_MHI_STATE_STARTED);
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_set_state %d\n", res);
-               return res;
-       }
-
-       ipa_mhi_ctx->host_ctrl_addr = params->host_ctrl_addr;
-       ipa_mhi_ctx->host_data_addr = params->host_data_addr;
-
-       /* Add MHI <-> Q6 dependencies to IPA RM */
-       res = ipa_rm_add_dependency(IPA_RM_RESOURCE_MHI_PROD,
-               IPA_RM_RESOURCE_Q6_CONS);
-       if (res && res != -EINPROGRESS) {
-               IPA_MHI_ERR("failed to add dependency %d\n", res);
-               goto fail_add_mhi_q6_dep;
-       }
-
-       res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
-               IPA_RM_RESOURCE_MHI_CONS);
-       if (res && res != -EINPROGRESS) {
-               IPA_MHI_ERR("failed to add dependency %d\n", res);
-               goto fail_add_q6_mhi_dep;
-       }
-
-       res = ipa_mhi_request_prod();
-       if (res) {
-               IPA_MHI_ERR("failed request prod %d\n", res);
-               goto fail_request_prod;
-       }
-
        /* Initialize IPA MHI engine */
-       res = ipa_uc_mhi_init_engine(&ipa_mhi_ctx->msi, ipa_mhi_ctx->mmio_addr,
-               ipa_mhi_ctx->host_ctrl_addr, ipa_mhi_ctx->host_data_addr,
-               ipa_mhi_ctx->first_ch_idx, ipa_mhi_ctx->first_er_idx);
+       res = ipa_uc_mhi_init_engine(params->uC.msi, params->uC.mmio_addr,
+               params->uC.host_ctrl_addr, params->uC.host_data_addr,
+               params->uC.first_ch_idx, params->uC.first_er_idx);
        if (res) {
                IPA_MHI_ERR("failed to start MHI engine %d\n", res);
                goto fail_init_engine;
        }
 
        /* Update UL/DL sync if valid */
-       res = ipa_uc_mhi_send_dl_ul_sync_info(cached_dl_ul_sync_info);
+       res = ipa2_uc_mhi_send_dl_ul_sync_info(
+               params->uC.ipa_cached_dl_ul_sync_info);
        if (res) {
                IPA_MHI_ERR("failed to update ul/dl sync %d\n", res);
                goto fail_init_engine;
@@ -1162,25 +132,16 @@ int ipa2_mhi_start(struct ipa_mhi_start_params *params)
        return 0;
 
 fail_init_engine:
-       ipa_mhi_release_prod();
-fail_request_prod:
-       ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
-               IPA_RM_RESOURCE_MHI_CONS);
-fail_add_q6_mhi_dep:
-       ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
-               IPA_RM_RESOURCE_Q6_CONS);
-fail_add_mhi_q6_dep:
-       ipa_mhi_set_state(IPA_MHI_STATE_INITIALIZED);
        return res;
 }
 
 /**
- * ipa2_mhi_connect_pipe() - Connect pipe to IPA and start corresponding
+ * ipa2_connect_mhi_pipe() - Connect pipe to IPA and start corresponding
  * MHI channel
  * @in: connect parameters
  * @clnt_hdl: [out] client handle for this pipe
  *
- * This function is called by MHI client driver on MHI channel start.
+ * This function is called by IPA MHI client driver on MHI channel start.
  * This function is called after MHI engine was started.
  * This function is doing the following:
  *     - Send command to uC to start corresponding MHI channel
@@ -1189,13 +150,12 @@ fail_add_mhi_q6_dep:
  * Return codes: 0       : success
  *              negative : error
  */
-int ipa2_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl)
+int ipa2_connect_mhi_pipe(struct ipa_mhi_connect_params_internal *in,
+               u32 *clnt_hdl)
 {
        struct ipa_ep_context *ep;
        int ipa_ep_idx;
        int res;
-       struct ipa_mhi_channel_ctx *channel = NULL;
-       unsigned long flags;
 
        IPA_MHI_FUNC_ENTRY();
 
@@ -1204,25 +164,12 @@ int ipa2_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl)
                return -EINVAL;
        }
 
-       if (in->sys.client >= IPA_CLIENT_MAX) {
-               IPA_MHI_ERR("bad parm client:%d\n", in->sys.client);
+       if (in->sys->client >= IPA_CLIENT_MAX) {
+               IPA_MHI_ERR("bad parm client:%d\n", in->sys->client);
                return -EINVAL;
        }
 
-       if (unlikely(!ipa_mhi_ctx)) {
-               IPA_MHI_ERR("IPA MHI was not initialized\n");
-               return -EINVAL;
-       }
-
-       spin_lock_irqsave(&ipa_mhi_ctx->state_lock, flags);
-       if (!ipa_mhi_ctx || ipa_mhi_ctx->state != IPA_MHI_STATE_STARTED) {
-               IPA_MHI_ERR("IPA MHI was not started\n");
-               spin_unlock_irqrestore(&ipa_mhi_ctx->state_lock, flags);
-               return -EINVAL;
-       }
-       spin_unlock_irqrestore(&ipa_mhi_ctx->state_lock, flags);
-
-       ipa_ep_idx = ipa2_get_ep_mapping(in->sys.client);
+       ipa_ep_idx = ipa2_get_ep_mapping(in->sys->client);
        if (ipa_ep_idx == -1) {
                IPA_MHI_ERR("Invalid client.\n");
                return -EINVAL;
@@ -1230,17 +177,8 @@ int ipa2_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl)
 
        ep = &ipa_ctx->ep[ipa_ep_idx];
 
-       channel = ipa_mhi_get_channel_context(in->sys.client,
-               in->channel_id);
-       if (!channel) {
-               IPA_MHI_ERR("ipa_mhi_get_channel_context failed\n");
-               return -EINVAL;
-       }
-
        IPA_MHI_DBG("client %d channelHandle %d channelIndex %d\n",
-               channel->client, channel->hdl, channel->id);
-
-       IPA_ACTIVE_CLIENTS_INC_EP(in->sys.client);
+               in->sys->client, in->start.uC.index, in->start.uC.id);
 
        if (ep->valid == 1) {
                IPA_MHI_ERR("EP already allocated.\n");
@@ -1249,40 +187,34 @@ int ipa2_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl)
 
        memset(ep, 0, offsetof(struct ipa_ep_context, sys));
        ep->valid = 1;
-       ep->skip_ep_cfg = in->sys.skip_ep_cfg;
-       ep->client = in->sys.client;
-       ep->client_notify = in->sys.notify;
-       ep->priv = in->sys.priv;
-       ep->keep_ipa_awake = in->sys.keep_ipa_awake;
+       ep->skip_ep_cfg = in->sys->skip_ep_cfg;
+       ep->client = in->sys->client;
+       ep->client_notify = in->sys->notify;
+       ep->priv = in->sys->priv;
+       ep->keep_ipa_awake = in->sys->keep_ipa_awake;
 
        /* start channel in uC */
-       if (channel->state == IPA_HW_MHI_CHANNEL_STATE_INVALID) {
+       if (in->start.uC.state == IPA_HW_MHI_CHANNEL_STATE_INVALID) {
                IPA_MHI_DBG("Initializing channel\n");
-               res = ipa_uc_mhi_init_channel(ipa_ep_idx, channel->hdl,
-                       channel->id, (IPA_CLIENT_IS_PROD(ep->client) ? 1 : 2));
+               res = ipa_uc_mhi_init_channel(ipa_ep_idx, in->start.uC.index,
+                       in->start.uC.id,
+                       (IPA_CLIENT_IS_PROD(ep->client) ? 1 : 2));
                if (res) {
                        IPA_MHI_ERR("init_channel failed %d\n", res);
                        goto fail_init_channel;
                }
-       } else if (channel->state == IPA_HW_MHI_CHANNEL_STATE_DISABLE) {
-               if (channel->client != ep->client) {
-                       IPA_MHI_ERR("previous channel client was %d\n",
-                               ep->client);
-                       goto fail_init_channel;
-               }
+       } else if (in->start.uC.state == IPA_HW_MHI_CHANNEL_STATE_DISABLE) {
                IPA_MHI_DBG("Starting channel\n");
-               res = ipa_uc_mhi_resume_channel(channel->hdl, false);
+               res = ipa_uc_mhi_resume_channel(in->start.uC.index, false);
                if (res) {
                        IPA_MHI_ERR("init_channel failed %d\n", res);
                        goto fail_init_channel;
                }
        } else {
-               IPA_MHI_ERR("Invalid channel state %d\n", channel->state);
+               IPA_MHI_ERR("Invalid channel state %d\n", in->start.uC.state);
                goto fail_init_channel;
        }
 
-       channel->state = IPA_HW_MHI_CHANNEL_STATE_RUN;
-
        res = ipa_enable_data_path(ipa_ep_idx);
        if (res) {
                IPA_MHI_ERR("enable data path failed res=%d clnt=%d.\n", res,
@@ -1291,7 +223,7 @@ int ipa2_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl)
        }
 
        if (!ep->skip_ep_cfg) {
-               if (ipa2_cfg_ep(ipa_ep_idx, &in->sys.ipa_ep_cfg)) {
+               if (ipa2_cfg_ep(ipa_ep_idx, &in->sys->ipa_ep_cfg)) {
                        IPAERR("fail to configure EP.\n");
                        goto fail_ep_cfg;
                }
@@ -1306,14 +238,11 @@ int ipa2_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl)
 
        *clnt_hdl = ipa_ep_idx;
 
-       if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->sys.client))
+       if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->sys->client))
                ipa_install_dflt_flt_rules(ipa_ep_idx);
 
-       if (!ep->keep_ipa_awake)
-               IPA_ACTIVE_CLIENTS_DEC_EP(in->sys.client);
-
        ipa_ctx->skip_ep_cfg_shadow[ipa_ep_idx] = ep->skip_ep_cfg;
-       IPA_MHI_DBG("client %d (ep: %d) connected\n", in->sys.client,
+       IPA_MHI_DBG("client %d (ep: %d) connected\n", in->sys->client,
                ipa_ep_idx);
 
        IPA_MHI_FUNC_EXIT();
@@ -1323,22 +252,20 @@ int ipa2_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl)
 fail_ep_cfg:
        ipa_disable_data_path(ipa_ep_idx);
 fail_enable_dp:
-       ipa_uc_mhi_reset_channel(channel->hdl);
-       channel->state = IPA_HW_MHI_CHANNEL_STATE_DISABLE;
+       ipa_uc_mhi_reset_channel(in->start.uC.index);
 fail_init_channel:
        memset(ep, 0, offsetof(struct ipa_ep_context, sys));
 fail_ep_exists:
-       IPA_ACTIVE_CLIENTS_DEC_EP(in->sys.client);
        return -EPERM;
 }
 
 /**
- * ipa2_mhi_disconnect_pipe() - Disconnect pipe from IPA and reset corresponding
+ * ipa2_disconnect_mhi_pipe() - Disconnect pipe from IPA and reset corresponding
  * MHI channel
  * @in: connect parameters
  * @clnt_hdl: [out] client handle for this pipe
  *
- * This function is called by MHI client driver on MHI channel reset.
+ * This function is called by IPA MHI client driver on MHI channel reset.
  * This function is called after MHI channel was started.
  * This function is doing the following:
  *     - Send command to uC to reset corresponding MHI channel
@@ -1347,11 +274,9 @@ fail_ep_exists:
  * Return codes: 0       : success
  *              negative : error
  */
-int ipa2_mhi_disconnect_pipe(u32 clnt_hdl)
+int ipa2_disconnect_mhi_pipe(u32 clnt_hdl)
 {
        struct ipa_ep_context *ep;
-       static struct ipa_mhi_channel_ctx *channel;
-       int res;
 
        IPA_MHI_FUNC_ENTRY();
 
@@ -1365,492 +290,29 @@ int ipa2_mhi_disconnect_pipe(u32 clnt_hdl)
                return -EINVAL;
        }
 
-       if (unlikely(!ipa_mhi_ctx)) {
-               IPA_MHI_ERR("IPA MHI was not initialized\n");
-               return -EINVAL;
-       }
-
-       channel = ipa_mhi_get_channel_context_by_clnt_hdl(clnt_hdl);
-       if (!channel) {
-               IPAERR("invalid clnt hdl\n");
-               return -EINVAL;
-       }
-
-       ep = &ipa_ctx->ep[clnt_hdl];
-
-       if (!ep->keep_ipa_awake)
-               IPA_ACTIVE_CLIENTS_INC_EP(ipa2_get_client_mapping(clnt_hdl));
-
-       res = ipa_mhi_reset_channel(channel);
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_reset_channel failed %d\n", res);
-               goto fail_reset_channel;
-       }
-
        ep->valid = 0;
        ipa_delete_dflt_flt_rules(clnt_hdl);
 
-       IPA_ACTIVE_CLIENTS_DEC_EP(ipa2_get_client_mapping(clnt_hdl));
-
        IPA_MHI_DBG("client (ep: %d) disconnected\n", clnt_hdl);
        IPA_MHI_FUNC_EXIT();
        return 0;
-
-fail_reset_channel:
-       if (!ep->keep_ipa_awake)
-               IPA_ACTIVE_CLIENTS_DEC_EP(ipa2_get_client_mapping(clnt_hdl));
-       return res;
-}
-
-static int ipa_mhi_suspend_ul_channels(void)
-{
-       int i;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               if (!ipa_mhi_ctx->ul_channels[i].valid)
-                       continue;
-               if (ipa_mhi_ctx->ul_channels[i].state !=
-                   IPA_HW_MHI_CHANNEL_STATE_RUN)
-                       continue;
-               IPA_MHI_DBG("suspending channel %d\n",
-                       ipa_mhi_ctx->ul_channels[i].hdl);
-               res = ipa_uc_mhi_suspend_channel(
-                       ipa_mhi_ctx->ul_channels[i].hdl);
-               if (res) {
-                       IPA_MHI_ERR("failed to suspend channel %d error %d\n",
-                               i, res);
-                       return res;
-               }
-               ipa_mhi_ctx->ul_channels[i].state =
-                       IPA_HW_MHI_CHANNEL_STATE_SUSPEND;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa_mhi_resume_ul_channels(bool LPTransitionRejected)
-{
-       int i;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               if (!ipa_mhi_ctx->ul_channels[i].valid)
-                       continue;
-               if (ipa_mhi_ctx->ul_channels[i].state !=
-                   IPA_HW_MHI_CHANNEL_STATE_SUSPEND)
-                       continue;
-               IPA_MHI_DBG("suspending channel %d\n",
-                       ipa_mhi_ctx->ul_channels[i].hdl);
-               res = ipa_uc_mhi_resume_channel(ipa_mhi_ctx->ul_channels[i].hdl,
-                       LPTransitionRejected);
-               if (res) {
-                       IPA_MHI_ERR("failed to suspend channel %d error %d\n",
-                               i, res);
-                       return res;
-               }
-               ipa_mhi_ctx->ul_channels[i].state =
-                       IPA_HW_MHI_CHANNEL_STATE_RUN;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa_mhi_stop_event_update_ul_channels(void)
-{
-       int i;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               if (!ipa_mhi_ctx->ul_channels[i].valid)
-                       continue;
-               if (ipa_mhi_ctx->ul_channels[i].state !=
-                   IPA_HW_MHI_CHANNEL_STATE_SUSPEND)
-                       continue;
-               IPA_MHI_DBG("stop update event channel %d\n",
-                       ipa_mhi_ctx->ul_channels[i].hdl);
-               res = ipa_uc_mhi_stop_event_update_channel(
-                       ipa_mhi_ctx->ul_channels[i].hdl);
-               if (res) {
-                       IPA_MHI_ERR("failed stop event channel %d error %d\n",
-                               i, res);
-                       return res;
-               }
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa_mhi_suspend_dl_channels(void)
-{
-       int i;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-               if (!ipa_mhi_ctx->dl_channels[i].valid)
-                       continue;
-               if (ipa_mhi_ctx->dl_channels[i].state !=
-                   IPA_HW_MHI_CHANNEL_STATE_RUN)
-                       continue;
-               IPA_MHI_DBG("suspending channel %d\n",
-                       ipa_mhi_ctx->dl_channels[i].hdl);
-               res = ipa_uc_mhi_suspend_channel(
-                       ipa_mhi_ctx->dl_channels[i].hdl);
-               if (res) {
-                       IPA_MHI_ERR("failed to suspend channel %d error %d\n",
-                               i, res);
-                       return res;
-               }
-               ipa_mhi_ctx->dl_channels[i].state =
-                       IPA_HW_MHI_CHANNEL_STATE_SUSPEND;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa_mhi_resume_dl_channels(bool LPTransitionRejected)
-{
-       int i;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-               if (!ipa_mhi_ctx->dl_channels[i].valid)
-                       continue;
-               if (ipa_mhi_ctx->dl_channels[i].state !=
-                   IPA_HW_MHI_CHANNEL_STATE_SUSPEND)
-                       continue;
-               IPA_MHI_DBG("suspending channel %d\n",
-                       ipa_mhi_ctx->dl_channels[i].hdl);
-               res = ipa_uc_mhi_resume_channel(ipa_mhi_ctx->dl_channels[i].hdl,
-                       LPTransitionRejected);
-               if (res) {
-                       IPA_MHI_ERR("failed to suspend channel %d error %d\n",
-                               i, res);
-                       return res;
-               }
-               ipa_mhi_ctx->dl_channels[i].state =
-                       IPA_HW_MHI_CHANNEL_STATE_RUN;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
 }
 
-static int ipa_mhi_stop_event_update_dl_channels(void)
+int ipa2_mhi_resume_channels_internal(enum ipa_client_type client,
+               bool LPTransitionRejected, bool brstmode_enabled,
+               union __packed gsi_channel_scratch ch_scratch, u8 index)
 {
        int i;
        int res;
 
        IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-               if (!ipa_mhi_ctx->dl_channels[i].valid)
-                       continue;
-               if (ipa_mhi_ctx->dl_channels[i].state !=
-                   IPA_HW_MHI_CHANNEL_STATE_SUSPEND)
-                       continue;
-               IPA_MHI_DBG("stop update event channel %d\n",
-                       ipa_mhi_ctx->dl_channels[i].hdl);
-               res = ipa_uc_mhi_stop_event_update_channel(
-                       ipa_mhi_ctx->dl_channels[i].hdl);
-               if (res) {
-                       IPA_MHI_ERR("failed stop event channel %d error %d\n",
-                               i, res);
-                       return res;
-               }
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-/**
- * ipa2_mhi_suspend() - Suspend MHI accelerated channels
- * @force:
- *     false: in case of data pending in IPA, MHI channels will not be
- *             suspended and function will fail.
- *     true:  in case of data pending in IPA, make sure no further access from
- *             IPA to PCIe is possible. In this case suspend cannot fail.
- *
- * This function is called by MHI client driver on MHI suspend.
- * This function is called after MHI channel was started.
- * When this function returns device can move to M1/M2/M3/D3cold state.
- * This function is doing the following:
- *     - Send command to uC to suspend corresponding MHI channel
- *     - Make sure no further access is possible from IPA to PCIe
- *     - Release MHI_PROD in IPA RM
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa2_mhi_suspend(bool force)
-{
-       int res;
-       bool bam_empty;
-       bool force_clear = false;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       if (unlikely(!ipa_mhi_ctx)) {
-               IPA_MHI_ERR("IPA MHI was not initialized\n");
-               return -EINVAL;
-       }
-
-       res = ipa_mhi_set_state(IPA_MHI_STATE_SUSPEND_IN_PROGRESS);
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_set_state failed %d\n", res);
-               return res;
-       }
-
-       res = ipa_mhi_suspend_ul_channels();
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_suspend_ul_channels failed %d\n", res);
-               goto fail_suspend_ul_channel;
-       }
-
-       bam_empty = ipa_mhi_wait_for_bam_empty_timeout(
-               IPA_MHI_BAM_EMPTY_TIMEOUT_MSEC);
-       if (!bam_empty) {
-               if (force) {
-                       res = ipa_mhi_enable_force_clear(
-                               ipa_mhi_ctx->qmi_req_id, false);
-                       if (res) {
-                               IPA_MHI_ERR("failed to enable force clear\n");
-                               BUG();
-                               return res;
-                       }
-                       force_clear = true;
-                       IPA_MHI_DBG("force clear datapath enabled\n");
-
-                       bam_empty = ipa_mhi_wait_for_bam_empty_timeout(
-                               IPA_MHI_BAM_EMPTY_TIMEOUT_MSEC);
-                       IPADBG("bam_empty=%d\n", bam_empty);
-
-               } else {
-                       IPA_MHI_DBG("BAM not empty\n");
-                       res = -EAGAIN;
-                       goto fail_suspend_ul_channel;
-               }
-       }
-
-       res = ipa_mhi_stop_event_update_ul_channels();
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_stop_event_update_ul_channels failed %d\n",
-                       res);
-               goto fail_suspend_ul_channel;
-       }
-
-       /*
-        * in case BAM not empty, hold IPA clocks and release them after all
-        * IPA RM resource are released to make sure tag process will not start
-        */
-       if (!bam_empty)
-               IPA_ACTIVE_CLIENTS_INC_SIMPLE();
-
-       IPA_MHI_DBG("release prod\n");
-       res = ipa_mhi_release_prod();
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_release_prod failed %d\n", res);
-               goto fail_release_prod;
-       }
-
-       IPA_MHI_DBG("wait for cons release\n");
-       res = ipa_mhi_wait_for_cons_release();
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_wait_for_cons_release failed %d\n", res);
-               goto fail_release_cons;
-       }
-
-       usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX);
-
-       res = ipa_mhi_suspend_dl_channels();
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_suspend_dl_channels failed %d\n", res);
-               goto fail_suspend_dl_channel;
-       }
-
-       res = ipa_mhi_stop_event_update_dl_channels();
-       if (res) {
-               IPA_MHI_ERR("failed to stop event update on DL %d\n", res);
-               goto fail_stop_event_update_dl_channel;
-       }
-
-       if (force_clear) {
-               res = ipa_mhi_disable_force_clear(ipa_mhi_ctx->qmi_req_id);
-               if (res) {
-                       IPA_MHI_ERR("failed to disable force clear\n");
-                       BUG();
-                       return res;
-               }
-               IPA_MHI_DBG("force clear datapath disabled\n");
-               ipa_mhi_ctx->qmi_req_id++;
-       }
-
-       if (!bam_empty) {
-               ipa_ctx->tag_process_before_gating = false;
-               IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
-       }
-
-       res = ipa_mhi_set_state(IPA_MHI_STATE_SUSPENDED);
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_set_state failed %d\n", res);
-               goto fail_release_cons;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-
-fail_stop_event_update_dl_channel:
-       ipa_mhi_resume_dl_channels(true);
-fail_suspend_dl_channel:
-fail_release_cons:
-       ipa_mhi_request_prod();
-fail_release_prod:
-fail_suspend_ul_channel:
-       ipa_mhi_resume_ul_channels(true);
-       ipa_mhi_set_state(IPA_MHI_STATE_STARTED);
-       return res;
-}
-
-/**
- * ipa2_mhi_resume() - Resume MHI accelerated channels
- *
- * This function is called by MHI client driver on MHI resume.
- * This function is called after MHI channel was suspended.
- * When this function returns device can move to M0 state.
- * This function is doing the following:
- *     - Send command to uC to resume corresponding MHI channel
- *     - Request MHI_PROD in IPA RM
- *     - Resume data to IPA
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa2_mhi_resume(void)
-{
-       int res;
-       bool dl_channel_resumed = false;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       if (unlikely(!ipa_mhi_ctx)) {
-               IPA_MHI_ERR("IPA MHI was not initialized\n");
-               return -EINVAL;
-       }
-
-       res = ipa_mhi_set_state(IPA_MHI_STATE_RESUME_IN_PROGRESS);
+       res = ipa_uc_mhi_resume_channel(index, LPTransitionRejected);
        if (res) {
-               IPA_MHI_ERR("ipa_mhi_set_state failed %d\n", res);
+               IPA_MHI_ERR("failed to suspend channel %d error %d\n",
+                       i, res);
                return res;
        }
 
-       if (ipa_mhi_ctx->rm_cons_state == IPA_MHI_RM_STATE_REQUESTED) {
-               /* resume all DL channels */
-               res = ipa_mhi_resume_dl_channels(false);
-               if (res) {
-                       IPA_MHI_ERR("ipa_mhi_resume_dl_channels failed %d\n",
-                               res);
-                       goto fail_resume_dl_channels;
-               }
-               dl_channel_resumed = true;
-
-               ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
-                       IPA_RM_RESOURCE_MHI_CONS);
-               ipa_mhi_ctx->rm_cons_state = IPA_MHI_RM_STATE_GRANTED;
-       }
-
-       res = ipa_mhi_request_prod();
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_request_prod failed %d\n", res);
-               goto fail_request_prod;
-       }
-
-       /* resume all UL channels */
-       res = ipa_mhi_resume_ul_channels(false);
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_resume_ul_channels failed %d\n", res);
-               goto fail_resume_ul_channels;
-       }
-
-       if (!dl_channel_resumed) {
-               res = ipa_mhi_resume_dl_channels(true);
-               if (res) {
-                       IPA_MHI_ERR("ipa_mhi_resume_dl_channels failed %d\n",
-                               res);
-                       goto fail_resume_dl_channels2;
-               }
-       }
-
-       res = ipa_mhi_set_state(IPA_MHI_STATE_STARTED);
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_set_state failed %d\n", res);
-               goto fail_set_state;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-
-fail_set_state:
-       ipa_mhi_suspend_dl_channels();
-fail_resume_dl_channels2:
-       ipa_mhi_suspend_ul_channels();
-fail_resume_ul_channels:
-       ipa_mhi_release_prod();
-fail_request_prod:
-       ipa_mhi_suspend_dl_channels();
-fail_resume_dl_channels:
-       ipa_mhi_set_state(IPA_MHI_STATE_SUSPENDED);
-       return res;
-}
-
-
-/**
- * ipa2_mhi_destroy() - Destroy MHI IPA
- *
- * This function is called by MHI client driver on MHI reset to destroy all IPA
- * MHI resources.
- */
-void ipa2_mhi_destroy(void)
-{
-       IPA_MHI_FUNC_ENTRY();
-
-       if (unlikely(!ipa_mhi_ctx)) {
-               IPA_MHI_ERR("IPA MHI was not initialized\n");
-               return;
-       }
-
-       IPAERR("Not implemented Yet!\n");
-       ipa_mhi_debugfs_destroy();
-
-       IPA_MHI_FUNC_EXIT();
-}
-
-/**
- * ipa_mhi_handle_ipa_config_req() - hanle IPA CONFIG QMI message
- *
- * This function is called by by IPA QMI service to indicate that IPA CONFIG
- * message was sent from modem. IPA MHI will update this information to IPA uC
- * or will cache it until IPA MHI will be initialized.
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa_mhi_handle_ipa_config_req(struct ipa_config_req_msg_v01 *config_req)
-{
-       IPA_MHI_FUNC_ENTRY();
-       ipa_mhi_cache_dl_ul_sync_info(config_req);
-
-       if (ipa_mhi_ctx && ipa_mhi_ctx->state != IPA_MHI_STATE_INITIALIZED)
-               ipa_uc_mhi_send_dl_ul_sync_info(cached_dl_ul_sync_info);
-
        IPA_MHI_FUNC_EXIT();
        return 0;
 }
index 00f1833..d5d2abe 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "ipa_qmi_service.h"
 #include "ipa_ram_mmap.h"
+#include "../ipa_common_i.h"
 
 #define IPA_Q6_SVC_VERS 1
 #define IPA_A5_SVC_VERS 1
index d529622..13db6b0 100644 (file)
@@ -284,13 +284,13 @@ bad_uc_top_ofst:
 }
 
 /**
- * ipa_uc_state_check() - Check the status of the uC interface
+ * ipa2_uc_state_check() - Check the status of the uC interface
  *
  * Return value: 0 if the uC is loaded, interface is initialized
  *               and there was no recent failure in one of the commands.
  *               A negative value is returned otherwise.
  */
-int ipa_uc_state_check(void)
+int ipa2_uc_state_check(void)
 {
        if (!ipa_ctx->uc_ctx.uc_inited) {
                IPAERR("uC interface not initialized\n");
@@ -309,7 +309,7 @@ int ipa_uc_state_check(void)
 
        return 0;
 }
-EXPORT_SYMBOL(ipa_uc_state_check);
+EXPORT_SYMBOL(ipa2_uc_state_check);
 
 /**
  * ipa_uc_loaded_check() - Check the uC has been loaded
@@ -384,7 +384,7 @@ static int ipa_uc_panic_notifier(struct notifier_block *this,
 
        IPADBG("this=%p evt=%lu ptr=%p\n", this, event, ptr);
 
-       result = ipa_uc_state_check();
+       result = ipa2_uc_state_check();
        if (result)
                goto fail;
        IPA_ACTIVE_CLIENTS_PREP_SIMPLE(log_info);
@@ -593,7 +593,7 @@ int ipa_uc_send_cmd(u32 cmd, u32 opcode, u32 expected_status,
 
        mutex_lock(&ipa_ctx->uc_ctx.uc_lock);
 
-       if (ipa_uc_state_check()) {
+       if (ipa2_uc_state_check()) {
                IPADBG("uC send command aborted\n");
                mutex_unlock(&ipa_ctx->uc_ctx.uc_lock);
                return -EBADF;
@@ -727,7 +727,7 @@ int ipa_uc_reset_pipe(enum ipa_client_type ipa_client)
         * continue with the sequence without resetting the
         * pipe.
         */
-       if (ipa_uc_state_check()) {
+       if (ipa2_uc_state_check()) {
                IPADBG("uC interface will not be used to reset %s pipe %d\n",
                       IPA_CLIENT_IS_PROD(ipa_client) ? "CONS" : "PROD",
                       ep_idx);
@@ -785,7 +785,7 @@ int ipa_uc_monitor_holb(enum ipa_client_type ipa_client, bool enable)
         * continue with the sequence without resetting the
         * pipe.
         */
-       if (ipa_uc_state_check()) {
+       if (ipa2_uc_state_check()) {
                IPADBG("uC interface will not be used to reset %s pipe %d\n",
                       IPA_CLIENT_IS_PROD(ipa_client) ? "CONS" : "PROD",
                       ep_idx);
@@ -849,7 +849,7 @@ int ipa_uc_notify_clk_state(bool enabled)
         * If the uC interface has not been initialized yet,
         * don't notify the uC on the enable/disable
         */
-       if (ipa_uc_state_check()) {
+       if (ipa2_uc_state_check()) {
                IPADBG("uC interface will not notify the UC on clock state\n");
                return 0;
        }
index ec3814b..08d7363 100644 (file)
@@ -571,7 +571,7 @@ static void ipa_uc_mhi_event_log_info_hdlr(
        }
 }
 
-int ipa_uc_mhi_init(void (*ready_cb)(void), void (*wakeup_request_cb)(void))
+int ipa2_uc_mhi_init(void (*ready_cb)(void), void (*wakeup_request_cb)(void))
 {
        struct ipa_uc_hdlrs hdlrs;
 
@@ -600,6 +600,23 @@ int ipa_uc_mhi_init(void (*ready_cb)(void), void (*wakeup_request_cb)(void))
        return 0;
 }
 
+void ipa2_uc_mhi_cleanup(void)
+{
+       struct ipa_uc_hdlrs null_hdlrs = { 0 };
+
+       IPADBG("Enter\n");
+
+       if (!ipa_uc_mhi_ctx) {
+               IPAERR("ipa3_uc_mhi_ctx is not initialized\n");
+               return;
+       }
+       ipa_uc_register_handlers(IPA_HW_FEATURE_MHI, &null_hdlrs);
+       kfree(ipa_uc_mhi_ctx);
+       ipa_uc_mhi_ctx = NULL;
+
+       IPADBG("Done\n");
+}
+
 int ipa_uc_mhi_init_engine(struct ipa_mhi_msi_info *msi, u32 mmio_addr,
        u32 host_ctrl_addr, u32 host_data_addr, u32 first_ch_idx,
        u32 first_evt_idx)
@@ -730,7 +747,7 @@ disable_clks:
 }
 
 
-int ipa_uc_mhi_reset_channel(int channelHandle)
+int ipa2_uc_mhi_reset_channel(int channelHandle)
 {
        union IpaHwMhiChangeChannelStateCmdData_t cmd;
        union IpaHwMhiChangeChannelStateResponseData_t uc_rsp;
@@ -767,7 +784,7 @@ disable_clks:
        return res;
 }
 
-int ipa_uc_mhi_suspend_channel(int channelHandle)
+int ipa2_uc_mhi_suspend_channel(int channelHandle)
 {
        union IpaHwMhiChangeChannelStateCmdData_t cmd;
        union IpaHwMhiChangeChannelStateResponseData_t uc_rsp;
@@ -842,7 +859,7 @@ disable_clks:
        return res;
 }
 
-int ipa_uc_mhi_stop_event_update_channel(int channelHandle)
+int ipa2_uc_mhi_stop_event_update_channel(int channelHandle)
 {
        union IpaHwMhiStopEventUpdateData_t cmd;
        int res;
@@ -874,7 +891,7 @@ disable_clks:
        return res;
 }
 
-int ipa_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t cmd)
+int ipa2_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t *cmd)
 {
        int res;
 
@@ -884,13 +901,14 @@ int ipa_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t cmd)
        }
 
        IPADBG("isDlUlSyncEnabled=0x%x UlAccmVal=0x%x\n",
-               cmd.params.isDlUlSyncEnabled, cmd.params.UlAccmVal);
+               cmd->params.isDlUlSyncEnabled, cmd->params.UlAccmVal);
        IPADBG("ulMsiEventThreshold=0x%x dlMsiEventThreshold=0x%x\n",
-               cmd.params.ulMsiEventThreshold, cmd.params.dlMsiEventThreshold);
+               cmd->params.ulMsiEventThreshold,
+               cmd->params.dlMsiEventThreshold);
 
        IPA_ACTIVE_CLIENTS_INC_SIMPLE();
 
-       res = ipa_uc_send_cmd(cmd.raw32b,
+       res = ipa_uc_send_cmd(cmd->raw32b,
                IPA_CPU_2_HW_CMD_MHI_DL_UL_SYNC_INFO, 0, false, HZ);
        if (res) {
                IPAERR("ipa_uc_send_cmd failed %d\n", res);
@@ -903,7 +921,7 @@ disable_clks:
        return res;
 }
 
-int ipa_uc_mhi_print_stats(char *dbg_buff, int size)
+int ipa2_uc_mhi_print_stats(char *dbg_buff, int size)
 {
        int nBytes = 0;
        int i;
index 40e856b..8ba4f04 100644 (file)
@@ -738,7 +738,7 @@ int ipa2_connect_wdi_pipe(struct ipa_wdi_in_params *in,
                }
        }
 
-       result = ipa_uc_state_check();
+       result = ipa2_uc_state_check();
        if (result)
                return result;
 
@@ -1005,7 +1005,7 @@ int ipa2_disconnect_wdi_pipe(u32 clnt_hdl)
                return -EINVAL;
        }
 
-       result = ipa_uc_state_check();
+       result = ipa2_uc_state_check();
        if (result)
                return result;
 
@@ -1071,7 +1071,7 @@ int ipa2_enable_wdi_pipe(u32 clnt_hdl)
                return -EINVAL;
        }
 
-       result = ipa_uc_state_check();
+       result = ipa2_uc_state_check();
        if (result)
                return result;
 
@@ -1139,7 +1139,7 @@ int ipa2_disable_wdi_pipe(u32 clnt_hdl)
                return -EINVAL;
        }
 
-       result = ipa_uc_state_check();
+       result = ipa2_uc_state_check();
        if (result)
                return result;
 
@@ -1239,7 +1239,7 @@ int ipa2_resume_wdi_pipe(u32 clnt_hdl)
                return -EINVAL;
        }
 
-       result = ipa_uc_state_check();
+       result = ipa2_uc_state_check();
        if (result)
                return result;
 
@@ -1306,7 +1306,7 @@ int ipa2_suspend_wdi_pipe(u32 clnt_hdl)
                return -EINVAL;
        }
 
-       result = ipa_uc_state_check();
+       result = ipa2_uc_state_check();
        if (result)
                return result;
 
@@ -1388,7 +1388,7 @@ int ipa_write_qmapid_wdi_pipe(u32 clnt_hdl, u8 qmap_id)
                return -EINVAL;
        }
 
-       result = ipa_uc_state_check();
+       result = ipa2_uc_state_check();
        if (result)
                return result;
 
@@ -1447,7 +1447,7 @@ int ipa2_uc_reg_rdyCB(
                return -EINVAL;
        }
 
-       result = ipa_uc_state_check();
+       result = ipa2_uc_state_check();
        if (result) {
                inout->is_uC_ready = false;
                ipa_ctx->uc_wdi_ctx.uc_ready_cb = inout->notify;
index 6fd9b4e..9fc6754 100644 (file)
@@ -4948,6 +4948,26 @@ static void *ipa2_get_ipc_logbuf_low(void)
        return NULL;
 }
 
+static void ipa2_get_holb(int ep_idx, struct ipa_ep_cfg_holb *holb)
+{
+       *holb = ipa_ctx->ep[ep_idx].holb;
+}
+
+static int ipa2_generate_tag_process(void)
+{
+       int res;
+
+       res = ipa_tag_process(NULL, 0, HZ);
+       if (res)
+               IPAERR("TAG process failed\n");
+
+       return res;
+}
+
+static void ipa2_set_tag_process_before_gating(bool val)
+{
+       ipa_ctx->tag_process_before_gating = val;
+}
 
 int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
        struct ipa_api_controller *api_ctrl)
@@ -4971,6 +4991,9 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
        api_ctrl->ipa_cfg_ep_deaggr = ipa2_cfg_ep_deaggr;
        api_ctrl->ipa_cfg_ep_route = ipa2_cfg_ep_route;
        api_ctrl->ipa_cfg_ep_holb = ipa2_cfg_ep_holb;
+       api_ctrl->ipa_get_holb = ipa2_get_holb;
+       api_ctrl->ipa_set_tag_process_before_gating =
+                       ipa2_set_tag_process_before_gating;
        api_ctrl->ipa_cfg_ep_cfg = ipa2_cfg_ep_cfg;
        api_ctrl->ipa_cfg_ep_metadata_mask = ipa2_cfg_ep_metadata_mask;
        api_ctrl->ipa_cfg_ep_holb_by_client = ipa2_cfg_ep_holb_by_client;
@@ -5044,13 +5067,32 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type,
        api_ctrl->ipa_dma_async_memcpy = ipa2_dma_async_memcpy;
        api_ctrl->ipa_dma_uc_memcpy = ipa2_dma_uc_memcpy;
        api_ctrl->ipa_dma_destroy = ipa2_dma_destroy;
-       api_ctrl->ipa_mhi_init = ipa2_mhi_init;
-       api_ctrl->ipa_mhi_start = ipa2_mhi_start;
-       api_ctrl->ipa_mhi_connect_pipe = ipa2_mhi_connect_pipe;
-       api_ctrl->ipa_mhi_disconnect_pipe = ipa2_mhi_disconnect_pipe;
-       api_ctrl->ipa_mhi_suspend = ipa2_mhi_suspend;
-       api_ctrl->ipa_mhi_resume = ipa2_mhi_resume;
-       api_ctrl->ipa_mhi_destroy = ipa2_mhi_destroy;
+       api_ctrl->ipa_mhi_init_engine = ipa2_mhi_init_engine;
+       api_ctrl->ipa_connect_mhi_pipe = ipa2_connect_mhi_pipe;
+       api_ctrl->ipa_disconnect_mhi_pipe = ipa2_disconnect_mhi_pipe;
+       api_ctrl->ipa_uc_mhi_reset_channel = ipa2_uc_mhi_reset_channel;
+       api_ctrl->ipa_mhi_sps_channel_empty = ipa2_mhi_sps_channel_empty;
+       api_ctrl->ipa_generate_tag_process = ipa2_generate_tag_process;
+       api_ctrl->ipa_disable_sps_pipe = ipa2_disable_sps_pipe;
+       api_ctrl->ipa_qmi_enable_force_clear_datapath_send =
+                       qmi_enable_force_clear_datapath_send;
+       api_ctrl->ipa_qmi_disable_force_clear_datapath_send =
+                       qmi_disable_force_clear_datapath_send;
+       api_ctrl->ipa_mhi_reset_channel_internal =
+                       ipa2_mhi_reset_channel_internal;
+       api_ctrl->ipa_mhi_start_channel_internal =
+                       ipa2_mhi_start_channel_internal;
+       api_ctrl->ipa_mhi_resume_channels_internal =
+                       ipa2_mhi_resume_channels_internal;
+       api_ctrl->ipa_uc_mhi_send_dl_ul_sync_info =
+                       ipa2_uc_mhi_send_dl_ul_sync_info;
+       api_ctrl->ipa_uc_mhi_init = ipa2_uc_mhi_init;
+       api_ctrl->ipa_uc_mhi_suspend_channel = ipa2_uc_mhi_suspend_channel;
+       api_ctrl->ipa_uc_mhi_stop_event_update_channel =
+                       ipa2_uc_mhi_stop_event_update_channel;
+       api_ctrl->ipa_uc_mhi_cleanup = ipa2_uc_mhi_cleanup;
+       api_ctrl->ipa_uc_mhi_print_stats = ipa2_uc_mhi_print_stats;
+       api_ctrl->ipa_uc_state_check = ipa2_uc_state_check;
        api_ctrl->ipa_write_qmap_id = ipa2_write_qmap_id;
        api_ctrl->ipa_add_interrupt_handler = ipa2_add_interrupt_handler;
        api_ctrl->ipa_remove_interrupt_handler = ipa2_remove_interrupt_handler;
index 032f43d..858693c 100644 (file)
@@ -1468,7 +1468,7 @@ static int ipa3_init_smem_region(int memory_region_size,
        struct ipahal_imm_cmd_dma_shared_mem cmd;
        struct ipahal_imm_cmd_pyld *cmd_pyld;
        struct ipa3_desc desc;
-       struct ipa3_mem_buffer mem;
+       struct ipa_mem_buffer mem;
        int rc;
 
        if (memory_region_size == 0)
@@ -1636,7 +1636,7 @@ static void ipa3_q6_avoid_holb(void)
 }
 
 static int ipa3_q6_clean_q6_flt_tbls(enum ipa_ip_type ip,
-       enum ipa_rule_type rlt, const struct ipa3_mem_buffer *mem)
+       enum ipa_rule_type rlt, const struct ipa_mem_buffer *mem)
 {
        struct ipa3_desc *desc;
        struct ipahal_imm_cmd_dma_shared_mem cmd;
@@ -1739,7 +1739,7 @@ free_desc:
 }
 
 static int ipa3_q6_clean_q6_rt_tbls(enum ipa_ip_type ip,
-       enum ipa_rule_type rlt, const struct ipa3_mem_buffer *mem)
+       enum ipa_rule_type rlt, const struct ipa_mem_buffer *mem)
 {
        struct ipa3_desc *desc;
        struct ipahal_imm_cmd_dma_shared_mem cmd;
@@ -1837,7 +1837,7 @@ static int ipa3_q6_clean_q6_tables(void)
        struct ipahal_imm_cmd_pyld *cmd_pyld;
        struct ipahal_imm_cmd_register_write reg_write_cmd = {0};
        int retval;
-       struct ipa3_mem_buffer mem = { 0 };
+       struct ipa_mem_buffer mem = { 0 };
        struct ipahal_reg_fltrt_hash_flush flush;
        struct ipahal_reg_valmask valmask;
        u64 *entry;
@@ -2146,7 +2146,7 @@ int _ipa_init_sram_v3_0(void)
 int _ipa_init_hdr_v3_0(void)
 {
        struct ipa3_desc desc = { 0 };
-       struct ipa3_mem_buffer mem;
+       struct ipa_mem_buffer mem;
        struct ipahal_imm_cmd_hdr_init_local cmd = {0};
        struct ipahal_imm_cmd_pyld *cmd_pyld;
        struct ipahal_imm_cmd_dma_shared_mem dma_cmd = { 0 };
@@ -2250,7 +2250,7 @@ int _ipa_init_hdr_v3_0(void)
 int _ipa_init_rt4_v3(void)
 {
        struct ipa3_desc desc = { 0 };
-       struct ipa3_mem_buffer mem;
+       struct ipa_mem_buffer mem;
        struct ipahal_imm_cmd_ip_v4_routing_init v4_cmd;
        struct ipahal_imm_cmd_pyld *cmd_pyld;
        u64 *entry;
@@ -2324,7 +2324,7 @@ free_mem:
 int _ipa_init_rt6_v3(void)
 {
        struct ipa3_desc desc = { 0 };
-       struct ipa3_mem_buffer mem;
+       struct ipa_mem_buffer mem;
        struct ipahal_imm_cmd_ip_v6_routing_init v6_cmd;
        struct ipahal_imm_cmd_pyld *cmd_pyld;
        u64 *entry;
@@ -2398,7 +2398,7 @@ free_mem:
 int _ipa_init_flt4_v3(void)
 {
        struct ipa3_desc desc = { 0 };
-       struct ipa3_mem_buffer mem;
+       struct ipa_mem_buffer mem;
        struct ipahal_imm_cmd_ip_v4_filter_init v4_cmd;
        struct ipahal_imm_cmd_pyld *cmd_pyld;
        u64 *entry;
@@ -2491,7 +2491,7 @@ free_mem:
 int _ipa_init_flt6_v3(void)
 {
        struct ipa3_desc desc = { 0 };
-       struct ipa3_mem_buffer mem;
+       struct ipa_mem_buffer mem;
        struct ipahal_imm_cmd_ip_v6_filter_init v6_cmd;
        struct ipahal_imm_cmd_pyld *cmd_pyld;
        u64 *entry;
index c1a7fdb..2a48b2b 100644 (file)
@@ -769,7 +769,7 @@ static void ipa_xfer_cb(struct gsi_chan_xfer_notify *notify)
 
 static int ipa3_reconfigure_channel_to_gpi(struct ipa3_ep_context *ep,
        struct gsi_chan_props *orig_chan_props,
-       struct ipa3_mem_buffer *chan_dma)
+       struct ipa_mem_buffer *chan_dma)
 {
        struct gsi_chan_props chan_props;
        enum gsi_status gsi_res;
@@ -837,7 +837,7 @@ static int ipa3_reset_with_open_aggr_frame_wa(u32 clnt_hdl,
        enum gsi_status gsi_res;
        struct gsi_chan_props orig_chan_props;
        union gsi_channel_scratch orig_chan_scratch;
-       struct ipa3_mem_buffer chan_dma;
+       struct ipa_mem_buffer chan_dma;
        void *buff;
        dma_addr_t dma_addr;
        struct gsi_xfer_elem xfer_elem;
@@ -863,7 +863,7 @@ static int ipa3_reset_with_open_aggr_frame_wa(u32 clnt_hdl,
                IPAERR("Error getting channel properties: %d\n", gsi_res);
                return -EFAULT;
        }
-       memset(&chan_dma, 0, sizeof(struct ipa3_mem_buffer));
+       memset(&chan_dma, 0, sizeof(struct ipa_mem_buffer));
        result = ipa3_reconfigure_channel_to_gpi(ep, &orig_chan_props,
                &chan_dma);
        if (result)
index 9d1ff18..483b2ca 100644 (file)
@@ -838,7 +838,7 @@ void ipa3_dma_destroy(void)
  *
  * @priv -not in use.
  * @evt - event name - IPA_RECIVE.
- * @data -the ipa3_mem_buffer.
+ * @data -the ipa_mem_buffer.
  */
 void ipa3_dma_async_memcpy_notify_cb(void *priv
                        , enum ipa_dp_evt_type evt, unsigned long data)
@@ -847,11 +847,11 @@ void ipa3_dma_async_memcpy_notify_cb(void *priv
        struct ipa3_dma_xfer_wrapper *xfer_descr_expected;
        struct ipa3_sys_context *sys;
        unsigned long flags;
-       struct ipa3_mem_buffer *mem_info;
+       struct ipa_mem_buffer *mem_info;
 
        IPADMA_FUNC_ENTRY();
 
-       mem_info = (struct ipa3_mem_buffer *)data;
+       mem_info = (struct ipa_mem_buffer *)data;
        ep_idx = ipa3_get_ep_mapping(IPA_CLIENT_MEMCPY_DMA_ASYNC_CONS);
        sys = ipa3_ctx->ep[ep_idx].sys;
 
index f2d60cb..3b5ce66 100644 (file)
@@ -73,7 +73,7 @@ static void ipa3_alloc_wlan_rx_common_cache(u32 size);
 static void ipa3_cleanup_wlan_rx_common_cache(void);
 static void ipa3_wq_repl_rx(struct work_struct *work);
 static void ipa3_dma_memcpy_notify(struct ipa3_sys_context *sys,
-               struct ipa3_mem_buffer *mem_info);
+               struct ipa_mem_buffer *mem_info);
 static int ipa_gsi_setup_channel(struct ipa_sys_connect_params *in,
        struct ipa3_ep_context *ep);
 static int ipa_populate_tag_field(struct ipa3_desc *desc,
@@ -2854,7 +2854,7 @@ static void ipa3_wlan_wq_rx_common(struct ipa3_sys_context *sys, u32 size)
 }
 
 static void ipa3_dma_memcpy_notify(struct ipa3_sys_context *sys,
-       struct ipa3_mem_buffer *mem_info)
+       struct ipa_mem_buffer *mem_info)
 {
        IPADBG_LOW("ENTER.\n");
        if (unlikely(list_empty(&sys->head_desc_list))) {
@@ -3785,7 +3785,7 @@ static int ipa_handle_rx_core_gsi(struct ipa3_sys_context *sys,
        struct ipa3_sys_context *sys_ptr;
        struct ipa3_rx_pkt_wrapper *rx_pkt;
        struct gsi_chan_xfer_notify xfer_notify;
-       struct ipa3_mem_buffer mem_info = {0};
+       struct ipa_mem_buffer mem_info = {0};
        enum ipa_client_type client;
 
        if (sys->ep->bytes_xfered_valid) {
@@ -3841,7 +3841,7 @@ static int ipa_handle_rx_core_sps(struct ipa3_sys_context *sys,
        struct sps_iovec iov;
        int ret;
        int cnt = 0;
-       struct ipa3_mem_buffer mem_info = {0};
+       struct ipa_mem_buffer mem_info = {0};
 
        while ((in_poll_state ? atomic_read(&sys->curr_polling_state) :
                        !atomic_read(&sys->curr_polling_state))) {
index 4044c28..f49b165 100644 (file)
@@ -317,7 +317,7 @@ static void __ipa_reap_sys_flt_tbls(enum ipa_ip_type ip, enum ipa_rule_type rlt)
  * Return: 0 on success, negative on failure
  */
 static int ipa_alloc_init_flt_tbl_hdr(enum ipa_ip_type ip,
-       struct ipa3_mem_buffer *hash_hdr, struct ipa3_mem_buffer *nhash_hdr)
+       struct ipa_mem_buffer *hash_hdr, struct ipa_mem_buffer *nhash_hdr)
 {
        int num_hdrs;
        u64 *hash_entr;
@@ -489,7 +489,7 @@ static int ipa_translate_flt_tbl_to_hw_fmt(enum ipa_ip_type ip,
        int res;
        struct ipa3_flt_entry *entry;
        u8 *tbl_mem_buf;
-       struct ipa3_mem_buffer tbl_mem;
+       struct ipa_mem_buffer tbl_mem;
        struct ipa3_flt_tbl *tbl;
        int i;
        int hdr_idx = 0;
@@ -612,8 +612,8 @@ err:
  * Return: 0 on success, negative on failure
  */
 static int ipa_generate_flt_hw_tbl_img(enum ipa_ip_type ip,
-       struct ipa3_mem_buffer *hash_hdr, struct ipa3_mem_buffer *nhash_hdr,
-       struct ipa3_mem_buffer *hash_bdy, struct ipa3_mem_buffer *nhash_bdy)
+       struct ipa_mem_buffer *hash_hdr, struct ipa_mem_buffer *nhash_hdr,
+       struct ipa_mem_buffer *hash_bdy, struct ipa_mem_buffer *nhash_bdy)
 {
        u32 hash_bdy_start_ofst, nhash_bdy_start_ofst;
        u32 hash_bdy_sz;
@@ -724,7 +724,7 @@ no_flt_tbls:
  * Return: true if enough space available or false in other cases
  */
 static bool ipa_flt_valid_lcl_tbl_size(enum ipa_ip_type ipt,
-       enum ipa_rule_type rlt, struct ipa3_mem_buffer *bdy)
+       enum ipa_rule_type rlt, struct ipa_mem_buffer *bdy)
 {
        u16 avail;
 
@@ -827,8 +827,8 @@ static bool ipa_flt_skip_pipe_config(int pipe)
  */
 int __ipa_commit_flt_v3(enum ipa_ip_type ip)
 {
-       struct ipa3_mem_buffer hash_bdy, nhash_bdy;
-       struct ipa3_mem_buffer hash_hdr, nhash_hdr;
+       struct ipa_mem_buffer hash_bdy, nhash_bdy;
+       struct ipa_mem_buffer hash_hdr, nhash_hdr;
        int rc = 0;
        struct ipa3_desc *desc;
        struct ipahal_imm_cmd_register_write reg_write_cmd = {0};
index f0f79d0..6a14d75 100644 (file)
@@ -28,7 +28,7 @@ static const u32 ipa_hdr_proc_ctx_bin_sz[IPA_HDR_PROC_CTX_BIN_MAX] = { 32, 64};
  *
  * Returns:    0 on success, negative on failure
  */
-static int ipa3_generate_hdr_hw_tbl(struct ipa3_mem_buffer *mem)
+static int ipa3_generate_hdr_hw_tbl(struct ipa_mem_buffer *mem)
 {
        struct ipa3_hdr_entry *entry;
 
@@ -61,7 +61,7 @@ static int ipa3_generate_hdr_hw_tbl(struct ipa3_mem_buffer *mem)
        return 0;
 }
 
-static int ipa3_hdr_proc_ctx_to_hw_format(struct ipa3_mem_buffer *mem,
+static int ipa3_hdr_proc_ctx_to_hw_format(struct ipa_mem_buffer *mem,
        u32 hdr_base_addr)
 {
        struct ipa3_hdr_proc_ctx_entry *entry;
@@ -96,7 +96,7 @@ static int ipa3_hdr_proc_ctx_to_hw_format(struct ipa3_mem_buffer *mem,
  * Returns:    0 on success, negative on failure
  */
 static int ipa3_generate_hdr_proc_ctx_hw_tbl(u32 hdr_sys_addr,
-       struct ipa3_mem_buffer *mem, struct ipa3_mem_buffer *aligned_mem)
+       struct ipa_mem_buffer *mem, struct ipa_mem_buffer *aligned_mem)
 {
        u32 hdr_base_addr;
 
@@ -133,9 +133,9 @@ static int ipa3_generate_hdr_proc_ctx_hw_tbl(u32 hdr_sys_addr,
 int __ipa_commit_hdr_v3_0(void)
 {
        struct ipa3_desc desc[2];
-       struct ipa3_mem_buffer hdr_mem;
-       struct ipa3_mem_buffer ctx_mem;
-       struct ipa3_mem_buffer aligned_ctx_mem;
+       struct ipa_mem_buffer hdr_mem;
+       struct ipa_mem_buffer ctx_mem;
+       struct ipa_mem_buffer aligned_ctx_mem;
        struct ipahal_imm_cmd_dma_shared_mem dma_cmd_hdr = {0};
        struct ipahal_imm_cmd_dma_shared_mem dma_cmd_ctx = {0};
        struct ipahal_imm_cmd_register_write reg_write_cmd = {0};
index e7e5d28..2331adb 100644 (file)
 #define IPA_LAN_RX_HDR_NAME "ipa_lan_hdr"
 #define IPA_INVALID_L4_PROTOCOL 0xFF
 
-#define IPA_CLIENT_IS_PROD(x) (x >= IPA_CLIENT_PROD && x < IPA_CLIENT_CONS)
-#define IPA_CLIENT_IS_CONS(x) (x >= IPA_CLIENT_CONS && x < IPA_CLIENT_MAX)
-
 #define IPA_HW_TABLE_ALIGNMENT(start_ofst) \
        (((start_ofst) + 127) & ~127)
 #define IPA_RT_FLT_HW_RULE_BUF_SIZE    (256)
 
 #define IPA_GSI_CHANNEL_STOP_MAX_RETRY 10
 #define IPA_GSI_CHANNEL_STOP_PKT_SIZE 1
-#define IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC (1000)
-#define IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC (2000)
 
 #define IPA_GSI_CHANNEL_EMPTY_MAX_RETRY 15
 #define IPA_GSI_CHANNEL_EMPTY_SLEEP_MIN_USEC (1000)
@@ -247,18 +242,6 @@ struct ipa_smmu_cb_ctx {
 };
 
 /**
- * struct ipa3_mem_buffer - IPA memory buffer
- * @base: base
- * @phys_base: physical base address
- * @size: size of memory buffer
- */
-struct ipa3_mem_buffer {
-       void *base;
-       dma_addr_t phys_base;
-       u32 size;
-};
-
-/**
  * struct ipa3_flt_entry - IPA filtering table entry
  * @link: entry's link in global filtering enrties list
  * @rule: filter rule
@@ -311,8 +294,8 @@ struct ipa3_rt_tbl {
        u32 cookie;
        bool in_sys[IPA_RULE_TYPE_MAX];
        u32 sz[IPA_RULE_TYPE_MAX];
-       struct ipa3_mem_buffer curr_mem[IPA_RULE_TYPE_MAX];
-       struct ipa3_mem_buffer prev_mem[IPA_RULE_TYPE_MAX];
+       struct ipa_mem_buffer curr_mem[IPA_RULE_TYPE_MAX];
+       struct ipa_mem_buffer prev_mem[IPA_RULE_TYPE_MAX];
        int id;
        struct idr rule_ids;
 };
@@ -449,8 +432,8 @@ struct ipa3_flt_tbl {
        u32 rule_cnt;
        bool in_sys[IPA_RULE_TYPE_MAX];
        u32 sz[IPA_RULE_TYPE_MAX];
-       struct ipa3_mem_buffer curr_mem[IPA_RULE_TYPE_MAX];
-       struct ipa3_mem_buffer prev_mem[IPA_RULE_TYPE_MAX];
+       struct ipa_mem_buffer curr_mem[IPA_RULE_TYPE_MAX];
+       struct ipa_mem_buffer prev_mem[IPA_RULE_TYPE_MAX];
        bool sticky_rear;
        struct idr rule_ids;
 };
@@ -745,14 +728,14 @@ enum ipa3_desc_type {
  */
 struct ipa3_tx_pkt_wrapper {
        enum ipa3_desc_type type;
-       struct ipa3_mem_buffer mem;
+       struct ipa_mem_buffer mem;
        struct work_struct work;
        struct list_head link;
        void (*callback)(void *user1, int user2);
        void *user1;
        int user2;
        struct ipa3_sys_context *sys;
-       struct ipa3_mem_buffer mult;
+       struct ipa_mem_buffer mult;
        u32 cnt;
        void *bounce;
        bool no_unmap_dma;
@@ -1189,58 +1172,6 @@ enum ipa3_hw_flags {
 };
 
 /**
- * enum ipa3_hw_mhi_channel_states - MHI channel state machine
- *
- * Values are according to MHI specification
- * @IPA_HW_MHI_CHANNEL_STATE_DISABLE: Channel is disabled and not processed by
- *     the host or device.
- * @IPA_HW_MHI_CHANNEL_STATE_ENABLE: A channel is enabled after being
- *     initialized and configured by host, including its channel context and
- *     associated transfer ring. While this state, the channel is not active
- *     and the device does not process transfer.
- * @IPA_HW_MHI_CHANNEL_STATE_RUN: The device processes transfers and doorbell
- *     for channels.
- * @IPA_HW_MHI_CHANNEL_STATE_SUSPEND: Used to halt operations on the channel.
- *     The device does not process transfers for the channel in this state.
- *     This state is typically used to synchronize the transition to low power
- *     modes.
- * @IPA_HW_MHI_CHANNEL_STATE_STOP: Used to halt operations on the channel.
- *     The device does not process transfers for the channel in this state.
- * @IPA_HW_MHI_CHANNEL_STATE_ERROR: The device detected an error in an element
- *     from the transfer ring associated with the channel.
- * @IPA_HW_MHI_CHANNEL_STATE_INVALID: Invalid state. Shall not be in use in
- *     operational scenario.
- */
-enum ipa3_hw_mhi_channel_states {
-       IPA_HW_MHI_CHANNEL_STATE_DISABLE        = 0,
-       IPA_HW_MHI_CHANNEL_STATE_ENABLE         = 1,
-       IPA_HW_MHI_CHANNEL_STATE_RUN            = 2,
-       IPA_HW_MHI_CHANNEL_STATE_SUSPEND        = 3,
-       IPA_HW_MHI_CHANNEL_STATE_STOP           = 4,
-       IPA_HW_MHI_CHANNEL_STATE_ERROR          = 5,
-       IPA_HW_MHI_CHANNEL_STATE_INVALID        = 0xFF
-};
-
-/**
- * Structure holding the parameters for IPA_CPU_2_HW_CMD_MHI_DL_UL_SYNC_INFO
- * command. Parameters are sent as 32b immediate parameters.
- * @isDlUlSyncEnabled: Flag to indicate if DL UL Syncronization is enabled
- * @UlAccmVal: UL Timer Accumulation value (Period after which device will poll
- *     for UL data)
- * @ulMsiEventThreshold: Threshold at which HW fires MSI to host for UL events
- * @dlMsiEventThreshold: Threshold at which HW fires MSI to host for DL events
- */
-union IpaHwMhiDlUlSyncCmdData_t {
-       struct IpaHwMhiDlUlSyncCmdParams_t {
-               u32 isDlUlSyncEnabled:8;
-               u32 UlAccmVal:8;
-               u32 ulMsiEventThreshold:8;
-               u32 dlMsiEventThreshold:8;
-       } params;
-       u32 raw32b;
-};
-
-/**
  * struct ipa3_uc_ctx - IPA uC context
  * @uc_inited: Indicates if uC interface has been initialized
  * @uc_loaded: Indicates if uC has loaded
@@ -1467,8 +1398,8 @@ struct ipa3_context {
        uint aggregation_time_limit;
        bool hdr_tbl_lcl;
        bool hdr_proc_ctx_tbl_lcl;
-       struct ipa3_mem_buffer hdr_mem;
-       struct ipa3_mem_buffer hdr_proc_ctx_mem;
+       struct ipa_mem_buffer hdr_mem;
+       struct ipa_mem_buffer hdr_proc_ctx_mem;
        bool ip4_rt_tbl_hash_lcl;
        bool ip4_rt_tbl_nhash_lcl;
        bool ip6_rt_tbl_hash_lcl;
@@ -1477,7 +1408,7 @@ struct ipa3_context {
        bool ip4_flt_tbl_nhash_lcl;
        bool ip6_flt_tbl_hash_lcl;
        bool ip6_flt_tbl_nhash_lcl;
-       struct ipa3_mem_buffer empty_rt_tbl_mem;
+       struct ipa_mem_buffer empty_rt_tbl_mem;
        struct gen_pool *pipe_mem_pool;
        struct dma_pool *dma_pool;
        struct ipa3_active_clients ipa3_active_clients;
@@ -1961,19 +1892,28 @@ void ipa3_dma_destroy(void);
 /*
  * MHI
  */
-int ipa3_mhi_init(struct ipa_mhi_init_params *params);
 
-int ipa3_mhi_start(struct ipa_mhi_start_params *params);
+int ipa3_mhi_init_engine(struct ipa_mhi_init_engine *params);
+
+int ipa3_connect_mhi_pipe(
+               struct ipa_mhi_connect_params_internal *in,
+               u32 *clnt_hdl);
+
+int ipa3_disconnect_mhi_pipe(u32 clnt_hdl);
+
+bool ipa3_mhi_stop_gsi_channel(enum ipa_client_type client);
 
-int ipa3_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl);
+int ipa3_mhi_reset_channel_internal(enum ipa_client_type client);
 
-int ipa3_mhi_disconnect_pipe(u32 clnt_hdl);
+int ipa3_mhi_start_channel_internal(enum ipa_client_type client);
 
-int ipa3_mhi_suspend(bool force);
+bool ipa3_has_open_aggr_frame(enum ipa_client_type client);
 
-int ipa3_mhi_resume(void);
+int ipa3_mhi_resume_channels_internal(enum ipa_client_type client,
+               bool LPTransitionRejected, bool brstmode_enabled,
+               union __packed gsi_channel_scratch ch_scratch, u8 index);
 
-void ipa3_mhi_destroy(void);
+int ipa3_mhi_destroy_channel(enum ipa_client_type client);
 
 /*
  * mux id
@@ -2165,6 +2105,8 @@ int ipa3_sps_connect_safe(struct sps_pipe *h, struct sps_connect *connect,
                         enum ipa_client_type ipa_client);
 
 int ipa3_mhi_handle_ipa_config_req(struct ipa_config_req_msg_v01 *config_req);
+int ipa3_mhi_query_ch_info(enum ipa_client_type client,
+               struct gsi_chan_info *ch_info);
 
 int ipa3_uc_interface_init(void);
 int ipa3_uc_reset_pipe(enum ipa_client_type ipa_client);
@@ -2185,7 +2127,7 @@ int ipa3_uc_update_hw_flags(u32 flags);
 
 int ipa3_uc_mhi_init(void (*ready_cb)(void), void (*wakeup_request_cb)(void));
 void ipa3_uc_mhi_cleanup(void);
-int ipa3_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t cmd);
+int ipa3_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t *cmd);
 int ipa3_uc_mhi_init_engine(struct ipa_mhi_msi_info *msi, u32 mmio_addr,
        u32 host_ctrl_addr, u32 host_data_addr, u32 first_ch_idx,
        u32 first_evt_idx);
index 517093a..14e2f1f 100644 (file)
@@ -17,6 +17,8 @@
 #include <linux/mutex.h>
 #include <linux/ipa.h>
 #include <linux/msm_gsi.h>
+#include <linux/ipa_mhi.h>
+#include "../ipa_common_i.h"
 #include "ipa_i.h"
 #include "ipa_qmi_service.h"
 
 #define IPA_MHI_FUNC_EXIT() \
        IPA_MHI_DBG_LOW("EXIT\n")
 
-#define IPA_MHI_GSI_ER_START 10
-#define IPA_MHI_GSI_ER_END 16
-
-#define IPA_MHI_RM_TIMEOUT_MSEC 10000
-
-#define IPA_MHI_CH_EMPTY_TIMEOUT_MSEC 10
-
 #define IPA_MHI_MAX_UL_CHANNELS 1
 #define IPA_MHI_MAX_DL_CHANNELS 1
 
-#if (IPA_MHI_MAX_UL_CHANNELS + IPA_MHI_MAX_DL_CHANNELS) > \
-       (IPA_MHI_GSI_ER_END - IPA_MHI_GSI_ER_START)
-#error not enought event rings for MHI
-#endif
-
-#define IPA_MHI_SUSPEND_SLEEP_MIN 900
-#define IPA_MHI_SUSPEND_SLEEP_MAX 1100
-
 /* bit #40 in address should be asserted for MHI transfers over pcie */
 #define IPA_MHI_HOST_ADDR_COND(addr) \
-               ((ipa3_mhi_ctx->assert_bit40)?(IPA_MHI_HOST_ADDR(addr)):(addr))
-
-enum ipa3_mhi_state {
-       IPA_MHI_STATE_INITIALIZED,
-       IPA_MHI_STATE_READY,
-       IPA_MHI_STATE_STARTED,
-       IPA_MHI_STATE_SUSPEND_IN_PROGRESS,
-       IPA_MHI_STATE_SUSPENDED,
-       IPA_MHI_STATE_RESUME_IN_PROGRESS,
-       IPA_MHI_STATE_MAX
-};
-
-static char *ipa3_mhi_state_str[] = {
-       __stringify(IPA_MHI_STATE_INITIALIZED),
-       __stringify(IPA_MHI_STATE_READY),
-       __stringify(IPA_MHI_STATE_STARTED),
-       __stringify(IPA_MHI_STATE_SUSPEND_IN_PROGRESS),
-       __stringify(IPA_MHI_STATE_SUSPENDED),
-       __stringify(IPA_MHI_STATE_RESUME_IN_PROGRESS),
-};
-
-#define MHI_STATE_STR(state) \
-       (((state) >= 0 && (state) < IPA_MHI_STATE_MAX) ? \
-               ipa3_mhi_state_str[(state)] : \
-               "INVALID")
-
-enum ipa_mhi_dma_dir {
-       IPA_MHI_DMA_TO_HOST,
-       IPA_MHI_DMA_FROM_HOST,
-};
+               ((params->assert_bit40)?(IPA_MHI_HOST_ADDR(addr)):(addr))
 
 /**
  * enum ipa3_mhi_burst_mode - MHI channel burst mode state
@@ -132,2944 +90,557 @@ enum ipa3_mhi_polling_mode {
        IPA_MHI_POLLING_MODE_POLL_MODE,
 };
 
-struct ipa3_mhi_ch_ctx {
-       u8 chstate;/*0-7*/
-       u8 brstmode:2;/*8-9*/
-       u8 pollcfg:6;/*10-15*/
-       u16 rsvd;/*16-31*/
-       u32 chtype;
-       u32 erindex;
-       u64 rbase;
-       u64 rlen;
-       u64 rp;
-       u64 wp;
-} __packed;
-
-struct ipa3_mhi_ev_ctx {
-       u32 intmodc:16;
-       u32 intmodt:16;
-       u32 ertype;
-       u32 msivec;
-       u64 rbase;
-       u64 rlen;
-       u64 rp;
-       u64 wp;
-} __packed;
-
-/**
- * struct ipa3_mhi_channel_ctx - MHI Channel context
- * @valid: entry is valid
- * @id: MHI channel ID
- * @index: channel handle for uC
- * @ep: IPA endpoint context
- * @state: Channel state
- * @stop_in_proc: flag to indicate if channel was stopped completely
- * @ch_info: information about channel occupancy
- * @channel_context_addr : the channel context address in host address space
- * @ch_ctx_host: MHI Channel context
- * @event_context_addr: the event context address in host address space
- * @ev_ctx_host: MHI event context
- * @cached_gsi_evt_ring_hdl: GSI channel event ring handle
- * @brstmode_enabled: is burst mode enabled for this channel?
- * @ch_scratch: the channel scratch configuration
- */
-struct ipa3_mhi_channel_ctx {
-       bool valid;
-       u8 id;
-       u8 index;
-       struct ipa3_ep_context *ep;
-       enum ipa3_hw_mhi_channel_states state;
-       bool stop_in_proc;
-       struct gsi_chan_info ch_info;
-       u64 channel_context_addr;
-       struct ipa3_mhi_ch_ctx ch_ctx_host;
-       u64 event_context_addr;
-       struct ipa3_mhi_ev_ctx ev_ctx_host;
-       unsigned long cached_gsi_evt_ring_hdl;
-       bool brstmode_enabled;
-       union __packed gsi_channel_scratch ch_scratch;
-};
-
-enum ipa3_mhi_rm_state {
-       IPA_MHI_RM_STATE_RELEASED,
-       IPA_MHI_RM_STATE_REQUESTED,
-       IPA_MHI_RM_STATE_GRANTED,
-       IPA_MHI_RM_STATE_MAX
-};
-
-/**
- * struct ipa3_mhi_ctx - IPA MHI context
- * @state: IPA MHI state
- * @state_lock: lock for state read/write operations
- * @msi: Message Signaled Interrupts parameters
- * @mmio_addr: MHI MMIO physical address
- * @first_ch_idx: First channel ID for hardware accelerated channels.
- * @first_er_idx: First event ring ID for hardware accelerated channels.
- * @host_ctrl_addr: Base address of MHI control data structures
- * @host_data_addr: Base address of MHI data buffers
- * @channel_context_addr: channel context array address in host address space
- * @event_context_addr: event context array address in host address space
- * @cb_notify: client callback
- * @cb_priv: client private data to be provided in client callback
- * @ul_channels: IPA MHI uplink channel contexts
- * @dl_channels: IPA MHI downlink channel contexts
- * @total_channels: Total number of channels ever connected to IPA MHI
- * @rm_prod_granted_comp: Completion object for MHI producer resource in IPA RM
- * @rm_cons_state: MHI consumer resource state in IPA RM
- * @rm_cons_comp: Completion object for MHI consumer resource in IPA RM
- * @trigger_wakeup: trigger wakeup callback ?
- * @wakeup_notified: MHI Client wakeup function was called
- * @wq: workqueue for wakeup event
- * @qmi_req_id: QMI request unique id
- * @use_ipadma: use IPADMA to access host space
- * @assert_bit40: should assert bit 40 in order to access hots space.
- *     if PCIe iATU is configured then not need to assert bit40
- * @ test_mode: flag to indicate if IPA MHI is in unit test mode
- */
-struct ipa3_mhi_ctx {
-       enum ipa3_mhi_state state;
-       spinlock_t state_lock;
-       struct ipa_mhi_msi_info msi;
-       u32 mmio_addr;
-       u32 first_ch_idx;
-       u32 first_er_idx;
-       u32 host_ctrl_addr;
-       u32 host_data_addr;
-       u64 channel_context_array_addr;
-       u64 event_context_array_addr;
-       mhi_client_cb cb_notify;
-       void *cb_priv;
-       struct ipa3_mhi_channel_ctx ul_channels[IPA_MHI_MAX_UL_CHANNELS];
-       struct ipa3_mhi_channel_ctx dl_channels[IPA_MHI_MAX_DL_CHANNELS];
-       u32 total_channels;
-       struct completion rm_prod_granted_comp;
-       enum ipa3_mhi_rm_state rm_cons_state;
-       struct completion rm_cons_comp;
-       bool trigger_wakeup;
-       bool wakeup_notified;
-       struct workqueue_struct *wq;
-       u32 qmi_req_id;
-       u32 use_ipadma;
-       bool assert_bit40;
-       bool test_mode;
-};
-
-static struct ipa3_mhi_ctx *ipa3_mhi_ctx;
-
-static void ipa3_mhi_wq_notify_wakeup(struct work_struct *work);
-static DECLARE_WORK(ipa_mhi_notify_wakeup_work, ipa3_mhi_wq_notify_wakeup);
-
-static void ipa3_mhi_wq_notify_ready(struct work_struct *work);
-static DECLARE_WORK(ipa_mhi_notify_ready_work, ipa3_mhi_wq_notify_ready);
-
-static union IpaHwMhiDlUlSyncCmdData_t ipa3_cached_dl_ul_sync_info;
-
-#ifdef CONFIG_DEBUG_FS
-#define IPA_MHI_MAX_MSG_LEN 512
-static char dbg_buff[IPA_MHI_MAX_MSG_LEN];
-static struct dentry *dent;
-
-static char *ipa3_mhi_channel_state_str[] = {
-       __stringify(IPA_HW_MHI_CHANNEL_STATE_DISABLE),
-       __stringify(IPA_HW_MHI_CHANNEL_STATE_ENABLE),
-       __stringify(IPA_HW_MHI_CHANNEL_STATE_RUN),
-       __stringify(IPA_HW_MHI_CHANNEL_STATE_SUSPEND),
-       __stringify(IPA_HW_MHI_CHANNEL_STATE_STOP),
-       __stringify(IPA_HW_MHI_CHANNEL_STATE_ERROR),
-};
-
-#define MHI_CH_STATE_STR(state) \
-       (((state) >= 0 && (state) <= IPA_HW_MHI_CHANNEL_STATE_ERROR) ? \
-       ipa3_mhi_channel_state_str[(state)] : \
-       "INVALID")
-
-static int ipa_mhi_read_write_host(enum ipa_mhi_dma_dir dir, void *dev_addr,
-       u64 host_addr, int size)
+bool ipa3_mhi_stop_gsi_channel(enum ipa_client_type client)
 {
-       struct ipa3_mem_buffer mem;
        int res;
+       int ipa_ep_idx;
+       struct ipa3_ep_context *ep;
 
        IPA_MHI_FUNC_ENTRY();
-
-       if (ipa3_mhi_ctx->use_ipadma) {
-               host_addr = IPA_MHI_HOST_ADDR_COND(host_addr);
-
-               mem.size = size;
-               mem.base = dma_alloc_coherent(ipa3_ctx->pdev, mem.size,
-                       &mem.phys_base, GFP_KERNEL);
-               if (!mem.base) {
-                       IPAERR("dma_alloc_coherent failed, DMA buff size %d\n",
-                               mem.size);
-                       return -ENOMEM;
-               }
-
-               if (dir == IPA_MHI_DMA_FROM_HOST) {
-                       res = ipa_dma_sync_memcpy(mem.phys_base, host_addr,
-                               size);
-                       if (res) {
-                               IPAERR("ipa_dma_sync_memcpy from host fail%d\n",
-                                       res);
-                               goto fail_memcopy;
-                       }
-                       memcpy(dev_addr, mem.base, size);
-               } else {
-                       memcpy(mem.base, dev_addr, size);
-                       res = ipa_dma_sync_memcpy(host_addr, mem.phys_base,
-                               size);
-                       if (res) {
-                               IPAERR("ipa_dma_sync_memcpy to host fail %d\n",
-                                       res);
-                               goto fail_memcopy;
-                       }
-               }
-               dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base,
-                       mem.phys_base);
-       } else {
-               void *host_ptr;
-
-               if (!ipa3_mhi_ctx->test_mode)
-                       host_ptr = ioremap(host_addr, size);
-               else
-                       host_ptr = phys_to_virt(host_addr);
-               if (!host_ptr) {
-                       IPAERR("ioremap failed for 0x%llx\n", host_addr);
-                       return -EFAULT;
-               }
-               if (dir == IPA_MHI_DMA_FROM_HOST)
-                       memcpy(dev_addr, host_ptr, size);
-               else
-                       memcpy(host_ptr, dev_addr, size);
-               if (!ipa3_mhi_ctx->test_mode)
-                       iounmap(host_ptr);
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-
-fail_memcopy:
-       dma_free_coherent(ipa3_ctx->pdev, mem.size, mem.base,
-                       mem.phys_base);
-       return res;
-}
-
-static int ipa3_mhi_print_channel_info(struct ipa3_mhi_channel_ctx *channel,
-       char *buff, int len)
-{
-       int nbytes = 0;
-
-       if (channel->valid) {
-               nbytes += scnprintf(&buff[nbytes],
-                       len - nbytes,
-                       "channel idx=%d ch_id=%d client=%d state=%s\n",
-                       channel->index, channel->id, channel->ep->client,
-                       MHI_CH_STATE_STR(channel->state));
-
-               nbytes += scnprintf(&buff[nbytes],
-                       len - nbytes,
-                       "       stop_in_proc=%d gsi_chan_hdl=%ld\n",
-                       channel->stop_in_proc, channel->ep->gsi_chan_hdl);
-
-               nbytes += scnprintf(&buff[nbytes],
-                       len - nbytes,
-                       "       ch_ctx=%llx\n",
-                       channel->channel_context_addr);
-
-               nbytes += scnprintf(&buff[nbytes],
-                       len - nbytes,
-                       "       gsi_evt_ring_hdl=%ld ev_ctx=%llx\n",
-                       channel->ep->gsi_evt_ring_hdl,
-                       channel->event_context_addr);
-       }
-       return nbytes;
-}
-
-static int ipa3_mhi_print_host_channel_ctx_info(
-               struct ipa3_mhi_channel_ctx *channel, char *buff, int len)
-{
-       int res, nbytes = 0;
-       struct ipa3_mhi_ch_ctx ch_ctx_host;
-
-       memset(&ch_ctx_host, 0, sizeof(ch_ctx_host));
-
-       /* reading ch context from host */
-       res = ipa_mhi_read_write_host(IPA_MHI_DMA_FROM_HOST,
-               &ch_ctx_host, channel->channel_context_addr,
-               sizeof(ch_ctx_host));
-       if (res) {
-               nbytes += scnprintf(&buff[nbytes], len - nbytes,
-                       "Failed to read from host %d\n", res);
-               return nbytes;
+       ipa_ep_idx = ipa3_get_ep_mapping(client);
+       if (ipa_ep_idx == -1) {
+               IPA_MHI_ERR("Invalid client.\n");
+               return -EINVAL;
        }
 
-       nbytes += scnprintf(&buff[nbytes], len - nbytes,
-               "ch_id: %d\n", channel->id);
-       nbytes += scnprintf(&buff[nbytes], len - nbytes,
-               "chstate: 0x%x\n", ch_ctx_host.chstate);
-       nbytes += scnprintf(&buff[nbytes], len - nbytes,
-               "brstmode: 0x%x\n", ch_ctx_host.brstmode);
-       nbytes += scnprintf(&buff[nbytes], len - nbytes,
-               "chtype: 0x%x\n", ch_ctx_host.chtype);
-       nbytes += scnprintf(&buff[nbytes], len - nbytes,
-               "erindex: 0x%x\n", ch_ctx_host.erindex);
-       nbytes += scnprintf(&buff[nbytes], len - nbytes,
-               "rbase: 0x%llx\n", ch_ctx_host.rbase);
-       nbytes += scnprintf(&buff[nbytes], len - nbytes,
-               "rlen: 0x%llx\n", ch_ctx_host.rlen);
-       nbytes += scnprintf(&buff[nbytes], len - nbytes,
-               "rp: 0x%llx\n", ch_ctx_host.rp);
-       nbytes += scnprintf(&buff[nbytes], len - nbytes,
-               "wp: 0x%llx\n", ch_ctx_host.wp);
-
-       return nbytes;
-}
-
-static ssize_t ipa3_mhi_debugfs_stats(struct file *file,
-       char __user *ubuf,
-       size_t count,
-       loff_t *ppos)
-{
-       int nbytes = 0;
-       int i;
-       struct ipa3_mhi_channel_ctx *channel;
-
-       nbytes += scnprintf(&dbg_buff[nbytes],
-               IPA_MHI_MAX_MSG_LEN - nbytes,
-               "IPA MHI state: %s\n", MHI_STATE_STR(ipa3_mhi_ctx->state));
-
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               channel = &ipa3_mhi_ctx->ul_channels[i];
-               nbytes += ipa3_mhi_print_channel_info(channel,
-                       &dbg_buff[nbytes], IPA_MHI_MAX_MSG_LEN - nbytes);
+       ep = &ipa3_ctx->ep[ipa_ep_idx];
+       IPA_MHI_DBG_LOW("Stopping GSI channel %ld\n", ep->gsi_chan_hdl);
+       res = gsi_stop_channel(ep->gsi_chan_hdl);
+       if (res != 0 &&
+               res != -GSI_STATUS_AGAIN &&
+               res != -GSI_STATUS_TIMED_OUT) {
+               IPA_MHI_ERR("GSI stop channel failed %d\n",
+                       res);
+               WARN_ON(1);
+               return false;
        }
 
-       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-               channel = &ipa3_mhi_ctx->dl_channels[i];
-               nbytes += ipa3_mhi_print_channel_info(channel,
-                       &dbg_buff[nbytes], IPA_MHI_MAX_MSG_LEN - nbytes);
+       if (res == 0) {
+               IPA_MHI_DBG_LOW("GSI channel %ld STOP\n",
+                       ep->gsi_chan_hdl);
+               return true;
        }
 
-       return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
-}
-
-static ssize_t ipa3_mhi_debugfs_uc_stats(struct file *file,
-       char __user *ubuf,
-       size_t count,
-       loff_t *ppos)
-{
-       int nbytes = 0;
-
-       nbytes += ipa3_uc_mhi_print_stats(dbg_buff, IPA_MHI_MAX_MSG_LEN);
-       return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+       return false;
 }
 
-static ssize_t ipa3_mhi_debugfs_dump_host_ch_ctx_arr(struct file *file,
-       char __user *ubuf,
-       size_t count,
-       loff_t *ppos)
+static int ipa3_mhi_reset_gsi_channel(enum ipa_client_type client)
 {
-       int i, nbytes = 0;
-       struct ipa3_mhi_channel_ctx *channel;
-
-       if (ipa3_mhi_ctx->state == IPA_MHI_STATE_INITIALIZED ||
-           ipa3_mhi_ctx->state == IPA_MHI_STATE_READY) {
-               nbytes += scnprintf(&dbg_buff[nbytes],
-               IPA_MHI_MAX_MSG_LEN - nbytes,
-                       "Cannot dump host channel context ");
-               nbytes += scnprintf(&dbg_buff[nbytes],
-                               IPA_MHI_MAX_MSG_LEN - nbytes,
-                               "before IPA MHI was STARTED\n");
-               return simple_read_from_buffer(ubuf, count, ppos,
-                       dbg_buff, nbytes);
-       }
-       if (ipa3_mhi_ctx->state == IPA_MHI_STATE_SUSPENDED) {
-               nbytes += scnprintf(&dbg_buff[nbytes],
-                       IPA_MHI_MAX_MSG_LEN - nbytes,
-                       "IPA MHI is suspended, cannot dump channel ctx array");
-               nbytes += scnprintf(&dbg_buff[nbytes],
-                       IPA_MHI_MAX_MSG_LEN - nbytes,
-                       " from host -PCIe can be in D3 state\n");
-               return simple_read_from_buffer(ubuf, count, ppos,
-                       dbg_buff, nbytes);
-       }
+       int res;
+       int clnt_hdl;
 
-       nbytes += scnprintf(&dbg_buff[nbytes],
-                       IPA_MHI_MAX_MSG_LEN - nbytes,
-                       "channel contex array - dump from host\n");
-       nbytes += scnprintf(&dbg_buff[nbytes],
-                       IPA_MHI_MAX_MSG_LEN - nbytes,
-                       "***** UL channels *******\n");
-
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               channel = &ipa3_mhi_ctx->ul_channels[i];
-               if (!channel->valid)
-                       continue;
-               nbytes += ipa3_mhi_print_host_channel_ctx_info(channel,
-                       &dbg_buff[nbytes],
-                       IPA_MHI_MAX_MSG_LEN - nbytes);
-       }
+       IPA_MHI_FUNC_ENTRY();
 
-       nbytes += scnprintf(&dbg_buff[nbytes],
-                       IPA_MHI_MAX_MSG_LEN - nbytes,
-                       "\n***** DL channels *******\n");
+       clnt_hdl = ipa3_get_ep_mapping(client);
+       if (clnt_hdl < 0)
+               return -EFAULT;
 
-       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-               channel = &ipa3_mhi_ctx->dl_channels[i];
-               if (!channel->valid)
-                       continue;
-               nbytes += ipa3_mhi_print_host_channel_ctx_info(channel,
-                       &dbg_buff[nbytes], IPA_MHI_MAX_MSG_LEN - nbytes);
+       res = ipa3_reset_gsi_channel(clnt_hdl);
+       if (res) {
+               IPA_MHI_ERR("ipa3_reset_gsi_channel failed %d\n", res);
+               return -EFAULT;
        }
 
-       return simple_read_from_buffer(ubuf, count, ppos, dbg_buff, nbytes);
+       IPA_MHI_FUNC_EXIT();
+       return 0;
 }
 
-const struct file_operations ipa3_mhi_stats_ops = {
-       .read = ipa3_mhi_debugfs_stats,
-};
-
-const struct file_operations ipa3_mhi_uc_stats_ops = {
-       .read = ipa3_mhi_debugfs_uc_stats,
-};
-
-const struct file_operations ipa3_mhi_dump_host_ch_ctx_ops = {
-       .read = ipa3_mhi_debugfs_dump_host_ch_ctx_arr,
-};
-
-
-static void ipa3_mhi_debugfs_init(void)
+int ipa3_mhi_reset_channel_internal(enum ipa_client_type client)
 {
-       const mode_t read_only_mode = S_IRUSR | S_IRGRP | S_IROTH;
-       const mode_t read_write_mode = S_IRUSR | S_IRGRP | S_IROTH |
-               S_IWUSR | S_IWGRP;
-       struct dentry *file;
+       int res;
 
        IPA_MHI_FUNC_ENTRY();
 
-       dent = debugfs_create_dir("ipa_mhi", 0);
-       if (IS_ERR(dent)) {
-               IPA_MHI_ERR("fail to create folder ipa_mhi\n");
-               return;
-       }
-
-       file = debugfs_create_file("stats", read_only_mode, dent,
-               0, &ipa3_mhi_stats_ops);
-       if (!file || IS_ERR(file)) {
-               IPA_MHI_ERR("fail to create file stats\n");
-               goto fail;
-       }
-
-       file = debugfs_create_file("uc_stats", read_only_mode, dent,
-               0, &ipa3_mhi_uc_stats_ops);
-       if (!file || IS_ERR(file)) {
-               IPA_MHI_ERR("fail to create file uc_stats\n");
-               goto fail;
-       }
-
-       file = debugfs_create_u32("use_ipadma", read_write_mode, dent,
-               &ipa3_mhi_ctx->use_ipadma);
-       if (!file || IS_ERR(file)) {
-               IPA_MHI_ERR("fail to create file use_ipadma\n");
-               goto fail;
+       res = ipa3_mhi_reset_gsi_channel(client);
+       if (res) {
+               IPAERR("ipa3_mhi_reset_gsi_channel failed\n");
+               ipa_assert();
+               return res;
        }
 
-       file = debugfs_create_file("dump_host_channel_ctx_array",
-               read_only_mode, dent, 0, &ipa3_mhi_dump_host_ch_ctx_ops);
-       if (!file || IS_ERR(file)) {
-               IPA_MHI_ERR("fail to create file dump_host_channel_ctx_arr\n");
-               goto fail;
+       res = ipa3_disable_data_path(ipa3_get_ep_mapping(client));
+       if (res) {
+               IPA_MHI_ERR("ipa3_disable_data_path failed %d\n", res);
+               return res;
        }
-
        IPA_MHI_FUNC_EXIT();
-       return;
-fail:
-       debugfs_remove_recursive(dent);
-}
 
-static void ipa3_mhi_debugfs_destroy(void)
-{
-       debugfs_remove_recursive(dent);
+       return 0;
 }
 
-#else
-static void ipa3_mhi_debugfs_init(void) {}
-static void ipa3_mhi_debugfs_destroy(void) {}
-#endif /* CONFIG_DEBUG_FS */
-
-
-static void ipa3_mhi_cache_dl_ul_sync_info(
-       struct ipa_config_req_msg_v01 *config_req)
+int ipa3_mhi_start_channel_internal(enum ipa_client_type client)
 {
-       ipa3_cached_dl_ul_sync_info.params.isDlUlSyncEnabled = true;
-       ipa3_cached_dl_ul_sync_info.params.UlAccmVal =
-               (config_req->ul_accumulation_time_limit_valid) ?
-               config_req->ul_accumulation_time_limit : 0;
-       ipa3_cached_dl_ul_sync_info.params.ulMsiEventThreshold =
-               (config_req->ul_msi_event_threshold_valid) ?
-               config_req->ul_msi_event_threshold : 0;
-       ipa3_cached_dl_ul_sync_info.params.dlMsiEventThreshold =
-               (config_req->dl_msi_event_threshold_valid) ?
-               config_req->dl_msi_event_threshold : 0;
-}
+       int res;
 
-/**
- * ipa3_mhi_wq_notify_wakeup() - Notify MHI client on data available
- *
- * This function is called from IPA MHI workqueue to notify
- * MHI client driver on data available event.
- */
-static void ipa3_mhi_wq_notify_wakeup(struct work_struct *work)
-{
        IPA_MHI_FUNC_ENTRY();
-       ipa3_mhi_ctx->cb_notify(ipa3_mhi_ctx->cb_priv,
-               IPA_MHI_EVENT_DATA_AVAILABLE, 0);
-       IPA_MHI_FUNC_EXIT();
-}
 
-/**
- * ipa3_mhi_notify_wakeup() - Schedule work to notify data available
- *
- * This function will schedule a work to notify data available event.
- * In case this function is called more than once, only one notification will
- * be sent to MHI client driver. No further notifications will be sent until
- * IPA MHI state will become STARTED.
- */
-static void ipa3_mhi_notify_wakeup(void)
-{
-       IPA_MHI_FUNC_ENTRY();
-       if (ipa3_mhi_ctx->wakeup_notified) {
-               IPADBG("wakeup already called\n");
-               return;
+       res = ipa3_enable_data_path(ipa3_get_ep_mapping(client));
+       if (res) {
+               IPA_MHI_ERR("ipa3_enable_data_path failed %d\n", res);
+               return res;
        }
-       queue_work(ipa3_mhi_ctx->wq, &ipa_mhi_notify_wakeup_work);
-       ipa3_mhi_ctx->wakeup_notified = true;
-       IPA_MHI_FUNC_EXIT();
-}
-
-/**
- * ipa3_mhi_wq_notify_ready() - Notify MHI client on ready
- *
- * This function is called from IPA MHI workqueue to notify
- * MHI client driver on ready event when IPA uC is loaded
- */
-static void ipa3_mhi_wq_notify_ready(struct work_struct *work)
-{
-       IPA_MHI_FUNC_ENTRY();
-       ipa3_mhi_ctx->cb_notify(ipa3_mhi_ctx->cb_priv,
-               IPA_MHI_EVENT_READY, 0);
-       IPA_MHI_FUNC_EXIT();
-}
-
-/**
- * ipa3_mhi_notify_ready() - Schedule work to notify ready
- *
- * This function will schedule a work to notify ready event.
- */
-static void ipa3_mhi_notify_ready(void)
-{
-       IPA_MHI_FUNC_ENTRY();
-       queue_work(ipa3_mhi_ctx->wq, &ipa_mhi_notify_ready_work);
        IPA_MHI_FUNC_EXIT();
-}
-
-/**
- * ipa3_mhi_set_state() - Set new state to IPA MHI
- * @state: new state
- *
- * Sets a new state to IPA MHI if possible according to IPA MHI state machine.
- * In some state transitions a wakeup request will be triggered.
- *
- * Returns: 0 on success, -1 otherwise
- */
-static int ipa3_mhi_set_state(enum ipa3_mhi_state new_state)
-{
-       unsigned long flags;
-       int res = -EPERM;
-
-       spin_lock_irqsave(&ipa3_mhi_ctx->state_lock, flags);
-       IPA_MHI_DBG("Current state: %s\n", MHI_STATE_STR(ipa3_mhi_ctx->state));
-
-       switch (ipa3_mhi_ctx->state) {
-       case IPA_MHI_STATE_INITIALIZED:
-               if (new_state == IPA_MHI_STATE_READY) {
-                       ipa3_mhi_notify_ready();
-                       res = 0;
-               }
-               break;
-
-       case IPA_MHI_STATE_READY:
-               if (new_state == IPA_MHI_STATE_READY)
-                       res = 0;
-               if (new_state == IPA_MHI_STATE_STARTED)
-                       res = 0;
-               break;
-
-       case IPA_MHI_STATE_STARTED:
-               if (new_state == IPA_MHI_STATE_INITIALIZED)
-                       res = 0;
-               else if (new_state == IPA_MHI_STATE_SUSPEND_IN_PROGRESS)
-                       res = 0;
-               break;
-
-       case IPA_MHI_STATE_SUSPEND_IN_PROGRESS:
-               if (new_state == IPA_MHI_STATE_SUSPENDED) {
-                       if (ipa3_mhi_ctx->trigger_wakeup) {
-                               ipa3_mhi_ctx->trigger_wakeup = false;
-                               ipa3_mhi_notify_wakeup();
-                       }
-                       res = 0;
-               } else if (new_state == IPA_MHI_STATE_STARTED) {
-                       ipa3_mhi_ctx->wakeup_notified = false;
-                       ipa3_mhi_ctx->trigger_wakeup = false;
-                       if (ipa3_mhi_ctx->rm_cons_state ==
-                               IPA_MHI_RM_STATE_REQUESTED) {
-                               ipa_rm_notify_completion(
-                                       IPA_RM_RESOURCE_GRANTED,
-                                       IPA_RM_RESOURCE_MHI_CONS);
-                               ipa3_mhi_ctx->rm_cons_state =
-                                       IPA_MHI_RM_STATE_GRANTED;
-                       }
-                       res = 0;
-               }
-               break;
-
-       case IPA_MHI_STATE_SUSPENDED:
-               if (new_state == IPA_MHI_STATE_RESUME_IN_PROGRESS)
-                       res = 0;
-               break;
-
-       case IPA_MHI_STATE_RESUME_IN_PROGRESS:
-               if (new_state == IPA_MHI_STATE_SUSPENDED) {
-                       if (ipa3_mhi_ctx->trigger_wakeup) {
-                               ipa3_mhi_ctx->trigger_wakeup = false;
-                               ipa3_mhi_notify_wakeup();
-                       }
-                       res = 0;
-               } else if (new_state == IPA_MHI_STATE_STARTED) {
-                       ipa3_mhi_ctx->trigger_wakeup = false;
-                       ipa3_mhi_ctx->wakeup_notified = false;
-                       if (ipa3_mhi_ctx->rm_cons_state ==
-                               IPA_MHI_RM_STATE_REQUESTED) {
-                               ipa_rm_notify_completion(
-                                       IPA_RM_RESOURCE_GRANTED,
-                                       IPA_RM_RESOURCE_MHI_CONS);
-                               ipa3_mhi_ctx->rm_cons_state =
-                                       IPA_MHI_RM_STATE_GRANTED;
-                       }
-                       res = 0;
-               }
-               break;
-
-       default:
-               IPA_MHI_ERR("Invalid state %d\n", ipa3_mhi_ctx->state);
-               WARN_ON(1);
-       }
 
-       if (res)
-               IPA_MHI_ERR("Invalid state change to %s\n",
-                                               MHI_STATE_STR(new_state));
-       else {
-               IPA_MHI_DBG("New state change to %s\n",
-                                               MHI_STATE_STR(new_state));
-               ipa3_mhi_ctx->state = new_state;
-       }
-       spin_unlock_irqrestore(&ipa3_mhi_ctx->state_lock, flags);
-       return res;
+       return 0;
 }
 
-static void ipa3_mhi_rm_prod_notify(void *user_data, enum ipa_rm_event event,
-       unsigned long data)
+static int ipa3_mhi_get_ch_poll_cfg(enum ipa_client_type client,
+               struct ipa_mhi_ch_ctx *ch_ctx_host, int ring_size)
 {
-       IPA_MHI_FUNC_ENTRY();
-
-       switch (event) {
-       case IPA_RM_RESOURCE_GRANTED:
-               IPA_MHI_DBG_LOW("IPA_RM_RESOURCE_GRANTED\n");
-               complete_all(&ipa3_mhi_ctx->rm_prod_granted_comp);
-               break;
-
-       case IPA_RM_RESOURCE_RELEASED:
-               IPA_MHI_DBG_LOW("IPA_RM_RESOURCE_RELEASED\n");
+       switch (ch_ctx_host->pollcfg) {
+       case 0:
+       /*set default polling configuration according to MHI spec*/
+               if (IPA_CLIENT_IS_PROD(client))
+                       return 7;
+               else
+                       return (ring_size/2)/8;
                break;
-
        default:
-               IPA_MHI_ERR("unexpected event %d\n", event);
-               WARN_ON(1);
-               break;
+               return ch_ctx_host->pollcfg;
        }
-
-       IPA_MHI_FUNC_EXIT();
-}
-
-static void ipa3_mhi_uc_ready_cb(void)
-{
-       IPA_MHI_FUNC_ENTRY();
-       ipa3_mhi_set_state(IPA_MHI_STATE_READY);
-       IPA_MHI_FUNC_EXIT();
-}
-
-static void ipa3_mhi_uc_wakeup_request_cb(void)
-{
-       unsigned long flags;
-
-       IPA_MHI_FUNC_ENTRY();
-       IPA_MHI_DBG("MHI state: %s\n", MHI_STATE_STR(ipa3_mhi_ctx->state));
-       spin_lock_irqsave(&ipa3_mhi_ctx->state_lock, flags);
-       if (ipa3_mhi_ctx->state == IPA_MHI_STATE_SUSPENDED)
-               ipa3_mhi_notify_wakeup();
-       else if (ipa3_mhi_ctx->state == IPA_MHI_STATE_SUSPEND_IN_PROGRESS)
-               /* wakeup event will be triggered after suspend finishes */
-               ipa3_mhi_ctx->trigger_wakeup = true;
-
-       spin_unlock_irqrestore(&ipa3_mhi_ctx->state_lock, flags);
-       IPA_MHI_FUNC_EXIT();
 }
 
-/**
- * ipa3_mhi_rm_cons_request() - callback function for IPA RM request resource
- *
- * In case IPA MHI is not suspended, MHI CONS will be granted immediately.
- * In case IPA MHI is suspended, MHI CONS will be granted after resume.
- */
-static int ipa3_mhi_rm_cons_request(void)
+static int ipa_mhi_start_gsi_channel(enum ipa_client_type client,
+       int ipa_ep_idx, struct start_gsi_channel *params)
 {
-       unsigned long flags;
        int res;
+       struct gsi_evt_ring_props ev_props;
+       struct ipa_mhi_msi_info *msi;
+       struct gsi_chan_props ch_props;
+       union __packed gsi_channel_scratch ch_scratch;
+       struct ipa3_ep_context *ep;
+       struct ipa_gsi_ep_config *ep_cfg;
 
        IPA_MHI_FUNC_ENTRY();
 
-       IPA_MHI_DBG("%s\n", MHI_STATE_STR(ipa3_mhi_ctx->state));
-       spin_lock_irqsave(&ipa3_mhi_ctx->state_lock, flags);
-       ipa3_mhi_ctx->rm_cons_state = IPA_MHI_RM_STATE_REQUESTED;
-       if (ipa3_mhi_ctx->state == IPA_MHI_STATE_STARTED) {
-               ipa3_mhi_ctx->rm_cons_state = IPA_MHI_RM_STATE_GRANTED;
-               res = 0;
-       } else if (ipa3_mhi_ctx->state == IPA_MHI_STATE_SUSPENDED) {
-               ipa3_mhi_notify_wakeup();
-               res = -EINPROGRESS;
-       } else if (ipa3_mhi_ctx->state == IPA_MHI_STATE_SUSPEND_IN_PROGRESS) {
-               /* wakeup event will be trigger after suspend finishes */
-               ipa3_mhi_ctx->trigger_wakeup = true;
-               res = -EINPROGRESS;
-       } else {
-               res = -EINPROGRESS;
-       }
-
-       spin_unlock_irqrestore(&ipa3_mhi_ctx->state_lock, flags);
-       IPA_MHI_DBG_LOW("EXIT with %d\n", res);
-       return res;
-}
+       ep = &ipa3_ctx->ep[ipa_ep_idx];
 
-static int ipa3_mhi_rm_cons_release(void)
-{
-       unsigned long flags;
+       msi = params->msi;
+       ep_cfg = ipa_get_gsi_ep_info(ipa_ep_idx);
+       if (!ep_cfg) {
+               IPA_MHI_ERR("Wrong parameter, ep_cfg is NULL\n");
+               return -EPERM;
+       }
 
-       IPA_MHI_FUNC_ENTRY();
+       /* allocate event ring only for the first time pipe is connected */
+       if (params->state == IPA_HW_MHI_CHANNEL_STATE_INVALID) {
+               IPA_MHI_DBG("allocating event ring\n");
+               memset(&ev_props, 0, sizeof(ev_props));
+               ev_props.intf = GSI_EVT_CHTYPE_MHI_EV;
+               ev_props.intr = GSI_INTR_MSI;
+               ev_props.re_size = GSI_EVT_RING_RE_SIZE_16B;
+               ev_props.ring_len = params->ev_ctx_host->rlen;
+               ev_props.ring_base_addr = IPA_MHI_HOST_ADDR_COND(
+                               params->ev_ctx_host->rbase);
+               ev_props.int_modt = params->ev_ctx_host->intmodt *
+                               IPA_SLEEP_CLK_RATE_KHZ;
+               ev_props.int_modc = params->ev_ctx_host->intmodc;
+               ev_props.intvec = ((msi->data & ~msi->mask) |
+                               (params->ev_ctx_host->msivec & msi->mask));
+               ev_props.msi_addr = IPA_MHI_HOST_ADDR_COND(
+                               (((u64)msi->addr_hi << 32) | msi->addr_low));
+               ev_props.rp_update_addr = IPA_MHI_HOST_ADDR_COND(
+                               params->event_context_addr +
+                               offsetof(struct ipa_mhi_ev_ctx, rp));
+               ev_props.exclusive = true;
+               ev_props.err_cb = params->ev_err_cb;
+               ev_props.user_data = params->channel;
+               ev_props.evchid_valid = true;
+               ev_props.evchid = params->evchid;
+               res = gsi_alloc_evt_ring(&ev_props, ipa3_ctx->gsi_dev_hdl,
+                       &ep->gsi_evt_ring_hdl);
+               if (res) {
+                       IPA_MHI_ERR("gsi_alloc_evt_ring failed %d\n", res);
+                       goto fail_alloc_evt;
+                       return res;
+               }
+               IPA_MHI_DBG("client %d, caching event ring hdl %lu\n",
+                               client,
+                               ep->gsi_evt_ring_hdl);
+               *params->cached_gsi_evt_ring_hdl =
+                       ep->gsi_evt_ring_hdl;
 
-       spin_lock_irqsave(&ipa3_mhi_ctx->state_lock, flags);
-       ipa3_mhi_ctx->rm_cons_state = IPA_MHI_RM_STATE_RELEASED;
-       complete_all(&ipa3_mhi_ctx->rm_cons_comp);
-       spin_unlock_irqrestore(&ipa3_mhi_ctx->state_lock, flags);
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
+       }
 
-static int ipa3_mhi_wait_for_cons_release(void)
-{
-       unsigned long flags;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       reinit_completion(&ipa3_mhi_ctx->rm_cons_comp);
-       spin_lock_irqsave(&ipa3_mhi_ctx->state_lock, flags);
-       if (ipa3_mhi_ctx->rm_cons_state != IPA_MHI_RM_STATE_GRANTED) {
-               spin_unlock_irqrestore(&ipa3_mhi_ctx->state_lock, flags);
-               return 0;
-       }
-       spin_unlock_irqrestore(&ipa3_mhi_ctx->state_lock, flags);
-
-       res = wait_for_completion_timeout(
-               &ipa3_mhi_ctx->rm_cons_comp,
-               msecs_to_jiffies(IPA_MHI_RM_TIMEOUT_MSEC));
-       if (res == 0) {
-               IPA_MHI_ERR("timeout release mhi cons\n");
-               return -ETIME;
-       }
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa3_mhi_request_prod(void)
-{
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       reinit_completion(&ipa3_mhi_ctx->rm_prod_granted_comp);
-       IPA_MHI_DBG_LOW("requesting mhi prod\n");
-       res = ipa_rm_request_resource(IPA_RM_RESOURCE_MHI_PROD);
-       if (res) {
-               if (res != -EINPROGRESS) {
-                       IPA_MHI_ERR("failed to request mhi prod %d\n", res);
-                       return res;
-               }
-               res = wait_for_completion_timeout(
-                       &ipa3_mhi_ctx->rm_prod_granted_comp,
-                       msecs_to_jiffies(IPA_MHI_RM_TIMEOUT_MSEC));
-               if (res == 0) {
-                       IPA_MHI_ERR("timeout request mhi prod\n");
-                       return -ETIME;
-               }
-       }
-
-       IPA_MHI_DBG_LOW("mhi prod granted\n");
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-
-}
-
-static int ipa3_mhi_release_prod(void)
-{
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       res = ipa_rm_release_resource(IPA_RM_RESOURCE_MHI_PROD);
-
-       IPA_MHI_FUNC_EXIT();
-       return res;
-
-}
-
-/**
- * ipa3_mhi_get_channel_context() - Get corresponding channel context
- * @ep: IPA ep
- * @channel_id: Channel ID
- *
- * This function will return the corresponding channel context or allocate new
- * one in case channel context for channel does not exist.
- */
-static struct ipa3_mhi_channel_ctx *ipa3_mhi_get_channel_context(
-       struct ipa3_ep_context *ep, u8 channel_id)
-{
-       int ch_idx;
-       struct ipa3_mhi_channel_ctx *channels;
-       int max_channels;
-
-       if (IPA_CLIENT_IS_PROD(ep->client)) {
-               channels = ipa3_mhi_ctx->ul_channels;
-               max_channels = IPA_MHI_MAX_UL_CHANNELS;
-       } else {
-               channels = ipa3_mhi_ctx->dl_channels;
-               max_channels = IPA_MHI_MAX_DL_CHANNELS;
-       }
-
-       /* find the channel context according to channel id */
-       for (ch_idx = 0; ch_idx < max_channels; ch_idx++) {
-               if (channels[ch_idx].valid &&
-                   channels[ch_idx].id == channel_id)
-                       return &channels[ch_idx];
-       }
-
-       /* channel context does not exists, allocate a new one */
-       for (ch_idx = 0; ch_idx < max_channels; ch_idx++) {
-               if (!channels[ch_idx].valid)
-                       break;
-       }
-
-       if (ch_idx == max_channels) {
-               IPA_MHI_ERR("no more channels available\n");
-               return NULL;
-       }
-
-       channels[ch_idx].valid = true;
-       channels[ch_idx].id = channel_id;
-       channels[ch_idx].index = ipa3_mhi_ctx->total_channels++;
-       channels[ch_idx].ep = ep;
-       channels[ch_idx].state = IPA_HW_MHI_CHANNEL_STATE_INVALID;
-
-       return &channels[ch_idx];
-}
-
-/**
- * ipa3_mhi_get_channel_context_by_clnt_hdl() - Get corresponding channel
- * context
- * @clnt_hdl: client handle as provided in ipa3_mhi_connect_pipe()
- *
- * This function will return the corresponding channel context or NULL in case
- * that channel does not exist.
- */
-static struct ipa3_mhi_channel_ctx *ipa3_mhi_get_channel_context_by_clnt_hdl(
-       u32 clnt_hdl)
-{
-       int ch_idx;
-
-       for (ch_idx = 0; ch_idx < IPA_MHI_MAX_UL_CHANNELS; ch_idx++) {
-               if (ipa3_mhi_ctx->ul_channels[ch_idx].valid &&
-                   ipa3_get_ep_mapping(
-                   ipa3_mhi_ctx->ul_channels[ch_idx].ep->client) == clnt_hdl)
-                       return &ipa3_mhi_ctx->ul_channels[ch_idx];
-       }
-
-       for (ch_idx = 0; ch_idx < IPA_MHI_MAX_DL_CHANNELS; ch_idx++) {
-               if (ipa3_mhi_ctx->dl_channels[ch_idx].valid &&
-                   ipa3_get_ep_mapping(
-                   ipa3_mhi_ctx->dl_channels[ch_idx].ep->client) == clnt_hdl)
-                       return &ipa3_mhi_ctx->dl_channels[ch_idx];
-       }
-
-       return NULL;
-}
-
-static int ipa3_mhi_enable_force_clear(u32 request_id, bool throttle_source)
-{
-       struct ipa_enable_force_clear_datapath_req_msg_v01 req;
-       int i;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       memset(&req, 0, sizeof(req));
-       req.request_id = request_id;
-       req.source_pipe_bitmask = 0;
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               if (!ipa3_mhi_ctx->ul_channels[i].valid)
-                       continue;
-               req.source_pipe_bitmask |= 1 << ipa3_get_ep_mapping(
-                               ipa3_mhi_ctx->ul_channels[i].ep->client);
-       }
-       if (throttle_source) {
-               req.throttle_source_valid = 1;
-               req.throttle_source = 1;
-       }
-       IPA_MHI_DBG("req_id=0x%x src_pipe_btmk=0x%x throt_src=%d\n",
-               req.request_id, req.source_pipe_bitmask,
-               req.throttle_source);
-       res = ipa3_qmi_enable_force_clear_datapath_send(&req);
-       if (res) {
-               IPA_MHI_ERR(
-                       "ipa3_qmi_enable_force_clear_datapath_send failed %d\n",
-                       res);
-               return res;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa3_mhi_disable_force_clear(u32 request_id)
-{
-       struct ipa_disable_force_clear_datapath_req_msg_v01 req;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       memset(&req, 0, sizeof(req));
-       req.request_id = request_id;
-       IPA_MHI_DBG("req_id=0x%x\n", req.request_id);
-       res = ipa3_qmi_disable_force_clear_datapath_send(&req);
+       memset(&ch_props, 0, sizeof(ch_props));
+       ch_props.prot = GSI_CHAN_PROT_MHI;
+       ch_props.dir = IPA_CLIENT_IS_PROD(client) ?
+               GSI_CHAN_DIR_TO_GSI : GSI_CHAN_DIR_FROM_GSI;
+       ch_props.ch_id = ep_cfg->ipa_gsi_chan_num;
+       ch_props.evt_ring_hdl = *params->cached_gsi_evt_ring_hdl;
+       ch_props.re_size = GSI_CHAN_RE_SIZE_16B;
+       ch_props.ring_len = params->ch_ctx_host->rlen;
+       ch_props.ring_base_addr = IPA_MHI_HOST_ADDR_COND(
+                       params->ch_ctx_host->rbase);
+       ch_props.use_db_eng = GSI_CHAN_DB_MODE;
+       ch_props.max_prefetch = GSI_ONE_PREFETCH_SEG;
+       ch_props.low_weight = 1;
+       ch_props.err_cb = params->ch_err_cb;
+       ch_props.chan_user_data = params->channel;
+       res = gsi_alloc_channel(&ch_props, ipa3_ctx->gsi_dev_hdl,
+               &ep->gsi_chan_hdl);
        if (res) {
-               IPA_MHI_ERR(
-                       "ipa3_qmi_disable_force_clear_datapath_send failed %d\n",
-                       res);
-               return res;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static bool ipa3_mhi_sps_channel_empty(struct ipa3_mhi_channel_ctx *channel)
-{
-       u32 pipe_idx;
-       bool pending;
-
-       pipe_idx = ipa3_get_ep_mapping(channel->ep->client);
-       if (sps_pipe_pending_desc(ipa3_ctx->bam_handle,
-               pipe_idx, &pending)) {
-               IPA_MHI_ERR("sps_pipe_pending_desc failed\n");
-               WARN_ON(1);
-               return false;
-       }
-
-       return !pending;
-}
-
-static bool ipa3_mhi_gsi_channel_empty(struct ipa3_mhi_channel_ctx *channel)
-{
-       int res;
-       IPA_MHI_FUNC_ENTRY();
-
-       if (!channel->stop_in_proc) {
-               IPA_MHI_DBG_LOW("Channel is not in STOP_IN_PROC\n");
-               return true;
-       }
-
-       IPA_MHI_DBG_LOW("Stopping GSI channel %ld\n",
-               channel->ep->gsi_chan_hdl);
-       res = gsi_stop_channel(channel->ep->gsi_chan_hdl);
-       if (res != 0 &&
-               res != -GSI_STATUS_AGAIN &&
-               res != -GSI_STATUS_TIMED_OUT) {
-               IPA_MHI_ERR("GSI stop channel failed %d\n",
+               IPA_MHI_ERR("gsi_alloc_channel failed %d\n",
                        res);
-               WARN_ON(1);
-               return false;
-       }
-
-       if (res == 0) {
-               IPA_MHI_DBG_LOW("GSI channel %ld STOP\n",
-                       channel->ep->gsi_chan_hdl);
-               channel->stop_in_proc = false;
-               return true;
-       }
-
-       return false;
-}
-
-/**
- * ipa3_mhi_wait_for_ul_empty_timeout() - wait for pending packets in uplink
- * @msecs: timeout to wait
- *
- * This function will poll until there are no packets pending in uplink channels
- * or timeout occurred.
- *
- * Return code: true - no pending packets in uplink channels
- *             false - timeout occurred
- */
-static bool ipa3_mhi_wait_for_ul_empty_timeout(unsigned int msecs)
-{
-       unsigned long jiffies_timeout = msecs_to_jiffies(msecs);
-       unsigned long jiffies_start = jiffies;
-       bool empty = false;
-       int i;
-
-       IPA_MHI_FUNC_ENTRY();
-       while (!empty) {
-               empty = true;
-               for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-                       if (!ipa3_mhi_ctx->ul_channels[i].valid)
-                               continue;
-                       if (ipa3_ctx->transport_prototype ==
-                           IPA_TRANSPORT_TYPE_GSI)
-                               empty &= ipa3_mhi_gsi_channel_empty(
-                                       &ipa3_mhi_ctx->ul_channels[i]);
-                       else
-                               empty &= ipa3_mhi_sps_channel_empty(
-                                       &ipa3_mhi_ctx->ul_channels[i]);
-               }
-
-               if (time_after(jiffies, jiffies_start + jiffies_timeout)) {
-                       IPA_MHI_DBG_LOW("timeout waiting for UL empty\n");
-                       break;
-               }
-
-               if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI &&
-                   IPA_MHI_MAX_UL_CHANNELS == 1)
-                       usleep_range(IPA_GSI_CHANNEL_STOP_SLEEP_MIN_USEC,
-                       IPA_GSI_CHANNEL_STOP_SLEEP_MAX_USEC);
-       }
-
-       IPA_MHI_DBG("IPA UL is %s\n", (empty) ? "empty" : "not empty");
-
-       IPA_MHI_FUNC_EXIT();
-       return empty;
-}
-
-static void ipa3_mhi_set_holb_on_dl_channels(bool enable,
-       struct ipa_ep_cfg_holb old_holb[])
-{
-       int i;
-       struct ipa_ep_cfg_holb ep_holb;
-       int ep_idx;
-       int res;
-
-       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-               if (!ipa3_mhi_ctx->dl_channels[i].valid)
-                       continue;
-               if (ipa3_mhi_ctx->dl_channels[i].state ==
-                       IPA_HW_MHI_CHANNEL_STATE_INVALID)
-                       continue;
-               ep_idx = ipa3_get_ep_mapping(
-                       ipa3_mhi_ctx->dl_channels[i].ep->client);
-               if (-1 == ep_idx) {
-                       IPA_MHI_ERR("Client %u is not mapped\n",
-                               ipa3_mhi_ctx->dl_channels[i].ep->client);
-                       BUG();
-                       return;
-               }
-               memset(&ep_holb, 0, sizeof(ep_holb));
-               if (enable) {
-                       ep_holb.en = 1;
-                       ep_holb.tmr_val = 0;
-                       old_holb[i] = ipa3_ctx->ep[ep_idx].holb;
-               } else {
-                       ep_holb = old_holb[i];
-               }
-               res = ipa3_cfg_ep_holb(ep_idx, &ep_holb);
-               if (res) {
-                       IPA_MHI_ERR("ipa3_cfg_ep_holb failed %d\n", res);
-                       BUG();
-                       return;
-               }
-       }
-}
-
-static int ipa3_mhi_suspend_gsi_channel(struct ipa3_mhi_channel_ctx *channel)
-{
-       int res;
-       int clnt_hdl;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       clnt_hdl = ipa3_get_ep_mapping(channel->ep->client);
-       if (clnt_hdl < 0)
-               return -EFAULT;
-
-       res = ipa3_stop_gsi_channel(clnt_hdl);
-       if (res != 0 && res != -GSI_STATUS_AGAIN &&
-           res != -GSI_STATUS_TIMED_OUT) {
-               IPA_MHI_ERR("GSI stop channel failed %d\n", res);
-               return -EFAULT;
-       }
-
-       /* check if channel was stopped completely */
-       if (res)
-               channel->stop_in_proc = true;
-
-       IPA_MHI_DBG("GSI channel is %s\n", (channel->stop_in_proc) ?
-               "STOP_IN_PROC" : "STOP");
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa3_mhi_reset_gsi_channel(struct ipa3_mhi_channel_ctx *channel)
-{
-       int res;
-       int clnt_hdl;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       clnt_hdl = ipa3_get_ep_mapping(channel->ep->client);
-       if (clnt_hdl < 0)
-               return -EFAULT;
-
-       res = ipa3_reset_gsi_channel(clnt_hdl);
-       if (res) {
-               IPA_MHI_ERR("ipa3_reset_gsi_channel failed %d\n", res);
-               return -EFAULT;
+               goto fail_alloc_ch;
        }
 
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa3_mhi_reset_ul_channel(struct ipa3_mhi_channel_ctx *channel)
-{
-       int res;
-       struct ipa_ep_cfg_holb old_ep_holb[IPA_MHI_MAX_DL_CHANNELS];
-       bool empty;
-
-       IPA_MHI_FUNC_ENTRY();
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-               res = ipa3_mhi_suspend_gsi_channel(channel);
-               if (res) {
-                       IPA_MHI_ERR("ipa3_mhi_suspend_gsi_channel failed %d\n",
-                                res);
-                       return res;
-               }
+       memset(&ch_scratch, 0, sizeof(ch_scratch));
+       ch_scratch.mhi.mhi_host_wp_addr = IPA_MHI_HOST_ADDR_COND(
+                       params->channel_context_addr +
+                       offsetof(struct ipa_mhi_ch_ctx, wp));
+       ch_scratch.mhi.assert_bit40 = params->assert_bit40;
+       ch_scratch.mhi.max_outstanding_tre =
+               ep_cfg->ipa_if_tlv * ch_props.re_size;
+       ch_scratch.mhi.outstanding_threshold =
+               min(ep_cfg->ipa_if_tlv / 2, 8) * ch_props.re_size;
+       ch_scratch.mhi.oob_mod_threshold = 4;
+       if (params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_DEFAULT ||
+               params->ch_ctx_host->brstmode == IPA_MHI_BURST_MODE_ENABLE) {
+               ch_scratch.mhi.burst_mode_enabled = true;
+               ch_scratch.mhi.polling_configuration =
+                       ipa3_mhi_get_ch_poll_cfg(client, params->ch_ctx_host,
+                               (ch_props.ring_len / ch_props.re_size));
+               ch_scratch.mhi.polling_mode = IPA_MHI_POLLING_MODE_DB_MODE;
        } else {
-               res = ipa3_uc_mhi_reset_channel(channel->index);
-               if (res) {
-                       IPA_MHI_ERR("ipa3_uc_mhi_reset_channel failed %d\n",
-                               res);
-                       return res;
-               }
-       }
-
-       empty = ipa3_mhi_wait_for_ul_empty_timeout(
-                       IPA_MHI_CH_EMPTY_TIMEOUT_MSEC);
-       if (!empty) {
-               IPA_MHI_DBG("%s not empty\n",
-                       (ipa3_ctx->transport_prototype ==
-                               IPA_TRANSPORT_TYPE_GSI) ? "GSI" : "BAM");
-               res = ipa3_mhi_enable_force_clear(ipa3_mhi_ctx->qmi_req_id,
-                       false);
-               if (res) {
-                       IPA_MHI_ERR("ipa3_mhi_enable_force_clear failed %d\n",
-                               res);
-                       BUG();
-                       return res;
-               }
-
-               if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-                       empty = ipa3_mhi_wait_for_ul_empty_timeout(
-                               IPA_MHI_CH_EMPTY_TIMEOUT_MSEC);
-
-                       IPADBG("empty=%d\n", empty);
-               } else {
-                       /* enable packet drop on all DL channels */
-                       ipa3_mhi_set_holb_on_dl_channels(true, old_ep_holb);
-                       res = ipa3_tag_process(NULL, 0, HZ);
-                       if (res)
-                               IPAERR("TAG process failed\n");
-
-                       /* disable packet drop on all DL channels */
-                       ipa3_mhi_set_holb_on_dl_channels(false, old_ep_holb);
-                       res = sps_pipe_disable(ipa3_ctx->bam_handle,
-                               ipa3_get_ep_mapping(channel->ep->client));
-                       if (res) {
-                               IPA_MHI_ERR("sps_pipe_disable fail %d\n", res);
-                               BUG();
-                               return res;
-                       }
-               }
-
-               res = ipa3_mhi_disable_force_clear(ipa3_mhi_ctx->qmi_req_id);
-               if (res) {
-                       IPA_MHI_ERR("ipa3_mhi_disable_force_clear failed %d\n",
-                               res);
-                       BUG();
-                       return res;
-               }
-               ipa3_mhi_ctx->qmi_req_id++;
-       }
-
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-               res = ipa3_mhi_reset_gsi_channel(channel);
-               if (res) {
-                       IPAERR("ipa3_mhi_reset_gsi_channel failed\n");
-                       BUG();
-                       return res;
-               }
+               ch_scratch.mhi.burst_mode_enabled = false;
        }
-
-       res = ipa3_disable_data_path(ipa3_get_ep_mapping(channel->ep->client));
-       if (res) {
-               IPA_MHI_ERR("ipa3_disable_data_path failed %d\n", res);
-               return res;
-       }
-       IPA_MHI_FUNC_EXIT();
-
-       return 0;
-}
-
-static int ipa3_mhi_reset_dl_channel(struct ipa3_mhi_channel_ctx *channel)
-{
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-               res = ipa3_mhi_suspend_gsi_channel(channel);
-               if (res) {
-                       IPAERR("ipa3_mhi_suspend_gsi_channel failed %d\n", res);
-                       return res;
-               }
-
-               res = ipa3_mhi_reset_gsi_channel(channel);
-               if (res) {
-                       IPAERR("ipa3_mhi_reset_gsi_channel failed\n");
-                       return res;
-               }
-
-               res = ipa3_disable_data_path(
-                       ipa3_get_ep_mapping(channel->ep->client));
-               if (res) {
-                       IPA_MHI_ERR("ipa3_disable_data_path failed\n");
-                       return res;
-               }
-       } else {
-               res = ipa3_disable_data_path(
-                       ipa3_get_ep_mapping(channel->ep->client));
-               if (res) {
-                       IPA_MHI_ERR("ipa3_disable_data_path failed %d\n", res);
-                       return res;
-               }
-
-               res = ipa3_uc_mhi_reset_channel(channel->index);
-               if (res) {
-                       IPA_MHI_ERR("ipa3_uc_mhi_reset_channel failed %d\n",
-                               res);
-                       ipa3_enable_data_path(
-                               ipa3_get_ep_mapping(channel->ep->client));
-                       return res;
-               }
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa3_mhi_reset_channel(struct ipa3_mhi_channel_ctx *channel)
-{
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       if (IPA_CLIENT_IS_PROD(channel->ep->client))
-               res = ipa3_mhi_reset_ul_channel(channel);
-       else
-               res = ipa3_mhi_reset_dl_channel(channel);
-       if (res) {
-               IPA_MHI_ERR("failed to reset channel error %d\n", res);
-               return res;
-       }
-
-       channel->state = IPA_HW_MHI_CHANNEL_STATE_DISABLE;
-
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-               res = ipa_mhi_read_write_host(IPA_MHI_DMA_TO_HOST,
-                       &channel->state, channel->channel_context_addr +
-                               offsetof(struct ipa3_mhi_ch_ctx, chstate),
-                               sizeof(((struct ipa3_mhi_ch_ctx *)0)->chstate));
-               if (res) {
-                       IPAERR("ipa_mhi_read_write_host failed %d\n", res);
-                       return res;
-               }
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa_mhi_start_uc_channel(struct ipa3_mhi_channel_ctx *channel,
-       int ipa_ep_idx)
-{
-       int res;
-       struct ipa3_ep_context *ep;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       ep = channel->ep;
-       if (channel->state == IPA_HW_MHI_CHANNEL_STATE_INVALID) {
-               IPA_MHI_DBG("Initializing channel\n");
-               res = ipa3_uc_mhi_init_channel(ipa_ep_idx, channel->index,
-                       channel->id, (IPA_CLIENT_IS_PROD(ep->client) ? 1 : 2));
-               if (res) {
-                       IPA_MHI_ERR("init_channel failed %d\n", res);
-                       return res;
-               }
-       } else if (channel->state == IPA_HW_MHI_CHANNEL_STATE_DISABLE) {
-               if (channel->ep != ep) {
-                       IPA_MHI_ERR("previous channel client was %d\n",
-                               ep->client);
-                       return res;
-               }
-               IPA_MHI_DBG("Starting channel\n");
-               res = ipa3_uc_mhi_resume_channel(channel->index, false);
-               if (res) {
-                       IPA_MHI_ERR("init_channel failed %d\n", res);
-                       return res;
-               }
-       } else {
-               IPA_MHI_ERR("Invalid channel state %d\n", channel->state);
-               return -EFAULT;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static void ipa_mhi_dump_ch_ctx(struct ipa3_mhi_channel_ctx *channel)
-{
-       IPA_MHI_DBG_LOW("ch_id %d\n", channel->id);
-       IPA_MHI_DBG_LOW("chstate 0x%x\n", channel->ch_ctx_host.chstate);
-       IPA_MHI_DBG_LOW("brstmode 0x%x\n", channel->ch_ctx_host.brstmode);
-       IPA_MHI_DBG_LOW("pollcfg 0x%x\n", channel->ch_ctx_host.pollcfg);
-       IPA_MHI_DBG_LOW("chtype 0x%x\n", channel->ch_ctx_host.chtype);
-       IPA_MHI_DBG_LOW("erindex 0x%x\n", channel->ch_ctx_host.erindex);
-       IPA_MHI_DBG_LOW("rbase 0x%llx\n", channel->ch_ctx_host.rbase);
-       IPA_MHI_DBG_LOW("rlen 0x%llx\n", channel->ch_ctx_host.rlen);
-       IPA_MHI_DBG_LOW("rp 0x%llx\n", channel->ch_ctx_host.rp);
-       IPA_MHI_DBG_LOW("wp 0x%llx\n", channel->ch_ctx_host.wp);
-}
-
-static void ipa_mhi_dump_ev_ctx(struct ipa3_mhi_channel_ctx *channel)
-{
-       IPA_MHI_DBG_LOW("ch_id %d event id %d\n", channel->id,
-               channel->ch_ctx_host.erindex);
-
-       IPA_MHI_DBG_LOW("intmodc 0x%x\n", channel->ev_ctx_host.intmodc);
-       IPA_MHI_DBG_LOW("intmodt 0x%x\n", channel->ev_ctx_host.intmodt);
-       IPA_MHI_DBG_LOW("ertype 0x%x\n", channel->ev_ctx_host.ertype);
-       IPA_MHI_DBG_LOW("msivec 0x%x\n", channel->ev_ctx_host.msivec);
-       IPA_MHI_DBG_LOW("rbase 0x%llx\n", channel->ev_ctx_host.rbase);
-       IPA_MHI_DBG_LOW("rlen 0x%llx\n", channel->ev_ctx_host.rlen);
-       IPA_MHI_DBG_LOW("rp 0x%llx\n", channel->ev_ctx_host.rp);
-       IPA_MHI_DBG_LOW("wp 0x%llx\n", channel->ev_ctx_host.wp);
-}
-
-static int ipa_mhi_read_ch_ctx(struct ipa3_mhi_channel_ctx *channel)
-{
-       int res;
-
-       res = ipa_mhi_read_write_host(IPA_MHI_DMA_FROM_HOST,
-               &channel->ch_ctx_host, channel->channel_context_addr,
-               sizeof(channel->ch_ctx_host));
-       if (res) {
-               IPAERR("ipa_mhi_read_write_host failed %d\n", res);
-               return res;
-
-       }
-       ipa_mhi_dump_ch_ctx(channel);
-
-       channel->event_context_addr = ipa3_mhi_ctx->event_context_array_addr +
-               channel->ch_ctx_host.erindex * sizeof(struct ipa3_mhi_ev_ctx);
-       IPA_MHI_DBG("ch %d event_context_addr 0x%llx\n", channel->id,
-               channel->event_context_addr);
-
-       res = ipa_mhi_read_write_host(IPA_MHI_DMA_FROM_HOST,
-               &channel->ev_ctx_host, channel->event_context_addr,
-               sizeof(channel->ev_ctx_host));
-       if (res) {
-               IPAERR("ipa_mhi_read_write_host failed %d\n", res);
-               return res;
-
-       }
-       ipa_mhi_dump_ev_ctx(channel);
-
-       return 0;
-}
-
-static void ipa_mhi_gsi_ev_err_cb(struct gsi_evt_err_notify *notify)
-{
-       struct ipa3_mhi_channel_ctx *channel = notify->user_data;
-
-       IPAERR("channel id=%d client=%d state=%d\n",
-               channel->id, channel->ep->client, channel->state);
-       switch (notify->evt_id) {
-       case GSI_EVT_OUT_OF_BUFFERS_ERR:
-               IPA_MHI_ERR("Received GSI_EVT_OUT_OF_BUFFERS_ERR\n");
-               break;
-       case GSI_EVT_OUT_OF_RESOURCES_ERR:
-               IPA_MHI_ERR("Received GSI_EVT_OUT_OF_RESOURCES_ERR\n");
-               break;
-       case GSI_EVT_UNSUPPORTED_INTER_EE_OP_ERR:
-               IPA_MHI_ERR("Received GSI_EVT_UNSUPPORTED_INTER_EE_OP_ERR\n");
-               break;
-       case GSI_EVT_EVT_RING_EMPTY_ERR:
-               IPA_MHI_ERR("Received GSI_EVT_EVT_RING_EMPTY_ERR\n");
-               break;
-       default:
-               IPA_MHI_ERR("Unexpected err evt: %d\n", notify->evt_id);
-       }
-       IPA_MHI_ERR("err_desc=0x%x\n", notify->err_desc);
-}
-
-static void ipa_mhi_gsi_ch_err_cb(struct gsi_chan_err_notify *notify)
-{
-       struct ipa3_mhi_channel_ctx *channel = notify->chan_user_data;
-
-       IPAERR("channel id=%d client=%d state=%d\n",
-               channel->id, channel->ep->client, channel->state);
-       switch (notify->evt_id) {
-       case GSI_CHAN_INVALID_TRE_ERR:
-               IPA_MHI_ERR("Received GSI_CHAN_INVALID_TRE_ERR\n");
-               break;
-       case GSI_CHAN_NON_ALLOCATED_EVT_ACCESS_ERR:
-               IPA_MHI_ERR("Received GSI_CHAN_NON_ALLOCATED_EVT_ACCESS_ERR\n");
-               break;
-       case GSI_CHAN_OUT_OF_BUFFERS_ERR:
-               IPA_MHI_ERR("Received GSI_CHAN_OUT_OF_BUFFERS_ERR\n");
-               break;
-       case GSI_CHAN_OUT_OF_RESOURCES_ERR:
-               IPA_MHI_ERR("Received GSI_CHAN_OUT_OF_RESOURCES_ERR\n");
-               break;
-       case GSI_CHAN_UNSUPPORTED_INTER_EE_OP_ERR:
-               IPA_MHI_ERR("Received GSI_CHAN_UNSUPPORTED_INTER_EE_OP_ERR\n");
-               break;
-       case GSI_CHAN_HWO_1_ERR:
-               IPA_MHI_ERR("Received GSI_CHAN_HWO_1_ERR\n");
-               break;
-       default:
-               IPAERR("Unexpected err evt: %d\n", notify->evt_id);
-       }
-       IPA_MHI_ERR("err_desc=0x%x\n", notify->err_desc);
-}
-
-static int ipa3_mhi_get_ch_poll_cfg(struct ipa3_mhi_channel_ctx *channel,
-       int ring_size)
-{
-       switch (channel->ch_ctx_host.pollcfg) {
-       case 0:
-       /*set default polling configuration according to MHI spec*/
-               if (IPA_CLIENT_IS_PROD(channel->ep->client))
-                       return 7;
-               else
-                       return (ring_size/2)/8;
-               break;
-       default:
-               return channel->ch_ctx_host.pollcfg;
-       }
-}
-
-static int ipa_mhi_start_gsi_channel(struct ipa3_mhi_channel_ctx *channel,
-       int ipa_ep_idx)
-{
-       int res;
-       struct ipa3_ep_context *ep;
-       struct gsi_evt_ring_props ev_props;
-       struct ipa_mhi_msi_info msi;
-       struct gsi_chan_props ch_props;
-       union __packed gsi_channel_scratch ch_scratch;
-       struct ipa_gsi_ep_config *ep_cfg;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       if (channel->state != IPA_HW_MHI_CHANNEL_STATE_INVALID &&
-           channel->state != IPA_HW_MHI_CHANNEL_STATE_DISABLE) {
-               IPA_MHI_ERR("Invalid channel state %d\n", channel->state);
-               return -EFAULT;
-       }
-
-       msi = ipa3_mhi_ctx->msi;
-       ep = channel->ep;
-       ep_cfg = ipa_get_gsi_ep_info(ipa_ep_idx);
-       if (!ep_cfg) {
-               IPA_MHI_ERR("Wrong parameter, ep_cfg is NULL\n");
-               return -EPERM;
-       }
-       IPA_MHI_DBG("reading ch/ev context from host\n");
-       res = ipa_mhi_read_ch_ctx(channel);
-       if (res) {
-               IPA_MHI_ERR("ipa_mhi_read_ch_ctx failed %d\n", res);
-               return res;
-       }
-
-       /* allocate event ring only for the first time pipe is connected */
-       if (channel->state == IPA_HW_MHI_CHANNEL_STATE_INVALID) {
-               IPA_MHI_DBG("allocating event ring\n");
-               memset(&ev_props, 0, sizeof(ev_props));
-               ev_props.intf = GSI_EVT_CHTYPE_MHI_EV;
-               ev_props.intr = GSI_INTR_MSI;
-               ev_props.re_size = GSI_EVT_RING_RE_SIZE_16B;
-               ev_props.ring_len = channel->ev_ctx_host.rlen;
-               ev_props.ring_base_addr = IPA_MHI_HOST_ADDR_COND(
-                               channel->ev_ctx_host.rbase);
-               ev_props.int_modt = channel->ev_ctx_host.intmodt *
-                               IPA_SLEEP_CLK_RATE_KHZ;
-               ev_props.int_modc = channel->ev_ctx_host.intmodc;
-               ev_props.intvec = ((msi.data & ~msi.mask) |
-                               (channel->ev_ctx_host.msivec & msi.mask));
-               ev_props.msi_addr = IPA_MHI_HOST_ADDR_COND(
-                               (((u64)msi.addr_hi << 32) | msi.addr_low));
-               ev_props.rp_update_addr = IPA_MHI_HOST_ADDR_COND(
-                               channel->event_context_addr +
-                               offsetof(struct ipa3_mhi_ev_ctx, rp));
-               ev_props.exclusive = true;
-               ev_props.err_cb = ipa_mhi_gsi_ev_err_cb;
-               ev_props.user_data = channel;
-               ev_props.evchid_valid = true;
-               ev_props.evchid = channel->index + IPA_MHI_GSI_ER_START;
-               res = gsi_alloc_evt_ring(&ev_props, ipa3_ctx->gsi_dev_hdl,
-                       &channel->ep->gsi_evt_ring_hdl);
-               if (res) {
-                       IPA_MHI_ERR("gsi_alloc_evt_ring failed %d\n", res);
-                       goto fail_alloc_evt;
-                       return res;
-               }
-
-               channel->cached_gsi_evt_ring_hdl =
-                       channel->ep->gsi_evt_ring_hdl;
-
-       }
-
-       memset(&ch_props, 0, sizeof(ch_props));
-       ch_props.prot = GSI_CHAN_PROT_MHI;
-       ch_props.dir = IPA_CLIENT_IS_PROD(ep->client) ?
-               GSI_CHAN_DIR_TO_GSI : GSI_CHAN_DIR_FROM_GSI;
-       ch_props.ch_id = ep_cfg->ipa_gsi_chan_num;
-       ch_props.evt_ring_hdl = channel->cached_gsi_evt_ring_hdl;
-       ch_props.re_size = GSI_CHAN_RE_SIZE_16B;
-       ch_props.ring_len = channel->ch_ctx_host.rlen;
-       ch_props.ring_base_addr = IPA_MHI_HOST_ADDR_COND(
-                       channel->ch_ctx_host.rbase);
-       ch_props.use_db_eng = GSI_CHAN_DB_MODE;
-       ch_props.max_prefetch = GSI_ONE_PREFETCH_SEG;
-       ch_props.low_weight = 1;
-       ch_props.err_cb = ipa_mhi_gsi_ch_err_cb;
-       ch_props.chan_user_data = channel;
-       res = gsi_alloc_channel(&ch_props, ipa3_ctx->gsi_dev_hdl,
-               &channel->ep->gsi_chan_hdl);
-       if (res) {
-               IPA_MHI_ERR("gsi_alloc_channel failed %d\n",
-                       res);
-               goto fail_alloc_ch;
-       }
-
-       memset(&ch_scratch, 0, sizeof(ch_scratch));
-       ch_scratch.mhi.mhi_host_wp_addr = IPA_MHI_HOST_ADDR_COND(
-                       channel->channel_context_addr +
-                       offsetof(struct ipa3_mhi_ch_ctx, wp));
-       ch_scratch.mhi.assert_bit40 = ipa3_mhi_ctx->assert_bit40;
-       ch_scratch.mhi.max_outstanding_tre =
-               ep_cfg->ipa_if_tlv * ch_props.re_size;
-       ch_scratch.mhi.outstanding_threshold =
-               min(ep_cfg->ipa_if_tlv / 2, 8) * ch_props.re_size;
-       ch_scratch.mhi.oob_mod_threshold = 4;
-       if (channel->ch_ctx_host.brstmode == IPA_MHI_BURST_MODE_DEFAULT ||
-               channel->ch_ctx_host.brstmode == IPA_MHI_BURST_MODE_ENABLE) {
-               ch_scratch.mhi.burst_mode_enabled = true;
-               ch_scratch.mhi.polling_configuration =
-                       ipa3_mhi_get_ch_poll_cfg(channel,
-                               (ch_props.ring_len / ch_props.re_size));
-               ch_scratch.mhi.polling_mode = IPA_MHI_POLLING_MODE_DB_MODE;
-       } else {
-               ch_scratch.mhi.burst_mode_enabled = false;
-       }
-       res = gsi_write_channel_scratch(channel->ep->gsi_chan_hdl,
-               ch_scratch);
+       res = gsi_write_channel_scratch(ep->gsi_chan_hdl,
+               ch_scratch);
        if (res) {
                IPA_MHI_ERR("gsi_write_channel_scratch failed %d\n",
                        res);
-               goto fail_ch_scratch;
-       }
-       channel->brstmode_enabled = ch_scratch.mhi.burst_mode_enabled;
-       channel->ch_scratch.mhi = ch_scratch.mhi;
-
-       IPA_MHI_DBG("Starting channel\n");
-       res = gsi_start_channel(channel->ep->gsi_chan_hdl);
-       if (res) {
-               IPA_MHI_ERR("gsi_start_channel failed %d\n", res);
-               goto fail_ch_start;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-
-fail_ch_start:
-fail_ch_scratch:
-       gsi_dealloc_channel(channel->ep->gsi_chan_hdl);
-fail_alloc_ch:
-       gsi_dealloc_evt_ring(channel->ep->gsi_evt_ring_hdl);
-       channel->ep->gsi_evt_ring_hdl = ~0;
-fail_alloc_evt:
-       return res;
-}
-
-/**
- * ipa3_mhi_init() - Initialize IPA MHI driver
- * @params: initialization params
- *
- * This function is called by MHI client driver on boot to initialize IPA MHI
- * Driver. When this function returns device can move to READY state.
- * This function is doing the following:
- *     - Initialize MHI IPA internal data structures
- *     - Create IPA RM resources
- *     - Initialize debugfs
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa3_mhi_init(struct ipa_mhi_init_params *params)
-{
-       int res;
-       struct ipa_rm_create_params mhi_prod_params;
-       struct ipa_rm_create_params mhi_cons_params;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       if (!params) {
-               IPA_MHI_ERR("null args\n");
-               return -EINVAL;
-       }
-
-       if (!params->notify) {
-               IPA_MHI_ERR("null notify function\n");
-               return -EINVAL;
-       }
-
-       if (ipa3_mhi_ctx) {
-               IPA_MHI_ERR("already initialized\n");
-               return -EPERM;
-       }
-
-       IPA_MHI_DBG("msi: addr_lo = 0x%x addr_hi = 0x%x\n",
-               params->msi.addr_low, params->msi.addr_hi);
-       IPA_MHI_DBG("msi: data = 0x%x mask = 0x%x\n",
-               params->msi.data, params->msi.mask);
-       IPA_MHI_DBG("mmio_addr = 0x%x\n", params->mmio_addr);
-       IPA_MHI_DBG("first_ch_idx = 0x%x\n", params->first_ch_idx);
-       IPA_MHI_DBG("first_er_idx = 0x%x\n", params->first_er_idx);
-       IPA_MHI_DBG("notify = %pF priv = %p\n", params->notify, params->priv);
-       IPA_MHI_DBG("assert_bit40=%d\n", params->assert_bit40);
-       IPA_MHI_DBG("test_mode=%d\n", params->test_mode);
-
-       /* Initialize context */
-       ipa3_mhi_ctx = kzalloc(sizeof(*ipa3_mhi_ctx), GFP_KERNEL);
-       if (!ipa3_mhi_ctx) {
-               IPA_MHI_ERR("no memory\n");
-               res = -EFAULT;
-               goto fail_alloc_ctx;
-       }
-
-       ipa3_mhi_ctx->state = IPA_MHI_STATE_INITIALIZED;
-       ipa3_mhi_ctx->msi = params->msi;
-       ipa3_mhi_ctx->mmio_addr = params->mmio_addr;
-       ipa3_mhi_ctx->first_ch_idx = params->first_ch_idx;
-       ipa3_mhi_ctx->first_er_idx = params->first_er_idx;
-       ipa3_mhi_ctx->cb_notify = params->notify;
-       ipa3_mhi_ctx->cb_priv = params->priv;
-       ipa3_mhi_ctx->rm_cons_state = IPA_MHI_RM_STATE_RELEASED;
-       ipa3_mhi_ctx->qmi_req_id = 0;
-       ipa3_mhi_ctx->use_ipadma = true;
-       ipa3_mhi_ctx->assert_bit40 = !!params->assert_bit40;
-       ipa3_mhi_ctx->test_mode = params->test_mode;
-       init_completion(&ipa3_mhi_ctx->rm_prod_granted_comp);
-       spin_lock_init(&ipa3_mhi_ctx->state_lock);
-       init_completion(&ipa3_mhi_ctx->rm_cons_comp);
-
-       ipa3_mhi_ctx->wq = create_singlethread_workqueue("ipa_mhi_wq");
-       if (!ipa3_mhi_ctx->wq) {
-               IPA_MHI_ERR("failed to create workqueue\n");
-               res = -EFAULT;
-               goto fail_create_wq;
-       }
-
-       /* Create PROD in IPA RM */
-       memset(&mhi_prod_params, 0, sizeof(mhi_prod_params));
-       mhi_prod_params.name = IPA_RM_RESOURCE_MHI_PROD;
-       mhi_prod_params.floor_voltage = IPA_VOLTAGE_SVS;
-       mhi_prod_params.reg_params.notify_cb = ipa3_mhi_rm_prod_notify;
-       res = ipa_rm_create_resource(&mhi_prod_params);
-       if (res) {
-               IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_PROD\n");
-               goto fail_create_rm_prod;
-       }
-
-       /* Create CONS in IPA RM */
-       memset(&mhi_cons_params, 0, sizeof(mhi_cons_params));
-       mhi_cons_params.name = IPA_RM_RESOURCE_MHI_CONS;
-       mhi_cons_params.floor_voltage = IPA_VOLTAGE_SVS;
-       mhi_cons_params.request_resource = ipa3_mhi_rm_cons_request;
-       mhi_cons_params.release_resource = ipa3_mhi_rm_cons_release;
-       res = ipa_rm_create_resource(&mhi_cons_params);
-       if (res) {
-               IPA_MHI_ERR("fail to create IPA_RM_RESOURCE_MHI_CONS\n");
-               goto fail_create_rm_cons;
-       }
-
-       /* (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI)
-        * we need to move to READY state only after
-        * HPS/DPS/GSI firmware are loaded.
-        */
-
-       /* Initialize uC interface */
-       ipa3_uc_mhi_init(ipa3_mhi_uc_ready_cb,
-               ipa3_mhi_uc_wakeup_request_cb);
-       if (ipa3_uc_state_check() == 0)
-               ipa3_mhi_set_state(IPA_MHI_STATE_READY);
-
-       /* Initialize debugfs */
-       ipa3_mhi_debugfs_init();
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-
-fail_create_rm_cons:
-       ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
-fail_create_rm_prod:
-       destroy_workqueue(ipa3_mhi_ctx->wq);
-fail_create_wq:
-       kfree(ipa3_mhi_ctx);
-       ipa3_mhi_ctx = NULL;
-fail_alloc_ctx:
-       return res;
-}
-
-/**
- * ipa3_mhi_start() - Start IPA MHI engine
- * @params: pcie addresses for MHI
- *
- * This function is called by MHI client driver on MHI engine start for
- * handling MHI accelerated channels. This function is called after
- * ipa3_mhi_init() was called and can be called after MHI reset to restart MHI
- * engine. When this function returns device can move to M0 state.
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa3_mhi_start(struct ipa_mhi_start_params *params)
-{
-       int res;
-       struct gsi_device_scratch gsi_scratch;
-       struct ipa_gsi_ep_config *gsi_ep_info;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       if (!params) {
-               IPA_MHI_ERR("null args\n");
-               return -EINVAL;
-       }
-
-       if (!ipa3_mhi_ctx) {
-               IPA_MHI_ERR("not initialized\n");
-               return -EPERM;
-       }
-
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_SPS &&
-           ipa3_uc_state_check()) {
-               IPA_MHI_ERR("IPA uc is not loaded\n");
-               return -EAGAIN;
-       }
-
-       res = ipa3_mhi_set_state(IPA_MHI_STATE_STARTED);
-       if (res) {
-               IPA_MHI_ERR("ipa3_mhi_set_state %d\n", res);
-               return res;
-       }
-
-       ipa3_mhi_ctx->host_ctrl_addr = params->host_ctrl_addr;
-       ipa3_mhi_ctx->host_data_addr = params->host_data_addr;
-       ipa3_mhi_ctx->channel_context_array_addr =
-               params->channel_context_array_addr;
-       ipa3_mhi_ctx->event_context_array_addr =
-               params->event_context_array_addr;
-       IPADBG("host_ctrl_addr 0x%x\n", ipa3_mhi_ctx->host_ctrl_addr);
-       IPADBG("host_data_addr 0x%x\n", ipa3_mhi_ctx->host_data_addr);
-       IPADBG("channel_context_array_addr 0x%llx\n",
-               ipa3_mhi_ctx->channel_context_array_addr);
-       IPADBG("event_context_array_addr 0x%llx\n",
-               ipa3_mhi_ctx->event_context_array_addr);
-
-       /* Add MHI <-> Q6 dependencies to IPA RM */
-       res = ipa_rm_add_dependency(IPA_RM_RESOURCE_MHI_PROD,
-               IPA_RM_RESOURCE_Q6_CONS);
-       if (res && res != -EINPROGRESS) {
-               IPA_MHI_ERR("failed to add dependency %d\n", res);
-               goto fail_add_mhi_q6_dep;
-       }
-
-       res = ipa_rm_add_dependency(IPA_RM_RESOURCE_Q6_PROD,
-               IPA_RM_RESOURCE_MHI_CONS);
-       if (res && res != -EINPROGRESS) {
-               IPA_MHI_ERR("failed to add dependency %d\n", res);
-               goto fail_add_q6_mhi_dep;
-       }
-
-       res = ipa3_mhi_request_prod();
-       if (res) {
-               IPA_MHI_ERR("failed request prod %d\n", res);
-               goto fail_request_prod;
-       }
-
-       /* Initialize IPA MHI engine */
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-               gsi_ep_info = ipa_get_gsi_ep_info(
-                       ipa_get_ep_mapping(IPA_CLIENT_MHI_PROD));
-               if (!gsi_ep_info) {
-                       IPAERR("MHI PROD has no ep allocated\n");
-                       BUG();
-               }
-               memset(&gsi_scratch, 0, sizeof(gsi_scratch));
-               gsi_scratch.mhi_base_chan_idx_valid = true;
-               gsi_scratch.mhi_base_chan_idx = gsi_ep_info->ipa_gsi_chan_num +
-                       ipa3_mhi_ctx->first_ch_idx;
-               res = gsi_write_device_scratch(ipa3_ctx->gsi_dev_hdl,
-                       &gsi_scratch);
-               if (res) {
-                       IPA_MHI_ERR("failed to write device scratch %d\n", res);
-                       goto fail_init_engine;
-               }
-       } else {
-               res = ipa3_uc_mhi_init_engine(&ipa3_mhi_ctx->msi,
-                       ipa3_mhi_ctx->mmio_addr,
-                       ipa3_mhi_ctx->host_ctrl_addr,
-                       ipa3_mhi_ctx->host_data_addr,
-                       ipa3_mhi_ctx->first_ch_idx,
-                       ipa3_mhi_ctx->first_er_idx);
-               if (res) {
-                       IPA_MHI_ERR("failed to start MHI engine %d\n", res);
-                       goto fail_init_engine;
-               }
-
-               /* Update UL/DL sync if valid */
-               res = ipa3_uc_mhi_send_dl_ul_sync_info(
-                       ipa3_cached_dl_ul_sync_info);
-               if (res) {
-                       IPA_MHI_ERR("failed to update ul/dl sync %d\n", res);
-                       goto fail_init_engine;
-               }
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-
-fail_init_engine:
-       ipa3_mhi_release_prod();
-fail_request_prod:
-       ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
-               IPA_RM_RESOURCE_MHI_CONS);
-fail_add_q6_mhi_dep:
-       ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
-               IPA_RM_RESOURCE_Q6_CONS);
-fail_add_mhi_q6_dep:
-       ipa3_mhi_set_state(IPA_MHI_STATE_INITIALIZED);
-       return res;
-}
-
-/**
- * ipa3_mhi_connect_pipe() - Connect pipe to IPA and start corresponding
- * MHI channel
- * @in: connect parameters
- * @clnt_hdl: [out] client handle for this pipe
- *
- * This function is called by MHI client driver on MHI channel start.
- * This function is called after MHI engine was started.
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa3_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl)
-{
-       struct ipa3_ep_context *ep;
-       int ipa_ep_idx;
-       int res;
-       struct ipa3_mhi_channel_ctx *channel = NULL;
-       unsigned long flags;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       if (!in || !clnt_hdl) {
-               IPA_MHI_ERR("NULL args\n");
-               return -EINVAL;
-       }
-
-       if (in->sys.client >= IPA_CLIENT_MAX) {
-               IPA_MHI_ERR("bad param client:%d\n", in->sys.client);
-               return -EINVAL;
-       }
-
-       if (!IPA_CLIENT_IS_MHI(in->sys.client)) {
-               IPA_MHI_ERR("Invalid MHI client, client: %d\n", in->sys.client);
-               return -EINVAL;
-       }
-
-       IPA_MHI_DBG("channel=%d\n", in->channel_id);
-
-       spin_lock_irqsave(&ipa3_mhi_ctx->state_lock, flags);
-       if (!ipa3_mhi_ctx || ipa3_mhi_ctx->state != IPA_MHI_STATE_STARTED) {
-               IPA_MHI_ERR("IPA MHI was not started\n");
-               spin_unlock_irqrestore(&ipa3_mhi_ctx->state_lock, flags);
-               return -EINVAL;
-       }
-       spin_unlock_irqrestore(&ipa3_mhi_ctx->state_lock, flags);
-
-       ipa_ep_idx = ipa3_get_ep_mapping(in->sys.client);
-       if (ipa_ep_idx == -1) {
-               IPA_MHI_ERR("Invalid client.\n");
-               return -EINVAL;
-       }
-
-       ep = &ipa3_ctx->ep[ipa_ep_idx];
-
-       if (ep->valid == 1) {
-               IPA_MHI_ERR("EP already allocated.\n");
-               return -EPERM;
-       }
-
-       memset(ep, 0, offsetof(struct ipa3_ep_context, sys));
-       ep->valid = 1;
-       ep->skip_ep_cfg = in->sys.skip_ep_cfg;
-       ep->client = in->sys.client;
-       ep->client_notify = in->sys.notify;
-       ep->priv = in->sys.priv;
-       ep->keep_ipa_awake = in->sys.keep_ipa_awake;
-
-       channel = ipa3_mhi_get_channel_context(ep,
-               in->channel_id);
-       if (!channel) {
-               IPA_MHI_ERR("ipa3_mhi_get_channel_context failed\n");
-               res = -EINVAL;
-               goto fail_init_channel;
-       }
-
-       channel->channel_context_addr =
-               ipa3_mhi_ctx->channel_context_array_addr +
-                       channel->id * sizeof(struct ipa3_mhi_ch_ctx);
-
-       /* for event context address index needs to read from host */
-
-       IPA_MHI_DBG("client %d channelHandle %d channelIndex %d\n",
-               channel->ep->client, channel->index, channel->id);
-       IPA_MHI_DBG("channel_context_addr 0x%llx\n",
-               channel->channel_context_addr);
-
-       IPA_ACTIVE_CLIENTS_INC_EP(in->sys.client);
-
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-               res = ipa_mhi_start_gsi_channel(channel, ipa_ep_idx);
-               if (res) {
-                       IPA_MHI_ERR("ipa_mhi_start_gsi_channel failed %d\n",
-                               res);
-                       goto fail_start_channel;
-               }
-               channel->state = IPA_HW_MHI_CHANNEL_STATE_RUN;
-
-               res = ipa_mhi_read_write_host(IPA_MHI_DMA_TO_HOST,
-                       &channel->state, channel->channel_context_addr +
-                               offsetof(struct ipa3_mhi_ch_ctx, chstate),
-                               sizeof(((struct ipa3_mhi_ch_ctx *)0)->chstate));
-               if (res) {
-                       IPAERR("ipa_mhi_read_write_host failed\n");
-                       return res;
-
-               }
-       } else {
-               res = ipa_mhi_start_uc_channel(channel, ipa_ep_idx);
-               if (res) {
-                       IPA_MHI_ERR("ipa_mhi_start_uc_channel failed %d\n",
-                               res);
-                       goto fail_start_channel;
-               }
-               channel->state = IPA_HW_MHI_CHANNEL_STATE_RUN;
-       }
-
-       res = ipa3_enable_data_path(ipa_ep_idx);
-       if (res) {
-               IPA_MHI_ERR("enable data path failed res=%d clnt=%d.\n", res,
-                       ipa_ep_idx);
-               goto fail_enable_dp;
-       }
-
-       if (!ep->skip_ep_cfg) {
-               if (ipa3_cfg_ep(ipa_ep_idx, &in->sys.ipa_ep_cfg)) {
-                       IPAERR("fail to configure EP.\n");
-                       goto fail_ep_cfg;
-               }
-               if (ipa3_cfg_ep_status(ipa_ep_idx, &ep->status)) {
-                       IPAERR("fail to configure status of EP.\n");
-                       goto fail_ep_cfg;
-               }
-               IPA_MHI_DBG("ep configuration successful\n");
-       } else {
-               IPA_MHI_DBG("skipping ep configuration\n");
-       }
-
-       *clnt_hdl = ipa_ep_idx;
-
-       if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->sys.client))
-               ipa3_install_dflt_flt_rules(ipa_ep_idx);
-
-       if (!ep->keep_ipa_awake)
-               IPA_ACTIVE_CLIENTS_DEC_EP(in->sys.client);
-
-       ipa3_ctx->skip_ep_cfg_shadow[ipa_ep_idx] = ep->skip_ep_cfg;
-       IPA_MHI_DBG("client %d (ep: %d) connected\n", in->sys.client,
-               ipa_ep_idx);
-
-       IPA_MHI_FUNC_EXIT();
-
-       return 0;
-
-fail_ep_cfg:
-       ipa3_disable_data_path(ipa_ep_idx);
-fail_enable_dp:
-       ipa3_mhi_reset_channel(channel);
-fail_start_channel:
-       IPA_ACTIVE_CLIENTS_DEC_EP(in->sys.client);
-fail_init_channel:
-       memset(ep, 0, offsetof(struct ipa3_ep_context, sys));
-       return -EPERM;
-}
-
-/**
- * ipa3_mhi_disconnect_pipe() - Disconnect pipe from IPA and reset corresponding
- * MHI channel
- * @clnt_hdl: client handle for this pipe
- *
- * This function is called by MHI client driver on MHI channel reset.
- * This function is called after MHI channel was started.
- * This function is doing the following:
- *     - Send command to uC/GSI to reset corresponding MHI channel
- *     - Configure IPA EP control
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa3_mhi_disconnect_pipe(u32 clnt_hdl)
-{
-       struct ipa3_ep_context *ep;
-       static struct ipa3_mhi_channel_ctx *channel;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-
-       if (clnt_hdl >= ipa3_ctx->ipa_num_pipes) {
-               IPAERR("invalid handle %d\n", clnt_hdl);
-               return -EINVAL;
-       }
-
-       if (ipa3_ctx->ep[clnt_hdl].valid == 0) {
-               IPAERR("pipe was not connected %d\n", clnt_hdl);
-               return -EINVAL;
-       }
-
-       if (!ipa3_mhi_ctx) {
-               IPA_MHI_ERR("IPA MHI was not initialized\n");
-               return -EINVAL;
-       }
-
-       if (!IPA_CLIENT_IS_MHI(ipa3_ctx->ep[clnt_hdl].client)) {
-               IPAERR("invalid IPA MHI client, client: %d\n",
-                       ipa3_ctx->ep[clnt_hdl].client);
-               return -EINVAL;
-       }
-
-       channel = ipa3_mhi_get_channel_context_by_clnt_hdl(clnt_hdl);
-       if (!channel) {
-               IPAERR("invalid clnt index\n");
-               return -EINVAL;
-       }
-       ep = &ipa3_ctx->ep[clnt_hdl];
-
-       if (!ep->keep_ipa_awake)
-               IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl));
-       res = ipa3_mhi_reset_channel(channel);
-       if (res) {
-               IPA_MHI_ERR("ipa3_mhi_reset_channel failed %d\n", res);
-               goto fail_reset_channel;
-       }
-
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-               res = gsi_dealloc_channel(channel->ep->gsi_chan_hdl);
-               if (res) {
-                       IPAERR("gsi_dealloc_channel failed %d\n", res);
-                       goto fail_reset_channel;
-               }
-       }
-
-       ep->valid = 0;
-       ipa3_delete_dflt_flt_rules(clnt_hdl);
-       IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
-
-       IPA_MHI_DBG("client (ep: %d) disconnected\n", clnt_hdl);
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-
-fail_reset_channel:
-       if (!ep->keep_ipa_awake)
-               IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
-       return res;
-}
-
-
-static int ipa3_mhi_suspend_ul_channels(void)
-{
-       int i;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               if (!ipa3_mhi_ctx->ul_channels[i].valid)
-                       continue;
-               if (ipa3_mhi_ctx->ul_channels[i].state !=
-                   IPA_HW_MHI_CHANNEL_STATE_RUN)
-                       continue;
-               IPA_MHI_DBG_LOW("suspending channel %d\n",
-                       ipa3_mhi_ctx->ul_channels[i].id);
-
-               if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI)
-                       res = ipa3_mhi_suspend_gsi_channel(
-                               &ipa3_mhi_ctx->ul_channels[i]);
-               else
-                       res = ipa3_uc_mhi_suspend_channel(
-                               ipa3_mhi_ctx->ul_channels[i].index);
-
-               if (res) {
-                       IPA_MHI_ERR("failed to suspend channel %d error %d\n",
-                               i, res);
-                       return res;
-               }
-               ipa3_mhi_ctx->ul_channels[i].state =
-                       IPA_HW_MHI_CHANNEL_STATE_SUSPEND;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-static int ipa3_mhi_resume_ul_channels(bool LPTransitionRejected)
-{
-       int i;
-       int res;
-       struct ipa3_mhi_channel_ctx *channel;
-
-       IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               if (!ipa3_mhi_ctx->ul_channels[i].valid)
-                       continue;
-               if (ipa3_mhi_ctx->ul_channels[i].state !=
-                   IPA_HW_MHI_CHANNEL_STATE_SUSPEND)
-                       continue;
-               channel = &ipa3_mhi_ctx->ul_channels[i];
-               IPA_MHI_DBG_LOW("resuming channel %d\n", channel->id);
-
-               if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-                       if (channel->brstmode_enabled &&
-                            !LPTransitionRejected) {
-                               /*
-                                * set polling mode bit to DB mode before
-                                * resuming the channel
-                                */
-                               res = gsi_write_channel_scratch(
-                                       channel->ep->gsi_chan_hdl,
-                                       channel->ch_scratch);
-                               if (res) {
-                                       IPA_MHI_ERR("write ch scratch fail %d\n"
-                                               , res);
-                                       return res;
-                               }
-                       }
-                       res = gsi_start_channel(channel->ep->gsi_chan_hdl);
-               } else {
-                       res = ipa3_uc_mhi_resume_channel(channel->index,
-                               LPTransitionRejected);
-               }
-
-               if (res) {
-                       IPA_MHI_ERR("failed to resume channel %d error %d\n",
-                               i, res);
-                       return res;
-               }
-
-               channel->stop_in_proc = false;
-               channel->state = IPA_HW_MHI_CHANNEL_STATE_RUN;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa3_mhi_stop_event_update_ul_channels(void)
-{
-       int i;
-       int res;
-
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI)
-               return 0;
-
-       IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               if (!ipa3_mhi_ctx->ul_channels[i].valid)
-                       continue;
-               if (ipa3_mhi_ctx->ul_channels[i].state !=
-                   IPA_HW_MHI_CHANNEL_STATE_SUSPEND)
-                       continue;
-               IPA_MHI_DBG_LOW("stop update event channel %d\n",
-                       ipa3_mhi_ctx->ul_channels[i].id);
-               res = ipa3_uc_mhi_stop_event_update_channel(
-                       ipa3_mhi_ctx->ul_channels[i].index);
-               if (res) {
-                       IPA_MHI_ERR("failed stop event channel %d error %d\n",
-                               i, res);
-                       return res;
-               }
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa3_mhi_suspend_dl_channels(void)
-{
-       int i;
-       int res;
-
-       IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-               if (!ipa3_mhi_ctx->dl_channels[i].valid)
-                       continue;
-               if (ipa3_mhi_ctx->dl_channels[i].state !=
-                   IPA_HW_MHI_CHANNEL_STATE_RUN)
-                       continue;
-               IPA_MHI_DBG_LOW("suspending channel %d\n",
-                       ipa3_mhi_ctx->dl_channels[i].id);
-               if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI)
-                       res = ipa3_mhi_suspend_gsi_channel(
-                               &ipa3_mhi_ctx->dl_channels[i]);
-               else
-                       res = ipa3_uc_mhi_suspend_channel(
-                               ipa3_mhi_ctx->dl_channels[i].index);
-               if (res) {
-                       IPA_MHI_ERR("failed to suspend channel %d error %d\n",
-                               i, res);
-                       return res;
-               }
-               ipa3_mhi_ctx->dl_channels[i].state =
-                       IPA_HW_MHI_CHANNEL_STATE_SUSPEND;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa3_mhi_resume_dl_channels(bool LPTransitionRejected)
-{
-       int i;
-       int res;
-       struct ipa3_mhi_channel_ctx *channel;
-
-       IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-               if (!ipa3_mhi_ctx->dl_channels[i].valid)
-                       continue;
-               if (ipa3_mhi_ctx->dl_channels[i].state !=
-                   IPA_HW_MHI_CHANNEL_STATE_SUSPEND)
-                       continue;
-               channel = &ipa3_mhi_ctx->dl_channels[i];
-               IPA_MHI_DBG_LOW("resuming channel %d\n", channel->id);
-
-               if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-                       if (channel->brstmode_enabled &&
-                           !LPTransitionRejected) {
-                               /*
-                                * set polling mode bit to DB mode before
-                                * resuming the channel
-                                */
-                               res = gsi_write_channel_scratch(
-                                       channel->ep->gsi_chan_hdl,
-                                       channel->ch_scratch);
-                               if (res) {
-                                       IPA_MHI_ERR("write ch scratch fail %d\n"
-                                               , res);
-                                       return res;
-                               }
-                       }
-                       res = gsi_start_channel(channel->ep->gsi_chan_hdl);
-               } else {
-                       res = ipa3_uc_mhi_resume_channel(channel->index,
-                               LPTransitionRejected);
-               }
-               if (res) {
-                       IPA_MHI_ERR("failed to resume channel %d error %d\n",
-                               i, res);
-                       return res;
-               }
-               channel->stop_in_proc = false;
-               channel->state = IPA_HW_MHI_CHANNEL_STATE_RUN;
-       }
-
-       IPA_MHI_FUNC_EXIT();
-       return 0;
-}
-
-static int ipa3_mhi_stop_event_update_dl_channels(void)
-{
-       int i;
-       int res;
+               goto fail_ch_scratch;
+       }
 
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI)
-               return 0;
+       *params->mhi = ch_scratch.mhi;
 
-       IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-               if (!ipa3_mhi_ctx->dl_channels[i].valid)
-                       continue;
-               if (ipa3_mhi_ctx->dl_channels[i].state !=
-                   IPA_HW_MHI_CHANNEL_STATE_SUSPEND)
-                       continue;
-               IPA_MHI_DBG_LOW("stop update event channel %d\n",
-                       ipa3_mhi_ctx->dl_channels[i].id);
-               res = ipa3_uc_mhi_stop_event_update_channel(
-                       ipa3_mhi_ctx->dl_channels[i].index);
-               if (res) {
-                       IPA_MHI_ERR("failed stop event channel %d error %d\n",
-                               i, res);
-                       return res;
-               }
+       IPA_MHI_DBG("Starting channel\n");
+       res = gsi_start_channel(ep->gsi_chan_hdl);
+       if (res) {
+               IPA_MHI_ERR("gsi_start_channel failed %d\n", res);
+               goto fail_ch_start;
        }
 
        IPA_MHI_FUNC_EXIT();
        return 0;
+
+fail_ch_start:
+fail_ch_scratch:
+       gsi_dealloc_channel(ep->gsi_chan_hdl);
+fail_alloc_ch:
+       gsi_dealloc_evt_ring(ep->gsi_evt_ring_hdl);
+       ep->gsi_evt_ring_hdl = ~0;
+fail_alloc_evt:
+       return res;
 }
 
-static bool ipa3_mhi_check_pending_packets_from_host(void)
+int ipa3_mhi_init_engine(struct ipa_mhi_init_engine *params)
 {
-       int i;
        int res;
-       struct ipa3_mhi_channel_ctx *channel;
+       struct gsi_device_scratch gsi_scratch;
+       struct ipa_gsi_ep_config *gsi_ep_info;
 
        IPA_MHI_FUNC_ENTRY();
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               channel = &ipa3_mhi_ctx->ul_channels[i];
-               if (!channel->valid)
-                       continue;
-
-               res = gsi_query_channel_info(channel->ep->gsi_chan_hdl,
-                       &channel->ch_info);
-               if (res) {
-                       IPAERR("gsi_query_channel_info failed\n");
-                       return true;
-               }
-               res = ipa_mhi_read_ch_ctx(channel);
-               if (res) {
-                       IPA_MHI_ERR("ipa_mhi_read_ch_ctx failed %d\n", res);
-                       return true;
-               }
-
-               if (channel->ch_info.rp != channel->ch_ctx_host.wp) {
-                       IPA_MHI_DBG("There are pending packets from host\n");
-                       IPA_MHI_DBG("device rp 0x%llx host 0x%llx\n",
-                               channel->ch_info.rp, channel->ch_ctx_host.wp);
 
-                       return true;
-               }
+       if (!params) {
+               IPA_MHI_ERR("null args\n");
+               return -EINVAL;
        }
 
-       IPA_MHI_FUNC_EXIT();
-       return false;
-}
-
-static void ipa3_mhi_update_host_ch_state(bool update_rp)
-{
-       int i;
-       int res;
-       struct ipa3_mhi_channel_ctx *channel;
-
-       for (i = 0; i < IPA_MHI_MAX_UL_CHANNELS; i++) {
-               channel = &ipa3_mhi_ctx->ul_channels[i];
-               if (!channel->valid)
-                       continue;
-
-               if (update_rp) {
-                       res = gsi_query_channel_info(channel->ep->gsi_chan_hdl,
-                               &channel->ch_info);
-                       if (res) {
-                               IPAERR("gsi_query_channel_info failed\n");
-                               BUG();
-                               return;
-                       }
-
-                       res = ipa_mhi_read_write_host(IPA_MHI_DMA_TO_HOST,
-                               &channel->ch_info.rp,
-                               channel->channel_context_addr +
-                                       offsetof(struct ipa3_mhi_ch_ctx, rp),
-                               sizeof(channel->ch_info.rp));
-                       if (res) {
-                               IPAERR("ipa_mhi_read_write_host failed\n");
-                               BUG();
-                               return;
-                       }
-               }
-
-               res = ipa_mhi_read_write_host(IPA_MHI_DMA_TO_HOST,
-                       &channel->state, channel->channel_context_addr +
-                               offsetof(struct ipa3_mhi_ch_ctx, chstate),
-                       sizeof(((struct ipa3_mhi_ch_ctx *)0)->chstate));
-               if (res) {
-                       IPAERR("ipa_mhi_read_write_host failed\n");
-                       BUG();
-                       return;
-               }
+       /* Initialize IPA MHI engine */
+       gsi_ep_info = ipa_get_gsi_ep_info(
+               ipa_get_ep_mapping(IPA_CLIENT_MHI_PROD));
+       if (!gsi_ep_info) {
+               IPAERR("MHI PROD has no ep allocated\n");
+               ipa_assert();
        }
-
-       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-               channel = &ipa3_mhi_ctx->dl_channels[i];
-               if (!channel->valid)
-                       continue;
-
-               if (update_rp) {
-                       res = gsi_query_channel_info(channel->ep->gsi_chan_hdl,
-                               &channel->ch_info);
-                       if (res) {
-                               IPAERR("gsi_query_channel_info failed\n");
-                               BUG();
-                               return;
-                       }
-
-                       res = ipa_mhi_read_write_host(IPA_MHI_DMA_TO_HOST,
-                               &channel->ch_info.rp,
-                               channel->channel_context_addr +
-                                       offsetof(struct ipa3_mhi_ch_ctx, rp),
-                               sizeof(channel->ch_info.rp));
-                       if (res) {
-                               IPAERR("ipa_mhi_read_write_host failed\n");
-                               BUG();
-                               return;
-                       }
-               }
-
-               res = ipa_mhi_read_write_host(IPA_MHI_DMA_TO_HOST,
-                       &channel->state, channel->channel_context_addr +
-                       offsetof(struct ipa3_mhi_ch_ctx, chstate),
-                       sizeof(((struct ipa3_mhi_ch_ctx *)0)->chstate));
-               if (res) {
-                       IPAERR("ipa_mhi_read_write_host failed\n");
-                       BUG();
-               }
+       memset(&gsi_scratch, 0, sizeof(gsi_scratch));
+       gsi_scratch.mhi_base_chan_idx_valid = true;
+       gsi_scratch.mhi_base_chan_idx = gsi_ep_info->ipa_gsi_chan_num +
+               params->gsi.first_ch_idx;
+       res = gsi_write_device_scratch(ipa3_ctx->gsi_dev_hdl,
+               &gsi_scratch);
+       if (res) {
+               IPA_MHI_ERR("failed to write device scratch %d\n", res);
+               goto fail_init_engine;
        }
-}
-
-static bool ipa3_mhi_has_open_aggr_frame(void)
-{
-       struct ipa3_mhi_channel_ctx *channel;
-       u32 aggr_state_active;
-       int i;
-       int ipa_ep_idx;
-
-       aggr_state_active = ipahal_read_reg(IPA_STATE_AGGR_ACTIVE);
-       IPA_MHI_DBG_LOW("IPA_STATE_AGGR_ACTIVE_OFST 0x%x\n", aggr_state_active);
-
-       for (i = 0; i < IPA_MHI_MAX_DL_CHANNELS; i++) {
-               channel = &ipa3_mhi_ctx->dl_channels[i];
-
-               if (!channel->valid)
-                       continue;
-
-               ipa_ep_idx = ipa_get_ep_mapping(channel->ep->client);
-               if (ipa_ep_idx == -1) {
-                       BUG();
-                       return false;
-               }
 
-               if ((1 << ipa_ep_idx) & aggr_state_active)
-                       return true;
-       }
+       IPA_MHI_FUNC_EXIT();
+       return 0;
 
-       return false;
+fail_init_engine:
+       return res;
 }
 
-
 /**
- * ipa3_mhi_suspend() - Suspend MHI accelerated channels
- * @force:
- *     false: in case of data pending in IPA, MHI channels will not be
- *             suspended and function will fail.
- *     true:  in case of data pending in IPA, make sure no further access from
- *             IPA to PCIe is possible. In this case suspend cannot fail.
+ * ipa3_connect_mhi_pipe() - Connect pipe to IPA and start corresponding
+ * MHI channel
+ * @in: connect parameters
+ * @clnt_hdl: [out] client handle for this pipe
  *
- * This function is called by MHI client driver on MHI suspend.
- * This function is called after MHI channel was started.
- * When this function returns device can move to M1/M2/M3/D3cold state.
+ * This function is called by IPA MHI client driver on MHI channel start.
+ * This function is called after MHI engine was started.
  *
  * Return codes: 0       : success
  *              negative : error
  */
-int ipa3_mhi_suspend(bool force)
+int ipa3_connect_mhi_pipe(struct ipa_mhi_connect_params_internal *in,
+               u32 *clnt_hdl)
 {
+       struct ipa3_ep_context *ep;
+       int ipa_ep_idx;
        int res;
-       bool empty;
-       bool force_clear = false;
+       enum ipa_client_type client;
 
        IPA_MHI_FUNC_ENTRY();
 
-       res = ipa3_mhi_set_state(IPA_MHI_STATE_SUSPEND_IN_PROGRESS);
-       if (res) {
-               IPA_MHI_ERR("ipa3_mhi_set_state failed %d\n", res);
-               return res;
+       if (!in || !clnt_hdl) {
+               IPA_MHI_ERR("NULL args\n");
+               return -EINVAL;
        }
 
-       res = ipa3_mhi_suspend_ul_channels();
-       if (res) {
-               IPA_MHI_ERR("ipa3_mhi_suspend_ul_channels failed %d\n", res);
-               goto fail_suspend_ul_channel;
+       client = in->sys->client;
+       ipa_ep_idx = ipa3_get_ep_mapping(client);
+       if (ipa_ep_idx == -1) {
+               IPA_MHI_ERR("Invalid client.\n");
+               return -EINVAL;
        }
 
-       empty = ipa3_mhi_wait_for_ul_empty_timeout(
-                       IPA_MHI_CH_EMPTY_TIMEOUT_MSEC);
-
-       if (!empty) {
-               if (force) {
-                       res = ipa3_mhi_enable_force_clear(
-                               ipa3_mhi_ctx->qmi_req_id, false);
-                       if (res) {
-                               IPA_MHI_ERR("failed to enable force clear\n");
-                               BUG();
-                               return res;
-                       }
-                       force_clear = true;
-                       IPA_MHI_DBG_LOW("force clear datapath enabled\n");
-
-                       empty = ipa3_mhi_wait_for_ul_empty_timeout(
-                               IPA_MHI_CH_EMPTY_TIMEOUT_MSEC);
-                       IPADBG("empty=%d\n", empty);
-                       if (!empty && ipa3_ctx->transport_prototype
-                               == IPA_TRANSPORT_TYPE_GSI) {
-                               IPA_MHI_ERR("Failed to suspend UL channels\n");
-                               if (ipa3_mhi_ctx->test_mode) {
-                                       res = -EAGAIN;
-                                       goto fail_suspend_ul_channel;
-                               }
-
-                               BUG();
-                       }
-               } else {
-                       IPA_MHI_DBG("IPA not empty\n");
-                       res = -EAGAIN;
-                       goto fail_suspend_ul_channel;
-               }
-       }
+       ep = &ipa3_ctx->ep[ipa_ep_idx];
 
-       if (force_clear) {
-               res = ipa3_mhi_disable_force_clear(ipa3_mhi_ctx->qmi_req_id);
-               if (res) {
-                       IPA_MHI_ERR("failed to disable force clear\n");
-                       BUG();
-                       return res;
-               }
-               IPA_MHI_DBG_LOW("force clear datapath disabled\n");
-               ipa3_mhi_ctx->qmi_req_id++;
+       if (ep->valid == 1) {
+               IPA_MHI_ERR("EP already allocated.\n");
+               return -EPERM;
        }
 
-       if (!force && ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-               if (ipa3_mhi_check_pending_packets_from_host()) {
-                       res = -EAGAIN;
-                       goto fail_suspend_ul_channel;
-               }
-       }
+       memset(ep, 0, offsetof(struct ipa3_ep_context, sys));
+       ep->valid = 1;
+       ep->skip_ep_cfg = in->sys->skip_ep_cfg;
+       ep->client = client;
+       ep->client_notify = in->sys->notify;
+       ep->priv = in->sys->priv;
+       ep->keep_ipa_awake = in->sys->keep_ipa_awake;
 
-       res = ipa3_mhi_stop_event_update_ul_channels();
+       res = ipa_mhi_start_gsi_channel(client,
+                                       ipa_ep_idx, &in->start.gsi);
        if (res) {
-               IPA_MHI_ERR(
-                       "ipa3_mhi_stop_event_update_ul_channels failed %d\n",
+               IPA_MHI_ERR("ipa_mhi_start_gsi_channel failed %d\n",
                        res);
-               goto fail_suspend_ul_channel;
-       }
-
-       /*
-        * hold IPA clocks and release them after all
-        * IPA RM resource are released to make sure tag process will not start
-        */
-       IPA_ACTIVE_CLIENTS_INC_SIMPLE();
-
-       IPA_MHI_DBG_LOW("release prod\n");
-       res = ipa3_mhi_release_prod();
-       if (res) {
-               IPA_MHI_ERR("ipa3_mhi_release_prod failed %d\n", res);
-               goto fail_release_prod;
-       }
-
-       IPA_MHI_DBG_LOW("wait for cons release\n");
-       res = ipa3_mhi_wait_for_cons_release();
-       if (res) {
-               IPA_MHI_ERR("ipa3_mhi_wait_for_cons_release failed %d\n", res);
-               goto fail_release_cons;
-       }
-
-       usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN, IPA_MHI_SUSPEND_SLEEP_MAX);
-
-       res = ipa3_mhi_suspend_dl_channels();
-       if (res) {
-               IPA_MHI_ERR("ipa3_mhi_suspend_dl_channels failed %d\n", res);
-               goto fail_suspend_dl_channel;
+               goto fail_start_channel;
        }
 
-       res = ipa3_mhi_stop_event_update_dl_channels();
+       res = ipa3_enable_data_path(ipa_ep_idx);
        if (res) {
-               IPA_MHI_ERR("failed to stop event update on DL %d\n", res);
-               goto fail_stop_event_update_dl_channel;
+               IPA_MHI_ERR("enable data path failed res=%d clnt=%d.\n", res,
+                       ipa_ep_idx);
+               goto fail_ep_cfg;
        }
 
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-               if (ipa3_mhi_has_open_aggr_frame()) {
-                       IPA_MHI_DBG("There is an open aggr frame\n");
-                       if (force) {
-                               ipa3_mhi_ctx->trigger_wakeup = true;
-                       } else {
-                               res = -EAGAIN;
-                               goto fail_stop_event_update_dl_channel;
-                       }
+       if (!ep->skip_ep_cfg) {
+               if (ipa3_cfg_ep(ipa_ep_idx, &in->sys->ipa_ep_cfg)) {
+                       IPAERR("fail to configure EP.\n");
+                       goto fail_ep_cfg;
+               }
+               if (ipa3_cfg_ep_status(ipa_ep_idx, &ep->status)) {
+                       IPAERR("fail to configure status of EP.\n");
+                       goto fail_ep_cfg;
                }
+               IPA_MHI_DBG("ep configuration successful\n");
+       } else {
+               IPA_MHI_DBG("skipping ep configuration\n");
        }
 
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI)
-               ipa3_mhi_update_host_ch_state(true);
+       *clnt_hdl = ipa_ep_idx;
 
-       if (!empty)
-               ipa3_ctx->tag_process_before_gating = false;
+       if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(client))
+               ipa3_install_dflt_flt_rules(ipa_ep_idx);
 
-       res = ipa3_mhi_set_state(IPA_MHI_STATE_SUSPENDED);
-       if (res) {
-               IPA_MHI_ERR("ipa3_mhi_set_state failed %d\n", res);
-               goto fail_release_cons;
-       }
+       ipa3_ctx->skip_ep_cfg_shadow[ipa_ep_idx] = ep->skip_ep_cfg;
+       IPA_MHI_DBG("client %d (ep: %d) connected\n", client,
+               ipa_ep_idx);
 
-       IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
        IPA_MHI_FUNC_EXIT();
+
        return 0;
 
-fail_stop_event_update_dl_channel:
-       ipa3_mhi_resume_dl_channels(true);
-fail_suspend_dl_channel:
-fail_release_cons:
-       ipa3_mhi_request_prod();
-fail_release_prod:
-       IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
-fail_suspend_ul_channel:
-       ipa3_mhi_resume_ul_channels(true);
-       ipa3_mhi_set_state(IPA_MHI_STATE_STARTED);
-       if (force_clear) {
-               if (ipa3_mhi_disable_force_clear(ipa3_mhi_ctx->qmi_req_id)) {
-                       IPA_MHI_ERR("failed to disable force clear\n");
-                       BUG();
-               }
-               IPA_MHI_DBG_LOW("force clear datapath disabled\n");
-               ipa3_mhi_ctx->qmi_req_id++;
-       }
-       return res;
+fail_ep_cfg:
+       ipa3_disable_data_path(ipa_ep_idx);
+fail_start_channel:
+       memset(ep, 0, offsetof(struct ipa3_ep_context, sys));
+       return -EPERM;
 }
 
 /**
- * ipa3_mhi_resume() - Resume MHI accelerated channels
+ * ipa3_disconnect_mhi_pipe() - Disconnect pipe from IPA and reset corresponding
+ * MHI channel
+ * @clnt_hdl: client handle for this pipe
  *
- * This function is called by MHI client driver on MHI resume.
- * This function is called after MHI channel was suspended.
- * When this function returns device can move to M0 state.
+ * This function is called by IPA MHI client driver on MHI channel reset.
+ * This function is called after MHI channel was started.
  * This function is doing the following:
- *     - Send command to uC/GSI to resume corresponding MHI channel
- *     - Request MHI_PROD in IPA RM
- *     - Resume data to IPA
+ *     - Send command to uC/GSI to reset corresponding MHI channel
+ *     - Configure IPA EP control
  *
  * Return codes: 0       : success
  *              negative : error
  */
-int ipa3_mhi_resume(void)
+int ipa3_disconnect_mhi_pipe(u32 clnt_hdl)
 {
+       struct ipa3_ep_context *ep;
        int res;
-       bool dl_channel_resumed = false;
 
        IPA_MHI_FUNC_ENTRY();
 
-       res = ipa3_mhi_set_state(IPA_MHI_STATE_RESUME_IN_PROGRESS);
-       if (res) {
-               IPA_MHI_ERR("ipa3_mhi_set_state failed %d\n", res);
-               return res;
-       }
-
-       if (ipa3_mhi_ctx->rm_cons_state == IPA_MHI_RM_STATE_REQUESTED) {
-               /* resume all DL channels */
-               res = ipa3_mhi_resume_dl_channels(false);
-               if (res) {
-                       IPA_MHI_ERR("ipa3_mhi_resume_dl_channels failed %d\n",
-                               res);
-                       goto fail_resume_dl_channels;
-               }
-               dl_channel_resumed = true;
-
-               ipa_rm_notify_completion(IPA_RM_RESOURCE_GRANTED,
-                       IPA_RM_RESOURCE_MHI_CONS);
-               ipa3_mhi_ctx->rm_cons_state = IPA_MHI_RM_STATE_GRANTED;
+       if (clnt_hdl >= ipa3_ctx->ipa_num_pipes) {
+               IPAERR("invalid handle %d\n", clnt_hdl);
+               return -EINVAL;
        }
 
-       res = ipa3_mhi_request_prod();
-       if (res) {
-               IPA_MHI_ERR("ipa3_mhi_request_prod failed %d\n", res);
-               goto fail_request_prod;
+       if (ipa3_ctx->ep[clnt_hdl].valid == 0) {
+               IPAERR("pipe was not connected %d\n", clnt_hdl);
+               return -EINVAL;
        }
 
-       /* resume all UL channels */
-       res = ipa3_mhi_resume_ul_channels(false);
-       if (res) {
-               IPA_MHI_ERR("ipa3_mhi_resume_ul_channels failed %d\n", res);
-               goto fail_resume_ul_channels;
-       }
+       ep = &ipa3_ctx->ep[clnt_hdl];
 
-       if (!dl_channel_resumed) {
-               res = ipa3_mhi_resume_dl_channels(false);
+       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
+               res = gsi_dealloc_channel(ep->gsi_chan_hdl);
                if (res) {
-                       IPA_MHI_ERR("ipa3_mhi_resume_dl_channels failed %d\n",
-                               res);
-                       goto fail_resume_dl_channels2;
+                       IPAERR("gsi_dealloc_channel failed %d\n", res);
+                       goto fail_reset_channel;
                }
        }
 
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI)
-               ipa3_mhi_update_host_ch_state(false);
-
-       res = ipa3_mhi_set_state(IPA_MHI_STATE_STARTED);
-       if (res) {
-               IPA_MHI_ERR("ipa3_mhi_set_state failed %d\n", res);
-               goto fail_set_state;
-       }
+       ep->valid = 0;
+       ipa3_delete_dflt_flt_rules(clnt_hdl);
 
+       IPA_MHI_DBG("client (ep: %d) disconnected\n", clnt_hdl);
        IPA_MHI_FUNC_EXIT();
        return 0;
 
-fail_set_state:
-       ipa3_mhi_suspend_dl_channels();
-fail_resume_dl_channels2:
-       ipa3_mhi_suspend_ul_channels();
-fail_resume_ul_channels:
-       ipa3_mhi_release_prod();
-fail_request_prod:
-       ipa3_mhi_suspend_dl_channels();
-fail_resume_dl_channels:
-       ipa3_mhi_set_state(IPA_MHI_STATE_SUSPENDED);
+fail_reset_channel:
        return res;
 }
 
-static int  ipa3_mhi_destroy_channels(struct ipa3_mhi_channel_ctx *channels,
-       int num_of_channels)
+int ipa3_mhi_resume_channels_internal(enum ipa_client_type client,
+               bool LPTransitionRejected, bool brstmode_enabled,
+               union __packed gsi_channel_scratch ch_scratch, u8 index)
 {
-       struct ipa3_mhi_channel_ctx *channel;
-       int i, res;
-       u32 clnt_hdl;
-
-       for (i = 0; i < num_of_channels; i++) {
-               channel = &channels[i];
-               if (!channel->valid)
-                       continue;
-               if (channel->state == IPA_HW_MHI_CHANNEL_STATE_INVALID)
-                       continue;
-               if (channel->state != IPA_HW_MHI_CHANNEL_STATE_DISABLE) {
-                       clnt_hdl = ipa3_get_ep_mapping(channel->ep->client);
-                       IPA_MHI_DBG("disconnect pipe (ep: %d)\n", clnt_hdl);
-                       res = ipa3_mhi_disconnect_pipe(clnt_hdl);
-                       if (res) {
-                               IPAERR("failed to disconnect pipe %d, err %d\n",
-                                       clnt_hdl, res);
-                               goto fail;
-                       }
-               }
+       int res;
+       int ipa_ep_idx;
+       struct ipa3_ep_context *ep;
+
+       IPA_MHI_FUNC_ENTRY();
 
-               if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_GSI) {
-                       IPA_MHI_DBG("reset event ring (hdl: %lu, ep: %d)\n",
-                               channel->ep->gsi_evt_ring_hdl, clnt_hdl);
-                       res = gsi_reset_evt_ring(channel->ep->gsi_evt_ring_hdl);
-                       if (res) {
-                               IPAERR(" failed to reset evt ring %lu, err %d\n"
-                                       , channel->ep->gsi_evt_ring_hdl, res);
-                               goto fail;
-                       }
-                       res = gsi_dealloc_evt_ring(
-                               channel->ep->gsi_evt_ring_hdl);
-                       if (res) {
-                               IPAERR("dealloc evt ring %lu failed, err %d\n"
-                                       , channel->ep->gsi_evt_ring_hdl, res);
-                               goto fail;
-                       }
+       ipa_ep_idx = ipa3_get_ep_mapping(client);
+       ep = &ipa3_ctx->ep[ipa_ep_idx];
+
+       if (brstmode_enabled && !LPTransitionRejected) {
+               /*
+                * set polling mode bit to DB mode before
+                * resuming the channel
+                */
+               res = gsi_write_channel_scratch(
+                       ep->gsi_chan_hdl, ch_scratch);
+               if (res) {
+                       IPA_MHI_ERR("write ch scratch fail %d\n"
+                               , res);
+                       return res;
                }
        }
+       if (res) {
+               IPA_MHI_ERR("failed to resume channel error %d\n",
+                       res);
+               return res;
+       }
+
+       res = gsi_start_channel(ep->gsi_chan_hdl);
+       if (res) {
+               IPA_MHI_ERR("failed to resume channel error %d\n", res);
+               return res;
+       }
 
+       IPA_MHI_FUNC_EXIT();
        return 0;
-fail:
-       return res;
 }
 
-/**
- * ipa3_mhi_destroy() - Destroy MHI IPA
- *
- * This function is called by MHI client driver on MHI reset to destroy all IPA
- * MHI resources.
- * When this function returns ipa_mhi can re-initialize.
- */
-void ipa3_mhi_destroy(void)
+int ipa3_mhi_query_ch_info(enum ipa_client_type client,
+               struct gsi_chan_info *ch_info)
 {
+       int ipa_ep_idx;
        int res;
+       struct ipa3_ep_context *ep;
 
        IPA_MHI_FUNC_ENTRY();
-       if (!ipa3_mhi_ctx) {
-               IPA_MHI_DBG("IPA MHI was not initialized, already destroyed\n");
-               return;
-       }
-       /* reset all UL and DL acc channels and its accociated event rings */
-       res = ipa3_mhi_destroy_channels(ipa3_mhi_ctx->ul_channels,
-               IPA_MHI_MAX_UL_CHANNELS);
-       if (res) {
-               IPAERR("ipa3_mhi_destroy_channels(ul_channels) failed %d\n",
-                       res);
-               goto fail;
-       }
-       IPA_MHI_DBG("All UL channels are disconnected\n");
 
-       res = ipa3_mhi_destroy_channels(ipa3_mhi_ctx->dl_channels,
-               IPA_MHI_MAX_DL_CHANNELS);
-       if (res) {
-               IPAERR("ipa3_mhi_destroy_channels(dl_channels) failed %d\n",
-                       res);
-               goto fail;
-       }
-       IPA_MHI_DBG("All DL channels are disconnected\n");
+       ipa_ep_idx = ipa3_get_ep_mapping(client);
 
-       if (ipa3_ctx->transport_prototype == IPA_TRANSPORT_TYPE_SPS) {
-               IPA_MHI_DBG("cleanup uC MHI\n");
-               ipa3_uc_mhi_cleanup();
+       ep = &ipa3_ctx->ep[ipa_ep_idx];
+       res = gsi_query_channel_info(ep->gsi_chan_hdl, ch_info);
+       if (res) {
+               IPAERR("gsi_query_channel_info failed\n");
+               return res;
        }
 
-       if (ipa3_mhi_ctx->state != IPA_MHI_STATE_INITIALIZED  &&
-           ipa3_mhi_ctx->state != IPA_MHI_STATE_READY) {
-               IPA_MHI_DBG("release prod\n");
-               res = ipa3_mhi_release_prod();
-               if (res) {
-                       IPA_MHI_ERR("ipa3_mhi_release_prod failed %d\n", res);
-                       goto fail;
-               }
-               IPA_MHI_DBG("wait for cons release\n");
-               res = ipa3_mhi_wait_for_cons_release();
-               if (res) {
-                       IPAERR("ipa3_mhi_wait_for_cons_release failed %d\n",
-                               res);
-                       goto fail;
-               }
-               usleep_range(IPA_MHI_SUSPEND_SLEEP_MIN,
-                               IPA_MHI_SUSPEND_SLEEP_MAX);
+       IPA_MHI_FUNC_EXIT();
+       return 0;
+}
 
-               IPA_MHI_DBG("deleate dependency Q6_PROD->MHI_CONS\n");
-               res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_Q6_PROD,
-                       IPA_RM_RESOURCE_MHI_CONS);
-               if (res) {
-                       IPAERR("Error deleting dependency %d->%d, res=%d\n",
-                       IPA_RM_RESOURCE_Q6_PROD, IPA_RM_RESOURCE_MHI_CONS, res);
-                       goto fail;
-               }
-               IPA_MHI_DBG("deleate dependency MHI_PROD->Q6_CONS\n");
-               res = ipa_rm_delete_dependency(IPA_RM_RESOURCE_MHI_PROD,
-                       IPA_RM_RESOURCE_Q6_CONS);
-               if (res) {
-                       IPAERR("Error deleting dependency %d->%d, res=%d\n",
-                       IPA_RM_RESOURCE_MHI_PROD, IPA_RM_RESOURCE_Q6_CONS, res);
-                       goto fail;
-               }
-       }
+bool ipa3_has_open_aggr_frame(enum ipa_client_type client)
+{
+       u32 aggr_state_active;
+       int ipa_ep_idx;
 
-       res = ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_PROD);
-       if (res) {
-               IPAERR("Error deleting resource %d, res=%d\n",
-                       IPA_RM_RESOURCE_MHI_PROD, res);
-               goto fail;
-       }
+       aggr_state_active = ipahal_read_reg(IPA_STATE_AGGR_ACTIVE);
+       IPA_MHI_DBG_LOW("IPA_STATE_AGGR_ACTIVE_OFST 0x%x\n", aggr_state_active);
 
-       res = ipa_rm_delete_resource(IPA_RM_RESOURCE_MHI_CONS);
-       if (res) {
-               IPAERR("Error deleting resource %d, res=%d\n",
-                       IPA_RM_RESOURCE_MHI_CONS, res);
-               goto fail;
+       ipa_ep_idx = ipa_get_ep_mapping(client);
+       if (ipa_ep_idx == -1) {
+               ipa_assert();
+               return false;
        }
 
-       ipa3_mhi_debugfs_destroy();
-       destroy_workqueue(ipa3_mhi_ctx->wq);
-       kfree(ipa3_mhi_ctx);
-       ipa3_mhi_ctx = NULL;
-       IPA_MHI_DBG("IPA MHI was reset, ready for re-init\n");
+       if ((1 << ipa_ep_idx) & aggr_state_active)
+               return true;
 
-       IPA_MHI_FUNC_EXIT();
-       return;
-fail:
-       BUG();
-       return;
+       return false;
 }
 
-/**
- * ipa3_mhi_handle_ipa_config_req() - hanle IPA CONFIG QMI message
- *
- * This function is called by by IPA QMI service to indicate that IPA CONFIG
- * message was sent from modem. IPA MHI will update this information to IPA uC
- * or will cache it until IPA MHI will be initialized.
- *
- * Return codes: 0       : success
- *              negative : error
- */
-int ipa3_mhi_handle_ipa_config_req(struct ipa_config_req_msg_v01 *config_req)
+int ipa3_mhi_destroy_channel(enum ipa_client_type client)
 {
-       IPA_MHI_FUNC_ENTRY();
+       int res;
+       int ipa_ep_idx;
+       struct ipa3_ep_context *ep;
+
+       ipa_ep_idx = ipa3_get_ep_mapping(client);
+
+       ep = &ipa3_ctx->ep[ipa_ep_idx];
+
+       IPA_MHI_DBG("reset event ring (hdl: %lu, ep: %d)\n",
+               ep->gsi_evt_ring_hdl, ipa_ep_idx);
+
+       res = gsi_reset_evt_ring(ep->gsi_evt_ring_hdl);
+       if (res) {
+               IPAERR(" failed to reset evt ring %lu, err %d\n"
+                       , ep->gsi_evt_ring_hdl, res);
+               goto fail;
+       }
 
-       if (ipa3_ctx->transport_prototype != IPA_TRANSPORT_TYPE_GSI) {
-               ipa3_mhi_cache_dl_ul_sync_info(config_req);
-               if (ipa3_mhi_ctx &&
-                   ipa3_mhi_ctx->state != IPA_MHI_STATE_INITIALIZED)
-                       ipa3_uc_mhi_send_dl_ul_sync_info(
-                               ipa3_cached_dl_ul_sync_info);
+       IPA_MHI_DBG("dealloc event ring (hdl: %lu, ep: %d)\n",
+               ep->gsi_evt_ring_hdl, ipa_ep_idx);
+
+       res = gsi_dealloc_evt_ring(
+               ep->gsi_evt_ring_hdl);
+       if (res) {
+               IPAERR("dealloc evt ring %lu failed, err %d\n"
+                       , ep->gsi_evt_ring_hdl, res);
+               goto fail;
        }
 
-       IPA_MHI_FUNC_EXIT();
        return 0;
+fail:
+       return res;
 }
 
 MODULE_LICENSE("GPL v2");
index 6444dcf..ce399c2 100644 (file)
@@ -219,7 +219,7 @@ static int handle_ipa_config_req(void *req_h, void *req)
        memset(&resp, 0, sizeof(struct ipa_config_resp_msg_v01));
        resp.resp.result = IPA_QMI_RESULT_SUCCESS_V01;
        IPAWANDBG("Received IPA CONFIG Request\n");
-       rc = ipa3_mhi_handle_ipa_config_req(
+       rc = ipa_mhi_handle_ipa_config_req(
                (struct ipa_config_req_msg_v01 *)req);
        if (rc) {
                IPAERR("ipa3_mhi_handle_ipa_config_req failed %d\n", rc);
index b70fd03..0e3cecb 100644 (file)
@@ -149,7 +149,7 @@ static int ipa_translate_rt_tbl_to_hw_fmt(enum ipa_ip_type ip,
 {
        struct ipa3_rt_tbl_set *set;
        struct ipa3_rt_tbl *tbl;
-       struct ipa3_mem_buffer tbl_mem;
+       struct ipa_mem_buffer tbl_mem;
        u8 *tbl_mem_buf;
        struct ipa3_rt_entry *entry;
        int res;
@@ -314,7 +314,7 @@ static void __ipa_reap_sys_rt_tbls(enum ipa_ip_type ip)
  * Return: 0 on success, negative on failure
  */
 static int ipa_alloc_init_rt_tbl_hdr(enum ipa_ip_type ip,
-       struct ipa3_mem_buffer *hash_hdr, struct ipa3_mem_buffer *nhash_hdr)
+       struct ipa_mem_buffer *hash_hdr, struct ipa_mem_buffer *nhash_hdr)
 {
        int num_index;
        u64 *hash_entr;
@@ -483,8 +483,8 @@ static void ipa_get_rt_tbl_lcl_bdy_size(enum ipa_ip_type ip,
  * Return: 0 on success, negative on failure
  */
 static int ipa_generate_rt_hw_tbl_img(enum ipa_ip_type ip,
-       struct ipa3_mem_buffer *hash_hdr, struct ipa3_mem_buffer *nhash_hdr,
-       struct ipa3_mem_buffer *hash_bdy, struct ipa3_mem_buffer *nhash_bdy)
+       struct ipa_mem_buffer *hash_hdr, struct ipa_mem_buffer *nhash_hdr,
+       struct ipa_mem_buffer *hash_bdy, struct ipa_mem_buffer *nhash_bdy)
 {
        u32 hash_bdy_start_ofst, nhash_bdy_start_ofst;
        u32 apps_start_idx;
@@ -604,7 +604,7 @@ no_rt_tbls:
  * Return: true if enough space available or false in other cases
  */
 static bool ipa_rt_valid_lcl_tbl_size(enum ipa_ip_type ipt,
-       enum ipa_rule_type rlt, struct ipa3_mem_buffer *bdy)
+       enum ipa_rule_type rlt, struct ipa_mem_buffer *bdy)
 {
        u16 avail;
 
@@ -639,8 +639,8 @@ int __ipa_commit_rt_v3(enum ipa_ip_type ip)
        struct ipahal_imm_cmd_dma_shared_mem  mem_cmd = {0};
        struct ipahal_imm_cmd_pyld *cmd_pyld[5];
        int num_cmd = 0;
-       struct ipa3_mem_buffer hash_bdy, nhash_bdy;
-       struct ipa3_mem_buffer hash_hdr, nhash_hdr;
+       struct ipa_mem_buffer hash_bdy, nhash_bdy;
+       struct ipa_mem_buffer hash_hdr, nhash_hdr;
        u32 num_modem_rt_index;
        int rc = 0;
        u32 lcl_hash_hdr, lcl_nhash_hdr;
index 7bc11a3..cb47773 100644 (file)
@@ -960,7 +960,7 @@ void ipa3_uc_rg10_write_reg(enum ipahal_reg_name reg, u32 n, u32 val)
 int ipa3_uc_memcpy(phys_addr_t dest, phys_addr_t src, int len)
 {
        int res;
-       struct ipa3_mem_buffer mem;
+       struct ipa_mem_buffer mem;
        struct IpaHwMemCopyData_t *cmd;
 
        IPADBG("dest 0x%pa src 0x%pa len %d\n", &dest, &src, len);
index ef88483..7949d91 100644 (file)
@@ -622,7 +622,7 @@ int ipa3_uc_mhi_init_engine(struct ipa_mhi_msi_info *msi, u32 mmio_addr,
        u32 first_evt_idx)
 {
        int res;
-       struct ipa3_mem_buffer mem;
+       struct ipa_mem_buffer mem;
        struct IpaHwMhiInitCmdData_t *init_cmd_data;
        struct IpaHwMhiMsiCmdData_t *msi_cmd;
 
@@ -887,7 +887,7 @@ disable_clks:
        return res;
 }
 
-int ipa3_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t cmd)
+int ipa3_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t *cmd)
 {
        int res;
 
@@ -897,13 +897,14 @@ int ipa3_uc_mhi_send_dl_ul_sync_info(union IpaHwMhiDlUlSyncCmdData_t cmd)
        }
 
        IPADBG("isDlUlSyncEnabled=0x%x UlAccmVal=0x%x\n",
-               cmd.params.isDlUlSyncEnabled, cmd.params.UlAccmVal);
+               cmd->params.isDlUlSyncEnabled, cmd->params.UlAccmVal);
        IPADBG("ulMsiEventThreshold=0x%x dlMsiEventThreshold=0x%x\n",
-               cmd.params.ulMsiEventThreshold, cmd.params.dlMsiEventThreshold);
+               cmd->params.ulMsiEventThreshold,
+               cmd->params.dlMsiEventThreshold);
 
        IPA_ACTIVE_CLIENTS_INC_SIMPLE();
 
-       res = ipa3_uc_send_cmd(cmd.raw32b,
+       res = ipa3_uc_send_cmd(cmd->raw32b,
                IPA_CPU_2_HW_CMD_MHI_DL_UL_SYNC_INFO, 0, false, HZ);
        if (res) {
                IPAERR("ipa3_uc_send_cmd failed %d\n", res);
index 9f4f3a6..393ae2a 100644 (file)
@@ -735,7 +735,7 @@ int ipa3_connect_wdi_pipe(struct ipa_wdi_in_params *in,
        int ipa_ep_idx;
        int result = -EFAULT;
        struct ipa3_ep_context *ep;
-       struct ipa3_mem_buffer cmd;
+       struct ipa_mem_buffer cmd;
        struct IpaHwWdiTxSetUpCmdData_t *tx;
        struct IpaHwWdiRxSetUpCmdData_t *rx;
        struct IpaHwWdi2TxSetUpCmdData_t *tx_2;
index 5574ef8..34d0ad5 100644 (file)
@@ -4455,6 +4455,16 @@ static void *ipa3_get_ipc_logbuf_low(void)
        return NULL;
 }
 
+static void ipa3_get_holb(int ep_idx, struct ipa_ep_cfg_holb *holb)
+{
+       *holb = ipa3_ctx->ep[ep_idx].holb;
+}
+
+static void ipa3_set_tag_process_before_gating(bool val)
+{
+       ipa3_ctx->tag_process_before_gating = val;
+}
+
 int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
        struct ipa_api_controller *api_ctrl)
 {
@@ -4477,6 +4487,9 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
        api_ctrl->ipa_cfg_ep_deaggr = ipa3_cfg_ep_deaggr;
        api_ctrl->ipa_cfg_ep_route = ipa3_cfg_ep_route;
        api_ctrl->ipa_cfg_ep_holb = ipa3_cfg_ep_holb;
+       api_ctrl->ipa_get_holb = ipa3_get_holb;
+       api_ctrl->ipa_set_tag_process_before_gating =
+                       ipa3_set_tag_process_before_gating;
        api_ctrl->ipa_cfg_ep_cfg = ipa3_cfg_ep_cfg;
        api_ctrl->ipa_cfg_ep_metadata_mask = ipa3_cfg_ep_metadata_mask;
        api_ctrl->ipa_cfg_ep_holb_by_client = ipa3_cfg_ep_holb_by_client;
@@ -4548,13 +4561,32 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type,
        api_ctrl->ipa_dma_async_memcpy = ipa3_dma_async_memcpy;
        api_ctrl->ipa_dma_uc_memcpy = ipa3_dma_uc_memcpy;
        api_ctrl->ipa_dma_destroy = ipa3_dma_destroy;
-       api_ctrl->ipa_mhi_init = ipa3_mhi_init;
-       api_ctrl->ipa_mhi_start = ipa3_mhi_start;
-       api_ctrl->ipa_mhi_connect_pipe = ipa3_mhi_connect_pipe;
-       api_ctrl->ipa_mhi_disconnect_pipe = ipa3_mhi_disconnect_pipe;
-       api_ctrl->ipa_mhi_suspend = ipa3_mhi_suspend;
-       api_ctrl->ipa_mhi_resume = ipa3_mhi_resume;
-       api_ctrl->ipa_mhi_destroy = ipa3_mhi_destroy;
+       api_ctrl->ipa_mhi_init_engine = ipa3_mhi_init_engine;
+       api_ctrl->ipa_connect_mhi_pipe = ipa3_connect_mhi_pipe;
+       api_ctrl->ipa_disconnect_mhi_pipe = ipa3_disconnect_mhi_pipe;
+       api_ctrl->ipa_mhi_stop_gsi_channel = ipa3_mhi_stop_gsi_channel;
+       api_ctrl->ipa_uc_mhi_reset_channel = ipa3_uc_mhi_reset_channel;
+       api_ctrl->ipa_qmi_enable_force_clear_datapath_send =
+                       ipa3_qmi_enable_force_clear_datapath_send;
+       api_ctrl->ipa_qmi_disable_force_clear_datapath_send =
+                       ipa3_qmi_disable_force_clear_datapath_send;
+       api_ctrl->ipa_mhi_reset_channel_internal =
+                       ipa3_mhi_reset_channel_internal;
+       api_ctrl->ipa_mhi_start_channel_internal =
+                       ipa3_mhi_start_channel_internal;
+       api_ctrl->ipa_mhi_query_ch_info = ipa3_mhi_query_ch_info;
+       api_ctrl->ipa_mhi_resume_channels_internal =
+                       ipa3_mhi_resume_channels_internal;
+       api_ctrl->ipa_has_open_aggr_frame = ipa3_has_open_aggr_frame;
+       api_ctrl->ipa_mhi_destroy_channel = ipa3_mhi_destroy_channel;
+       api_ctrl->ipa_uc_mhi_send_dl_ul_sync_info =
+                       ipa3_uc_mhi_send_dl_ul_sync_info;
+       api_ctrl->ipa_uc_mhi_init = ipa3_uc_mhi_init;
+       api_ctrl->ipa_uc_mhi_suspend_channel = ipa3_uc_mhi_suspend_channel;
+       api_ctrl->ipa_uc_mhi_stop_event_update_channel =
+                       ipa3_uc_mhi_stop_event_update_channel;
+       api_ctrl->ipa_uc_mhi_cleanup = ipa3_uc_mhi_cleanup;
+       api_ctrl->ipa_uc_state_check = ipa3_uc_state_check;
        api_ctrl->ipa_write_qmap_id = ipa3_write_qmap_id;
        api_ctrl->ipa_add_interrupt_handler = ipa3_add_interrupt_handler;
        api_ctrl->ipa_remove_interrupt_handler = ipa3_remove_interrupt_handler;
@@ -4822,7 +4854,7 @@ void ipa3_suspend_apps_pipes(bool suspend)
  */
 int ipa3_inject_dma_task_for_gsi(void)
 {
-       static struct ipa3_mem_buffer mem = {0};
+       static struct ipa_mem_buffer mem = {0};
        struct ipahal_imm_cmd_dma_task_32b_addr cmd = {0};
        static struct ipahal_imm_cmd_pyld *cmd_pyld;
        struct ipa3_desc desc = {0};
@@ -4879,7 +4911,7 @@ int ipa3_inject_dma_task_for_gsi(void)
  */
 int ipa3_stop_gsi_channel(u32 clnt_hdl)
 {
-       struct ipa3_mem_buffer mem;
+       struct ipa_mem_buffer mem;
        int res = 0;
        int i;
        struct ipa3_ep_context *ep;
index 142263b..d131fdc 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/completion.h>
 #include <linux/platform_device.h>
 #include <linux/msm_ep_pcie.h>
-#include <linux/ipa.h>
+#include <linux/ipa_mhi.h>
 #include <linux/vmalloc.h>
 
 #include "mhi.h"
index 12a4fb2..4456f9b 100644 (file)
@@ -16,7 +16,7 @@
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/debugfs.h>
-#include <linux/ipa.h>
+#include <linux/ipa_mhi.h>
 #include "mhi_hwio.h"
 #include "mhi_sm.h"
 
index 0dd2f0b..a0dd21d 100644 (file)
@@ -1056,92 +1056,6 @@ struct ipa_wdi_buffer_info {
 };
 
 /**
- * enum ipa_mhi_event_type - event type for mhi callback
- *
- * @IPA_MHI_EVENT_READY: IPA MHI is ready and IPA uC is loaded. After getting
- *     this event MHI client is expected to call to ipa_mhi_start() API
- * @IPA_MHI_EVENT_DATA_AVAILABLE: downlink data available on MHI channel
- */
-enum ipa_mhi_event_type {
-       IPA_MHI_EVENT_READY,
-       IPA_MHI_EVENT_DATA_AVAILABLE,
-       IPA_MHI_EVENT_MAX,
-};
-
-typedef void (*mhi_client_cb)(void *priv, enum ipa_mhi_event_type event,
-       unsigned long data);
-
-/**
- * struct ipa_mhi_msi_info - parameters for MSI (Message Signaled Interrupts)
- * @addr_low: MSI lower base physical address
- * @addr_hi: MSI higher base physical address
- * @data: Data Pattern to use when generating the MSI
- * @mask: Mask indicating number of messages assigned by the host to device
- *
- * msi value is written according to this formula:
- *     ((data & ~mask) | (mmio.msiVec & mask))
- */
-struct ipa_mhi_msi_info {
-       u32 addr_low;
-       u32 addr_hi;
-       u32 data;
-       u32 mask;
-};
-
-/**
- * struct ipa_mhi_init_params - parameters for IPA MHI initialization API
- *
- * @msi: MSI (Message Signaled Interrupts) parameters
- * @mmio_addr: MHI MMIO physical address
- * @first_ch_idx: First channel ID for hardware accelerated channels.
- * @first_er_idx: First event ring ID for hardware accelerated channels.
- * @assert_bit40: should assert bit 40 in order to access hots space.
- *     if PCIe iATU is configured then not need to assert bit40
- * @notify: client callback
- * @priv: client private data to be provided in client callback
- * @test_mode: flag to indicate if IPA MHI is in unit test mode
- */
-struct ipa_mhi_init_params {
-       struct ipa_mhi_msi_info msi;
-       u32 mmio_addr;
-       u32 first_ch_idx;
-       u32 first_er_idx;
-       bool assert_bit40;
-       mhi_client_cb notify;
-       void *priv;
-       bool test_mode;
-};
-
-/**
- * struct ipa_mhi_start_params - parameters for IPA MHI start API
- *
- * @host_ctrl_addr: Base address of MHI control data structures
- * @host_data_addr: Base address of MHI data buffers
- * @channel_context_addr: channel context array address in host address space
- * @event_context_addr: event context array address in host address space
- */
-struct ipa_mhi_start_params {
-       u32 host_ctrl_addr;
-       u32 host_data_addr;
-       u64 channel_context_array_addr;
-       u64 event_context_array_addr;
-};
-
-/**
- * struct ipa_mhi_connect_params - parameters for IPA MHI channel connect API
- *
- * @sys: IPA EP configuration info
- * @channel_id: MHI channel id
- */
-struct ipa_mhi_connect_params {
-       struct ipa_sys_connect_params sys;
-       u8 channel_id;
-};
-
-/* bit #40 in address should be asserted for MHI transfers over pcie */
-#define IPA_MHI_HOST_ADDR(addr) ((addr) | BIT_ULL(40))
-
-/**
  * struct ipa_gsi_ep_config - IPA GSI endpoint configurations
  *
  * @ipa_ep_num: IPA EP pipe number
@@ -1436,23 +1350,6 @@ int ipa_dma_uc_memcpy(phys_addr_t dest, phys_addr_t src, int len);
 void ipa_dma_destroy(void);
 
 /*
- * MHI
- */
-int ipa_mhi_init(struct ipa_mhi_init_params *params);
-
-int ipa_mhi_start(struct ipa_mhi_start_params *params);
-
-int ipa_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl);
-
-int ipa_mhi_disconnect_pipe(u32 clnt_hdl);
-
-int ipa_mhi_suspend(bool force);
-
-int ipa_mhi_resume(void);
-
-void ipa_mhi_destroy(void);
-
-/*
  * mux id
  */
 int ipa_write_qmap_id(struct ipa_ioc_write_qmapid *param_in);
@@ -2112,45 +2009,6 @@ static inline void ipa_dma_destroy(void)
 }
 
 /*
- * MHI
- */
-static inline int ipa_mhi_init(struct ipa_mhi_init_params *params)
-{
-       return -EPERM;
-}
-
-static inline int ipa_mhi_start(struct ipa_mhi_start_params *params)
-{
-       return -EPERM;
-}
-
-static inline int ipa_mhi_connect_pipe(struct ipa_mhi_connect_params *in,
-       u32 *clnt_hdl)
-{
-       return -EPERM;
-}
-
-static inline int ipa_mhi_disconnect_pipe(u32 clnt_hdl)
-{
-       return -EPERM;
-}
-
-static inline int ipa_mhi_suspend(bool force)
-{
-       return -EPERM;
-}
-
-static inline int ipa_mhi_resume(void)
-{
-       return -EPERM;
-}
-
-static inline void ipa_mhi_destroy(void)
-{
-       return;
-}
-
-/*
  * mux id
  */
 static inline int ipa_write_qmap_id(struct ipa_ioc_write_qmapid *param_in)
diff --git a/include/linux/ipa_mhi.h b/include/linux/ipa_mhi.h
new file mode 100644 (file)
index 0000000..4d3b974
--- /dev/null
@@ -0,0 +1,161 @@
+/* Copyright (c) 2016, 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 IPA_MHI_H_
+#define IPA_MHI_H_
+
+#include <linux/ipa.h>
+#include <linux/types.h>
+
+/**
+ * enum ipa_mhi_event_type - event type for mhi callback
+ *
+ * @IPA_MHI_EVENT_READY: IPA MHI is ready and IPA uC is loaded. After getting
+ *     this event MHI client is expected to call to ipa_mhi_start() API
+ * @IPA_MHI_EVENT_DATA_AVAILABLE: downlink data available on MHI channel
+ */
+enum ipa_mhi_event_type {
+       IPA_MHI_EVENT_READY,
+       IPA_MHI_EVENT_DATA_AVAILABLE,
+       IPA_MHI_EVENT_MAX,
+};
+
+typedef void (*mhi_client_cb)(void *priv, enum ipa_mhi_event_type event,
+       unsigned long data);
+
+/**
+ * struct ipa_mhi_msi_info - parameters for MSI (Message Signaled Interrupts)
+ * @addr_low: MSI lower base physical address
+ * @addr_hi: MSI higher base physical address
+ * @data: Data Pattern to use when generating the MSI
+ * @mask: Mask indicating number of messages assigned by the host to device
+ *
+ * msi value is written according to this formula:
+ *     ((data & ~mask) | (mmio.msiVec & mask))
+ */
+struct ipa_mhi_msi_info {
+       u32 addr_low;
+       u32 addr_hi;
+       u32 data;
+       u32 mask;
+};
+
+/**
+ * struct ipa_mhi_init_params - parameters for IPA MHI initialization API
+ *
+ * @msi: MSI (Message Signaled Interrupts) parameters
+ * @mmio_addr: MHI MMIO physical address
+ * @first_ch_idx: First channel ID for hardware accelerated channels.
+ * @first_er_idx: First event ring ID for hardware accelerated channels.
+ * @assert_bit40: should assert bit 40 in order to access host space.
+ *     if PCIe iATU is configured then not need to assert bit40
+ * @notify: client callback
+ * @priv: client private data to be provided in client callback
+ * @test_mode: flag to indicate if IPA MHI is in unit test mode
+ */
+struct ipa_mhi_init_params {
+       struct ipa_mhi_msi_info msi;
+       u32 mmio_addr;
+       u32 first_ch_idx;
+       u32 first_er_idx;
+       bool assert_bit40;
+       mhi_client_cb notify;
+       void *priv;
+       bool test_mode;
+};
+
+/**
+ * struct ipa_mhi_start_params - parameters for IPA MHI start API
+ *
+ * @host_ctrl_addr: Base address of MHI control data structures
+ * @host_data_addr: Base address of MHI data buffers
+ * @channel_context_addr: channel context array address in host address space
+ * @event_context_addr: event context array address in host address space
+ */
+struct ipa_mhi_start_params {
+       u32 host_ctrl_addr;
+       u32 host_data_addr;
+       u64 channel_context_array_addr;
+       u64 event_context_array_addr;
+};
+
+/**
+ * struct ipa_mhi_connect_params - parameters for IPA MHI channel connect API
+ *
+ * @sys: IPA EP configuration info
+ * @channel_id: MHI channel id
+ */
+struct ipa_mhi_connect_params {
+       struct ipa_sys_connect_params sys;
+       u8 channel_id;
+};
+
+/* bit #40 in address should be asserted for MHI transfers over pcie */
+#define IPA_MHI_HOST_ADDR(addr) ((addr) | BIT_ULL(40))
+
+#if defined CONFIG_IPA || defined CONFIG_IPA3
+
+int ipa_mhi_init(struct ipa_mhi_init_params *params);
+
+int ipa_mhi_start(struct ipa_mhi_start_params *params);
+
+int ipa_mhi_connect_pipe(struct ipa_mhi_connect_params *in, u32 *clnt_hdl);
+
+int ipa_mhi_disconnect_pipe(u32 clnt_hdl);
+
+int ipa_mhi_suspend(bool force);
+
+int ipa_mhi_resume(void);
+
+void ipa_mhi_destroy(void);
+
+#else /* (CONFIG_IPA || CONFIG_IPA3) */
+
+static inline int ipa_mhi_init(struct ipa_mhi_init_params *params)
+{
+       return -EPERM;
+}
+
+static inline int ipa_mhi_start(struct ipa_mhi_start_params *params)
+{
+       return -EPERM;
+}
+
+static inline int ipa_mhi_connect_pipe(struct ipa_mhi_connect_params *in,
+       u32 *clnt_hdl)
+{
+       return -EPERM;
+}
+
+static inline int ipa_mhi_disconnect_pipe(u32 clnt_hdl)
+{
+       return -EPERM;
+}
+
+static inline int ipa_mhi_suspend(bool force)
+{
+       return -EPERM;
+}
+
+static inline int ipa_mhi_resume(void)
+{
+       return -EPERM;
+}
+
+static inline void ipa_mhi_destroy(void)
+{
+
+}
+
+#endif /* (CONFIG_IPA || CONFIG_IPA3) */
+
+#endif /* IPA_MHI_H_ */