[PATCH 2/2] i2c: qcom-geni: Add panic notifier to prevent transfers during panic
Praveen Talari <[email protected]>
| Newsgroups | org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-i2c,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <20260818-add-shutdown-and-panic-notifier-for-i2c-v1-2-9f31b5fae5f6@oss.qualcomm.com> |
When a VM crashes with an active I2C DMA transfer in progress, the SMMU raises context faults as the DMA engine continues to access IOVAs that are invalidated when the VM's memory context is torn down. These faults can affect other VMs sharing the same SMMU instance. Register a panic notifier that calls the same geni_i2c_quiesce() helper used by the shutdown path. This marks the I2C adapter suspended, preventing new transfers from being initiated, and cancels/aborts any transfer already in flight, limiting the window during which the DMA engine can access IOVAs that are about to be invalidated. Signed-off-by: Praveen Talari <[email protected]> --- drivers/i2c/busses/i2c-qcom-geni.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 10c6a4b0b825..2f8237c232e1 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -16,6 +16,7 @@ #include <linux/iopoll.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/panic_notifier.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/soc/qcom/geni-se.h> @@ -139,6 +140,7 @@ struct geni_i2c_dev { u32 num_msgs; struct geni_i2c_gpi_multi_desc_xfer i2c_multi_desc_config; const struct geni_i2c_desc *dev_data; + struct notifier_block panic_nb; }; struct geni_i2c_err_log { @@ -1082,6 +1084,19 @@ static void geni_i2c_quiesce(struct geni_i2c_dev *gi2c) } } +static int geni_i2c_panic_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct geni_i2c_dev *gi2c = container_of(nb, struct geni_i2c_dev, panic_nb); + + /* Make client i2c transfers start failing */ + i2c_mark_adapter_suspended(&gi2c->adap); + + geni_i2c_quiesce(gi2c); + + return NOTIFY_OK; +} + static int geni_i2c_init(struct geni_i2c_dev *gi2c) { u32 proto, tx_depth; @@ -1236,9 +1251,16 @@ static int geni_i2c_probe(struct platform_device *pdev) if (ret < 0) return ret; - ret = i2c_add_adapter(&gi2c->adap); + gi2c->panic_nb.notifier_call = geni_i2c_panic_notifier; + ret = atomic_notifier_chain_register(&panic_notifier_list, &gi2c->panic_nb); if (ret) + return dev_err_probe(dev, ret, "Error registering panic notifier\n"); + + ret = i2c_add_adapter(&gi2c->adap); + if (ret) { + atomic_notifier_chain_unregister(&panic_notifier_list, &gi2c->panic_nb); return dev_err_probe(dev, ret, "Error adding i2c adapter\n"); + } dev_dbg(dev, "Geni-I2C adaptor successfully added\n"); @@ -1249,6 +1271,8 @@ static void geni_i2c_remove(struct platform_device *pdev) { struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); + atomic_notifier_chain_unregister(&panic_notifier_list, &gi2c->panic_nb); + i2c_del_adapter(&gi2c->adap); release_gpi_dma(gi2c); } -- 2.34.1