aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenrique de Moraes Holschuh <hmh@hmh.eng.br>2007-04-24 10:48:17 -0400
committerLen Brown <len.brown@intel.com>2007-04-25 02:00:27 -0400
commitfe98a52ce7540fb3a19d57488a08864110cf4d5c (patch)
tree8a9ba42e5a4d4ff208297cd18782aa85fef27164
parent2c37aa4e22dd55070c608290c5031f2ee93e69ce (diff)
ACPI: thinkpad-acpi: add sysfs support to fan subdriver
Export sysfs attributes to monitor and control the internal thinkpad fan (some thinkpads have more than one fan, but thinkpad-acpi doesn't support the second fan yet). The sysfs interface follows the hwmon design guide for fan devices. Also, fix some stray "thermal" files in the fan procfs description that have been there forever, and officially support "full-speed" as the name for the PWM-disabled state of the fan controller to keep it in line with the hwmon interface. It is much better a name for that mode than the unobvious "disengaged" anyway. Change the procfs interface to also accept full-speed as a fan level, but still report it as disengaged for backwards compatibility. Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br> Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r--Documentation/thinkpad-acpi.txt157
-rw-r--r--drivers/misc/thinkpad_acpi.c326
-rw-r--r--drivers/misc/thinkpad_acpi.h6
3 files changed, 415 insertions, 74 deletions
diff --git a/Documentation/thinkpad-acpi.txt b/Documentation/thinkpad-acpi.txt
index 80c0bf28e392..339ce21e59df 100644
--- a/Documentation/thinkpad-acpi.txt
+++ b/Documentation/thinkpad-acpi.txt
@@ -642,8 +642,11 @@ distinct. The unmute the volume after the mute command, use either the
642up or down command (the level command will not unmute the volume). 642up or down command (the level command will not unmute the volume).
643The current volume level and mute state is shown in the file. 643The current volume level and mute state is shown in the file.
644 644
645EXPERIMENTAL: fan speed, fan enable/disable -- /proc/acpi/ibm/fan 645EXPERIMENTAL: fan speed, fan enable/disable
646----------------------------------------------------------------- 646-------------------------------------------
647
648procfs: /proc/acpi/ibm/fan
649sysfs device attributes: (hwmon) fan_input, pwm1, pwm1_enable
647 650
648This feature is marked EXPERIMENTAL because the implementation 651This feature is marked EXPERIMENTAL because the implementation
649directly accesses hardware registers and may not work as expected. USE 652directly accesses hardware registers and may not work as expected. USE
@@ -656,27 +659,26 @@ from the hardware registers of the embedded controller. This is known
656to work on later R, T and X series ThinkPads but may show a bogus 659to work on later R, T and X series ThinkPads but may show a bogus
657value on other models. 660value on other models.
658 661
659Most ThinkPad fans work in "levels". Level 0 stops the fan. The higher 662Fan levels:
660the level, the higher the fan speed, although adjacent levels often map
661to the same fan speed. 7 is the highest level, where the fan reaches
662the maximum recommended speed. Level "auto" means the EC changes the
663fan level according to some internal algorithm, usually based on
664readings from the thermal sensors. Level "disengaged" means the EC
665disables the speed-locked closed-loop fan control, and drives the fan as
666fast as it can go, which might exceed hardware limits, so use this level
667with caution.
668 663
669The fan usually ramps up or down slowly from one speed to another, 664Most ThinkPad fans work in "levels" at the firmware interface. Level 0
670and it is normal for the EC to take several seconds to react to fan 665stops the fan. The higher the level, the higher the fan speed, although
671commands. 666adjacent levels often map to the same fan speed. 7 is the highest
667level, where the fan reaches the maximum recommended speed.
672 668
673The fan may be enabled or disabled with the following commands: 669Level "auto" means the EC changes the fan level according to some
670internal algorithm, usually based on readings from the thermal sensors.
674 671
675 echo enable >/proc/acpi/ibm/fan 672There is also a "full-speed" level, also known as "disengaged" level.
676 echo disable >/proc/acpi/ibm/fan 673In this level, the EC disables the speed-locked closed-loop fan control,
674and drives the fan as fast as it can go, which might exceed hardware
675limits, so use this level with caution.
677 676
678Placing a fan on level 0 is the same as disabling it. Enabling a fan 677The fan usually ramps up or down slowly from one speed to another, and
679will try to place it in a safe level if it is too slow or disabled. 678it is normal for the EC to take several seconds to react to fan
679commands. The full-speed level may take up to two minutes to ramp up to
680maximum speed, and in some ThinkPads, the tachometer readings go stale
681while the EC is transitioning to the full-speed level.
680 682
681WARNING WARNING WARNING: do not leave the fan disabled unless you are 683WARNING WARNING WARNING: do not leave the fan disabled unless you are
682monitoring all of the temperature sensor readings and you are ready to 684monitoring all of the temperature sensor readings and you are ready to
@@ -694,48 +696,101 @@ fan is turned off when the CPU temperature drops to 49 degrees and the
694HDD temperature drops to 41 degrees. These thresholds cannot 696HDD temperature drops to 41 degrees. These thresholds cannot
695currently be controlled. 697currently be controlled.
696 698
699The ThinkPad's ACPI DSDT code will reprogram the fan on its own when
700certain conditions are met. It will override any fan programming done
701through thinkpad-acpi.
702
703The thinkpad-acpi kernel driver can be programmed to revert the fan
704level to a safe setting if userspace does not issue one of the procfs
705fan commands: "enable", "disable", "level" or "watchdog", or if there
706are no writes to pwm1_enable (or to pwm1 *if and only if* pwm1_enable is
707set to 1, manual mode) within a configurable amount of time of up to
708120 seconds. This functionality is called fan safety watchdog.
709
710Note that the watchdog timer stops after it enables the fan. It will be
711rearmed again automatically (using the same interval) when one of the
712above mentioned fan commands is received. The fan watchdog is,
713therefore, not suitable to protect against fan mode changes made through
714means other than the "enable", "disable", and "level" procfs fan
715commands, or the hwmon fan control sysfs interface.
716
717Procfs notes:
718
719The fan may be enabled or disabled with the following commands:
720
721 echo enable >/proc/acpi/ibm/fan
722 echo disable >/proc/acpi/ibm/fan
723
724Placing a fan on level 0 is the same as disabling it. Enabling a fan
725will try to place it in a safe level if it is too slow or disabled.
726
697The fan level can be controlled with the command: 727The fan level can be controlled with the command:
698 728
699 echo 'level <level>' > /proc/acpi/ibm/thermal 729 echo 'level <level>' > /proc/acpi/ibm/fan
700 730
701Where <level> is an integer from 0 to 7, or one of the words "auto" 731Where <level> is an integer from 0 to 7, or one of the words "auto" or
702or "disengaged" (without the quotes). Not all ThinkPads support the 732"full-speed" (without the quotes). Not all ThinkPads support the "auto"
703"auto" and "disengaged" levels. 733and "full-speed" levels. The driver accepts "disengaged" as an alias for
734"full-speed", and reports it as "disengaged" for backwards
735compatibility.
704 736
705On the X31 and X40 (and ONLY on those models), the fan speed can be 737On the X31 and X40 (and ONLY on those models), the fan speed can be
706controlled to a certain degree. Once the fan is running, it can be 738controlled to a certain degree. Once the fan is running, it can be
707forced to run faster or slower with the following command: 739forced to run faster or slower with the following command:
708 740
709 echo 'speed <speed>' > /proc/acpi/ibm/thermal 741 echo 'speed <speed>' > /proc/acpi/ibm/fan
710 742
711The sustainable range of fan speeds on the X40 appears to be from 743The sustainable range of fan speeds on the X40 appears to be from about
712about 3700 to about 7350. Values outside this range either do not have 7443700 to about 7350. Values outside this range either do not have any
713any effect or the fan speed eventually settles somewhere in that 745effect or the fan speed eventually settles somewhere in that range. The
714range. The fan cannot be stopped or started with this command. 746fan cannot be stopped or started with this command. This functionality
747is incomplete, and not available through the sysfs interface.
715 748
716The ThinkPad's ACPI DSDT code will reprogram the fan on its own when 749To program the safety watchdog, use the "watchdog" command.
717certain conditions are met. It will override any fan programming done 750
718through thinkpad-acpi. 751 echo 'watchdog <interval in seconds>' > /proc/acpi/ibm/fan
752
753If you want to disable the watchdog, use 0 as the interval.
754
755Sysfs notes:
756
757The sysfs interface follows the hwmon subsystem guidelines for the most
758part, and the exception is the fan safety watchdog.
759
760hwmon device attribute pwm1_enable:
761 0: PWM offline (fan is set to full-speed mode)
762 1: Manual PWM control (use pwm1 to set fan level)
763 2: Hardware PWM control (EC "auto" mode)
764 3: reserved (Software PWM control, not implemented yet)
765
766 Modes 0 and 2 are not supported by all ThinkPads, and the driver
767 is not always able to detect this. If it does know a mode is
768 unsupported, it will return -EINVAL.
769
770hwmon device attribute pwm1:
771 Fan level, scaled from the firmware values of 0-7 to the hwmon
772 scale of 0-255. 0 means fan stopped, 255 means highest normal
773 speed (level 7).
774
775 This attribute only commands the fan if pmw1_enable is set to 1
776 (manual PWM control).
777
778hwmon device attribute fan1_input:
779 Fan tachometer reading, in RPM. May go stale on certain
780 ThinkPads while the EC transitions the PWM to offline mode,
781 which can take up to two minutes. May return rubbish on older
782 ThinkPads.
783
784driver attribute fan_watchdog:
785 Fan safety watchdog timer interval, in seconds. Minimum is
786 1 second, maximum is 120 seconds. 0 disables the watchdog.
787
788To stop the fan: set pwm1 to zero, and pwm1_enable to 1.
789
790To start the fan in a safe mode: set pwm1_enable to 2. If that fails
791with ENOTSUP, set it to 1 and set pwm1 to at least 128 (255 would be the
792safest choice, though).
719 793
720The thinkpad-acpi kernel driver can be programmed to revert the fan
721level to a safe setting if userspace does not issue one of the fan
722commands: "enable", "disable", "level" or "watchdog" within a
723configurable ammount of time. To do this, use the "watchdog" command.
724
725 echo 'watchdog <interval>' > /proc/acpi/ibm/fan
726
727Interval is the ammount of time in seconds to wait for one of the
728above mentioned fan commands before reseting the fan level to a safe
729one. If set to zero, the watchdog is disabled (default). When the
730watchdog timer runs out, it does the exact equivalent of the "enable"
731fan command.
732
733Note that the watchdog timer stops after it enables the fan. It will
734be rearmed again automatically (using the same interval) when one of
735the above mentioned fan commands is received. The fan watchdog is,
736therefore, not suitable to protect against fan mode changes made
737through means other than the "enable", "disable", and "level" fan
738commands.
739 794
740EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan 795EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan
741--------------------------------------- 796---------------------------------------
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index d5526e882ddd..a4d7ee472396 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -2695,6 +2695,7 @@ static enum fan_control_access_mode fan_control_access_mode;
2695static enum fan_control_commands fan_control_commands; 2695static enum fan_control_commands fan_control_commands;
2696 2696
2697static u8 fan_control_initial_status; 2697static u8 fan_control_initial_status;
2698static u8 fan_control_desired_level;
2698 2699
2699static void fan_watchdog_fire(struct work_struct *ignored); 2700static void fan_watchdog_fire(struct work_struct *ignored);
2700static int fan_watchdog_maxinterval; 2701static int fan_watchdog_maxinterval;
@@ -2708,8 +2709,222 @@ IBM_HANDLE(sfan, ec, "SFAN", /* 570 */
2708 "JFNS", /* 770x-JL */ 2709 "JFNS", /* 770x-JL */
2709 ); /* all others */ 2710 ); /* all others */
2710 2711
2712/*
2713 * SYSFS fan layout: hwmon compatible (device)
2714 *
2715 * pwm*_enable:
2716 * 0: "disengaged" mode
2717 * 1: manual mode
2718 * 2: native EC "auto" mode (recommended, hardware default)
2719 *
2720 * pwm*: set speed in manual mode, ignored otherwise.
2721 * 0 is level 0; 255 is level 7. Intermediate points done with linear
2722 * interpolation.
2723 *
2724 * fan*_input: tachometer reading, RPM
2725 *
2726 *
2727 * SYSFS fan layout: extensions
2728 *
2729 * fan_watchdog (driver):
2730 * fan watchdog interval in seconds, 0 disables (default), max 120
2731 */
2732
2733/* sysfs fan pwm1_enable ----------------------------------------------- */
2734static ssize_t fan_pwm1_enable_show(struct device *dev,
2735 struct device_attribute *attr,
2736 char *buf)
2737{
2738 int res, mode;
2739 u8 status;
2740
2741 res = fan_get_status_safe(&status);
2742 if (res)
2743 return res;
2744
2745 if (unlikely(tp_features.fan_ctrl_status_undef)) {
2746 if (status != fan_control_initial_status) {
2747 tp_features.fan_ctrl_status_undef = 0;
2748 } else {
2749 /* Return most likely status. In fact, it
2750 * might be the only possible status */
2751 status = TP_EC_FAN_AUTO;
2752 }
2753 }
2754
2755 if (status & TP_EC_FAN_FULLSPEED) {
2756 mode = 0;
2757 } else if (status & TP_EC_FAN_AUTO) {
2758 mode = 2;
2759 } else
2760 mode = 1;
2761
2762 return snprintf(buf, PAGE_SIZE, "%d\n", mode);
2763}
2764
2765static ssize_t fan_pwm1_enable_store(struct device *dev,
2766 struct device_attribute *attr,
2767 const char *buf, size_t count)
2768{
2769 unsigned long t;
2770 int res, level;
2771
2772 if (parse_strtoul(buf, 2, &t))
2773 return -EINVAL;
2774
2775 switch (t) {
2776 case 0:
2777 level = TP_EC_FAN_FULLSPEED;
2778 break;
2779 case 1:
2780 level = TPACPI_FAN_LAST_LEVEL;
2781 break;
2782 case 2:
2783 level = TP_EC_FAN_AUTO;
2784 break;
2785 case 3:
2786 /* reserved for software-controlled auto mode */
2787 return -ENOSYS;
2788 default:
2789 return -EINVAL;
2790 }
2791
2792 res = fan_set_level_safe(level);
2793 if (res < 0)
2794 return res;
2795
2796 fan_watchdog_reset();
2797
2798 return count;
2799}
2800
2801static struct device_attribute dev_attr_fan_pwm1_enable =
2802 __ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
2803 fan_pwm1_enable_show, fan_pwm1_enable_store);
2804
2805/* sysfs fan pwm1 ------------------------------------------------------ */
2806static ssize_t fan_pwm1_show(struct device *dev,
2807 struct device_attribute *attr,
2808 char *buf)
2809{
2810 int res;
2811 u8 status;
2812
2813 res = fan_get_status_safe(&status);
2814 if (res)
2815 return res;
2816
2817 if (unlikely(tp_features.fan_ctrl_status_undef)) {
2818 if (status != fan_control_initial_status) {
2819 tp_features.fan_ctrl_status_undef = 0;
2820 } else {
2821 status = TP_EC_FAN_AUTO;
2822 }
2823 }
2824
2825 if ((status &
2826 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) != 0)
2827 status = fan_control_desired_level;
2828
2829 if (status > 7)
2830 status = 7;
2831
2832 return snprintf(buf, PAGE_SIZE, "%u\n", (status * 255) / 7);
2833}
2834
2835static ssize_t fan_pwm1_store(struct device *dev,
2836 struct device_attribute *attr,
2837 const char *buf, size_t count)
2838{
2839 unsigned long s;
2840 int rc;
2841 u8 status, newlevel;
2842
2843 if (parse_strtoul(buf, 255, &s))
2844 return -EINVAL;
2845
2846 /* scale down from 0-255 to 0-7 */
2847 newlevel = (s >> 5) & 0x07;
2848
2849 rc = mutex_lock_interruptible(&fan_mutex);
2850 if (rc < 0)
2851 return rc;
2852
2853 rc = fan_get_status(&status);
2854 if (!rc && (status &
2855 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
2856 rc = fan_set_level(newlevel);
2857 if (!rc)
2858 fan_update_desired_level(newlevel);
2859 fan_watchdog_reset();
2860 }
2861
2862 mutex_unlock(&fan_mutex);
2863 return (rc)? rc : count;
2864}
2865
2866static struct device_attribute dev_attr_fan_pwm1 =
2867 __ATTR(pwm1, S_IWUSR | S_IRUGO,
2868 fan_pwm1_show, fan_pwm1_store);
2869
2870/* sysfs fan fan1_input ------------------------------------------------ */
2871static ssize_t fan_fan1_input_show(struct device *dev,
2872 struct device_attribute *attr,
2873 char *buf)
2874{
2875 int res;
2876 unsigned int speed;
2877
2878 res = fan_get_speed(&speed);
2879 if (res < 0)
2880 return res;
2881
2882 return snprintf(buf, PAGE_SIZE, "%u\n", speed);
2883}
2884
2885static struct device_attribute dev_attr_fan_fan1_input =
2886 __ATTR(fan1_input, S_IRUGO,
2887 fan_fan1_input_show, NULL);
2888
2889/* sysfs fan fan_watchdog (driver) ------------------------------------- */
2890static ssize_t fan_fan_watchdog_show(struct device_driver *drv,
2891 char *buf)
2892{
2893 return snprintf(buf, PAGE_SIZE, "%u\n", fan_watchdog_maxinterval);
2894}
2895
2896static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
2897 const char *buf, size_t count)
2898{
2899 unsigned long t;
2900
2901 if (parse_strtoul(buf, 120, &t))
2902 return -EINVAL;
2903
2904 fan_watchdog_maxinterval = t;
2905 fan_watchdog_reset();
2906
2907 return count;
2908}
2909
2910static DRIVER_ATTR(fan_watchdog, S_IWUSR | S_IRUGO,
2911 fan_fan_watchdog_show, fan_fan_watchdog_store);
2912
2913/* --------------------------------------------------------------------- */
2914static struct attribute *fan_attributes[] = {
2915 &dev_attr_fan_pwm1_enable.attr, &dev_attr_fan_pwm1.attr,
2916 &dev_attr_fan_fan1_input.attr,
2917 NULL
2918};
2919
2920static const struct attribute_group fan_attr_group = {
2921 .attrs = fan_attributes,
2922};
2923
2711static int __init fan_init(struct ibm_init_struct *iibm) 2924static int __init fan_init(struct ibm_init_struct *iibm)
2712{ 2925{
2926 int rc;
2927
2713 vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); 2928 vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n");
2714 2929
2715 mutex_init(&fan_mutex); 2930 mutex_init(&fan_mutex);
@@ -2718,6 +2933,7 @@ static int __init fan_init(struct ibm_init_struct *iibm)
2718 fan_control_commands = 0; 2933 fan_control_commands = 0;
2719 fan_watchdog_maxinterval = 0; 2934 fan_watchdog_maxinterval = 0;
2720 tp_features.fan_ctrl_status_undef = 0; 2935 tp_features.fan_ctrl_status_undef = 0;
2936 fan_control_desired_level = 7;
2721 2937
2722 IBM_ACPIHANDLE_INIT(fans); 2938 IBM_ACPIHANDLE_INIT(fans);
2723 IBM_ACPIHANDLE_INIT(gfan); 2939 IBM_ACPIHANDLE_INIT(gfan);
@@ -2796,9 +3012,36 @@ static int __init fan_init(struct ibm_init_struct *iibm)
2796 fan_control_access_mode != TPACPI_FAN_WR_NONE), 3012 fan_control_access_mode != TPACPI_FAN_WR_NONE),
2797 fan_status_access_mode, fan_control_access_mode); 3013 fan_status_access_mode, fan_control_access_mode);
2798 3014
2799 return (fan_status_access_mode != TPACPI_FAN_NONE || 3015 /* update fan_control_desired_level */
2800 fan_control_access_mode != TPACPI_FAN_WR_NONE)? 3016 if (fan_status_access_mode != TPACPI_FAN_NONE)
2801 0 : 1; 3017 fan_get_status_safe(NULL);
3018
3019 if (fan_status_access_mode != TPACPI_FAN_NONE ||
3020 fan_control_access_mode != TPACPI_FAN_WR_NONE) {
3021 rc = sysfs_create_group(&tpacpi_pdev->dev.kobj,
3022 &fan_attr_group);
3023 if (!(rc < 0))
3024 rc = driver_create_file(&tpacpi_pdriver.driver,
3025 &driver_attr_fan_watchdog);
3026 if (rc < 0)
3027 return rc;
3028 return 0;
3029 } else
3030 return 1;
3031}
3032
3033/*
3034 * Call with fan_mutex held
3035 */
3036static void fan_update_desired_level(u8 status)
3037{
3038 if ((status &
3039 (TP_EC_FAN_AUTO | TP_EC_FAN_FULLSPEED)) == 0) {
3040 if (status > 7)
3041 fan_control_desired_level = 7;
3042 else
3043 fan_control_desired_level = status;
3044 }
2802} 3045}
2803 3046
2804static int fan_get_status(u8 *status) 3047static int fan_get_status(u8 *status)
@@ -2837,9 +3080,33 @@ static int fan_get_status(u8 *status)
2837 return 0; 3080 return 0;
2838} 3081}
2839 3082
3083static int fan_get_status_safe(u8 *status)
3084{
3085 int rc;
3086 u8 s;
3087
3088 rc = mutex_lock_interruptible(&fan_mutex);
3089 if (rc < 0)
3090 return rc;
3091 rc = fan_get_status(&s);
3092 if (!rc)
3093 fan_update_desired_level(s);
3094 mutex_unlock(&fan_mutex);
3095
3096 if (status)
3097 *status = s;
3098
3099 return rc;
3100}
3101
2840static void fan_exit(void) 3102static void fan_exit(void)
2841{ 3103{
2842 vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n"); 3104 vdbg_printk(TPACPI_DBG_EXIT, "cancelling any pending fan watchdog tasks\n");
3105
3106 /* FIXME: can we really do this unconditionally? */
3107 sysfs_remove_group(&tpacpi_pdev->dev.kobj, &fan_attr_group);
3108 driver_remove_file(&tpacpi_pdriver.driver, &driver_attr_fan_watchdog);
3109
2843 cancel_delayed_work(&fan_watchdog_task); 3110 cancel_delayed_work(&fan_watchdog_task);
2844 flush_scheduled_work(); 3111 flush_scheduled_work();
2845} 3112}
@@ -2902,17 +3169,10 @@ static void fan_watchdog_reset(void)
2902 3169
2903static int fan_set_level(int level) 3170static int fan_set_level(int level)
2904{ 3171{
2905 int res;
2906
2907 switch (fan_control_access_mode) { 3172 switch (fan_control_access_mode) {
2908 case TPACPI_FAN_WR_ACPI_SFAN: 3173 case TPACPI_FAN_WR_ACPI_SFAN:
2909 if (level >= 0 && level <= 7) { 3174 if (level >= 0 && level <= 7) {
2910 res = mutex_lock_interruptible(&fan_mutex); 3175 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", level))
2911 if (res < 0)
2912 return res;
2913 res = acpi_evalf(sfan_handle, NULL, NULL, "vd", level);
2914 mutex_unlock(&fan_mutex);
2915 if (!res)
2916 return -EIO; 3176 return -EIO;
2917 } else 3177 } else
2918 return -EINVAL; 3178 return -EINVAL;
@@ -2925,12 +3185,7 @@ static int fan_set_level(int level)
2925 ((level < 0) || (level > 7))) 3185 ((level < 0) || (level > 7)))
2926 return -EINVAL; 3186 return -EINVAL;
2927 3187
2928 res = mutex_lock_interruptible(&fan_mutex); 3188 if (!acpi_ec_write(fan_status_offset, level))
2929 if (res < 0)
2930 return res;
2931 res = acpi_ec_write(fan_status_offset, level);
2932 mutex_unlock(&fan_mutex);
2933 if (!res)
2934 return -EIO; 3189 return -EIO;
2935 else 3190 else
2936 tp_features.fan_ctrl_status_undef = 0; 3191 tp_features.fan_ctrl_status_undef = 0;
@@ -2942,6 +3197,25 @@ static int fan_set_level(int level)
2942 return 0; 3197 return 0;
2943} 3198}
2944 3199
3200static int fan_set_level_safe(int level)
3201{
3202 int rc;
3203
3204 rc = mutex_lock_interruptible(&fan_mutex);
3205 if (rc < 0)
3206 return rc;
3207
3208 if (level == TPACPI_FAN_LAST_LEVEL)
3209 level = fan_control_desired_level;
3210
3211 rc = fan_set_level(level);
3212 if (!rc)
3213 fan_update_desired_level(level);
3214
3215 mutex_unlock(&fan_mutex);
3216 return rc;
3217}
3218
2945static int fan_set_enable(void) 3219static int fan_set_enable(void)
2946{ 3220{
2947 u8 s; 3221 u8 s;
@@ -3009,19 +3283,24 @@ static int fan_set_disable(void)
3009 case TPACPI_FAN_WR_TPEC: 3283 case TPACPI_FAN_WR_TPEC:
3010 if (!acpi_ec_write(fan_status_offset, 0x00)) 3284 if (!acpi_ec_write(fan_status_offset, 0x00))
3011 rc = -EIO; 3285 rc = -EIO;
3012 else 3286 else {
3287 fan_control_desired_level = 0;
3013 tp_features.fan_ctrl_status_undef = 0; 3288 tp_features.fan_ctrl_status_undef = 0;
3289 }
3014 break; 3290 break;
3015 3291
3016 case TPACPI_FAN_WR_ACPI_SFAN: 3292 case TPACPI_FAN_WR_ACPI_SFAN:
3017 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00)) 3293 if (!acpi_evalf(sfan_handle, NULL, NULL, "vd", 0x00))
3018 rc = -EIO; 3294 rc = -EIO;
3295 else
3296 fan_control_desired_level = 0;
3019 break; 3297 break;
3020 3298
3021 default: 3299 default:
3022 rc = -ENXIO; 3300 rc = -ENXIO;
3023 } 3301 }
3024 3302
3303
3025 mutex_unlock(&fan_mutex); 3304 mutex_unlock(&fan_mutex);
3026 return rc; 3305 return rc;
3027} 3306}
@@ -3063,7 +3342,7 @@ static int fan_read(char *p)
3063 switch (fan_status_access_mode) { 3342 switch (fan_status_access_mode) {
3064 case TPACPI_FAN_RD_ACPI_GFAN: 3343 case TPACPI_FAN_RD_ACPI_GFAN:
3065 /* 570, 600e/x, 770e, 770x */ 3344 /* 570, 600e/x, 770e, 770x */
3066 if ((rc = fan_get_status(&status)) < 0) 3345 if ((rc = fan_get_status_safe(&status)) < 0)
3067 return rc; 3346 return rc;
3068 3347
3069 len += sprintf(p + len, "status:\t\t%s\n" 3348 len += sprintf(p + len, "status:\t\t%s\n"
@@ -3073,7 +3352,7 @@ static int fan_read(char *p)
3073 3352
3074 case TPACPI_FAN_RD_TPEC: 3353 case TPACPI_FAN_RD_TPEC:
3075 /* all except 570, 600e/x, 770e, 770x */ 3354 /* all except 570, 600e/x, 770e, 770x */
3076 if ((rc = fan_get_status(&status)) < 0) 3355 if ((rc = fan_get_status_safe(&status)) < 0)
3077 return rc; 3356 return rc;
3078 3357
3079 if (unlikely(tp_features.fan_ctrl_status_undef)) { 3358 if (unlikely(tp_features.fan_ctrl_status_undef)) {
@@ -3117,7 +3396,7 @@ static int fan_read(char *p)
3117 3396
3118 default: 3397 default:
3119 len += sprintf(p + len, " (<level> is 0-7, " 3398 len += sprintf(p + len, " (<level> is 0-7, "
3120 "auto, disengaged)\n"); 3399 "auto, disengaged, full-speed)\n");
3121 break; 3400 break;
3122 } 3401 }
3123 } 3402 }
@@ -3140,12 +3419,13 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
3140 3419
3141 if (strlencmp(cmd, "level auto") == 0) 3420 if (strlencmp(cmd, "level auto") == 0)
3142 level = TP_EC_FAN_AUTO; 3421 level = TP_EC_FAN_AUTO;
3143 else if (strlencmp(cmd, "level disengaged") == 0) 3422 else if ((strlencmp(cmd, "level disengaged") == 0) |
3423 (strlencmp(cmd, "level full-speed") == 0))
3144 level = TP_EC_FAN_FULLSPEED; 3424 level = TP_EC_FAN_FULLSPEED;
3145 else if (sscanf(cmd, "level %d", &level) != 1) 3425 else if (sscanf(cmd, "level %d", &level) != 1)
3146 return 0; 3426 return 0;
3147 3427
3148 if ((*rc = fan_set_level(level)) == -ENXIO) 3428 if ((*rc = fan_set_level_safe(level)) == -ENXIO)
3149 printk(IBM_ERR "level command accepted for unsupported " 3429 printk(IBM_ERR "level command accepted for unsupported "
3150 "access mode %d", fan_control_access_mode); 3430 "access mode %d", fan_control_access_mode);
3151 3431
diff --git a/drivers/misc/thinkpad_acpi.h b/drivers/misc/thinkpad_acpi.h
index e833ff3caf39..2fe4d61cc27f 100644
--- a/drivers/misc/thinkpad_acpi.h
+++ b/drivers/misc/thinkpad_acpi.h
@@ -349,6 +349,8 @@ enum { /* Fan control constants */
349 349
350 TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ 350 TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
351 TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ 351 TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
352
353 TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */
352}; 354};
353 355
354enum fan_status_access_mode { 356enum fan_status_access_mode {
@@ -375,6 +377,7 @@ static enum fan_status_access_mode fan_status_access_mode;
375static enum fan_control_access_mode fan_control_access_mode; 377static enum fan_control_access_mode fan_control_access_mode;
376static enum fan_control_commands fan_control_commands; 378static enum fan_control_commands fan_control_commands;
377static u8 fan_control_initial_status; 379static u8 fan_control_initial_status;
380static u8 fan_control_desired_level;
378static int fan_watchdog_maxinterval; 381static int fan_watchdog_maxinterval;
379 382
380struct mutex fan_mutex; 383struct mutex fan_mutex;
@@ -384,10 +387,13 @@ static acpi_handle fans_handle, gfan_handle, sfan_handle;
384static int fan_init(struct ibm_init_struct *iibm); 387static int fan_init(struct ibm_init_struct *iibm);
385static void fan_exit(void); 388static void fan_exit(void);
386static int fan_get_status(u8 *status); 389static int fan_get_status(u8 *status);
390static int fan_get_status_safe(u8 *status);
387static int fan_get_speed(unsigned int *speed); 391static int fan_get_speed(unsigned int *speed);
392static void fan_update_desired_level(u8 status);
388static void fan_watchdog_fire(struct work_struct *ignored); 393static void fan_watchdog_fire(struct work_struct *ignored);
389static void fan_watchdog_reset(void); 394static void fan_watchdog_reset(void);
390static int fan_set_level(int level); 395static int fan_set_level(int level);
396static int fan_set_level_safe(int level);
391static int fan_set_enable(void); 397static int fan_set_enable(void);
392static int fan_set_disable(void); 398static int fan_set_disable(void);
393static int fan_set_speed(int speed); 399static int fan_set_speed(int speed);