diff options
| author | Clemens Ladisch <clemens@ladisch.de> | 2010-06-10 08:40:49 +0200 | 
|---|---|---|
| committer | Clemens Ladisch <clemens@ladisch.de> | 2010-06-10 08:40:49 +0200 | 
| commit | e91b2787d0a2e4719b016e8dec0afd2d5ab6c30f (patch) | |
| tree | e76a3665243ed9fb7275228d9a14dcb0eb5b567a | |
| parent | 7e0e314f198d5048b74c8f0ef9f4c1c02e5ecfc9 (diff) | |
| download | olio-linux-3.10-e91b2787d0a2e4719b016e8dec0afd2d5ab6c30f.tar.xz olio-linux-3.10-e91b2787d0a2e4719b016e8dec0afd2d5ab6c30f.zip  | |
firewire: allocate broadcast channel in hardware
On OHCI 1.1 controllers, let the hardware allocate the broadcast channel
automatically.  This removes a theoretical race condition directly after
a bus reset where it could be possible to read the channel allocation
register with channel 31 still being unallocated.
Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
| -rw-r--r-- | drivers/firewire/core-card.c | 16 | ||||
| -rw-r--r-- | drivers/firewire/core-topology.c | 3 | ||||
| -rw-r--r-- | drivers/firewire/core.h | 1 | ||||
| -rw-r--r-- | drivers/firewire/ohci.c | 18 | 
4 files changed, 26 insertions, 12 deletions
diff --git a/drivers/firewire/core-card.c b/drivers/firewire/core-card.c index 7c4cf6cfa74..faf2eee473b 100644 --- a/drivers/firewire/core-card.c +++ b/drivers/firewire/core-card.c @@ -208,13 +208,19 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation)  {  	int channel, bandwidth = 0; -	fw_iso_resource_manage(card, generation, 1ULL << 31, &channel, -			       &bandwidth, true, card->bm_transaction_data); -	if (channel == 31) { +	if (!card->broadcast_channel_allocated) { +		fw_iso_resource_manage(card, generation, 1ULL << 31, +				       &channel, &bandwidth, true, +				       card->bm_transaction_data); +		if (channel != 31) { +			fw_notify("failed to allocate broadcast channel\n"); +			return; +		}  		card->broadcast_channel_allocated = true; -		device_for_each_child(card->device, (void *)(long)generation, -				      fw_device_set_broadcast_channel);  	} + +	device_for_each_child(card->device, (void *)(long)generation, +			      fw_device_set_broadcast_channel);  }  static const char gap_count_table[] = { diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index ca3c6531816..00a556f3a58 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c @@ -543,7 +543,8 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation,  	spin_lock_irqsave(&card->lock, flags); -	card->broadcast_channel_allocated = false; +	card->broadcast_channel_allocated = (card->driver->get_features(card) & +					     FEATURE_CHANNEL_31_ALLOCATED) != 0;  	card->node_id = node_id;  	/*  	 * Update node_id before generation to prevent anybody from using diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index a9ace1f8dc3..3f9e39b60bc 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h @@ -39,6 +39,7 @@ struct fw_packet;  #define BROADCAST_CHANNEL_VALID		(1 << 30)  #define FEATURE_PRIORITY_BUDGET		0x01 +#define FEATURE_CHANNEL_31_ALLOCATED	0x02  #define CSR_STATE_BIT_CMSTR	(1 << 8)  #define CSR_STATE_BIT_ABDICATE	(1 << 10) diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 1dcc2e427eb..51a55808d88 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c @@ -171,6 +171,7 @@ struct fw_ohci {  	int request_generation;	/* for timestamping incoming requests */  	unsigned quirks;  	unsigned int pri_req_max; +	unsigned int features;  	u32 bus_time;  	bool is_root; @@ -1694,7 +1695,7 @@ static int ohci_enable(struct fw_card *card,  {  	struct fw_ohci *ohci = fw_ohci(card);  	struct pci_dev *dev = to_pci_dev(card->device); -	u32 lps, seconds, irqs; +	u32 lps, seconds, version, irqs;  	int i, ret;  	if (software_reset(ohci)) { @@ -1747,10 +1748,19 @@ static int ohci_enable(struct fw_card *card,  	reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25);  	ohci->bus_time = seconds & ~0x3f; +	version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; +	if (version >= OHCI_VERSION_1_1) { +		reg_write(ohci, OHCI1394_InitialChannelsAvailableHi, +			  0xfffffffe); +		ohci->features |= FEATURE_CHANNEL_31_ALLOCATED; +	} +  	/* Get implemented bits of the priority arbitration request counter. */  	reg_write(ohci, OHCI1394_FairnessControl, 0x3f);  	ohci->pri_req_max = reg_read(ohci, OHCI1394_FairnessControl) & 0x3f;  	reg_write(ohci, OHCI1394_FairnessControl, 0); +	if (ohci->pri_req_max != 0) +		ohci->features |= FEATURE_PRIORITY_BUDGET;  	ar_context_run(&ohci->ar_request_ctx);  	ar_context_run(&ohci->ar_response_ctx); @@ -2124,12 +2134,8 @@ static void ohci_write_csr_reg(struct fw_card *card, int csr_offset, u32 value)  static unsigned int ohci_get_features(struct fw_card *card)  {  	struct fw_ohci *ohci = fw_ohci(card); -	unsigned int features = 0; - -	if (ohci->pri_req_max != 0) -		features |= FEATURE_PRIORITY_BUDGET; -	return features; +	return ohci->features;  }  static void copy_iso_headers(struct iso_context *ctx, void *p)  |