From: Jinhui Guo guojinhui.liam@bytedance.com
[ Upstream commit d3429178ee51dd7155445d15a5ab87a45fae3c73 ]
When probing the I2C master, disable SMBus interrupts to prevent storms caused by broken firmware mis-configuring IC_SMBUS=1; the handler never services them and a mis-configured SMBUS Master extend-clock timeout or SMBUS Slave extend-clock timeout can flood the CPU.
Signed-off-by: Jinhui Guo guojinhui.liam@bytedance.com Reviewed-by: Andy Shevchenko andriy.shevchenko@linux.intel.com Acked-by: Mika Westerberg mika.westerberg@linux.intel.com Signed-off-by: Andi Shyti andi.shyti@kernel.org Link: https://lore.kernel.org/r/20251021075714.3712-2-guojinhui.liam@bytedance.com Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
## ANALYSIS SUMMARY
### Problem Being Fixed This commit fixes an **interrupt storm** caused by misconfigured firmware that leaves `IC_SMBUS=1` in the DesignWare I2C controller. When this happens: 1. SMBus-related interrupts (Master/Slave extend-clock timeout) get enabled 2. The driver has NO handler for these interrupts 3. Unserviced interrupts fire continuously, flooding the CPU 4. This effectively causes a denial-of-service condition
### Code Change Assessment
**Header file (`i2c-designware-core.h`):** - Adds one register offset: `#define DW_IC_SMBUS_INTR_MASK 0xcc`
**Master file (`i2c-designware-master.c`):** - In `i2c_dw_init_master()`, after disabling the adapter, writes 0 to the SMBus interrupt mask register to disable all SMBus interrupts
The fix is **defensive programming**: it proactively masks interrupts the driver doesn't use, regardless of what firmware may have configured.
### Stable Criteria Evaluation
| Criterion | Assessment | |-----------|------------| | Obviously correct | ✅ Yes - writing 0 to mask unused interrupts is safe | | Fixes real bug | ✅ Yes - interrupt storms are real and severe | | Important issue | ✅ Yes - system can become unresponsive | | Small and contained | ✅ Yes - 2 lines of actual code | | No new features | ✅ Correct - purely defensive | | Clean backport | ✅ Yes - minimal, self-contained change |
### Risk vs Benefit
**Benefits:** - Prevents interrupt storms that can make systems unusable - ByteDance reporting this suggests real-world occurrence in production - The i2c-designware driver is widely used (Intel SoCs, embedded systems)
**Risks:** - Nearly zero - only disables interrupts the driver never uses - Writing 0 to an interrupt mask register is inherently safe - The function structure (`i2c_dw_init_master`) has been stable
### Stability Indicators - **Reviewed-by:** Andy Shevchenko (well-known kernel developer) - **Acked-by:** Mika Westerberg (Intel/I2C maintainer) - Well-commented explaining the rationale
### Missing Tags Analysis - **No `Cc: stable`** - not disqualifying; many important fixes lack this - **No `Fixes:` tag** - the bug likely existed since driver creation, not a recent regression
### Category This falls into the **hardware quirk/workaround** exception category - defensive code to handle broken/misconfigured firmware, which is explicitly allowed in stable trees.
### Dependency Check - No dependencies on other commits - The `i2c_dw_init_master()` function exists in all stable trees with the same structure - Should apply cleanly to stable kernels
---
## Conclusion
This commit should be backported to stable kernels because:
1. **Severity**: Interrupt storms can make systems completely unresponsive 2. **Fix quality**: Minimal, surgical, well-reviewed change 3. **Risk**: Effectively zero - disabling unused interrupts cannot cause regression 4. **Scope**: Affects a widely-used I2C controller driver 5. **Real-world impact**: Reported by ByteDance, indicating production occurrence 6. **Category**: Hardware workaround - appropriate for stable
The fix is a textbook example of defensive programming that protects against broken firmware while having no downside.
**YES**
drivers/i2c/busses/i2c-designware-core.h | 1 + drivers/i2c/busses/i2c-designware-master.c | 7 +++++++ 2 files changed, 8 insertions(+)
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 347843b4f5dd7..436555543c79d 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -78,6 +78,7 @@ #define DW_IC_TX_ABRT_SOURCE 0x80 #define DW_IC_ENABLE_STATUS 0x9c #define DW_IC_CLR_RESTART_DET 0xa8 +#define DW_IC_SMBUS_INTR_MASK 0xcc #define DW_IC_COMP_PARAM_1 0xf4 #define DW_IC_COMP_VERSION 0xf8 #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A /* "111*" == v1.11* */ diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 41e9b5ecad201..45bfca05bb300 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -220,6 +220,13 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev) /* Disable the adapter */ __i2c_dw_disable(dev);
+ /* + * Mask SMBus interrupts to block storms from broken + * firmware that leaves IC_SMBUS=1; the handler never + * services them. + */ + regmap_write(dev->map, DW_IC_SMBUS_INTR_MASK, 0); + /* Write standard speed timing parameters */ regmap_write(dev->map, DW_IC_SS_SCL_HCNT, dev->ss_hcnt); regmap_write(dev->map, DW_IC_SS_SCL_LCNT, dev->ss_lcnt);