From patchwork Sun Dec 7 21:10:45 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: ?????? ?????? X-Patchwork-Id: 5452991 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 658419F507 for ; Sun, 7 Dec 2014 21:10:54 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 5D9D720145 for ; Sun, 7 Dec 2014 21:10:53 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id 438BC20154 for ; Sun, 7 Dec 2014 21:10:52 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 6544F6E2EC; Sun, 7 Dec 2014 13:10:51 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mail-lb0-f181.google.com (mail-lb0-f181.google.com [209.85.217.181]) by gabe.freedesktop.org (Postfix) with ESMTP id 2894C6E2EC for ; Sun, 7 Dec 2014 13:10:49 -0800 (PST) Received: by mail-lb0-f181.google.com with SMTP id l4so2835577lbv.26 for ; Sun, 07 Dec 2014 13:10:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ymOfjV8ybFnwh/bXZRqBiX/K8Z4fQwllVzn7Rv4FQPw=; b=NFqgRweciL56iw1UW/dD01T/rPhfvOpptjg3YcTLxgXf0vEiJkUUB8E+z7yoQ03wVm 9Xa9SnW/HCuJckzOIv+OmWzhunUDShZT9s7hOwJPWGpV52iLhV8NeG069bEhtLmFaL3k pmYzeONzGB43Cdv3KATAb634z9oiqHbh+/vUqo3ky6AsxapDy5rfh/SzPp+5hbBu4IJT p9ospOoxacYuEMv4AhEG8cQI4GlYn5NtgdL+AXkYgNAgGY8x1Xi642Xfs+YhgsmXFhs7 2fiDuLDJUJX07XpHu7dHtf/pcvzmyWLyFCu5Vrhw1h6yVPhA+LQAta1qVGDkxNCc2YZX xUdQ== X-Received: by 10.112.138.137 with SMTP id qq9mr13187955lbb.80.1417986648387; Sun, 07 Dec 2014 13:10:48 -0800 (PST) Received: from Heaven.lan ([95.140.92.49]) by mx.google.com with ESMTPSA id jj7sm10257813lbc.5.2014.12.07.13.10.47 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sun, 07 Dec 2014 13:10:47 -0800 (PST) From: Oleg Chernovskiy To: dri-devel@lists.freedesktop.org Subject: [PATCH 2/3] add hwmon interface for managing fan pwm Date: Mon, 8 Dec 2014 00:10:45 +0300 Message-Id: <1417986646-8989-2-git-send-email-algonkvel@gmail.com> X-Mailer: git-send-email 2.1.3 In-Reply-To: <1417986646-8989-1-git-send-email-algonkvel@gmail.com> References: <1417986646-8989-1-git-send-email-algonkvel@gmail.com> X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This adds percent-based fan control. Attributes (I hope) follow the sysfs-interface specification: * pwm1 - fan speed query/manage * pwm1_max, pwm1_min - min/max values for fan pwm (constant) * pwm1_enable - fan control query/manage (enable/disable) (There is no rpm-based control for now) Signed-off-by: Oleg Chernovskiy --- drivers/gpu/drm/radeon/radeon_pm.c | 129 ++++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 32522cc..58daa23 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -24,6 +24,7 @@ #include "radeon.h" #include "avivod.h" #include "atom.h" +#include "r600_dpm.h" #include #include #include @@ -554,6 +555,94 @@ fail: return count; } +static ssize_t radeon_hwmon_get_pwm1_enable(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct radeon_device *rdev = dev_get_drvdata(dev); + u32 pwm_mode = 0; + + if(rdev->asic->dpm.fan_ctrl_get_mode) + pwm_mode = rdev->asic->dpm.fan_ctrl_get_mode(rdev); + + return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC); +} + +static ssize_t radeon_hwmon_set_pwm1_enable(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct radeon_device *rdev = dev_get_drvdata(dev); + int err; + int value; + + if(!rdev->asic->dpm.fan_ctrl_set_mode) + return -EINVAL; + + err = kstrtoint(buf, 10, &value); + if(err) + return err; + + switch(value) { + case 1: // manual, percent-based + rdev->asic->dpm.fan_ctrl_set_mode(rdev, FDO_PWM_MODE_STATIC); + break; + default: // disable + rdev->asic->dpm.fan_ctrl_set_mode(rdev, 0); + break; + } + + return count; +} + +static ssize_t radeon_hwmon_get_pwm1_min(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%i\n", 0); +} + +static ssize_t radeon_hwmon_get_pwm1_max(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%i\n", 100); // pwm uses percent-based fan-control +} + +static ssize_t radeon_hwmon_set_pwm1(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct radeon_device *rdev = dev_get_drvdata(dev); + int err; + u32 value; + + err = kstrtou32(buf, 10, &value); + if(err) + return err; + + err = rdev->asic->dpm.set_fan_speed_percent(rdev, value); + if(err) + return err; + + return count; +} + +static ssize_t radeon_hwmon_get_pwm1(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct radeon_device *rdev = dev_get_drvdata(dev); + int err; + u32 speed; + err = rdev->asic->dpm.get_fan_speed_percent(rdev, &speed); + if(err) + return err; + + return sprintf(buf, "%i\n", speed); +} + static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile); static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method); static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state); @@ -601,11 +690,20 @@ static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev, static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 0); static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 1); +static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1, radeon_hwmon_set_pwm1, 0); +static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1_enable, radeon_hwmon_set_pwm1_enable, 0); +static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, radeon_hwmon_get_pwm1_min, NULL, 0); +static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, radeon_hwmon_get_pwm1_max, NULL, 0); + static struct attribute *hwmon_attributes[] = { &sensor_dev_attr_temp1_input.dev_attr.attr, &sensor_dev_attr_temp1_crit.dev_attr.attr, &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr, + &sensor_dev_attr_pwm1.dev_attr.attr, + &sensor_dev_attr_pwm1_enable.dev_attr.attr, + &sensor_dev_attr_pwm1_min.dev_attr.attr, + &sensor_dev_attr_pwm1_max.dev_attr.attr, NULL }; @@ -614,6 +712,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, { struct device *dev = container_of(kobj, struct device, kobj); struct radeon_device *rdev = dev_get_drvdata(dev); + umode_t effective_mode = attr->mode; /* Skip limit attributes if DPM is not enabled */ if (rdev->pm.pm_method != PM_METHOD_DPM && @@ -621,7 +720,35 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj, attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr)) return 0; - return attr->mode; + /* Skip fan attributes if fan is not present */ + if(rdev->pm.no_fan && + (attr == &sensor_dev_attr_pwm1.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) + return 0; + + /* mask fan attributes if we have no bindings for this asic to expose */ + if((!rdev->asic->dpm.get_fan_speed_percent && + attr == &sensor_dev_attr_pwm1.dev_attr.attr) || // can't query fan + (!rdev->asic->dpm.fan_ctrl_get_mode && + attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) // can't query state + effective_mode &= ~S_IRUGO; + + if((!rdev->asic->dpm.set_fan_speed_percent && + attr == &sensor_dev_attr_pwm1.dev_attr.attr) || // can't manage fan + (!rdev->asic->dpm.fan_ctrl_set_mode && + attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) // can't manage state + effective_mode &= ~S_IWUSR; + + /* hide max/min values if we can't both query and manage the fan */ + if((!rdev->asic->dpm.set_fan_speed_percent && + !rdev->asic->dpm.get_fan_speed_percent) && + (attr == &sensor_dev_attr_pwm1_max.dev_attr.attr || + attr == &sensor_dev_attr_pwm1_min.dev_attr.attr)) + return 0; + + return effective_mode; } static const struct attribute_group hwmon_attrgroup = {