From patchwork Sun May 22 11:50:36 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 9130921 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id DED6C60760 for ; Sun, 22 May 2016 11:51:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 184772819C for ; Sun, 22 May 2016 11:51:10 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0B0D0281AC; Sun, 22 May 2016 11:51:10 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7C9A42819C for ; Sun, 22 May 2016 11:51:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752366AbcEVLvK (ORCPT ); Sun, 22 May 2016 07:51:10 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:34797 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752273AbcEVLvI (ORCPT ); Sun, 22 May 2016 07:51:08 -0400 Received: by mail-wm0-f68.google.com with SMTP id n129so7864231wmn.1; Sun, 22 May 2016 04:51:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=iY9mN0LBwE38OJe8MUdGaS0UlaWdQDyernFSsHWpmP8=; b=NpYk4J5vYtUUG90Gg9HqeO8fEUwajDBeQd2l2ahDBa82+ECfaHM2ZkWhmo8COfeU22 gX3Tf/w99dexbpz3DQ8E+i4tNcCq25zS+P0K4V7GDXVHkX4nS2mNZIVdup15zCyGSwIj Vy0c/J4BTC/ctyePmTJ3jy5R5UZwbKvDxJIdDOhCztjN2q1S4Do/R8gwA3oaVYxodJh6 vPaCzTA8hLML8DojqYOX9Am6M7Vw0/+6mAKwxryId7nojawqftzU/K0v2LBprOr7ldxL QKFHag9NC/qyZ2pzGgOeM6Z+sSsnhxxfgBsUKhP+pMxEWK3+HMxahakEY3+cFWnxOGg3 qNHA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=iY9mN0LBwE38OJe8MUdGaS0UlaWdQDyernFSsHWpmP8=; b=KVS3CNg+R1F/R1eF1yrL2BFRPv1oqHJIHYMN7TJ1VC72AmoWUIhsC1LgHd+WVK7OOM bOGnQxVfiidPUDIYSs0gIcn2R8CSog+pI4CF0OmCKneLKbLqciOp8xJoduDe/B5n1VPX DAaW5wlOf8ciJBz3RxQvNR3lwknJh2agUJT5ZNKT8H6rJke0F5Aq6RhNm/Iieh1ifAO9 0Mwye1UNQ9pGvGibLBRrvCJAbiRQ3NtKG0GZdVRcAe3KZ5VC4BF6//td/Z/NBINfNDbG ttgm54Ckl6kTgw7hIPEo1qELTpV0RCB4gJMgplKCf6wB8fKr692JcbP0t+LZ62pq4UMu kFzQ== X-Gm-Message-State: AOPr4FWH+GtqMCFn3s8cMmOqrFkCQlTDJIck0KvuXn+fK9+FIBM0eke6VLEivDarnE5ALg== X-Received: by 10.28.154.73 with SMTP id c70mr12689342wme.12.1463917867058; Sun, 22 May 2016 04:51:07 -0700 (PDT) Received: from localhost.localdomain (pali.kolej.mff.cuni.cz. [78.128.193.202]) by smtp.gmail.com with ESMTPSA id q76sm7942562wmd.6.2016.05.22.04.51.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 22 May 2016 04:51:06 -0700 (PDT) From: =?UTF-8?q?Pali=20Roh=C3=A1r?= To: Jean Delvare , Guenter Roeck , Gabriele Mazzotta , =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= , Andy Lutomirski , Jethro Cc: linux-hwmon@vger.kernel.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Pali=20Roh=C3=A1r?= Subject: [Experimental PATCH] dell-smm-hwmon: Add support for disabling automatic BIOS fan control Date: Sun, 22 May 2016 13:50:36 +0200 Message-Id: <1463917836-12985-1-git-send-email-pali.rohar@gmail.com> X-Mailer: git-send-email 1.7.9.5 MIME-Version: 1.0 Sender: linux-hwmon-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-hwmon@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This patch exports standard hwmon pwmX_enable sysfs attribute for enabling or disabling automatic fan control by BIOS. Standard value "1" is for disabling automatic BIOS fan control and value "2" for enabling. Currently there is no way to check if BIOS auto mode is enabled (at least it is not know how to do it), so hwmon sysfs attribute is write-only. By default BIOS auto mode is enabled by laptop firmware. When BIOS auto mode is enabled, custom fan speed value (set via hwmon pwmX sysfs attribute) is overwritten by SMM in few seconds and therefore any custom settings are without effect. So this is reason why implementing option for disabling BIOS auto mode is needed. So finally this patch allows kernel to set and control fan speed on laptops, but it can be dangerous (like setting speed of other fans). This new feature is highly experimental, uses Dell SMM calls, so does not have to be supported by all laptops BIOSes. It was tested on Dell Latitude E6440 with BIOS A5. Signed-off-by: Pali Rohár --- drivers/hwmon/dell-smm-hwmon.c | 64 ++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/drivers/hwmon/dell-smm-hwmon.c b/drivers/hwmon/dell-smm-hwmon.c index 8a66a42..7b5144a 100644 --- a/drivers/hwmon/dell-smm-hwmon.c +++ b/drivers/hwmon/dell-smm-hwmon.c @@ -45,6 +45,8 @@ #define I8K_SMM_GET_SPEED 0x02a3 #define I8K_SMM_GET_FAN_TYPE 0x03a3 #define I8K_SMM_GET_NOM_SPEED 0x04a3 +#define I8K_SMM_MANUAL_FAN 0x34a3 +#define I8K_SMM_AUTO_FAN 0x35a3 #define I8K_SMM_GET_TEMP 0x10a3 #define I8K_SMM_GET_TEMP_TYPE 0x11a3 #define I8K_SMM_GET_DELL_SIG1 0xfea3 @@ -284,6 +286,17 @@ static int i8k_get_fan_nominal_speed(int fan, int speed) } /* + * Enable or disable automatic BIOS fan control support + */ +static int i8k_enable_fan_auto_mode(bool enable) +{ + struct smm_regs regs = { }; + + regs.eax = enable ? I8K_SMM_AUTO_FAN : I8K_SMM_MANUAL_FAN; + return i8k_smm(®s); +} + +/* * Set the fan speed (off, low, high). Returns the new fan status. */ static int i8k_set_fan(int fan, int speed) @@ -702,6 +715,30 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev, return err < 0 ? -EIO : count; } +static ssize_t i8k_hwmon_set_pwm_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int err; + bool enable; + unsigned long val; + + err = kstrtoul(buf, 10, &val); + if (err) + return err; + + if (val == 0) + return -EINVAL; + + enable = (val != 1); + + mutex_lock(&i8k_mutex); + err = i8k_enable_fan_auto_mode(enable); + mutex_unlock(&i8k_mutex); + + return err ? -EIO : count; +} + static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL, 0); @@ -719,18 +756,24 @@ static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, 0); static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, i8k_hwmon_set_pwm, 0); +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR, NULL, i8k_hwmon_set_pwm_enable, + 0); static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 1); static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, 1); static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, i8k_hwmon_set_pwm, 1); +static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR, NULL, i8k_hwmon_set_pwm_enable, + 1); static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 2); static SENSOR_DEVICE_ATTR(fan3_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL, 2); static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm, i8k_hwmon_set_pwm, 2); +static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR, NULL, i8k_hwmon_set_pwm_enable, + 2); static struct attribute *i8k_attrs[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */ @@ -744,12 +787,15 @@ static struct attribute *i8k_attrs[] = { &sensor_dev_attr_fan1_input.dev_attr.attr, /* 8 */ &sensor_dev_attr_fan1_label.dev_attr.attr, /* 9 */ &sensor_dev_attr_pwm1.dev_attr.attr, /* 10 */ - &sensor_dev_attr_fan2_input.dev_attr.attr, /* 11 */ - &sensor_dev_attr_fan2_label.dev_attr.attr, /* 12 */ - &sensor_dev_attr_pwm2.dev_attr.attr, /* 13 */ - &sensor_dev_attr_fan3_input.dev_attr.attr, /* 14 */ - &sensor_dev_attr_fan3_label.dev_attr.attr, /* 15 */ - &sensor_dev_attr_pwm3.dev_attr.attr, /* 16 */ + &sensor_dev_attr_pwm1_enable.dev_attr.attr, /* 11 */ + &sensor_dev_attr_fan2_input.dev_attr.attr, /* 12 */ + &sensor_dev_attr_fan2_label.dev_attr.attr, /* 13 */ + &sensor_dev_attr_pwm2.dev_attr.attr, /* 14 */ + &sensor_dev_attr_pwm2_enable.dev_attr.attr, /* 15 */ + &sensor_dev_attr_fan3_input.dev_attr.attr, /* 16 */ + &sensor_dev_attr_fan3_label.dev_attr.attr, /* 17 */ + &sensor_dev_attr_pwm3.dev_attr.attr, /* 18 */ + &sensor_dev_attr_pwm3_enable.dev_attr.attr, /* 19 */ NULL }; @@ -768,13 +814,13 @@ static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr, if (index >= 6 && index <= 7 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4)) return 0; - if (index >= 8 && index <= 10 && + if (index >= 8 && index <= 11 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1)) return 0; - if (index >= 11 && index <= 13 && + if (index >= 12 && index <= 15 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2)) return 0; - if (index >= 14 && index <= 16 && + if (index >= 16 && index <= 19 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN3)) return 0;