aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
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
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')
-rw-r--r--drivers/firewire/core-card.c11
-rw-r--r--drivers/firewire/core-transaction.c70
-rw-r--r--drivers/firewire/core.h1
3 files changed, 37 insertions, 45 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c
index 42cf911b73cf..9dcb30466ec0 100644
--- a/drivers/firewire/core-card.c
+++ b/drivers/firewire/core-card.c
@@ -30,7 +30,6 @@
30#include <linux/module.h> 30#include <linux/module.h>
31#include <linux/mutex.h> 31#include <linux/mutex.h>
32#include <linux/spinlock.h> 32#include <linux/spinlock.h>
33#include <linux/timer.h>
34#include <linux/workqueue.h> 33#include <linux/workqueue.h>
35 34
36#include <asm/atomic.h> 35#include <asm/atomic.h>
@@ -408,13 +407,6 @@ static void fw_card_bm_work(struct work_struct *work)
408 fw_card_put(card); 407 fw_card_put(card);
409} 408}
410 409
411static void flush_timer_callback(unsigned long data)
412{
413 struct fw_card *card = (struct fw_card *)data;
414
415 fw_flush_transactions(card);
416}
417
418void fw_card_initialize(struct fw_card *card, 410void fw_card_initialize(struct fw_card *card,
419 const struct fw_card_driver *driver, 411 const struct fw_card_driver *driver,
420 struct device *device) 412 struct device *device)
@@ -433,8 +425,6 @@ void fw_card_initialize(struct fw_card *card,
433 init_completion(&card->done); 425 init_completion(&card->done);
434 INIT_LIST_HEAD(&card->transaction_list); 426 INIT_LIST_HEAD(&card->transaction_list);
435 spin_lock_init(&card->lock); 427 spin_lock_init(&card->lock);
436 setup_timer(&card->flush_timer,
437 flush_timer_callback, (unsigned long)card);
438 428
439 card->local_node = NULL; 429 card->local_node = NULL;
440 430
@@ -559,7 +549,6 @@ void fw_core_remove_card(struct fw_card *card)
559 wait_for_completion(&card->done); 549 wait_for_completion(&card->done);
560 550
561 WARN_ON(!list_empty(&card->transaction_list)); 551 WARN_ON(!list_empty(&card->transaction_list));
562 del_timer_sync(&card->flush_timer);
563} 552}
564EXPORT_SYMBOL(fw_core_remove_card); 553EXPORT_SYMBOL(fw_core_remove_card);
565 554
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.
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index 7a9759bf6837..0ecfcd95f4c5 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -220,7 +220,6 @@ void fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
220void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); 220void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
221void fw_fill_response(struct fw_packet *response, u32 *request_header, 221void fw_fill_response(struct fw_packet *response, u32 *request_header,
222 int rcode, void *payload, size_t length); 222 int rcode, void *payload, size_t length);
223void fw_flush_transactions(struct fw_card *card);
224void fw_send_phy_config(struct fw_card *card, 223void fw_send_phy_config(struct fw_card *card,
225 int node_id, int generation, int gap_count); 224 int node_id, int generation, int gap_count);
226 225