diff options
Diffstat (limited to 'drivers/firewire/ohci.c')
| -rw-r--r-- | drivers/firewire/ohci.c | 41 | 
1 files changed, 35 insertions, 6 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 5d524254499..94260aa76aa 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -275,7 +275,7 @@ static void log_irqs(u32 evt)  	    !(evt & OHCI1394_busReset))  		return; -	fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt, +	fw_notify("IRQ %08x%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", evt,  	    evt & OHCI1394_selfIDComplete	? " selfID"		: "",  	    evt & OHCI1394_RQPkt		? " AR_req"		: "",  	    evt & OHCI1394_RSPkt		? " AR_resp"		: "", @@ -286,6 +286,7 @@ static void log_irqs(u32 evt)  	    evt & OHCI1394_postedWriteErr	? " postedWriteErr"	: "",  	    evt & OHCI1394_cycleTooLong		? " cycleTooLong"	: "",  	    evt & OHCI1394_cycle64Seconds	? " cycle64Seconds"	: "", +	    evt & OHCI1394_cycleInconsistent	? " cycleInconsistent"	: "",  	    evt & OHCI1394_regAccessFail	? " regAccessFail"	: "",  	    evt & OHCI1394_busReset		? " busReset"		: "",  	    evt & ~(OHCI1394_selfIDComplete | OHCI1394_RQPkt | @@ -293,6 +294,7 @@ static void log_irqs(u32 evt)  		    OHCI1394_respTxComplete | OHCI1394_isochRx |  		    OHCI1394_isochTx | OHCI1394_postedWriteErr |  		    OHCI1394_cycleTooLong | OHCI1394_cycle64Seconds | +		    OHCI1394_cycleInconsistent |  		    OHCI1394_regAccessFail | OHCI1394_busReset)  						? " ?"			: "");  } @@ -1439,6 +1441,17 @@ static irqreturn_t irq_handler(int irq, void *data)  			  OHCI1394_LinkControl_cycleMaster);  	} +	if (unlikely(event & OHCI1394_cycleInconsistent)) { +		/* +		 * We need to clear this event bit in order to make +		 * cycleMatch isochronous I/O work.  In theory we should +		 * stop active cycleMatch iso contexts now and restart +		 * them at least two cycles later.  (FIXME?) +		 */ +		if (printk_ratelimit()) +			fw_notify("isochronous cycle inconsistent\n"); +	} +  	if (event & OHCI1394_cycle64Seconds) {  		cycle_time = reg_read(ohci, OHCI1394_IsochronousCycleTimer);  		if ((cycle_time & 0x80000000) == 0) @@ -1528,6 +1541,7 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)  		  OHCI1394_reqTxComplete | OHCI1394_respTxComplete |  		  OHCI1394_isochRx | OHCI1394_isochTx |  		  OHCI1394_postedWriteErr | OHCI1394_cycleTooLong | +		  OHCI1394_cycleInconsistent |  		  OHCI1394_cycle64Seconds | OHCI1394_regAccessFail |  		  OHCI1394_masterIntEnable);  	if (param_debug & OHCI_PARAM_DEBUG_BUSRESETS) @@ -1890,15 +1904,30 @@ static int handle_it_packet(struct context *context,  {  	struct iso_context *ctx =  		container_of(context, struct iso_context, context); +	int i; +	struct descriptor *pd; -	if (last->transfer_status == 0) -		/* This descriptor isn't done yet, stop iteration. */ +	for (pd = d; pd <= last; pd++) +		if (pd->transfer_status) +			break; +	if (pd > last) +		/* Descriptor(s) not done yet, stop iteration */  		return 0; -	if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) +	i = ctx->header_length; +	if (i + 4 < PAGE_SIZE) { +		/* Present this value as big-endian to match the receive code */ +		*(__be32 *)(ctx->header + i) = cpu_to_be32( +				((u32)le16_to_cpu(pd->transfer_status) << 16) | +				le16_to_cpu(pd->res_count)); +		ctx->header_length += 4; +	} +	if (le16_to_cpu(last->control) & DESCRIPTOR_IRQ_ALWAYS) {  		ctx->base.callback(&ctx->base, le16_to_cpu(last->res_count), -				   0, NULL, ctx->base.callback_data); - +				   ctx->header_length, ctx->header, +				   ctx->base.callback_data); +		ctx->header_length = 0; +	}  	return 1;  }  |