gpio: mlxbf3: Support shutdown() function
PATCH 1/1 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. The gige driver uses polling while the GPIO10 interrupt is still enabled from 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().
--- drivers/gpio/gpio-mlxbf3.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/gpio/gpio-mlxbf3.c +14 -0
@@ -39,6 +39,8 @@#define MLXBF_GPIO_CAUSE_OR_EVTEN0 0x14#define MLXBF_GPIO_CAUSE_OR_CLRCAUSE 0x18 +#define MLXBF_GPIO_CLR_ALL_INTS 0xFFFFFFFF +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 =dev_get_drvdata (&pdev->dev); + +/* 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);
Signature · 1 line
2.30.1
Quoted 6 lines · Asmaa Mnebhi
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.
Quoted 10 lines
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. The gige driver uses polling while the GPIO10 interrupt is still enabled from 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
GPIO
Quoted 3 lines
interrupt line which was not cleared.
The solution is to add a shutdown function to the gpio driver to clear and disable
GPIO
Quoted 1 line
all interrupts. Also clear the interrupt after disabling it in
mlxbf3_gpio_irq_disable().
...
Quoted 1 line
+#define
MLXBF_GPIO_CLR_ALL_INTS0xFFFFFFFF
GENMASK()
...
drivers/gpio/gpio-mlxbf3.c static int mlxbf3_gpio_probe(struct platform_device *pdev) · line 262
Quoted 3 lines
drivers/gpio/gpio-mlxbf3.c +3
-0+static void mlxbf3_gpio_shutdown (struct platform_device *pdev) +{ +struct mlxbf3_gpio_context *gs =dev_get_drvdata (&pdev->dev);
platform_get_drvdata()
Quoted 4 lines
drivers/gpio/gpio-mlxbf3.c +4
-0+/* 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 ); +}
Signature · 2 lines
With Best Regards, Andy Shevchenko