| From 15f049ea16aaa2b4b47349093f8fd6cfb53f505d Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 4 Jun 2021 16:27:44 -0700 |
| Subject: i2c: core: Disable client irq on reboot/shutdown |
| |
| From: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| |
| [ Upstream commit b64210f2f7c11c757432ba3701d88241b2b98fb1 ] |
| |
| If an i2c client receives an interrupt during reboot or shutdown it may |
| be too late to service it by making an i2c transaction on the bus |
| because the i2c controller has already been shutdown. This can lead to |
| system hangs if the i2c controller tries to make a transfer that is |
| doomed to fail because the access to the i2c pins is already shut down, |
| or an iommu translation has been torn down so i2c controller register |
| access doesn't work. |
| |
| Let's simply disable the irq if there isn't a shutdown callback for an |
| i2c client when there is an irq associated with the device. This will |
| make sure that irqs don't come in later than the time that we can handle |
| it. We don't do this if the i2c client device already has a shutdown |
| callback because presumably they're doing the right thing and quieting |
| the device so irqs don't come in after the shutdown callback returns. |
| |
| Reported-by: kernel test robot <lkp@intel.com> |
| [swboyd@chromium.org: Dropped newline, added commit text, added |
| interrupt.h for robot build error] |
| Signed-off-by: Stephen Boyd <swboyd@chromium.org> |
| Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> |
| Signed-off-by: Wolfram Sang <wsa@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/i2c/i2c-core-base.c | 3 +++ |
| 1 file changed, 3 insertions(+) |
| |
| diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c |
| index f21362355973..8e4be0d4ce34 100644 |
| --- a/drivers/i2c/i2c-core-base.c |
| +++ b/drivers/i2c/i2c-core-base.c |
| @@ -24,6 +24,7 @@ |
| #include <linux/i2c-smbus.h> |
| #include <linux/idr.h> |
| #include <linux/init.h> |
| +#include <linux/interrupt.h> |
| #include <linux/irqflags.h> |
| #include <linux/jump_label.h> |
| #include <linux/kernel.h> |
| @@ -587,6 +588,8 @@ static void i2c_device_shutdown(struct device *dev) |
| driver = to_i2c_driver(dev->driver); |
| if (driver->shutdown) |
| driver->shutdown(client); |
| + else if (client->irq > 0) |
| + disable_irq(client->irq); |
| } |
| |
| static void i2c_client_dev_release(struct device *dev) |
| -- |
| 2.30.2 |
| |