aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/fw-ohci.c
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2007-02-06 14:49:32 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2007-03-09 16:02:51 -0500
commit730c32f58ba81b3a4fe6d19c7d9e9829dd96d363 (patch)
tree79149d002b095ca27582d4d7ef00c8eefec67170 /drivers/firewire/fw-ohci.c
parent72e318e07e1fa9840bfdd5788421fc6dc51a93de (diff)
firewire: Implement proper transaction cancelation.
Drivers such as fw-sbp2 had no way to properly cancel in-progress transactions, which could leave a pending transaction or an unset packet in the low-level queues after kfree'ing the containing structure. fw_cancel_transaction() lets drivers cancel a submitted transaction. Signed-off-by: Kristian Høgsberg <krh@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/fw-ohci.c')
-rw-r--r--drivers/firewire/fw-ohci.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c
index 02b2b69c8741..e6fa3496183e 100644
--- a/drivers/firewire/fw-ohci.c
+++ b/drivers/firewire/fw-ohci.c
@@ -79,6 +79,7 @@ struct at_context {
79 struct fw_ohci *ohci; 79 struct fw_ohci *ohci;
80 dma_addr_t descriptor_bus; 80 dma_addr_t descriptor_bus;
81 dma_addr_t buffer_bus; 81 dma_addr_t buffer_bus;
82 struct fw_packet *current_packet;
82 83
83 struct list_head list; 84 struct list_head list;
84 85
@@ -489,6 +490,7 @@ at_context_setup_packet(struct at_context *ctx, struct list_head *list)
489 ctx->descriptor_bus | z); 490 ctx->descriptor_bus | z);
490 reg_write(ctx->ohci, control_set(ctx->regs), 491 reg_write(ctx->ohci, control_set(ctx->regs),
491 CONTEXT_RUN | CONTEXT_WAKE); 492 CONTEXT_RUN | CONTEXT_WAKE);
493 ctx->current_packet = packet;
492 } else { 494 } else {
493 /* We dont return error codes from this function; all 495 /* We dont return error codes from this function; all
494 * transmission errors are reported through the 496 * transmission errors are reported through the
@@ -524,6 +526,12 @@ static void at_context_tasklet(unsigned long data)
524 526
525 at_context_stop(ctx); 527 at_context_stop(ctx);
526 528
529 /* If the head of the list isn't the packet that just got
530 * transmitted, the packet got cancelled before we finished
531 * transmitting it. */
532 if (ctx->current_packet != packet)
533 goto skip_to_next;
534
527 if (packet->payload_length > 0) { 535 if (packet->payload_length > 0) {
528 dma_unmap_single(ohci->card.device, packet->payload_bus, 536 dma_unmap_single(ohci->card.device, packet->payload_bus,
529 packet->payload_length, DMA_TO_DEVICE); 537 packet->payload_length, DMA_TO_DEVICE);
@@ -564,6 +572,7 @@ static void at_context_tasklet(unsigned long data)
564 } else 572 } else
565 complete_transmission(packet, evt - 16, &list); 573 complete_transmission(packet, evt - 16, &list);
566 574
575 skip_to_next:
567 /* If more packets are queued, set up the next one. */ 576 /* If more packets are queued, set up the next one. */
568 if (!list_empty(&ctx->list)) 577 if (!list_empty(&ctx->list))
569 at_context_setup_packet(ctx, &list); 578 at_context_setup_packet(ctx, &list);
@@ -1012,6 +1021,29 @@ static void ohci_send_response(struct fw_card *card, struct fw_packet *packet)
1012 at_context_transmit(&ohci->at_response_ctx, packet); 1021 at_context_transmit(&ohci->at_response_ctx, packet);
1013} 1022}
1014 1023
1024static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
1025{
1026 struct fw_ohci *ohci = fw_ohci(card);
1027 LIST_HEAD(list);
1028 unsigned long flags;
1029
1030 spin_lock_irqsave(&ohci->lock, flags);
1031
1032 if (packet->ack == 0) {
1033 fw_notify("cancelling packet %p (header[0]=%08x)\n",
1034 packet, packet->header[0]);
1035
1036 complete_transmission(packet, RCODE_CANCELLED, &list);
1037 }
1038
1039 spin_unlock_irqrestore(&ohci->lock, flags);
1040
1041 do_packet_callbacks(ohci, &list);
1042
1043 /* Return success if we actually cancelled something. */
1044 return list_empty(&list) ? -ENOENT : 0;
1045}
1046
1015static int 1047static int
1016ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation) 1048ohci_enable_phys_dma(struct fw_card *card, int node_id, int generation)
1017{ 1049{
@@ -1339,6 +1371,7 @@ static const struct fw_card_driver ohci_driver = {
1339 .set_config_rom = ohci_set_config_rom, 1371 .set_config_rom = ohci_set_config_rom,
1340 .send_request = ohci_send_request, 1372 .send_request = ohci_send_request,
1341 .send_response = ohci_send_response, 1373 .send_response = ohci_send_response,
1374 .cancel_packet = ohci_cancel_packet,
1342 .enable_phys_dma = ohci_enable_phys_dma, 1375 .enable_phys_dma = ohci_enable_phys_dma,
1343 1376
1344 .allocate_iso_context = ohci_allocate_iso_context, 1377 .allocate_iso_context = ohci_allocate_iso_context,