diff options
author | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-03-02 13:35:42 -0500 |
---|---|---|
committer | Stefan Richter <stefanr@s5r6.in-berlin.de> | 2008-04-18 11:55:35 -0400 |
commit | 1dadff71d6356ebb804c3f4f1d3049247e16111c (patch) | |
tree | 103cab576092528c4820436028ac6cc3bfbc5652 /drivers/firewire/fw-device.c | |
parent | d34316a4bdcd4fef050da584401c7f4ed22482f2 (diff) |
firewire: replace static ROM cache by allocated cache
read_bus_info_block() is repeatedly called by workqueue jobs.
These will step on each others toes eventually if there are multiple
workqueue threads, and we end up with corrupt config ROM images.
Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
Diffstat (limited to 'drivers/firewire/fw-device.c')
-rw-r--r-- | drivers/firewire/fw-device.c | 41 |
1 files changed, 27 insertions, 14 deletions
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 870125a3638e..20ac9a5afc37 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c | |||
@@ -400,6 +400,9 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data) | |||
400 | return callback_data.rcode; | 400 | return callback_data.rcode; |
401 | } | 401 | } |
402 | 402 | ||
403 | #define READ_BIB_ROM_SIZE 256 | ||
404 | #define READ_BIB_STACK_SIZE 16 | ||
405 | |||
403 | /* | 406 | /* |
404 | * Read the bus info block, perform a speed probe, and read all of the rest of | 407 | * Read the bus info block, perform a speed probe, and read all of the rest of |
405 | * the config ROM. We do all this with a cached bus generation. If the bus | 408 | * the config ROM. We do all this with a cached bus generation. If the bus |
@@ -409,16 +412,23 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data) | |||
409 | */ | 412 | */ |
410 | static int read_bus_info_block(struct fw_device *device, int generation) | 413 | static int read_bus_info_block(struct fw_device *device, int generation) |
411 | { | 414 | { |
412 | static u32 rom[256]; | 415 | u32 *rom, *stack; |
413 | u32 stack[16], sp, key; | 416 | u32 sp, key; |
414 | int i, end, length; | 417 | int i, end, length, ret = -1; |
418 | |||
419 | rom = kmalloc(sizeof(*rom) * READ_BIB_ROM_SIZE + | ||
420 | sizeof(*stack) * READ_BIB_STACK_SIZE, GFP_KERNEL); | ||
421 | if (rom == NULL) | ||
422 | return -ENOMEM; | ||
423 | |||
424 | stack = &rom[READ_BIB_ROM_SIZE]; | ||
415 | 425 | ||
416 | device->max_speed = SCODE_100; | 426 | device->max_speed = SCODE_100; |
417 | 427 | ||
418 | /* First read the bus info block. */ | 428 | /* First read the bus info block. */ |
419 | for (i = 0; i < 5; i++) { | 429 | for (i = 0; i < 5; i++) { |
420 | if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) | 430 | if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) |
421 | return -1; | 431 | goto out; |
422 | /* | 432 | /* |
423 | * As per IEEE1212 7.2, during power-up, devices can | 433 | * As per IEEE1212 7.2, during power-up, devices can |
424 | * reply with a 0 for the first quadlet of the config | 434 | * reply with a 0 for the first quadlet of the config |
@@ -428,7 +438,7 @@ static int read_bus_info_block(struct fw_device *device, int generation) | |||
428 | * retry mechanism will try again later. | 438 | * retry mechanism will try again later. |
429 | */ | 439 | */ |
430 | if (i == 0 && rom[i] == 0) | 440 | if (i == 0 && rom[i] == 0) |
431 | return -1; | 441 | goto out; |
432 | } | 442 | } |
433 | 443 | ||
434 | device->max_speed = device->node->max_speed; | 444 | device->max_speed = device->node->max_speed; |
@@ -478,26 +488,26 @@ static int read_bus_info_block(struct fw_device *device, int generation) | |||
478 | */ | 488 | */ |
479 | key = stack[--sp]; | 489 | key = stack[--sp]; |
480 | i = key & 0xffffff; | 490 | i = key & 0xffffff; |
481 | if (i >= ARRAY_SIZE(rom)) | 491 | if (i >= READ_BIB_ROM_SIZE) |
482 | /* | 492 | /* |
483 | * The reference points outside the standard | 493 | * The reference points outside the standard |
484 | * config rom area, something's fishy. | 494 | * config rom area, something's fishy. |
485 | */ | 495 | */ |
486 | return -1; | 496 | goto out; |
487 | 497 | ||
488 | /* Read header quadlet for the block to get the length. */ | 498 | /* Read header quadlet for the block to get the length. */ |
489 | if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) | 499 | if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) |
490 | return -1; | 500 | goto out; |
491 | end = i + (rom[i] >> 16) + 1; | 501 | end = i + (rom[i] >> 16) + 1; |
492 | i++; | 502 | i++; |
493 | if (end > ARRAY_SIZE(rom)) | 503 | if (end > READ_BIB_ROM_SIZE) |
494 | /* | 504 | /* |
495 | * This block extends outside standard config | 505 | * This block extends outside standard config |
496 | * area (and the array we're reading it | 506 | * area (and the array we're reading it |
497 | * into). That's broken, so ignore this | 507 | * into). That's broken, so ignore this |
498 | * device. | 508 | * device. |
499 | */ | 509 | */ |
500 | return -1; | 510 | goto out; |
501 | 511 | ||
502 | /* | 512 | /* |
503 | * Now read in the block. If this is a directory | 513 | * Now read in the block. If this is a directory |
@@ -507,9 +517,9 @@ static int read_bus_info_block(struct fw_device *device, int generation) | |||
507 | while (i < end) { | 517 | while (i < end) { |
508 | if (read_rom(device, generation, i, &rom[i]) != | 518 | if (read_rom(device, generation, i, &rom[i]) != |
509 | RCODE_COMPLETE) | 519 | RCODE_COMPLETE) |
510 | return -1; | 520 | goto out; |
511 | if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && | 521 | if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && |
512 | sp < ARRAY_SIZE(stack)) | 522 | sp < READ_BIB_STACK_SIZE) |
513 | stack[sp++] = i + rom[i]; | 523 | stack[sp++] = i + rom[i]; |
514 | i++; | 524 | i++; |
515 | } | 525 | } |
@@ -519,11 +529,14 @@ static int read_bus_info_block(struct fw_device *device, int generation) | |||
519 | 529 | ||
520 | device->config_rom = kmalloc(length * 4, GFP_KERNEL); | 530 | device->config_rom = kmalloc(length * 4, GFP_KERNEL); |
521 | if (device->config_rom == NULL) | 531 | if (device->config_rom == NULL) |
522 | return -1; | 532 | goto out; |
523 | memcpy(device->config_rom, rom, length * 4); | 533 | memcpy(device->config_rom, rom, length * 4); |
524 | device->config_rom_length = length; | 534 | device->config_rom_length = length; |
535 | ret = 0; | ||
536 | out: | ||
537 | kfree(rom); | ||
525 | 538 | ||
526 | return 0; | 539 | return ret; |
527 | } | 540 | } |
528 | 541 | ||
529 | static void fw_unit_release(struct device *dev) | 542 | static void fw_unit_release(struct device *dev) |