diff options
author | Clemens Ladisch <clemens@ladisch.de> | 2010-06-10 02:40:49 -0400 |
---|---|---|
committer | Clemens Ladisch <clemens@ladisch.de> | 2010-06-10 02:40:49 -0400 |
commit | e91b2787d0a2e4719b016e8dec0afd2d5ab6c30f (patch) | |
tree | e76a3665243ed9fb7275228d9a14dcb0eb5b567a /drivers/firewire | |
parent | 7e0e314f198d5048b74c8f0ef9f4c1c02e5ecfc9 (diff) |
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>
Diffstat (limited to 'drivers/firewire')
-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 7c4cf6cfa746..faf2eee473b9 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) | |||
208 | { | 208 | { |
209 | int channel, bandwidth = 0; | 209 | int channel, bandwidth = 0; |
210 | 210 | ||
211 | fw_iso_resource_manage(card, generation, 1ULL << 31, &channel, | 211 | if (!card->broadcast_channel_allocated) { |
212 | &bandwidth, true, card->bm_transaction_data); | 212 | fw_iso_resource_manage(card, generation, 1ULL << 31, |
213 | if (channel == 31) { | 213 | &channel, &bandwidth, true, |
214 | card->bm_transaction_data); | ||
215 | if (channel != 31) { | ||
216 | fw_notify("failed to allocate broadcast channel\n"); | ||
217 | return; | ||
218 | } | ||
214 | card->broadcast_channel_allocated = true; | 219 | card->broadcast_channel_allocated = true; |
215 | device_for_each_child(card->device, (void *)(long)generation, | ||
216 | fw_device_set_broadcast_channel); | ||
217 | } | 220 | } |
221 | |||
222 | device_for_each_child(card->device, (void *)(long)generation, | ||
223 | fw_device_set_broadcast_channel); | ||
218 | } | 224 | } |
219 | 225 | ||
220 | static const char gap_count_table[] = { | 226 | static const char gap_count_table[] = { |
diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index ca3c65318165..00a556f3a585 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, | |||
543 | 543 | ||
544 | spin_lock_irqsave(&card->lock, flags); | 544 | spin_lock_irqsave(&card->lock, flags); |
545 | 545 | ||
546 | card->broadcast_channel_allocated = false; | 546 | card->broadcast_channel_allocated = (card->driver->get_features(card) & |
547 | FEATURE_CHANNEL_31_ALLOCATED) != 0; | ||
547 | card->node_id = node_id; | 548 | card->node_id = node_id; |
548 | /* | 549 | /* |
549 | * Update node_id before generation to prevent anybody from using | 550 | * Update node_id before generation to prevent anybody from using |
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h index a9ace1f8dc3f..3f9e39b60bca 100644 --- a/drivers/firewire/core.h +++ b/drivers/firewire/core.h | |||
@@ -39,6 +39,7 @@ struct fw_packet; | |||
39 | #define BROADCAST_CHANNEL_VALID (1 << 30) | 39 | #define BROADCAST_CHANNEL_VALID (1 << 30) |
40 | 40 | ||
41 | #define FEATURE_PRIORITY_BUDGET 0x01 | 41 | #define FEATURE_PRIORITY_BUDGET 0x01 |
42 | #define FEATURE_CHANNEL_31_ALLOCATED 0x02 | ||
42 | 43 | ||
43 | #define CSR_STATE_BIT_CMSTR (1 << 8) | 44 | #define CSR_STATE_BIT_CMSTR (1 << 8) |
44 | #define CSR_STATE_BIT_ABDICATE (1 << 10) | 45 | #define CSR_STATE_BIT_ABDICATE (1 << 10) |
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c index 1dcc2e427eb1..51a55808d88a 100644 --- a/drivers/firewire/ohci.c +++ b/drivers/firewire/ohci.c | |||
@@ -171,6 +171,7 @@ struct fw_ohci { | |||
171 | int request_generation; /* for timestamping incoming requests */ | 171 | int request_generation; /* for timestamping incoming requests */ |
172 | unsigned quirks; | 172 | unsigned quirks; |
173 | unsigned int pri_req_max; | 173 | unsigned int pri_req_max; |
174 | unsigned int features; | ||
174 | u32 bus_time; | 175 | u32 bus_time; |
175 | bool is_root; | 176 | bool is_root; |
176 | 177 | ||
@@ -1694,7 +1695,7 @@ static int ohci_enable(struct fw_card *card, | |||
1694 | { | 1695 | { |
1695 | struct fw_ohci *ohci = fw_ohci(card); | 1696 | struct fw_ohci *ohci = fw_ohci(card); |
1696 | struct pci_dev *dev = to_pci_dev(card->device); | 1697 | struct pci_dev *dev = to_pci_dev(card->device); |
1697 | u32 lps, seconds, irqs; | 1698 | u32 lps, seconds, version, irqs; |
1698 | int i, ret; | 1699 | int i, ret; |
1699 | 1700 | ||
1700 | if (software_reset(ohci)) { | 1701 | if (software_reset(ohci)) { |
@@ -1747,10 +1748,19 @@ static int ohci_enable(struct fw_card *card, | |||
1747 | reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25); | 1748 | reg_write(ohci, OHCI1394_IsochronousCycleTimer, seconds << 25); |
1748 | ohci->bus_time = seconds & ~0x3f; | 1749 | ohci->bus_time = seconds & ~0x3f; |
1749 | 1750 | ||
1751 | version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff; | ||
1752 | if (version >= OHCI_VERSION_1_1) { | ||
1753 | reg_write(ohci, OHCI1394_InitialChannelsAvailableHi, | ||
1754 | 0xfffffffe); | ||
1755 | ohci->features |= FEATURE_CHANNEL_31_ALLOCATED; | ||
1756 | } | ||
1757 | |||
1750 | /* Get implemented bits of the priority arbitration request counter. */ | 1758 | /* Get implemented bits of the priority arbitration request counter. */ |
1751 | reg_write(ohci, OHCI1394_FairnessControl, 0x3f); | 1759 | reg_write(ohci, OHCI1394_FairnessControl, 0x3f); |
1752 | ohci->pri_req_max = reg_read(ohci, OHCI1394_FairnessControl) & 0x3f; | 1760 | ohci->pri_req_max = reg_read(ohci, OHCI1394_FairnessControl) & 0x3f; |
1753 | reg_write(ohci, OHCI1394_FairnessControl, 0); | 1761 | reg_write(ohci, OHCI1394_FairnessControl, 0); |
1762 | if (ohci->pri_req_max != 0) | ||
1763 | ohci->features |= FEATURE_PRIORITY_BUDGET; | ||
1754 | 1764 | ||
1755 | ar_context_run(&ohci->ar_request_ctx); | 1765 | ar_context_run(&ohci->ar_request_ctx); |
1756 | ar_context_run(&ohci->ar_response_ctx); | 1766 | 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) | |||
2124 | static unsigned int ohci_get_features(struct fw_card *card) | 2134 | static unsigned int ohci_get_features(struct fw_card *card) |
2125 | { | 2135 | { |
2126 | struct fw_ohci *ohci = fw_ohci(card); | 2136 | struct fw_ohci *ohci = fw_ohci(card); |
2127 | unsigned int features = 0; | ||
2128 | |||
2129 | if (ohci->pri_req_max != 0) | ||
2130 | features |= FEATURE_PRIORITY_BUDGET; | ||
2131 | 2137 | ||
2132 | return features; | 2138 | return ohci->features; |
2133 | } | 2139 | } |
2134 | 2140 | ||
2135 | static void copy_iso_headers(struct iso_context *ctx, void *p) | 2141 | static void copy_iso_headers(struct iso_context *ctx, void *p) |