Skip to content

Commit 594a6a2

Browse files
committed
firewire: core: clear sources of hardware interrupt at card removal
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. Link: https://lore.kernel.org/r/20251109065525.163464-1-o-takashi@sakamocchi.jp Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
1 parent fa2dc27 commit 594a6a2

3 files changed

Lines changed: 42 additions & 8 deletions

File tree

drivers/firewire/core-card.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -784,9 +784,12 @@ void fw_core_remove_card(struct fw_card *card)
784784
/* Switch off most of the card driver interface. */
785785
dummy_driver.free_iso_context = card->driver->free_iso_context;
786786
dummy_driver.stop_iso = card->driver->stop_iso;
787+
dummy_driver.disable = card->driver->disable;
787788
card->driver = &dummy_driver;
789+
788790
drain_workqueue(card->isoc_wq);
789791
drain_workqueue(card->async_wq);
792+
card->driver->disable(card);
790793

791794
scoped_guard(spinlock_irqsave, &card->lock)
792795
fw_destroy_nodes(card);

drivers/firewire/core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ struct fw_card_driver {
6565
int (*enable)(struct fw_card *card,
6666
const __be32 *config_rom, size_t length);
6767

68+
// After returning the call, any function is no longer triggered to handle hardware event.
69+
void (*disable)(struct fw_card *card);
70+
6871
int (*read_phy_reg)(struct fw_card *card, int address);
6972
int (*update_phy_reg)(struct fw_card *card, int address,
7073
int clear_bits, int set_bits);

drivers/firewire/ohci.c

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2408,6 +2408,41 @@ static int ohci_enable(struct fw_card *card,
24082408
return 0;
24092409
}
24102410

2411+
static void ohci_disable(struct fw_card *card)
2412+
{
2413+
struct pci_dev *pdev = to_pci_dev(card->device);
2414+
struct fw_ohci *ohci = pci_get_drvdata(pdev);
2415+
int i, irq = pci_irq_vector(pdev, 0);
2416+
2417+
// If the removal is happening from the suspend state, LPS won't be enabled and host
2418+
// registers (eg., IntMaskClear) won't be accessible.
2419+
if (!(reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_LPS))
2420+
return;
2421+
2422+
reg_write(ohci, OHCI1394_IntMaskClear, ~0);
2423+
flush_writes(ohci);
2424+
2425+
if (irq >= 0)
2426+
synchronize_irq(irq);
2427+
2428+
flush_work(&ohci->ar_request_ctx.work);
2429+
flush_work(&ohci->ar_response_ctx.work);
2430+
flush_work(&ohci->at_request_ctx.work);
2431+
flush_work(&ohci->at_response_ctx.work);
2432+
2433+
for (i = 0; i < ohci->n_ir; ++i) {
2434+
if (!(ohci->ir_context_mask & BIT(i)))
2435+
flush_work(&ohci->ir_context_list[i].base.work);
2436+
}
2437+
for (i = 0; i < ohci->n_it; ++i) {
2438+
if (!(ohci->it_context_mask & BIT(i)))
2439+
flush_work(&ohci->it_context_list[i].base.work);
2440+
}
2441+
2442+
at_context_flush(&ohci->at_request_ctx);
2443+
at_context_flush(&ohci->at_response_ctx);
2444+
}
2445+
24112446
static int ohci_set_config_rom(struct fw_card *card,
24122447
const __be32 *config_rom, size_t length)
24132448
{
@@ -3442,6 +3477,7 @@ static int ohci_flush_iso_completions(struct fw_iso_context *base)
34423477

34433478
static const struct fw_card_driver ohci_driver = {
34443479
.enable = ohci_enable,
3480+
.disable = ohci_disable,
34453481
.read_phy_reg = ohci_read_phy_reg,
34463482
.update_phy_reg = ohci_update_phy_reg,
34473483
.set_config_rom = ohci_set_config_rom,
@@ -3681,14 +3717,6 @@ static void pci_remove(struct pci_dev *dev)
36813717
struct fw_ohci *ohci = pci_get_drvdata(dev);
36823718
int irq;
36833719

3684-
/*
3685-
* If the removal is happening from the suspend state, LPS won't be
3686-
* enabled and host registers (eg., IntMaskClear) won't be accessible.
3687-
*/
3688-
if (reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_LPS) {
3689-
reg_write(ohci, OHCI1394_IntMaskClear, ~0);
3690-
flush_writes(ohci);
3691-
}
36923720
fw_core_remove_card(&ohci->card);
36933721

36943722
/*

0 commit comments

Comments
 (0)