diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2010-12-13 08:56:02 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2011-01-04 02:48:34 -0500 |
commit | 410cf2bd3dc6ec1ed9e1b36b25b9d7aa927ed14e (patch) | |
tree | 4226510c642e882fde0cc801e626492577b61fd0 | |
parent | 693a50b511818e07a131efc944cba1a504b63d3d (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>
-rw-r--r-- | drivers/firewire/core-transaction.c | 45 | ||||
-rw-r--r-- | include/linux/firewire.h | 2 |
2 files changed, 33 insertions, 14 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 */ | ||
76 | static 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 | |||
75 | static int close_transaction(struct fw_transaction *transaction, | 84 | static 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 | ||
156 | static 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 | |||
154 | static void transmit_complete_callback(struct fw_packet *packet, | 175 | static 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 | } |
diff --git a/include/linux/firewire.h b/include/linux/firewire.h index 1cd637ef62d2..9a3f5f9383f6 100644 --- a/include/linux/firewire.h +++ b/include/linux/firewire.h | |||
@@ -302,9 +302,9 @@ struct fw_packet { | |||
302 | struct fw_transaction { | 302 | struct fw_transaction { |
303 | int node_id; /* The generation is implied; it is always the current. */ | 303 | int node_id; /* The generation is implied; it is always the current. */ |
304 | int tlabel; | 304 | int tlabel; |
305 | int timestamp; | ||
306 | struct list_head link; | 305 | struct list_head link; |
307 | struct fw_card *card; | 306 | struct fw_card *card; |
307 | bool is_split_transaction; | ||
308 | struct timer_list split_timeout_timer; | 308 | struct timer_list split_timeout_timer; |
309 | 309 | ||
310 | struct fw_packet packet; | 310 | struct fw_packet packet; |