@@ -926,6 +926,79 @@ static int get_dma_id(struct dma_device *device)
926926 return 0 ;
927927}
928928
929+ static int __dma_async_device_channel_register (struct dma_device * device ,
930+ struct dma_chan * chan ,
931+ int chan_id )
932+ {
933+ int rc = 0 ;
934+ int chancnt = device -> chancnt ;
935+ atomic_t * idr_ref ;
936+ struct dma_chan * tchan ;
937+
938+ tchan = list_first_entry_or_null (& device -> channels ,
939+ struct dma_chan , device_node );
940+ if (tchan -> dev ) {
941+ idr_ref = tchan -> dev -> idr_ref ;
942+ } else {
943+ idr_ref = kmalloc (sizeof (* idr_ref ), GFP_KERNEL );
944+ if (!idr_ref )
945+ return - ENOMEM ;
946+ atomic_set (idr_ref , 0 );
947+ }
948+
949+ chan -> local = alloc_percpu (typeof (* chan -> local ));
950+ if (!chan -> local )
951+ goto err_out ;
952+ chan -> dev = kzalloc (sizeof (* chan -> dev ), GFP_KERNEL );
953+ if (!chan -> dev ) {
954+ free_percpu (chan -> local );
955+ chan -> local = NULL ;
956+ goto err_out ;
957+ }
958+
959+ /*
960+ * When the chan_id is a negative value, we are dynamically adding
961+ * the channel. Otherwise we are static enumerating.
962+ */
963+ chan -> chan_id = chan_id < 0 ? chancnt : chan_id ;
964+ chan -> dev -> device .class = & dma_devclass ;
965+ chan -> dev -> device .parent = device -> dev ;
966+ chan -> dev -> chan = chan ;
967+ chan -> dev -> idr_ref = idr_ref ;
968+ chan -> dev -> dev_id = device -> dev_id ;
969+ atomic_inc (idr_ref );
970+ dev_set_name (& chan -> dev -> device , "dma%dchan%d" ,
971+ device -> dev_id , chan -> chan_id );
972+
973+ rc = device_register (& chan -> dev -> device );
974+ if (rc )
975+ goto err_out ;
976+ chan -> client_count = 0 ;
977+ device -> chancnt = chan -> chan_id + 1 ;
978+
979+ return 0 ;
980+
981+ err_out :
982+ free_percpu (chan -> local );
983+ kfree (chan -> dev );
984+ if (atomic_dec_return (idr_ref ) == 0 )
985+ kfree (idr_ref );
986+ return rc ;
987+ }
988+
989+ static void __dma_async_device_channel_unregister (struct dma_device * device ,
990+ struct dma_chan * chan )
991+ {
992+ WARN_ONCE (!device -> device_release && chan -> client_count ,
993+ "%s called while %d clients hold a reference\n" ,
994+ __func__ , chan -> client_count );
995+ mutex_lock (& dma_list_mutex );
996+ chan -> dev -> chan = NULL ;
997+ mutex_unlock (& dma_list_mutex );
998+ device_unregister (& chan -> dev -> device );
999+ free_percpu (chan -> local );
1000+ }
1001+
9291002/**
9301003 * dma_async_device_register - registers DMA devices found
9311004 * @device: &dma_device
@@ -936,9 +1009,8 @@ static int get_dma_id(struct dma_device *device)
9361009 */
9371010int dma_async_device_register (struct dma_device * device )
9381011{
939- int chancnt = 0 , rc ;
1012+ int rc , i = 0 ;
9401013 struct dma_chan * chan ;
941- atomic_t * idr_ref ;
9421014
9431015 if (!device )
9441016 return - ENODEV ;
@@ -1038,59 +1110,23 @@ int dma_async_device_register(struct dma_device *device)
10381110 if (device_has_all_tx_types (device ))
10391111 dma_cap_set (DMA_ASYNC_TX , device -> cap_mask );
10401112
1041- idr_ref = kmalloc (sizeof (* idr_ref ), GFP_KERNEL );
1042- if (!idr_ref )
1043- return - ENOMEM ;
10441113 rc = get_dma_id (device );
1045- if (rc != 0 ) {
1046- kfree (idr_ref );
1114+ if (rc != 0 )
10471115 return rc ;
1048- }
1049-
1050- atomic_set (idr_ref , 0 );
10511116
10521117 /* represent channels in sysfs. Probably want devs too */
10531118 list_for_each_entry (chan , & device -> channels , device_node ) {
1054- rc = - ENOMEM ;
1055- chan -> local = alloc_percpu (typeof (* chan -> local ));
1056- if (chan -> local == NULL )
1119+ rc = __dma_async_device_channel_register (device , chan , i ++ );
1120+ if (rc < 0 )
10571121 goto err_out ;
1058- chan -> dev = kzalloc (sizeof (* chan -> dev ), GFP_KERNEL );
1059- if (chan -> dev == NULL ) {
1060- free_percpu (chan -> local );
1061- chan -> local = NULL ;
1062- goto err_out ;
1063- }
1064-
1065- chan -> chan_id = chancnt ++ ;
1066- chan -> dev -> device .class = & dma_devclass ;
1067- chan -> dev -> device .parent = device -> dev ;
1068- chan -> dev -> chan = chan ;
1069- chan -> dev -> idr_ref = idr_ref ;
1070- chan -> dev -> dev_id = device -> dev_id ;
1071- atomic_inc (idr_ref );
1072- dev_set_name (& chan -> dev -> device , "dma%dchan%d" ,
1073- device -> dev_id , chan -> chan_id );
1074-
1075- rc = device_register (& chan -> dev -> device );
1076- if (rc ) {
1077- free_percpu (chan -> local );
1078- chan -> local = NULL ;
1079- kfree (chan -> dev );
1080- atomic_dec (idr_ref );
1081- goto err_out ;
1082- }
1083- chan -> client_count = 0 ;
10841122 }
10851123
1086- if (!chancnt ) {
1124+ if (!device -> chancnt ) {
10871125 dev_err (device -> dev , "%s: device has no channels!\n" , __func__ );
10881126 rc = - ENODEV ;
10891127 goto err_out ;
10901128 }
10911129
1092- device -> chancnt = chancnt ;
1093-
10941130 mutex_lock (& dma_list_mutex );
10951131 /* take references on public channels */
10961132 if (dmaengine_ref_count && !dma_has_cap (DMA_PRIVATE , device -> cap_mask ))
@@ -1118,9 +1154,8 @@ int dma_async_device_register(struct dma_device *device)
11181154
11191155err_out :
11201156 /* if we never registered a channel just release the idr */
1121- if (atomic_read ( idr_ref ) == 0 ) {
1157+ if (! device -> chancnt ) {
11221158 ida_free (& dma_ida , device -> dev_id );
1123- kfree (idr_ref );
11241159 return rc ;
11251160 }
11261161
@@ -1148,16 +1183,8 @@ void dma_async_device_unregister(struct dma_device *device)
11481183{
11491184 struct dma_chan * chan ;
11501185
1151- list_for_each_entry (chan , & device -> channels , device_node ) {
1152- WARN_ONCE (!device -> device_release && chan -> client_count ,
1153- "%s called while %d clients hold a reference\n" ,
1154- __func__ , chan -> client_count );
1155- mutex_lock (& dma_list_mutex );
1156- chan -> dev -> chan = NULL ;
1157- mutex_unlock (& dma_list_mutex );
1158- device_unregister (& chan -> dev -> device );
1159- free_percpu (chan -> local );
1160- }
1186+ list_for_each_entry (chan , & device -> channels , device_node )
1187+ __dma_async_device_channel_unregister (device , chan );
11611188
11621189 mutex_lock (& dma_list_mutex );
11631190 /*
0 commit comments