Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1d5fcfe

Browse files
committed
PM / Domains: Add device domain data reference counter
Add a mechanism for counting references to the struct generic_pm_domain_data object pointed to by dev->power.subsys_data->domain_data if the device in question belongs to a generic PM domain. This change is necessary for a subsequent patch making it possible to allocate that object from within pm_genpd_add_callbacks(), so that drivers can attach their PM domain device callbacks to devices before those devices are added to PM domains. This patch has been tested on the SH7372 Mackerel board. Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent cbc9ef0 commit 1d5fcfe

File tree

2 files changed

+58
-26
lines changed

2 files changed

+58
-26
lines changed

drivers/base/power/domain.c

Lines changed: 57 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
297297

298298
pdd = dev->power.subsys_data ?
299299
dev->power.subsys_data->domain_data : NULL;
300-
if (pdd) {
300+
if (pdd && pdd->dev) {
301301
to_gpd_data(pdd)->td.constraint_changed = true;
302302
genpd = dev_to_genpd(dev);
303303
} else {
@@ -1266,6 +1266,27 @@ static void pm_genpd_complete(struct device *dev)
12661266

12671267
#endif /* CONFIG_PM_SLEEP */
12681268

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+
12691290
/**
12701291
* __pm_genpd_add_device - Add a device to an I/O PM domain.
12711292
* @genpd: PM domain to add the device to.
@@ -1275,7 +1296,7 @@ static void pm_genpd_complete(struct device *dev)
12751296
int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
12761297
struct gpd_timing_data *td)
12771298
{
1278-
struct generic_pm_domain_data *gpd_data;
1299+
struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL;
12791300
struct pm_domain_data *pdd;
12801301
int ret = 0;
12811302

@@ -1284,14 +1305,10 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
12841305
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
12851306
return -EINVAL;
12861307

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)
12891310
return -ENOMEM;
12901311

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-
12951312
genpd_acquire_lock(genpd);
12961313

12971314
if (genpd->prepared_count > 0) {
@@ -1305,35 +1322,42 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
13051322
goto out;
13061323
}
13071324

1325+
ret = dev_pm_get_subsys_data(dev);
1326+
if (ret)
1327+
goto out;
1328+
13081329
genpd->device_count++;
13091330
genpd->max_off_time_changed = true;
13101331

1311-
dev_pm_get_subsys_data(dev);
1312-
1313-
mutex_lock(&gpd_data->lock);
13141332
spin_lock_irq(&dev->power.lock);
1333+
13151334
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++;
13201342
if (td)
13211343
gpd_data->td = *td;
13221344

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;
13231351
gpd_data->td.constraint_changed = true;
13241352
gpd_data->td.effective_constraint_ns = -1;
1325-
spin_unlock_irq(&dev->power.lock);
13261353
mutex_unlock(&gpd_data->lock);
13271354

1328-
genpd_release_lock(genpd);
1329-
1330-
return 0;
1331-
13321355
out:
13331356
genpd_release_lock(genpd);
13341357

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+
13371361
return ret;
13381362
}
13391363

@@ -1379,6 +1403,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
13791403
{
13801404
struct generic_pm_domain_data *gpd_data;
13811405
struct pm_domain_data *pdd;
1406+
bool remove = false;
13821407
int ret = 0;
13831408

13841409
dev_dbg(dev, "%s()\n", __func__);
@@ -1399,22 +1424,28 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
13991424
genpd->max_off_time_changed = true;
14001425

14011426
spin_lock_irq(&dev->power.lock);
1427+
14021428
dev->pm_domain = NULL;
14031429
pdd = dev->power.subsys_data->domain_data;
14041430
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+
14061437
spin_unlock_irq(&dev->power.lock);
14071438

1408-
gpd_data = to_gpd_data(pdd);
14091439
mutex_lock(&gpd_data->lock);
14101440
pdd->dev = NULL;
14111441
mutex_unlock(&gpd_data->lock);
14121442

14131443
genpd_release_lock(genpd);
14141444

1415-
dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
1416-
kfree(gpd_data);
14171445
dev_pm_put_subsys_data(dev);
1446+
if (remove)
1447+
__pm_genpd_free_dev_data(dev, gpd_data);
1448+
14181449
return 0;
14191450

14201451
out:

include/linux/pm_domain.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ struct generic_pm_domain_data {
112112
struct gpd_timing_data td;
113113
struct notifier_block nb;
114114
struct mutex lock;
115+
unsigned int refcount;
115116
bool need_restore;
116117
bool always_on;
117118
};

0 commit comments

Comments
 (0)