From: Roja Rani Yarubandi <rojay@codeaurora.org>
To: wsa@kernel.org
Cc: swboyd@chromium.org, dianders@chromium.org,
saiprakash.ranjan@codeaurora.org, gregkh@linuxfoundation.org,
mka@chromium.org, akashast@codeaurora.org,
msavaliy@qti.qualcomm.com, skakit@codeaurora.org,
vkaur@codeaurora.org, pyarlaga@codeaurora.org,
rnayak@codeaurora.org, agross@kernel.org,
bjorn.andersson@linaro.org, linux-arm-msm@vger.kernel.org,
linux-i2c@vger.kernel.org, linux-kernel@vger.kernel.org,
sumit.semwal@linaro.org, linux-media@vger.kernel.org,
Roja Rani Yarubandi <rojay@codeaurora.org>
Subject: [PATCH V4] i2c: i2c-qcom-geni: Add shutdown callback for i2c
Date: Thu, 17 Sep 2020 17:55:58 +0530 [thread overview]
Message-ID: <20200917122558.23110-1-rojay@codeaurora.org> (raw)
If the hardware is still accessing memory after SMMU translation
is disabled (as part of smmu shutdown callback), then the
IOVAs (I/O virtual address) which it was using will go on the bus
as the physical addresses which will result in unknown crashes
like NoC/interconnect errors.
So, implement shutdown callback to i2c driver to stop on-going transfer
and unmap DMA mappings during system "reboot" or "shutdown".
Store DMA mapping data in geni_i2c_dev struct to enhance DMA mapping
data scope. For example during shutdown callback to unmap DMA mapping,
this stored DMA mapping data can be used to call geni_se_tx_dma_unprep,
geni_se_rx_dma_unprep and i2c_put_dma_safe_msg_buf functions.
Add two helper functions geni_i2c_rx_msg_cleanup and
geni_i2c_tx_msg_cleanup to unwrap the things after rx/tx FIFO/DMA
transfers, so that the same can be used in geni_i2c_stop_xfer()
function during shutdown callback.
Remove "iova" check from geni_se_tx_dma_unprep and geni_se_rx_dma_unprep
fucntions as invalidating with dma_mapping_error() is enough.
Fixes: 37692de5d523 ("i2c: i2c-qcom-geni: Add bus driver for the Qualcomm GENI I2C controller")
Signed-off-by: Roja Rani Yarubandi <rojay@codeaurora.org>
---
Changes in V2:
- As per Stephen's comments added seperate function for stop transfer,
fixed minor nitpicks.
- As per Stephen's comments, changed commit text.
Changes in V3:
- As per Stephen's comments, squashed patch 1 into patch 2, added Fixes tag.
- As per Akash's comments, included FIFO case in stop_xfer, fixed minor nitpicks.
Changes in V4:
- As per Stephen's comments cleaned up geni_i2c_stop_xfer function,
added dma_buf in geni_i2c_dev struct to call i2c_put_dma_safe_msg_buf()
from other functions, removed "iova" check in geni_se_rx_dma_unprep()
and geni_se_tx_dma_unprep() functions.
- Added two helper functions geni_i2c_rx_msg_cleanup() and
geni_i2c_tx_msg_cleanup() to unwrap the things after rx/tx FIFO/DMA
transfers, so that the same can be used in geni_i2c_stop_xfer() function
during shutdown callback. Updated commit text accordingly.
- In stop_xfer check whether it is tx/rx transfer using I2C_M_RD which is valid
for both FIFO and DMA cases, so dropped DMA_RX_ACTIVE and DMA_TX_ACTIVE bit
check of SE_DMA_DEBUG_REG0 register.
drivers/i2c/busses/i2c-qcom-geni.c | 93 ++++++++++++++++++++++++------
drivers/soc/qcom/qcom-geni-se.c | 4 +-
2 files changed, 78 insertions(+), 19 deletions(-)
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index dead5db3315a..b0d8043c8cb2 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -86,6 +86,10 @@ struct geni_i2c_dev {
u32 clk_freq_out;
const struct geni_i2c_clk_fld *clk_fld;
int suspended;
+ void *dma_buf;
+ size_t xfer_len;
+ dma_addr_t tx_dma;
+ dma_addr_t rx_dma;
};
struct geni_i2c_err_log {
@@ -307,7 +311,6 @@ static void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c)
spin_lock_irqsave(&gi2c->lock, flags);
geni_i2c_err(gi2c, GENI_TIMEOUT);
- gi2c->cur = NULL;
geni_se_abort_m_cmd(&gi2c->se);
spin_unlock_irqrestore(&gi2c->lock, flags);
do {
@@ -349,10 +352,62 @@ static void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c)
dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n");
}
+static void geni_i2c_rx_msg_cleanup(struct geni_i2c_dev *gi2c)
+{
+ struct geni_se *se = &gi2c->se;
+
+ gi2c->cur_rd = 0;
+ if (gi2c->dma_buf) {
+ if (gi2c->err)
+ geni_i2c_rx_fsm_rst(gi2c);
+ geni_se_rx_dma_unprep(se, gi2c->rx_dma, gi2c->xfer_len);
+ i2c_put_dma_safe_msg_buf(gi2c->dma_buf, gi2c->cur, !gi2c->err);
+ }
+}
+
+static void geni_i2c_tx_msg_cleanup(struct geni_i2c_dev *gi2c)
+{
+ struct geni_se *se = &gi2c->se;
+
+ gi2c->cur_wr = 0;
+ if (gi2c->dma_buf) {
+ if (gi2c->err)
+ geni_i2c_tx_fsm_rst(gi2c);
+ geni_se_tx_dma_unprep(se, gi2c->tx_dma, gi2c->xfer_len);
+ i2c_put_dma_safe_msg_buf(gi2c->dma_buf, gi2c->cur, !gi2c->err);
+ }
+}
+
+static void geni_i2c_stop_xfer(struct geni_i2c_dev *gi2c)
+{
+ int ret;
+ u32 geni_status;
+
+ /* Resume device, as runtime suspend can happen anytime during transfer */
+ ret = pm_runtime_get_sync(gi2c->se.dev);
+ if (ret < 0) {
+ dev_err(gi2c->se.dev, "Failed to resume device: %d\n", ret);
+ return;
+ }
+
+ geni_status = readl_relaxed(gi2c->se.base + SE_GENI_STATUS);
+ if (!(geni_status & M_GENI_CMD_ACTIVE))
+ goto out;
+
+ geni_i2c_abort_xfer(gi2c);
+ if (gi2c->cur->flags & I2C_M_RD)
+ geni_i2c_rx_msg_cleanup(gi2c);
+ else
+ geni_i2c_tx_msg_cleanup(gi2c);
+ gi2c->cur = NULL;
+out:
+ pm_runtime_put_sync_suspend(gi2c->se.dev);
+}
+
static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
u32 m_param)
{
- dma_addr_t rx_dma;
+ dma_addr_t rx_dma = 0;
unsigned long time_left;
void *dma_buf = NULL;
struct geni_se *se = &gi2c->se;
@@ -372,6 +427,10 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
geni_se_select_mode(se, GENI_SE_FIFO);
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
dma_buf = NULL;
+ } else {
+ gi2c->xfer_len = len;
+ gi2c->rx_dma = rx_dma;
+ gi2c->dma_buf = dma_buf;
}
geni_se_setup_m_cmd(se, I2C_READ, m_param);
@@ -380,13 +439,7 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
if (!time_left)
geni_i2c_abort_xfer(gi2c);
- gi2c->cur_rd = 0;
- if (dma_buf) {
- if (gi2c->err)
- geni_i2c_rx_fsm_rst(gi2c);
- geni_se_rx_dma_unprep(se, rx_dma, len);
- i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
- }
+ geni_i2c_rx_msg_cleanup(gi2c);
return gi2c->err;
}
@@ -394,7 +447,7 @@ static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
u32 m_param)
{
- dma_addr_t tx_dma;
+ dma_addr_t tx_dma = 0;
unsigned long time_left;
void *dma_buf = NULL;
struct geni_se *se = &gi2c->se;
@@ -414,6 +467,10 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
geni_se_select_mode(se, GENI_SE_FIFO);
i2c_put_dma_safe_msg_buf(dma_buf, msg, false);
dma_buf = NULL;
+ } else {
+ gi2c->xfer_len = len;
+ gi2c->tx_dma = tx_dma;
+ gi2c->dma_buf = dma_buf;
}
geni_se_setup_m_cmd(se, I2C_WRITE, m_param);
@@ -425,13 +482,7 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
if (!time_left)
geni_i2c_abort_xfer(gi2c);
- gi2c->cur_wr = 0;
- if (dma_buf) {
- if (gi2c->err)
- geni_i2c_tx_fsm_rst(gi2c);
- geni_se_tx_dma_unprep(se, tx_dma, len);
- i2c_put_dma_safe_msg_buf(dma_buf, msg, !gi2c->err);
- }
+ geni_i2c_tx_msg_cleanup(gi2c);
return gi2c->err;
}
@@ -630,6 +681,13 @@ static int geni_i2c_remove(struct platform_device *pdev)
return 0;
}
+static void geni_i2c_shutdown(struct platform_device *pdev)
+{
+ struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev);
+
+ geni_i2c_stop_xfer(gi2c);
+}
+
static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
{
int ret;
@@ -694,6 +752,7 @@ MODULE_DEVICE_TABLE(of, geni_i2c_dt_match);
static struct platform_driver geni_i2c_driver = {
.probe = geni_i2c_probe,
.remove = geni_i2c_remove,
+ .shutdown = geni_i2c_shutdown,
.driver = {
.name = "geni_i2c",
.pm = &geni_i2c_pm_ops,
diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c
index d0e4f520cff8..0216b38c1e9a 100644
--- a/drivers/soc/qcom/qcom-geni-se.c
+++ b/drivers/soc/qcom/qcom-geni-se.c
@@ -705,7 +705,7 @@ void geni_se_tx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len)
{
struct geni_wrapper *wrapper = se->wrapper;
- if (iova && !dma_mapping_error(wrapper->dev, iova))
+ if (!dma_mapping_error(wrapper->dev, iova))
dma_unmap_single(wrapper->dev, iova, len, DMA_TO_DEVICE);
}
EXPORT_SYMBOL(geni_se_tx_dma_unprep);
@@ -722,7 +722,7 @@ void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len)
{
struct geni_wrapper *wrapper = se->wrapper;
- if (iova && !dma_mapping_error(wrapper->dev, iova))
+ if (!dma_mapping_error(wrapper->dev, iova))
dma_unmap_single(wrapper->dev, iova, len, DMA_FROM_DEVICE);
}
EXPORT_SYMBOL(geni_se_rx_dma_unprep);
--
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation
next reply other threads:[~2020-09-17 13:05 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-09-17 12:25 Roja Rani Yarubandi [this message]
2020-09-17 20:23 ` [PATCH V4] i2c: i2c-qcom-geni: Add shutdown callback for i2c Stephen Boyd
2020-09-21 11:21 ` rojay
2020-09-21 20:12 ` Stephen Boyd
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200917122558.23110-1-rojay@codeaurora.org \
--to=rojay@codeaurora.org \
--cc=agross@kernel.org \
--cc=akashast@codeaurora.org \
--cc=bjorn.andersson@linaro.org \
--cc=dianders@chromium.org \
--cc=gregkh@linuxfoundation.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-i2c@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-media@vger.kernel.org \
--cc=mka@chromium.org \
--cc=msavaliy@qti.qualcomm.com \
--cc=pyarlaga@codeaurora.org \
--cc=rnayak@codeaurora.org \
--cc=saiprakash.ranjan@codeaurora.org \
--cc=skakit@codeaurora.org \
--cc=sumit.semwal@linaro.org \
--cc=swboyd@chromium.org \
--cc=vkaur@codeaurora.org \
--cc=wsa@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.