aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/core-transaction.c
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2010-04-27 03:07:00 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-05-18 18:26:30 -0400
commit5c40cbfefa828208c671e2f58789e4dd04f79563 (patch)
treeaa7c38eb0c9e19ee0153a1764b24c67abaf5746d /drivers/firewire/core-transaction.c
parent753a8970f68594ea69c5fc13fbca18dbd9402996 (diff)
firewire: core: use separate timeout for each transaction
Using a single timeout for all transaction that need to be flushed does not work if the submission of new transactions can defer the timeout indefinitely into the future. We need to have timeouts that do not change due to other transactions; the simplest way to do this is with a separate timer for each transaction. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> (+ one lockdep annotation)
Diffstat (limited to 'drivers/firewire/core-transaction.c')
-rw-r--r--drivers/firewire/core-transaction.c70
1 files changed, 37 insertions, 33 deletions
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 901669876c25..fdc33ff06dc1 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -81,7 +81,7 @@ static int close_transaction(struct fw_transaction *transaction,
81 spin_lock_irqsave(&card->lock, flags); 81 spin_lock_irqsave(&card->lock, flags);
82 list_for_each_entry(t, &card->transaction_list, link) { 82 list_for_each_entry(t, &card->transaction_list, link) {
83 if (t == transaction) { 83 if (t == transaction) {
84 list_del(&t->link); 84 list_del_init(&t->link);
85 card->tlabel_mask &= ~(1ULL << t->tlabel); 85 card->tlabel_mask &= ~(1ULL << t->tlabel);
86 break; 86 break;
87 } 87 }
@@ -89,6 +89,7 @@ static int close_transaction(struct fw_transaction *transaction,
89 spin_unlock_irqrestore(&card->lock, flags); 89 spin_unlock_irqrestore(&card->lock, flags);
90 90
91 if (&t->link != &card->transaction_list) { 91 if (&t->link != &card->transaction_list) {
92 del_timer_sync(&t->split_timeout_timer);
92 t->callback(card, rcode, NULL, 0, t->callback_data); 93 t->callback(card, rcode, NULL, 0, t->callback_data);
93 return 0; 94 return 0;
94 } 95 }
@@ -121,6 +122,31 @@ int fw_cancel_transaction(struct fw_card *card,
121} 122}
122EXPORT_SYMBOL(fw_cancel_transaction); 123EXPORT_SYMBOL(fw_cancel_transaction);
123 124
125static void split_transaction_timeout_callback(unsigned long data)
126{
127 struct fw_transaction *t = (struct fw_transaction *)data;
128 struct fw_card *card = t->card;
129 unsigned long flags;
130
131 spin_lock_irqsave(&card->lock, flags);
132 if (list_empty(&t->link)) {
133 spin_unlock_irqrestore(&card->lock, flags);
134 return;
135 }
136 list_del(&t->link);
137 card->tlabel_mask &= ~(1ULL << t->tlabel);
138 spin_unlock_irqrestore(&card->lock, flags);
139
140 card->driver->cancel_packet(card, &t->packet);
141
142 /*
143 * At this point cancel_packet will never call the transaction
144 * callback, since we just took the transaction out of the list.
145 * So do it here.
146 */
147 t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
148}
149
124static void transmit_complete_callback(struct fw_packet *packet, 150static void transmit_complete_callback(struct fw_packet *packet,
125 struct fw_card *card, int status) 151 struct fw_card *card, int status)
126{ 152{
@@ -294,13 +320,6 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
294 int tlabel; 320 int tlabel;
295 321
296 /* 322 /*
297 * Bump the flush timer up 100ms first of all so we
298 * don't race with a flush timer callback.
299 */
300
301 mod_timer(&card->flush_timer, jiffies + DIV_ROUND_UP(HZ, 10));
302
303 /*
304 * Allocate tlabel from the bitmap and put the transaction on 323 * Allocate tlabel from the bitmap and put the transaction on
305 * the list while holding the card spinlock. 324 * the list while holding the card spinlock.
306 */ 325 */
@@ -316,6 +335,11 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
316 335
317 t->node_id = destination_id; 336 t->node_id = destination_id;
318 t->tlabel = tlabel; 337 t->tlabel = tlabel;
338 t->card = card;
339 setup_timer(&t->split_timeout_timer,
340 split_transaction_timeout_callback, (unsigned long)t);
341 /* FIXME: start this timer later, relative to t->timestamp */
342 mod_timer(&t->split_timeout_timer, jiffies + DIV_ROUND_UP(HZ, 10));
319 t->callback = callback; 343 t->callback = callback;
320 t->callback_data = callback_data; 344 t->callback_data = callback_data;
321 345
@@ -361,11 +385,13 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id,
361 struct transaction_callback_data d; 385 struct transaction_callback_data d;
362 struct fw_transaction t; 386 struct fw_transaction t;
363 387
388 init_timer_on_stack(&t.split_timeout_timer);
364 init_completion(&d.done); 389 init_completion(&d.done);
365 d.payload = payload; 390 d.payload = payload;
366 fw_send_request(card, &t, tcode, destination_id, generation, speed, 391 fw_send_request(card, &t, tcode, destination_id, generation, speed,
367 offset, payload, length, transaction_callback, &d); 392 offset, payload, length, transaction_callback, &d);
368 wait_for_completion(&d.done); 393 wait_for_completion(&d.done);
394 destroy_timer_on_stack(&t.split_timeout_timer);
369 395
370 return d.rcode; 396 return d.rcode;
371} 397}
@@ -408,30 +434,6 @@ void fw_send_phy_config(struct fw_card *card,
408 mutex_unlock(&phy_config_mutex); 434 mutex_unlock(&phy_config_mutex);
409} 435}
410 436
411void fw_flush_transactions(struct fw_card *card)
412{
413 struct fw_transaction *t, *next;
414 struct list_head list;
415 unsigned long flags;
416
417 INIT_LIST_HEAD(&list);
418 spin_lock_irqsave(&card->lock, flags);
419 list_splice_init(&card->transaction_list, &list);
420 card->tlabel_mask = 0;
421 spin_unlock_irqrestore(&card->lock, flags);
422
423 list_for_each_entry_safe(t, next, &list, link) {
424 card->driver->cancel_packet(card, &t->packet);
425
426 /*
427 * At this point cancel_packet will never call the
428 * transaction callback, since we just took all the
429 * transactions out of the list. So do it here.
430 */
431 t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
432 }
433}
434
435static struct fw_address_handler *lookup_overlapping_address_handler( 437static struct fw_address_handler *lookup_overlapping_address_handler(
436 struct list_head *list, unsigned long long offset, size_t length) 438 struct list_head *list, unsigned long long offset, size_t length)
437{ 439{
@@ -841,7 +843,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
841 spin_lock_irqsave(&card->lock, flags); 843 spin_lock_irqsave(&card->lock, flags);
842 list_for_each_entry(t, &card->transaction_list, link) { 844 list_for_each_entry(t, &card->transaction_list, link) {
843 if (t->node_id == source && t->tlabel == tlabel) { 845 if (t->node_id == source && t->tlabel == tlabel) {
844 list_del(&t->link); 846 list_del_init(&t->link);
845 card->tlabel_mask &= ~(1ULL << t->tlabel); 847 card->tlabel_mask &= ~(1ULL << t->tlabel);
846 break; 848 break;
847 } 849 }
@@ -883,6 +885,8 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
883 break; 885 break;
884 } 886 }
885 887
888 del_timer_sync(&t->split_timeout_timer);
889
886 /* 890 /*
887 * The response handler may be executed while the request handler 891 * The response handler may be executed while the request handler
888 * is still pending. Cancel the request handler. 892 * is still pending. Cancel the request handler.