diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-12-16 20:34:23 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-12-18 09:13:38 -0800 |
commit | bc7c91468b80aab044dd9dd61c3492cf57dffabb (patch) | |
tree | 2221285ea974838f2a26705ee293da9c3a8bec07 /drivers/firewire/fw-ohci.c | |
parent | 123cd635a810bea55c41f09c09e4d6dc1f493876 (diff) |
firewire: fw-ohci: fix IOMMU resource exhaustion
commit 1d1dc5e83f3299c108a4e44d58cc4bfef48c876a upstream.
There is a DMA map/ unmap imbalance whenever a block write request
packet is sent and then dequeued with ohci_cancel_packet. The latter
may happen frequently if the AR resp tasklet is executed before the AT
req tasklet for the same transaction.
Add the missing dma_unmap_single. This fixes
https://bugzilla.redhat.com/show_bug.cgi?id=475156
Reported-by: Emmanuel Kowalski
Tested-by: Emmanuel Kowalski
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/firewire/fw-ohci.c')
-rw-r--r-- | drivers/firewire/fw-ohci.c | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/drivers/firewire/fw-ohci.c b/drivers/firewire/fw-ohci.c index 251416f2148f..595759c97f52 100644 --- a/drivers/firewire/fw-ohci.c +++ b/drivers/firewire/fw-ohci.c @@ -958,6 +958,7 @@ at_context_queue_packet(struct context *ctx, struct fw_packet *packet) packet->ack = RCODE_SEND_ERROR; return -1; } + packet->payload_bus = payload_bus; d[2].req_count = cpu_to_le16(packet->payload_length); d[2].data_address = cpu_to_le32(payload_bus); @@ -1009,7 +1010,6 @@ static int handle_at_packet(struct context *context, struct driver_data *driver_data; struct fw_packet *packet; struct fw_ohci *ohci = context->ohci; - dma_addr_t payload_bus; int evt; if (last->transfer_status == 0) @@ -1022,9 +1022,8 @@ static int handle_at_packet(struct context *context, /* This packet was cancelled, just continue. */ return 1; - payload_bus = le32_to_cpu(last->data_address); - if (payload_bus != 0) - dma_unmap_single(ohci->card.device, payload_bus, + if (packet->payload_bus) + dma_unmap_single(ohci->card.device, packet->payload_bus, packet->payload_length, DMA_TO_DEVICE); evt = le16_to_cpu(last->transfer_status) & 0x1f; @@ -1681,6 +1680,10 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet) if (packet->ack != 0) goto out; + if (packet->payload_bus) + dma_unmap_single(ohci->card.device, packet->payload_bus, + packet->payload_length, DMA_TO_DEVICE); + log_ar_at_event('T', packet->speed, packet->header, 0x20); driver_data->packet = NULL; packet->ack = RCODE_CANCELLED; |