diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq.c')
| -rw-r--r-- | drivers/cpufreq/cpufreq.c | 75 |
1 files changed, 54 insertions, 21 deletions
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index bc1088d9b379..b3df613ae4ec 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
| @@ -284,39 +284,69 @@ EXPORT_SYMBOL_GPL(cpufreq_notify_transition); | |||
| 284 | * SYSFS INTERFACE * | 284 | * SYSFS INTERFACE * |
| 285 | *********************************************************************/ | 285 | *********************************************************************/ |
| 286 | 286 | ||
| 287 | static struct cpufreq_governor *__find_governor(const char *str_governor) | ||
| 288 | { | ||
| 289 | struct cpufreq_governor *t; | ||
| 290 | |||
| 291 | list_for_each_entry(t, &cpufreq_governor_list, governor_list) | ||
| 292 | if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) | ||
| 293 | return t; | ||
| 294 | |||
| 295 | return NULL; | ||
| 296 | } | ||
| 297 | |||
| 287 | /** | 298 | /** |
| 288 | * cpufreq_parse_governor - parse a governor string | 299 | * cpufreq_parse_governor - parse a governor string |
| 289 | */ | 300 | */ |
| 290 | static int cpufreq_parse_governor (char *str_governor, unsigned int *policy, | 301 | static int cpufreq_parse_governor (char *str_governor, unsigned int *policy, |
| 291 | struct cpufreq_governor **governor) | 302 | struct cpufreq_governor **governor) |
| 292 | { | 303 | { |
| 304 | int err = -EINVAL; | ||
| 305 | |||
| 293 | if (!cpufreq_driver) | 306 | if (!cpufreq_driver) |
| 294 | return -EINVAL; | 307 | goto out; |
| 308 | |||
| 295 | if (cpufreq_driver->setpolicy) { | 309 | if (cpufreq_driver->setpolicy) { |
| 296 | if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { | 310 | if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { |
| 297 | *policy = CPUFREQ_POLICY_PERFORMANCE; | 311 | *policy = CPUFREQ_POLICY_PERFORMANCE; |
| 298 | return 0; | 312 | err = 0; |
| 299 | } else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) { | 313 | } else if (!strnicmp(str_governor, "powersave", CPUFREQ_NAME_LEN)) { |
| 300 | *policy = CPUFREQ_POLICY_POWERSAVE; | 314 | *policy = CPUFREQ_POLICY_POWERSAVE; |
| 301 | return 0; | 315 | err = 0; |
| 302 | } | 316 | } |
| 303 | return -EINVAL; | 317 | } else if (cpufreq_driver->target) { |
| 304 | } else { | ||
| 305 | struct cpufreq_governor *t; | 318 | struct cpufreq_governor *t; |
| 319 | |||
| 306 | mutex_lock(&cpufreq_governor_mutex); | 320 | mutex_lock(&cpufreq_governor_mutex); |
| 307 | if (!cpufreq_driver || !cpufreq_driver->target) | 321 | |
| 308 | goto out; | 322 | t = __find_governor(str_governor); |
| 309 | list_for_each_entry(t, &cpufreq_governor_list, governor_list) { | 323 | |
| 310 | if (!strnicmp(str_governor,t->name,CPUFREQ_NAME_LEN)) { | 324 | if (t == NULL) { |
| 311 | *governor = t; | 325 | char *name = kasprintf(GFP_KERNEL, "cpufreq_%s", str_governor); |
| 326 | |||
| 327 | if (name) { | ||
| 328 | int ret; | ||
| 329 | |||
| 312 | mutex_unlock(&cpufreq_governor_mutex); | 330 | mutex_unlock(&cpufreq_governor_mutex); |
| 313 | return 0; | 331 | ret = request_module(name); |
| 332 | mutex_lock(&cpufreq_governor_mutex); | ||
| 333 | |||
| 334 | if (ret == 0) | ||
| 335 | t = __find_governor(str_governor); | ||
| 314 | } | 336 | } |
| 337 | |||
| 338 | kfree(name); | ||
| 315 | } | 339 | } |
| 316 | out: | 340 | |
| 341 | if (t != NULL) { | ||
| 342 | *governor = t; | ||
| 343 | err = 0; | ||
| 344 | } | ||
| 345 | |||
| 317 | mutex_unlock(&cpufreq_governor_mutex); | 346 | mutex_unlock(&cpufreq_governor_mutex); |
| 318 | } | 347 | } |
| 319 | return -EINVAL; | 348 | out: |
| 349 | return err; | ||
| 320 | } | 350 | } |
| 321 | 351 | ||
| 322 | 352 | ||
| @@ -1265,23 +1295,21 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) | |||
| 1265 | 1295 | ||
| 1266 | int cpufreq_register_governor(struct cpufreq_governor *governor) | 1296 | int cpufreq_register_governor(struct cpufreq_governor *governor) |
| 1267 | { | 1297 | { |
| 1268 | struct cpufreq_governor *t; | 1298 | int err; |
| 1269 | 1299 | ||
| 1270 | if (!governor) | 1300 | if (!governor) |
| 1271 | return -EINVAL; | 1301 | return -EINVAL; |
| 1272 | 1302 | ||
| 1273 | mutex_lock(&cpufreq_governor_mutex); | 1303 | mutex_lock(&cpufreq_governor_mutex); |
| 1274 | 1304 | ||
| 1275 | list_for_each_entry(t, &cpufreq_governor_list, governor_list) { | 1305 | err = -EBUSY; |
| 1276 | if (!strnicmp(governor->name,t->name,CPUFREQ_NAME_LEN)) { | 1306 | if (__find_governor(governor->name) == NULL) { |
| 1277 | mutex_unlock(&cpufreq_governor_mutex); | 1307 | err = 0; |
| 1278 | return -EBUSY; | 1308 | list_add(&governor->governor_list, &cpufreq_governor_list); |
| 1279 | } | ||
| 1280 | } | 1309 | } |
| 1281 | list_add(&governor->governor_list, &cpufreq_governor_list); | ||
| 1282 | 1310 | ||
| 1283 | mutex_unlock(&cpufreq_governor_mutex); | 1311 | mutex_unlock(&cpufreq_governor_mutex); |
| 1284 | return 0; | 1312 | return err; |
| 1285 | } | 1313 | } |
| 1286 | EXPORT_SYMBOL_GPL(cpufreq_register_governor); | 1314 | EXPORT_SYMBOL_GPL(cpufreq_register_governor); |
| 1287 | 1315 | ||
| @@ -1343,6 +1371,11 @@ static int __cpufreq_set_policy(struct cpufreq_policy *data, struct cpufreq_poli | |||
| 1343 | 1371 | ||
| 1344 | memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo)); | 1372 | memcpy(&policy->cpuinfo, &data->cpuinfo, sizeof(struct cpufreq_cpuinfo)); |
| 1345 | 1373 | ||
| 1374 | if (policy->min > data->min && policy->min > policy->max) { | ||
| 1375 | ret = -EINVAL; | ||
| 1376 | goto error_out; | ||
| 1377 | } | ||
| 1378 | |||
| 1346 | /* verify the cpu speed can be set within this limit */ | 1379 | /* verify the cpu speed can be set within this limit */ |
| 1347 | ret = cpufreq_driver->verify(policy); | 1380 | ret = cpufreq_driver->verify(policy); |
| 1348 | if (ret) | 1381 | if (ret) |
