diff options
Diffstat (limited to 'drivers/firewire/ohci.c')
| -rw-r--r-- | drivers/firewire/ohci.c | 103 | 
1 files changed, 67 insertions, 36 deletions
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index f903d7b6f34..438e6c83117 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -1006,13 +1006,12 @@ static void ar_context_run(struct ar_context *ctx)  static struct descriptor *find_branch_descriptor(struct descriptor *d, int z)  { -	int b, key; +	__le16 branch; -	b   = (le16_to_cpu(d->control) & DESCRIPTOR_BRANCH_ALWAYS) >> 2; -	key = (le16_to_cpu(d->control) & DESCRIPTOR_KEY_IMMEDIATE) >> 8; +	branch = d->control & cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS);  	/* figure out which descriptor the branch address goes in */ -	if (z == 2 && (b == 3 || key == 2)) +	if (z == 2 && branch == cpu_to_le16(DESCRIPTOR_BRANCH_ALWAYS))  		return d;  	else  		return d + z - 1; @@ -1193,9 +1192,6 @@ static void context_append(struct context *ctx,  	wmb(); /* finish init of new descriptors before branch_address update */  	ctx->prev->branch_address = cpu_to_le32(d_bus | z);  	ctx->prev = find_branch_descriptor(d, z); - -	reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); -	flush_writes(ctx->ohci);  }  static void context_stop(struct context *ctx) @@ -1218,6 +1214,7 @@ static void context_stop(struct context *ctx)  }  struct driver_data { +	u8 inline_data[8];  	struct fw_packet *packet;  }; @@ -1301,20 +1298,28 @@ static int at_context_queue_packet(struct context *ctx,  		return -1;  	} +	BUILD_BUG_ON(sizeof(struct driver_data) > sizeof(struct descriptor));  	driver_data = (struct driver_data *) &d[3];  	driver_data->packet = packet;  	packet->driver_data = driver_data;  	if (packet->payload_length > 0) { -		payload_bus = -			dma_map_single(ohci->card.device, packet->payload, -				       packet->payload_length, DMA_TO_DEVICE); -		if (dma_mapping_error(ohci->card.device, payload_bus)) { -			packet->ack = RCODE_SEND_ERROR; -			return -1; +		if (packet->payload_length > sizeof(driver_data->inline_data)) { +			payload_bus = dma_map_single(ohci->card.device, +						     packet->payload, +						     packet->payload_length, +						     DMA_TO_DEVICE); +			if (dma_mapping_error(ohci->card.device, payload_bus)) { +				packet->ack = RCODE_SEND_ERROR; +				return -1; +			} +			packet->payload_bus	= payload_bus; +			packet->payload_mapped	= true; +		} else { +			memcpy(driver_data->inline_data, packet->payload, +			       packet->payload_length); +			payload_bus = d_bus + 3 * sizeof(*d);  		} -		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); @@ -1340,8 +1345,12 @@ static int at_context_queue_packet(struct context *ctx,  	context_append(ctx, d, z, 4 - z); -	if (!ctx->running) +	if (ctx->running) { +		reg_write(ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); +		flush_writes(ohci); +	} else {  		context_run(ctx, 0); +	}  	return 0;  } @@ -2066,8 +2075,6 @@ static int ohci_enable(struct fw_card *card,  	reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->self_id_bus);  	reg_write(ohci, OHCI1394_LinkControlSet, -		  OHCI1394_LinkControl_rcvSelfID | -		  OHCI1394_LinkControl_rcvPhyPkt |  		  OHCI1394_LinkControl_cycleTimerEnable |  		  OHCI1394_LinkControl_cycleMaster); @@ -2094,9 +2101,6 @@ static int ohci_enable(struct fw_card *card,  	reg_write(ohci, OHCI1394_FairnessControl, 0);  	card->priority_budget_implemented = ohci->pri_req_max != 0; -	ar_context_run(&ohci->ar_request_ctx); -	ar_context_run(&ohci->ar_response_ctx); -  	reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);  	reg_write(ohci, OHCI1394_IntEventClear, ~0);  	reg_write(ohci, OHCI1394_IntMaskClear, ~0); @@ -2186,7 +2190,13 @@ static int ohci_enable(struct fw_card *card,  	reg_write(ohci, OHCI1394_HCControlSet,  		  OHCI1394_HCControl_linkEnable |  		  OHCI1394_HCControl_BIBimageValid); -	flush_writes(ohci); + +	reg_write(ohci, OHCI1394_LinkControlSet, +		  OHCI1394_LinkControl_rcvSelfID | +		  OHCI1394_LinkControl_rcvPhyPkt); + +	ar_context_run(&ohci->ar_request_ctx); +	ar_context_run(&ohci->ar_response_ctx); /* also flushes writes */  	/* We are ready to go, reset bus to finish initialization. */  	fw_schedule_bus_reset(&ohci->card, false, true); @@ -2199,7 +2209,6 @@ static int ohci_set_config_rom(struct fw_card *card,  {  	struct fw_ohci *ohci;  	unsigned long flags; -	int ret = -EBUSY;  	__be32 *next_config_rom;  	dma_addr_t uninitialized_var(next_config_rom_bus); @@ -2240,22 +2249,37 @@ static int ohci_set_config_rom(struct fw_card *card,  	spin_lock_irqsave(&ohci->lock, flags); +	/* +	 * If there is not an already pending config_rom update, +	 * push our new allocation into the ohci->next_config_rom +	 * and then mark the local variable as null so that we +	 * won't deallocate the new buffer. +	 * +	 * OTOH, if there is a pending config_rom update, just +	 * use that buffer with the new config_rom data, and +	 * let this routine free the unused DMA allocation. +	 */ +  	if (ohci->next_config_rom == NULL) {  		ohci->next_config_rom = next_config_rom;  		ohci->next_config_rom_bus = next_config_rom_bus; +		next_config_rom = NULL; +	} -		copy_config_rom(ohci->next_config_rom, config_rom, length); +	copy_config_rom(ohci->next_config_rom, config_rom, length); -		ohci->next_header = config_rom[0]; -		ohci->next_config_rom[0] = 0; +	ohci->next_header = config_rom[0]; +	ohci->next_config_rom[0] = 0; -		reg_write(ohci, OHCI1394_ConfigROMmap, -			  ohci->next_config_rom_bus); -		ret = 0; -	} +	reg_write(ohci, OHCI1394_ConfigROMmap, ohci->next_config_rom_bus);  	spin_unlock_irqrestore(&ohci->lock, flags); +	/* If we didn't use the DMA allocation, delete it. */ +	if (next_config_rom != NULL) +		dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, +				  next_config_rom, next_config_rom_bus); +  	/*  	 * Now initiate a bus reset to have the changes take  	 * effect. We clean up the old config rom memory and DMA @@ -2263,13 +2287,10 @@ static int ohci_set_config_rom(struct fw_card *card,  	 * controller could need to access it before the bus reset  	 * takes effect.  	 */ -	if (ret == 0) -		fw_schedule_bus_reset(&ohci->card, true, true); -	else -		dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE, -				  next_config_rom, next_config_rom_bus); -	return ret; +	fw_schedule_bus_reset(&ohci->card, true, true); + +	return 0;  }  static void ohci_send_request(struct fw_card *card, struct fw_packet *packet) @@ -3101,6 +3122,15 @@ static int ohci_queue_iso(struct fw_iso_context *base,  	return ret;  } +static void ohci_flush_queue_iso(struct fw_iso_context *base) +{ +	struct context *ctx = +			&container_of(base, struct iso_context, base)->context; + +	reg_write(ctx->ohci, CONTROL_SET(ctx->regs), CONTEXT_WAKE); +	flush_writes(ctx->ohci); +} +  static const struct fw_card_driver ohci_driver = {  	.enable			= ohci_enable,  	.read_phy_reg		= ohci_read_phy_reg, @@ -3117,6 +3147,7 @@ static const struct fw_card_driver ohci_driver = {  	.free_iso_context	= ohci_free_iso_context,  	.set_iso_channels	= ohci_set_iso_channels,  	.queue_iso		= ohci_queue_iso, +	.flush_queue_iso	= ohci_flush_queue_iso,  	.start_iso		= ohci_start_iso,  	.stop_iso		= ohci_stop_iso,  };  |