summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/firewire/core-card.c1
-rw-r--r--drivers/firewire/core-transaction.c28
-rw-r--r--drivers/firewire/core.h2
-rw-r--r--drivers/firewire/ohci.c5
4 files changed, 31 insertions, 5 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 65bd9db996c0..9869ea3fd9fc 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -790,6 +790,7 @@ void fw_core_remove_card(struct fw_card *card)
drain_workqueue(card->isoc_wq);
drain_workqueue(card->async_wq);
card->driver->disable(card);
+ fw_cancel_pending_transactions(card);
scoped_guard(spinlock_irqsave, &card->lock)
fw_destroy_nodes(card);
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) \
({ \
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 903812b6bb3f..41fb39d9a4e6 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -287,6 +287,8 @@ void fw_fill_response(struct fw_packet *response, u32 *request_header,
void fw_request_get(struct fw_request *request);
void fw_request_put(struct fw_request *request);
+void fw_cancel_pending_transactions(struct fw_card *card);
+
// Convert the value of IEEE 1394 CYCLE_TIME register to the format of timeStamp field in
// descriptors of 1394 OHCI.
static inline u32 cycle_time_to_ohci_tstamp(u32 tstamp)
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index 0625d11dbd74..e3e78dc42530 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -3719,11 +3719,6 @@ static void pci_remove(struct pci_dev *dev)
fw_core_remove_card(&ohci->card);
- /*
- * FIXME: Fail all pending packets here, now that the upper
- * layers can't queue any more.
- */
-
software_reset(ohci);
irq = pci_irq_vector(dev, 0);