diff options
Diffstat (limited to 'drivers/firewire/core-transaction.c')
-rw-r--r-- | drivers/firewire/core-transaction.c | 70 |
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, spin_lock_irqsave(&card->lock, flags); list_for_each_entry(t, &card->transaction_list, link) { if (t == transaction) { - list_del(&t->link); + list_del_init(&t->link); card->tlabel_mask &= ~(1ULL << t->tlabel); break; } @@ -89,6 +89,7 @@ static int close_transaction(struct fw_transaction *transaction, spin_unlock_irqrestore(&card->lock, flags); if (&t->link != &card->transaction_list) { + del_timer_sync(&t->split_timeout_timer); t->callback(card, rcode, NULL, 0, t->callback_data); return 0; } @@ -121,6 +122,31 @@ int fw_cancel_transaction(struct fw_card *card, } EXPORT_SYMBOL(fw_cancel_transaction); +static void split_transaction_timeout_callback(unsigned long data) +{ + struct fw_transaction *t = (struct fw_transaction *)data; + struct fw_card *card = t->card; + unsigned long flags; + + spin_lock_irqsave(&card->lock, flags); + if (list_empty(&t->link)) { + spin_unlock_irqrestore(&card->lock, flags); + return; + } + list_del(&t->link); + card->tlabel_mask &= ~(1ULL << t->tlabel); + spin_unlock_irqrestore(&card->lock, flags); + + card->driver->cancel_packet(card, &t->packet); + + /* + * At this point cancel_packet will never call the transaction + * callback, since we just took the transaction out of the list. + * So do it here. + */ + t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); +} + static void transmit_complete_callback(struct fw_packet *packet, struct fw_card *card, int status) { @@ -294,13 +320,6 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, int tlabel; /* - * Bump the flush timer up 100ms first of all so we - * don't race with a flush timer callback. - */ - - mod_timer(&card->flush_timer, jiffies + DIV_ROUND_UP(HZ, 10)); - - /* * Allocate tlabel from the bitmap and put the transaction on * the list while holding the card spinlock. */ @@ -316,6 +335,11 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, t->node_id = destination_id; t->tlabel = tlabel; + t->card = card; + setup_timer(&t->split_timeout_timer, + split_transaction_timeout_callback, (unsigned long)t); + /* FIXME: start this timer later, relative to t->timestamp */ + mod_timer(&t->split_timeout_timer, jiffies + DIV_ROUND_UP(HZ, 10)); t->callback = callback; t->callback_data = callback_data; @@ -361,11 +385,13 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, struct transaction_callback_data d; struct fw_transaction t; + init_timer_on_stack(&t.split_timeout_timer); init_completion(&d.done); d.payload = payload; fw_send_request(card, &t, tcode, destination_id, generation, speed, offset, payload, length, transaction_callback, &d); wait_for_completion(&d.done); + destroy_timer_on_stack(&t.split_timeout_timer); return d.rcode; } @@ -408,30 +434,6 @@ void fw_send_phy_config(struct fw_card *card, mutex_unlock(&phy_config_mutex); } -void fw_flush_transactions(struct fw_card *card) -{ - struct fw_transaction *t, *next; - struct list_head list; - unsigned long flags; - - INIT_LIST_HEAD(&list); - spin_lock_irqsave(&card->lock, flags); - list_splice_init(&card->transaction_list, &list); - card->tlabel_mask = 0; - spin_unlock_irqrestore(&card->lock, flags); - - list_for_each_entry_safe(t, next, &list, link) { - card->driver->cancel_packet(card, &t->packet); - - /* - * At this point cancel_packet will never call the - * transaction callback, since we just took all the - * transactions out of the list. So do it here. - */ - t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); - } -} - static struct fw_address_handler *lookup_overlapping_address_handler( struct list_head *list, unsigned long long offset, size_t length) { @@ -841,7 +843,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) spin_lock_irqsave(&card->lock, flags); list_for_each_entry(t, &card->transaction_list, link) { if (t->node_id == source && t->tlabel == tlabel) { - list_del(&t->link); + list_del_init(&t->link); card->tlabel_mask &= ~(1ULL << t->tlabel); break; } @@ -883,6 +885,8 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) break; } + del_timer_sync(&t->split_timeout_timer); + /* * The response handler may be executed while the request handler * is still pending. Cancel the request handler. |