1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 /* Platform profile sysfs interface */ 4 5 #include <linux/acpi.h> 6 #include <linux/bits.h> 7 #include <linux/init.h> 8 #include <linux/kdev_t.h> 9 #include <linux/mutex.h> 10 #include <linux/platform_profile.h> 11 #include <linux/sysfs.h> 12 13 static DEFINE_MUTEX(profile_lock); 14 15 static const char * const profile_names[] = { 16 [PLATFORM_PROFILE_LOW_POWER] = "low-power", 17 [PLATFORM_PROFILE_COOL] = "cool", 18 [PLATFORM_PROFILE_QUIET] = "quiet", 19 [PLATFORM_PROFILE_BALANCED] = "balanced", 20 [PLATFORM_PROFILE_BALANCED_PERFORMANCE] = "balanced-performance", 21 [PLATFORM_PROFILE_PERFORMANCE] = "performance", 22 [PLATFORM_PROFILE_CUSTOM] = "custom", 23 }; 24 static_assert(ARRAY_SIZE(profile_names) == PLATFORM_PROFILE_LAST); 25 26 static DEFINE_IDA(platform_profile_ida); 27 28 /** 29 * _commmon_choices_show - Show the available profile choices 30 * @choices: The available profile choices 31 * @buf: The buffer to write to 32 * 33 * Return: The number of bytes written 34 */ 35 static ssize_t _commmon_choices_show(unsigned long *choices, char *buf) 36 { 37 int i, len = 0; 38 39 for_each_set_bit(i, choices, PLATFORM_PROFILE_LAST) { 40 if (len == 0) 41 len += sysfs_emit_at(buf, len, "%s", profile_names[i]); 42 else 43 len += sysfs_emit_at(buf, len, " %s", profile_names[i]); 44 } 45 len += sysfs_emit_at(buf, len, "\n"); 46 47 return len; 48 } 49 50 /** 51 * _store_class_profile - Set the profile for a class device 52 * @dev: The class device 53 * @data: The profile to set 54 * 55 * Return: 0 on success, -errno on failure 56 */ 57 static int _store_class_profile(struct device *dev, void *data) 58 { 59 struct platform_profile_handler *handler; 60 int *bit = (int *)data; 61 62 lockdep_assert_held(&profile_lock); 63 handler = dev_get_drvdata(dev); 64 if (!test_bit(*bit, handler->choices)) 65 return -EOPNOTSUPP; 66 67 return handler->profile_set(handler, *bit); 68 } 69 70 /** 71 * _notify_class_profile - Notify the class device of a profile change 72 * @dev: The class device 73 * @data: Unused 74 * 75 * Return: 0 on success, -errno on failure 76 */ 77 static int _notify_class_profile(struct device *dev, void *data) 78 { 79 struct platform_profile_handler *handler = dev_get_drvdata(dev); 80 81 lockdep_assert_held(&profile_lock); 82 sysfs_notify(&handler->class_dev->kobj, NULL, "profile"); 83 kobject_uevent(&handler->class_dev->kobj, KOBJ_CHANGE); 84 85 return 0; 86 } 87 88 /** 89 * get_class_profile - Show the current profile for a class device 90 * @dev: The class device 91 * @profile: The profile to return 92 * 93 * Return: 0 on success, -errno on failure 94 */ 95 static int get_class_profile(struct device *dev, 96 enum platform_profile_option *profile) 97 { 98 struct platform_profile_handler *handler; 99 enum platform_profile_option val; 100 int err; 101 102 lockdep_assert_held(&profile_lock); 103 handler = dev_get_drvdata(dev); 104 err = handler->profile_get(handler, &val); 105 if (err) { 106 pr_err("Failed to get profile for handler %s\n", handler->name); 107 return err; 108 } 109 110 if (WARN_ON(val >= PLATFORM_PROFILE_LAST)) 111 return -EINVAL; 112 *profile = val; 113 114 return 0; 115 } 116 117 /** 118 * name_show - Show the name of the profile handler 119 * @dev: The device 120 * @attr: The attribute 121 * @buf: The buffer to write to 122 * 123 * Return: The number of bytes written 124 */ 125 static ssize_t name_show(struct device *dev, struct device_attribute *attr, char *buf) 126 { 127 struct platform_profile_handler *handler = dev_get_drvdata(dev); 128 129 return sysfs_emit(buf, "%s\n", handler->name); 130 } 131 static DEVICE_ATTR_RO(name); 132 133 /** 134 * choices_show - Show the available profile choices 135 * @dev: The device 136 * @attr: The attribute 137 * @buf: The buffer to write to 138 * 139 * Return: The number of bytes written 140 */ 141 static ssize_t choices_show(struct device *dev, 142 struct device_attribute *attr, 143 char *buf) 144 { 145 struct platform_profile_handler *handler = dev_get_drvdata(dev); 146 147 return _commmon_choices_show(handler->choices, buf); 148 } 149 static DEVICE_ATTR_RO(choices); 150 151 /** 152 * profile_show - Show the current profile for a class device 153 * @dev: The device 154 * @attr: The attribute 155 * @buf: The buffer to write to 156 * 157 * Return: The number of bytes written 158 */ 159 static ssize_t profile_show(struct device *dev, 160 struct device_attribute *attr, 161 char *buf) 162 { 163 enum platform_profile_option profile = PLATFORM_PROFILE_LAST; 164 int err; 165 166 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &profile_lock) { 167 err = get_class_profile(dev, &profile); 168 if (err) 169 return err; 170 } 171 172 return sysfs_emit(buf, "%s\n", profile_names[profile]); 173 } 174 175 /** 176 * profile_store - Set the profile for a class device 177 * @dev: The device 178 * @attr: The attribute 179 * @buf: The buffer to read from 180 * @count: The number of bytes to read 181 * 182 * Return: The number of bytes read 183 */ 184 static ssize_t profile_store(struct device *dev, 185 struct device_attribute *attr, 186 const char *buf, size_t count) 187 { 188 int index, ret; 189 190 index = sysfs_match_string(profile_names, buf); 191 if (index < 0) 192 return -EINVAL; 193 194 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &profile_lock) { 195 ret = _store_class_profile(dev, &index); 196 if (ret) 197 return ret; 198 } 199 200 sysfs_notify(acpi_kobj, NULL, "platform_profile"); 201 202 return count; 203 } 204 static DEVICE_ATTR_RW(profile); 205 206 static struct attribute *profile_attrs[] = { 207 &dev_attr_name.attr, 208 &dev_attr_choices.attr, 209 &dev_attr_profile.attr, 210 NULL 211 }; 212 ATTRIBUTE_GROUPS(profile); 213 214 static const struct class platform_profile_class = { 215 .name = "platform-profile", 216 .dev_groups = profile_groups, 217 }; 218 219 /** 220 * _aggregate_choices - Aggregate the available profile choices 221 * @dev: The device 222 * @data: The available profile choices 223 * 224 * Return: 0 on success, -errno on failure 225 */ 226 static int _aggregate_choices(struct device *dev, void *data) 227 { 228 struct platform_profile_handler *handler; 229 unsigned long *aggregate = data; 230 231 lockdep_assert_held(&profile_lock); 232 handler = dev_get_drvdata(dev); 233 if (test_bit(PLATFORM_PROFILE_LAST, aggregate)) 234 bitmap_copy(aggregate, handler->choices, PLATFORM_PROFILE_LAST); 235 else 236 bitmap_and(aggregate, handler->choices, aggregate, PLATFORM_PROFILE_LAST); 237 238 return 0; 239 } 240 241 /** 242 * platform_profile_choices_show - Show the available profile choices for legacy sysfs interface 243 * @dev: The device 244 * @attr: The attribute 245 * @buf: The buffer to write to 246 * 247 * Return: The number of bytes written 248 */ 249 static ssize_t platform_profile_choices_show(struct device *dev, 250 struct device_attribute *attr, 251 char *buf) 252 { 253 unsigned long aggregate[BITS_TO_LONGS(PLATFORM_PROFILE_LAST)]; 254 int err; 255 256 set_bit(PLATFORM_PROFILE_LAST, aggregate); 257 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &profile_lock) { 258 err = class_for_each_device(&platform_profile_class, NULL, 259 aggregate, _aggregate_choices); 260 if (err) 261 return err; 262 } 263 264 /* no profile handler registered any more */ 265 if (bitmap_empty(aggregate, PLATFORM_PROFILE_LAST)) 266 return -EINVAL; 267 268 return _commmon_choices_show(aggregate, buf); 269 } 270 271 /** 272 * _aggregate_profiles - Aggregate the profiles for legacy sysfs interface 273 * @dev: The device 274 * @data: The profile to return 275 * 276 * Return: 0 on success, -errno on failure 277 */ 278 static int _aggregate_profiles(struct device *dev, void *data) 279 { 280 enum platform_profile_option *profile = data; 281 enum platform_profile_option val; 282 int err; 283 284 err = get_class_profile(dev, &val); 285 if (err) 286 return err; 287 288 if (*profile != PLATFORM_PROFILE_LAST && *profile != val) 289 *profile = PLATFORM_PROFILE_CUSTOM; 290 else 291 *profile = val; 292 293 return 0; 294 } 295 296 /** 297 * _store_and_notify - Store and notify a class from legacy sysfs interface 298 * @dev: The device 299 * @data: The profile to return 300 * 301 * Return: 0 on success, -errno on failure 302 */ 303 static int _store_and_notify(struct device *dev, void *data) 304 { 305 enum platform_profile_option *profile = data; 306 int err; 307 308 err = _store_class_profile(dev, profile); 309 if (err) 310 return err; 311 return _notify_class_profile(dev, NULL); 312 } 313 314 /** 315 * platform_profile_show - Show the current profile for legacy sysfs interface 316 * @dev: The device 317 * @attr: The attribute 318 * @buf: The buffer to write to 319 * 320 * Return: The number of bytes written 321 */ 322 static ssize_t platform_profile_show(struct device *dev, 323 struct device_attribute *attr, 324 char *buf) 325 { 326 enum platform_profile_option profile = PLATFORM_PROFILE_LAST; 327 int err; 328 329 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &profile_lock) { 330 err = class_for_each_device(&platform_profile_class, NULL, 331 &profile, _aggregate_profiles); 332 if (err) 333 return err; 334 } 335 336 /* no profile handler registered any more */ 337 if (profile == PLATFORM_PROFILE_LAST) 338 return -EINVAL; 339 340 return sysfs_emit(buf, "%s\n", profile_names[profile]); 341 } 342 343 /** 344 * platform_profile_store - Set the profile for legacy sysfs interface 345 * @dev: The device 346 * @attr: The attribute 347 * @buf: The buffer to read from 348 * @count: The number of bytes to read 349 * 350 * Return: The number of bytes read 351 */ 352 static ssize_t platform_profile_store(struct device *dev, 353 struct device_attribute *attr, 354 const char *buf, size_t count) 355 { 356 unsigned long choices[BITS_TO_LONGS(PLATFORM_PROFILE_LAST)]; 357 int ret; 358 int i; 359 360 /* Scan for a matching profile */ 361 i = sysfs_match_string(profile_names, buf); 362 if (i < 0 || i == PLATFORM_PROFILE_CUSTOM) 363 return -EINVAL; 364 set_bit(PLATFORM_PROFILE_LAST, choices); 365 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &profile_lock) { 366 ret = class_for_each_device(&platform_profile_class, NULL, 367 choices, _aggregate_choices); 368 if (ret) 369 return ret; 370 if (!test_bit(i, choices)) 371 return -EOPNOTSUPP; 372 373 ret = class_for_each_device(&platform_profile_class, NULL, &i, 374 _store_and_notify); 375 if (ret) 376 return ret; 377 } 378 379 sysfs_notify(acpi_kobj, NULL, "platform_profile"); 380 381 return count; 382 } 383 384 static DEVICE_ATTR_RO(platform_profile_choices); 385 static DEVICE_ATTR_RW(platform_profile); 386 387 static struct attribute *platform_profile_attrs[] = { 388 &dev_attr_platform_profile_choices.attr, 389 &dev_attr_platform_profile.attr, 390 NULL 391 }; 392 393 static int profile_class_registered(struct device *dev, const void *data) 394 { 395 return 1; 396 } 397 398 static umode_t profile_class_is_visible(struct kobject *kobj, struct attribute *attr, int idx) 399 { 400 if (!class_find_device(&platform_profile_class, NULL, NULL, profile_class_registered)) 401 return 0; 402 return attr->mode; 403 } 404 405 static const struct attribute_group platform_profile_group = { 406 .attrs = platform_profile_attrs, 407 .is_visible = profile_class_is_visible, 408 }; 409 410 void platform_profile_notify(struct platform_profile_handler *pprof) 411 { 412 scoped_cond_guard(mutex_intr, return, &profile_lock) { 413 _notify_class_profile(pprof->class_dev, NULL); 414 } 415 sysfs_notify(acpi_kobj, NULL, "platform_profile"); 416 } 417 EXPORT_SYMBOL_GPL(platform_profile_notify); 418 419 int platform_profile_cycle(void) 420 { 421 enum platform_profile_option next = PLATFORM_PROFILE_LAST; 422 enum platform_profile_option profile = PLATFORM_PROFILE_LAST; 423 unsigned long choices[BITS_TO_LONGS(PLATFORM_PROFILE_LAST)]; 424 int err; 425 426 set_bit(PLATFORM_PROFILE_LAST, choices); 427 scoped_cond_guard(mutex_intr, return -ERESTARTSYS, &profile_lock) { 428 err = class_for_each_device(&platform_profile_class, NULL, 429 &profile, _aggregate_profiles); 430 if (err) 431 return err; 432 433 if (profile == PLATFORM_PROFILE_CUSTOM || 434 profile == PLATFORM_PROFILE_LAST) 435 return -EINVAL; 436 437 err = class_for_each_device(&platform_profile_class, NULL, 438 choices, _aggregate_choices); 439 if (err) 440 return err; 441 442 /* never iterate into a custom if all drivers supported it */ 443 clear_bit(PLATFORM_PROFILE_CUSTOM, choices); 444 445 next = find_next_bit_wrap(choices, 446 PLATFORM_PROFILE_LAST, 447 profile + 1); 448 449 err = class_for_each_device(&platform_profile_class, NULL, &next, 450 _store_and_notify); 451 452 if (err) 453 return err; 454 } 455 456 sysfs_notify(acpi_kobj, NULL, "platform_profile"); 457 458 return 0; 459 } 460 EXPORT_SYMBOL_GPL(platform_profile_cycle); 461 462 int platform_profile_register(struct platform_profile_handler *pprof) 463 { 464 int err; 465 466 /* Sanity check the profile handler */ 467 if (!pprof || bitmap_empty(pprof->choices, PLATFORM_PROFILE_LAST) || 468 !pprof->profile_set || !pprof->profile_get) { 469 pr_err("platform_profile: handler is invalid\n"); 470 return -EINVAL; 471 } 472 473 guard(mutex)(&profile_lock); 474 475 /* create class interface for individual handler */ 476 pprof->minor = ida_alloc(&platform_profile_ida, GFP_KERNEL); 477 if (pprof->minor < 0) 478 return pprof->minor; 479 pprof->class_dev = device_create(&platform_profile_class, pprof->dev, 480 MKDEV(0, 0), pprof, "platform-profile-%d", 481 pprof->minor); 482 if (IS_ERR(pprof->class_dev)) { 483 err = PTR_ERR(pprof->class_dev); 484 goto cleanup_ida; 485 } 486 487 sysfs_notify(acpi_kobj, NULL, "platform_profile"); 488 489 err = sysfs_update_group(acpi_kobj, &platform_profile_group); 490 if (err) 491 goto cleanup_cur; 492 493 return 0; 494 495 cleanup_cur: 496 device_unregister(pprof->class_dev); 497 498 cleanup_ida: 499 ida_free(&platform_profile_ida, pprof->minor); 500 501 return err; 502 } 503 EXPORT_SYMBOL_GPL(platform_profile_register); 504 505 int platform_profile_remove(struct platform_profile_handler *pprof) 506 { 507 int id; 508 guard(mutex)(&profile_lock); 509 510 id = pprof->minor; 511 device_unregister(pprof->class_dev); 512 ida_free(&platform_profile_ida, id); 513 514 sysfs_notify(acpi_kobj, NULL, "platform_profile"); 515 516 sysfs_update_group(acpi_kobj, &platform_profile_group); 517 518 return 0; 519 } 520 EXPORT_SYMBOL_GPL(platform_profile_remove); 521 522 static int __init platform_profile_init(void) 523 { 524 int err; 525 526 err = class_register(&platform_profile_class); 527 if (err) 528 return err; 529 530 err = sysfs_create_group(acpi_kobj, &platform_profile_group); 531 if (err) 532 class_unregister(&platform_profile_class); 533 534 return err; 535 } 536 537 static void __exit platform_profile_exit(void) 538 { 539 sysfs_remove_group(acpi_kobj, &platform_profile_group); 540 class_unregister(&platform_profile_class); 541 } 542 module_init(platform_profile_init); 543 module_exit(platform_profile_exit); 544 545 MODULE_AUTHOR("Mark Pearson <[email protected]>"); 546 MODULE_DESCRIPTION("ACPI platform profile sysfs interface"); 547 MODULE_LICENSE("GPL"); 548