From patchwork Tue Jan 23 15:34:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 125544 Delivered-To: patch@linaro.org Received: by 10.46.66.141 with SMTP id h13csp1828508ljf; Tue, 23 Jan 2018 07:38:22 -0800 (PST) X-Google-Smtp-Source: AH8x2269zJm0V13njJSyNHtpeuMun8f5FVHAPnvRbB2G0WJcthfblihiybZ23kNMvYWsqcxiCsxQ X-Received: by 10.36.112.206 with SMTP id f197mr3779829itc.133.1516721902601; Tue, 23 Jan 2018 07:38:22 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516721902; cv=none; d=google.com; s=arc-20160816; b=aeGmk4xRHfhzIw+4sCc0AMtszfHF9eaBaDDwCjUKkODrb6iMtlbdNGDnVn3W5XY23H v/yt5imrc9xBbhkmszdbxtE5k2Z+JapWB+Osnw2+iuFCHjZatYIJ1Dpw9ZEDsL7uVJZR yASEyBJf0kCm819FZ9R2k6Gwq+o5PUaxjI9VtlKpZ4ip0QxKKKFemUhE6+TR5ftBSVg1 kd6I5DtQrtCXuC+wp67GnEOoS5G7bH2iJ/7W4O3bxlAVIDSTqHsMQbWiCXJc+TPgo/RH 95KEjeZz+fHVa9UYotpJeYgl99vjjYypjFfeS6127tGiHTQ+7016L82BEwgD7XncVNLW 86kg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=VGobxTXbpF8Wnetd/GFIIq1m84Lto7wGE/1IccwqmTQ=; b=v7J0suc6ZMIERCH/UKmI7cG7FPAxDyJWLt33PWN56s1rSlM8Xf7Dfvk4zCSIZZzzxG EEx2d+ZwUfca/fmzgPGHqqupWG0XEZDB28EnZXoRjdUL5cmM6qZViYAwVJDYMcKzN/a2 by5SnXiv/fqfdsBGmeJhQJnOOk1iT3mHiPsdJRa/FdbFQNOLueWlQn3ggfmbndghcRP0 Tv7BVzqq04A6RvvVSYFwlxUl+vVLU+QYq7Ja8xT865NjnX53PPsUvqEkLhu5lLwvBpgC S25mqlXmZYpaI0H3YAyQcI/CC9wXXe78XyRyOS8OWWSxPmJd6I20k3PQc5yxllRuKE6Y J0gQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=GMS22S+v; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id e5si8071681itf.84.2018.01.23.07.38.22; Tue, 23 Jan 2018 07:38:22 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=GMS22S+v; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752144AbeAWPiU (ORCPT + 28 others); Tue, 23 Jan 2018 10:38:20 -0500 Received: from mail-wm0-f67.google.com ([74.125.82.67]:46979 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751374AbeAWPfY (ORCPT ); Tue, 23 Jan 2018 10:35:24 -0500 Received: by mail-wm0-f67.google.com with SMTP id 143so2628612wma.5 for ; Tue, 23 Jan 2018 07:35:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=VGobxTXbpF8Wnetd/GFIIq1m84Lto7wGE/1IccwqmTQ=; b=GMS22S+vz1TNt23TStJJSy4KDaLdGZz64Ivu9LivL0QwTGxlFpSJgWdT42HsAjWkUn Peb9mxWP3H47sNw7WpZ8tTqmroGL7ZumnuyIl5dN9wS3um73g6R8Y7/kUhdrTNLWAtXH 98QCfFgGTLaC9Z3hzynwcE4AEdnZu2o8ga580= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=VGobxTXbpF8Wnetd/GFIIq1m84Lto7wGE/1IccwqmTQ=; b=TKjlOFH1WhgF5g6ZoMaonuLmZaLhyU/EZGpUDeP1okfMfA1CBncqPJGQyGLAPS7Mln 0d98OCl4ceTefLpa3pagATqHZ2wh4uDRv8tqvo8V/6q90BVDSFa6LonakJd4gbbZAwWf 3V5nqfpYU4OR4HbqJ8Ppxu3lSk+KwKsRZmXflynTvsKtGn5CKkRVFbVIFKcy/qLlsouS Vcgd3qkDiv60U7fWql0Jcj0UMKM5+5tBBpGfEBxlVWRbPC1LApfEw0XMGiKpkczkiRJ8 rs34KFulB0TDdECoENdmdhmUt0XW9PUysDyr4/KPt8WuwlPe8s29y+tk3a8x1RbucbKl 1Dig== X-Gm-Message-State: AKwxytflh1esnLJdn1yi6SsKw7tR7t+kuiJBC2BimQGgNkD0q7vHkuyw w1HQwGK538gIvWWske+F/g1rPw== X-Received: by 10.28.118.15 with SMTP id r15mr2514688wmc.88.1516721722833; Tue, 23 Jan 2018 07:35:22 -0800 (PST) Received: from localhost.localdomain ([2a01:e35:879a:6cd0:8138:f09d:5869:1250]) by smtp.gmail.com with ESMTPSA id o98sm915624wrb.19.2018.01.23.07.35.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 23 Jan 2018 07:35:22 -0800 (PST) From: Daniel Lezcano To: edubezval@gmail.com Cc: kevin.wangtao@linaro.org, leo.yan@linaro.org, vincent.guittot@linaro.org, amit.kachhap@gmail.com, viresh.kumar@linaro.org, linux-kernel@vger.kernel.org, Javi Merino , Zhang Rui , linux-pm@vger.kernel.org (open list:THERMAL/CPU_COOLING) Subject: [PATCH 1/8] thermal/drivers/cpu_cooling: Fixup the header and copyright Date: Tue, 23 Jan 2018 16:34:24 +0100 Message-Id: <1516721671-16360-2-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> References: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The copyright format does not conform to the format requested by Linaro: https://wiki.linaro.org/Copyright Fix it. Signed-off-by: Daniel Lezcano --- drivers/thermal/cpu_cooling.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) -- 2.7.4 diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index dc63aba..988fc55 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -2,9 +2,11 @@ * linux/drivers/thermal/cpu_cooling.c * * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) - * Copyright (C) 2012 Amit Daniel * - * Copyright (C) 2014 Viresh Kumar + * Copyright (C) 2018 Linaro Limited. + * + * Authors: Amit Daniel + * Viresh Kumar * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * This program is free software; you can redistribute it and/or modify From patchwork Tue Jan 23 15:34:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 125543 Delivered-To: patch@linaro.org Received: by 10.46.66.141 with SMTP id h13csp1828257ljf; Tue, 23 Jan 2018 07:37:53 -0800 (PST) X-Google-Smtp-Source: AH8x227g2eJJJT0iqkBI8TyhFnxe9XjqGrdkCjTRNGkHGpIByKy0qUCN+1HxTvp+yEoL/pgeajUi X-Received: by 10.107.198.86 with SMTP id w83mr3966765iof.75.1516721872990; Tue, 23 Jan 2018 07:37:52 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516721872; cv=none; d=google.com; s=arc-20160816; b=qMorGgFC2E9VCCRA0nir/oxjTd/5TksoSI4YNwtEZBBbevRekdgaI0bbk5r8WGrA/h 5J72+bXt2iH2BHcX6HMeJQbloTslyUGz5CTyUJKBADpBAhvoDqyMKRAjHxj5HxEajSgw gLPi9fYqDjYdQkyYGZSWv/hKtr1208OWXdsp8J5x5pFBDYqlW1yZJr9LOhXN2IY0UmxN GYf+LeG9f0rmlYa2zKPcBeaf4pKEFJvz8FYH0nzO+NQBJUqmbMSSQfm1sj/kV6vmxOJb LjgV1GgbL6qRy8zOfqcodGIdIiUFI1Bvovt/zsf1brQIqz1hk8uRmSIet9UcNCV14QXr fpZQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=UckMi7dtZhalpmHgnLZADqEUWSKn04OayeolrhwQt58=; b=o3EV7Lel+GjfWve1Rp7OZxZngA4wgG34tGRbS2E0pPI7Pq5hjShYSlwQrqoUHwqe7v U/tePesYrsKgI2YC6CafSfVzDK/SY/XxDGF3fG53HyUhZvgAz/8swKZhM5EtL8ZO2L5p qCfgXvrHIMWFquHe8j/YcI8w9n6qjG8JdaNxW8jDINVGtR+B19s40vH/GAlj4680HWtp dvxYTkDJ9VHEzJ01AiswLCBBPk4OfWrLq4izK/7J0VKwe1wWi6bYSaMzoZsT6NfKrGds 8poYXQPzbDLr0L4foYfUcuOmCsPU68zLA0GPE6uGa2LwNB3CQ4Z7C594pHqEgecquOCT AP8g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=S+arlwrs; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j42si15671311iod.69.2018.01.23.07.37.52; Tue, 23 Jan 2018 07:37:52 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=S+arlwrs; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752225AbeAWPhw (ORCPT + 28 others); Tue, 23 Jan 2018 10:37:52 -0500 Received: from mail-wm0-f65.google.com ([74.125.82.65]:45149 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751233AbeAWPf1 (ORCPT ); Tue, 23 Jan 2018 10:35:27 -0500 Received: by mail-wm0-f65.google.com with SMTP id i186so2635609wmi.4 for ; Tue, 23 Jan 2018 07:35:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=UckMi7dtZhalpmHgnLZADqEUWSKn04OayeolrhwQt58=; b=S+arlwrsDnls4y68i8+vt1O2A/zByUOym0YCW+NPHHeb7BnRBq4TlmaksYLb/Tef2H UF1wvsqJYeoxbXMX+l3JxFluxp1n77P/7onpjIs82knrOLRzWoPjgsidMIKQncbmig4B YSQ5pD0YwQ6HdWJkbIc1bfF87Ix90MOEFCmTE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=UckMi7dtZhalpmHgnLZADqEUWSKn04OayeolrhwQt58=; b=gTkqJ9RBwzUi1TbQxBCmF8dJLZeTWV5drLEGm34+UJtwZ04PizKU3A1WxXCivsKXwx nKiXy81uGP6IG+55mUsXl1Gjv+r1HTUAV/1wQ98943tgCJYr/cJxPCJXy9tBYjzGAYK7 eb3kKN+miW8rnOEmEW1lB/KbqMc/AAqy2WgBQST9AE5NChpA70vGbYGBYBkQvyVR2sem n429lxkHZ9eRBzOnJ5r8ccNSHCA6d3SKoeQu4vud60il0FVlxWHZ2QcJfZxcfDljfuXF 1D2TYcE9n+Y5s5bSBVyV1QF4LNGyAmKz3LaqyWf1hGi/mfgcRZD6y7VzEOWMAbWc0ZTw ADzA== X-Gm-Message-State: AKwxytfi5q6/w+buGI88PDpRBlgRAbx/jLlkkvNNGLv3N6HwZ6bmkJUw m97VWCe7Tdxoe4SZl0qaoqd4AQ== X-Received: by 10.28.168.8 with SMTP id r8mr2421317wme.157.1516721726406; Tue, 23 Jan 2018 07:35:26 -0800 (PST) Received: from localhost.localdomain ([2a01:e35:879a:6cd0:8138:f09d:5869:1250]) by smtp.gmail.com with ESMTPSA id o98sm915624wrb.19.2018.01.23.07.35.25 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 23 Jan 2018 07:35:25 -0800 (PST) From: Daniel Lezcano To: edubezval@gmail.com Cc: kevin.wangtao@linaro.org, leo.yan@linaro.org, vincent.guittot@linaro.org, amit.kachhap@gmail.com, viresh.kumar@linaro.org, linux-kernel@vger.kernel.org, Javi Merino , Zhang Rui , linux-pm@vger.kernel.org (open list:THERMAL/CPU_COOLING) Subject: [PATCH 3/8] thermal/drivers/cpu_cooling: Remove pointless field Date: Tue, 23 Jan 2018 16:34:26 +0100 Message-Id: <1516721671-16360-4-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> References: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The structure cpufreq_cooling_device provides a backpointer to the thermal device but this one is used for a trace and to unregister. For the trace, we don't really need this field and the unregister function as the same pointer passed as parameter. Remove it. Signed-off-by: Daniel Lezcano --- drivers/thermal/cpu_cooling.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) -- 2.7.4 Acked-by: Viresh Kumar diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index e62be75..d05bb73 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -88,7 +88,6 @@ struct cpufreq_cooling_device { unsigned int clipped_freq; unsigned int max_level; struct freq_table *freq_table; /* In descending order */ - struct thermal_cooling_device *cdev; struct cpufreq_policy *policy; struct list_head node; struct time_in_idle *idle_time; @@ -197,8 +196,7 @@ static int update_freq_table(struct cpufreq_cooling_device *cpufreq_cdev, dev = get_cpu_device(cpu); if (unlikely(!dev)) { - dev_warn(&cpufreq_cdev->cdev->device, - "No cpu device for cpu %d\n", cpu); + pr_warn("No cpu device for cpu %d\n", cpu); return -ENODEV; } @@ -762,7 +760,6 @@ __cpufreq_cooling_register(struct device_node *np, goto remove_ida; cpufreq_cdev->clipped_freq = cpufreq_cdev->freq_table[0].frequency; - cpufreq_cdev->cdev = cdev; mutex_lock(&cooling_list_lock); /* Register the notifier for first cpufreq cooling device */ @@ -922,7 +919,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); - thermal_cooling_device_unregister(cpufreq_cdev->cdev); + thermal_cooling_device_unregister(cdev); ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id); kfree(cpufreq_cdev->idle_time); kfree(cpufreq_cdev->freq_table); From patchwork Tue Jan 23 15:34:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 125538 Delivered-To: patch@linaro.org Received: by 10.46.66.141 with SMTP id h13csp1826974ljf; Tue, 23 Jan 2018 07:35:38 -0800 (PST) X-Google-Smtp-Source: AH8x225pQonjDG1S60UQltPSWeR6+8P7eDTEpL+UitLzAqLF0qXzoSoojCFIcadP8A2wYoYqCqJu X-Received: by 10.107.167.69 with SMTP id q66mr3946506ioe.130.1516721738103; Tue, 23 Jan 2018 07:35:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516721738; cv=none; d=google.com; s=arc-20160816; b=umz74CJrPxak/m02Morx5r1OkcwzhRXz7gy0dwvhJboL1RsAXs1SlP57Hx4+z2EUZp IPho+iyxA7sXU6gW8T/izUn5MyjOCqghiVJ0ZjBGj09V305WXHZvVIuAErLdriiBJc9z U/vZv4LxpP/hKg682oqvaZ4aptRZAzKuaJs7WmCGhSfrvrNtEggJiMPzlwh+7wbJTA8x g199EmCvN7jBcu+kDm9aXQqsQqBPdTg1hwXAeZNbO2IK6lz/8YHaB0sz7aA75cYjIxcw lA3vznaisflPlfFdktTOTIsklo4twYHq8ScTDRj8ZxnOV1xVjebnm4Xn3DO+TzdUFdIc gtQA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=sh97EkWc09kfczjwyPtKYXB2KEPdfcahX13diBwKfHY=; b=pRdL2RjJ7S85BQyRVzGukfPtqx7/4X//ASCxHNg4j0OHWtImWif98AKzFPAb0UpF0M 5k5Ht9//bNkWgnVk5eTfv2lYVz7w+tTb93ga942Y8cdAhYiI7WlmXKsUIReJILoHLZtk wdFcjQvCqi14fH5zCf73sludaNj1Ae+V3U35Az+tE8/pru0lI7ZATKrgeAJ4QAEN39/i bOZRWvkzDDazoDIApldfLSkQ039wThSL+EY6V5zutdCw1RxQ2B1TyejI4FbfeYpP17oK R0WDvZr3JYltXc+y7oaoAlUceUPNosxNU848obLuOTISy0+//mZJUqwVLnGIOC1/wCY+ c1Rg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=hM2n/88S; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 186si9515001ioc.215.2018.01.23.07.35.37; Tue, 23 Jan 2018 07:35:38 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=hM2n/88S; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752136AbeAWPfg (ORCPT + 28 others); Tue, 23 Jan 2018 10:35:36 -0500 Received: from mail-wm0-f65.google.com ([74.125.82.65]:47000 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751827AbeAWPf3 (ORCPT ); Tue, 23 Jan 2018 10:35:29 -0500 Received: by mail-wm0-f65.google.com with SMTP id 143so2629230wma.5 for ; Tue, 23 Jan 2018 07:35:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=sh97EkWc09kfczjwyPtKYXB2KEPdfcahX13diBwKfHY=; b=hM2n/88SU3dUsZOtkP//Q8IxLbtr/hTH8Lpi30aiPsRpVtwV93gi21vzxsGSzYqhRE n0W9CgfuTyKszvIl2O/RMYaIfxhlJ9e7cxjv5LrG/p4J8k4gslQfhSc+fXBAqRbdvlL9 VFLXkN5+JKLZO7NY5r5fz2SbNZreTraatWCfE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=sh97EkWc09kfczjwyPtKYXB2KEPdfcahX13diBwKfHY=; b=N02Q/+zvcyFScd1n0FDHEh6pMqtMldi3Bbd+NdNbIVGQmX1Hxau5tCThYyQSTekfiK nDuvFCMS0yaOD77VjB/iACGIxxZRwFMKrUN0RCpC7n4B5U+IVa0qlCsrGS1TAjJUdkX6 3OBUDky9wNP804++leDz+QfAo6bSh+HOHX9hWHqv8ITjsH8MB2n1jq9kguu3dchgnG/4 H9TrMwx/tZT28vGjY7jbhh6mGdWDRl850fSeY1YSMZl6FShAN45IqwWoMMszTPGDD2kh 3ls9HpCvjCa1FdO27oSHzxOVgPjtiucvL6N42TyaJkp1RIyD75UyN+MumiSagrqFv98D NHKQ== X-Gm-Message-State: AKwxytfCwx39qfn5Ki9x7RaqYQyV3+phbJWZ246JL7Q/hE/7wAQazAXT NaCUTyi1Ci2y5fq6ker5ejxtLA== X-Received: by 10.28.32.5 with SMTP id g5mr2026281wmg.62.1516721728143; Tue, 23 Jan 2018 07:35:28 -0800 (PST) Received: from localhost.localdomain ([2a01:e35:879a:6cd0:8138:f09d:5869:1250]) by smtp.gmail.com with ESMTPSA id o98sm915624wrb.19.2018.01.23.07.35.26 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 23 Jan 2018 07:35:27 -0800 (PST) From: Daniel Lezcano To: edubezval@gmail.com Cc: kevin.wangtao@linaro.org, leo.yan@linaro.org, vincent.guittot@linaro.org, amit.kachhap@gmail.com, viresh.kumar@linaro.org, linux-kernel@vger.kernel.org, Zhang Rui , linux-pm@vger.kernel.org (open list:THERMAL) Subject: [PATCH 4/8] thermal/drivers/Kconfig: Convert the CPU cooling device to a choice Date: Tue, 23 Jan 2018 16:34:27 +0100 Message-Id: <1516721671-16360-5-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> References: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The next changes will add new way to cool down a CPU. In order to sanitize and make the overall cpu cooling code consistent and robust we must prevent the cpu cooling devices to co-exists with the same purpose at the same time in the kernel. Make the CPU cooling device a choice in the Kconfig, so only one CPU cooling strategy can be chosen. Signed-off-by: Daniel Lezcano --- drivers/thermal/Kconfig | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) -- 2.7.4 diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 315ae29..925e73b 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -142,17 +142,31 @@ config THERMAL_GOV_POWER_ALLOCATOR allocating and limiting power to devices. config CPU_THERMAL - bool "generic cpu cooling support" - depends on CPU_FREQ + bool "Generic cpu cooling support" depends on THERMAL_OF help + Enable the CPU cooling features. If the system has no active + cooling device available, this option allows to use the CPU + as a cooling device. + +choice + prompt "CPU cooling strategies" + depends on CPU_THERMAL + default CPU_FREQ_THERMAL + help + Select the CPU cooling strategy. + +config CPU_FREQ_THERMAL + bool "CPU frequency cooling strategy" + depends on CPU_FREQ + help This implements the generic cpu cooling mechanism through frequency reduction. An ACPI version of this already exists (drivers/acpi/processor_thermal.c). This will be useful for platforms using the generic thermal interface and not the ACPI interface. - If you want this support, you should say Y here. +endchoice config CLOCK_THERMAL bool "Generic clock cooling support" From patchwork Tue Jan 23 15:34:28 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 125542 Delivered-To: patch@linaro.org Received: by 10.46.66.141 with SMTP id h13csp1827837ljf; Tue, 23 Jan 2018 07:37:01 -0800 (PST) X-Google-Smtp-Source: AH8x225fReipqq8szJN+qugcEzAyKzoWCpycw22kHnzYbykTiA8Ef/heSfeOmQQOSoyAYlHInnkw X-Received: by 10.36.110.143 with SMTP id w137mr3856956itc.119.1516721821769; Tue, 23 Jan 2018 07:37:01 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516721821; cv=none; d=google.com; s=arc-20160816; b=H1XmCglGfNfmGW2QiNw7xRy0lQz1oSaNRBXQnaFBEil9+kmKKH1PyyfKz0UdjO+gSC ugYc3k/wtdVRd56l3WGLzvj/hoQs9bhbGyDdJ3zYohikCCOqzjYN49EdIQdOUpNl6QFK KTEZ0F3f+1eTnjm+blRm+VBt/5t2RR/+lWlwD0cGoSnZI0IDxFgpP6jmtSEC6ax4julx qHKT+o2OyBbyoe+flE39ZS+JvTwgL/5kwdTOeI3/iygIb9w7L+Bj7QOUyBiImvDZXjwV VRstJu8cNzNVIWut0BYghpOhqYht6r+evRdnCaWSYweC2rqxFFlztj32J/4mRFE/5Tpp 46Vw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature:arc-authentication-results; bh=xVtCv7kbmrkBNh5/gLly9FsHJJD0rzKiXkBq+Vqv6Ck=; b=VkqunjZOI9NpUV/wjSk6X0ntXA2Gb10rpTTqmIPobi8xVsi/jz+PzJUmxGI5l+cB+e V7EMcyawZHxHyY5vsrGGhnJy7L0O9M5k3EBoScrgB4IlNC+W7LYbHo9LkjVGopiVBcZ7 IYQj260yn17lWpZXuybzYcBDPM5pcBnu7ACLoFw6FwNR6/BycN2CyXpxMfxBTjvfUg1l xcQXWxcQ4DyktHx2cuvZ+yNlOGklsD9+kxOjIU1l2StTnEIx/cY/4noFBoj3i2Yo4HE+ m20WGlxIZ6nlwrNfkGHJvKaW4ic4kR6hYMfaEZL9Dkk0NV4cIG3U1R8sSK5VRE1AtGIq FCCg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=FKMPNWv6; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j42si15671311iod.69.2018.01.23.07.37.01; Tue, 23 Jan 2018 07:37:01 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=FKMPNWv6; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752186AbeAWPg7 (ORCPT + 28 others); Tue, 23 Jan 2018 10:36:59 -0500 Received: from mail-wm0-f65.google.com ([74.125.82.65]:41856 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751409AbeAWPfc (ORCPT ); Tue, 23 Jan 2018 10:35:32 -0500 Received: by mail-wm0-f65.google.com with SMTP id f71so2673890wmf.0 for ; Tue, 23 Jan 2018 07:35:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=xVtCv7kbmrkBNh5/gLly9FsHJJD0rzKiXkBq+Vqv6Ck=; b=FKMPNWv6PKSTP0DtFujqkeWtR6fjLOZmxq1Q5wL/k44E/UdJVbrBG8kvRC0JUOf7DO LFcgaka2hYh4fsQQ7r/uAuDIED9JRN3ttaiZcZK1jBuPgsVte1CCSYmefTcJ1dQms8Pr yFE35dNZEqO3taEHk3qIJST1ldPiRlkX84BhQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=xVtCv7kbmrkBNh5/gLly9FsHJJD0rzKiXkBq+Vqv6Ck=; b=BFMI7erYwWXfZgcfA+2qiLn0ZU8KespiCK/gphVhMrCpVcOORD7/0ildGu5V350ceI ai/FXOQvdY4a4Sfk6VpE7iF//hOg4id8NQ4C8Y5p1HOZ8CQpI5ly514/CNaLJ3wOIUf4 cgNZ8AbxejNzyfT5rkvnJqesVNZs3CeoHRmpp9qrVDKt1BANqpJzmp2TDcnPE/rlYdGG XQ7av4i9GOzggJZ9H83Haw3vD5TgMFkzPuesndaK1XSHBlbzYg6J23hPgTYViST8hyBU w6EZdF3EqYAtydWfcCBkls7dZ3NUSrdey9n9m1dQM9Kevdk7cVBkF5KLNsWTGHbwa58Q x8hQ== X-Gm-Message-State: AKwxytfkq4kODk0RXi9yytSFvkUDk4lbyHWRRxX9jc96mSzfVJ4J40Lk pERJD0ehq/rdQRwjfFAQ7mP8Qw== X-Received: by 10.28.134.205 with SMTP id i196mr2535996wmd.117.1516721730511; Tue, 23 Jan 2018 07:35:30 -0800 (PST) Received: from localhost.localdomain ([2a01:e35:879a:6cd0:8138:f09d:5869:1250]) by smtp.gmail.com with ESMTPSA id o98sm915624wrb.19.2018.01.23.07.35.28 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 23 Jan 2018 07:35:29 -0800 (PST) From: Daniel Lezcano To: edubezval@gmail.com Cc: kevin.wangtao@linaro.org, leo.yan@linaro.org, vincent.guittot@linaro.org, amit.kachhap@gmail.com, viresh.kumar@linaro.org, linux-kernel@vger.kernel.org, Zhang Rui , Javi Merino , linux-pm@vger.kernel.org (open list:THERMAL) Subject: [PATCH 5/8] thermal/drivers/cpu_cooling: Introduce the cpu idle cooling driver Date: Tue, 23 Jan 2018 16:34:28 +0100 Message-Id: <1516721671-16360-6-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> References: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> MIME-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The cpu idle cooling driver performs synchronized idle injection across all cpus belonging to the same cluster and offers a new method to cool down a SoC. Each cluster has its own idle cooling device, each core has its own idle injection thread, each idle injection thread uses play_idle to enter idle. In order to reach the deepest idle state, each cooling device has the idle injection threads synchronized together. It has some similarity with the intel power clamp driver but it is actually designed to work on the ARM architecture via the DT with a mathematical proof with the power model which comes with the Documentation. The idle injection cycle is fixed while the running cycle is variable. That allows to have control on the device reactivity for the user experience. At the mitigation point the idle threads are unparked, they play idle the specified amount of time and they schedule themselves. The last thread sets the next idle injection deadline and when the timer expires it wakes up all the threads which in turn play idle again. Meanwhile the running cycle is changed by set_cur_state. When the mitigation ends, the threads are parked. The algorithm is self adaptive, so there is no need to handle hotplugging. If we take an example of the balanced point, we can use the DT for the hi6220. The sustainable power for the SoC is 3326mW to mitigate at 75°C. Eight cores running at full blast at the maximum OPP consumes 5280mW. The first value is given in the DT, the second is calculated from the OPP with the formula: Pdyn = Cdyn x Voltage^2 x Frequency As the SoC vendors don't want to share the static leakage values, we assume it is zero, so the Prun = Pdyn + Pstatic = Pdyn + 0 = Pdyn. In order to reduce the power to 3326mW, we have to apply a ratio to the running time. ratio = (Prun - Ptarget) / Ptarget = (5280 - 3326) / 3326 = 0,5874 We know the idle cycle which is fixed, let's assume 10ms. However from this duration we have to substract the wake up latency for the cluster idle state. In our case, it is 1.5ms. So for a 10ms latency for idle, we are really idle 8.5ms. As we know the idle duration and the ratio, we can compute the running cycle. running_cycle = 8.5 / 0.5874 = 14.47ms So for 8.5ms of idle, we have 14.47ms of running cycle, and that brings the SoC to the balanced trip point of 75°C. The driver has been tested on the hi6220 and it appears the temperature stabilizes at 75°C with an idle injection time of 10ms (8.5ms real) and running cycle of 14ms as expected by the theory above. Signed-off-by: Kevin WangTao Signed-off-by: Daniel Lezcano --- drivers/thermal/Kconfig | 10 + drivers/thermal/cpu_cooling.c | 471 ++++++++++++++++++++++++++++++++++++++++++ include/linux/cpu_cooling.h | 6 + 3 files changed, 487 insertions(+) -- 2.7.4 diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 925e73b..4bd4be7 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -166,6 +166,16 @@ config CPU_FREQ_THERMAL This will be useful for platforms using the generic thermal interface and not the ACPI interface. +config CPU_IDLE_THERMAL + bool "CPU idle cooling strategy" + depends on CPU_IDLE + help + This implements the generic CPU cooling mechanism through + idle injection. This will throttle the CPU by injecting + fixed idle cycle. All CPUs belonging to the same cluster + will enter idle synchronously to reach the deepest idle + state. + endchoice config CLOCK_THERMAL diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index d05bb73..916a627 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -10,18 +10,33 @@ * Viresh Kumar * */ +#undef DEBUG +#define pr_fmt(fmt) "CPU cooling: " fmt + #include #include #include +#include #include +#include #include +#include #include #include +#include +#include #include #include +#include + +#include +#include #include +#include + +#ifdef CONFIG_CPU_FREQ_THERMAL /* * Cooling state <-> CPUFreq frequency * @@ -926,3 +941,459 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) kfree(cpufreq_cdev); } EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); + +#endif /* CPU_FREQ_THERMAL */ + +#ifdef CONFIG_CPU_IDLE_THERMAL +/* + * The idle duration injection. As we don't have yet a way to specify + * from the DT configuration, let's default to a tick duration. + */ +#define DEFAULT_IDLE_TIME_US TICK_USEC + +/** + * struct cpuidle_cooling_device - data for the idle cooling device + * @cdev: a pointer to a struct thermal_cooling_device + * @tsk: an array of pointer to the idle injection tasks + * @cpumask: a cpumask containing the CPU managed by the cooling device + * @timer: a hrtimer giving the tempo for the idle injection cycles + * @kref: a kernel refcount on this structure + * @waitq: the waiq for the idle injection tasks + * @count: an atomic to keep track of the last task exiting the idle cycle + * @idle_cycle: an integer defining the duration of the idle injection + * @state: an normalized integer giving the state of the cooling device + */ +struct cpuidle_cooling_device { + struct thermal_cooling_device *cdev; + struct task_struct **tsk; + struct cpumask *cpumask; + struct list_head node; + struct hrtimer timer; + struct kref kref; + wait_queue_head_t *waitq; + atomic_t count; + unsigned int idle_cycle; + unsigned int state; +}; + +static LIST_HEAD(cpuidle_cdev_list); + +/** + * cpuidle_cooling_wakeup - Wake up all idle injection threads + * @idle_cdev: the idle cooling device + * + * Every idle injection task belonging to the idle cooling device and + * running on an online cpu will be wake up by this call. + */ +static void cpuidle_cooling_wakeup(struct cpuidle_cooling_device *idle_cdev) +{ + int cpu; + int weight = cpumask_weight(idle_cdev->cpumask); + + for_each_cpu_and(cpu, idle_cdev->cpumask, cpu_online_mask) + wake_up_process(idle_cdev->tsk[cpu % weight]); +} + +/** + * cpuidle_cooling_wakeup_fn - Running cycle timer callback + * @timer: a hrtimer structure + * + * When the mitigation is acting, the CPU is allowed to run an amount + * of time, then the idle injection happens for the specified delay + * and the idle task injection schedules itself until the timer event + * wakes the idle injection tasks again for a new idle injection + * cycle. The time between the end of the idle injection and the timer + * expiration is the allocated running time for the CPU. + * + * Returns always HRTIMER_NORESTART + */ +static enum hrtimer_restart cpuidle_cooling_wakeup_fn(struct hrtimer *timer) +{ + struct cpuidle_cooling_device *idle_cdev = + container_of(timer, struct cpuidle_cooling_device, timer); + + cpuidle_cooling_wakeup(idle_cdev); + + return HRTIMER_NORESTART; +} + +/** + * cpuidle_cooling_runtime - Running time computation + * @idle_cdev: the idle cooling device + * + * The running duration is computed from the idle injection duration + * which is fixed. If we reach 100% of idle injection ratio, that + * means the running duration is zero. If we have a 50% ratio + * injection, that means we have equal duration for idle and for + * running duration. + * + * The formula is deduced as the following: + * + * running = idle x ((100 / ratio) - 1) + * + * For precision purpose for integer math, we use the following: + * + * running = (idle x 100) / ratio - idle + * + * For example, if we have an injected duration of 50%, then we end up + * with 10ms of idle injection and 10ms of running duration. + * + * Returns a s64 nanosecond based + */ +static s64 cpuidle_cooling_runtime(struct cpuidle_cooling_device *idle_cdev) +{ + s64 next_wakeup; + int state = idle_cdev->state; + + /* + * The function must never be called when there is no + * mitigation because: + * - that does not make sense + * - we end up with a division by zero + */ + BUG_ON(!state); + + next_wakeup = (s64)((idle_cdev->idle_cycle * 100) / state) - + idle_cdev->idle_cycle; + + return next_wakeup * NSEC_PER_USEC; +} + +/** + * cpuidle_cooling_injection_thread - Idle injection mainloop thread function + * @arg: a void pointer containing the idle cooling device address + * + * This main function does basically two operations: + * + * - Goes idle for a specific amount of time + * + * - Sets a timer to wake up all the idle injection threads after a + * running period + * + * That happens only when the mitigation is enabled, otherwise the + * task is scheduled out. + * + * In order to keep the tasks synchronized together, it is the last + * task exiting the idle period which is in charge of setting the + * timer. + * + * This function never returns. + */ +static int cpuidle_cooling_injection_thread(void *arg) +{ + struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO/2 }; + struct cpuidle_cooling_device *idle_cdev = arg; + int index = smp_processor_id() % cpumask_weight(idle_cdev->cpumask); + DEFINE_WAIT(wait); + + set_freezable(); + + sched_setscheduler(current, SCHED_FIFO, ¶m); + + while (1) { + + s64 next_wakeup; + + prepare_to_wait(&idle_cdev->waitq[index], + &wait, TASK_INTERRUPTIBLE); + + schedule(); + + atomic_inc(&idle_cdev->count); + + play_idle(idle_cdev->idle_cycle / USEC_PER_MSEC); + + /* + * The last CPU waking up is in charge of setting the + * timer. If the CPU is hotplugged, the timer will + * move to another CPU (which may not belong to the + * same cluster) but that is not a problem as the + * timer will be set again by another CPU belonging to + * the cluster, so this mechanism is self adaptive and + * does not require any hotplugging dance. + */ + if (!atomic_dec_and_test(&idle_cdev->count)) + continue; + + if (!idle_cdev->state) + continue; + + next_wakeup = cpuidle_cooling_runtime(idle_cdev); + + hrtimer_start(&idle_cdev->timer, ns_to_ktime(next_wakeup), + HRTIMER_MODE_REL_PINNED); + } + + finish_wait(&idle_cdev->waitq[index], &wait); + + return 0; +} + +/** + * cpuidle_cooling_get_max_state - Get the maximum state + * @cdev : the thermal cooling device + * @state : a pointer to the state variable to be filled + * + * The function gives always 100 as the injection ratio is percentile + * based for consistency accros different platforms. + * + * The function can not fail, it returns always zero. + */ +static int cpuidle_cooling_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + /* + * Depending on the configuration or the hardware, the running + * cycle and the idle cycle could be different. We want unify + * that to an 0..100 interval, so the set state interface will + * be the same whatever the platform is. + * + * The state 100% will make the cluster 100% ... idle. A 0% + * injection ratio means no idle injection at all and 50% + * means for 10ms of idle injection, we have 10ms of running + * time. + */ + *state = 100; + + return 0; +} + +/** + * cpuidle_cooling_get_cur_state - Get the current cooling state + * @cdev: the thermal cooling device + * @state: a pointer to the state + * + * The function just copy the state value from the private thermal + * cooling device structure, the mapping is 1 <-> 1. + * + * The function can not fail, it returns always zero. + */ +static int cpuidle_cooling_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct cpuidle_cooling_device *idle_cdev = cdev->devdata; + + *state = idle_cdev->state; + + return 0; +} + +/** + * cpuidle_cooling_set_cur_state - Set the current cooling state + * @cdev: the thermal cooling device + * @state: the target state + * + * The function checks first if we are initiating the mitigation which + * in turn wakes up all the idle injection tasks belonging to the idle + * cooling device. In any case, it updates the internal state for the + * cooling device. + * + * The function can not fail, it returns always zero. + */ +static int cpuidle_cooling_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct cpuidle_cooling_device *idle_cdev = cdev->devdata; + unsigned long current_state = idle_cdev->state; + + idle_cdev->state = state; + + if (current_state == 0 && state > 0) { + pr_debug("Starting cooling cpus '%*pbl'\n", + cpumask_pr_args(idle_cdev->cpumask)); + cpuidle_cooling_wakeup(idle_cdev); + } else if (current_state > 0 && !state) { + pr_debug("Stopping cooling cpus '%*pbl'\n", + cpumask_pr_args(idle_cdev->cpumask)); + } + + return 0; +} + +/** + * cpuidle_cooling_ops - thermal cooling device ops + */ +static struct thermal_cooling_device_ops cpuidle_cooling_ops = { + .get_max_state = cpuidle_cooling_get_max_state, + .get_cur_state = cpuidle_cooling_get_cur_state, + .set_cur_state = cpuidle_cooling_set_cur_state, +}; + +/** + * cpuidle_cooling_release - Kref based release helper + * @kref: a pointer to the kref structure + * + * This function is automatically called by the kref_put function when + * the idle cooling device refcount reaches zero. At this point, we + * have the guarantee the structure is no longer in use and we can + * safely release all the ressources. + */ +static void __init cpuidle_cooling_release(struct kref *kref) +{ + struct cpuidle_cooling_device *idle_cdev = + container_of(kref, struct cpuidle_cooling_device, kref); + + thermal_cooling_device_unregister(idle_cdev->cdev); + kfree(idle_cdev->waitq); + kfree(idle_cdev->tsk); + kfree(idle_cdev); +} + +/** + * cpuidle_cooling_register - Idle cooling device initialization function + * + * This function is in charge of creating a cooling device per cluster + * and register it to thermal framework. For this we rely on the + * topology as there is nothing yet describing better the idle state + * power domains. + * + * For each first CPU of the cluster's cpumask, we allocate the idle + * cooling device, initialize the general fields and then we initialze + * the rest in a per cpu basis. + * + * Returns zero on success, < 0 otherwise. + */ +int cpuidle_cooling_register(void) +{ + struct cpuidle_cooling_device *idle_cdev = NULL; + struct thermal_cooling_device *cdev; + struct task_struct *tsk; + struct device_node *np; + cpumask_t *cpumask; + char dev_name[THERMAL_NAME_LENGTH]; + int weight; + int ret = -ENOMEM, cpu; + int index = 0; + + for_each_possible_cpu(cpu) { + + cpumask = topology_core_cpumask(cpu); + weight = cpumask_weight(cpumask); + + /* + * This condition makes the first cpu belonging to the + * cluster to create a cooling device and allocates + * the structure. Others CPUs belonging to the same + * cluster will just increment the refcount on the + * cooling device structure and initialize it. + */ + if (cpu == cpumask_first(cpumask)) { + + np = of_cpu_device_node_get(cpu); + + idle_cdev = kzalloc(sizeof(*idle_cdev), GFP_KERNEL); + if (!idle_cdev) + goto out_fail; + + idle_cdev->tsk = kzalloc(sizeof(*idle_cdev->tsk) * + weight, GFP_KERNEL); + if (!idle_cdev->tsk) + goto out_fail; + + idle_cdev->waitq = kzalloc(sizeof(*idle_cdev->waitq) * + weight, GFP_KERNEL); + if (!idle_cdev->waitq) + goto out_fail; + + idle_cdev->idle_cycle = DEFAULT_IDLE_TIME_US; + + atomic_set(&idle_cdev->count, 0); + + kref_init(&idle_cdev->kref); + + /* + * Initialize the timer to wakeup all the idle + * injection tasks + */ + hrtimer_init(&idle_cdev->timer, + CLOCK_MONOTONIC, HRTIMER_MODE_REL); + + /* + * The wakeup function callback which is in + * charge of waking up all CPUs belonging to + * the same cluster + */ + idle_cdev->timer.function = cpuidle_cooling_wakeup_fn; + + /* + * The thermal cooling device name + */ + snprintf(dev_name, sizeof(dev_name), "thermal-idle-%d", index++); + cdev = thermal_of_cooling_device_register(np, dev_name, + idle_cdev, + &cpuidle_cooling_ops); + if (IS_ERR(cdev)) { + ret = PTR_ERR(cdev); + goto out_fail; + } + + idle_cdev->cdev = cdev; + + idle_cdev->cpumask = cpumask; + + list_add(&idle_cdev->node, &cpuidle_cdev_list); + + pr_info("Created idle cooling device for cpus '%*pbl'\n", + cpumask_pr_args(cpumask)); + } + + kref_get(&idle_cdev->kref); + + /* + * Each cooling device is per package. Each package + * has a set of cpus where the physical number is + * duplicate in the kernel namespace. We need a way to + * address the waitq[] and tsk[] arrays with index + * which are not Linux cpu numbered. + * + * One solution is to use the + * topology_core_id(cpu). Other solution is to use the + * modulo. + * + * eg. 2 x cluster - 4 cores. + * + * Physical numbering -> Linux numbering -> % nr_cpus + * + * Pkg0 - Cpu0 -> 0 -> 0 + * Pkg0 - Cpu1 -> 1 -> 1 + * Pkg0 - Cpu2 -> 2 -> 2 + * Pkg0 - Cpu3 -> 3 -> 3 + * + * Pkg1 - Cpu0 -> 4 -> 0 + * Pkg1 - Cpu1 -> 5 -> 1 + * Pkg1 - Cpu2 -> 6 -> 2 + * Pkg1 - Cpu3 -> 7 -> 3 + */ + init_waitqueue_head(&idle_cdev->waitq[cpu % weight]); + + tsk = kthread_create_on_cpu(cpuidle_cooling_injection_thread, + idle_cdev, cpu, "kidle_inject/%u"); + if (IS_ERR(tsk)) { + ret = PTR_ERR(tsk); + goto out_fail; + } + + idle_cdev->tsk[cpu % weight] = tsk; + + wake_up_process(tsk); + } + + return 0; + +out_fail: + list_for_each_entry(idle_cdev, &cpuidle_cdev_list, node) { + + for_each_cpu(cpu, idle_cdev->cpumask) { + + if (idle_cdev->tsk[cpu]) + kthread_stop(idle_cdev->tsk[cpu]); + + kref_put(&idle_cdev->kref, cpuidle_cooling_release); + } + } + + pr_err("Failed to create idle cooling device (%d)\n", ret); + + return ret; +} +#endif diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h index d4292eb..2b5950b 100644 --- a/include/linux/cpu_cooling.h +++ b/include/linux/cpu_cooling.h @@ -45,6 +45,7 @@ struct thermal_cooling_device * cpufreq_power_cooling_register(struct cpufreq_policy *policy, u32 capacitance, get_static_t plat_static_func); +extern int cpuidle_cooling_register(void); /** * of_cpufreq_cooling_register - create cpufreq cooling device based on DT. * @np: a valid struct device_node to the cooling device device tree node. @@ -118,6 +119,11 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) { return; } + +static inline int cpuidle_cooling_register(void) +{ + return 0; +} #endif /* CONFIG_CPU_THERMAL */ #endif /* __CPU_COOLING_H__ */ From patchwork Tue Jan 23 15:34:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 125539 Delivered-To: patch@linaro.org Received: by 10.46.66.141 with SMTP id h13csp1827088ljf; Tue, 23 Jan 2018 07:35:47 -0800 (PST) X-Google-Smtp-Source: AH8x225Xfw1qRpKfJ4l+fTnFbyyrO+knCl7veRC+/zTLxpyeGpjC8JX9oU0YXNhU/I/81OEr8/DC X-Received: by 10.107.151.72 with SMTP id z69mr1927759iod.185.1516721747781; Tue, 23 Jan 2018 07:35:47 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516721747; cv=none; d=google.com; s=arc-20160816; b=RIjSx0U4u6gdSRSgG+QMIEdyq4k+rd7Rx6mpOJ2YB4Y0l4AqFWpldNaoObSH7oYn2+ wDcr6OqVkkGrckv0MsZtFKVC/Dp93vLWPE4m2MPz/8AUt0Xp2705YjG9QM1X9pZLhdst nyfhbbu3ZX74Qs4eBwv0/AtypYPPD3yWZuvVSMh8FiuiuMRdglF5g/yF4h3ut5J9rwHS J0FCFdY05Vwn0V0KVlbPK3LF9bZ5YK/9RBJvocT+xDkeAXDPUZKNQy+JI9jBIS8LfmXf L7LZ06m2+z2gBHTh5bx2DabAvmVDhB3AB5xIhF3o4SgQmzVx7cNPTOYKgaHvVhGbZIwZ MjNQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature:arc-authentication-results; bh=kTkJlfqja9pe90J9GmtjZEgGq0M+vVVr/PR/H26gJ7I=; b=fRspcg07l8Ot/MGGcnf6fMY4eYD4Kx/jehrskWCKiO/ZyUV1YOlPXAGFhxD4F65VaX wJX68Qxh4jmluZpoHhxGsSsGal0WGBgEiM2ei4aL+Rkr6nC3j8AMAmmh3tDH+i1Uss7h nkre8NdPur1IlSYCl7Xk7GDLcCpFVMHP0FGirX7Tl8gny0T1UODLpzY5SOoigF6lnST8 P/kzXd+zZrwKdAPI0GhYwdRx4BgRRa+mMExA83FaYb6N1krr3nSwqPvCBsT8oOYVVXr1 UnDjqgjnp9rocUKQBcW+seWbFmYzWEAzP0HVDHquMdJTvz66GNFIbTwH0WGlHDE1fUZF g0ZA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=DKAczYb7; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id c66si16614560iof.274.2018.01.23.07.35.47; Tue, 23 Jan 2018 07:35:47 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=DKAczYb7; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752148AbeAWPfq (ORCPT + 28 others); Tue, 23 Jan 2018 10:35:46 -0500 Received: from mail-wm0-f49.google.com ([74.125.82.49]:37687 "EHLO mail-wm0-f49.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751660AbeAWPfn (ORCPT ); Tue, 23 Jan 2018 10:35:43 -0500 Received: by mail-wm0-f49.google.com with SMTP id v71so2742642wmv.2 for ; Tue, 23 Jan 2018 07:35:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=kTkJlfqja9pe90J9GmtjZEgGq0M+vVVr/PR/H26gJ7I=; b=DKAczYb7lPuaH/X6yp8lRinv/Fjyc2fKvcNdWEjpDbj9spAXZXCoKLDMPpQfADlltb 9gLKU369AgtLI30V2Pe+vE03r6MJie+o0aZCW4amXt4etYlVzyMfI7fOe+NFWBtXuNFW AnA7ViyMhUnLmyjV/G4KA0F0sA9hAeZ4GCBgc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=kTkJlfqja9pe90J9GmtjZEgGq0M+vVVr/PR/H26gJ7I=; b=ou6EGGGKAAU4p9la0nu8YxQv9WcRn/HPnr4HZ7v9xBI2tNaLTOKaHs1j12pCr1TjPK e2NrLDTEKOjXQA5ElZlxAN4Y5GzCafW58SMIEJvpyJ9h4VJQcMQpliRqWicN7x4w6za/ ermHDkSzSUygVFcOTQb5elmDp7pNlCf8tGoLpTyMTy/xXlUcOa0sqJfcuub3gQoKXNS0 c55obRnhVxme4F6wk2fAGpRO3oa3UXArEx3REJbq1BcJ2QlmOYvrq+a7z3W0n6LLKVSA oJDcrjTNxgF+V6wjhfKVGwcJgurl423MUTP6RcN9G1jiwRP07bBEAT6VNyxJNMoGv9DD lbRg== X-Gm-Message-State: AKwxytf1ibv/RJDd0YNbjxUKoi2S/HjS/QIsTnyyA6Fgd0kaHNLX+Axz JhNr4bZbt2VIa57I6iKdmoP+vw== X-Received: by 10.28.135.208 with SMTP id j199mr2232264wmd.151.1516721742061; Tue, 23 Jan 2018 07:35:42 -0800 (PST) Received: from localhost.localdomain ([2a01:e35:879a:6cd0:8138:f09d:5869:1250]) by smtp.gmail.com with ESMTPSA id o98sm915624wrb.19.2018.01.23.07.35.40 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 23 Jan 2018 07:35:41 -0800 (PST) From: Daniel Lezcano To: edubezval@gmail.com Cc: kevin.wangtao@linaro.org, leo.yan@linaro.org, vincent.guittot@linaro.org, amit.kachhap@gmail.com, viresh.kumar@linaro.org, linux-kernel@vger.kernel.org, Jonathan Corbet , linux-doc@vger.kernel.org (open list:DOCUMENTATION) Subject: [PATCH 6/8] thermal/drivers/cpu_cooling: Add idle cooling device documentation Date: Tue, 23 Jan 2018 16:34:29 +0100 Message-Id: <1516721671-16360-7-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> References: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> MIME-Version: 1.0 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Provide some documentation for the idle injection cooling effect in order to let people to understand the rational of the approach for the idle injection CPU cooling device. Signed-off-by: Daniel Lezcano --- Documentation/thermal/cpu-idle-cooling.txt | 165 +++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 Documentation/thermal/cpu-idle-cooling.txt -- 2.7.4 diff --git a/Documentation/thermal/cpu-idle-cooling.txt b/Documentation/thermal/cpu-idle-cooling.txt new file mode 100644 index 0000000..29fc651 --- /dev/null +++ b/Documentation/thermal/cpu-idle-cooling.txt @@ -0,0 +1,165 @@ + +Situation: +---------- + +Under certain circumstances, the SoC reaches a temperature exceeding +the allocated power budget or the maximum temperature limit. The +former must be mitigated to stabilize the SoC temperature around the +temperature control using the defined cooling devices, the latter is a +catastrophic situation where a radical decision must be taken to +reduce the temperature under the critical threshold, that can impact +the performances. + +Another situation is when the silicon reaches a certain temperature +which continues to increase even if the dynamic leakage is reduced to +its minimum by clock gating the component. The runaway phenomena will +continue with the static leakage and only powering down the component, +thus dropping the dynamic and static leakage will allow the component +to cool down. This situation is critical. + +Last but not least, the system can ask for a specific power budget but +because of the OPP density, we can only choose an OPP with a power +budget lower than the requested one and underuse the CPU, thus losing +performances. In other words, one OPP under uses the CPU with a power +lesser than the power budget and the next OPP exceed the power budget, +an intermediate OPP could have been used if it were present. + +Solutions: +---------- + +If we can remove the static and the dynamic leakage for a specific +duration in a controlled period, the SoC temperature will +decrease. Acting at the idle state duration or the idle cycle +injection period, we can mitigate the temperature by modulating the +power budget. + +The Operating Performance Point (OPP) density has a great influence on +the control precision of cpufreq, however different vendors have a +plethora of OPP density, and some have large power gap between OPPs, +that will result in loss of performance during thermal control and +loss of power in other scenes. + +At a specific OPP, we can assume injecting idle cycle on all CPUs, +belonging to the same cluster, with a duration greater than the +cluster idle state target residency, we drop the static and the +dynamic leakage for this period (modulo the energy needed to enter +this state). So the sustainable power with idle cycles has a linear +relation with the OPP’s sustainable power and can be computed with a +coefficient similar to: + + Power(IdleCycle) = Coef x Power(OPP) + +Idle Injection: +--------------- + +The base concept of the idle injection is to force the CPU to go to an +idle state for a specified time each control cycle, it provides +another way to control CPU power and heat in addition to +cpufreq. Ideally, if all CPUs of a cluster inject idle synchronously, +this cluster can get into the deepest idle state and achieve minimum +power consumption, but that will also increase system response latency +if we inject less than cpuidle latency. + + ^ + | + | + |------- ------- ------- + |_______|_____|_______|_____|_______|___________ + + <-----> + idle <----> + running + +With the fixed idle injection duration, we can give a value which is +an acceptable performance drop off or latency when we reach a specific +temperature and we begin to mitigate by varying the Idle injection +period. + +The mitigation begins with a maximum period value which decrease when +more cooling effect is requested. When the period duration is equal to +the idle duration, then we are in a situation the platform can’t +dissipate the heat enough and the mitigation fails. In this case the +situation is considered critical and there is nothing to do. The idle +injection duration must be changed by configuration and until we reach +the cooling effect, otherwise an additionnal cooling device must be +used or ultimately decrease the SoC performance by dropping the +highest OPP point of the SoC. + +The idle injection duration value must comply with the constraints: + +- It is lesser or equal to the latency we tolerate when the mitigation + begins. It is platform dependent and will depend on the user + experience, reactivity vs performance trade off we want. This value + should be specified. + +- It is greater than the idle state’s target residency we want to go + for thermal mitigation, otherwise we end up consuming more energy. + +Minimum period +-------------- + +The idle injection duration being fixed, it is obvious the minimum +period can’t be lesser than that, otherwise we will be scheduling the +idle injection task right before the idle injection duration is +complete, so waking up the CPU to put it asleep again. + +Maximum period +-------------- + +The maximum period is the initial period when the mitigation +begins. Theoretically when we reach the thermal trip point, we have to +sustain a specified power for specific temperature but at this time we +consume: + + Power = Capacitance x Voltage^2 x Frequency x Utilisation + +... which is more than the sustainable power (or there is something +wrong on the system setup). The ‘Capacitance’ and ‘Utilisation’ are a +fixed value, ‘Voltage’ and the ‘Frequency’ are fixed artificially +because we don’t want to change the OPP. We can group the +‘Capacitance’ and the ‘Utilisation’ into a single term which is the +‘Dynamic Power Coefficient (Cdyn)’ Simplifying the above, we have: + + Pdyn = Cdyn x Voltage^2 x Frequency + +The IPA will ask us somehow to reduce our power in order to target the +sustainable power defined in the device tree. So with the idle +injection mechanism, we want an average power (Ptarget) resulting on +an amount of time running at full power on a specific OPP and idle +another amount of time. That could be put in a equation: + + P(opp)target = ((trunning x (P(opp)running) + (tidle P(opp)idle)) / + (trunning + tidle) + ... + + tidle = trunning x ((P(opp)running / P(opp)target) - 1) + +At this point if we know the running period for the CPU, that gives us +the idle injection, we need. Alternatively if we have the idle +injection duration, we can compute the running duration with: + + trunning = tidle / ((P(opp)running / P(opp)target) - 1) + +Practically, if the running power is lesses than the targeted power, +we end up with a negative time value, so obviously the equation usage +is bound to a power reduction, hence a higher OPP is needed to have +the running power greater than the targeted power. + +However, in this demonstration we ignore three aspects: + + * The static leakage is not defined here, we can introduce it in the + equation but assuming it will be zero most of the time as it is + difficult to get the values from the SoC vendors + + * The idle state wake up latency (or entry + exit latency) is not + taken into account, it must be added in the equation in order to + rigorously compute the idle injection + + * The injected idle duration must be greater than the idle state + target residency, otherwise we end up consuming more energy and + potentially invert the mitigation effect + +So the final equation is: + + trunning = (tidle - twakeup ) x + (((P(opp)dyn + P(opp)static ) - P(opp)target) / P(opp)target ) From patchwork Tue Jan 23 15:34:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 125541 Delivered-To: patch@linaro.org Received: by 10.46.66.141 with SMTP id h13csp1827388ljf; Tue, 23 Jan 2018 07:36:17 -0800 (PST) X-Google-Smtp-Source: AH8x226RRKIIGoOq6/UoMbxYltrHl2AadnFAJ4Rs6DolFpBE7pnnkuN6d2rx2UQhhpQwVSd29lUK X-Received: by 10.107.199.67 with SMTP id x64mr3999474iof.169.1516721777397; Tue, 23 Jan 2018 07:36:17 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516721777; cv=none; d=google.com; s=arc-20160816; b=xBv3oSWmYhu0DpHTYrPT9RR6EPfyEN3XlcZcbR/ZvjJgOBL/uQ5CpycFlsncK/RrVW jylKrHvxWVjcX5P5hCP3XXOZJq/qY0QN31sZecpgFmVfGXnV5XRKDgTB/yrwkBeGFlw4 LCXNCBeN8/rmt5JOTXjkAMSCfy/HPTuFAjgaWjD+iW8B6KUIA/m7PhGdIGFeirkx7u7C Zh6f0YfFf08hnyNVaNHLMP27AJqltoEzMJSMYVVcfLTfoz2hBNjYXVPvlJk1m+3RDbb+ Fznv9khTaKVLL5G50IHF5nvppfJ1RYhhQharnm3LQ0v+vX67aDK3XwfFKSjTECcenut/ 1O6w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=ZqxBlmNsHznBskX1KBTP0UGbIstMc1gUTKwTLHUhTJE=; b=XJEhCncy4E2EioCcR4n+WJOsQasWnzGGD741OEpK8n8xfE7T2VoKZZI17meeGbo0Pt lj34m0zwyWpD9CUQPbMs57vOOiKPpE+1fwr278qakhvkZUaNCYFRqRBOaPF9SIbzm/W5 js1AtKRUnyqJGGSBe5fzeMov5FDLM7IvqQJzmweeaFWu/B0Ltxbx2XWfVCCGyz2/oPVF JSCJCcCkwagFkcqlb+tB+bfc2Rz2pckGWUjEOeWXdw6rGKob0j/kaoIhFrC+IGb4nq8F 6V5Mi3pvxP+t724JFOMZa2RSpY3M/dTafdK4bCcgnx8u2/nZcsX3RG4ljA/h4WeaJkNN A6bg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=FT8MOBkw; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id a189si15343949iog.285.2018.01.23.07.36.16; Tue, 23 Jan 2018 07:36:17 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=FT8MOBkw; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752149AbeAWPgP (ORCPT + 28 others); Tue, 23 Jan 2018 10:36:15 -0500 Received: from mail-wm0-f67.google.com ([74.125.82.67]:33646 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751720AbeAWPfo (ORCPT ); Tue, 23 Jan 2018 10:35:44 -0500 Received: by mail-wm0-f67.google.com with SMTP id x4so22525239wmc.0 for ; Tue, 23 Jan 2018 07:35:44 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ZqxBlmNsHznBskX1KBTP0UGbIstMc1gUTKwTLHUhTJE=; b=FT8MOBkwkq1sy3NqB2w5w9gxP/jL9erx6ulCWGFlTwcPjS5XHeHNT9+/KEdz3DNzm4 YqqQKIkmglypoReHrx5gjN3WnYP5ElKC5ehUtBYRlzxvq+MKMcV24uFXgs+jYcm9I7rG dc8D//J1ydwHFAmVGDO8HpxQ8GKrFvZmvfUek= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ZqxBlmNsHznBskX1KBTP0UGbIstMc1gUTKwTLHUhTJE=; b=uNoLRSXBm3P2dL0g9NOEt9j9cK49IohYZG8iJA1iHN2Q0syxbgJZQ7l4f6OIcU1zi8 GmWw44cFVnok7dcsf+wIbTimFHniQZpxPHyOxQqfjBlLtQQvwa060RnbknP41jOYXR9c TBkHiQ9i6+8ioJNaijcZFFgIV3wXwcQGhoSiGg7ft3SzZfNq6QuMtFB5SbiswkBSAh7s xzq9w3agpuZX3awOtEBqUKlMi/ppSBFTUUM7PxMCBV9mUPC4QZXiJyKmPqMC7q9SsmQ7 b+9m8UTrQ+eafJmlIO/nisIXRmh5H71HNVZzGaoqeL5k3hi3d/JpH1CIrh+XKazbVmk+ lB5g== X-Gm-Message-State: AKwxyte+IuGlqjSeugUQ9Qvyrv6kEnO1V25xPt+obkuvPvBXYKvWMpl7 OZOe6OVttLMcesWrqT3J/+JhgA== X-Received: by 10.28.17.141 with SMTP id 135mr2087744wmr.80.1516721743689; Tue, 23 Jan 2018 07:35:43 -0800 (PST) Received: from localhost.localdomain ([2a01:e35:879a:6cd0:8138:f09d:5869:1250]) by smtp.gmail.com with ESMTPSA id o98sm915624wrb.19.2018.01.23.07.35.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 23 Jan 2018 07:35:43 -0800 (PST) From: Daniel Lezcano To: edubezval@gmail.com Cc: kevin.wangtao@linaro.org, leo.yan@linaro.org, vincent.guittot@linaro.org, amit.kachhap@gmail.com, viresh.kumar@linaro.org, linux-kernel@vger.kernel.org, "Rafael J. Wysocki" , linux-pm@vger.kernel.org (open list:CPUIDLE DRIVERS) Subject: [PATCH 7/8] cpuidle/drivers/cpuidle-arm: Register the cooling device Date: Tue, 23 Jan 2018 16:34:30 +0100 Message-Id: <1516721671-16360-8-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> References: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Register the ARM generic cpuidle driver as a cooling device. Signed-off-by: Daniel Lezcano --- drivers/cpuidle/cpuidle-arm.c | 5 +++++ 1 file changed, 5 insertions(+) -- 2.7.4 diff --git a/drivers/cpuidle/cpuidle-arm.c b/drivers/cpuidle/cpuidle-arm.c index ddee1b6..c100915 100644 --- a/drivers/cpuidle/cpuidle-arm.c +++ b/drivers/cpuidle/cpuidle-arm.c @@ -11,6 +11,7 @@ #define pr_fmt(fmt) "CPUidle arm: " fmt +#include #include #include #include @@ -172,6 +173,10 @@ static int __init arm_idle_init(void) goto out_fail; } + ret = cpuidle_cooling_register(); + if (ret) + pr_warn("Failed to register the cpuidle cooling device\n"); + return 0; out_fail: From patchwork Tue Jan 23 15:34:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Daniel Lezcano X-Patchwork-Id: 125540 Delivered-To: patch@linaro.org Received: by 10.46.66.141 with SMTP id h13csp1827130ljf; Tue, 23 Jan 2018 07:35:54 -0800 (PST) X-Google-Smtp-Source: AH8x227Z3sudDKfsNqryYZds4ybdtMfDTiBCvPkDodZS5V8ZjU+x7sqWRK//kVhuy6pWDLYXD8bV X-Received: by 10.107.13.143 with SMTP id 137mr3957766ion.265.1516721754652; Tue, 23 Jan 2018 07:35:54 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1516721754; cv=none; d=google.com; s=arc-20160816; b=ewTD4we2+giOWDDQB/YeuxvU3MKroRll8WK53C6WJTDcmwd8upjZihv90m7Kra6UFc TD+iagYonQsxTOPIGDnGKOwpyExSgF4Pyhf28/CEssQsCdy/NHDzuXUF1WVoL3vhHmPN Ligjfmq2DSaypoBCoK7vYjfsEBFwcMfBG8Tmi50J3wADrXhgsCm/yhWlPH0uflNZYm6l oky9+MMdywvHqp61cu/oJD0NOLQEKvP7aawbx2/Xz9OlT+5qhE0nZ2Dw6xXJ89KemLTg NRNEwSBEEAvVYR905n27lpHWsb+CIvFZ6n19e9wkm8LD2GIJD022y/EZMiSU0HALPx6D 7yVg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=CwcAtwk9IqTPqM0YQlY0JMWnyWaRQvOsOLOBgDLoW04=; b=voV6H0EGVEx/xxRUfkzMkJbYxI7BPwwQ/f76VKtBTJraln9pxU6Te+pz4jIyxrcgzP kSWUtGtZ9i5mzqwvWkupVVsTWbWDY/3+Unfgz5r/FpwgjVkduR9JOdMSl4U/RbbHPtDa u/jL4ut6Kh5KR122VBBmlPPu7nGTwbSPHOcc+Hd3W+ecRiKKgvAJjKgIwZfIZxzavkc/ GWPWorikY0pbOW3HDdtA3YlLoetGLukH3tKsA9w3B50OrDLZX1lxgJtBESqS1nfFO5iU sA/tOHcnCHkXJlnY+kTa6eema70ewRmFQYAyOc9t7i0ACUe9l6F+YHV8+9WjSud2ff0L n7rQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=bH9wxdXW; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id g143si15492682ioe.289.2018.01.23.07.35.54; Tue, 23 Jan 2018 07:35:54 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=bH9wxdXW; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752174AbeAWPfx (ORCPT + 28 others); Tue, 23 Jan 2018 10:35:53 -0500 Received: from mail-wm0-f53.google.com ([74.125.82.53]:34844 "EHLO mail-wm0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751681AbeAWPfs (ORCPT ); Tue, 23 Jan 2018 10:35:48 -0500 Received: by mail-wm0-f53.google.com with SMTP id r78so2759485wme.0 for ; Tue, 23 Jan 2018 07:35:47 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=CwcAtwk9IqTPqM0YQlY0JMWnyWaRQvOsOLOBgDLoW04=; b=bH9wxdXWBQUZclQJnvJuvrGTVlNu0WJCRAtDVIszlX/Ajq5T8eysNxg9hEECE7gFte eNsXlrcaVWDaB9UFSSb3CFv8NB8WcA5X8543wKZrMr+Nlgq744UJtwtRn2SiSrXAoq0G hderc8x5FrD0hVtp/E+7GHq8xsU2VIPKLePEI= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=CwcAtwk9IqTPqM0YQlY0JMWnyWaRQvOsOLOBgDLoW04=; b=KAl1TOCe0dTZTaJtfUeio3U9XvF9b3/obTVMH2fVoxoLftULOxmcrSMfclwzPn++56 pyIxvALifmL38v6iu0JYcWbddRb0HbuJrfuJmzQMTSgCykX7ri2RfamjEWT0E6vQTgys gm0BvodM4Khr61llQ7TSxxwocnNElGnGK8g9FYL3z69HdFalQa+dPEEvoHH6qkaQNYyF o3XsJgAzp3lhL4HPRCC/BBZ40pmr434vYvrgxL5h5+MluUtzJJRSTQSn6mJXZc1IStey ztEE4oYd3m8Odlsukp5rDO9tYKv2dgIMv3iuul1kZMgkY9813GRRV/4xMnQkGBiBGEur HEhA== X-Gm-Message-State: AKwxytete3FqO38F3Eyh2bbQyhWiJTbeDV5cp5CjuLKjysceJypPRqzc wDT9HFpveumEpYgaAjKa+j5BQA== X-Received: by 10.28.206.75 with SMTP id e72mr2477185wmg.100.1516721746122; Tue, 23 Jan 2018 07:35:46 -0800 (PST) Received: from localhost.localdomain ([2a01:e35:879a:6cd0:8138:f09d:5869:1250]) by smtp.gmail.com with ESMTPSA id o98sm915624wrb.19.2018.01.23.07.35.44 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 23 Jan 2018 07:35:45 -0800 (PST) From: Daniel Lezcano To: edubezval@gmail.com Cc: kevin.wangtao@linaro.org, leo.yan@linaro.org, vincent.guittot@linaro.org, amit.kachhap@gmail.com, viresh.kumar@linaro.org, linux-kernel@vger.kernel.org, Zhang Rui , Javi Merino , linux-pm@vger.kernel.org (open list:THERMAL) Subject: [PATCH 8/8] thermal/drivers/cpu_cooling: Add the combo cpu cooling device Date: Tue, 23 Jan 2018 16:34:31 +0100 Message-Id: <1516721671-16360-9-git-send-email-daniel.lezcano@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> References: <1516721671-16360-1-git-send-email-daniel.lezcano@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The cpu cooling device has two strategies to cool down a SoC. The first one decreases the OPP, the second one forces the cpus to enter a cluster power down state during an amount of time. The first cooling device has the benefit to simply decrease the OPP until the temperature goes below the threshold and then increases the OPP again. The change of the OPP back and forth allows to keep the cpu temperature around the specified threshold. Unfortunately, in some cases, the gap between the OPPs is high and decreasing the OPP makes the cpu performance unoptimal. The second cooling device keeps injecting more and more idle cycles until the temperature stabilizes around the specified threshold. That is simple and efficient in terms of cooling effect but with the drawback of increasing the latency. This new cooling device combines the cooling effect of both the cpuidle and the cpufreq cooling devices by injecting idle cycle at the upper OPP boundary of the power interval. When the power of the OPP minus the idle injection time is equal to the OPP beneath, the cooling device decreases the OPP and resets the idle injection cycles. By this way, we can artifically create intermediate OPP by using the power information found in the DT where we sum the benefit of both cooling effects without the drawbacks. Signed-off-by: Daniel Lezcano --- drivers/thermal/Kconfig | 7 + drivers/thermal/cpu_cooling.c | 475 +++++++++++++++++++++++++++++++++++++----- include/linux/cpu_cooling.h | 21 +- 3 files changed, 438 insertions(+), 65 deletions(-) -- 2.7.4 diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 4bd4be7..200e1f49 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -176,6 +176,13 @@ config CPU_IDLE_THERMAL will enter idle synchronously to reach the deepest idle state. +config CPU_THERMAL_COMBO + bool "CPU idle/freq combo cooling strategy" + depends on CPU_IDLE && CPU_FREQ + help + The cpu combo cooling device combines the cooling effect of the + cpufreq and the cpuidle cooling devices. + endchoice config CLOCK_THERMAL diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 916a627..a2459d6 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -8,6 +8,8 @@ * * Authors: Amit Daniel * Viresh Kumar + * Daniel Lezcano + * Kevin WangTao * */ #undef DEBUG @@ -36,7 +38,7 @@ #include -#ifdef CONFIG_CPU_FREQ_THERMAL +#if defined(CONFIG_CPU_FREQ_THERMAL) || defined (CONFIG_CPU_THERMAL_COMBO) /* * Cooling state <-> CPUFreq frequency * @@ -441,10 +443,9 @@ static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev, * * Return: 0 on success, an error code otherwise. */ -static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, - unsigned long state) +static int __cpufreq_set_cur_state(struct cpufreq_cooling_device *cpufreq_cdev, + unsigned long state) { - struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata; unsigned int clip_freq; /* Request state should be less than max_level */ @@ -464,6 +465,14 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, return 0; } +static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata; + + return __cpufreq_set_cur_state(cpufreq_cdev, state); +} + /** * cpufreq_get_requested_power() - get the current power * @cdev: &thermal_cooling_device pointer @@ -666,6 +675,25 @@ static unsigned int find_next_max(struct cpufreq_frequency_table *table, return max; } +#ifdef CONFIG_CPU_FREQ_THERMAL +static struct thermal_cooling_device * +__cpufreq_cooling_thermal_register(struct device_node *np, char *dev_name, + struct cpufreq_cooling_device *cpufreq_cdev, + struct thermal_cooling_device_ops *ops) +{ + return thermal_of_cooling_device_register(np, dev_name, cpufreq_cdev, + ops); +} +#else +static inline struct thermal_cooling_device * +__cpufreq_cooling_thermal_register(struct device_node *np, char *dev_name, + struct cpufreq_cooling_device *cpufreq_cdev, + struct thermal_cooling_device_ops *ops) +{ + return NULL; +} +#endif + /** * __cpufreq_cooling_register - helper function to create cpufreq cooling device * @np: a valid struct device_node to the cooling device device tree node @@ -769,7 +797,7 @@ __cpufreq_cooling_register(struct device_node *np, cooling_ops = &cpufreq_cooling_ops; } - cdev = thermal_of_cooling_device_register(np, dev_name, cpufreq_cdev, + cdev = __cpufreq_cooling_thermal_register(np, dev_name, cpufreq_cdev, cooling_ops); if (IS_ERR(cdev)) goto remove_ida; @@ -944,7 +972,7 @@ EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); #endif /* CPU_FREQ_THERMAL */ -#ifdef CONFIG_CPU_IDLE_THERMAL +#if defined(CONFIG_CPU_IDLE_THERMAL) || defined(CONFIG_CPU_THERMAL_COMBO) /* * The idle duration injection. As we don't have yet a way to specify * from the DT configuration, let's default to a tick duration. @@ -1130,6 +1158,60 @@ static int cpuidle_cooling_injection_thread(void *arg) } /** + * cpuidle_cooling_set_cur_state - Set the current cooling state + * @cdev: the thermal cooling device + * @state: the target state + * + * The function checks first if we are initiating the mitigation which + * in turn wakes up all the idle injection tasks belonging to the idle + * cooling device. In any case, it updates the internal state for the + * cooling device. + * + * The function can not fail, it returns always zero. + */ +static int +__cpuidle_cooling_set_cur_state(struct cpuidle_cooling_device *idle_cdev, + unsigned long state) +{ + unsigned long current_state = idle_cdev->state; + + idle_cdev->state = state; + + if (current_state == 0 && state > 0) { + pr_debug("Starting cooling cpus '%*pbl'\n", + cpumask_pr_args(idle_cdev->cpumask)); + cpuidle_cooling_wakeup(idle_cdev); + } else if (current_state > 0 && !state) { + pr_debug("Stopping cooling cpus '%*pbl'\n", + cpumask_pr_args(idle_cdev->cpumask)); + } + + return 0; +} + +/** + * cpuidle_cooling_release - Kref based release helper + * @kref: a pointer to the kref structure + * + * This function is automatically called by the kref_put function when + * the idle cooling device refcount reaches zero. At this point, we + * have the guarantee the structure is no longer in use and we can + * safely release all the ressources. + */ +static void __init cpuidle_cooling_release(struct kref *kref) +{ + struct cpuidle_cooling_device *idle_cdev = + container_of(kref, struct cpuidle_cooling_device, kref); + + thermal_cooling_device_unregister(idle_cdev->cdev); + kfree(idle_cdev->waitq); + kfree(idle_cdev->tsk); + kfree(idle_cdev); +} + +#ifdef CONFIG_CPU_IDLE_THERMAL + +/** * cpuidle_cooling_get_max_state - Get the maximum state * @cdev : the thermal cooling device * @state : a pointer to the state variable to be filled @@ -1178,36 +1260,12 @@ static int cpuidle_cooling_get_cur_state(struct thermal_cooling_device *cdev, return 0; } -/** - * cpuidle_cooling_set_cur_state - Set the current cooling state - * @cdev: the thermal cooling device - * @state: the target state - * - * The function checks first if we are initiating the mitigation which - * in turn wakes up all the idle injection tasks belonging to the idle - * cooling device. In any case, it updates the internal state for the - * cooling device. - * - * The function can not fail, it returns always zero. - */ static int cpuidle_cooling_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) { struct cpuidle_cooling_device *idle_cdev = cdev->devdata; - unsigned long current_state = idle_cdev->state; - - idle_cdev->state = state; - - if (current_state == 0 && state > 0) { - pr_debug("Starting cooling cpus '%*pbl'\n", - cpumask_pr_args(idle_cdev->cpumask)); - cpuidle_cooling_wakeup(idle_cdev); - } else if (current_state > 0 && !state) { - pr_debug("Stopping cooling cpus '%*pbl'\n", - cpumask_pr_args(idle_cdev->cpumask)); - } - return 0; + return __cpuidle_cooling_set_cur_state(idle_cdev, state); } /** @@ -1219,25 +1277,30 @@ static struct thermal_cooling_device_ops cpuidle_cooling_ops = { .set_cur_state = cpuidle_cooling_set_cur_state, }; -/** - * cpuidle_cooling_release - Kref based release helper - * @kref: a pointer to the kref structure - * - * This function is automatically called by the kref_put function when - * the idle cooling device refcount reaches zero. At this point, we - * have the guarantee the structure is no longer in use and we can - * safely release all the ressources. - */ -static void __init cpuidle_cooling_release(struct kref *kref) +static int __cpuidle_cooling_thermal_register(struct device_node *np, + struct cpuidle_cooling_device *idle_cdev, + char *dev_name) { - struct cpuidle_cooling_device *idle_cdev = - container_of(kref, struct cpuidle_cooling_device, kref); + struct thermal_cooling_device *cdev; - thermal_cooling_device_unregister(idle_cdev->cdev); - kfree(idle_cdev->waitq); - kfree(idle_cdev->tsk); - kfree(idle_cdev); + cdev = thermal_of_cooling_device_register(np, dev_name, + idle_cdev, + &cpuidle_cooling_ops); + if (IS_ERR(cdev)) + return PTR_ERR(cdev); + + idle_cdev->cdev = cdev; + + return 0; } +#else +static inline int __cpuidle_cooling_thermal_register(struct device_node *np, + struct cpuidle_cooling_device *idle_cdev, + char *dev_name) +{ + return 0; +} +#endif /** * cpuidle_cooling_register - Idle cooling device initialization function @@ -1256,7 +1319,6 @@ static void __init cpuidle_cooling_release(struct kref *kref) int cpuidle_cooling_register(void) { struct cpuidle_cooling_device *idle_cdev = NULL; - struct thermal_cooling_device *cdev; struct task_struct *tsk; struct device_node *np; cpumask_t *cpumask; @@ -1319,15 +1381,10 @@ int cpuidle_cooling_register(void) * The thermal cooling device name */ snprintf(dev_name, sizeof(dev_name), "thermal-idle-%d", index++); - cdev = thermal_of_cooling_device_register(np, dev_name, - idle_cdev, - &cpuidle_cooling_ops); - if (IS_ERR(cdev)) { - ret = PTR_ERR(cdev); - goto out_fail; - } - idle_cdev->cdev = cdev; + ret = __cpuidle_cooling_thermal_register(np, idle_cdev, dev_name); + if (ret) + goto out_fail; idle_cdev->cpumask = cpumask; @@ -1397,3 +1454,309 @@ int cpuidle_cooling_register(void) return ret; } #endif + +#ifdef CONFIG_CPU_THERMAL_COMBO +/** + * struct cpu_cooling_device - the cpu cooling device + * @cpuidle_cdev: a pointer to the instanciated cpuidle cooling device + * @cpufreq_cdev: a pointer to the instanciated cpufreq cooling device + * @max_power: the maximum power managed by the cooling device + * @state: the current cooling device state + * + * The SoC could have different designs. If the SoC is a single + * cluster, we have a single clock line for cpufreq and single cluster + * powerdown state. If the SoC is a dual cluster we can have a single + * clock line for cpufreq and a cluster power down, hence two cpuidle + * cooling device. Alternatively, we can have two clock lines. + * + * 1 cluster - 1 clock line (eg. db410c): There is one cpuidle cooling + * device and one cpufreq cooling device. Consequently, there is one + * cpu cooling device where the cpuidle_cdev and the cpufreq_cdev + * pointers point to the corresponding cooling device instances. + * + * 2 clusters - 1 clock line (eg. hi6220) : There are two cpuidle + * cooling devices and one cpufreq cooling device. It results in two + * cpu cooling devices where the cpuidle_cdev points to the cpuidle + * instance and the cpufreq_cdev contains a shared pointer to the + * cpufreq cooling device. This configuration makes the power + * computation to be ponderated by the number of cpus managed by the + * cpuidle cooling device. + * + * 2 clusters - 2 clock lines (eg. hi3660): There are two cpuidle + * cooling devices, two cpufreq cooling devices and two cpu cooling + * devices. + */ +struct cpu_cooling_device { + struct cpuidle_cooling_device *cpuidle_cdev; + struct cpufreq_cooling_device *cpufreq_cdev; + u32 max_power; + int state; +}; + +/* + * The combo CPU cooling device combines the OPP states and the idle + * injection cycles in order to provide an intermediate state where we + * meet the power budget but without decreasing the OPP. That allows + * to keep a higher OPP while reducing the dissipated power. For + * example, using the cpufreq cooling device only, we may have to + * downgrade the OPP because the current one dissipates too much power + * but by downgrading the OPP, we still have room for more power. So + * the perfect match would have be in between these two OPPs. + * + * For example, let's imagine we have 4 cores ruled by a cpufreq + * driver with 2 OPPs consuming respectively 250mW and 500mW per + * core. With all CPUs loaded at 100%, at the highest OPP, we have + * 2000mW of dissipated power for the cluster. Now the thermal + * framework allocates 1500mW of power budget. We can decrease to the + * other OPP where we end up consuming 1000mW but we still have room + * for 500mw. Alternatively, we can stay at the highest OPP but force + * to be idle 25% of the time (2000 - 1500) / 1500. + * + * By inserting idle cycles at a specific OPP, we can reduce the power + * without decreasing the OPP, which results on a better power / + * performance trade-off. + * + * The combo CPU cooling device works in a percentile way, the states + * represent the percentage of power we want to save. The combo device + * is in charge of setting the state for the idle injection cooling + * device and the cpufreq cooling device, as well as sorting out when + * to go to a specific OPP or/and insert idle cycles. + */ + +/** + * cpu_cooling_get_max_state - Return the maximum number of states + * @cdev : the thermal cooling device + * @state : a pointer to the state variable to be filled + * + * The function gives always 100 as a percentage of the maximum power + * on the thermal zone. + * + * The function can not fail, it returns always zero. + */ +static int cpu_cooling_get_max_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + *state = 100; + return 0; +} + +/** + * cpu_cooling_power_opp - Find the upper OPP for a specific power + * @cpufreq_cdev: the cpufreq cooling device + * @num_cpus: the number of cpus managed by the idle cooling device + * @power: the requested power + * + * The function returns the OPP which is the upper limit of the power + * interval between two OPPs. It is imposible the requested power is + * greater than the maximum power of the cluster. + * + * Returns an index in the freq_table on success, -EINVAL if the + * requested power is invalid (zero or greater than the maximum + * cluster power). + */ +static int cpu_cooling_power_opp(struct cpufreq_cooling_device *cpufreq_cdev, + int num_cpus, u32 power) +{ + struct freq_table *freq_table = cpufreq_cdev->freq_table; + int i; + + if (!power || power > freq_table[0].power * num_cpus) + return -EINVAL; + + for (i = 0; i < cpufreq_cdev->max_level - 1; i++) { + + if (power <= (freq_table[i].power * num_cpus) && + power > (freq_table[i + 1].power * num_cpus)) + break; + } + + return i; +} + +/** + * cpu_cooling_set_cur_state - Sets a percentage of the max power + * @cdev: the thermal cooling device + * @state: the target state representing a ratio + * + * The function computes the power ratio of the OPP and the + * corresponding idle ratio to reach the requested state. The state is + * a percentage of the maximum power. + * + * The function returns zero on success, -EINVAL if the ratio + * computation fails any reason, < 0 for the set_cur_state subcalls + * failure on the cpuidle / cpufreq cooling devices. + */ +static int cpu_cooling_set_cur_state(struct thermal_cooling_device *cdev, + unsigned long state) +{ + struct cpu_cooling_device *cpu_cdev = cdev->devdata; + struct cpuidle_cooling_device *cpuidle_cdev = cpu_cdev->cpuidle_cdev; + struct cpufreq_cooling_device *cpufreq_cdev = cpu_cdev->cpufreq_cdev; + int num_cpus = cpumask_weight(cpuidle_cdev->cpumask); + int opp_index, idle_state, ret; + u32 power, opp_power; + + /* + * The state gives the percentage of the maximum power on the + * thermal zone the cooling device is handling. + * + * In order to find out which OPP must be selected and the + * percentage of idle time to be injected, we must compute + * first how much power represents the requested percentage. + * + * For this we apply a simple ratio: + * + * requested_power = (max_power * pct) / 100 + */ + power = (cpu_cdev->max_power * (100 - state)) / 100; + + /* + * The second step is to sort out which OPP it does apply and + * how much power it represents. We must convert in a CPU + * basis to browse the freq table. + * + * Pitfall: Don't compare in the function with power / + * num_cpus but with opp.power * num_cpus. Otherwise, because + * of the rounding effect, we end up with a power lesser than + * the opp power and then with a negative value in the idle + * ratio computation a few lines below. + */ + opp_index = cpu_cooling_power_opp(cpufreq_cdev, num_cpus, power); + if (opp_index < 0) + return opp_index; + + /* + * The third step is to compute the percentage of idle time + * regarding the dissipated power for the selected OPP above. + */ + opp_power = cpufreq_cdev->freq_table[opp_index].power * num_cpus; + + idle_state = ((opp_power - power) * 100) / power; + + /* + * Catch unexpected situation where we are out of bound of the + * idle state percentage values. + */ + if (WARN_ON_ONCE(idle_state < 0 || idle_state > 100)) + return -EINVAL; + + /* + * Set the cpufreq OPP state + */ + ret = __cpufreq_set_cur_state(cpufreq_cdev, opp_index); + if (ret) + return ret; + + /* + * And inject idle cycles to reduce the power + */ + ret = __cpuidle_cooling_set_cur_state(cpuidle_cdev, idle_state); + if (ret) + return ret; + + cpu_cdev->state = state; + + return 0; +} + +/** + * cpu_cooling_get_cur_state - Gets the percentage of the max power + * @cdev : the thermal cooling device + * @state : a pointer to the state variable to be filled + * + * Fill the state pointer variable with the current state of the cpu + * cooling device, the value is between 0 and 100 (included). + * + * The function never fails and returns zero. + */ +static int cpu_cooling_get_cur_state(struct thermal_cooling_device *cdev, + unsigned long *state) +{ + struct cpu_cooling_device *cpu_cdev = cdev->devdata; + + *state = cpu_cdev->state; + + return 0; +} + +/** + * cpu_cooling_ops - thermal cooling device ops + */ +static struct thermal_cooling_device_ops cpu_cooling_ops = { + .get_max_state = cpu_cooling_get_max_state, + .get_cur_state = cpu_cooling_get_cur_state, + .set_cur_state = cpu_cooling_set_cur_state, +}; + +static int __init cpu_cooling_init(void) +{ + struct thermal_cooling_device *cdev; + struct cpu_cooling_device *cpu_cdev; + struct cpuidle_cooling_device *cpuidle_cdev; + struct cpufreq_cooling_device *cpufreq_cdev; + struct device_node *np; + cpumask_t *cpumask; + char dev_name[THERMAL_NAME_LENGTH]; + int cpu, index = 0; + + for_each_possible_cpu(cpu) { + + cpumask = topology_core_cpumask(cpu); + + if (cpu != cpumask_first(cpumask)) + continue; + + np = of_cpu_device_node_get(cpu); + + cpu_cdev = kzalloc(sizeof(*cpu_cdev), GFP_KERNEL); + if (!cpu_cdev) + return -ENOMEM; + + list_for_each_entry(cpuidle_cdev, + &cpuidle_cdev_list, node) { + + cpumask = cpuidle_cdev->cpumask; + if (!cpumask_test_cpu(cpu, cpumask)) + continue; + + cpu_cdev->cpuidle_cdev = cpuidle_cdev; + break; + } + + list_for_each_entry(cpufreq_cdev, + &cpufreq_cdev_list, node) { + + cpumask = cpufreq_cdev->policy->related_cpus; + if (!cpumask_test_cpu(cpu, cpumask)) + continue; + + cpu_cdev->cpufreq_cdev = cpufreq_cdev; + break; + } + + if (!cpu_cdev->cpuidle_cdev || !cpu_cdev->cpufreq_cdev) { + pr_err("Something is going wrong with the CPU cooling device\n"); + return -EINVAL; + } + + if (!cpufreq_cdev->freq_table[0].power) { + pr_err("No power number for the platform\n"); + return -EINVAL; + } + + cpu_cdev->max_power = cpufreq_cdev->freq_table[0].power; + cpu_cdev->max_power *= cpumask_weight(cpuidle_cdev->cpumask); + + snprintf(dev_name, sizeof(dev_name), + "thermal-cpu-%d", index++); + cdev = thermal_of_cooling_device_register(np, dev_name, + cpu_cdev, + &cpu_cooling_ops); + if (IS_ERR(cdev)) + return PTR_ERR(cdev); + } + + return 0; +} +late_initcall(cpu_cooling_init); +#endif diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h index 2b5950b..308a914 100644 --- a/include/linux/cpu_cooling.h +++ b/include/linux/cpu_cooling.h @@ -33,7 +33,16 @@ struct cpufreq_policy; typedef int (*get_static_t)(cpumask_t *cpumask, int interval, unsigned long voltage, u32 *power); -#ifdef CONFIG_CPU_THERMAL +#if defined(CONFIG_CPU_IDLE_THERMAL) || defined(CONFIG_CPU_THERMAL_COMBO) +extern int cpuidle_cooling_register(void); +#else +static inline int cpuidle_cooling_register(void) +{ + return 0; +} +#endif + +#if defined(CONFIG_CPU_FREQ_THERMAL) || defined(CONFIG_CPU_THERMAL_COMBO) /** * cpufreq_cooling_register - function to create cpufreq cooling device. * @policy: cpufreq policy. @@ -45,7 +54,6 @@ struct thermal_cooling_device * cpufreq_power_cooling_register(struct cpufreq_policy *policy, u32 capacitance, get_static_t plat_static_func); -extern int cpuidle_cooling_register(void); /** * of_cpufreq_cooling_register - create cpufreq cooling device based on DT. * @np: a valid struct device_node to the cooling device device tree node. @@ -85,7 +93,7 @@ of_cpufreq_power_cooling_register(struct device_node *np, */ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev); -#else /* !CONFIG_CPU_THERMAL */ +#else /* !CONFIG_CPU_FREQ_THERMAL */ static inline struct thermal_cooling_device * cpufreq_cooling_register(struct cpufreq_policy *policy) { @@ -119,11 +127,6 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) { return; } - -static inline int cpuidle_cooling_register(void) -{ - return 0; -} -#endif /* CONFIG_CPU_THERMAL */ +#endif /* CONFIG_CPU_FREQ_THERMAL */ #endif /* __CPU_COOLING_H__ */