@@ -928,56 +928,6 @@ static void fw_device_update(struct work_struct *work)
928928 device_for_each_child (& device -> device , NULL , update_unit );
929929}
930930
931- /*
932- * If a device was pending for deletion because its node went away but its
933- * bus info block and root directory header matches that of a newly discovered
934- * device, revive the existing fw_device.
935- * The newly allocated fw_device becomes obsolete instead.
936- */
937- static int lookup_existing_device (struct device * dev , void * data )
938- {
939- struct fw_device * old = fw_device (dev );
940- struct fw_device * new = data ;
941- struct fw_card * card = new -> card ;
942- int match = 0 ;
943-
944- if (!is_fw_device (dev ))
945- return 0 ;
946-
947- guard (rwsem_read )(& fw_device_rwsem ); // serialize config_rom access
948- guard (spinlock_irq )(& card -> lock ); // serialize node access
949-
950- if (memcmp (old -> config_rom , new -> config_rom , 6 * 4 ) == 0 &&
951- atomic_cmpxchg (& old -> state ,
952- FW_DEVICE_GONE ,
953- FW_DEVICE_RUNNING ) == FW_DEVICE_GONE ) {
954- struct fw_node * current_node = new -> node ;
955- struct fw_node * obsolete_node = old -> node ;
956-
957- new -> node = obsolete_node ;
958- new -> node -> data = new ;
959- old -> node = current_node ;
960- old -> node -> data = old ;
961-
962- old -> max_speed = new -> max_speed ;
963- old -> node_id = current_node -> node_id ;
964- smp_wmb (); /* update node_id before generation */
965- old -> generation = card -> generation ;
966- old -> config_rom_retries = 0 ;
967- fw_notice (card , "rediscovered device %s\n" , dev_name (dev ));
968-
969- old -> workfn = fw_device_update ;
970- fw_schedule_device_work (old , 0 );
971-
972- if (current_node == card -> root_node )
973- fw_schedule_bm_work (card , 0 );
974-
975- match = 1 ;
976- }
977-
978- return match ;
979- }
980-
981931enum { BC_UNKNOWN = 0 , BC_UNIMPLEMENTED , BC_IMPLEMENTED , };
982932
983933static void set_broadcast_channel (struct fw_device * device , int generation )
@@ -1038,12 +988,24 @@ int fw_device_set_broadcast_channel(struct device *dev, void *gen)
1038988 return 0 ;
1039989}
1040990
991+ static int compare_configuration_rom (struct device * dev , void * data )
992+ {
993+ const struct fw_device * old = fw_device (dev );
994+ const u32 * config_rom = data ;
995+
996+ if (!is_fw_device (dev ))
997+ return 0 ;
998+
999+ // Compare the bus information block and root_length/root_crc.
1000+ return !memcmp (old -> config_rom , config_rom , 6 * 4 );
1001+ }
1002+
10411003static void fw_device_init (struct work_struct * work )
10421004{
10431005 struct fw_device * device =
10441006 container_of (work , struct fw_device , work .work );
10451007 struct fw_card * card = device -> card ;
1046- struct device * revived_dev ;
1008+ struct device * found ;
10471009 u32 minor ;
10481010 int ret ;
10491011
@@ -1071,13 +1033,53 @@ static void fw_device_init(struct work_struct *work)
10711033 return ;
10721034 }
10731035
1074- revived_dev = device_find_child (card -> device ,
1075- device , lookup_existing_device );
1076- if (revived_dev ) {
1077- put_device (revived_dev );
1078- fw_device_release (& device -> device );
1036+ // If a device was pending for deletion because its node went away but its bus info block
1037+ // and root directory header matches that of a newly discovered device, revive the
1038+ // existing fw_device. The newly allocated fw_device becomes obsolete instead.
1039+ //
1040+ // serialize config_rom access.
1041+ scoped_guard (rwsem_read , & fw_device_rwsem ) {
1042+ found = device_find_child (card -> device , (void * )device -> config_rom ,
1043+ compare_configuration_rom );
1044+ }
1045+ if (found ) {
1046+ struct fw_device * reused = fw_device (found );
1047+
1048+ if (atomic_cmpxchg (& reused -> state ,
1049+ FW_DEVICE_GONE ,
1050+ FW_DEVICE_RUNNING ) == FW_DEVICE_GONE ) {
1051+ // serialize node access
1052+ scoped_guard (spinlock_irq , & card -> lock ) {
1053+ struct fw_node * current_node = device -> node ;
1054+ struct fw_node * obsolete_node = reused -> node ;
1055+
1056+ device -> node = obsolete_node ;
1057+ device -> node -> data = device ;
1058+ reused -> node = current_node ;
1059+ reused -> node -> data = reused ;
1060+
1061+ reused -> max_speed = device -> max_speed ;
1062+ reused -> node_id = current_node -> node_id ;
1063+ smp_wmb (); /* update node_id before generation */
1064+ reused -> generation = card -> generation ;
1065+ reused -> config_rom_retries = 0 ;
1066+ fw_notice (card , "rediscovered device %s\n" ,
1067+ dev_name (found ));
1068+
1069+ reused -> workfn = fw_device_update ;
1070+ fw_schedule_device_work (reused , 0 );
1071+
1072+ if (current_node == card -> root_node )
1073+ fw_schedule_bm_work (card , 0 );
1074+ }
10791075
1080- return ;
1076+ put_device (found );
1077+ fw_device_release (& device -> device );
1078+
1079+ return ;
1080+ }
1081+
1082+ put_device (found );
10811083 }
10821084
10831085 device_initialize (& device -> device );
0 commit comments