aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/core-transaction.c
diff options
context:
space:
mode:
authorClemens Ladisch <clemens@ladisch.de>2010-04-19 11:29:14 -0400
committerStefan Richter <stefanr@s5r6.in-berlin.de>2010-04-19 14:00:44 -0400
commit7906054f0d597246178b3154adca76de29913aa5 (patch)
tree0645ad88ab8ad5cd98ce3cef95655ccc5bca0ef8 /drivers/firewire/core-transaction.c
parentedd5bdaf128e04066caac84fcb21377197ea0d64 (diff)
firewire: core: make transaction label allocation more robust
If one request is so long-lived that it does not get a response before the following 63 requests, its bit in tlabel_mask is still set when the next request tries to allocate a transaction label for that number. In this state, while the first request is not completed or timed out, no new requests can be submitted. To fix this, skip over any label still in use, and do not error out unless we have entirely run out of labels. Signed-off-by: Clemens Ladisch <clemens@ladisch.de> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/core-transaction.c')
-rw-r--r--drivers/firewire/core-transaction.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index 673b03f8b4ec..9882240205cd 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -229,6 +229,23 @@ static void fw_fill_request(struct fw_packet *packet, int tcode, int tlabel,
229 packet->payload_mapped = false; 229 packet->payload_mapped = false;
230} 230}
231 231
232static int allocate_tlabel(struct fw_card *card)
233{
234 int tlabel;
235
236 tlabel = card->current_tlabel;
237 while (card->tlabel_mask & (1ULL << tlabel)) {
238 tlabel = (tlabel + 1) & 0x3f;
239 if (tlabel == card->current_tlabel)
240 return -EBUSY;
241 }
242
243 card->current_tlabel = (tlabel + 1) & 0x3f;
244 card->tlabel_mask |= 1ULL << tlabel;
245
246 return tlabel;
247}
248
232/** 249/**
233 * This function provides low-level access to the IEEE1394 transaction 250 * This function provides low-level access to the IEEE1394 transaction
234 * logic. Most C programs would use either fw_read(), fw_write() or 251 * logic. Most C programs would use either fw_read(), fw_write() or
@@ -290,16 +307,13 @@ void fw_send_request(struct fw_card *card, struct fw_transaction *t, int tcode,
290 307
291 spin_lock_irqsave(&card->lock, flags); 308 spin_lock_irqsave(&card->lock, flags);
292 309
293 tlabel = card->current_tlabel; 310 tlabel = allocate_tlabel(card);
294 if (card->tlabel_mask & (1ULL << tlabel)) { 311 if (tlabel < 0) {
295 spin_unlock_irqrestore(&card->lock, flags); 312 spin_unlock_irqrestore(&card->lock, flags);
296 callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data); 313 callback(card, RCODE_SEND_ERROR, NULL, 0, callback_data);
297 return; 314 return;
298 } 315 }
299 316
300 card->current_tlabel = (card->current_tlabel + 1) & 0x3f;
301 card->tlabel_mask |= (1ULL << tlabel);
302
303 t->node_id = destination_id; 317 t->node_id = destination_id;
304 t->tlabel = tlabel; 318 t->tlabel = tlabel;
305 t->callback = callback; 319 t->callback = callback;