summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2018-10-23 06:53:29 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2018-10-23 06:53:28 -0700
commitd8bc349f5414150a5d59ea73b2d0a2b1fa270043 (patch)
treef0dba248b871492887caa1ead5200f2939d73a10
parent869b2c41ea91b68f0e8af0d1cb7c004f390dd622 (diff)
parentdd24e947d5dafbe7759d862d44a53954ab3c4719 (diff)
Merge "msm: ipa: Check ep empty before reset"
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa.c232
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_i.h5
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_reg.h5
-rw-r--r--include/linux/ipa.h22
4 files changed, 262 insertions, 2 deletions
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c
index d9f8912c0514..f1e27fd3d011 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c
@@ -74,6 +74,11 @@
#define IPA_SPS_PROD_TIMEOUT_MSEC 100
+#define EP_EMPTY_MAX_RETRY 5
+#define IPA_BAM_REG_MAP_SIZE 4
+#define IPA_BAM_REG_N_OFST 0x1000
+
+
#ifdef CONFIG_COMPAT
#define IPA_IOC_ADD_HDR32 _IOWR(IPA_IOC_MAGIC, \
IPA_IOCTL_ADD_HDR, \
@@ -2238,6 +2243,8 @@ int ipa_apps_shutdown_cleanup(void)
ipa2_apps_shutdown_apps_ep_reset();
+ iounmap_non_ap_bam_regs();
+
IPA_ACTIVE_CLIENTS_DEC_SPECIAL("APPS_SHUTDOWN");
return 0;
@@ -2293,6 +2300,205 @@ int ipa_q6_pre_shutdown_cleanup(void)
return 0;
}
+static void __iomem *ioremap_sw_desc_ofst_bam_register(int ep_idx)
+{
+ int ep_ofst = IPA_BAM_REG_N_OFST * ep_idx;
+
+ return ioremap(ipa_ctx->ipa_wrapper_base
+ + IPA_BAM_REG_BASE_OFST
+ + IPA_BAM_SW_DESC_OFST
+ + ep_ofst,
+ IPA_BAM_REG_MAP_SIZE);
+}
+
+static void __iomem *ioremap_peer_desc_ofst_bam_register(int ep_idx)
+{
+ int ep_ofst = IPA_BAM_REG_N_OFST * ep_idx;
+
+ return ioremap(ipa_ctx->ipa_wrapper_base
+ + IPA_BAM_REG_BASE_OFST
+ + IPA_BAM_PEER_DESC_OFST
+ + ep_ofst,
+ IPA_BAM_REG_MAP_SIZE);
+}
+
+/**
+* ioremap_non_ap_bam_regs() -
+ perform ioremap of non-apps eps
+ bam sw_ofsts and evnt_ring
+ register.
+ Present only Q6 ep's are done.
+*
+* Return codes:
+* 0: success
+* non-Zero: In case of memory failure
+*/
+int ioremap_non_ap_bam_regs(void)
+{
+ int client_idx;
+ int ep_idx;
+
+ if (!ipa_ctx) {
+ IPAERR("IPA driver init not done\n");
+ return -ENODEV;
+ }
+
+ for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++)
+ if (IPA_CLIENT_IS_Q6_NON_ZIP_CONS(client_idx) ||
+ IPA_CLIENT_IS_Q6_ZIP_CONS(client_idx) ||
+ IPA_CLIENT_IS_Q6_NON_ZIP_PROD(client_idx) ||
+ IPA_CLIENT_IS_Q6_ZIP_PROD(client_idx)) {
+
+ ep_idx = ipa2_get_ep_mapping(client_idx);
+
+ if (ep_idx == -1)
+ continue;
+
+ ipa_ctx->ipa_non_ap_bam_s_desc_iova[ep_idx] =
+ ioremap_sw_desc_ofst_bam_register(ep_idx);
+ ipa_ctx->ipa_non_ap_bam_p_desc_iova[ep_idx] =
+ ioremap_peer_desc_ofst_bam_register(ep_idx);
+
+ if (!ipa_ctx->ipa_non_ap_bam_s_desc_iova[ep_idx] ||
+ !ipa_ctx->ipa_non_ap_bam_p_desc_iova[ep_idx]) {
+ IPAERR("IOREMA Failure @ ep %d\n", ep_idx);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+/**
+* iounmap_non_ap_bam_regs() -
+ unmap the ioremapped addr of
+ non-apps ep bam sw_ofsts and
+ evnt_ring register.
+*/
+void iounmap_non_ap_bam_regs(void)
+{
+ int client_idx;
+ int ep_idx;
+
+ if (!ipa_ctx) {
+ IPAERR("IPA driver init not done\n");
+ return;
+ }
+
+ for (client_idx = 0; client_idx < IPA_CLIENT_MAX; client_idx++)
+ if (IPA_CLIENT_IS_Q6_NON_ZIP_CONS(client_idx) ||
+ IPA_CLIENT_IS_Q6_ZIP_CONS(client_idx) ||
+ IPA_CLIENT_IS_Q6_NON_ZIP_PROD(client_idx) ||
+ IPA_CLIENT_IS_Q6_ZIP_PROD(client_idx)) {
+
+ ep_idx = ipa2_get_ep_mapping(client_idx);
+
+ if (ep_idx == -1)
+ continue;
+
+ if (ipa_ctx->ipa_non_ap_bam_s_desc_iova[ep_idx])
+ iounmap
+ (ipa_ctx->ipa_non_ap_bam_s_desc_iova[ep_idx]);
+ if (ipa_ctx->ipa_non_ap_bam_p_desc_iova[ep_idx])
+ iounmap
+ (ipa_ctx->ipa_non_ap_bam_p_desc_iova[ep_idx]);
+ }
+}
+
+/**
+* wait_for_ep_empty() - Wait for sps bam empty
+*
+* @client: ipa client to check for empty
+*
+* Return codes:
+* 0: success upon ep empty
+* non-Zero: Failure if ep non-empty
+*/
+
+int wait_for_ep_empty(enum ipa_client_type client)
+{
+ struct ipa_ep_context *ep = NULL;
+ u32 is_ep_empty = 0;
+ int ret = 0;
+ union ipa_bam_sw_peer_desc read_sw_desc;
+ union ipa_bam_sw_peer_desc read_peer_desc;
+ u32 retry = EP_EMPTY_MAX_RETRY;
+ int ep_idx = ipa2_get_ep_mapping(client);
+
+ if (ep_idx == -1)
+ return -ENODEV;
+
+ ep = &ipa_ctx->ep[ep_idx];
+
+check_ap_ep_empty:
+ if (ep->valid) {
+ ret = sps_is_pipe_empty(ep->ep_hdl, &is_ep_empty);
+ if (ret && retry--) {
+ usleep_range(IPA_UC_WAIT_MIN_SLEEP,
+ IPA_UC_WAII_MAX_SLEEP);
+ goto check_ap_ep_empty;
+ } else {
+ IPAERR("Ep %d is non-empty even after retries\n",
+ ep_idx);
+ ret = -1;
+ }
+ } else {
+ /* Might be Q6 ep, which is non-AP ep */
+
+check_non_ap_ep_empty:
+ IPADBG("request is for non-Apps ep %d\n", ep_idx);
+
+ if (IPA_CLIENT_IS_CONS(client)) {
+ /*
+ * Do not wait for empty in client CONS ep's
+ * It is software responsibility
+ * to set sus/holb on client cons ep
+ * and ipa would be empty due to that.
+ */
+ ret = 0;
+ goto success;
+ }
+
+ if (ipa_ctx->ipa_non_ap_bam_s_desc_iova[ep_idx] &&
+ ipa_ctx->ipa_non_ap_bam_p_desc_iova[ep_idx]) {
+
+ read_sw_desc.read_reg =
+ ioread32
+ (ipa_ctx->ipa_non_ap_bam_s_desc_iova[ep_idx]);
+ read_peer_desc.read_reg =
+ ioread32
+ (ipa_ctx->ipa_non_ap_bam_p_desc_iova[ep_idx]);
+
+ IPADBG("sw_desc reg 0x%x\n",
+ read_sw_desc.read_reg);
+ IPADBG("sw_dsc_ofst = 0x%x\n",
+ read_sw_desc.sw_desc.sw_dsc_ofst);
+ IPADBG("sw_desc reg 0x%x\n",
+ read_peer_desc.read_reg);
+ IPADBG("p_dsc_fifo_peer_ofst = 0x%x\n",
+ read_peer_desc.peer_desc.p_dsc_fifo_peer_ofst);
+
+ if (read_sw_desc.sw_desc.sw_dsc_ofst ==
+ read_peer_desc.peer_desc.p_dsc_fifo_peer_ofst) {
+ IPADBG("EP %d is empty\n", ep_idx);
+ ret = 0;
+ } else if (retry) {
+ retry--;
+ usleep_range(IPA_UC_WAIT_MIN_SLEEP,
+ IPA_UC_WAII_MAX_SLEEP);
+ goto check_non_ap_ep_empty;
+ } else {
+ IPAERR
+ ("Ep %d is non-empty even after retries\n",
+ ep_idx);
+ ret = -1;
+ }
+ }
+ }
+
+success:
+ return ret;
+}
+
/**
* ipa_q6_post_shutdown_cleanup() - A cleanup for the Q6 pipes
* in IPA HW after modem shutdown. This is performed
@@ -2331,7 +2537,22 @@ int ipa_q6_post_shutdown_cleanup(void)
IPA_CLIENT_IS_Q6_ZIP_CONS(client_idx) ||
IPA_CLIENT_IS_Q6_NON_ZIP_PROD(client_idx) ||
IPA_CLIENT_IS_Q6_ZIP_PROD(client_idx)) {
- res = ipa_uc_reset_pipe(client_idx);
+
+ if (ipa_ctx->is_apps_shutdown_support &&
+ (ipa2_get_ep_mapping(client_idx) != -1)) {
+ /*
+ * Check for Q6 ep empty
+ * before issue a reset
+ */
+ res = wait_for_ep_empty(client_idx);
+ if (res)
+ IPAERR("ep %d not empty\n",
+ ipa2_get_ep_mapping(client_idx));
+ else
+ res = ipa_uc_reset_pipe(client_idx);
+ } else {
+ res = ipa_uc_reset_pipe(client_idx);
+ }
if (res)
BUG();
}
@@ -4514,6 +4735,15 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p,
ipa_register_panic_hdlr();
+ if (ipa_ctx->is_apps_shutdown_support) {
+ result = ioremap_non_ap_bam_regs();
+ if (result) {
+ IPAERR(":IOREMAP Failed (%d)\n", result);
+ goto fail_add_interrupt_handler;
+ } else {
+ IPAERR(":IOREMAP success (%d)\n", result);
+ }
+ }
pr_info("IPA driver initialization was successful.\n");
return 0;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index 1d34564664bc..1c9eeb50d1cd 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -1105,6 +1105,8 @@ struct ipa_context {
struct cdev cdev;
unsigned long bam_handle;
struct ipa_ep_context ep[IPA_MAX_NUM_PIPES];
+ void __iomem *ipa_non_ap_bam_s_desc_iova[IPA_MAX_NUM_PIPES];
+ void __iomem *ipa_non_ap_bam_p_desc_iova[IPA_MAX_NUM_PIPES];
bool skip_ep_cfg_shadow[IPA_MAX_NUM_PIPES];
bool resume_on_connect[IPA_CLIENT_MAX];
struct ipa_flt_tbl flt_tbl[IPA_MAX_NUM_PIPES][IPA_IP_MAX];
@@ -1900,6 +1902,9 @@ int ipa_q6_pre_shutdown_cleanup(void);
int ipa_apps_shutdown_cleanup(void);
int register_ipa_platform_cb(int (*cb)(void));
int ipa_q6_post_shutdown_cleanup(void);
+int wait_for_ep_empty(enum ipa_client_type client);
+int ioremap_non_ap_bam_regs(void);
+void iounmap_non_ap_bam_regs(void);
int ipa_init_q6_smem(void);
int ipa_q6_monitor_holb_mitigation(bool enable);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_reg.h b/drivers/platform/msm/ipa/ipa_v2/ipa_reg.h
index 33e42ae7bb71..19aa1d114b07 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_reg.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2016,2018 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
@@ -93,6 +93,9 @@
*/
#define IPA_ENABLED_PIPES_OFST 0x000005DC
#define IPA_YELLOW_MARKER_SYS_CFG_OFST 0x00000728
+#define IPA_BAM_SW_DESC_OFST 0x00013800
+#define IPA_BAM_PEER_DESC_OFST 0x00013818
+
/*
* End of IPA 2.6/2.6L Registers
*/
diff --git a/include/linux/ipa.h b/include/linux/ipa.h
index 623d0f08cdf9..2586395886a3 100644
--- a/include/linux/ipa.h
+++ b/include/linux/ipa.h
@@ -1164,6 +1164,28 @@ struct ipa_gsi_ep_config {
int ee;
};
+/**
+ * union ipa_bam_sw_peer_desc - IPA sps sw peer desc
+ *
+ * @sw_dsc_ofst: software desc offset
+ * @sw_ofst_in_desc: offset in desc
+ * @p_dsc_fifo_peer_ofst: peer desc offset
+ * @p_bytes_consumed: bytes consumed
+ */
+union ipa_bam_sw_peer_desc {
+ struct sw_ofsts_reg {
+ u32 sw_dsc_ofst:16;
+ u32 sw_ofst_in_desc:15;
+ } sw_desc;
+
+ struct evnt_reg {
+ u32 p_dsc_fifo_peer_ofst:16;
+ u32 p_bytes_consumed:15;
+ } peer_desc;
+
+ u32 read_reg;
+};
+
#if defined CONFIG_IPA || defined CONFIG_IPA3
/*