From patchwork Fri Jan 16 23:05:48 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Pandruvada X-Patchwork-Id: 5650681 X-Patchwork-Delegate: rui.zhang@intel.com Return-Path: X-Original-To: patchwork-linux-pm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9B2959F6E2 for ; Fri, 16 Jan 2015 23:06:41 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id AF63C20375 for ; Fri, 16 Jan 2015 23:06:40 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 13EC720377 for ; Fri, 16 Jan 2015 23:06:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751134AbbAPXGg (ORCPT ); Fri, 16 Jan 2015 18:06:36 -0500 Received: from mga03.intel.com ([134.134.136.65]:32583 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751648AbbAPXGf (ORCPT ); Fri, 16 Jan 2015 18:06:35 -0500 Received: from orsmga001.jf.intel.com ([10.7.209.18]) by orsmga103.jf.intel.com with ESMTP; 16 Jan 2015 15:02:47 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.09,413,1418112000"; d="scan'208";a="638557390" Received: from spandruv-desktop.jf.intel.com ([10.7.199.150]) by orsmga001.jf.intel.com with ESMTP; 16 Jan 2015 15:06:32 -0800 From: Srinivas Pandruvada To: rui.zhang@intel.com, edubezval@gmail.com Cc: linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [PATCH v1 4/4] Thermal/int340x/processor_thermal: Add thermal zone support Date: Fri, 16 Jan 2015 15:05:48 -0800 Message-Id: <1421449548-2172-5-git-send-email-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1421449548-2172-1-git-send-email-srinivas.pandruvada@linux.intel.com> References: <1421449548-2172-1-git-send-email-srinivas.pandruvada@linux.intel.com> Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, 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 Added thermal zones for processor thermal using APIs provided by int340x thermal zone module. Like other INT340x devices, processor thermal device can also contain trip points and way to get temperature. On some platform there is no ACPI _TMP method, in those platform using IA64 architecture MSRs to get temperature. Signed-off-by: Srinivas Pandruvada --- .../int340x_thermal/processor_thermal_device.c | 90 ++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c index 0fe5dbb..7c3848d 100644 --- a/drivers/thermal/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include "int340x_thermal_zone.h" /* Broadwell-U/HSB thermal reporting device */ #define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 @@ -39,6 +41,7 @@ struct proc_thermal_device { struct device *dev; struct acpi_device *adev; struct power_config power_limits[2]; + struct int34x_thermal_zone *int340x_zone; }; enum proc_thermal_emum_mode_type { @@ -117,6 +120,72 @@ static struct attribute_group power_limit_attribute_group = { .name = "power_limits" }; +static int stored_tjmax; /* since it is fixed, we can have local storage */ + +static int get_tjmax(void) +{ + u32 eax, edx; + u32 val; + int err; + + err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx); + if (err) + return err; + + val = (eax >> 16) & 0xff; + if (val) + return val; + + return -EINVAL; +} + +static int read_temp_msr(unsigned long *temp) +{ + int cpu; + u32 eax, edx; + int err; + unsigned long curr_temp_off = 0; + + *temp = 0; + + for_each_online_cpu(cpu) { + err = rdmsr_safe_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax, + &edx); + if (err) + goto err_ret; + else { + if (eax & 0x80000000) { + curr_temp_off = (eax >> 16) & 0x7f; + if (!*temp || curr_temp_off < *temp) + *temp = curr_temp_off; + } else { + err = -EINVAL; + goto err_ret; + } + } + } + + return 0; +err_ret: + return err; +} + +static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone, + unsigned long *temp) +{ + int ret; + + ret = read_temp_msr(temp); + if (!ret) + *temp = (stored_tjmax - *temp) * 1000; + + return ret; +} + +static struct thermal_zone_device_ops proc_thermal_local_ops = { + .get_temp = proc_thermal_get_zone_temp, +}; + static int proc_thermal_add(struct device *dev, struct proc_thermal_device **priv) { @@ -126,6 +195,8 @@ static int proc_thermal_add(struct device *dev, struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *elements, *ppcc; union acpi_object *p; + unsigned long long tmp; + struct thermal_zone_device_ops *ops = NULL; int i; int ret; @@ -178,6 +249,24 @@ static int proc_thermal_add(struct device *dev, ret = sysfs_create_group(&dev->kobj, &power_limit_attribute_group); + if (ret) + goto free_buffer; + + status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp); + if (ACPI_FAILURE(status)) { + /* there is no _TMP method, add local method */ + stored_tjmax = get_tjmax(); + if (stored_tjmax > 0) + ops = &proc_thermal_local_ops; + } + + proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops); + if (IS_ERR(proc_priv->int340x_zone)) { + sysfs_remove_group(&proc_priv->dev->kobj, + &power_limit_attribute_group); + ret = PTR_ERR(proc_priv->int340x_zone); + } else + ret = 0; free_buffer: kfree(buf.pointer); @@ -187,6 +276,7 @@ free_buffer: void proc_thermal_remove(struct proc_thermal_device *proc_priv) { + int340x_thermal_zone_remove(proc_priv->int340x_zone); sysfs_remove_group(&proc_priv->dev->kobj, &power_limit_attribute_group); }