diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2009-03-10 16:09:28 -0400 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2009-03-24 15:56:52 -0400 |
commit | 7889b60ee71eafaf50699a154a2455424bb92daa (patch) | |
tree | d5bb3a4d274bf186e32605284a34a36398475818 | |
parent | cbae787c0f288c3ad385ad4165ae30b5500a1f23 (diff) |
firewire: core: optimize propagation of BROADCAST_CHANNEL
Cache the test result of whether a device implements BROADCAST_CHANNEL.
This minimizes traffic on the bus after each bus reset. A majority of
devices does not implement BROADCAST_CHANNEL.
Remove busy retries; just rely on the hardware to retry requests to busy
responders. Remove unnecessary log messages.
Rename the flag is_irm to broadcast_channel_allocated to better reflect
its meaning. Reset the flag earlier in fw_core_handle_bus_reset.
Pass the generation down as a call parameter; that way generation can't
be newer than card->broadcast_channel_allocated and device->node_id.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
-rw-r--r-- | drivers/firewire/fw-card.c | 85 | ||||
-rw-r--r-- | drivers/firewire/fw-device.c | 45 | ||||
-rw-r--r-- | drivers/firewire/fw-device.h | 5 | ||||
-rw-r--r-- | drivers/firewire/fw-topology.c | 1 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.h | 6 |
5 files changed, 52 insertions, 90 deletions
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index d63d0ed9e048..8b8c8c22f0fc 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c | |||
@@ -181,83 +181,9 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc) | |||
181 | mutex_unlock(&card_mutex); | 181 | mutex_unlock(&card_mutex); |
182 | } | 182 | } |
183 | 183 | ||
184 | #define IRM_RETRIES 2 | 184 | static int set_broadcast_channel(struct device *dev, void *data) |
185 | |||
186 | /* | ||
187 | * The abi is set by device_for_each_child(), even though we have no use | ||
188 | * for data, nor do we have a meaningful return value. | ||
189 | */ | ||
190 | int fw_irm_set_broadcast_channel_register(struct device *dev, void *data) | ||
191 | { | 185 | { |
192 | struct fw_device *d; | 186 | fw_device_set_broadcast_channel(fw_device(dev), (long)data); |
193 | int rcode; | ||
194 | int node_id; | ||
195 | int max_speed; | ||
196 | int retries; | ||
197 | int generation; | ||
198 | __be32 regval; | ||
199 | struct fw_card *card; | ||
200 | |||
201 | d = fw_device(dev); | ||
202 | /* FIXME: do we need locking here? */ | ||
203 | generation = d->generation; | ||
204 | smp_rmb(); /* Ensure generation is at least as old as node_id */ | ||
205 | node_id = d->node_id; | ||
206 | max_speed = d->max_speed; | ||
207 | retries = IRM_RETRIES; | ||
208 | card = d->card; | ||
209 | tryagain_r: | ||
210 | rcode = fw_run_transaction(card, TCODE_READ_QUADLET_REQUEST, | ||
211 | node_id, generation, max_speed, | ||
212 | CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL, | ||
213 | ®val, 4); | ||
214 | switch (rcode) { | ||
215 | case RCODE_BUSY: | ||
216 | if (retries--) | ||
217 | goto tryagain_r; | ||
218 | fw_notify("node %x read broadcast channel busy\n", | ||
219 | node_id); | ||
220 | return 0; | ||
221 | |||
222 | default: | ||
223 | fw_notify("node %x read broadcast channel failed %x\n", | ||
224 | node_id, rcode); | ||
225 | return 0; | ||
226 | |||
227 | case RCODE_COMPLETE: | ||
228 | /* | ||
229 | * Paranoid reporting of nonstandard broadcast channel | ||
230 | * contents goes here | ||
231 | */ | ||
232 | if (regval != cpu_to_be32(BROADCAST_CHANNEL_INITIAL)) | ||
233 | return 0; | ||
234 | break; | ||
235 | } | ||
236 | retries = IRM_RETRIES; | ||
237 | regval = cpu_to_be32(BROADCAST_CHANNEL_INITIAL | | ||
238 | BROADCAST_CHANNEL_VALID); | ||
239 | tryagain_w: | ||
240 | rcode = fw_run_transaction(card, | ||
241 | TCODE_WRITE_QUADLET_REQUEST, node_id, | ||
242 | generation, max_speed, | ||
243 | CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL, | ||
244 | ®val, 4); | ||
245 | switch (rcode) { | ||
246 | case RCODE_BUSY: | ||
247 | if (retries--) | ||
248 | goto tryagain_w; | ||
249 | fw_notify("node %x write broadcast channel busy\n", | ||
250 | node_id); | ||
251 | return 0; | ||
252 | |||
253 | default: | ||
254 | fw_notify("node %x write broadcast channel failed %x\n", | ||
255 | node_id, rcode); | ||
256 | return 0; | ||
257 | |||
258 | case RCODE_COMPLETE: | ||
259 | return 0; | ||
260 | } | ||
261 | return 0; | 187 | return 0; |
262 | } | 188 | } |
263 | 189 | ||
@@ -268,9 +194,9 @@ static void allocate_broadcast_channel(struct fw_card *card, int generation) | |||
268 | fw_iso_resource_manage(card, generation, 1ULL << 31, | 194 | fw_iso_resource_manage(card, generation, 1ULL << 31, |
269 | &channel, &bandwidth, true); | 195 | &channel, &bandwidth, true); |
270 | if (channel == 31) { | 196 | if (channel == 31) { |
271 | card->is_irm = true; | 197 | card->broadcast_channel_allocated = true; |
272 | device_for_each_child(card->device, NULL, | 198 | device_for_each_child(card->device, (void *)(long)generation, |
273 | fw_irm_set_broadcast_channel_register); | 199 | set_broadcast_channel); |
274 | } | 200 | } |
275 | } | 201 | } |
276 | 202 | ||
@@ -302,7 +228,6 @@ static void fw_card_bm_work(struct work_struct *work) | |||
302 | __be32 lock_data[2]; | 228 | __be32 lock_data[2]; |
303 | 229 | ||
304 | spin_lock_irqsave(&card->lock, flags); | 230 | spin_lock_irqsave(&card->lock, flags); |
305 | card->is_irm = false; | ||
306 | 231 | ||
307 | if (card->local_node == NULL) { | 232 | if (card->local_node == NULL) { |
308 | spin_unlock_irqrestore(&card->lock, flags); | 233 | spin_unlock_irqrestore(&card->lock, flags); |
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index a40444e8eb20..a47e2129d83d 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c | |||
@@ -518,7 +518,7 @@ static int read_bus_info_block(struct fw_device *device, int generation) | |||
518 | 518 | ||
519 | kfree(old_rom); | 519 | kfree(old_rom); |
520 | ret = 0; | 520 | ret = 0; |
521 | device->cmc = rom[2] & 1 << 30; | 521 | device->cmc = rom[2] >> 30 & 1; |
522 | out: | 522 | out: |
523 | kfree(rom); | 523 | kfree(rom); |
524 | 524 | ||
@@ -756,6 +756,44 @@ static int lookup_existing_device(struct device *dev, void *data) | |||
756 | return match; | 756 | return match; |
757 | } | 757 | } |
758 | 758 | ||
759 | enum { BC_UNKNOWN = 0, BC_UNIMPLEMENTED, BC_IMPLEMENTED, }; | ||
760 | |||
761 | void fw_device_set_broadcast_channel(struct fw_device *device, int generation) | ||
762 | { | ||
763 | struct fw_card *card = device->card; | ||
764 | __be32 data; | ||
765 | int rcode; | ||
766 | |||
767 | if (!card->broadcast_channel_allocated) | ||
768 | return; | ||
769 | |||
770 | if (device->bc_implemented == BC_UNKNOWN) { | ||
771 | rcode = fw_run_transaction(card, TCODE_READ_QUADLET_REQUEST, | ||
772 | device->node_id, generation, device->max_speed, | ||
773 | CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL, | ||
774 | &data, 4); | ||
775 | switch (rcode) { | ||
776 | case RCODE_COMPLETE: | ||
777 | if (data & cpu_to_be32(1 << 31)) { | ||
778 | device->bc_implemented = BC_IMPLEMENTED; | ||
779 | break; | ||
780 | } | ||
781 | /* else fall through to case address error */ | ||
782 | case RCODE_ADDRESS_ERROR: | ||
783 | device->bc_implemented = BC_UNIMPLEMENTED; | ||
784 | } | ||
785 | } | ||
786 | |||
787 | if (device->bc_implemented == BC_IMPLEMENTED) { | ||
788 | data = cpu_to_be32(BROADCAST_CHANNEL_INITIAL | | ||
789 | BROADCAST_CHANNEL_VALID); | ||
790 | fw_run_transaction(card, TCODE_WRITE_QUADLET_REQUEST, | ||
791 | device->node_id, generation, device->max_speed, | ||
792 | CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL, | ||
793 | &data, 4); | ||
794 | } | ||
795 | } | ||
796 | |||
759 | static void fw_device_init(struct work_struct *work) | 797 | static void fw_device_init(struct work_struct *work) |
760 | { | 798 | { |
761 | struct fw_device *device = | 799 | struct fw_device *device = |
@@ -849,9 +887,8 @@ static void fw_device_init(struct work_struct *work) | |||
849 | device->config_rom[3], device->config_rom[4], | 887 | device->config_rom[3], device->config_rom[4], |
850 | 1 << device->max_speed); | 888 | 1 << device->max_speed); |
851 | device->config_rom_retries = 0; | 889 | device->config_rom_retries = 0; |
852 | if (device->card->is_irm) | 890 | |
853 | fw_irm_set_broadcast_channel_register(&device->device, | 891 | fw_device_set_broadcast_channel(device, device->generation); |
854 | NULL); | ||
855 | } | 892 | } |
856 | 893 | ||
857 | /* | 894 | /* |
diff --git a/drivers/firewire/fw-device.h b/drivers/firewire/fw-device.h index 3085a74669b5..97588937c018 100644 --- a/drivers/firewire/fw-device.h +++ b/drivers/firewire/fw-device.h | |||
@@ -71,7 +71,6 @@ struct fw_device { | |||
71 | int node_id; | 71 | int node_id; |
72 | int generation; | 72 | int generation; |
73 | unsigned max_speed; | 73 | unsigned max_speed; |
74 | bool cmc; | ||
75 | struct fw_card *card; | 74 | struct fw_card *card; |
76 | struct device device; | 75 | struct device device; |
77 | 76 | ||
@@ -81,6 +80,9 @@ struct fw_device { | |||
81 | u32 *config_rom; | 80 | u32 *config_rom; |
82 | size_t config_rom_length; | 81 | size_t config_rom_length; |
83 | int config_rom_retries; | 82 | int config_rom_retries; |
83 | unsigned cmc:1; | ||
84 | unsigned bc_implemented:2; | ||
85 | |||
84 | struct delayed_work work; | 86 | struct delayed_work work; |
85 | struct fw_attribute_group attribute_group; | 87 | struct fw_attribute_group attribute_group; |
86 | }; | 88 | }; |
@@ -109,6 +111,7 @@ static inline void fw_device_put(struct fw_device *device) | |||
109 | 111 | ||
110 | struct fw_device *fw_device_get_by_devt(dev_t devt); | 112 | struct fw_device *fw_device_get_by_devt(dev_t devt); |
111 | int fw_device_enable_phys_dma(struct fw_device *device); | 113 | int fw_device_enable_phys_dma(struct fw_device *device); |
114 | void fw_device_set_broadcast_channel(struct fw_device *device, int generation); | ||
112 | 115 | ||
113 | void fw_device_cdev_update(struct fw_device *device); | 116 | void fw_device_cdev_update(struct fw_device *device); |
114 | void fw_device_cdev_remove(struct fw_device *device); | 117 | void fw_device_cdev_remove(struct fw_device *device); |
diff --git a/drivers/firewire/fw-topology.c b/drivers/firewire/fw-topology.c index b44131cf0c62..d0deecc4de93 100644 --- a/drivers/firewire/fw-topology.c +++ b/drivers/firewire/fw-topology.c | |||
@@ -526,6 +526,7 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, int generation, | |||
526 | 526 | ||
527 | spin_lock_irqsave(&card->lock, flags); | 527 | spin_lock_irqsave(&card->lock, flags); |
528 | 528 | ||
529 | card->broadcast_channel_allocated = false; | ||
529 | card->node_id = node_id; | 530 | card->node_id = node_id; |
530 | /* | 531 | /* |
531 | * Update node_id before generation to prevent anybody from using | 532 | * Update node_id before generation to prevent anybody from using |
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index d4f42cecbdfa..dfa799068f89 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h | |||
@@ -230,11 +230,6 @@ struct fw_card { | |||
230 | u8 color; /* must be u8 to match the definition in struct fw_node */ | 230 | u8 color; /* must be u8 to match the definition in struct fw_node */ |
231 | int gap_count; | 231 | int gap_count; |
232 | bool beta_repeaters_present; | 232 | bool beta_repeaters_present; |
233 | /* | ||
234 | * Set if the local device is the IRM and the broadcast channel | ||
235 | * was allocated. | ||
236 | */ | ||
237 | bool is_irm; | ||
238 | 233 | ||
239 | int index; | 234 | int index; |
240 | 235 | ||
@@ -245,6 +240,7 @@ struct fw_card { | |||
245 | int bm_retries; | 240 | int bm_retries; |
246 | int bm_generation; | 241 | int bm_generation; |
247 | 242 | ||
243 | bool broadcast_channel_allocated; | ||
248 | u32 broadcast_channel; | 244 | u32 broadcast_channel; |
249 | u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4]; | 245 | u32 topology_map[(CSR_TOPOLOGY_MAP_END - CSR_TOPOLOGY_MAP) / 4]; |
250 | }; | 246 | }; |