[PATCH] firewire: core: clear sources of hardware interrupt at card removal

Takashi Sakamoto posted 1 patch 1 month, 1 week ago
drivers/firewire/core-card.c |  3 +++
drivers/firewire/core.h      |  3 +++
drivers/firewire/ohci.c      | 44 +++++++++++++++++++++++++++++-------
3 files changed, 42 insertions(+), 8 deletions(-)
[PATCH] firewire: core: clear sources of hardware interrupt at card removal
Posted by Takashi Sakamoto 1 month, 1 week ago
Due to the factors external to the system, hardware events may still be
handled while a card instance is being removed. The sources of hardware
IRQs should be cleared during card removal so that workqueues can be safely
destroyed.

This commit adds a disable callback to the underlying driver operations.
After this callback returns, the underlying driver guarantees that it
will no longer handle hardware events.

Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 drivers/firewire/core-card.c |  3 +++
 drivers/firewire/core.h      |  3 +++
 drivers/firewire/ohci.c      | 44 +++++++++++++++++++++++++++++-------
 3 files changed, 42 insertions(+), 8 deletions(-)

diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 6979d6a88ae2..65bd9db996c0 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -784,9 +784,12 @@ void fw_core_remove_card(struct fw_card *card)
 	/* Switch off most of the card driver interface. */
 	dummy_driver.free_iso_context	= card->driver->free_iso_context;
 	dummy_driver.stop_iso		= card->driver->stop_iso;
+	dummy_driver.disable		= card->driver->disable;
 	card->driver = &dummy_driver;
+
 	drain_workqueue(card->isoc_wq);
 	drain_workqueue(card->async_wq);
+	card->driver->disable(card);
 
 	scoped_guard(spinlock_irqsave, &card->lock)
 		fw_destroy_nodes(card);
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index e67395ce26b5..903812b6bb3f 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -65,6 +65,9 @@ struct fw_card_driver {
 	int (*enable)(struct fw_card *card,
 		      const __be32 *config_rom, size_t length);
 
+	// After returning the call, any function is no longer triggered to handle hardware event.
+	void (*disable)(struct fw_card *card);
+
 	int (*read_phy_reg)(struct fw_card *card, int address);
 	int (*update_phy_reg)(struct fw_card *card, int address,
 			      int clear_bits, int set_bits);
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 757dd9c64b1c..0625d11dbd74 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -2408,6 +2408,41 @@ static int ohci_enable(struct fw_card *card,
 	return 0;
 }
 
+static void ohci_disable(struct fw_card *card)
+{
+	struct pci_dev *pdev = to_pci_dev(card->device);
+	struct fw_ohci *ohci = pci_get_drvdata(pdev);
+	int i, irq = pci_irq_vector(pdev, 0);
+
+	// If the removal is happening from the suspend state, LPS won't be enabled and host
+	// registers (eg., IntMaskClear) won't be accessible.
+	if (!(reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_LPS))
+		return;
+
+	reg_write(ohci, OHCI1394_IntMaskClear, ~0);
+	flush_writes(ohci);
+
+	if (irq >= 0)
+		synchronize_irq(irq);
+
+	flush_work(&ohci->ar_request_ctx.work);
+	flush_work(&ohci->ar_response_ctx.work);
+	flush_work(&ohci->at_request_ctx.work);
+	flush_work(&ohci->at_response_ctx.work);
+
+	for (i = 0; i < ohci->n_ir; ++i) {
+		if (!(ohci->ir_context_mask & BIT(i)))
+			flush_work(&ohci->ir_context_list[i].base.work);
+	}
+	for (i = 0; i < ohci->n_it; ++i) {
+		if (!(ohci->it_context_mask & BIT(i)))
+			flush_work(&ohci->it_context_list[i].base.work);
+	}
+
+	at_context_flush(&ohci->at_request_ctx);
+	at_context_flush(&ohci->at_response_ctx);
+}
+
 static int ohci_set_config_rom(struct fw_card *card,
 			       const __be32 *config_rom, size_t length)
 {
@@ -3442,6 +3477,7 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base)
 
 static const struct fw_card_driver ohci_driver = {
 	.enable			= ohci_enable,
+	.disable		= ohci_disable,
 	.read_phy_reg		= ohci_read_phy_reg,
 	.update_phy_reg		= ohci_update_phy_reg,
 	.set_config_rom		= ohci_set_config_rom,
@@ -3681,14 +3717,6 @@ static void pci_remove(struct pci_dev *dev)
 	struct fw_ohci *ohci = pci_get_drvdata(dev);
 	int irq;
 
-	/*
-	 * If the removal is happening from the suspend state, LPS won't be
-	 * enabled and host registers (eg., IntMaskClear) won't be accessible.
-	 */
-	if (reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_LPS) {
-		reg_write(ohci, OHCI1394_IntMaskClear, ~0);
-		flush_writes(ohci);
-	}
 	fw_core_remove_card(&ohci->card);
 
 	/*

base-commit: fa2dc27100768a8a994c377051fa17a47cc66c76
-- 
2.51.0
Re: [PATCH] firewire: core: clear sources of hardware interrupt at card removal
Posted by Takashi Sakamoto 1 month, 1 week ago
On Sun, Nov 09, 2025 at 03:55:25PM +0900, Takashi Sakamoto wrote:
> Due to the factors external to the system, hardware events may still be
> handled while a card instance is being removed. The sources of hardware
> IRQs should be cleared during card removal so that workqueues can be safely
> destroyed.
> 
> This commit adds a disable callback to the underlying driver operations.
> After this callback returns, the underlying driver guarantees that it
> will no longer handle hardware events.
> 
> Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
> ---
>  drivers/firewire/core-card.c |  3 +++
>  drivers/firewire/core.h      |  3 +++
>  drivers/firewire/ohci.c      | 44 +++++++++++++++++++++++++++++-------
>  3 files changed, 42 insertions(+), 8 deletions(-)

Applied to for-next branch.


Regards

Takashi Sakamoto