mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
gpio: mlxbf3: Support shutdown() function
During Linux graceful reboot, the GPIO interrupts are not disabled.
Since the drivers are not removed during graceful reboot,
the logic to call mlxbf3_gpio_irq_disable() is not triggered.
Interrupts that remain enabled can cause issues on subsequent boots.
For example, the mlxbf-gige driver contains PHY logic to bring up the link.
If the gpio-mlxbf3 driver loads first, the mlxbf-gige driver
will use a GPIO interrupt to bring up the link.
Otherwise, it will use polling.
The next time Linux boots and loads the drivers in this order, we encounter the issue:
- mlxbf-gige loads first and uses polling while the GPIO10
interrupt is still enabled from the previous boot. So if
the interrupt triggers, there is nothing to clear it.
- gpio-mlxbf3 loads.
- i2c-mlxbf loads. The interrupt doesn't trigger for I2C
because it is shared with the GPIO interrupt line which
was not cleared.
The solution is to add a shutdown function to the GPIO driver to clear and disable
all interrupts. Also clear the interrupt after disabling it in mlxbf3_gpio_irq_disable().
Fixes: 38a700efc5
("gpio: mlxbf3: Add gpio driver support")
Signed-off-by: Asmaa Mnebhi <asmaa@nvidia.com>
Reviewed-by: David Thompson <davthompson@nvidia.com>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
Link: https://lore.kernel.org/r/20240611171509.22151-1-asmaa@nvidia.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
This commit is contained in:
parent
8400291e28
commit
aad4183232
@ -39,6 +39,8 @@
|
||||
#define MLXBF_GPIO_CAUSE_OR_EVTEN0 0x14
|
||||
#define MLXBF_GPIO_CAUSE_OR_CLRCAUSE 0x18
|
||||
|
||||
#define MLXBF_GPIO_CLR_ALL_INTS GENMASK(31, 0)
|
||||
|
||||
struct mlxbf3_gpio_context {
|
||||
struct gpio_chip gc;
|
||||
|
||||
@ -82,6 +84,8 @@ static void mlxbf3_gpio_irq_disable(struct irq_data *irqd)
|
||||
val = readl(gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
|
||||
val &= ~BIT(offset);
|
||||
writel(val, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
|
||||
|
||||
writel(BIT(offset), gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CLRCAUSE);
|
||||
raw_spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags);
|
||||
|
||||
gpiochip_disable_irq(gc, offset);
|
||||
@ -253,6 +257,15 @@ static int mlxbf3_gpio_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mlxbf3_gpio_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct mlxbf3_gpio_context *gs = platform_get_drvdata(pdev);
|
||||
|
||||
/* Disable and clear all interrupts */
|
||||
writel(0, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_EVTEN0);
|
||||
writel(MLXBF_GPIO_CLR_ALL_INTS, gs->gpio_cause_io + MLXBF_GPIO_CAUSE_OR_CLRCAUSE);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id mlxbf3_gpio_acpi_match[] = {
|
||||
{ "MLNXBF33", 0 },
|
||||
{}
|
||||
@ -265,6 +278,7 @@ static struct platform_driver mlxbf3_gpio_driver = {
|
||||
.acpi_match_table = mlxbf3_gpio_acpi_match,
|
||||
},
|
||||
.probe = mlxbf3_gpio_probe,
|
||||
.shutdown = mlxbf3_gpio_shutdown,
|
||||
};
|
||||
module_platform_driver(mlxbf3_gpio_driver);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user