Browse Source

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>
Clemens Ladisch 15 years ago
parent
commit
e91b2787d0

+ 11 - 5
drivers/firewire/core-card.c

@@ -208,13 +208,19 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation)
 {
 {
 	int channel, bandwidth = 0;
 	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;
 		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[] = {
 static const char gap_count_table[] = {

+ 2 - 1
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);
 	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;
 	card->node_id = node_id;
 	/*
 	/*
 	 * Update node_id before generation to prevent anybody from using
 	 * Update node_id before generation to prevent anybody from using

+ 1 - 0
drivers/firewire/core.h

@@ -39,6 +39,7 @@ struct fw_packet;
 #define BROADCAST_CHANNEL_VALID		(1 << 30)
 #define BROADCAST_CHANNEL_VALID		(1 << 30)
 
 
 #define FEATURE_PRIORITY_BUDGET		0x01
 #define FEATURE_PRIORITY_BUDGET		0x01
+#define FEATURE_CHANNEL_31_ALLOCATED	0x02
 
 
 #define CSR_STATE_BIT_CMSTR	(1 << 8)
 #define CSR_STATE_BIT_CMSTR	(1 << 8)
 #define CSR_STATE_BIT_ABDICATE	(1 << 10)
 #define CSR_STATE_BIT_ABDICATE	(1 << 10)

+ 12 - 6
drivers/firewire/ohci.c

@@ -171,6 +171,7 @@ struct fw_ohci {
 	int request_generation;	/* for timestamping incoming requests */
 	int request_generation;	/* for timestamping incoming requests */
 	unsigned quirks;
 	unsigned quirks;
 	unsigned int pri_req_max;
 	unsigned int pri_req_max;
+	unsigned int features;
 	u32 bus_time;
 	u32 bus_time;
 	bool is_root;
 	bool is_root;
 
 
@@ -1694,7 +1695,7 @@ static int ohci_enable(struct fw_card *card,
 {
 {
 	struct fw_ohci *ohci = fw_ohci(card);
 	struct fw_ohci *ohci = fw_ohci(card);
 	struct pci_dev *dev = to_pci_dev(card->device);
 	struct pci_dev *dev = to_pci_dev(card->device);
-	u32 lps, seconds, irqs;
+	u32 lps, seconds, version, irqs;
 	int i, ret;
 	int i, ret;
 
 
 	if (software_reset(ohci)) {
 	if (software_reset(ohci)) {
@@ -1747,10 +1748,19 @@ static int ohci_enable(struct fw_card *card,
 	reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25);
 	reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25);
 	ohci->bus_time = seconds & ~0x3f;
 	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. */
 	/* Get implemented bits of the priority arbitration request counter. */
 	reg_write(ohci, OHCI1394_FairnessControl, 0x3f);
 	reg_write(ohci, OHCI1394_FairnessControl, 0x3f);
 	ohci->pri_req_max = reg_read(ohci, OHCI1394_FairnessControl) & 0x3f;
 	ohci->pri_req_max = reg_read(ohci, OHCI1394_FairnessControl) & 0x3f;
 	reg_write(ohci, OHCI1394_FairnessControl, 0);
 	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_request_ctx);
 	ar_context_run(&ohci->ar_response_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)
 static unsigned int ohci_get_features(struct fw_card *card)
 {
 {
 	struct fw_ohci *ohci = fw_ohci(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)
 static void copy_iso_headers(struct iso_context *ctx, void *p)