dect
/
linux-2.6
Archived
13
0
Fork 0

firewire: ohci: flush AT contexts after bus reset for OHCI 1.2

The OHCI 1.2 (draft) specification, clause 7.2.3.3, allows and
recommends that, after a bus reset, the controller does not flush all
the packets in the AT queues.  Therefore, the driver has to do this
itself.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
This commit is contained in:
Clemens Ladisch 2010-12-24 14:40:15 +01:00 committed by Stefan Richter
parent c16714704b
commit 82b662dc41
1 changed files with 39 additions and 7 deletions

View File

@ -125,6 +125,7 @@ struct context {
struct fw_ohci *ohci; struct fw_ohci *ohci;
u32 regs; u32 regs;
int total_allocation; int total_allocation;
bool flushing;
/* /*
* List of page-sized buffers for storing DMA descriptors. * List of page-sized buffers for storing DMA descriptors.
@ -1356,6 +1357,17 @@ static int at_context_queue_packet(struct context *ctx,
return 0; return 0;
} }
static void at_context_flush(struct context *ctx)
{
tasklet_disable(&ctx->tasklet);
ctx->flushing = true;
context_tasklet((unsigned long)ctx);
ctx->flushing = false;
tasklet_enable(&ctx->tasklet);
}
static int handle_at_packet(struct context *context, static int handle_at_packet(struct context *context,
struct descriptor *d, struct descriptor *d,
struct descriptor *last) struct descriptor *last)
@ -1365,7 +1377,7 @@ static int handle_at_packet(struct context *context,
struct fw_ohci *ohci = context->ohci; struct fw_ohci *ohci = context->ohci;
int evt; int evt;
if (last->transfer_status == 0) if (last->transfer_status == 0 && !context->flushing)
/* This descriptor isn't done yet, stop iteration. */ /* This descriptor isn't done yet, stop iteration. */
return 0; return 0;
@ -1399,11 +1411,15 @@ static int handle_at_packet(struct context *context,
break; break;
case OHCI1394_evt_missing_ack: case OHCI1394_evt_missing_ack:
/* if (context->flushing)
* Using a valid (current) generation count, but the packet->ack = RCODE_GENERATION;
* node is not on the bus or not sending acks. else {
*/ /*
packet->ack = RCODE_NO_ACK; * Using a valid (current) generation count, but the
* node is not on the bus or not sending acks.
*/
packet->ack = RCODE_NO_ACK;
}
break; break;
case ACK_COMPLETE + 0x10: case ACK_COMPLETE + 0x10:
@ -1416,6 +1432,13 @@ static int handle_at_packet(struct context *context,
packet->ack = evt - 0x10; packet->ack = evt - 0x10;
break; break;
case OHCI1394_evt_no_status:
if (context->flushing) {
packet->ack = RCODE_GENERATION;
break;
}
/* fall through */
default: default:
packet->ack = RCODE_SEND_ERROR; packet->ack = RCODE_SEND_ERROR;
break; break;
@ -1721,9 +1744,18 @@ static void bus_reset_tasklet(unsigned long data)
/* FIXME: Document how the locking works. */ /* FIXME: Document how the locking works. */
spin_lock_irqsave(&ohci->lock, flags); spin_lock_irqsave(&ohci->lock, flags);
ohci->generation = generation; ohci->generation = -1; /* prevent AT packet queueing */
context_stop(&ohci->at_request_ctx); context_stop(&ohci->at_request_ctx);
context_stop(&ohci->at_response_ctx); context_stop(&ohci->at_response_ctx);
spin_unlock_irqrestore(&ohci->lock, flags);
at_context_flush(&ohci->at_request_ctx);
at_context_flush(&ohci->at_response_ctx);
spin_lock_irqsave(&ohci->lock, flags);
ohci->generation = generation;
reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset); reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
if (ohci->quirks & QUIRK_RESET_PACKET) if (ohci->quirks & QUIRK_RESET_PACKET)