Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd: max77620: Fix potential IRQ chip conflict when probing two devices

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>

authored by

Krzysztof Kozlowski and committed by
Lee Jones
2bac49ba 5d5d7c42

+11 -4
+11 -4
drivers/mfd/max77620.c
··· 254 254 return ret; 255 255 } 256 256 257 - static struct regmap_irq_chip max77620_top_irq_chip = { 257 + static const struct regmap_irq_chip max77620_top_irq_chip = { 258 258 .name = "max77620-top", 259 259 .irqs = max77620_top_irqs, 260 260 .num_irqs = ARRAY_SIZE(max77620_top_irqs), ··· 498 498 const struct i2c_device_id *id = i2c_client_get_device_id(client); 499 499 const struct regmap_config *rmap_config; 500 500 struct max77620_chip *chip; 501 + struct regmap_irq_chip *chip_desc; 501 502 const struct mfd_cell *mfd_cells; 502 503 int n_mfd_cells; 503 504 bool pm_off; ··· 509 508 return -ENOMEM; 510 509 511 510 i2c_set_clientdata(client, chip); 511 + 512 + chip_desc = devm_kmemdup(&client->dev, &max77620_top_irq_chip, 513 + sizeof(max77620_top_irq_chip), 514 + GFP_KERNEL); 515 + if (!chip_desc) 516 + return -ENOMEM; 517 + chip_desc->irq_drv_data = chip; 518 + 512 519 chip->dev = &client->dev; 513 520 chip->chip_irq = client->irq; 514 521 chip->chip_id = (enum max77620_chip_id)id->driver_data; ··· 553 544 if (ret < 0) 554 545 return ret; 555 546 556 - max77620_top_irq_chip.irq_drv_data = chip; 557 547 ret = devm_regmap_add_irq_chip(chip->dev, chip->rmap, client->irq, 558 548 IRQF_ONESHOT | IRQF_SHARED, 0, 559 - &max77620_top_irq_chip, 560 - &chip->top_irq_data); 549 + chip_desc, &chip->top_irq_data); 561 550 if (ret < 0) { 562 551 dev_err(chip->dev, "Failed to add regmap irq: %d\n", ret); 563 552 return ret;