aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firewire/fw-device.c
diff options
context:
space:
mode:
authorStefan Richter <stefanr@s5r6.in-berlin.de>2008-01-25 11:53:49 -0500
committerStefan Richter <stefanr@s5r6.in-berlin.de>2008-01-30 16:22:28 -0500
commitf8d2dc39389d6ccc0def290dc4b7eb71d68645a2 (patch)
tree7576ee70223a9ad550b8dd7dbad339d9f6b03052 /drivers/firewire/fw-device.c
parentb5d2a5e04e6a26cb3f77af8cbc31e74c361d706c (diff)
firewire: fw-core: react on bus resets while the config ROM is being fetched
read_rom() obtained a fresh new fw_device.generation for each read transaction. Hence it was able to continue reading in the middle of the ROM even if a bus reset happened. However the device may have modified the ROM during the reset. We would end up with a corrupt fetched ROM image then. Although all of this is quite unlikely, it is not impossible. Therefore we now restart reading the ROM if the bus generation changed. Note, the memory barrier in read_rom() is still necessary according to tests by Jarod Wilson, despite of the ->generation access being moved up in the call chain. Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de> This is essentially what I've been beating on locally, and I've yet to hit another config rom read failure with it. Signed-off-by: Jarod Wilson <jwilson@redhat.com>
Diffstat (limited to 'drivers/firewire/fw-device.c')
-rw-r--r--drivers/firewire/fw-device.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c
index 872df2238609..de9066e69adf 100644
--- a/drivers/firewire/fw-device.c
+++ b/drivers/firewire/fw-device.c
@@ -390,12 +390,12 @@ complete_transaction(struct fw_card *card, int rcode,
390 complete(&callback_data->done); 390 complete(&callback_data->done);
391} 391}
392 392
393static int read_rom(struct fw_device *device, int index, u32 * data) 393static int
394read_rom(struct fw_device *device, int generation, int index, u32 *data)
394{ 395{
395 struct read_quadlet_callback_data callback_data; 396 struct read_quadlet_callback_data callback_data;
396 struct fw_transaction t; 397 struct fw_transaction t;
397 u64 offset; 398 u64 offset;
398 int generation = device->generation;
399 399
400 /* device->node_id, accessed below, must not be older than generation */ 400 /* device->node_id, accessed below, must not be older than generation */
401 smp_rmb(); 401 smp_rmb();
@@ -414,7 +414,14 @@ static int read_rom(struct fw_device *device, int index, u32 * data)
414 return callback_data.rcode; 414 return callback_data.rcode;
415} 415}
416 416
417static int read_bus_info_block(struct fw_device *device) 417/*
418 * Read the bus info block, perform a speed probe, and read all of the rest of
419 * the config ROM. We do all this with a cached bus generation. If the bus
420 * generation changes under us, read_bus_info_block will fail and get retried.
421 * It's better to start all over in this case because the node from which we
422 * are reading the ROM may have changed the ROM during the reset.
423 */
424static int read_bus_info_block(struct fw_device *device, int generation)
418{ 425{
419 static u32 rom[256]; 426 static u32 rom[256];
420 u32 stack[16], sp, key; 427 u32 stack[16], sp, key;
@@ -424,7 +431,7 @@ static int read_bus_info_block(struct fw_device *device)
424 431
425 /* First read the bus info block. */ 432 /* First read the bus info block. */
426 for (i = 0; i < 5; i++) { 433 for (i = 0; i < 5; i++) {
427 if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE) 434 if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
428 return -1; 435 return -1;
429 /* 436 /*
430 * As per IEEE1212 7.2, during power-up, devices can 437 * As per IEEE1212 7.2, during power-up, devices can
@@ -459,7 +466,8 @@ static int read_bus_info_block(struct fw_device *device)
459 device->max_speed = device->card->link_speed; 466 device->max_speed = device->card->link_speed;
460 467
461 while (device->max_speed > SCODE_100) { 468 while (device->max_speed > SCODE_100) {
462 if (read_rom(device, 0, &dummy) == RCODE_COMPLETE) 469 if (read_rom(device, generation, 0, &dummy) ==
470 RCODE_COMPLETE)
463 break; 471 break;
464 device->max_speed--; 472 device->max_speed--;
465 } 473 }
@@ -492,7 +500,7 @@ static int read_bus_info_block(struct fw_device *device)
492 return -1; 500 return -1;
493 501
494 /* Read header quadlet for the block to get the length. */ 502 /* Read header quadlet for the block to get the length. */
495 if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE) 503 if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE)
496 return -1; 504 return -1;
497 end = i + (rom[i] >> 16) + 1; 505 end = i + (rom[i] >> 16) + 1;
498 i++; 506 i++;
@@ -511,7 +519,8 @@ static int read_bus_info_block(struct fw_device *device)
511 * it references another block, and push it in that case. 519 * it references another block, and push it in that case.
512 */ 520 */
513 while (i < end) { 521 while (i < end) {
514 if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE) 522 if (read_rom(device, generation, i, &rom[i]) !=
523 RCODE_COMPLETE)
515 return -1; 524 return -1;
516 if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && 525 if ((key >> 30) == 3 && (rom[i] >> 30) > 1 &&
517 sp < ARRAY_SIZE(stack)) 526 sp < ARRAY_SIZE(stack))
@@ -658,7 +667,7 @@ static void fw_device_init(struct work_struct *work)
658 * device. 667 * device.
659 */ 668 */
660 669
661 if (read_bus_info_block(device) < 0) { 670 if (read_bus_info_block(device, device->generation) < 0) {
662 if (device->config_rom_retries < MAX_RETRIES) { 671 if (device->config_rom_retries < MAX_RETRIES) {
663 device->config_rom_retries++; 672 device->config_rom_retries++;
664 schedule_delayed_work(&device->work, RETRY_DELAY); 673 schedule_delayed_work(&device->work, RETRY_DELAY);