diff options
author | Jean Delvare <khali@linux-fr.org> | 2011-07-28 16:48:42 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2011-08-02 14:51:57 -0400 |
commit | 31f5396ad3bde23c8416e8d23ba425e27f413314 (patch) | |
tree | 923ec07b9afff6cf952cbc2bd5f26bf490793c6f /drivers/thermal | |
parent | 0d97d7a494d43be77f57e688369be0aae33d1ade (diff) |
thermal: make THERMAL_HWMON implementation fully internal
THERMAL_HWMON is implemented inside the thermal_sys driver and has no
effect on drivers implementing thermal zones, so they shouldn't see
anything related to it in <linux/thermal.h>. Making the THERMAL_HWMON
implementation fully internal has two advantages beyond the cleaner
design:
* This avoids rebuilding all thermal drivers if the THERMAL_HWMON
implementation changes, or if CONFIG_THERMAL_HWMON gets enabled or
disabled.
* This avoids breaking the thermal kABI in these cases too, which should
make distributions happy.
The only drawback I can see is slightly higher memory fragmentation, as
the number of kzalloc() calls will increase by one per thermal zone. But
I doubt it will be a problem in practice, as I've never seen a system with
more than two thermal zones.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Cc: Rene Herman <rene.herman@gmail.com>
Acked-by: Guenter Roeck <guenter.roeck@ericsson.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/thermal')
-rw-r--r-- | drivers/thermal/thermal_sys.c | 117 |
1 files changed, 92 insertions, 25 deletions
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index b6353d61fac..708f8e92771 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c | |||
@@ -420,6 +420,29 @@ thermal_cooling_device_trip_point_show(struct device *dev, | |||
420 | 420 | ||
421 | /* hwmon sys I/F */ | 421 | /* hwmon sys I/F */ |
422 | #include <linux/hwmon.h> | 422 | #include <linux/hwmon.h> |
423 | |||
424 | /* thermal zone devices with the same type share one hwmon device */ | ||
425 | struct thermal_hwmon_device { | ||
426 | char type[THERMAL_NAME_LENGTH]; | ||
427 | struct device *device; | ||
428 | int count; | ||
429 | struct list_head tz_list; | ||
430 | struct list_head node; | ||
431 | }; | ||
432 | |||
433 | struct thermal_hwmon_attr { | ||
434 | struct device_attribute attr; | ||
435 | char name[16]; | ||
436 | }; | ||
437 | |||
438 | /* one temperature input for each thermal zone */ | ||
439 | struct thermal_hwmon_temp { | ||
440 | struct list_head hwmon_node; | ||
441 | struct thermal_zone_device *tz; | ||
442 | struct thermal_hwmon_attr temp_input; /* hwmon sys attr */ | ||
443 | struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */ | ||
444 | }; | ||
445 | |||
423 | static LIST_HEAD(thermal_hwmon_list); | 446 | static LIST_HEAD(thermal_hwmon_list); |
424 | 447 | ||
425 | static ssize_t | 448 | static ssize_t |
@@ -437,9 +460,10 @@ temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) | |||
437 | int ret; | 460 | int ret; |
438 | struct thermal_hwmon_attr *hwmon_attr | 461 | struct thermal_hwmon_attr *hwmon_attr |
439 | = container_of(attr, struct thermal_hwmon_attr, attr); | 462 | = container_of(attr, struct thermal_hwmon_attr, attr); |
440 | struct thermal_zone_device *tz | 463 | struct thermal_hwmon_temp *temp |
441 | = container_of(hwmon_attr, struct thermal_zone_device, | 464 | = container_of(hwmon_attr, struct thermal_hwmon_temp, |
442 | temp_input); | 465 | temp_input); |
466 | struct thermal_zone_device *tz = temp->tz; | ||
443 | 467 | ||
444 | ret = tz->ops->get_temp(tz, &temperature); | 468 | ret = tz->ops->get_temp(tz, &temperature); |
445 | 469 | ||
@@ -455,9 +479,10 @@ temp_crit_show(struct device *dev, struct device_attribute *attr, | |||
455 | { | 479 | { |
456 | struct thermal_hwmon_attr *hwmon_attr | 480 | struct thermal_hwmon_attr *hwmon_attr |
457 | = container_of(attr, struct thermal_hwmon_attr, attr); | 481 | = container_of(attr, struct thermal_hwmon_attr, attr); |
458 | struct thermal_zone_device *tz | 482 | struct thermal_hwmon_temp *temp |
459 | = container_of(hwmon_attr, struct thermal_zone_device, | 483 | = container_of(hwmon_attr, struct thermal_hwmon_temp, |
460 | temp_crit); | 484 | temp_crit); |
485 | struct thermal_zone_device *tz = temp->tz; | ||
461 | long temperature; | 486 | long temperature; |
462 | int ret; | 487 | int ret; |
463 | 488 | ||
@@ -485,10 +510,29 @@ thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz) | |||
485 | return NULL; | 510 | return NULL; |
486 | } | 511 | } |
487 | 512 | ||
513 | /* Find the temperature input matching a given thermal zone */ | ||
514 | static struct thermal_hwmon_temp * | ||
515 | thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon, | ||
516 | const struct thermal_zone_device *tz) | ||
517 | { | ||
518 | struct thermal_hwmon_temp *temp; | ||
519 | |||
520 | mutex_lock(&thermal_list_lock); | ||
521 | list_for_each_entry(temp, &hwmon->tz_list, hwmon_node) | ||
522 | if (temp->tz == tz) { | ||
523 | mutex_unlock(&thermal_list_lock); | ||
524 | return temp; | ||
525 | } | ||
526 | mutex_unlock(&thermal_list_lock); | ||
527 | |||
528 | return NULL; | ||
529 | } | ||
530 | |||
488 | static int | 531 | static int |
489 | thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) | 532 | thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) |
490 | { | 533 | { |
491 | struct thermal_hwmon_device *hwmon; | 534 | struct thermal_hwmon_device *hwmon; |
535 | struct thermal_hwmon_temp *temp; | ||
492 | int new_hwmon_device = 1; | 536 | int new_hwmon_device = 1; |
493 | int result; | 537 | int result; |
494 | 538 | ||
@@ -515,30 +559,36 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) | |||
515 | goto free_mem; | 559 | goto free_mem; |
516 | 560 | ||
517 | register_sys_interface: | 561 | register_sys_interface: |
518 | tz->hwmon = hwmon; | 562 | temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL); |
563 | if (!temp) { | ||
564 | result = -ENOMEM; | ||
565 | goto unregister_name; | ||
566 | } | ||
567 | |||
568 | temp->tz = tz; | ||
519 | hwmon->count++; | 569 | hwmon->count++; |
520 | 570 | ||
521 | snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH, | 571 | snprintf(temp->temp_input.name, THERMAL_NAME_LENGTH, |
522 | "temp%d_input", hwmon->count); | 572 | "temp%d_input", hwmon->count); |
523 | tz->temp_input.attr.attr.name = tz->temp_input.name; | 573 | temp->temp_input.attr.attr.name = temp->temp_input.name; |
524 | tz->temp_input.attr.attr.mode = 0444; | 574 | temp->temp_input.attr.attr.mode = 0444; |
525 | tz->temp_input.attr.show = temp_input_show; | 575 | temp->temp_input.attr.show = temp_input_show; |
526 | sysfs_attr_init(&tz->temp_input.attr.attr); | 576 | sysfs_attr_init(&temp->temp_input.attr.attr); |
527 | result = device_create_file(hwmon->device, &tz->temp_input.attr); | 577 | result = device_create_file(hwmon->device, &temp->temp_input.attr); |
528 | if (result) | 578 | if (result) |
529 | goto unregister_name; | 579 | goto free_temp_mem; |
530 | 580 | ||
531 | if (tz->ops->get_crit_temp) { | 581 | if (tz->ops->get_crit_temp) { |
532 | unsigned long temperature; | 582 | unsigned long temperature; |
533 | if (!tz->ops->get_crit_temp(tz, &temperature)) { | 583 | if (!tz->ops->get_crit_temp(tz, &temperature)) { |
534 | snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH, | 584 | snprintf(temp->temp_crit.name, THERMAL_NAME_LENGTH, |
535 | "temp%d_crit", hwmon->count); | 585 | "temp%d_crit", hwmon->count); |
536 | tz->temp_crit.attr.attr.name = tz->temp_crit.name; | 586 | temp->temp_crit.attr.attr.name = temp->temp_crit.name; |
537 | tz->temp_crit.attr.attr.mode = 0444; | 587 | temp->temp_crit.attr.attr.mode = 0444; |
538 | tz->temp_crit.attr.show = temp_crit_show; | 588 | temp->temp_crit.attr.show = temp_crit_show; |
539 | sysfs_attr_init(&tz->temp_crit.attr.attr); | 589 | sysfs_attr_init(&temp->temp_crit.attr.attr); |
540 | result = device_create_file(hwmon->device, | 590 | result = device_create_file(hwmon->device, |
541 | &tz->temp_crit.attr); | 591 | &temp->temp_crit.attr); |
542 | if (result) | 592 | if (result) |
543 | goto unregister_input; | 593 | goto unregister_input; |
544 | } | 594 | } |
@@ -547,13 +597,15 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) | |||
547 | mutex_lock(&thermal_list_lock); | 597 | mutex_lock(&thermal_list_lock); |
548 | if (new_hwmon_device) | 598 | if (new_hwmon_device) |
549 | list_add_tail(&hwmon->node, &thermal_hwmon_list); | 599 | list_add_tail(&hwmon->node, &thermal_hwmon_list); |
550 | list_add_tail(&tz->hwmon_node, &hwmon->tz_list); | 600 | list_add_tail(&temp->hwmon_node, &hwmon->tz_list); |
551 | mutex_unlock(&thermal_list_lock); | 601 | mutex_unlock(&thermal_list_lock); |
552 | 602 | ||
553 | return 0; | 603 | return 0; |
554 | 604 | ||
555 | unregister_input: | 605 | unregister_input: |
556 | device_remove_file(hwmon->device, &tz->temp_input.attr); | 606 | device_remove_file(hwmon->device, &temp->temp_input.attr); |
607 | free_temp_mem: | ||
608 | kfree(temp); | ||
557 | unregister_name: | 609 | unregister_name: |
558 | if (new_hwmon_device) { | 610 | if (new_hwmon_device) { |
559 | device_remove_file(hwmon->device, &dev_attr_name); | 611 | device_remove_file(hwmon->device, &dev_attr_name); |
@@ -569,15 +621,30 @@ thermal_add_hwmon_sysfs(struct thermal_zone_device *tz) | |||
569 | static void | 621 | static void |
570 | thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) | 622 | thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz) |
571 | { | 623 | { |
572 | struct thermal_hwmon_device *hwmon = tz->hwmon; | 624 | struct thermal_hwmon_device *hwmon; |
625 | struct thermal_hwmon_temp *temp; | ||
626 | |||
627 | hwmon = thermal_hwmon_lookup_by_type(tz); | ||
628 | if (unlikely(!hwmon)) { | ||
629 | /* Should never happen... */ | ||
630 | dev_dbg(&tz->device, "hwmon device lookup failed!\n"); | ||
631 | return; | ||
632 | } | ||
633 | |||
634 | temp = thermal_hwmon_lookup_temp(hwmon, tz); | ||
635 | if (unlikely(!temp)) { | ||
636 | /* Should never happen... */ | ||
637 | dev_dbg(&tz->device, "temperature input lookup failed!\n"); | ||
638 | return; | ||
639 | } | ||
573 | 640 | ||
574 | tz->hwmon = NULL; | 641 | device_remove_file(hwmon->device, &temp->temp_input.attr); |
575 | device_remove_file(hwmon->device, &tz->temp_input.attr); | ||
576 | if (tz->ops->get_crit_temp) | 642 | if (tz->ops->get_crit_temp) |
577 | device_remove_file(hwmon->device, &tz->temp_crit.attr); | 643 | device_remove_file(hwmon->device, &temp->temp_crit.attr); |
578 | 644 | ||
579 | mutex_lock(&thermal_list_lock); | 645 | mutex_lock(&thermal_list_lock); |
580 | list_del(&tz->hwmon_node); | 646 | list_del(&temp->hwmon_node); |
647 | kfree(temp); | ||
581 | if (!list_empty(&hwmon->tz_list)) { | 648 | if (!list_empty(&hwmon->tz_list)) { |
582 | mutex_unlock(&thermal_list_lock); | 649 | mutex_unlock(&thermal_list_lock); |
583 | return; | 650 | return; |