From patchwork Mon May 4 18:16:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: srinivas pandruvada X-Patchwork-Id: 11527351 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 16C0815AB for ; Mon, 4 May 2020 18:17:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 03C5B20661 for ; Mon, 4 May 2020 18:17:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731949AbgEDSQn (ORCPT ); Mon, 4 May 2020 14:16:43 -0400 Received: from mga12.intel.com ([192.55.52.136]:27142 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730657AbgEDSQl (ORCPT ); Mon, 4 May 2020 14:16:41 -0400 IronPort-SDR: VLJwayYw3x53mUP8Kp+OcOIC3+n0SK2gHXim9pd4+nYLP5WtZdQsBQ8+Hi71ZiEB9DZqQV+3cb pjUemP/yny1Q== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 May 2020 11:16:32 -0700 IronPort-SDR: oWB94z3vmcJwRlcip6yGYRP9hzAigw19BqdDV8aTAAD7ubvVwZLi41gRSjbl268guVtRt/XHPN RrEpp1yYzoew== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,352,1583222400"; d="scan'208";a="259427109" Received: from spandruv-mobl.amr.corp.intel.com ([10.212.145.237]) by orsmga003.jf.intel.com with ESMTP; 04 May 2020 11:16:31 -0700 From: Srinivas Pandruvada To: rui.zhang@intel.com, daniel.lezcano@linaro.org, amit.kucheria@verdurent.com Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [RFC][PATCH 1/5] thermal: Add support for /dev/thermal_notify Date: Mon, 4 May 2020 11:16:12 -0700 Message-Id: <20200504181616.175477-2-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200504181616.175477-1-srinivas.pandruvada@linux.intel.com> References: <20200504181616.175477-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org This change adds an optional feature to add a new device entry /dev/thermal_notify. When config CONFIG_THERMAL_USER_EVENT_INTERFACE is selected, this new device entry is created. Thermal core or any thermal driver can use thermal_dev_send_event() interface to send events. Each user events follows a standard format: - zone_id - event_id - event_data - reserved for future, currently 0s User space can basically: fd = open ("/dev/thermal_notify") In a loop read (fd) read and process event or fd = open ("/dev/thermal_notify") Set the fs as non blocking In a loop Use poll() and wait read and process event There are predefined events added to thermal.h. Based on need they can be extended. Signed-off-by: Srinivas Pandruvada --- drivers/thermal/Kconfig | 9 ++ drivers/thermal/Makefile | 3 + drivers/thermal/thermal_dev_if.c | 195 +++++++++++++++++++++++++++++++ include/linux/thermal.h | 24 ++++ 4 files changed, 231 insertions(+) create mode 100644 drivers/thermal/thermal_dev_if.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 91af271e9bb0..27d05d62458e 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -78,6 +78,15 @@ config THERMAL_WRITABLE_TRIPS Say 'Y' here if you would like to allow userspace tools to change trip temperatures. +config THERMAL_USER_EVENT_INTERFACE + bool "Allow user space to read thermal events from a dev file" + help + This option allows a user space program to read thermal events + via /dev/thermal_notify file. + + Say 'Y' here if you would like to allow userspace programs to + read thermal events. + choice prompt "Default Thermal governor" default THERMAL_DEFAULT_GOV_STEP_WISE diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 8c8ed7b79915..8f65832d755a 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -11,6 +11,9 @@ thermal_sys-y += thermal_core.o thermal_sysfs.o \ thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o thermal_sys-$(CONFIG_THERMAL_OF) += of-thermal.o +# Thermal user space events +obj-$(CONFIG_THERMAL_USER_EVENT_INTERFACE) += thermal_dev_if.o + # governors thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o thermal_sys-$(CONFIG_THERMAL_GOV_BANG_BANG) += gov_bang_bang.o diff --git a/drivers/thermal/thermal_dev_if.c b/drivers/thermal/thermal_dev_if.c new file mode 100644 index 000000000000..763bfe9eef9d --- /dev/null +++ b/drivers/thermal/thermal_dev_if.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Thermal device file interface + * Copyright (c) 2020, Intel Corporation. + * All rights reserved. + * + * Author: Srinivas Pandruvada + */ + +#include +#include +#include +#include +#include +#include +#include + +#define THERMAL_DEV_FIFO_SIZE 1024 + +struct thermal_chdev_sample { + int zone_id; + int event; + u64 event_data; + u64 reserved; +}; + +struct thermal_chdev { + struct miscdevice therm_dev; + struct kfifo data_fifo; + unsigned long misc_opened; + wait_queue_head_t wait; +}; + +static DEFINE_MUTEX(thermal_chdev_mutex); +static struct thermal_chdev *thermal_chdev; + +static int thermal_chdev_open(struct inode *inode, struct file *file) +{ + struct thermal_chdev *chdev; + + chdev = container_of(file->private_data, struct thermal_chdev, therm_dev); + + /* We essentially have single reader and writer */ + if (test_and_set_bit(0, &chdev->misc_opened)) + return -EBUSY; + + return stream_open(inode, file); +} + +static int thermal_chdev_release(struct inode *inode, struct file *file) +{ + struct thermal_chdev *chdev; + + chdev = container_of(file->private_data, struct thermal_chdev, therm_dev); + + clear_bit(0, &chdev->misc_opened); + + return 0; +} + +static __poll_t thermal_chdev_poll(struct file *file, struct poll_table_struct *wait) +{ + struct thermal_chdev *chdev; + __poll_t mask = 0; + + chdev = container_of(file->private_data, struct thermal_chdev, therm_dev); + + poll_wait(file, &chdev->wait, wait); + + if (!kfifo_is_empty(&chdev->data_fifo)) + mask = EPOLLIN | EPOLLRDNORM; + + return mask; +} + +static ssize_t thermal_chdev_read(struct file *file, char __user *buf, size_t count, loff_t *f_ps) +{ + struct thermal_chdev *chdev; + unsigned int copied; + int ret; + + chdev = container_of(file->private_data, struct thermal_chdev, therm_dev); + + if (count < sizeof(struct thermal_chdev_sample)) + return -EINVAL; + + do { + if (kfifo_is_empty(&chdev->data_fifo)) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + ret = wait_event_interruptible(chdev->wait, !kfifo_is_empty(&chdev->data_fifo)); + if (ret) + return ret; + } + ret = kfifo_to_user(&chdev->data_fifo, buf, count, &copied); + if (ret) + return ret; + + } while (copied == 0); + + return copied; +} + +static int thermal_chdev_capture_sample(struct thermal_chdev *chdev, struct thermal_chdev_sample *sample) +{ + int ret = 0; + + if (!test_bit(0, &chdev->misc_opened)) + return 0; + + mutex_lock(&thermal_chdev_mutex); + if (kfifo_avail(&chdev->data_fifo) >= sizeof(*sample)) { + kfifo_in(&chdev->data_fifo, (unsigned char *)sample, sizeof(*sample)); + wake_up(&chdev->wait); + } else { + ret = -ENOMEM; + } + mutex_unlock(&thermal_chdev_mutex); + + return ret; +} + +static const struct file_operations thermal_chdev_fops = { + .open = thermal_chdev_open, + .read = thermal_chdev_read, + .release = thermal_chdev_release, + .poll = thermal_chdev_poll, + .llseek = noop_llseek, +}; + +static int thermal_dev_if_add(void) +{ + int ret; + + if (thermal_chdev) + return 0; + + thermal_chdev = kzalloc(sizeof(*thermal_chdev), GFP_KERNEL); + if (!thermal_chdev) + return -ENOMEM; + + ret = kfifo_alloc(&thermal_chdev->data_fifo, THERMAL_DEV_FIFO_SIZE, GFP_KERNEL); + if (ret) + goto free_mem; + + init_waitqueue_head(&thermal_chdev->wait); + + thermal_chdev->therm_dev.minor = MISC_DYNAMIC_MINOR; + thermal_chdev->therm_dev.name = "thermal_notify"; + thermal_chdev->therm_dev.fops = &thermal_chdev_fops; + ret = misc_register(&thermal_chdev->therm_dev); + if (ret) { + kfifo_free(&thermal_chdev->data_fifo); + goto free_mem; + } + + return 0; + +free_mem: + kfree(thermal_chdev); + thermal_chdev = NULL; + return ret; +} + +/** + * thermal_dev_send_event() - Send thermal event to user space + * @zone_id: Zone id of the caller + * @event: A predefined thermal event + * @event_data: Event specific data + * + * An interface to send event to user space with an optional associated + * data. + * + * Return: 0 on success, other values on error. + */ +int thermal_dev_send_event(int zone_id, enum thermal_device_events event, u64 event_data) +{ + struct thermal_chdev_sample sample; + + if (!thermal_chdev) { + int ret; + + ret = thermal_dev_if_add(); + if (ret) + return ret; + } + + sample.zone_id = zone_id; + sample.event = event; + sample.event_data = event_data; + sample.reserved = 0; + return thermal_chdev_capture_sample(thermal_chdev, &sample); +} +EXPORT_SYMBOL_GPL(thermal_dev_send_event); diff --git a/include/linux/thermal.h b/include/linux/thermal.h index c91b1e344d56..f5e1e7c6a9a2 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -543,4 +543,28 @@ static inline void thermal_notify_framework(struct thermal_zone_device *tz, { } #endif /* CONFIG_THERMAL */ +enum thermal_device_events { + THERMAL_TEMP_SAMPLE = 0, + THERMAL_ZONE_CREATE, + THERMAL_ZONE_DELETE, + THERMAL_ZONE_DISABLED, + THERMAL_ZONE_ENABLED, + THERMAL_TEMP_LOW_THRES, + THERMAL_TEMP_HIGH_THRES, + THERMAL_TRIP_ADD, + THERMAL_TRIP_DELETE, + THERMAL_TRIP_UPDATE, + THERMAL_TRIP_REACHED, + THERMAL_PERF_CHANGED, +}; + +#ifdef CONFIG_THERMAL_USER_EVENT_INTERFACE +int thermal_dev_send_event(int zone_id, enum thermal_device_events event, u64 event_data); +#else +int thermal_dev_send_event(int zone_id, enum thermal_device_events event, u64 event_data) +{ + return 0; +} +#endif + #endif /* __THERMAL_H__ */ From patchwork Mon May 4 18:16:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: srinivas pandruvada X-Patchwork-Id: 11527343 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 73E8915AB for ; Mon, 4 May 2020 18:16:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6656720705 for ; Mon, 4 May 2020 18:16:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730118AbgEDSQm (ORCPT ); Mon, 4 May 2020 14:16:42 -0400 Received: from mga12.intel.com ([192.55.52.136]:27142 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731651AbgEDSQm (ORCPT ); Mon, 4 May 2020 14:16:42 -0400 IronPort-SDR: iCyM7OTrg9xXAbpe5CP/qc2iHeBrJRDvswaHw9vT0ABO2ZrOme+fpu17rR6NR22JfqwOcg/dSn BqYJ19LFG5hA== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 May 2020 11:16:33 -0700 IronPort-SDR: V766HvWC6rBdcZA8Jv4qpDf6TH6op0Ofg3z2QG/C+iaWJhoNwivZZQTLjSJKncla9w9g1xdsqG oMMZ6K9bQ2Ww== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,352,1583222400"; d="scan'208";a="259427120" Received: from spandruv-mobl.amr.corp.intel.com ([10.212.145.237]) by orsmga003.jf.intel.com with ESMTP; 04 May 2020 11:16:32 -0700 From: Srinivas Pandruvada To: rui.zhang@intel.com, daniel.lezcano@linaro.org, amit.kucheria@verdurent.com Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [RFC][PATCH 2/5] thermal: Add notification for zone creation and deletion Date: Mon, 4 May 2020 11:16:13 -0700 Message-Id: <20200504181616.175477-3-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200504181616.175477-1-srinivas.pandruvada@linux.intel.com> References: <20200504181616.175477-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Whenever thermal_zone_device_register() is called and zone is created successfully, send a notification "THERMAL_ZONE_CREATE". Similarly send "THERMAL_ZONE_DELETE" when thermal_zone_device_unregister is called. Signed-off-by: Srinivas Pandruvada --- drivers/thermal/thermal_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 9a321dc548c8..14770d882d42 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1350,6 +1350,8 @@ thermal_zone_device_register(const char *type, int trips, int mask, if (atomic_cmpxchg(&tz->need_update, 1, 0)) thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + thermal_dev_send_event(tz->id, THERMAL_ZONE_CREATE, 0); + return tz; unregister: @@ -1379,6 +1381,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) if (!tz) return; + thermal_dev_send_event(tz->id, THERMAL_ZONE_DELETE, 0); + tzp = tz->tzp; mutex_lock(&thermal_list_lock); From patchwork Mon May 4 18:16:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: srinivas pandruvada X-Patchwork-Id: 11527349 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id CE4AC17E8 for ; Mon, 4 May 2020 18:16:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B59B624959 for ; Mon, 4 May 2020 18:16:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732431AbgEDSQ4 (ORCPT ); Mon, 4 May 2020 14:16:56 -0400 Received: from mga12.intel.com ([192.55.52.136]:27142 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1731270AbgEDSQo (ORCPT ); Mon, 4 May 2020 14:16:44 -0400 IronPort-SDR: 4qqtT4SPLEW/sZ2KAqQ3bQ6K7RZVNZYa4oq1WLROY4Ier09QnqJr1an+s1fCBkdRe6uTC6TzZ8 zPa6nkEhh2kQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 May 2020 11:16:34 -0700 IronPort-SDR: 078soUGTQ5aWln7LwyIGSfzdYrqG9zKepNPq/uYGF4Bp6UlW0KLBeYvJnCSw8oBij1UNmT8kMw f8SJEbN23THA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,352,1583222400"; d="scan'208";a="259427129" Received: from spandruv-mobl.amr.corp.intel.com ([10.212.145.237]) by orsmga003.jf.intel.com with ESMTP; 04 May 2020 11:16:33 -0700 From: Srinivas Pandruvada To: rui.zhang@intel.com, daniel.lezcano@linaro.org, amit.kucheria@verdurent.com Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [RFC][PATCH 3/5] thermal: Add support for setting notification thresholds Date: Mon, 4 May 2020 11:16:14 -0700 Message-Id: <20200504181616.175477-4-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200504181616.175477-1-srinivas.pandruvada@linux.intel.com> References: <20200504181616.175477-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Add new attributes in thermal syfs when a thermal drivers provides callbacks for them and CONFIG_THERMAL_USER_EVENT_INTERFACE is defined. These attribute allow user space to stop polling for temperature. These attributes are: - temp_thres_low: Specify a notification temperature for a low temperature threshold event. temp_thres_high: Specify a notification temperature for a high temperature threshold event. temp_thres_hyst: Specify a change in temperature to send notification again. This is implemented by adding additional sysfs attribute group. The changes in this patch are trivial to add new attributes in thermal sysfs as done for other attributes. Signed-off-by: Srinivas Pandruvada --- drivers/thermal/thermal_sysfs.c | 136 +++++++++++++++++++++++++++++++- include/linux/thermal.h | 10 ++- 2 files changed, 143 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index aa99edb4dff7..aa85424c3ac4 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -215,6 +215,125 @@ trip_point_hyst_show(struct device *dev, struct device_attribute *attr, return ret ? ret : sprintf(buf, "%d\n", temperature); } +#if IS_ENABLED(CONFIG_THERMAL_USER_EVENT_INTERFACE) + +#define create_thres_attr(name) \ + static ssize_t \ + name##_show(struct device *dev, struct device_attribute *devattr, \ + char *buf) \ + { \ + struct thermal_zone_device *tz = to_thermal_zone(dev); \ + int temperature, ret; \ + \ + ret = tz->ops->get_##name(tz, &temperature); \ + \ + return ret ? ret : sprintf(buf, "%d\n", temperature); \ + } \ + \ + static ssize_t \ + name##_store(struct device *dev, struct device_attribute *devattr, \ + const char *buf, size_t count) \ + { \ + struct thermal_zone_device *tz = to_thermal_zone(dev); \ + int temperature, ret; \ + \ + if (kstrtoint(buf, 10, &temperature)) \ + return -EINVAL; \ + \ + ret = tz->ops->set_##name(tz, temperature); \ + return ret ? ret : count; \ + } + +create_thres_attr(temp_thres_low); +create_thres_attr(temp_thres_high); +create_thres_attr(temp_thres_hyst); + +static int create_user_events_attrs(struct thermal_zone_device *tz) +{ + struct attribute **attrs; + int index = 0; + + if (tz->ops->get_temp_thres_low) + ++index; + if (tz->ops->get_temp_thres_high) + ++index; + if (tz->ops->get_temp_thres_high) + ++index; + + /* One additional space for NULL */ + attrs = kcalloc(index + 1, sizeof(*attrs), GFP_KERNEL); + if (!attrs) + return -ENOMEM; + + tz->threshold_attrs = kcalloc(index, sizeof(*tz->threshold_attrs), GFP_KERNEL); + if (!tz->threshold_attrs) { + kfree(attrs); + return -ENOMEM; + } + + index = 0; + + if (tz->ops->get_temp_thres_low) { + snprintf(tz->threshold_attrs[index].name, THERMAL_NAME_LENGTH, + "temp_thres_low"); + + sysfs_attr_init(&tz->threshold_attrs[index].attr.attr); + tz->threshold_attrs[index].attr.attr.name = + tz->threshold_attrs[index].name; + tz->threshold_attrs[index].attr.attr.mode = S_IWUSR | S_IRUGO; + tz->threshold_attrs[index].attr.show = temp_thres_low_show; + tz->threshold_attrs[index].attr.store = temp_thres_low_store; + attrs[index] = &tz->threshold_attrs[index].attr.attr; + ++index; + } + if (tz->ops->get_temp_thres_high) { + snprintf(tz->threshold_attrs[index].name, THERMAL_NAME_LENGTH, + "temp_thres_high"); + + sysfs_attr_init(&tz->threshold_attrs[index].attr.attr); + tz->threshold_attrs[index].attr.attr.name = + tz->threshold_attrs[index].name; + tz->threshold_attrs[index].attr.attr.mode = S_IWUSR | S_IRUGO; + tz->threshold_attrs[index].attr.show = temp_thres_high_show; + tz->threshold_attrs[index].attr.store = temp_thres_high_store; + attrs[index] = &tz->threshold_attrs[index].attr.attr; + ++index; + } + if (tz->ops->get_temp_thres_hyst) { + snprintf(tz->threshold_attrs[index].name, THERMAL_NAME_LENGTH, + "temp_thres_hyst"); + + sysfs_attr_init(&tz->threshold_attrs[index].attr.attr); + tz->threshold_attrs[index].attr.attr.name = + tz->threshold_attrs[index].name; + tz->threshold_attrs[index].attr.attr.mode = S_IWUSR | S_IRUGO; + tz->threshold_attrs[index].attr.show = temp_thres_hyst_show; + tz->threshold_attrs[index].attr.store = temp_thres_hyst_store; + attrs[index] = &tz->threshold_attrs[index].attr.attr; + ++index; + } + attrs[index] = NULL; + tz->threshold_attribute_group.attrs = attrs; + + return 0; +} + +static void delete_user_events_attrs(struct thermal_zone_device *tz) +{ + kfree(tz->threshold_attrs); + kfree(tz->threshold_attribute_group.attrs); +} +#else +static int create_user_events_attrs(struct thermal_zone_device *tz) +{ + return -EINVAL; +} + +static void delete_user_events_attrs(struct thermal_zone_device *tz) +{ +} +#endif + static ssize_t passive_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -625,16 +744,27 @@ int thermal_zone_create_device_groups(struct thermal_zone_device *tz, { const struct attribute_group **groups; int i, size, result; + int start = 0; /* we need one extra for trips and the NULL to terminate the array */ size = ARRAY_SIZE(thermal_zone_attribute_groups) + 2; + + result = create_user_events_attrs(tz); + if (!result) { + ++size; + ++start; + } + /* This also takes care of API requirement to be NULL terminated */ groups = kcalloc(size, sizeof(*groups), GFP_KERNEL); if (!groups) return -ENOMEM; - for (i = 0; i < size - 2; i++) - groups[i] = thermal_zone_attribute_groups[i]; + if (start) + groups[0] = &tz->threshold_attribute_group; + + for (i = 0; i < size - 2 - start; i++) + groups[i + start] = thermal_zone_attribute_groups[i]; if (tz->trips) { result = create_trip_attrs(tz, mask); @@ -660,6 +790,8 @@ void thermal_zone_destroy_device_groups(struct thermal_zone_device *tz) if (tz->trips) destroy_trip_attrs(tz); + delete_user_events_attrs(tz); + kfree(tz->device.groups); } diff --git a/include/linux/thermal.h b/include/linux/thermal.h index f5e1e7c6a9a2..ee9d79ace7ce 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -102,6 +102,12 @@ struct thermal_zone_device_ops { enum thermal_trend *); int (*notify) (struct thermal_zone_device *, int, enum thermal_trip_type); + int (*set_temp_thres_low)(struct thermal_zone_device *, int); + int (*set_temp_thres_high)(struct thermal_zone_device *, int); + int (*set_temp_thres_hyst)(struct thermal_zone_device *, int); + int (*get_temp_thres_low)(struct thermal_zone_device *, int *); + int (*get_temp_thres_high)(struct thermal_zone_device *, int *); + int (*get_temp_thres_hyst)(struct thermal_zone_device *, int *); }; struct thermal_cooling_device_ops { @@ -208,6 +214,8 @@ struct thermal_zone_device { struct list_head node; struct delayed_work poll_queue; enum thermal_notify_event notify_event; + struct attribute_group threshold_attribute_group; + struct thermal_attr *threshold_attrs; }; /** @@ -558,7 +566,7 @@ enum thermal_device_events { THERMAL_PERF_CHANGED, }; -#ifdef CONFIG_THERMAL_USER_EVENT_INTERFACE +#if IS_ENABLED(CONFIG_THERMAL_USER_EVENT_INTERFACE) int thermal_dev_send_event(int zone_id, enum thermal_device_events event, u64 event_data); #else int thermal_dev_send_event(int zone_id, enum thermal_device_events event, u64 event_data) From patchwork Mon May 4 18:16:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: srinivas pandruvada X-Patchwork-Id: 11527345 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7109C1668 for ; Mon, 4 May 2020 18:16:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 633E920661 for ; Mon, 4 May 2020 18:16:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1732382AbgEDSQp (ORCPT ); Mon, 4 May 2020 14:16:45 -0400 Received: from mga12.intel.com ([192.55.52.136]:27145 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732278AbgEDSQo (ORCPT ); Mon, 4 May 2020 14:16:44 -0400 IronPort-SDR: OphSXnXIigcuahTUBJ6R4Xomb3S2mYLZ/GjwWJQMrV8+KikGCrfNiEBfl/Jq2admAt0QkYHEbL cvhqS86rQgWQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 May 2020 11:16:34 -0700 IronPort-SDR: dNMkY38EIkVXXa27TiyYYe6z7BrjLhUlmnlPlboysHT6WLyDfmGS7ojOVc1TzjIpr7OlrMWib6 UBwG1bEKSyLA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,352,1583222400"; d="scan'208";a="259427135" Received: from spandruv-mobl.amr.corp.intel.com ([10.212.145.237]) by orsmga003.jf.intel.com with ESMTP; 04 May 2020 11:16:33 -0700 From: Srinivas Pandruvada To: rui.zhang@intel.com, daniel.lezcano@linaro.org, amit.kucheria@verdurent.com Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [RFC][PATCH 4/5] thermal: Add support for setting polling interval Date: Mon, 4 May 2020 11:16:15 -0700 Message-Id: <20200504181616.175477-5-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200504181616.175477-1-srinivas.pandruvada@linux.intel.com> References: <20200504181616.175477-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Add new attribute in the thermal syfs for setting temperature sampling interval when CONFIG_THERMAL_USER_EVENT_INTERFACE is defined. The default value is 0, which means no polling. At this interval user space will get an event THERMAL_TEMP_SAMPLE with temperature sample. This reuses existing polling mecahnism when polling or passive delay is specified during zone registry. To avoid interference with passive and polling delay, this new polling attribute can't be used for those zones. Signed-off-by: Srinivas Pandruvada --- drivers/thermal/thermal_core.c | 7 +++++++ drivers/thermal/thermal_sysfs.c | 36 +++++++++++++++++++++++++++++++-- include/linux/thermal.h | 1 + 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 14770d882d42..17cd799b0073 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -313,6 +313,8 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz) thermal_zone_device_set_polling(tz, tz->passive_delay); else if (tz->polling_delay) thermal_zone_device_set_polling(tz, tz->polling_delay); + else if (tz->temp_polling_delay) + thermal_zone_device_set_polling(tz, tz->temp_polling_delay); else thermal_zone_device_set_polling(tz, 0); @@ -446,6 +448,11 @@ static void update_temperature(struct thermal_zone_device *tz) tz->temperature = temp; mutex_unlock(&tz->lock); + if (tz->temp_polling_delay) { + thermal_dev_send_event(tz->id, THERMAL_TEMP_SAMPLE, temp); + monitor_thermal_zone(tz); + } + trace_thermal_temperature(tz); if (tz->last_temperature == THERMAL_TEMP_INVALID) dev_dbg(&tz->device, "last_temperature N/A, current_temperature=%d\n", diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index aa85424c3ac4..0df7997993fe 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -248,6 +248,36 @@ create_thres_attr(temp_thres_low); create_thres_attr(temp_thres_high); create_thres_attr(temp_thres_hyst); +static ssize_t +temp_polling_delay_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct thermal_zone_device *tz = to_thermal_zone(dev); + int val; + + if (kstrtoint(buf, 10, &val)) + return -EINVAL; + + if (val && val < 1000) + return -EINVAL; + + tz->temp_polling_delay = val; + thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + + return count; +} + +static ssize_t +temp_polling_delay_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct thermal_zone_device *tz = to_thermal_zone(dev); + + return sprintf(buf, "%d\n", tz->temp_polling_delay); +} + +static DEVICE_ATTR_RW(temp_polling_delay); + static int create_user_events_attrs(struct thermal_zone_device *tz) { struct attribute **attrs; @@ -260,8 +290,8 @@ static int create_user_events_attrs(struct thermal_zone_device *tz) if (tz->ops->get_temp_thres_high) ++index; - /* One additional space for NULL */ - attrs = kcalloc(index + 1, sizeof(*attrs), GFP_KERNEL); + /* One additional space for NULL and temp_pollling_delay */ + attrs = kcalloc(index + 2, sizeof(*attrs), GFP_KERNEL); if (!attrs) return -ENOMEM; @@ -312,6 +342,8 @@ static int create_user_events_attrs(struct thermal_zone_device *tz) attrs[index] = &tz->threshold_attrs[index].attr.attr; ++index; } + if (!tz->polling_delay && !tz->passive_delay) + attrs[index++] = &dev_attr_temp_polling_delay.attr; attrs[index] = NULL; tz->threshold_attribute_group.attrs = attrs; diff --git a/include/linux/thermal.h b/include/linux/thermal.h index ee9d79ace7ce..0ec4bd8c9c5c 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -216,6 +216,7 @@ struct thermal_zone_device { enum thermal_notify_event notify_event; struct attribute_group threshold_attribute_group; struct thermal_attr *threshold_attrs; + int temp_polling_delay; }; /** From patchwork Mon May 4 18:16:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: srinivas pandruvada X-Patchwork-Id: 11527347 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 79A7E15AB for ; Mon, 4 May 2020 18:16:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6B48A20661 for ; Mon, 4 May 2020 18:16:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1731138AbgEDSQv (ORCPT ); Mon, 4 May 2020 14:16:51 -0400 Received: from mga12.intel.com ([192.55.52.136]:27142 "EHLO mga12.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732300AbgEDSQp (ORCPT ); Mon, 4 May 2020 14:16:45 -0400 IronPort-SDR: ltC6PEoAL5UZSGBC6COMMyP3JP0yADVUk6h2a5cRJv9iWwLq72heEXfqLgfHh48UEDUgbrZFq4 LZ6K7wYNz2Tw== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga003.jf.intel.com ([10.7.209.27]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 May 2020 11:16:35 -0700 IronPort-SDR: mvLLiJAuzzRExPXFYoNI1g29gexMvcoi/88KTXr0i7bmqEuaESdFvfjEiWu77537aI5xy8CkGU GIbfMIsfrafg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,352,1583222400"; d="scan'208";a="259427141" Received: from spandruv-mobl.amr.corp.intel.com ([10.212.145.237]) by orsmga003.jf.intel.com with ESMTP; 04 May 2020 11:16:34 -0700 From: Srinivas Pandruvada To: rui.zhang@intel.com, daniel.lezcano@linaro.org, amit.kucheria@verdurent.com Cc: linux-kernel@vger.kernel.org, linux-pm@vger.kernel.org, Srinivas Pandruvada Subject: [RFC][PATCH 5/5] thermal: int340x: Use new device interface Date: Mon, 4 May 2020 11:16:16 -0700 Message-Id: <20200504181616.175477-6-srinivas.pandruvada@linux.intel.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: <20200504181616.175477-1-srinivas.pandruvada@linux.intel.com> References: <20200504181616.175477-1-srinivas.pandruvada@linux.intel.com> MIME-Version: 1.0 Sender: linux-pm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org Use the new framework to send notifications for: - Setting temperature threshold for notification to avoid polling - Send THERMAL_TRIP_REACHED event on reaching threshold - Send THERMAL_TRIP_UPDATE when firmware change the the existing trip temperature Signed-off-by: Srinivas Pandruvada --- .../intel/int340x_thermal/int3403_thermal.c | 3 ++ .../int340x_thermal/int340x_thermal_zone.c | 29 +++++++++++++++++++ .../int340x_thermal/int340x_thermal_zone.h | 7 +++++ .../processor_thermal_device.c | 1 + 4 files changed, 40 insertions(+) diff --git a/drivers/thermal/intel/int340x_thermal/int3403_thermal.c b/drivers/thermal/intel/int340x_thermal/int3403_thermal.c index f86cbb125e2f..77c014a113a4 100644 --- a/drivers/thermal/intel/int340x_thermal/int3403_thermal.c +++ b/drivers/thermal/intel/int340x_thermal/int3403_thermal.c @@ -63,15 +63,18 @@ static void int3403_notify(acpi_handle handle, switch (event) { case INT3403_PERF_CHANGED_EVENT: + int340x_thermal_send_user_event(obj->int340x_zone, THERMAL_PERF_CHANGED, 0); break; case INT3403_THERMAL_EVENT: int340x_thermal_zone_device_update(obj->int340x_zone, THERMAL_TRIP_VIOLATED); + int340x_thermal_send_user_event(obj->int340x_zone, THERMAL_TRIP_REACHED, 0); break; case INT3403_PERF_TRIP_POINT_CHANGED: int340x_thermal_read_trips(obj->int340x_zone); int340x_thermal_zone_device_update(obj->int340x_zone, THERMAL_TRIP_CHANGED); + int340x_thermal_send_user_event(obj->int340x_zone, THERMAL_TRIP_UPDATE, 0); break; default: dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event); diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c index 432213272f1e..9568a2db7afd 100644 --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.c @@ -146,12 +146,41 @@ static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone, return 0; } +static int int340x_thermal_get_thres_low(struct thermal_zone_device *zone, int *temp) +{ + struct int34x_thermal_zone *d = zone->devdata; + + *temp = d->aux_trips[0]; + + return 0; +} + +static int int340x_thermal_set_thres_low(struct thermal_zone_device *zone, int temp) +{ + struct int34x_thermal_zone *d = zone->devdata; + acpi_status status; + + if (d->override_ops && d->override_ops->set_trip_temp) + return d->override_ops->set_trip_temp(zone, 0, temp); + + status = acpi_execute_simple_method(d->adev->handle, "PAT0", + millicelsius_to_deci_kelvin(temp)); + if (ACPI_FAILURE(status)) + return -EIO; + + d->aux_trips[0] = temp; + + return 0; +} + static struct thermal_zone_device_ops int340x_thermal_zone_ops = { .get_temp = int340x_thermal_get_zone_temp, .get_trip_temp = int340x_thermal_get_trip_temp, .get_trip_type = int340x_thermal_get_trip_type, .set_trip_temp = int340x_thermal_set_trip_temp, .get_trip_hyst = int340x_thermal_get_trip_hyst, + .set_temp_thres_low = int340x_thermal_set_thres_low, + .get_temp_thres_low = int340x_thermal_get_thres_low, }; static int int340x_thermal_get_trip_config(acpi_handle handle, char *name, diff --git a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h index 3b4971df1b33..142027e4955f 100644 --- a/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h +++ b/drivers/thermal/intel/int340x_thermal/int340x_thermal_zone.h @@ -58,4 +58,11 @@ static inline void int340x_thermal_zone_device_update( thermal_zone_device_update(tzone->zone, event); } +static inline void int340x_thermal_send_user_event( + struct int34x_thermal_zone *tzone, + enum thermal_device_events event, + u64 data) +{ + thermal_dev_send_event(tzone->zone->id, event, data); +} #endif diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c index 297db1d2d960..e25f01948d33 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_device.c @@ -340,6 +340,7 @@ static void proc_thermal_notify(acpi_handle handle, u32 event, void *data) proc_thermal_read_ppcc(proc_priv); int340x_thermal_zone_device_update(proc_priv->int340x_zone, THERMAL_DEVICE_POWER_CAPABILITY_CHANGED); + int340x_thermal_send_user_event(proc_priv->int340x_zone, THERMAL_PERF_CHANGED, 0); break; default: dev_dbg(proc_priv->dev, "Unsupported event [0x%x]\n", event);