]> Gentwo Git Trees - linux/.git/commitdiff
mfd: max77620: Fix potential IRQ chip conflict when probing two devices
authorKrzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Thu, 23 Oct 2025 10:19:40 +0000 (12:19 +0200)
committerLee Jones <lee@kernel.org>
Thu, 6 Nov 2025 14:04:02 +0000 (14:04 +0000)
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>
drivers/mfd/max77620.c

index 21d2ab3db2542ef8bcbd82262ac1fbd1dfdbce5c..3af2974b302327c2d21d05a675ac69d632f6732a 100644 (file)
@@ -254,7 +254,7 @@ static int max77620_irq_global_unmask(void *irq_drv_data)
        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),
@@ -498,6 +498,7 @@ static int max77620_probe(struct i2c_client *client)
        const struct i2c_device_id *id = i2c_client_get_device_id(client);
        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;
@@ -508,6 +509,14 @@ static int max77620_probe(struct i2c_client *client)
                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;
@@ -544,11 +553,9 @@ static int max77620_probe(struct i2c_client *client)
        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;