aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2010-12-13 08:56:02 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2011-01-04 02:48:34 -0500
commit410cf2bd3dc6ec1ed9e1b36b25b9d7aa927ed14e (patch)
tree4226510c642e882fde0cc801e626492577b61fd0 /drivers/firewire
parent693a50b511818e07a131efc944cba1a504b63d3d (diff)
firewire: use split transaction timeout only for split transactions
Instead of starting the split transaction timeout timer when any request is submitted, start it only when the destination's ACK_PENDING has been received. This prevents us from using a timeout that is too short, and, if the controller's AT queue is emptying very slowly, from cancelling a packet that has not yet been sent. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire')
-rw-r--r--drivers/firewire/core-transaction.c45
1 files changed, 32 insertions, 13 deletions
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 9e81cc54abd2..d00f8ce902cc 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -72,6 +72,15 @@
72#define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23)) 72#define PHY_CONFIG_ROOT_ID(node_id) ((((node_id) & 0x3f) << 24) | (1 << 23))
73#define PHY_IDENTIFIER(id) ((id) << 30) 73#define PHY_IDENTIFIER(id) ((id) << 30)
74 74
75/* returns 0 if the split timeout handler is already running */
76static int try_cancel_split_timeout(struct fw_transaction *t)
77{
78 if (t->is_split_transaction)
79 return del_timer(&t->split_timeout_timer);
80 else
81 return 1;
82}
83
75static int close_transaction(struct fw_transaction *transaction, 84static int close_transaction(struct fw_transaction *transaction,
76 struct fw_card *card, int rcode) 85 struct fw_card *card, int rcode)
77{ 86{
@@ -81,7 +90,7 @@ static int close_transaction(struct fw_transaction *transaction,
81 spin_lock_irqsave(&card->lock, flags); 90 spin_lock_irqsave(&card->lock, flags);
82 list_for_each_entry(t, &card->transaction_list, link) { 91 list_for_each_entry(t, &card->transaction_list, link) {
83 if (t == transaction) { 92 if (t == transaction) {
84 if (!del_timer(&t->split_timeout_timer)) { 93 if (!try_cancel_split_timeout(t)) {
85 spin_unlock_irqrestore(&card->lock, flags); 94 spin_unlock_irqrestore(&card->lock, flags);
86 goto timed_out; 95 goto timed_out;
87 } 96 }
@@ -141,16 +150,28 @@ static void split_transaction_timeout_callback(unsigned long data)
141 card->tlabel_mask &= ~(1ULL << t->tlabel); 150 card->tlabel_mask &= ~(1ULL << t->tlabel);
142 spin_unlock_irqrestore(&card->lock, flags); 151 spin_unlock_irqrestore(&card->lock, flags);
143 152
144 card->driver->cancel_packet(card, &t->packet);
145
146 /*
147 * At this point cancel_packet will never call the transaction
148 * callback, since we just took the transaction out of the list.
149 * So do it here.
150 */
151 t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); 153 t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data);
152} 154}
153 155
156static void start_split_transaction_timeout(struct fw_transaction *t,
157 struct fw_card *card)
158{
159 unsigned long flags;
160
161 spin_lock_irqsave(&card->lock, flags);
162
163 if (list_empty(&t->link) || WARN_ON(t->is_split_transaction)) {
164 spin_unlock_irqrestore(&card->lock, flags);
165 return;
166 }
167
168 t->is_split_transaction = true;
169 mod_timer(&t->split_timeout_timer,
170 jiffies + card->split_timeout_jiffies);
171
172 spin_unlock_irqrestore(&card->lock, flags);
173}
174
154static void transmit_complete_callback(struct fw_packet *packet, 175static void transmit_complete_callback(struct fw_packet *packet,
155 struct fw_card *card, int status) 176 struct fw_card *card, int status)
156{ 177{
@@ -162,7 +183,7 @@ static void transmit_complete_callback(struct fw_packet *packet,
162 close_transaction(t, card, RCODE_COMPLETE); 183 close_transaction(t, card, RCODE_COMPLETE);
163 break; 184 break;
164 case ACK_PENDING: 185 case ACK_PENDING:
165 t->timestamp = packet->timestamp; 186 start_split_transaction_timeout(t, card);
166 break; 187 break;
167 case ACK_BUSY_X: 188 case ACK_BUSY_X:
168 case ACK_BUSY_A: 189 case ACK_BUSY_A:
@@ -349,11 +370,9 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
349 t->node_id = destination_id; 370 t->node_id = destination_id;
350 t->tlabel = tlabel; 371 t->tlabel = tlabel;
351 t->card = card; 372 t->card = card;
373 t->is_split_transaction = false;
352 setup_timer(&t->split_timeout_timer, 374 setup_timer(&t->split_timeout_timer,
353 split_transaction_timeout_callback, (unsigned long)t); 375 split_transaction_timeout_callback, (unsigned long)t);
354 /* FIXME: start this timer later, relative to t->timestamp */
355 mod_timer(&t->split_timeout_timer,
356 jiffies + card->split_timeout_jiffies);
357 t->callback = callback; 376 t->callback = callback;
358 t->callback_data = callback_data; 377 t->callback_data = callback_data;
359 378
@@ -926,7 +945,7 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p)
926 spin_lock_irqsave(&card->lock, flags); 945 spin_lock_irqsave(&card->lock, flags);
927 list_for_each_entry(t, &card->transaction_list, link) { 946 list_for_each_entry(t, &card->transaction_list, link) {
928 if (t->node_id == source && t->tlabel == tlabel) { 947 if (t->node_id == source && t->tlabel == tlabel) {
929 if (!del_timer(&t->split_timeout_timer)) { 948 if (!try_cancel_split_timeout(t)) {
930 spin_unlock_irqrestore(&card->lock, flags); 949 spin_unlock_irqrestore(&card->lock, flags);
931 goto timed_out; 950 goto timed_out;
932 } 951 }