diff options
Diffstat (limited to 'drivers/firewire/core-transaction.c')
-rw-r--r-- | drivers/firewire/core-transaction.c | 96 |
1 files changed, 57 insertions, 39 deletions
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c index 673b03f8b4e..fdc33ff06dc 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 | } |
122 | EXPORT_SYMBOL(fw_cancel_transaction); | 123 | EXPORT_SYMBOL(fw_cancel_transaction); |
123 | 124 | ||
125 | static 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 | |||
124 | static void transmit_complete_callback(struct fw_packet *packet, | 150 | static void transmit_complete_callback(struct fw_packet *packet, |
125 | struct fw_card *card, int status) | 151 | struct fw_card *card, int status) |
126 | { | 152 | { |
@@ -229,6 +255,23 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel, | |||
229 | packet->payload_mapped = false; | 255 | packet->payload_mapped = false; |
230 | } | 256 | } |
231 | 257 | ||
258 | static int allocate_tlabel(struct fw_card *card) | ||
259 | { | ||
260 | int tlabel; | ||
261 | |||
262 | tlabel = card->current_tlabel; | ||
263 | while (card->tlabel_mask & (1ULL << tlabel)) { | ||
264 | tlabel = (tlabel + 1) & 0x3f; | ||
265 | if (tlabel == card->current_tlabel) | ||
266 | return -EBUSY; | ||
267 | } | ||
268 | |||
269 | card->current_tlabel = (tlabel + 1) & 0x3f; | ||
270 | card->tlabel_mask |= 1ULL << tlabel; | ||
271 | |||
272 | return tlabel; | ||
273 | } | ||
274 | |||
232 | /** | 275 | /** |
233 | * This function provides low-level access to the IEEE1394 transaction | 276 | * This function provides low-level access to the IEEE1394 transaction |
234 | * logic. Most C programs would use either fw_read(), fw_write() or | 277 | * logic. Most C programs would use either fw_read(), fw_write() or |
@@ -277,31 +320,26 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode, | |||
277 | int tlabel; | 320 | int tlabel; |
278 | 321 | ||
279 | /* | 322 | /* |
280 | * Bump the flush timer up 100ms first of all so we | ||
281 | * don't race with a flush timer callback. | ||
282 | */ | ||
283 | |||
284 | mod_timer(&card->flush_timer, jiffies + DIV_ROUND_UP(HZ, 10)); | ||
285 | |||
286 | /* | ||
287 | * Allocate tlabel from the bitmap and put the transaction on | 323 | * Allocate tlabel from the bitmap and put the transaction on |
288 | * the list while holding the card spinlock. | 324 | * the list while holding the card spinlock. |
289 | */ | 325 | */ |
290 | 326 | ||
291 | spin_lock_irqsave(&card->lock, flags); | 327 | spin_lock_irqsave(&card->lock, flags); |
292 | 328 | ||
293 | tlabel = card->current_tlabel; | 329 | tlabel = allocate_tlabel(card); |
294 | if (card->tlabel_mask & (1ULL << tlabel)) { | 330 | if (tlabel < 0) { |
295 | spin_unlock_irqrestore(&card->lock, flags); | 331 | spin_unlock_irqrestore(&card->lock, flags); |
296 | callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data); | 332 | callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data); |
297 | return; | 333 | return; |
298 | } | 334 | } |
299 | 335 | ||
300 | card->current_tlabel = (card->current_tlabel + 1) & 0x3f; | ||
301 | card->tlabel_mask |= (1ULL << tlabel); | ||
302 | |||
303 | t->node_id = destination_id; | 336 | t->node_id = destination_id; |
304 | 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)); | ||
305 | t->callback = callback; | 343 | t->callback = callback; |
306 | t->callback_data = callback_data; | 344 | t->callback_data = callback_data; |
307 | 345 | ||
@@ -347,11 +385,13 @@ int fw_run_transaction(struct fw_card *card, int tcode, int destination_id, | |||
347 | struct transaction_callback_data d; | 385 | struct transaction_callback_data d; |
348 | struct fw_transaction t; | 386 | struct fw_transaction t; |
349 | 387 | ||
388 | init_timer_on_stack(&t.split_timeout_timer); | ||
350 | init_completion(&d.done); | 389 | init_completion(&d.done); |
351 | d.payload = payload; | 390 | d.payload = payload; |
352 | fw_send_request(card, &t, tcode, destination_id, generation, speed, | 391 | fw_send_request(card, &t, tcode, destination_id, generation, speed, |
353 | offset, payload, length, transaction_callback, &d); | 392 | offset, payload, length, transaction_callback, &d); |
354 | wait_for_completion(&d.done); | 393 | wait_for_completion(&d.done); |
394 | destroy_timer_on_stack(&t.split_timeout_timer); | ||
355 | 395 | ||
356 | return d.rcode; | 396 | return d.rcode; |
357 | } | 397 | } |
@@ -394,30 +434,6 @@ void fw_send_phy_config(struct fw_card *card, | |||
394 | mutex_unlock(&phy_config_mutex); | 434 | mutex_unlock(&phy_config_mutex); |
395 | } | 435 | } |
396 | 436 | ||
397 | void fw_flush_transactions(struct fw_card *card) | ||
398 | { | ||
399 | struct fw_transaction *t, *next; | ||
400 | struct list_head list; | ||
401 | unsigned long flags; | ||
402 | |||
403 | INIT_LIST_HEAD(&list); | ||
404 | spin_lock_irqsave(&card->lock, flags); | ||
405 | list_splice_init(&card->transaction_list, &list); | ||
406 | card->tlabel_mask = 0; | ||
407 | spin_unlock_irqrestore(&card->lock, flags); | ||
408 | |||
409 | list_for_each_entry_safe(t, next, &list, link) { | ||
410 | card->driver->cancel_packet(card, &t->packet); | ||
411 | |||
412 | /* | ||
413 | * At this point cancel_packet will never call the | ||
414 | * transaction callback, since we just took all the | ||
415 | * transactions out of the list. So do it here. | ||
416 | */ | ||
417 | t->callback(card, RCODE_CANCELLED, NULL, 0, t->callback_data); | ||
418 | } | ||
419 | } | ||
420 | |||
421 | static struct fw_address_handler *lookup_overlapping_address_handler( | 437 | static struct fw_address_handler *lookup_overlapping_address_handler( |
422 | struct list_head *list, unsigned long long offset, size_t length) | 438 | struct list_head *list, unsigned long long offset, size_t length) |
423 | { | 439 | { |
@@ -827,8 +843,8 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) | |||
827 | spin_lock_irqsave(&card->lock, flags); | 843 | spin_lock_irqsave(&card->lock, flags); |
828 | list_for_each_entry(t, &card->transaction_list, link) { | 844 | list_for_each_entry(t, &card->transaction_list, link) { |
829 | if (t->node_id == source && t->tlabel == tlabel) { | 845 | if (t->node_id == source && t->tlabel == tlabel) { |
830 | list_del(&t->link); | 846 | list_del_init(&t->link); |
831 | card->tlabel_mask &= ~(1 << t->tlabel); | 847 | card->tlabel_mask &= ~(1ULL << t->tlabel); |
832 | break; | 848 | break; |
833 | } | 849 | } |
834 | } | 850 | } |
@@ -869,6 +885,8 @@ void fw_core_handle_response(struct fw_card *card, struct fw_packet *p) | |||
869 | break; | 885 | break; |
870 | } | 886 | } |
871 | 887 | ||
888 | del_timer_sync(&t->split_timeout_timer); | ||
889 | |||
872 | /* | 890 | /* |
873 | * The response handler may be executed while the request handler | 891 | * The response handler may be executed while the request handler |
874 | * is still pending. Cancel the request handler. | 892 | * is still pending. Cancel the request handler. |