diff options
Diffstat (limited to 'drivers/firewire/fw-device.c')
| -rw-r--r-- | drivers/firewire/fw-device.c | 38 |
1 files changed, 29 insertions, 9 deletions
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 56681b3b297b..de9066e69adf 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/idr.h> | 27 | #include <linux/idr.h> |
| 28 | #include <linux/rwsem.h> | 28 | #include <linux/rwsem.h> |
| 29 | #include <asm/semaphore.h> | 29 | #include <asm/semaphore.h> |
| 30 | #include <asm/system.h> | ||
| 30 | #include <linux/ctype.h> | 31 | #include <linux/ctype.h> |
| 31 | #include "fw-transaction.h" | 32 | #include "fw-transaction.h" |
| 32 | #include "fw-topology.h" | 33 | #include "fw-topology.h" |
| @@ -182,9 +183,14 @@ static void fw_device_release(struct device *dev) | |||
| 182 | 183 | ||
| 183 | int fw_device_enable_phys_dma(struct fw_device *device) | 184 | int fw_device_enable_phys_dma(struct fw_device *device) |
| 184 | { | 185 | { |
| 186 | int generation = device->generation; | ||
| 187 | |||
| 188 | /* device->node_id, accessed below, must not be older than generation */ | ||
| 189 | smp_rmb(); | ||
| 190 | |||
| 185 | return device->card->driver->enable_phys_dma(device->card, | 191 | return device->card->driver->enable_phys_dma(device->card, |
| 186 | device->node_id, | 192 | device->node_id, |
| 187 | device->generation); | 193 | generation); |
| 188 | } | 194 | } |
| 189 | EXPORT_SYMBOL(fw_device_enable_phys_dma); | 195 | EXPORT_SYMBOL(fw_device_enable_phys_dma); |
| 190 | 196 | ||
| @@ -384,17 +390,21 @@ complete_transaction(struct fw_card *card, int rcode, | |||
| 384 | complete(&callback_data->done); | 390 | complete(&callback_data->done); |
| 385 | } | 391 | } |
| 386 | 392 | ||
| 387 | static int read_rom(struct fw_device *device, int index, u32 * data) | 393 | static int |
| 394 | read_rom(struct fw_device *device, int generation, int index, u32 *data) | ||
| 388 | { | 395 | { |
| 389 | struct read_quadlet_callback_data callback_data; | 396 | struct read_quadlet_callback_data callback_data; |
| 390 | struct fw_transaction t; | 397 | struct fw_transaction t; |
| 391 | u64 offset; | 398 | u64 offset; |
| 392 | 399 | ||
| 400 | /* device->node_id, accessed below, must not be older than generation */ | ||
| 401 | smp_rmb(); | ||
| 402 | |||
| 393 | init_completion(&callback_data.done); | 403 | init_completion(&callback_data.done); |
| 394 | 404 | ||
| 395 | offset = 0xfffff0000400ULL + index * 4; | 405 | offset = 0xfffff0000400ULL + index * 4; |
| 396 | fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST, | 406 | fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST, |
| 397 | device->node_id, device->generation, device->max_speed, | 407 | device->node_id, generation, device->max_speed, |
| 398 | offset, NULL, 4, complete_transaction, &callback_data); | 408 | offset, NULL, 4, complete_transaction, &callback_data); |
| 399 | 409 | ||
| 400 | wait_for_completion(&callback_data.done); | 410 | wait_for_completion(&callback_data.done); |
| @@ -404,7 +414,14 @@ static int read_rom(struct fw_device *device, int index, u32 * data) | |||
| 404 | return callback_data.rcode; | 414 | return callback_data.rcode; |
| 405 | } | 415 | } |
| 406 | 416 | ||
| 407 | static 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 | */ | ||
| 424 | static int read_bus_info_block(struct fw_device *device, int generation) | ||
| 408 | { | 425 | { |
| 409 | static u32 rom[256]; | 426 | static u32 rom[256]; |
| 410 | u32 stack[16], sp, key; | 427 | u32 stack[16], sp, key; |
| @@ -414,7 +431,7 @@ static int read_bus_info_block(struct fw_device *device) | |||
| 414 | 431 | ||
| 415 | /* First read the bus info block. */ | 432 | /* First read the bus info block. */ |
| 416 | for (i = 0; i < 5; i++) { | 433 | for (i = 0; i < 5; i++) { |
| 417 | if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE) | 434 | if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) |
| 418 | return -1; | 435 | return -1; |
| 419 | /* | 436 | /* |
| 420 | * As per IEEE1212 7.2, during power-up, devices can | 437 | * As per IEEE1212 7.2, during power-up, devices can |
| @@ -449,7 +466,8 @@ static int read_bus_info_block(struct fw_device *device) | |||
| 449 | device->max_speed = device->card->link_speed; | 466 | device->max_speed = device->card->link_speed; |
| 450 | 467 | ||
| 451 | while (device->max_speed > SCODE_100) { | 468 | while (device->max_speed > SCODE_100) { |
| 452 | if (read_rom(device, 0, &dummy) == RCODE_COMPLETE) | 469 | if (read_rom(device, generation, 0, &dummy) == |
| 470 | RCODE_COMPLETE) | ||
| 453 | break; | 471 | break; |
| 454 | device->max_speed--; | 472 | device->max_speed--; |
| 455 | } | 473 | } |
| @@ -482,7 +500,7 @@ static int read_bus_info_block(struct fw_device *device) | |||
| 482 | return -1; | 500 | return -1; |
| 483 | 501 | ||
| 484 | /* Read header quadlet for the block to get the length. */ | 502 | /* Read header quadlet for the block to get the length. */ |
| 485 | if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE) | 503 | if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) |
| 486 | return -1; | 504 | return -1; |
| 487 | end = i + (rom[i] >> 16) + 1; | 505 | end = i + (rom[i] >> 16) + 1; |
| 488 | i++; | 506 | i++; |
| @@ -501,7 +519,8 @@ static int read_bus_info_block(struct fw_device *device) | |||
| 501 | * it references another block, and push it in that case. | 519 | * it references another block, and push it in that case. |
| 502 | */ | 520 | */ |
| 503 | while (i < end) { | 521 | while (i < end) { |
| 504 | if (read_rom(device, i, &rom[i]) != RCODE_COMPLETE) | 522 | if (read_rom(device, generation, i, &rom[i]) != |
| 523 | RCODE_COMPLETE) | ||
| 505 | return -1; | 524 | return -1; |
| 506 | if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && | 525 | if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && |
| 507 | sp < ARRAY_SIZE(stack)) | 526 | sp < ARRAY_SIZE(stack)) |
| @@ -648,7 +667,7 @@ static void fw_device_init(struct work_struct *work) | |||
| 648 | * device. | 667 | * device. |
| 649 | */ | 668 | */ |
| 650 | 669 | ||
| 651 | if (read_bus_info_block(device) < 0) { | 670 | if (read_bus_info_block(device, device->generation) < 0) { |
| 652 | if (device->config_rom_retries < MAX_RETRIES) { | 671 | if (device->config_rom_retries < MAX_RETRIES) { |
| 653 | device->config_rom_retries++; | 672 | device->config_rom_retries++; |
| 654 | schedule_delayed_work(&device->work, RETRY_DELAY); | 673 | schedule_delayed_work(&device->work, RETRY_DELAY); |
| @@ -801,6 +820,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) | |||
| 801 | 820 | ||
| 802 | device = node->data; | 821 | device = node->data; |
| 803 | device->node_id = node->node_id; | 822 | device->node_id = node->node_id; |
| 823 | smp_wmb(); /* update node_id before generation */ | ||
| 804 | device->generation = card->generation; | 824 | device->generation = card->generation; |
| 805 | if (atomic_read(&device->state) == FW_DEVICE_RUNNING) { | 825 | if (atomic_read(&device->state) == FW_DEVICE_RUNNING) { |
| 806 | PREPARE_DELAYED_WORK(&device->work, fw_device_update); | 826 | PREPARE_DELAYED_WORK(&device->work, fw_device_update); |
