@@ -297,7 +297,7 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
297
297
298
298
pdd = dev -> power .subsys_data ?
299
299
dev -> power .subsys_data -> domain_data : NULL ;
300
- if (pdd ) {
300
+ if (pdd && pdd -> dev ) {
301
301
to_gpd_data (pdd )-> td .constraint_changed = true;
302
302
genpd = dev_to_genpd (dev );
303
303
} else {
@@ -1266,6 +1266,27 @@ static void pm_genpd_complete(struct device *dev)
1266
1266
1267
1267
#endif /* CONFIG_PM_SLEEP */
1268
1268
1269
+ static struct generic_pm_domain_data * __pm_genpd_alloc_dev_data (struct device * dev )
1270
+ {
1271
+ struct generic_pm_domain_data * gpd_data ;
1272
+
1273
+ gpd_data = kzalloc (sizeof (* gpd_data ), GFP_KERNEL );
1274
+ if (!gpd_data )
1275
+ return NULL ;
1276
+
1277
+ mutex_init (& gpd_data -> lock );
1278
+ gpd_data -> nb .notifier_call = genpd_dev_pm_qos_notifier ;
1279
+ dev_pm_qos_add_notifier (dev , & gpd_data -> nb );
1280
+ return gpd_data ;
1281
+ }
1282
+
1283
+ static void __pm_genpd_free_dev_data (struct device * dev ,
1284
+ struct generic_pm_domain_data * gpd_data )
1285
+ {
1286
+ dev_pm_qos_remove_notifier (dev , & gpd_data -> nb );
1287
+ kfree (gpd_data );
1288
+ }
1289
+
1269
1290
/**
1270
1291
* __pm_genpd_add_device - Add a device to an I/O PM domain.
1271
1292
* @genpd: PM domain to add the device to.
@@ -1275,7 +1296,7 @@ static void pm_genpd_complete(struct device *dev)
1275
1296
int __pm_genpd_add_device (struct generic_pm_domain * genpd , struct device * dev ,
1276
1297
struct gpd_timing_data * td )
1277
1298
{
1278
- struct generic_pm_domain_data * gpd_data ;
1299
+ struct generic_pm_domain_data * gpd_data_new , * gpd_data = NULL ;
1279
1300
struct pm_domain_data * pdd ;
1280
1301
int ret = 0 ;
1281
1302
@@ -1284,14 +1305,10 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1284
1305
if (IS_ERR_OR_NULL (genpd ) || IS_ERR_OR_NULL (dev ))
1285
1306
return - EINVAL ;
1286
1307
1287
- gpd_data = kzalloc ( sizeof ( * gpd_data ), GFP_KERNEL );
1288
- if (!gpd_data )
1308
+ gpd_data_new = __pm_genpd_alloc_dev_data ( dev );
1309
+ if (!gpd_data_new )
1289
1310
return - ENOMEM ;
1290
1311
1291
- mutex_init (& gpd_data -> lock );
1292
- gpd_data -> nb .notifier_call = genpd_dev_pm_qos_notifier ;
1293
- dev_pm_qos_add_notifier (dev , & gpd_data -> nb );
1294
-
1295
1312
genpd_acquire_lock (genpd );
1296
1313
1297
1314
if (genpd -> prepared_count > 0 ) {
@@ -1305,35 +1322,42 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
1305
1322
goto out ;
1306
1323
}
1307
1324
1325
+ ret = dev_pm_get_subsys_data (dev );
1326
+ if (ret )
1327
+ goto out ;
1328
+
1308
1329
genpd -> device_count ++ ;
1309
1330
genpd -> max_off_time_changed = true;
1310
1331
1311
- dev_pm_get_subsys_data (dev );
1312
-
1313
- mutex_lock (& gpd_data -> lock );
1314
1332
spin_lock_irq (& dev -> power .lock );
1333
+
1315
1334
dev -> pm_domain = & genpd -> domain ;
1316
- dev -> power .subsys_data -> domain_data = & gpd_data -> base ;
1317
- gpd_data -> base .dev = dev ;
1318
- list_add_tail (& gpd_data -> base .list_node , & genpd -> dev_list );
1319
- gpd_data -> need_restore = genpd -> status == GPD_STATE_POWER_OFF ;
1335
+ if (dev -> power .subsys_data -> domain_data ) {
1336
+ gpd_data = to_gpd_data (dev -> power .subsys_data -> domain_data );
1337
+ } else {
1338
+ gpd_data = gpd_data_new ;
1339
+ dev -> power .subsys_data -> domain_data = & gpd_data -> base ;
1340
+ }
1341
+ gpd_data -> refcount ++ ;
1320
1342
if (td )
1321
1343
gpd_data -> td = * td ;
1322
1344
1345
+ spin_unlock_irq (& dev -> power .lock );
1346
+
1347
+ mutex_lock (& gpd_data -> lock );
1348
+ gpd_data -> base .dev = dev ;
1349
+ list_add_tail (& gpd_data -> base .list_node , & genpd -> dev_list );
1350
+ gpd_data -> need_restore = genpd -> status == GPD_STATE_POWER_OFF ;
1323
1351
gpd_data -> td .constraint_changed = true;
1324
1352
gpd_data -> td .effective_constraint_ns = -1 ;
1325
- spin_unlock_irq (& dev -> power .lock );
1326
1353
mutex_unlock (& gpd_data -> lock );
1327
1354
1328
- genpd_release_lock (genpd );
1329
-
1330
- return 0 ;
1331
-
1332
1355
out :
1333
1356
genpd_release_lock (genpd );
1334
1357
1335
- dev_pm_qos_remove_notifier (dev , & gpd_data -> nb );
1336
- kfree (gpd_data );
1358
+ if (gpd_data != gpd_data_new )
1359
+ __pm_genpd_free_dev_data (dev , gpd_data_new );
1360
+
1337
1361
return ret ;
1338
1362
}
1339
1363
@@ -1379,6 +1403,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
1379
1403
{
1380
1404
struct generic_pm_domain_data * gpd_data ;
1381
1405
struct pm_domain_data * pdd ;
1406
+ bool remove = false;
1382
1407
int ret = 0 ;
1383
1408
1384
1409
dev_dbg (dev , "%s()\n" , __func__ );
@@ -1399,22 +1424,28 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
1399
1424
genpd -> max_off_time_changed = true;
1400
1425
1401
1426
spin_lock_irq (& dev -> power .lock );
1427
+
1402
1428
dev -> pm_domain = NULL ;
1403
1429
pdd = dev -> power .subsys_data -> domain_data ;
1404
1430
list_del_init (& pdd -> list_node );
1405
- dev -> power .subsys_data -> domain_data = NULL ;
1431
+ gpd_data = to_gpd_data (pdd );
1432
+ if (-- gpd_data -> refcount == 0 ) {
1433
+ dev -> power .subsys_data -> domain_data = NULL ;
1434
+ remove = true;
1435
+ }
1436
+
1406
1437
spin_unlock_irq (& dev -> power .lock );
1407
1438
1408
- gpd_data = to_gpd_data (pdd );
1409
1439
mutex_lock (& gpd_data -> lock );
1410
1440
pdd -> dev = NULL ;
1411
1441
mutex_unlock (& gpd_data -> lock );
1412
1442
1413
1443
genpd_release_lock (genpd );
1414
1444
1415
- dev_pm_qos_remove_notifier (dev , & gpd_data -> nb );
1416
- kfree (gpd_data );
1417
1445
dev_pm_put_subsys_data (dev );
1446
+ if (remove )
1447
+ __pm_genpd_free_dev_data (dev , gpd_data );
1448
+
1418
1449
return 0 ;
1419
1450
1420
1451
out :
0 commit comments