| From a4c0cfd2356c6a86ac5f383c49e4466be2855d18 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 27 May 2025 05:33:55 +0000 |
| Subject: pps: clients: gpio: fix interrupt handling order in remove path |
| |
| From: Eliav Farber <farbere@amazon.com> |
| |
| [ Upstream commit 6bca1e955830808dc90e0506b2951b4256b81bbb ] |
| |
| The interrupt handler in pps_gpio_probe() is registered after calling |
| pps_register_source() using devm_request_irq(). However, in the |
| corresponding remove function, pps_unregister_source() is called before |
| the IRQ is freed, since devm-managed resources are released after the |
| remove function completes. |
| |
| This creates a potential race condition where an interrupt may occur |
| after the PPS source is unregistered but before the handler is removed, |
| possibly leading to a kernel panic. |
| |
| To prevent this, switch from devm-managed IRQ registration to manual |
| management by using request_irq() and calling free_irq() explicitly in |
| the remove path before unregistering the PPS source. This ensures the |
| interrupt handler is safely removed before deactivating the PPS source. |
| |
| Signed-off-by: Eliav Farber <farbere@amazon.com> |
| Link: https://lore.kernel.org/r/20250527053355.37185-1-farbere@amazon.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/pps/clients/pps-gpio.c | 5 +++-- |
| 1 file changed, 3 insertions(+), 2 deletions(-) |
| |
| diff --git a/drivers/pps/clients/pps-gpio.c b/drivers/pps/clients/pps-gpio.c |
| index bf3b6f1aa984..41e1fdbcda16 100644 |
| --- a/drivers/pps/clients/pps-gpio.c |
| +++ b/drivers/pps/clients/pps-gpio.c |
| @@ -206,8 +206,8 @@ static int pps_gpio_probe(struct platform_device *pdev) |
| } |
| |
| /* register IRQ interrupt handler */ |
| - ret = devm_request_irq(dev, data->irq, pps_gpio_irq_handler, |
| - get_irqf_trigger_flags(data), data->info.name, data); |
| + ret = request_irq(data->irq, pps_gpio_irq_handler, |
| + get_irqf_trigger_flags(data), data->info.name, data); |
| if (ret) { |
| pps_unregister_source(data->pps); |
| dev_err(dev, "failed to acquire IRQ %d\n", data->irq); |
| @@ -224,6 +224,7 @@ static int pps_gpio_remove(struct platform_device *pdev) |
| { |
| struct pps_gpio_device_data *data = platform_get_drvdata(pdev); |
| |
| + free_irq(data->irq, data); |
| pps_unregister_source(data->pps); |
| del_timer_sync(&data->echo_timer); |
| /* reset echo pin in any case */ |
| -- |
| 2.39.5 |
| |