diff options
-rw-r--r-- | drivers/cpufreq/cpufreq.c | 69 |
1 files changed, 53 insertions, 16 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 1d041aff4d48..e0ace3d9382c 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -44,6 +44,7 @@ | |||
44 | */ | 44 | */ |
45 | static struct cpufreq_driver *cpufreq_driver; | 45 | static struct cpufreq_driver *cpufreq_driver; |
46 | static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); | 46 | static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data); |
47 | static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback); | ||
47 | static DEFINE_RWLOCK(cpufreq_driver_lock); | 48 | static DEFINE_RWLOCK(cpufreq_driver_lock); |
48 | static DEFINE_MUTEX(cpufreq_governor_lock); | 49 | static DEFINE_MUTEX(cpufreq_governor_lock); |
49 | 50 | ||
@@ -946,6 +947,20 @@ static int cpufreq_add_policy_cpu(unsigned int cpu, unsigned int sibling, | |||
946 | } | 947 | } |
947 | #endif | 948 | #endif |
948 | 949 | ||
950 | static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu) | ||
951 | { | ||
952 | struct cpufreq_policy *policy; | ||
953 | unsigned long flags; | ||
954 | |||
955 | write_lock_irqsave(&cpufreq_driver_lock, flags); | ||
956 | |||
957 | policy = per_cpu(cpufreq_cpu_data_fallback, cpu); | ||
958 | |||
959 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); | ||
960 | |||
961 | return policy; | ||
962 | } | ||
963 | |||
949 | static struct cpufreq_policy *cpufreq_policy_alloc(void) | 964 | static struct cpufreq_policy *cpufreq_policy_alloc(void) |
950 | { | 965 | { |
951 | struct cpufreq_policy *policy; | 966 | struct cpufreq_policy *policy; |
@@ -1023,7 +1038,12 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, | |||
1023 | goto module_out; | 1038 | goto module_out; |
1024 | } | 1039 | } |
1025 | 1040 | ||
1026 | policy = cpufreq_policy_alloc(); | 1041 | if (frozen) |
1042 | /* Restore the saved policy when doing light-weight init */ | ||
1043 | policy = cpufreq_policy_restore(cpu); | ||
1044 | else | ||
1045 | policy = cpufreq_policy_alloc(); | ||
1046 | |||
1027 | if (!policy) | 1047 | if (!policy) |
1028 | goto nomem_out; | 1048 | goto nomem_out; |
1029 | 1049 | ||
@@ -1204,6 +1224,10 @@ static int __cpufreq_remove_dev(struct device *dev, | |||
1204 | data = per_cpu(cpufreq_cpu_data, cpu); | 1224 | data = per_cpu(cpufreq_cpu_data, cpu); |
1205 | per_cpu(cpufreq_cpu_data, cpu) = NULL; | 1225 | per_cpu(cpufreq_cpu_data, cpu) = NULL; |
1206 | 1226 | ||
1227 | /* Save the policy somewhere when doing a light-weight tear-down */ | ||
1228 | if (frozen) | ||
1229 | per_cpu(cpufreq_cpu_data_fallback, cpu) = data; | ||
1230 | |||
1207 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); | 1231 | write_unlock_irqrestore(&cpufreq_driver_lock, flags); |
1208 | 1232 | ||
1209 | if (!data) { | 1233 | if (!data) { |
@@ -1249,27 +1273,40 @@ static int __cpufreq_remove_dev(struct device *dev, | |||
1249 | if (cpufreq_driver->target) | 1273 | if (cpufreq_driver->target) |
1250 | __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); | 1274 | __cpufreq_governor(data, CPUFREQ_GOV_POLICY_EXIT); |
1251 | 1275 | ||
1252 | lock_policy_rwsem_read(cpu); | 1276 | if (!frozen) { |
1253 | kobj = &data->kobj; | 1277 | lock_policy_rwsem_read(cpu); |
1254 | cmp = &data->kobj_unregister; | 1278 | kobj = &data->kobj; |
1255 | unlock_policy_rwsem_read(cpu); | 1279 | cmp = &data->kobj_unregister; |
1256 | kobject_put(kobj); | 1280 | unlock_policy_rwsem_read(cpu); |
1281 | kobject_put(kobj); | ||
1282 | |||
1283 | /* | ||
1284 | * We need to make sure that the underlying kobj is | ||
1285 | * actually not referenced anymore by anybody before we | ||
1286 | * proceed with unloading. | ||
1287 | */ | ||
1288 | pr_debug("waiting for dropping of refcount\n"); | ||
1289 | wait_for_completion(cmp); | ||
1290 | pr_debug("wait complete\n"); | ||
1291 | } | ||
1257 | 1292 | ||
1258 | /* we need to make sure that the underlying kobj is actually | 1293 | /* |
1259 | * not referenced anymore by anybody before we proceed with | 1294 | * Perform the ->exit() even during light-weight tear-down, |
1260 | * unloading. | 1295 | * since this is a core component, and is essential for the |
1296 | * subsequent light-weight ->init() to succeed. | ||
1261 | */ | 1297 | */ |
1262 | pr_debug("waiting for dropping of refcount\n"); | ||
1263 | wait_for_completion(cmp); | ||
1264 | pr_debug("wait complete\n"); | ||
1265 | |||
1266 | if (cpufreq_driver->exit) | 1298 | if (cpufreq_driver->exit) |
1267 | cpufreq_driver->exit(data); | 1299 | cpufreq_driver->exit(data); |
1268 | 1300 | ||
1269 | cpufreq_policy_free(data); | 1301 | if (!frozen) |
1302 | cpufreq_policy_free(data); | ||
1270 | } else { | 1303 | } else { |
1271 | pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); | 1304 | |
1272 | cpufreq_cpu_put(data); | 1305 | if (!frozen) { |
1306 | pr_debug("%s: removing link, cpu: %d\n", __func__, cpu); | ||
1307 | cpufreq_cpu_put(data); | ||
1308 | } | ||
1309 | |||
1273 | if (cpufreq_driver->target) { | 1310 | if (cpufreq_driver->target) { |
1274 | __cpufreq_governor(data, CPUFREQ_GOV_START); | 1311 | __cpufreq_governor(data, CPUFREQ_GOV_START); |
1275 | __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); | 1312 | __cpufreq_governor(data, CPUFREQ_GOV_LIMITS); |