diff options
-rw-r--r-- | drivers/firewire/fw-card.c | 172 | ||||
-rw-r--r-- | drivers/firewire/fw-device.c | 3 | ||||
-rw-r--r-- | drivers/firewire/fw-transaction.h | 8 |
3 files changed, 177 insertions, 6 deletions
diff --git a/drivers/firewire/fw-card.c b/drivers/firewire/fw-card.c index 08a7e18526e..f2b363ea443 100644 --- a/drivers/firewire/fw-card.c +++ b/drivers/firewire/fw-card.c | |||
@@ -181,6 +181,147 @@ void fw_core_remove_descriptor(struct fw_descriptor *desc) | |||
181 | mutex_unlock(&card_mutex); | 181 | mutex_unlock(&card_mutex); |
182 | } | 182 | } |
183 | 183 | ||
184 | /* ------------------------------------------------------------------ */ | ||
185 | /* Code to handle 1394a broadcast channel */ | ||
186 | |||
187 | #define THIRTY_TWO_CHANNELS (0xFFFFFFFFU) | ||
188 | #define IRM_RETRIES 2 | ||
189 | |||
190 | /* | ||
191 | * The abi is set by device_for_each_child(), even though we have no use | ||
192 | * for data, nor do we have a meaningful return value. | ||
193 | */ | ||
194 | int fw_irm_set_broadcast_channel_register(struct device *dev, void *data) | ||
195 | { | ||
196 | struct fw_device *d; | ||
197 | int rcode; | ||
198 | int node_id; | ||
199 | int max_speed; | ||
200 | int retries; | ||
201 | int generation; | ||
202 | __be32 regval; | ||
203 | struct fw_card *card; | ||
204 | |||
205 | d = fw_device(dev); | ||
206 | /* FIXME: do we need locking here? */ | ||
207 | generation = d->generation; | ||
208 | smp_rmb(); /* Ensure generation is at least as old as node_id */ | ||
209 | node_id = d->node_id; | ||
210 | max_speed = d->max_speed; | ||
211 | retries = IRM_RETRIES; | ||
212 | card = d->card; | ||
213 | tryagain_r: | ||
214 | rcode = fw_run_transaction(card, TCODE_READ_QUADLET_REQUEST, | ||
215 | node_id, generation, max_speed, | ||
216 | CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL, | ||
217 | ®val, 4); | ||
218 | switch (rcode) { | ||
219 | case RCODE_BUSY: | ||
220 | if (retries--) | ||
221 | goto tryagain_r; | ||
222 | fw_notify("node %x read broadcast channel busy\n", | ||
223 | node_id); | ||
224 | return 0; | ||
225 | |||
226 | default: | ||
227 | fw_notify("node %x read broadcast channel failed %x\n", | ||
228 | node_id, rcode); | ||
229 | return 0; | ||
230 | |||
231 | case RCODE_COMPLETE: | ||
232 | /* | ||
233 | * Paranoid reporting of nonstandard broadcast channel | ||
234 | * contents goes here | ||
235 | */ | ||
236 | if (regval != cpu_to_be32(BROADCAST_CHANNEL_INITIAL)) | ||
237 | return 0; | ||
238 | break; | ||
239 | } | ||
240 | retries = IRM_RETRIES; | ||
241 | regval = cpu_to_be32(BROADCAST_CHANNEL_INITIAL | | ||
242 | BROADCAST_CHANNEL_VALID); | ||
243 | tryagain_w: | ||
244 | rcode = fw_run_transaction(card, | ||
245 | TCODE_WRITE_QUADLET_REQUEST, node_id, | ||
246 | generation, max_speed, | ||
247 | CSR_REGISTER_BASE + CSR_BROADCAST_CHANNEL, | ||
248 | ®val, 4); | ||
249 | switch (rcode) { | ||
250 | case RCODE_BUSY: | ||
251 | if (retries--) | ||
252 | goto tryagain_w; | ||
253 | fw_notify("node %x write broadcast channel busy\n", | ||
254 | node_id); | ||
255 | return 0; | ||
256 | |||
257 | default: | ||
258 | fw_notify("node %x write broadcast channel failed %x\n", | ||
259 | node_id, rcode); | ||
260 | return 0; | ||
261 | |||
262 | case RCODE_COMPLETE: | ||
263 | return 0; | ||
264 | } | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static void | ||
269 | irm_allocate_broadcast(struct fw_device *irm_dev, struct device *locald) | ||
270 | { | ||
271 | u32 generation; | ||
272 | u32 node_id; | ||
273 | u32 max_speed; | ||
274 | u32 retries; | ||
275 | __be32 old_data; | ||
276 | __be32 lock_data[2]; | ||
277 | int rcode; | ||
278 | |||
279 | /* | ||
280 | * The device we are updating is the IRM, so we must do | ||
281 | * some extra work. | ||
282 | */ | ||
283 | retries = IRM_RETRIES; | ||
284 | generation = irm_dev->generation; | ||
285 | /* FIXME: do we need locking here? */ | ||
286 | smp_rmb(); | ||
287 | node_id = irm_dev->node_id; | ||
288 | max_speed = irm_dev->max_speed; | ||
289 | |||
290 | lock_data[0] = cpu_to_be32(THIRTY_TWO_CHANNELS); | ||
291 | lock_data[1] = cpu_to_be32(THIRTY_TWO_CHANNELS & ~1); | ||
292 | tryagain: | ||
293 | old_data = lock_data[0]; | ||
294 | rcode = fw_run_transaction(irm_dev->card, TCODE_LOCK_COMPARE_SWAP, | ||
295 | node_id, generation, max_speed, | ||
296 | CSR_REGISTER_BASE+CSR_CHANNELS_AVAILABLE_HI, | ||
297 | &lock_data[0], 8); | ||
298 | switch (rcode) { | ||
299 | case RCODE_BUSY: | ||
300 | if (retries--) | ||
301 | goto tryagain; | ||
302 | /* fallthrough */ | ||
303 | default: | ||
304 | fw_error("node %x: allocate broadcast channel failed (%x)\n", | ||
305 | node_id, rcode); | ||
306 | return; | ||
307 | |||
308 | case RCODE_COMPLETE: | ||
309 | if (lock_data[0] == old_data) | ||
310 | break; | ||
311 | if (retries--) { | ||
312 | lock_data[1] = cpu_to_be32(be32_to_cpu(lock_data[0])&~1); | ||
313 | goto tryagain; | ||
314 | } | ||
315 | fw_error("node %x: allocate broadcast channel failed: too many" | ||
316 | " retries\n", node_id); | ||
317 | return; | ||
318 | } | ||
319 | irm_dev->card->is_irm = true; | ||
320 | device_for_each_child(locald, NULL, fw_irm_set_broadcast_channel_register); | ||
321 | } | ||
322 | /* ------------------------------------------------------------------ */ | ||
323 | |||
324 | |||
184 | static const char gap_count_table[] = { | 325 | static const char gap_count_table[] = { |
185 | 63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40 | 326 | 63, 5, 7, 8, 10, 13, 16, 18, 21, 24, 26, 29, 32, 35, 37, 40 |
186 | }; | 327 | }; |
@@ -198,8 +339,8 @@ void fw_schedule_bm_work(struct fw_card *card, unsigned long delay) | |||
198 | static void fw_card_bm_work(struct work_struct *work) | 339 | static void fw_card_bm_work(struct work_struct *work) |
199 | { | 340 | { |
200 | struct fw_card *card = container_of(work, struct fw_card, work.work); | 341 | struct fw_card *card = container_of(work, struct fw_card, work.work); |
201 | struct fw_device *root_device; | 342 | struct fw_device *root_device, *irm_device, *local_device; |
202 | struct fw_node *root_node, *local_node; | 343 | struct fw_node *root_node, *local_node, *irm_node; |
203 | unsigned long flags; | 344 | unsigned long flags; |
204 | int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode; | 345 | int root_id, new_root_id, irm_id, gap_count, generation, grace, rcode; |
205 | bool do_reset = false; | 346 | bool do_reset = false; |
@@ -208,8 +349,10 @@ static void fw_card_bm_work(struct work_struct *work) | |||
208 | __be32 lock_data[2]; | 349 | __be32 lock_data[2]; |
209 | 350 | ||
210 | spin_lock_irqsave(&card->lock, flags); | 351 | spin_lock_irqsave(&card->lock, flags); |
352 | card->is_irm = false; | ||
211 | local_node = card->local_node; | 353 | local_node = card->local_node; |
212 | root_node = card->root_node; | 354 | root_node = card->root_node; |
355 | irm_node = card->irm_node; | ||
213 | 356 | ||
214 | if (local_node == NULL) { | 357 | if (local_node == NULL) { |
215 | spin_unlock_irqrestore(&card->lock, flags); | 358 | spin_unlock_irqrestore(&card->lock, flags); |
@@ -217,6 +360,7 @@ static void fw_card_bm_work(struct work_struct *work) | |||
217 | } | 360 | } |
218 | fw_node_get(local_node); | 361 | fw_node_get(local_node); |
219 | fw_node_get(root_node); | 362 | fw_node_get(root_node); |
363 | fw_node_get(irm_node); | ||
220 | 364 | ||
221 | generation = card->generation; | 365 | generation = card->generation; |
222 | root_device = root_node->data; | 366 | root_device = root_node->data; |
@@ -225,7 +369,8 @@ static void fw_card_bm_work(struct work_struct *work) | |||
225 | root_device_is_cmc = root_device && root_device->cmc; | 369 | root_device_is_cmc = root_device && root_device->cmc; |
226 | root_id = root_node->node_id; | 370 | root_id = root_node->node_id; |
227 | grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10)); | 371 | grace = time_after(jiffies, card->reset_jiffies + DIV_ROUND_UP(HZ, 10)); |
228 | 372 | irm_device = irm_node->data; | |
373 | local_device = local_node->data; | ||
229 | if (is_next_generation(generation, card->bm_generation) || | 374 | if (is_next_generation(generation, card->bm_generation) || |
230 | (card->bm_generation != generation && grace)) { | 375 | (card->bm_generation != generation && grace)) { |
231 | /* | 376 | /* |
@@ -240,8 +385,8 @@ static void fw_card_bm_work(struct work_struct *work) | |||
240 | * next generation. | 385 | * next generation. |
241 | */ | 386 | */ |
242 | 387 | ||
243 | irm_id = card->irm_node->node_id; | 388 | irm_id = irm_node->node_id; |
244 | if (!card->irm_node->link_on) { | 389 | if (!irm_node->link_on) { |
245 | new_root_id = local_node->node_id; | 390 | new_root_id = local_node->node_id; |
246 | fw_notify("IRM has link off, making local node (%02x) root.\n", | 391 | fw_notify("IRM has link off, making local node (%02x) root.\n", |
247 | new_root_id); | 392 | new_root_id); |
@@ -263,9 +408,15 @@ static void fw_card_bm_work(struct work_struct *work) | |||
263 | goto out; | 408 | goto out; |
264 | 409 | ||
265 | if (rcode == RCODE_COMPLETE && | 410 | if (rcode == RCODE_COMPLETE && |
266 | lock_data[0] != cpu_to_be32(0x3f)) | 411 | lock_data[0] != cpu_to_be32(0x3f)) { |
267 | /* Somebody else is BM, let them do the work. */ | 412 | /* Somebody else is BM, let them do the work. */ |
413 | if (irm_id == local_node->node_id) { | ||
414 | /* But we are IRM, so do irm-y things */ | ||
415 | irm_allocate_broadcast(irm_device, | ||
416 | card->device); | ||
417 | } | ||
268 | goto out; | 418 | goto out; |
419 | } | ||
269 | 420 | ||
270 | spin_lock_irqsave(&card->lock, flags); | 421 | spin_lock_irqsave(&card->lock, flags); |
271 | 422 | ||
@@ -357,10 +508,19 @@ static void fw_card_bm_work(struct work_struct *work) | |||
357 | card->index, new_root_id, gap_count); | 508 | card->index, new_root_id, gap_count); |
358 | fw_send_phy_config(card, new_root_id, generation, gap_count); | 509 | fw_send_phy_config(card, new_root_id, generation, gap_count); |
359 | fw_core_initiate_bus_reset(card, 1); | 510 | fw_core_initiate_bus_reset(card, 1); |
511 | } else if (irm_node->node_id == local_node->node_id) { | ||
512 | /* | ||
513 | * We are IRM, so do irm-y things. | ||
514 | * There's no reason to do this if we're doing a reset. . . | ||
515 | * We'll be back. | ||
516 | */ | ||
517 | irm_allocate_broadcast(irm_device, card->device); | ||
360 | } | 518 | } |
519 | |||
361 | out: | 520 | out: |
362 | fw_node_put(root_node); | 521 | fw_node_put(root_node); |
363 | fw_node_put(local_node); | 522 | fw_node_put(local_node); |
523 | fw_node_put(irm_node); | ||
364 | out_put_card: | 524 | out_put_card: |
365 | fw_card_put(card); | 525 | fw_card_put(card); |
366 | } | 526 | } |
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 633e44de5d1..a40444e8eb2 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c | |||
@@ -849,6 +849,9 @@ static void fw_device_init(struct work_struct *work) | |||
849 | device->config_rom[3], device->config_rom[4], | 849 | device->config_rom[3], device->config_rom[4], |
850 | 1 << device->max_speed); | 850 | 1 << device->max_speed); |
851 | device->config_rom_retries = 0; | 851 | device->config_rom_retries = 0; |
852 | if (device->card->is_irm) | ||
853 | fw_irm_set_broadcast_channel_register(&device->device, | ||
854 | NULL); | ||
852 | } | 855 | } |
853 | 856 | ||
854 | /* | 857 | /* |
diff --git a/drivers/firewire/fw-transaction.h b/drivers/firewire/fw-transaction.h index eed2e295eb3..f90f09c0583 100644 --- a/drivers/firewire/fw-transaction.h +++ b/drivers/firewire/fw-transaction.h | |||
@@ -230,6 +230,11 @@ 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; | ||
233 | 238 | ||
234 | int index; | 239 | int index; |
235 | 240 | ||
@@ -438,4 +443,7 @@ void fw_core_handle_bus_reset(struct fw_card *card, int node_id, | |||
438 | void fw_core_handle_request(struct fw_card *card, struct fw_packet *request); | 443 | void fw_core_handle_request(struct fw_card *card, struct fw_packet *request); |
439 | void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); | 444 | void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet); |
440 | 445 | ||
446 | extern int fw_irm_set_broadcast_channel_register(struct device *dev, | ||
447 | void *data); | ||
448 | |||
441 | #endif /* __fw_transaction_h */ | 449 | #endif /* __fw_transaction_h */ |