diff options
Diffstat (limited to 'drivers/firewire/ohci.c')
| -rw-r--r-- | drivers/firewire/ohci.c | 80 | 
1 files changed, 59 insertions, 21 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 5d524254499..ae4556f0c0c 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -205,7 +205,7 @@ struct fw_ohci {  	dma_addr_t config_rom_bus;  	__be32 *next_config_rom;  	dma_addr_t next_config_rom_bus; -	u32 next_header; +	__be32 next_header;  	struct ar_context ar_request_ctx;  	struct ar_context ar_response_ctx; @@ -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)  						? " ?"			: "");  } @@ -995,7 +997,8 @@ static int at_context_queue_packet(struct context *ctx,  			packet->ack = RCODE_SEND_ERROR;  			return -1;  		} -		packet->payload_bus = payload_bus; +		packet->payload_bus	= payload_bus; +		packet->payload_mapped	= true;  		d[2].req_count    = cpu_to_le16(packet->payload_length);  		d[2].data_address = cpu_to_le32(payload_bus); @@ -1023,7 +1026,7 @@ static int at_context_queue_packet(struct context *ctx,  	 */  	if (ohci->generation != packet->generation ||  	    reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) { -		if (packet->payload_length > 0) +		if (packet->payload_mapped)  			dma_unmap_single(ohci->card.device, payload_bus,  					 packet->payload_length, DMA_TO_DEVICE);  		packet->ack = RCODE_GENERATION; @@ -1059,7 +1062,7 @@ static int handle_at_packet(struct context *context,  		/* This packet was cancelled, just continue. */  		return 1; -	if (packet->payload_bus) +	if (packet->payload_mapped)  		dma_unmap_single(ohci->card.device, packet->payload_bus,  				 packet->payload_length, DMA_TO_DEVICE); @@ -1355,8 +1358,9 @@ static void bus_reset_tasklet(unsigned long data)  		 */  		reg_write(ohci, OHCI1394_BusOptions,  			  be32_to_cpu(ohci->config_rom[2])); -		ohci->config_rom[0] = cpu_to_be32(ohci->next_header); -		reg_write(ohci, OHCI1394_ConfigROMhdr, ohci->next_header); +		ohci->config_rom[0] = ohci->next_header; +		reg_write(ohci, OHCI1394_ConfigROMhdr, +			  be32_to_cpu(ohci->next_header));  	}  #ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA @@ -1439,6 +1443,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) @@ -1464,7 +1479,17 @@ static int software_reset(struct fw_ohci *ohci)  	return -EBUSY;  } -static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length) +static void copy_config_rom(__be32 *dest, const __be32 *src, size_t length) +{ +	size_t size = length * 4; + +	memcpy(dest, src, size); +	if (size < CONFIG_ROM_SIZE) +		memset(&dest[length], 0, CONFIG_ROM_SIZE - size); +} + +static int ohci_enable(struct fw_card *card, +		       const __be32 *config_rom, size_t length)  {  	struct fw_ohci *ohci = fw_ohci(card);  	struct pci_dev *dev = to_pci_dev(card->device); @@ -1528,6 +1553,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) @@ -1565,8 +1591,7 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)  		if (ohci->next_config_rom == NULL)  			return -ENOMEM; -		memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE); -		fw_memcpy_to_be32(ohci->next_config_rom, config_rom, length * 4); +		copy_config_rom(ohci->next_config_rom, config_rom, length);  	} else {  		/*  		 * In the suspend case, config_rom is NULL, which @@ -1576,7 +1601,7 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)  		ohci->next_config_rom_bus = ohci->config_rom_bus;  	} -	ohci->next_header = be32_to_cpu(ohci->next_config_rom[0]); +	ohci->next_header = ohci->next_config_rom[0];  	ohci->next_config_rom[0] = 0;  	reg_write(ohci, OHCI1394_ConfigROMhdr, 0);  	reg_write(ohci, OHCI1394_BusOptions, @@ -1610,7 +1635,7 @@ static int ohci_enable(struct fw_card *card, u32 *config_rom, size_t length)  }  static int ohci_set_config_rom(struct fw_card *card, -			       u32 *config_rom, size_t length) +			       const __be32 *config_rom, size_t length)  {  	struct fw_ohci *ohci;  	unsigned long flags; @@ -1659,9 +1684,7 @@ static int ohci_set_config_rom(struct fw_card *card,  		ohci->next_config_rom = next_config_rom;  		ohci->next_config_rom_bus = next_config_rom_bus; -		memset(ohci->next_config_rom, 0, CONFIG_ROM_SIZE); -		fw_memcpy_to_be32(ohci->next_config_rom, config_rom, -				  length * 4); +		copy_config_rom(ohci->next_config_rom, config_rom, length);  		ohci->next_header = config_rom[0];  		ohci->next_config_rom[0] = 0; @@ -1715,7 +1738,7 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)  	if (packet->ack != 0)  		goto out; -	if (packet->payload_bus) +	if (packet->payload_mapped)  		dma_unmap_single(ohci->card.device, packet->payload_bus,  				 packet->payload_length, DMA_TO_DEVICE); @@ -1890,15 +1913,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;  }  |