aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/fw-transaction.c
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2007-02-06 14:49:32 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-03-09 16:02:51 -0500
commit730c32f58ba81b3a4fe6d19c7d9e9829dd96d363 (patch)
tree79149d002b095ca27582d4d7ef00c8eefec67170 /drivers/firewire/fw-transaction.c
parent72e318e07e1fa9840bfdd5788421fc6dc51a93de (diff)
firewire: Implement proper transaction cancelation.
Drivers such as fw-sbp2 had no way to properly cancel in-progress transactions, which could leave a pending transaction or an unset packet in the low-level queues after kfree'ing the containing structure. fw_cancel_transaction() lets drivers cancel a submitted transaction. Signed-off-by: Kristian Høgsberg <krh@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/fw-transaction.c')
-rw-r--r--drivers/firewire/fw-transaction.c54
1 files changed, 47 insertions, 7 deletions
diff --git a/drivers/firewire/fw-transaction.c b/drivers/firewire/fw-transaction.c
index fb3b77e1bb2d..5394569a1c89 100644
--- a/drivers/firewire/fw-transaction.c
+++ b/drivers/firewire/fw-transaction.c
@@ -59,20 +59,52 @@
59#define phy_config_root_id(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) 59#define phy_config_root_id(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23))
60#define phy_identifier(id) ((id) << 30) 60#define phy_identifier(id) ((id) << 30)
61 61
62static void 62static int
63close_transaction(struct fw_transaction *t, struct fw_card *card, int rcode, 63close_transaction(struct fw_transaction *transaction,
64 u32 * payload, size_t length) 64 struct fw_card *card, int rcode,
65 u32 *payload, size_t length)
65{ 66{
67 struct fw_transaction *t;
66 unsigned long flags; 68 unsigned long flags;
67 69
68 spin_lock_irqsave(&card->lock, flags); 70 spin_lock_irqsave(&card->lock, flags);
69 card->tlabel_mask &= ~(1 << t->tlabel); 71 list_for_each_entry(t, &card->transaction_list, link) {
70 list_del(&t->link); 72 if (t == transaction) {
73 list_del(&t->link);
74 card->tlabel_mask &= ~(1 << t->tlabel);
75 break;
76 }
77 }
71 spin_unlock_irqrestore(&card->lock, flags); 78 spin_unlock_irqrestore(&card->lock, flags);
72 79
73 t->callback(card, rcode, payload, length, t->callback_data); 80 if (&t->link != &card->transaction_list) {
81 t->callback(card, rcode, payload, length, t->callback_data);
82 return 0;
83 }
84
85 return -ENOENT;
74} 86}
75 87
88/* Only valid for transactions that are potentially pending (ie have
89 * been sent). */
90int
91fw_cancel_transaction(struct fw_card *card,
92 struct fw_transaction *transaction)
93{
94 /* Cancel the packet transmission if it's still queued. That
95 * will call the packet transmission callback which cancels
96 * the transaction. */
97
98 if (card->driver->cancel_packet(card, &transaction->packet) == 0)
99 return 0;
100
101 /* If the request packet has already been sent, we need to see
102 * if the transaction is still pending and remove it in that case. */
103
104 return close_transaction(transaction, card, RCODE_CANCELLED, NULL, 0);
105}
106EXPORT_SYMBOL(fw_cancel_transaction);
107
76static void 108static void
77transmit_complete_callback(struct fw_packet *packet, 109transmit_complete_callback(struct fw_packet *packet,
78 struct fw_card *card, int status) 110 struct fw_card *card, int status)
@@ -162,6 +194,7 @@ fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
162 194
163 packet->speed = speed; 195 packet->speed = speed;
164 packet->generation = generation; 196 packet->generation = generation;
197 packet->ack = 0;
165} 198}
166 199
167/** 200/**
@@ -298,8 +331,14 @@ void fw_flush_transactions(struct fw_card *card)
298 card->tlabel_mask = 0; 331 card->tlabel_mask = 0;
299 spin_unlock_irqrestore(&card->lock, flags); 332 spin_unlock_irqrestore(&card->lock, flags);
300 333
301 list_for_each_entry_safe(t, next, &list, link) 334 list_for_each_entry_safe(t, next, &list, link) {
335 card->driver->cancel_packet(card, &t->packet);
336
337 /* At this point cancel_packet will never call the
338 * transaction callback, since we just took all the
339 * transactions out of the list. So do it here.*/
302 t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); 340 t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
341 }
303} 342}
304 343
305static struct fw_address_handler * 344static struct fw_address_handler *
@@ -531,6 +570,7 @@ allocate_request(struct fw_packet *p)
531 request->response.speed = p->speed; 570 request->response.speed = p->speed;
532 request->response.timestamp = t; 571 request->response.timestamp = t;
533 request->response.generation = p->generation; 572 request->response.generation = p->generation;
573 request->response.ack = 0;
534 request->response.callback = free_response_callback; 574 request->response.callback = free_response_callback;
535 request->ack = p->ack; 575 request->ack = p->ack;
536 request->length = length; 576 request->length = length;