summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKrzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>2026-03-06 00:45:48 +0300
committerLee Jones <lee@kernel.org>2026-03-25 15:45:59 +0300
commit30eedf2446a9ada57a6bda22ec6b89533feb81ed (patch)
treea5e65f6651d7c0a7e3b15da4c14867b5975c053b
parentef5a54c542f5388df3f142a84de642d33790bd7b (diff)
downloadlinux-30eedf2446a9ada57a6bda22ec6b89533feb81ed.tar.xz
mfd: ezx-pcap: Avoid rescheduling after destroying workqueue
Driver allocates workqueue and then registers additional interrupt handler with devm interface. This means that device removal will not use a reversed order, but first destroy workqueue and then, via devm release handlers, free the interrupt. The interrupt handler registered with devm does not directly use/schedule work items on the workqueue and the remove() function correctly removes other IRQs handlers, however the code mixing devm and non-devm interfaces is difficult to analyze and read. Make the code flow much more obvious by using devm interface for allocating the workqueue, so it will be freed with the rest of devm resources. Change is not equivalent in the workqueue itself: use non-legacy API which does not set (__WQ_LEGACY | WQ_MEM_RECLAIM). The workqueue is used to update device registers, thus there is no point to run it for memory reclaim. Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Link: https://patch.msgid.link/20260305-workqueue-devm-v2-9-66a38741c652@oss.qualcomm.com Signed-off-by: Lee Jones <lee@kernel.org>
-rw-r--r--drivers/mfd/ezx-pcap.c8
1 files changed, 2 insertions, 6 deletions
diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c
index 8e51c113a320..9a685ff8cd15 100644
--- a/drivers/mfd/ezx-pcap.c
+++ b/drivers/mfd/ezx-pcap.c
@@ -375,8 +375,6 @@ static void ezx_pcap_remove(struct spi_device *spi)
/* cleanup irqchip */
for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++)
irq_set_chip_and_handler(i, NULL, NULL);
-
- destroy_workqueue(pcap->workqueue);
}
static int ezx_pcap_probe(struct spi_device *spi)
@@ -411,7 +409,7 @@ static int ezx_pcap_probe(struct spi_device *spi)
/* setup irq */
pcap->irq_base = pdata->irq_base;
- pcap->workqueue = create_singlethread_workqueue("pcapd");
+ pcap->workqueue = devm_alloc_ordered_workqueue(&spi->dev, "pcapd", 0);
if (!pcap->workqueue)
return -ENOMEM;
@@ -463,9 +461,7 @@ remove_subdevs:
free_irqchip:
for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++)
irq_set_chip_and_handler(i, NULL, NULL);
-/* destroy_workqueue: */
- destroy_workqueue(pcap->workqueue);
-ret:
+
return ret;
}