| From 2bac49bad1f3553cc3b3bfb22cc194e9bd9e8427 Mon Sep 17 00:00:00 2001 |
| From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> |
| Date: Thu, 23 Oct 2025 12:19:40 +0200 |
| Subject: mfd: max77620: Fix potential IRQ chip conflict when probing two devices |
| |
| From: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> |
| |
| commit 2bac49bad1f3553cc3b3bfb22cc194e9bd9e8427 upstream. |
| |
| MAX77620 is most likely always a single device on the board, however |
| nothing stops board designers to have two of them, thus same device |
| driver could probe twice. Or user could manually try to probing second |
| time. |
| |
| Device driver is not ready for that case, because it allocates |
| statically 'struct regmap_irq_chip' as non-const and stores during |
| probe in 'irq_drv_data' member a pointer to per-probe state |
| container ('struct max77620_chip'). devm_regmap_add_irq_chip() does not |
| make a copy of 'struct regmap_irq_chip' but store the pointer. |
| |
| Second probe - either successful or failure - would overwrite the |
| 'irq_drv_data' from previous device probe, so interrupts would be |
| executed in a wrong context. |
| |
| Cc: stable@vger.kernel.org |
| Fixes: 3df140d11c6d ("mfd: max77620: Mask/unmask interrupt before/after servicing it") |
| Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org> |
| Link: https://patch.msgid.link/20251023101939.67991-2-krzysztof.kozlowski@linaro.org |
| Signed-off-by: Lee Jones <lee@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/mfd/max77620.c | 15 +++++++++++---- |
| 1 file changed, 11 insertions(+), 4 deletions(-) |
| |
| --- a/drivers/mfd/max77620.c |
| +++ b/drivers/mfd/max77620.c |
| @@ -254,7 +254,7 @@ static int max77620_irq_global_unmask(vo |
| return ret; |
| } |
| |
| -static struct regmap_irq_chip max77620_top_irq_chip = { |
| +static const struct regmap_irq_chip max77620_top_irq_chip = { |
| .name = "max77620-top", |
| .irqs = max77620_top_irqs, |
| .num_irqs = ARRAY_SIZE(max77620_top_irqs), |
| @@ -499,6 +499,7 @@ static int max77620_probe(struct i2c_cli |
| { |
| const struct regmap_config *rmap_config; |
| struct max77620_chip *chip; |
| + struct regmap_irq_chip *chip_desc; |
| const struct mfd_cell *mfd_cells; |
| int n_mfd_cells; |
| bool pm_off; |
| @@ -509,6 +510,14 @@ static int max77620_probe(struct i2c_cli |
| return -ENOMEM; |
| |
| i2c_set_clientdata(client, chip); |
| + |
| + chip_desc = devm_kmemdup(&client->dev, &max77620_top_irq_chip, |
| + sizeof(max77620_top_irq_chip), |
| + GFP_KERNEL); |
| + if (!chip_desc) |
| + return -ENOMEM; |
| + chip_desc->irq_drv_data = chip; |
| + |
| chip->dev = &client->dev; |
| chip->chip_irq = client->irq; |
| chip->chip_id = (enum max77620_chip_id)id->driver_data; |
| @@ -545,11 +554,9 @@ static int max77620_probe(struct i2c_cli |
| if (ret < 0) |
| return ret; |
| |
| - max77620_top_irq_chip.irq_drv_data = chip; |
| ret = devm_regmap_add_irq_chip(chip->dev, chip->rmap, client->irq, |
| IRQF_ONESHOT | IRQF_SHARED, 0, |
| - &max77620_top_irq_chip, |
| - &chip->top_irq_data); |
| + chip_desc, &chip->top_irq_data); |
| if (ret < 0) { |
| dev_err(chip->dev, "Failed to add regmap irq: %d\n", ret); |
| return ret; |