diff options
| author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2025-11-12 07:38:34 +0900 |
|---|---|---|
| committer | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2025-11-14 04:30:58 +0900 |
| commit | 036176d9dba74e23e3ef358e171a77b75837fee0 (patch) | |
| tree | 0af96930d3a5404c92009657bddadd01b11e91c1 /drivers/firewire/core-transaction.c | |
| parent | ae1ef2fbb8c9091e0ea62734a4a232ad9928701b (diff) | |
firewire: core: abort pending transactions at card removal
IEEE 1394 defines the split, concatenated, and unified transaction.
To support the split transaction, core function uses linked list to
maintain the transactions waiting for acknowledge packet. After clearing
sources of hardware interrupts, the acknowledge packet is no longer
handled, therefore it is required to abort the pending transactions.
This commit executes callback with RCODE_CANCELLED for the pending
transactions at card removal.
Link: https://lore.kernel.org/r/20251111223834.311287-1-o-takashi@sakamocchi.jp
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Diffstat (limited to 'drivers/firewire/core-transaction.c')
| -rw-r--r-- | drivers/firewire/core-transaction.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 642387f0d7ca..7be4ae3b36b5 100644 --- a/drivers/firewire/core-transaction.c +++ b/drivers/firewire/core-transaction.c @@ -51,6 +51,34 @@ static void remove_transaction_entry(struct fw_card *card, struct fw_transaction card->transactions.tlabel_mask &= ~(1ULL << entry->tlabel); } +// Must be called without holding card->transactions.lock. +void fw_cancel_pending_transactions(struct fw_card *card) +{ + struct fw_transaction *t, *tmp; + LIST_HEAD(pending_list); + + // NOTE: This can be without irqsave when we can guarantee that __fw_send_request() for + // local destination never runs in any type of IRQ context. + scoped_guard(spinlock_irqsave, &card->transactions.lock) { + list_for_each_entry_safe(t, tmp, &card->transactions.list, link) { + if (try_cancel_split_timeout(t)) + list_move(&t->link, &pending_list); + } + } + + list_for_each_entry_safe(t, tmp, &pending_list, link) { + list_del(&t->link); + + if (!t->with_tstamp) { + t->callback.without_tstamp(card, RCODE_CANCELLED, NULL, 0, + t->callback_data); + } else { + t->callback.with_tstamp(card, RCODE_CANCELLED, t->packet.timestamp, 0, + NULL, 0, t->callback_data); + } + } +} + // card->transactions.lock must be acquired in advance. #define find_and_pop_transaction_entry(card, condition) \ ({ \ |
