diff options
Diffstat (limited to 'drivers/firewire/fw-device.c')
-rw-r--r-- | drivers/firewire/fw-device.c | 263 |
1 files changed, 215 insertions, 48 deletions
diff --git a/drivers/firewire/fw-device.c b/drivers/firewire/fw-device.c index 870125a3638e..2d01bc1b9752 100644 --- a/drivers/firewire/fw-device.c +++ b/drivers/firewire/fw-device.c | |||
@@ -25,7 +25,7 @@ | |||
25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/idr.h> | 27 | #include <linux/idr.h> |
28 | #include <linux/rwsem.h> | 28 | #include <linux/string.h> |
29 | #include <asm/semaphore.h> | 29 | #include <asm/semaphore.h> |
30 | #include <asm/system.h> | 30 | #include <asm/system.h> |
31 | #include <linux/ctype.h> | 31 | #include <linux/ctype.h> |
@@ -160,9 +160,9 @@ static void fw_device_release(struct device *dev) | |||
160 | * Take the card lock so we don't set this to NULL while a | 160 | * Take the card lock so we don't set this to NULL while a |
161 | * FW_NODE_UPDATED callback is being handled. | 161 | * FW_NODE_UPDATED callback is being handled. |
162 | */ | 162 | */ |
163 | spin_lock_irqsave(&device->card->lock, flags); | 163 | spin_lock_irqsave(&card->lock, flags); |
164 | device->node->data = NULL; | 164 | device->node->data = NULL; |
165 | spin_unlock_irqrestore(&device->card->lock, flags); | 165 | spin_unlock_irqrestore(&card->lock, flags); |
166 | 166 | ||
167 | fw_node_put(device->node); | 167 | fw_node_put(device->node); |
168 | kfree(device->config_rom); | 168 | kfree(device->config_rom); |
@@ -195,7 +195,9 @@ show_immediate(struct device *dev, struct device_attribute *dattr, char *buf) | |||
195 | container_of(dattr, struct config_rom_attribute, attr); | 195 | container_of(dattr, struct config_rom_attribute, attr); |
196 | struct fw_csr_iterator ci; | 196 | struct fw_csr_iterator ci; |
197 | u32 *dir; | 197 | u32 *dir; |
198 | int key, value; | 198 | int key, value, ret = -ENOENT; |
199 | |||
200 | down_read(&fw_device_rwsem); | ||
199 | 201 | ||
200 | if (is_fw_unit(dev)) | 202 | if (is_fw_unit(dev)) |
201 | dir = fw_unit(dev)->directory; | 203 | dir = fw_unit(dev)->directory; |
@@ -204,11 +206,15 @@ show_immediate(struct device *dev, struct device_attribute *dattr, char *buf) | |||
204 | 206 | ||
205 | fw_csr_iterator_init(&ci, dir); | 207 | fw_csr_iterator_init(&ci, dir); |
206 | while (fw_csr_iterator_next(&ci, &key, &value)) | 208 | while (fw_csr_iterator_next(&ci, &key, &value)) |
207 | if (attr->key == key) | 209 | if (attr->key == key) { |
208 | return snprintf(buf, buf ? PAGE_SIZE : 0, | 210 | ret = snprintf(buf, buf ? PAGE_SIZE : 0, |
209 | "0x%06x\n", value); | 211 | "0x%06x\n", value); |
212 | break; | ||
213 | } | ||
214 | |||
215 | up_read(&fw_device_rwsem); | ||
210 | 216 | ||
211 | return -ENOENT; | 217 | return ret; |
212 | } | 218 | } |
213 | 219 | ||
214 | #define IMMEDIATE_ATTR(name, key) \ | 220 | #define IMMEDIATE_ATTR(name, key) \ |
@@ -221,9 +227,11 @@ show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf) | |||
221 | container_of(dattr, struct config_rom_attribute, attr); | 227 | container_of(dattr, struct config_rom_attribute, attr); |
222 | struct fw_csr_iterator ci; | 228 | struct fw_csr_iterator ci; |
223 | u32 *dir, *block = NULL, *p, *end; | 229 | u32 *dir, *block = NULL, *p, *end; |
224 | int length, key, value, last_key = 0; | 230 | int length, key, value, last_key = 0, ret = -ENOENT; |
225 | char *b; | 231 | char *b; |
226 | 232 | ||
233 | down_read(&fw_device_rwsem); | ||
234 | |||
227 | if (is_fw_unit(dev)) | 235 | if (is_fw_unit(dev)) |
228 | dir = fw_unit(dev)->directory; | 236 | dir = fw_unit(dev)->directory; |
229 | else | 237 | else |
@@ -238,18 +246,20 @@ show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf) | |||
238 | } | 246 | } |
239 | 247 | ||
240 | if (block == NULL) | 248 | if (block == NULL) |
241 | return -ENOENT; | 249 | goto out; |
242 | 250 | ||
243 | length = min(block[0] >> 16, 256U); | 251 | length = min(block[0] >> 16, 256U); |
244 | if (length < 3) | 252 | if (length < 3) |
245 | return -ENOENT; | 253 | goto out; |
246 | 254 | ||
247 | if (block[1] != 0 || block[2] != 0) | 255 | if (block[1] != 0 || block[2] != 0) |
248 | /* Unknown encoding. */ | 256 | /* Unknown encoding. */ |
249 | return -ENOENT; | 257 | goto out; |
250 | 258 | ||
251 | if (buf == NULL) | 259 | if (buf == NULL) { |
252 | return length * 4; | 260 | ret = length * 4; |
261 | goto out; | ||
262 | } | ||
253 | 263 | ||
254 | b = buf; | 264 | b = buf; |
255 | end = &block[length + 1]; | 265 | end = &block[length + 1]; |
@@ -259,8 +269,11 @@ show_text_leaf(struct device *dev, struct device_attribute *dattr, char *buf) | |||
259 | /* Strip trailing whitespace and add newline. */ | 269 | /* Strip trailing whitespace and add newline. */ |
260 | while (b--, (isspace(*b) || *b == '\0') && b > buf); | 270 | while (b--, (isspace(*b) || *b == '\0') && b > buf); |
261 | strcpy(b + 1, "\n"); | 271 | strcpy(b + 1, "\n"); |
272 | ret = b + 2 - buf; | ||
273 | out: | ||
274 | up_read(&fw_device_rwsem); | ||
262 | 275 | ||
263 | return b + 2 - buf; | 276 | return ret; |
264 | } | 277 | } |
265 | 278 | ||
266 | #define TEXT_LEAF_ATTR(name, key) \ | 279 | #define TEXT_LEAF_ATTR(name, key) \ |
@@ -337,19 +350,28 @@ static ssize_t | |||
337 | config_rom_show(struct device *dev, struct device_attribute *attr, char *buf) | 350 | config_rom_show(struct device *dev, struct device_attribute *attr, char *buf) |
338 | { | 351 | { |
339 | struct fw_device *device = fw_device(dev); | 352 | struct fw_device *device = fw_device(dev); |
353 | size_t length; | ||
340 | 354 | ||
341 | memcpy(buf, device->config_rom, device->config_rom_length * 4); | 355 | down_read(&fw_device_rwsem); |
356 | length = device->config_rom_length * 4; | ||
357 | memcpy(buf, device->config_rom, length); | ||
358 | up_read(&fw_device_rwsem); | ||
342 | 359 | ||
343 | return device->config_rom_length * 4; | 360 | return length; |
344 | } | 361 | } |
345 | 362 | ||
346 | static ssize_t | 363 | static ssize_t |
347 | guid_show(struct device *dev, struct device_attribute *attr, char *buf) | 364 | guid_show(struct device *dev, struct device_attribute *attr, char *buf) |
348 | { | 365 | { |
349 | struct fw_device *device = fw_device(dev); | 366 | struct fw_device *device = fw_device(dev); |
367 | int ret; | ||
368 | |||
369 | down_read(&fw_device_rwsem); | ||
370 | ret = snprintf(buf, PAGE_SIZE, "0x%08x%08x\n", | ||
371 | device->config_rom[3], device->config_rom[4]); | ||
372 | up_read(&fw_device_rwsem); | ||
350 | 373 | ||
351 | return snprintf(buf, PAGE_SIZE, "0x%08x%08x\n", | 374 | return ret; |
352 | device->config_rom[3], device->config_rom[4]); | ||
353 | } | 375 | } |
354 | 376 | ||
355 | static struct device_attribute fw_device_attributes[] = { | 377 | static struct device_attribute fw_device_attributes[] = { |
@@ -388,7 +410,7 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data) | |||
388 | 410 | ||
389 | init_completion(&callback_data.done); | 411 | init_completion(&callback_data.done); |
390 | 412 | ||
391 | offset = 0xfffff0000400ULL + index * 4; | 413 | offset = (CSR_REGISTER_BASE | CSR_CONFIG_ROM) + index * 4; |
392 | fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST, | 414 | fw_send_request(device->card, &t, TCODE_READ_QUADLET_REQUEST, |
393 | device->node_id, generation, device->max_speed, | 415 | device->node_id, generation, device->max_speed, |
394 | offset, NULL, 4, complete_transaction, &callback_data); | 416 | offset, NULL, 4, complete_transaction, &callback_data); |
@@ -400,6 +422,9 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data) | |||
400 | return callback_data.rcode; | 422 | return callback_data.rcode; |
401 | } | 423 | } |
402 | 424 | ||
425 | #define READ_BIB_ROM_SIZE 256 | ||
426 | #define READ_BIB_STACK_SIZE 16 | ||
427 | |||
403 | /* | 428 | /* |
404 | * Read the bus info block, perform a speed probe, and read all of the rest of | 429 | * 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 | 430 | * the config ROM. We do all this with a cached bus generation. If the bus |
@@ -409,16 +434,23 @@ read_rom(struct fw_device *device, int generation, int index, u32 *data) | |||
409 | */ | 434 | */ |
410 | static int read_bus_info_block(struct fw_device *device, int generation) | 435 | static int read_bus_info_block(struct fw_device *device, int generation) |
411 | { | 436 | { |
412 | static u32 rom[256]; | 437 | u32 *rom, *stack, *old_rom, *new_rom; |
413 | u32 stack[16], sp, key; | 438 | u32 sp, key; |
414 | int i, end, length; | 439 | int i, end, length, ret = -1; |
440 | |||
441 | rom = kmalloc(sizeof(*rom) * READ_BIB_ROM_SIZE + | ||
442 | sizeof(*stack) * READ_BIB_STACK_SIZE, GFP_KERNEL); | ||
443 | if (rom == NULL) | ||
444 | return -ENOMEM; | ||
445 | |||
446 | stack = &rom[READ_BIB_ROM_SIZE]; | ||
415 | 447 | ||
416 | device->max_speed = SCODE_100; | 448 | device->max_speed = SCODE_100; |
417 | 449 | ||
418 | /* First read the bus info block. */ | 450 | /* First read the bus info block. */ |
419 | for (i = 0; i < 5; i++) { | 451 | for (i = 0; i < 5; i++) { |
420 | if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) | 452 | if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) |
421 | return -1; | 453 | goto out; |
422 | /* | 454 | /* |
423 | * As per IEEE1212 7.2, during power-up, devices can | 455 | * As per IEEE1212 7.2, during power-up, devices can |
424 | * reply with a 0 for the first quadlet of the config | 456 | * reply with a 0 for the first quadlet of the config |
@@ -428,7 +460,7 @@ static int read_bus_info_block(struct fw_device *device, int generation) | |||
428 | * retry mechanism will try again later. | 460 | * retry mechanism will try again later. |
429 | */ | 461 | */ |
430 | if (i == 0 && rom[i] == 0) | 462 | if (i == 0 && rom[i] == 0) |
431 | return -1; | 463 | goto out; |
432 | } | 464 | } |
433 | 465 | ||
434 | device->max_speed = device->node->max_speed; | 466 | device->max_speed = device->node->max_speed; |
@@ -478,26 +510,26 @@ static int read_bus_info_block(struct fw_device *device, int generation) | |||
478 | */ | 510 | */ |
479 | key = stack[--sp]; | 511 | key = stack[--sp]; |
480 | i = key & 0xffffff; | 512 | i = key & 0xffffff; |
481 | if (i >= ARRAY_SIZE(rom)) | 513 | if (i >= READ_BIB_ROM_SIZE) |
482 | /* | 514 | /* |
483 | * The reference points outside the standard | 515 | * The reference points outside the standard |
484 | * config rom area, something's fishy. | 516 | * config rom area, something's fishy. |
485 | */ | 517 | */ |
486 | return -1; | 518 | goto out; |
487 | 519 | ||
488 | /* Read header quadlet for the block to get the length. */ | 520 | /* Read header quadlet for the block to get the length. */ |
489 | if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) | 521 | if (read_rom(device, generation, i, &rom[i]) != RCODE_COMPLETE) |
490 | return -1; | 522 | goto out; |
491 | end = i + (rom[i] >> 16) + 1; | 523 | end = i + (rom[i] >> 16) + 1; |
492 | i++; | 524 | i++; |
493 | if (end > ARRAY_SIZE(rom)) | 525 | if (end > READ_BIB_ROM_SIZE) |
494 | /* | 526 | /* |
495 | * This block extends outside standard config | 527 | * This block extends outside standard config |
496 | * area (and the array we're reading it | 528 | * area (and the array we're reading it |
497 | * into). That's broken, so ignore this | 529 | * into). That's broken, so ignore this |
498 | * device. | 530 | * device. |
499 | */ | 531 | */ |
500 | return -1; | 532 | goto out; |
501 | 533 | ||
502 | /* | 534 | /* |
503 | * Now read in the block. If this is a directory | 535 | * Now read in the block. If this is a directory |
@@ -507,9 +539,9 @@ static int read_bus_info_block(struct fw_device *device, int generation) | |||
507 | while (i < end) { | 539 | while (i < end) { |
508 | if (read_rom(device, generation, i, &rom[i]) != | 540 | if (read_rom(device, generation, i, &rom[i]) != |
509 | RCODE_COMPLETE) | 541 | RCODE_COMPLETE) |
510 | return -1; | 542 | goto out; |
511 | if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && | 543 | if ((key >> 30) == 3 && (rom[i] >> 30) > 1 && |
512 | sp < ARRAY_SIZE(stack)) | 544 | sp < READ_BIB_STACK_SIZE) |
513 | stack[sp++] = i + rom[i]; | 545 | stack[sp++] = i + rom[i]; |
514 | i++; | 546 | i++; |
515 | } | 547 | } |
@@ -517,13 +549,23 @@ static int read_bus_info_block(struct fw_device *device, int generation) | |||
517 | length = i; | 549 | length = i; |
518 | } | 550 | } |
519 | 551 | ||
520 | device->config_rom = kmalloc(length * 4, GFP_KERNEL); | 552 | old_rom = device->config_rom; |
521 | if (device->config_rom == NULL) | 553 | new_rom = kmemdup(rom, length * 4, GFP_KERNEL); |
522 | return -1; | 554 | if (new_rom == NULL) |
523 | memcpy(device->config_rom, rom, length * 4); | 555 | goto out; |
556 | |||
557 | down_write(&fw_device_rwsem); | ||
558 | device->config_rom = new_rom; | ||
524 | device->config_rom_length = length; | 559 | device->config_rom_length = length; |
560 | up_write(&fw_device_rwsem); | ||
525 | 561 | ||
526 | return 0; | 562 | kfree(old_rom); |
563 | ret = 0; | ||
564 | device->cmc = rom[2] & 1 << 30; | ||
565 | out: | ||
566 | kfree(rom); | ||
567 | |||
568 | return ret; | ||
527 | } | 569 | } |
528 | 570 | ||
529 | static void fw_unit_release(struct device *dev) | 571 | static void fw_unit_release(struct device *dev) |
@@ -592,7 +634,14 @@ static int shutdown_unit(struct device *device, void *data) | |||
592 | return 0; | 634 | return 0; |
593 | } | 635 | } |
594 | 636 | ||
595 | static DECLARE_RWSEM(idr_rwsem); | 637 | /* |
638 | * fw_device_rwsem acts as dual purpose mutex: | ||
639 | * - serializes accesses to fw_device_idr, | ||
640 | * - serializes accesses to fw_device.config_rom/.config_rom_length and | ||
641 | * fw_unit.directory, unless those accesses happen at safe occasions | ||
642 | */ | ||
643 | DECLARE_RWSEM(fw_device_rwsem); | ||
644 | |||
596 | static DEFINE_IDR(fw_device_idr); | 645 | static DEFINE_IDR(fw_device_idr); |
597 | int fw_cdev_major; | 646 | int fw_cdev_major; |
598 | 647 | ||
@@ -600,11 +649,11 @@ struct fw_device *fw_device_get_by_devt(dev_t devt) | |||
600 | { | 649 | { |
601 | struct fw_device *device; | 650 | struct fw_device *device; |
602 | 651 | ||
603 | down_read(&idr_rwsem); | 652 | down_read(&fw_device_rwsem); |
604 | device = idr_find(&fw_device_idr, MINOR(devt)); | 653 | device = idr_find(&fw_device_idr, MINOR(devt)); |
605 | if (device) | 654 | if (device) |
606 | fw_device_get(device); | 655 | fw_device_get(device); |
607 | up_read(&idr_rwsem); | 656 | up_read(&fw_device_rwsem); |
608 | 657 | ||
609 | return device; | 658 | return device; |
610 | } | 659 | } |
@@ -619,9 +668,9 @@ static void fw_device_shutdown(struct work_struct *work) | |||
619 | device_for_each_child(&device->device, NULL, shutdown_unit); | 668 | device_for_each_child(&device->device, NULL, shutdown_unit); |
620 | device_unregister(&device->device); | 669 | device_unregister(&device->device); |
621 | 670 | ||
622 | down_write(&idr_rwsem); | 671 | down_write(&fw_device_rwsem); |
623 | idr_remove(&fw_device_idr, minor); | 672 | idr_remove(&fw_device_idr, minor); |
624 | up_write(&idr_rwsem); | 673 | up_write(&fw_device_rwsem); |
625 | fw_device_put(device); | 674 | fw_device_put(device); |
626 | } | 675 | } |
627 | 676 | ||
@@ -674,10 +723,10 @@ static void fw_device_init(struct work_struct *work) | |||
674 | err = -ENOMEM; | 723 | err = -ENOMEM; |
675 | 724 | ||
676 | fw_device_get(device); | 725 | fw_device_get(device); |
677 | down_write(&idr_rwsem); | 726 | down_write(&fw_device_rwsem); |
678 | if (idr_pre_get(&fw_device_idr, GFP_KERNEL)) | 727 | if (idr_pre_get(&fw_device_idr, GFP_KERNEL)) |
679 | err = idr_get_new(&fw_device_idr, device, &minor); | 728 | err = idr_get_new(&fw_device_idr, device, &minor); |
680 | up_write(&idr_rwsem); | 729 | up_write(&fw_device_rwsem); |
681 | 730 | ||
682 | if (err < 0) | 731 | if (err < 0) |
683 | goto error; | 732 | goto error; |
@@ -711,7 +760,7 @@ static void fw_device_init(struct work_struct *work) | |||
711 | if (atomic_cmpxchg(&device->state, | 760 | if (atomic_cmpxchg(&device->state, |
712 | FW_DEVICE_INITIALIZING, | 761 | FW_DEVICE_INITIALIZING, |
713 | FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) { | 762 | FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) { |
714 | fw_device_shutdown(&device->work.work); | 763 | fw_device_shutdown(work); |
715 | } else { | 764 | } else { |
716 | if (device->config_rom_retries) | 765 | if (device->config_rom_retries) |
717 | fw_notify("created device %s: GUID %08x%08x, S%d00, " | 766 | fw_notify("created device %s: GUID %08x%08x, S%d00, " |
@@ -725,6 +774,7 @@ static void fw_device_init(struct work_struct *work) | |||
725 | device->device.bus_id, | 774 | device->device.bus_id, |
726 | device->config_rom[3], device->config_rom[4], | 775 | device->config_rom[3], device->config_rom[4], |
727 | 1 << device->max_speed); | 776 | 1 << device->max_speed); |
777 | device->config_rom_retries = 0; | ||
728 | } | 778 | } |
729 | 779 | ||
730 | /* | 780 | /* |
@@ -739,9 +789,9 @@ static void fw_device_init(struct work_struct *work) | |||
739 | return; | 789 | return; |
740 | 790 | ||
741 | error_with_cdev: | 791 | error_with_cdev: |
742 | down_write(&idr_rwsem); | 792 | down_write(&fw_device_rwsem); |
743 | idr_remove(&fw_device_idr, minor); | 793 | idr_remove(&fw_device_idr, minor); |
744 | up_write(&idr_rwsem); | 794 | up_write(&fw_device_rwsem); |
745 | error: | 795 | error: |
746 | fw_device_put(device); /* fw_device_idr's reference */ | 796 | fw_device_put(device); /* fw_device_idr's reference */ |
747 | 797 | ||
@@ -771,6 +821,106 @@ static void fw_device_update(struct work_struct *work) | |||
771 | device_for_each_child(&device->device, NULL, update_unit); | 821 | device_for_each_child(&device->device, NULL, update_unit); |
772 | } | 822 | } |
773 | 823 | ||
824 | enum { | ||
825 | REREAD_BIB_ERROR, | ||
826 | REREAD_BIB_GONE, | ||
827 | REREAD_BIB_UNCHANGED, | ||
828 | REREAD_BIB_CHANGED, | ||
829 | }; | ||
830 | |||
831 | /* Reread and compare bus info block and header of root directory */ | ||
832 | static int reread_bus_info_block(struct fw_device *device, int generation) | ||
833 | { | ||
834 | u32 q; | ||
835 | int i; | ||
836 | |||
837 | for (i = 0; i < 6; i++) { | ||
838 | if (read_rom(device, generation, i, &q) != RCODE_COMPLETE) | ||
839 | return REREAD_BIB_ERROR; | ||
840 | |||
841 | if (i == 0 && q == 0) | ||
842 | return REREAD_BIB_GONE; | ||
843 | |||
844 | if (i > device->config_rom_length || q != device->config_rom[i]) | ||
845 | return REREAD_BIB_CHANGED; | ||
846 | } | ||
847 | |||
848 | return REREAD_BIB_UNCHANGED; | ||
849 | } | ||
850 | |||
851 | static void fw_device_refresh(struct work_struct *work) | ||
852 | { | ||
853 | struct fw_device *device = | ||
854 | container_of(work, struct fw_device, work.work); | ||
855 | struct fw_card *card = device->card; | ||
856 | int node_id = device->node_id; | ||
857 | |||
858 | switch (reread_bus_info_block(device, device->generation)) { | ||
859 | case REREAD_BIB_ERROR: | ||
860 | if (device->config_rom_retries < MAX_RETRIES / 2 && | ||
861 | atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { | ||
862 | device->config_rom_retries++; | ||
863 | schedule_delayed_work(&device->work, RETRY_DELAY / 2); | ||
864 | |||
865 | return; | ||
866 | } | ||
867 | goto give_up; | ||
868 | |||
869 | case REREAD_BIB_GONE: | ||
870 | goto gone; | ||
871 | |||
872 | case REREAD_BIB_UNCHANGED: | ||
873 | if (atomic_cmpxchg(&device->state, | ||
874 | FW_DEVICE_INITIALIZING, | ||
875 | FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) | ||
876 | goto gone; | ||
877 | |||
878 | fw_device_update(work); | ||
879 | device->config_rom_retries = 0; | ||
880 | goto out; | ||
881 | |||
882 | case REREAD_BIB_CHANGED: | ||
883 | break; | ||
884 | } | ||
885 | |||
886 | /* | ||
887 | * Something changed. We keep things simple and don't investigate | ||
888 | * further. We just destroy all previous units and create new ones. | ||
889 | */ | ||
890 | device_for_each_child(&device->device, NULL, shutdown_unit); | ||
891 | |||
892 | if (read_bus_info_block(device, device->generation) < 0) { | ||
893 | if (device->config_rom_retries < MAX_RETRIES && | ||
894 | atomic_read(&device->state) == FW_DEVICE_INITIALIZING) { | ||
895 | device->config_rom_retries++; | ||
896 | schedule_delayed_work(&device->work, RETRY_DELAY); | ||
897 | |||
898 | return; | ||
899 | } | ||
900 | goto give_up; | ||
901 | } | ||
902 | |||
903 | create_units(device); | ||
904 | |||
905 | if (atomic_cmpxchg(&device->state, | ||
906 | FW_DEVICE_INITIALIZING, | ||
907 | FW_DEVICE_RUNNING) == FW_DEVICE_SHUTDOWN) | ||
908 | goto gone; | ||
909 | |||
910 | fw_notify("refreshed device %s\n", device->device.bus_id); | ||
911 | device->config_rom_retries = 0; | ||
912 | goto out; | ||
913 | |||
914 | give_up: | ||
915 | fw_notify("giving up on refresh of device %s\n", device->device.bus_id); | ||
916 | gone: | ||
917 | atomic_set(&device->state, FW_DEVICE_SHUTDOWN); | ||
918 | fw_device_shutdown(work); | ||
919 | out: | ||
920 | if (node_id == card->root_node->node_id) | ||
921 | schedule_delayed_work(&card->work, 0); | ||
922 | } | ||
923 | |||
774 | void fw_node_event(struct fw_card *card, struct fw_node *node, int event) | 924 | void fw_node_event(struct fw_card *card, struct fw_node *node, int event) |
775 | { | 925 | { |
776 | struct fw_device *device; | 926 | struct fw_device *device; |
@@ -780,7 +930,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) | |||
780 | case FW_NODE_LINK_ON: | 930 | case FW_NODE_LINK_ON: |
781 | if (!node->link_on) | 931 | if (!node->link_on) |
782 | break; | 932 | break; |
783 | 933 | create: | |
784 | device = kzalloc(sizeof(*device), GFP_ATOMIC); | 934 | device = kzalloc(sizeof(*device), GFP_ATOMIC); |
785 | if (device == NULL) | 935 | if (device == NULL) |
786 | break; | 936 | break; |
@@ -819,6 +969,23 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) | |||
819 | schedule_delayed_work(&device->work, INITIAL_DELAY); | 969 | schedule_delayed_work(&device->work, INITIAL_DELAY); |
820 | break; | 970 | break; |
821 | 971 | ||
972 | case FW_NODE_INITIATED_RESET: | ||
973 | device = node->data; | ||
974 | if (device == NULL) | ||
975 | goto create; | ||
976 | |||
977 | device->node_id = node->node_id; | ||
978 | smp_wmb(); /* update node_id before generation */ | ||
979 | device->generation = card->generation; | ||
980 | if (atomic_cmpxchg(&device->state, | ||
981 | FW_DEVICE_RUNNING, | ||
982 | FW_DEVICE_INITIALIZING) == FW_DEVICE_RUNNING) { | ||
983 | PREPARE_DELAYED_WORK(&device->work, fw_device_refresh); | ||
984 | schedule_delayed_work(&device->work, | ||
985 | node == card->local_node ? 0 : INITIAL_DELAY); | ||
986 | } | ||
987 | break; | ||
988 | |||
822 | case FW_NODE_UPDATED: | 989 | case FW_NODE_UPDATED: |
823 | if (!node->link_on || node->data == NULL) | 990 | if (!node->link_on || node->data == NULL) |
824 | break; | 991 | break; |