Skip to content

Commit

Permalink
firewire: ohci: flush AT contexts after bus reset for OHCI 1.2
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Clemens Ladisch authored and Stefan Richter committed Jan 3, 2011
1 parent c167147 commit 82b662d
Showing 1 changed file with 39 additions and 7 deletions.
46 changes: 39 additions & 7 deletions drivers/firewire/ohci.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ struct context {
struct fw_ohci *ohci;
u32 regs;
int total_allocation;
bool flushing;

/*
* List of page-sized buffers for storing DMA descriptors.
Expand Down Expand Up @@ -1356,6 +1357,17 @@ static int at_context_queue_packet(struct context *ctx,
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,
struct descriptor *d,
struct descriptor *last)
Expand All @@ -1365,7 +1377,7 @@ static int handle_at_packet(struct context *context,
struct fw_ohci *ohci = context->ohci;
int evt;

if (last->transfer_status == 0)
if (last->transfer_status == 0 && !context->flushing)
/* This descriptor isn't done yet, stop iteration. */
return 0;

Expand Down Expand Up @@ -1399,11 +1411,15 @@ static int handle_at_packet(struct context *context,
break;

case OHCI1394_evt_missing_ack:
/*
* Using a valid (current) generation count, but the
* node is not on the bus or not sending acks.
*/
packet->ack = RCODE_NO_ACK;
if (context->flushing)
packet->ack = RCODE_GENERATION;
else {
/*
* Using a valid (current) generation count, but the
* node is not on the bus or not sending acks.
*/
packet->ack = RCODE_NO_ACK;
}
break;

case ACK_COMPLETE + 0x10:
Expand All @@ -1416,6 +1432,13 @@ static int handle_at_packet(struct context *context,
packet->ack = evt - 0x10;
break;

case OHCI1394_evt_no_status:
if (context->flushing) {
packet->ack = RCODE_GENERATION;
break;
}
/* fall through */

default:
packet->ack = RCODE_SEND_ERROR;
break;
Expand Down Expand Up @@ -1721,9 +1744,18 @@ static void bus_reset_tasklet(unsigned long data)
/* FIXME: Document how the locking works. */
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_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);

if (ohci->quirks & QUIRK_RESET_PACKET)
Expand Down

0 comments on commit 82b662d

Please sign in to comment.