From patchwork Wed Feb 22 10:14:09 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Amit Daniel Kachhap X-Patchwork-Id: 6878 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 47A9923E48 for ; Wed, 22 Feb 2012 10:16:19 +0000 (UTC) Received: from mail-iy0-f180.google.com (mail-iy0-f180.google.com [209.85.210.180]) by fiordland.canonical.com (Postfix) with ESMTP id 0529FA186A7 for ; Wed, 22 Feb 2012 10:16:18 +0000 (UTC) Received: by mail-iy0-f180.google.com with SMTP id z7so14190952iab.11 for ; Wed, 22 Feb 2012 02:16:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=mime-version:x-forwarded-to:x-forwarded-for:delivered-to :received-spf:dkim-signature:sender:from:to:cc:subject:date :message-id:x-mailer:in-reply-to:references; bh=AMeyBTkTyOldPTLlMdHInvfnt02SiBhvH43MY56ST9s=; b=crveZmlObN++d1WUw0CvOdUihYwFRnePZ4XyuM0bTir8cX1BQt2XC3xHwGaSWpzvNd ixRsfhVlgy6t8zojPMLI7Z+9T33ItPCiJQpEtLWed4s5VjzRppFNdteDleW5UjAbaNvZ yo4HkwNVXZR+uskDDovXlPu1UnxZTaGRNONak= MIME-Version: 1.0 Received: by 10.42.131.129 with SMTP id z1mr25170518ics.53.1329905778741; Wed, 22 Feb 2012 02:16:18 -0800 (PST) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.11.10 with SMTP id r10csp130296ibr; Wed, 22 Feb 2012 02:16:18 -0800 (PST) Received: by 10.68.211.132 with SMTP id nc4mr72004432pbc.109.1329905778008; Wed, 22 Feb 2012 02:16:18 -0800 (PST) Received: from mail-pw0-f53.google.com (mail-pw0-f53.google.com [209.85.160.53]) by mx.google.com with ESMTPS id g9si28222995pbd.101.2012.02.22.02.16.17 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 22 Feb 2012 02:16:18 -0800 (PST) Received-SPF: pass (google.com: domain of amitdanielk@gmail.com designates 209.85.160.53 as permitted sender) client-ip=209.85.160.53; Authentication-Results: mx.google.com; spf=pass (google.com: domain of amitdanielk@gmail.com designates 209.85.160.53 as permitted sender) smtp.mail=amitdanielk@gmail.com; dkim=pass header.i=@gmail.com Received: by mail-pw0-f53.google.com with SMTP id rq13so10009753pbb.12 for ; Wed, 22 Feb 2012 02:16:17 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=sender:from:to:cc:subject:date:message-id:x-mailer:in-reply-to :references; bh=AMeyBTkTyOldPTLlMdHInvfnt02SiBhvH43MY56ST9s=; b=pgJiWjEfRTFqkLya/4H4vhU1n9BZsMhm2GT4cH/Ke/Uuh9sHAg2S0rcZATmMy8ZiGL yVF2yMegpzV1v84LPRT/lzqrGuvnzYdKkpN4+UmHzLAsVh2ZyYpk9aUF9jahemsNCv8Y abpmIbjbkYowYkOeTKf0o7Ef1v3Gpue7uhgBY= Received: by 10.68.224.9 with SMTP id qy9mr71052357pbc.102.1329905776977; Wed, 22 Feb 2012 02:16:16 -0800 (PST) Received: from localhost.localdomain ([115.113.119.130]) by mx.google.com with ESMTPS id r10sm30178210pbs.12.2012.02.22.02.16.13 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 22 Feb 2012 02:16:16 -0800 (PST) Sender: amit kachhap From: Amit Daniel Kachhap To: linux-pm@lists.linux-foundation.org Cc: linux-kernel@vger.kernel.org, mjg59@srcf.ucam.org, linux-acpi@vger.kernel.org, lenb@kernel.org, linaro-dev@lists.linaro.org, amit.kachhap@linaro.org, durgadoss.r@intel.com, rob.lee@linaro.org, patches@linaro.org Subject: [PATCH 3/4] thermal: Add generic cpuhotplug cooling implementation Date: Wed, 22 Feb 2012 15:44:09 +0530 Message-Id: <1329905650-30161-4-git-send-email-amit.kachhap@linaro.org> X-Mailer: git-send-email 1.7.1 In-Reply-To: <1329905650-30161-1-git-send-email-amit.kachhap@linaro.org> References: <1329905650-30161-1-git-send-email-amit.kachhap@linaro.org> X-Gm-Message-State: ALoCoQnZelDFXgVHMMSwmGGu6kwTFPjdEaqhHmZ8j0tvpMvIG8ZtXYbQZrCIUAePSTRaimfBUulX This patch adds support for generic cpu thermal cooling low level implementations using cpuhotplug based on the thermal level requested from user. Different cpu related cooling devices can be registered by the user and the binding of these cooling devices to the corresponding trip points can be easily done as the registration API's return the cooling device pointer. The user of these api's are responsible for passing the cpumask. Signed-off-by: Amit Daniel Kachhap --- Documentation/thermal/cpu-cooling-api.txt | 17 +++ drivers/thermal/cpu_cooling.c | 174 +++++++++++++++++++++++++++++ include/linux/cpu_cooling.h | 17 +++ 3 files changed, 208 insertions(+), 0 deletions(-) diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt index 04de67c..bdaf509 100644 --- a/Documentation/thermal/cpu-cooling-api.txt +++ b/Documentation/thermal/cpu-cooling-api.txt @@ -38,3 +38,20 @@ the cooling device pointer. This interface function unregisters the "thermal-cpufreq-%x" cooling device. cdev: Cooling device pointer which has to be unregistered. + +1.2 cpuhotplug registration api's + +1.2.1 struct thermal_cooling_device *cpuhotplug_cooling_register( + const struct cpumask *mask_val) + + This interface function registers the cpuhotplug cooling device with the name + "cpu-hotplug-%x". This api can support multiple instance of cpuhotplug cooling + devices. + + mask_val: all the allowed cpu's which can be hotplugged out. + +1.1.2 void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev) + + This interface function unregisters the "thermal-cpuhotplug-%x" cooling device. + + cdev: Cooling device pointer which has to be unregistered. diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 298f550..3d2d87f 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -48,6 +48,21 @@ static struct cpufreq_cooling_device *notify_cpufreq; static DEFINE_PER_CPU(unsigned int, max_policy_freq); #endif /*CONFIG_CPU_FREQ*/ +#ifdef CONFIG_HOTPLUG_CPU +struct hotplug_cooling_device { + int id; + struct thermal_cooling_device *cool_dev; + unsigned int hotplug_state; + const struct cpumask *allowed_cpus; + struct list_head node; +}; + +static LIST_HEAD(cooling_cpuhotplug_list); +static DEFINE_MUTEX(cooling_cpuhotplug_lock); +static DEFINE_IDR(cpuhotplug_idr); +#endif /*CONFIG_HOTPLUG_CPU*/ + + static int get_idr(struct idr *idr, struct mutex *lock, int *id) { int err; @@ -308,3 +323,162 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) } EXPORT_SYMBOL(cpufreq_cooling_unregister); #endif /*CONFIG_CPU_FREQ*/ + +#ifdef CONFIG_HOTPLUG_CPU +/* + * cpu hotplug cooling device callback functions + */ +static int cpuhotplug_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct hotplug_cooling_device *hotplug_dev = NULL; + + mutex_lock(&cooling_cpuhotplug_lock); + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) + if (hotplug_dev && hotplug_dev->cool_dev == cdev) + break; + + mutex_unlock(&cooling_cpuhotplug_lock); + if (!hotplug_dev || hotplug_dev->cool_dev != cdev) + return -EINVAL; + + *state = 1; + return 0; +} + +static int cpuhotplug_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct hotplug_cooling_device *hotplug_dev = NULL; + + mutex_lock(&cooling_cpuhotplug_lock); + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) + if (hotplug_dev && hotplug_dev->cool_dev == cdev) + break; + + mutex_unlock(&cooling_cpuhotplug_lock); + if (!hotplug_dev || hotplug_dev->cool_dev != cdev) + return -EINVAL; + + /* + * This cooling device may be of type ACTIVE, so state field can + * be 0 or 1 + */ + *state = hotplug_dev->hotplug_state; + return 0; +} + +/*This cooling may be as ACTIVE type*/ +static int cpuhotplug_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + int cpuid, this_cpu = smp_processor_id(); + struct hotplug_cooling_device *hotplug_dev = NULL; + + mutex_lock(&cooling_cpuhotplug_lock); + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) + if (hotplug_dev && hotplug_dev->cool_dev == cdev) + break; + + mutex_unlock(&cooling_cpuhotplug_lock); + if (!hotplug_dev || hotplug_dev->cool_dev != cdev) + return -EINVAL; + + if (hotplug_dev->hotplug_state == state) + return 0; + + /* + * This cooling device may be of type ACTIVE, so state field can + * be 0 or 1 + */ + if (state == 1) { + for_each_cpu(cpuid, hotplug_dev->allowed_cpus) { + if (cpu_online(cpuid) && (cpuid != this_cpu)) + cpu_down(cpuid); + } + } else if (state == 0) { + for_each_cpu(cpuid, hotplug_dev->allowed_cpus) { + if (!cpu_online(cpuid) && (cpuid != this_cpu)) + cpu_up(cpuid); + } + } else { + return -EINVAL; + } + + hotplug_dev->hotplug_state = state; + + return 0; +} +/* bind hotplug callbacks to cpu hotplug cooling device */ +static struct thermal_cooling_device_ops cpuhotplug_cooling_ops = { + .get_max_state = cpuhotplug_get_max_state, + .get_cur_state = cpuhotplug_get_cur_state, + .set_cur_state = cpuhotplug_set_cur_state, +}; + +struct thermal_cooling_device *cpuhotplug_cooling_register( + const struct cpumask *mask_val) +{ + struct thermal_cooling_device *cool_dev; + struct hotplug_cooling_device *hotplug_dev; + int ret = 0; + char dev_name[THERMAL_NAME_LENGTH]; + + hotplug_dev = + kzalloc(sizeof(struct hotplug_cooling_device), GFP_KERNEL); + + if (!hotplug_dev) + return ERR_PTR(-ENOMEM); + + ret = get_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock, + &hotplug_dev->id); + if (ret) { + kfree(hotplug_dev); + return ERR_PTR(-EINVAL); + } + + sprintf(dev_name, "cpu-hotplug-%u", hotplug_dev->id); + + hotplug_dev->hotplug_state = 0; + hotplug_dev->allowed_cpus = mask_val; + cool_dev = thermal_cooling_device_register(dev_name, hotplug_dev, + &cpuhotplug_cooling_ops); + if (!cool_dev) { + release_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock, + hotplug_dev->id); + kfree(hotplug_dev); + return ERR_PTR(-EINVAL); + } + + hotplug_dev->cool_dev = cool_dev; + mutex_lock(&cooling_cpuhotplug_lock); + list_add_tail(&hotplug_dev->node, &cooling_cpuhotplug_list); + mutex_unlock(&cooling_cpuhotplug_lock); + + return cool_dev; +} +EXPORT_SYMBOL(cpuhotplug_cooling_register); + +void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev) +{ + struct hotplug_cooling_device *hotplug_dev = NULL; + + mutex_lock(&cooling_cpuhotplug_lock); + list_for_each_entry(hotplug_dev, &cooling_cpuhotplug_list, node) + if (hotplug_dev && hotplug_dev->cool_dev == cdev) + break; + + if (!hotplug_dev || hotplug_dev->cool_dev != cdev) { + mutex_unlock(&cooling_cpuhotplug_lock); + return; + } + + list_del(&hotplug_dev->node); + mutex_unlock(&cooling_cpuhotplug_lock); + thermal_cooling_device_unregister(hotplug_dev->cool_dev); + release_idr(&cpuhotplug_idr, &cooling_cpuhotplug_lock, + hotplug_dev->id); + kfree(hotplug_dev); +} +EXPORT_SYMBOL(cpuhotplug_cooling_unregister); +#endif /*CONFIG_HOTPLUG_CPU*/ diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h index 5dc5632..8d195d5 100644 --- a/include/linux/cpu_cooling.h +++ b/include/linux/cpu_cooling.h @@ -50,5 +50,22 @@ static inline void cpufreq_cooling_unregister( return; } #endif /*CONFIG_CPU_FREQ*/ +#ifdef CONFIG_HOTPLUG_CPU +extern struct thermal_cooling_device *cpuhotplug_cooling_register( + const struct cpumask *mask_val); + +extern void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev); +#else /*!CONFIG_HOTPLUG_CPU*/ +static inline struct thermal_cooling_device *cpuhotplug_cooling_register( + const struct cpumask *mask_val) +{ + return NULL; +} +static inline void cpuhotplug_cooling_unregister( + struct thermal_cooling_device *cdev) +{ + return; +} +#endif /*CONFIG_HOTPLUG_CPU*/ #endif /* __CPU_COOLING_H__ */