| From 0c0efbacab8d70700d13301e0ae7975783c0cb0a Mon Sep 17 00:00:00 2001 |
| From: Clemens Ladisch <clemens@ladisch.de> |
| Date: Mon, 12 Mar 2012 21:45:47 +0100 |
| Subject: firewire: ohci: fix too-early completion of IR multichannel buffers |
| |
| From: Clemens Ladisch <clemens@ladisch.de> |
| |
| commit 0c0efbacab8d70700d13301e0ae7975783c0cb0a upstream. |
| |
| handle_ir_buffer_fill() assumed that a completed descriptor would be |
| indicated by a non-zero transfer_status (as in most other descriptors). |
| However, this field is written by the controller as soon as (the end of) |
| the first packet has been written into the buffer. As a consequence, if |
| we happen to run into such a descriptor when the interrupt handler is |
| executed after such a packet has completed, the descriptor would be |
| taken out of the list of active descriptors as soon as the buffer had |
| been partially filled, so the event for the buffer being completely |
| filled would never be sent. |
| |
| To fix this, handle descriptors only when they have been completely |
| filled, i.e., when res_count == 0. (This also matches the condition |
| that is reported by the controller with an interrupt.) |
| |
| Signed-off-by: Clemens Ladisch <clemens@ladisch.de> |
| Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/firewire/ohci.c | 5 ++--- |
| 1 file changed, 2 insertions(+), 3 deletions(-) |
| |
| --- a/drivers/firewire/ohci.c |
| +++ b/drivers/firewire/ohci.c |
| @@ -2748,7 +2748,7 @@ static int handle_ir_buffer_fill(struct |
| container_of(context, struct iso_context, context); |
| u32 buffer_dma; |
| |
| - if (!last->transfer_status) |
| + if (last->res_count != 0) |
| /* Descriptor(s) not done yet, stop iteration */ |
| return 0; |
| |
| @@ -2762,8 +2762,7 @@ static int handle_ir_buffer_fill(struct |
| if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) |
| ctx->base.callback.mc(&ctx->base, |
| le32_to_cpu(last->data_address) + |
| - le16_to_cpu(last->req_count) - |
| - le16_to_cpu(last->res_count), |
| + le16_to_cpu(last->req_count), |
| ctx->base.callback_data); |
| |
| return 1; |