@@ -928,56 +928,6 @@ static void fw_device_update(struct work_struct *work)
928
928
device_for_each_child (& device -> device , NULL , update_unit );
929
929
}
930
930
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
-
981
931
enum { BC_UNKNOWN = 0 , BC_UNIMPLEMENTED , BC_IMPLEMENTED , };
982
932
983
933
static 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)
1038
988
return 0 ;
1039
989
}
1040
990
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
+
1041
1003
static void fw_device_init (struct work_struct * work )
1042
1004
{
1043
1005
struct fw_device * device =
1044
1006
container_of (work , struct fw_device , work .work );
1045
1007
struct fw_card * card = device -> card ;
1046
- struct device * revived_dev ;
1008
+ struct device * found ;
1047
1009
u32 minor ;
1048
1010
int ret ;
1049
1011
@@ -1071,13 +1033,53 @@ static void fw_device_init(struct work_struct *work)
1071
1033
return ;
1072
1034
}
1073
1035
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
+ }
1079
1075
1080
- return ;
1076
+ put_device (found );
1077
+ fw_device_release (& device -> device );
1078
+
1079
+ return ;
1080
+ }
1081
+
1082
+ put_device (found );
1081
1083
}
1082
1084
1083
1085
device_initialize (& device -> device );
0 commit comments