Commit e0371298 authored by Roja Rani Yarubandi's avatar Roja Rani Yarubandi Committed by Wolfram Sang

i2c: i2c-qcom-geni: Add shutdown callback for i2c

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".

Fixes: 37692de5 ("i2c: i2c-qcom-geni: Add bus driver for the Qualcomm GENI I2C controller")
Signed-off-by: default avatarRoja Rani Yarubandi <rojay@codeaurora.org>
Reviewed-by: default avatarAkash Asthana <akashast@codeaurora.org>
Signed-off-by: default avatarWolfram Sang <wsa@kernel.org>
parent e5c02cf5
...@@ -375,6 +375,32 @@ static void geni_i2c_tx_msg_cleanup(struct geni_i2c_dev *gi2c, ...@@ -375,6 +375,32 @@ static void geni_i2c_tx_msg_cleanup(struct geni_i2c_dev *gi2c,
} }
} }
static void geni_i2c_stop_xfer(struct geni_i2c_dev *gi2c)
{
int ret;
u32 geni_status;
struct i2c_msg *cur;
/* 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) {
cur = gi2c->cur;
geni_i2c_abort_xfer(gi2c);
if (cur->flags & I2C_M_RD)
geni_i2c_rx_msg_cleanup(gi2c, cur);
else
geni_i2c_tx_msg_cleanup(gi2c, cur);
}
pm_runtime_put_sync_suspend(gi2c->se.dev);
}
static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, static int geni_i2c_rx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
u32 m_param) u32 m_param)
{ {
...@@ -650,6 +676,13 @@ static int geni_i2c_remove(struct platform_device *pdev) ...@@ -650,6 +676,13 @@ static int geni_i2c_remove(struct platform_device *pdev)
return 0; 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) static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev)
{ {
int ret; int ret;
...@@ -714,6 +747,7 @@ MODULE_DEVICE_TABLE(of, geni_i2c_dt_match); ...@@ -714,6 +747,7 @@ MODULE_DEVICE_TABLE(of, geni_i2c_dt_match);
static struct platform_driver geni_i2c_driver = { static struct platform_driver geni_i2c_driver = {
.probe = geni_i2c_probe, .probe = geni_i2c_probe,
.remove = geni_i2c_remove, .remove = geni_i2c_remove,
.shutdown = geni_i2c_shutdown,
.driver = { .driver = {
.name = "geni_i2c", .name = "geni_i2c",
.pm = &geni_i2c_pm_ops, .pm = &geni_i2c_pm_ops,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment