All of lore.kernel.org
 help / color / mirror / Atom feed
From: Zhang Rui <rui.zhang@intel.com>
To: "Valentin, Eduardo" <eduardo.valentin@ti.com>
Cc: Amit Kachhap <amit.kachhap@linaro.org>,
	linux-pm@lists.linux-foundation.org,
	Andrew Morton <akpm@linux-foundation.org>,
	Len Brown <lenb@kernel.org>,
	linux-samsung-soc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-acpi@vger.kernel.org, lm-sensors@lm-sensors.org,
	Guenter Roeck <guenter.roeck@ericsson.com>,
	SangWook Ju <sw.ju@samsung.com>,
	Durgadoss <durgadoss.r@intel.com>,
	Jean Delvare <khali@linux-fr.org>,
	Kyungmin Park <kmpark@infradead.org>,
	Kukjin Kim <kgene.kim@samsung.com>
Subject: Re: [PATCH v6 1/6] thermal: add generic cpufreq cooling implementation
Date: Mon, 20 Aug 2012 10:16:03 +0800	[thread overview]
Message-ID: <1345428963.1682.899.camel@rui.sh.intel.com> (raw)
In-Reply-To: <CAGF5oy_uhgbzTQeXPyJP51JXxbszX1cL+B=V0mzfRt7bcSi_sQ@mail.gmail.com>

On 五, 2012-08-17 at 11:56 +0300, Valentin, Eduardo wrote:
> Hello,

> >>> +
> >>> +
> >>> +1.2 CPU cooling action notifier register/unregister interface
> >>> +1.2.1 int cputherm_register_notifier(struct notifier_block *nb,
> >>> +     unsigned int list)
> >>> +
> >>> +    This interface registers a driver with cpu cooling layer. The driver will
> >>> +    be notified when any cpu cooling action is called.
> >>> +
> >>> +    nb: notifier function to register
> >>> +    list: CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP
> >>> +
> >>> +1.2.2 int cputherm_unregister_notifier(struct notifier_block *nb,
> >>> +     unsigned int list)
> >>> +
> >>> +    This interface registers a driver with cpu cooling layer. The driver will
> >>> +    be notified when any cpu cooling action is called.
> >>> +
> >>> +    nb: notifier function to register
> >>> +    list: CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP
> >>
> >> what are these two APIs used for?
> >> I did not see they are used in your patch set, do I miss something?
> > No currently they are not used by my patches. I added them on request
> > from Eduardo and others
> 
> Yeah, this was a suggestion as we didn't really know how the FW part
> would evolve by that time.
> 
> The reasoning is to allow any interested user (in kernel) to be
> notified when max frequency changes.

in this case, the cooling device should be updated.
Say all the target of the thermal_instances of a cooling devices is 0,
which means they want the cpu to run at maximum frequency, when the max
frequency changes, we should set the processor to the new max frequency
as well.
Using notification is not a good idea as user can not handle this
without interacting with the thermal framework.

IMO, we should introduce a new API to handle this, rather than just
notifications to users.

>  Actually, the use case behind
> this is to allow such users to perform some handshaking or stop their
> activities or even change some paramenters, in case the max frequency
> would change.

It is the cooling device driver that notice this change first, and it
should invoke something like thermal_cooling_device_update/rebind() to
tell the thermal framework this change.

>  Ideally it would be possible to nack the cooling
> transition. But that is yet a wider discussion. So far we don't have
> users for this.
> 
yep.
I thought about this before, but I'd prefer to do this when there is a
real user. Or else, we are kind of over-designing here.
how about removing this piece of code for now?

thanks,
rui

> >>
> >>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> >>> index 7dd8c34..996003b 100644
> >>> --- a/drivers/thermal/Kconfig
> >>> +++ b/drivers/thermal/Kconfig
> >>> @@ -19,6 +19,17 @@ config THERMAL_HWMON
> >>>       depends on HWMON=y || HWMON=THERMAL
> >>>       default y
> >>>
> >>> +config CPU_THERMAL
> >>> +     bool "generic cpu cooling support"
> >>> +     depends on THERMAL && CPU_FREQ
> >>> +     help
> >>> +       This implements the generic cpu cooling mechanism through frequency
> >>> +       reduction, cpu hotplug and any other ways of reducing temperature. 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.
> >>> +
> >>>  config SPEAR_THERMAL
> >>>       bool "SPEAr thermal sensor driver"
> >>>       depends on THERMAL
> >>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> >>> index fd9369a..aae59ad 100644
> >>> --- a/drivers/thermal/Makefile
> >>> +++ b/drivers/thermal/Makefile
> >>> @@ -3,5 +3,6 @@
> >>>  #
> >>>
> >>>  obj-$(CONFIG_THERMAL)                += thermal_sys.o
> >>> +obj-$(CONFIG_CPU_THERMAL)            += cpu_cooling.o
> >>>  obj-$(CONFIG_SPEAR_THERMAL)          += spear_thermal.o
> >>>  obj-$(CONFIG_RCAR_THERMAL)   += rcar_thermal.o
> >>> diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
> >>> new file mode 100644
> >>> index 0000000..c42e557
> >>> --- /dev/null
> >>> +++ b/drivers/thermal/cpu_cooling.c
> >>> @@ -0,0 +1,512 @@
> >>> +/*
> >>> + *  linux/drivers/thermal/cpu_cooling.c
> >>> + *
> >>> + *  Copyright (C) 2012       Samsung Electronics Co., Ltd(http://www.samsung.com)
> >>> + *  Copyright (C) 2012  Amit Daniel <amit.kachhap@linaro.org>
> >>> + *
> >>> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >>> + *  This program is free software; you can redistribute it and/or modify
> >>> + *  it under the terms of the GNU General Public License as published by
> >>> + *  the Free Software Foundation; version 2 of the License.
> >>> + *
> >>> + *  This program is distributed in the hope that it will be useful, but
> >>> + *  WITHOUT ANY WARRANTY; without even the implied warranty of
> >>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >>> + *  General Public License for more details.
> >>> + *
> >>> + *  You should have received a copy of the GNU General Public License along
> >>> + *  with this program; if not, write to the Free Software Foundation, Inc.,
> >>> + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> >>> + *
> >>> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >>> + */
> >>> +#include <linux/kernel.h>
> >>> +#include <linux/module.h>
> >>> +#include <linux/thermal.h>
> >>> +#include <linux/platform_device.h>
> >>> +#include <linux/cpufreq.h>
> >>> +#include <linux/err.h>
> >>> +#include <linux/slab.h>
> >>> +#include <linux/cpu.h>
> >>> +#include <linux/cpu_cooling.h>
> >>> +
> >>> +/**
> >>> + * struct cpufreq_cooling_device
> >>> + * @id: unique integer value corresponding to each cpufreq_cooling_device
> >>> + *   registered.
> >>> + * @cool_dev: thermal_cooling_device pointer to keep track of the the
> >>> + *   egistered cooling device.
> >>> + * @cpufreq_state: integer value representing the current state of cpufreq
> >>> + *   cooling devices.
> >>> + * @cpufreq_val: integer value representing the absolute value of the clipped
> >>> + *   frequency.
> >>> + * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device.
> >>> + * @node: list_head to link all cpufreq_cooling_device together.
> >>> + *
> >>> + * This structure is required for keeping information of each
> >>> + * cpufreq_cooling_device registered as a list whose head is represented by
> >>> + * cooling_cpufreq_list. In order to prevent corruption of this list a
> >>> + * mutex lock cooling_cpufreq_lock is used.
> >>> + */
> >>> +struct cpufreq_cooling_device {
> >>> +     int id;
> >>> +     struct thermal_cooling_device *cool_dev;
> >>> +     unsigned int cpufreq_state;
> >>> +     unsigned int cpufreq_val;
> >>> +     struct cpumask allowed_cpus;
> >>> +     struct list_head node;
> >>> +};
> >>> +static LIST_HEAD(cooling_cpufreq_list);
> >>> +static DEFINE_IDR(cpufreq_idr);
> >>> +
> >>> +static struct mutex cooling_cpufreq_lock;
> >>> +
> >>> +/* notify_table passes value to the CPUFREQ_ADJUST callback function. */
> >>> +#define NOTIFY_INVALID NULL
> >>> +struct cpufreq_cooling_device *notify_device;
> >>> +
> >>> +/* Head of the blocking notifier chain to inform about frequency clamping */
> >>> +static BLOCKING_NOTIFIER_HEAD(cputherm_state_notifier_list);
> >>> +
> >>> +/**
> >>> + * get_idr - function to get a unique id.
> >>> + * @idr: struct idr * handle used to create a id.
> >>> + * @id: int * value generated by this function.
> >>> + */
> >>> +static int get_idr(struct idr *idr, int *id)
> >>> +{
> >>> +     int err;
> >>> +again:
> >>> +     if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
> >>> +             return -ENOMEM;
> >>> +
> >>> +     mutex_lock(&cooling_cpufreq_lock);
> >>> +     err = idr_get_new(idr, NULL, id);
> >>> +     mutex_unlock(&cooling_cpufreq_lock);
> >>> +
> >>> +     if (unlikely(err == -EAGAIN))
> >>> +             goto again;
> >>> +     else if (unlikely(err))
> >>> +             return err;
> >>> +
> >>> +     *id = *id & MAX_ID_MASK;
> >>> +     return 0;
> >>> +}
> >>> +
> >>> +/**
> >>> + * release_idr - function to free the unique id.
> >>> + * @idr: struct idr * handle used for creating the id.
> >>> + * @id: int value representing the unique id.
> >>> + */
> >>> +static void release_idr(struct idr *idr, int id)
> >>> +{
> >>> +     mutex_lock(&cooling_cpufreq_lock);
> >>> +     idr_remove(idr, id);
> >>> +     mutex_unlock(&cooling_cpufreq_lock);
> >>> +}
> >>> +
> >>> +/**
> >>> + * cputherm_register_notifier - Register a notifier with cpu cooling interface.
> >>> + * @nb:      struct notifier_block * with callback info.
> >>> + * @list: integer value for which notification is needed. possible values are
> >>> + *   CPUFREQ_COOLING_START and CPUFREQ_COOLING_STOP.
> >>> + *
> >>> + * This exported function registers a driver with cpu cooling layer. The driver
> >>> + * will be notified when any cpu cooling action is called.
> >>> + */
> >>> +int cputherm_register_notifier(struct notifier_block *nb, unsigned int list)
> >>> +{
> >>> +     int ret = 0;
> >>> +
> >>> +     switch (list) {
> >>> +     case CPUFREQ_COOLING_START:
> >>> +     case CPUFREQ_COOLING_STOP:
> >>> +             ret = blocking_notifier_chain_register(
> >>> +                             &cputherm_state_notifier_list, nb);
> >>> +             break;
> >>> +     default:
> >>> +             ret = -EINVAL;
> >>> +     }
> >>> +     return ret;
> >>> +}
> >>> +EXPORT_SYMBOL(cputherm_register_notifier);
> >>> +
> >>> +/**
> >>> + * cputherm_unregister_notifier - Un-register a notifier.
> >>> + * @nb:      struct notifier_block * with callback info.
> >>> + * @list: integer value for which notification is needed. values possible are
> >>> + *   CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP.
> >>> + *
> >>> + * This exported function un-registers a driver with cpu cooling layer.
> >>> + */
> >>> +int cputherm_unregister_notifier(struct notifier_block *nb, unsigned int list)
> >>> +{
> >>> +     int ret = 0;
> >>> +
> >>> +     switch (list) {
> >>> +     case CPUFREQ_COOLING_START:
> >>> +     case CPUFREQ_COOLING_STOP:
> >>> +             ret = blocking_notifier_chain_unregister(
> >>> +                             &cputherm_state_notifier_list, nb);
> >>> +             break;
> >>> +     default:
> >>> +             ret = -EINVAL;
> >>> +     }
> >>> +     return ret;
> >>> +}
> >>> +EXPORT_SYMBOL(cputherm_unregister_notifier);
> >>> +
> >>> +/* Below code defines functions to be used for cpufreq as cooling device */
> >>> +
> >>> +/**
> >>> + * is_cpufreq_valid - function to check if a cpu has frequency transition policy.
> >>> + * @cpu: cpu for which check is needed.
> >>> + */
> >>> +static int is_cpufreq_valid(int cpu)
> >>> +{
> >>> +     struct cpufreq_policy policy;
> >>> +     return !cpufreq_get_policy(&policy, cpu);
> >>> +}
> >>> +
> >>> +/**
> >>> + * get_cpu_frequency - get the absolute value of frequency from level.
> >>> + * @cpu: cpu for which frequency is fetched.
> >>> + * @level: level of frequency of the CPU
> >>> + *   e.g level=1 --> 1st MAX FREQ, LEVEL=2 ---> 2nd MAX FREQ, .... etc
> >>> + */
> >>> +static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level)
> >>> +{
> >>> +     int ret = 0, i = 0;
> >>> +     unsigned long level_index;
> >>> +     bool descend = false;
> >>> +     struct cpufreq_frequency_table *table =
> >>> +                                     cpufreq_frequency_get_table(cpu);
> >>> +     if (!table)
> >>> +             return ret;
> >>> +
> >>> +     while (table[i].frequency != CPUFREQ_TABLE_END) {
> >>> +             if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
> >>> +                     continue;
> >>> +
> >>> +             /*check if table in ascending or descending order*/
> >>> +             if ((table[i + 1].frequency != CPUFREQ_TABLE_END) &&
> >>> +                     (table[i + 1].frequency < table[i].frequency)
> >>> +                     && !descend) {
> >>> +                     descend = true;
> >>> +             }
> >>> +
> >>> +             /*return if level matched and table in descending order*/
> >>> +             if (descend && i == level)
> >>> +                     return table[i].frequency;
> >>> +             i++;
> >>> +     }
> >>> +     i--;
> >>> +
> >>> +     if (level > i || descend)
> >>> +             return ret;
> >>> +     level_index = i - level;
> >>> +
> >>> +     /*Scan the table in reverse order and match the level*/
> >>> +     while (i >= 0) {
> >>> +             if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
> >>> +                     continue;
> >>> +             /*return if level matched*/
> >>> +             if (i == level_index)
> >>> +                     return table[i].frequency;
> >>> +             i--;
> >>> +     }
> >>> +     return ret;
> >>> +}
> >>> +
> >>> +/**
> >>> + * cpufreq_apply_cooling - function to apply frequency clipping.
> >>> + * @cpufreq_device: cpufreq_cooling_device pointer containing frequency
> >>> + *   clipping data.
> >>> + * @cooling_state: value of the cooling state.
> >>> + */
> >>> +static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
> >>> +                             unsigned long cooling_state)
> >>> +{
> >>> +     unsigned int event, cpuid, clip_freq;
> >>> +     struct cpumask *maskPtr = &cpufreq_device->allowed_cpus;
> >>> +     unsigned int cpu = cpumask_any(maskPtr);
> >>> +
> >>> +
> >>> +     /* Check if the old cooling action is same as new cooling action */
> >>> +     if (cpufreq_device->cpufreq_state == cooling_state)
> >>> +             return 0;
> >>> +
> >>> +     clip_freq = get_cpu_frequency(cpu, cooling_state);
> >>> +     if (!clip_freq)
> >>> +             return -EINVAL;
> >>> +
> >>> +     cpufreq_device->cpufreq_state = cooling_state;
> >>> +     cpufreq_device->cpufreq_val = clip_freq;
> >>> +     notify_device = cpufreq_device;
> >>> +
> >>> +     if (cooling_state != 0)
> >>> +             event = CPUFREQ_COOLING_START;
> >>> +     else
> >>> +             event = CPUFREQ_COOLING_STOP;
> >>> +
> >>> +     blocking_notifier_call_chain(&cputherm_state_notifier_list,
> >>> +                                             event, &clip_freq);
> >>> +
> >>> +     for_each_cpu(cpuid, maskPtr) {
> >>> +             if (is_cpufreq_valid(cpuid))
> >>> +                     cpufreq_update_policy(cpuid);
> >>> +     }
> >>> +
> >>> +     notify_device = NOTIFY_INVALID;
> >>> +
> >>> +     return 0;
> >>> +}
> >>> +
> >>> +/**
> >>> + * cpufreq_thermal_notifier - notifier callback for cpufreq policy change.
> >>> + * @nb:      struct notifier_block * with callback info.
> >>> + * @event: value showing cpufreq event for which this function invoked.
> >>> + * @data: callback-specific data
> >>> + */
> >>> +static int cpufreq_thermal_notifier(struct notifier_block *nb,
> >>> +                                     unsigned long event, void *data)
> >>> +{
> >>> +     struct cpufreq_policy *policy = data;
> >>> +     unsigned long max_freq = 0;
> >>> +
> >>> +     if (event != CPUFREQ_ADJUST || notify_device == NOTIFY_INVALID)
> >>> +             return 0;
> >>> +
> >>> +     if (cpumask_test_cpu(policy->cpu, &notify_device->allowed_cpus))
> >>> +             max_freq = notify_device->cpufreq_val;
> >>> +
> >>> +     /* Never exceed user_policy.max*/
> >>> +     if (max_freq > policy->user_policy.max)
> >>> +             max_freq = policy->user_policy.max;
> >>> +
> >>> +     if (policy->max != max_freq)
> >>> +             cpufreq_verify_within_limits(policy, 0, max_freq);
> >>> +
> >>> +     return 0;
> >>> +}
> >>> +
> >>> +/*
> >>> + * cpufreq cooling device callback functions are defined below
> >>> + */
> >>> +
> >>> +/**
> >>> + * cpufreq_get_max_state - callback function to get the max cooling state.
> >>> + * @cdev: thermal cooling device pointer.
> >>> + * @state: fill this variable with the max cooling state.
> >>> + */
> >>> +static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
> >>> +                              unsigned long *state)
> >>> +{
> >>> +     int ret = -EINVAL, i = 0;
> >>> +     struct cpufreq_cooling_device *cpufreq_device;
> >>> +     struct cpumask *maskPtr;
> >>> +     unsigned int cpu;
> >>> +     struct cpufreq_frequency_table *table;
> >>> +
> >>> +     mutex_lock(&cooling_cpufreq_lock);
> >>> +     list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
> >>> +             if (cpufreq_device && cpufreq_device->cool_dev == cdev)
> >>> +                     break;
> >>> +     }
> >>> +     if (cpufreq_device == NULL)
> >>> +             goto return_get_max_state;
> >>> +
> >>> +     maskPtr = &cpufreq_device->allowed_cpus;
> >>> +     cpu = cpumask_any(maskPtr);
> >>> +     table = cpufreq_frequency_get_table(cpu);
> >>> +     if (!table) {
> >>> +             *state = 0;
> >>> +             ret = 0;
> >>> +             goto return_get_max_state;
> >>> +     }
> >>> +
> >>> +     while (table[i].frequency != CPUFREQ_TABLE_END) {
> >>> +             if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
> >>> +                     continue;
> >>> +             i++;
> >>> +     }
> >>> +     if (i > 0) {
> >>> +             *state = --i;
> >>> +             ret = 0;
> >>> +     }
> >>> +
> >>> +return_get_max_state:
> >>> +     mutex_unlock(&cooling_cpufreq_lock);
> >>> +     return ret;
> >>> +}
> >>> +
> >>> +/**
> >>> + * cpufreq_get_cur_state - callback function to get the current cooling state.
> >>> + * @cdev: thermal cooling device pointer.
> >>> + * @state: fill this variable with the current cooling state.
> >>> + */
> >>> +static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
> >>> +                              unsigned long *state)
> >>> +{
> >>> +     int ret = -EINVAL;
> >>> +     struct cpufreq_cooling_device *cpufreq_device;
> >>> +
> >>> +     mutex_lock(&cooling_cpufreq_lock);
> >>> +     list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
> >>> +             if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
> >>> +                     *state = cpufreq_device->cpufreq_state;
> >>> +                     ret = 0;
> >>> +                     break;
> >>> +             }
> >>> +     }
> >>> +     mutex_unlock(&cooling_cpufreq_lock);
> >>> +
> >>
> >> as cpufreq may be changed in other places, e.g. via sysfs I/F, we should
> >> use the current cpu frequency to get the REAL cooling state, rather than
> >> using a cached value.
> >
> > Yes agreed , I will repost with your suggestion.
> >
> > Thanks,
> > Amit
> >>
> >> thanks,
> >> rui
> >>
> >>
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 
> 


--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

WARNING: multiple messages have this Message-ID (diff)
From: Zhang Rui <rui.zhang@intel.com>
To: "Valentin, Eduardo" <eduardo.valentin@ti.com>
Cc: Amit Kachhap <amit.kachhap@linaro.org>,
	linux-pm@lists.linux-foundation.org,
	Andrew Morton <akpm@linux-foundation.org>,
	Len Brown <lenb@kernel.org>,
	linux-samsung-soc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-acpi@vger.kernel.org, lm-sensors@lm-sensors.org,
	Guenter Roeck <guenter.roeck@ericsson.com>,
	SangWook Ju <sw.ju@samsung.com>,
	Durgadoss <durgadoss.r@intel.com>,
	Jean Delvare <khali@linux-fr.org>,
	Kyungmin Park <kmpark@infradead.org>,
	Kukjin Kim <kgene.kim@samsung.com>
Subject: Re: [lm-sensors] [PATCH v6 1/6] thermal: add generic cpufreq cooling implementation
Date: Mon, 20 Aug 2012 02:16:03 +0000	[thread overview]
Message-ID: <1345428963.1682.899.camel@rui.sh.intel.com> (raw)
In-Reply-To: <CAGF5oy_uhgbzTQeXPyJP51JXxbszX1cL+B=V0mzfRt7bcSi_sQ@mail.gmail.com>

T24g5LqULCAyMDEyLTA4LTE3IGF0IDExOjU2ICswMzAwLCBWYWxlbnRpbiwgRWR1YXJkbyB3cm90
ZToKPiBIZWxsbywKCj4gPj4+ICsKPiA+Pj4gKwo+ID4+PiArMS4yIENQVSBjb29saW5nIGFjdGlv
biBub3RpZmllciByZWdpc3Rlci91bnJlZ2lzdGVyIGludGVyZmFjZQo+ID4+PiArMS4yLjEgaW50
IGNwdXRoZXJtX3JlZ2lzdGVyX25vdGlmaWVyKHN0cnVjdCBub3RpZmllcl9ibG9jayAqbmIsCj4g
Pj4+ICsgICAgIHVuc2lnbmVkIGludCBsaXN0KQo+ID4+PiArCj4gPj4+ICsgICAgVGhpcyBpbnRl
cmZhY2UgcmVnaXN0ZXJzIGEgZHJpdmVyIHdpdGggY3B1IGNvb2xpbmcgbGF5ZXIuIFRoZSBkcml2
ZXIgd2lsbAo+ID4+PiArICAgIGJlIG5vdGlmaWVkIHdoZW4gYW55IGNwdSBjb29saW5nIGFjdGlv
biBpcyBjYWxsZWQuCj4gPj4+ICsKPiA+Pj4gKyAgICBuYjogbm90aWZpZXIgZnVuY3Rpb24gdG8g
cmVnaXN0ZXIKPiA+Pj4gKyAgICBsaXN0OiBDUFVGUkVRX0NPT0xJTkdfU1RBUlQgb3IgQ1BVRlJF
UV9DT09MSU5HX1NUT1AKPiA+Pj4gKwo+ID4+PiArMS4yLjIgaW50IGNwdXRoZXJtX3VucmVnaXN0
ZXJfbm90aWZpZXIoc3RydWN0IG5vdGlmaWVyX2Jsb2NrICpuYiwKPiA+Pj4gKyAgICAgdW5zaWdu
ZWQgaW50IGxpc3QpCj4gPj4+ICsKPiA+Pj4gKyAgICBUaGlzIGludGVyZmFjZSByZWdpc3RlcnMg
YSBkcml2ZXIgd2l0aCBjcHUgY29vbGluZyBsYXllci4gVGhlIGRyaXZlciB3aWxsCj4gPj4+ICsg
ICAgYmUgbm90aWZpZWQgd2hlbiBhbnkgY3B1IGNvb2xpbmcgYWN0aW9uIGlzIGNhbGxlZC4KPiA+
Pj4gKwo+ID4+PiArICAgIG5iOiBub3RpZmllciBmdW5jdGlvbiB0byByZWdpc3Rlcgo+ID4+PiAr
ICAgIGxpc3Q6IENQVUZSRVFfQ09PTElOR19TVEFSVCBvciBDUFVGUkVRX0NPT0xJTkdfU1RPUAo+
ID4+Cj4gPj4gd2hhdCBhcmUgdGhlc2UgdHdvIEFQSXMgdXNlZCBmb3I/Cj4gPj4gSSBkaWQgbm90
IHNlZSB0aGV5IGFyZSB1c2VkIGluIHlvdXIgcGF0Y2ggc2V0LCBkbyBJIG1pc3Mgc29tZXRoaW5n
Pwo+ID4gTm8gY3VycmVudGx5IHRoZXkgYXJlIG5vdCB1c2VkIGJ5IG15IHBhdGNoZXMuIEkgYWRk
ZWQgdGhlbSBvbiByZXF1ZXN0Cj4gPiBmcm9tIEVkdWFyZG8gYW5kIG90aGVycwo+IAo+IFllYWgs
IHRoaXMgd2FzIGEgc3VnZ2VzdGlvbiBhcyB3ZSBkaWRuJ3QgcmVhbGx5IGtub3cgaG93IHRoZSBG
VyBwYXJ0Cj4gd291bGQgZXZvbHZlIGJ5IHRoYXQgdGltZS4KPiAKPiBUaGUgcmVhc29uaW5nIGlz
IHRvIGFsbG93IGFueSBpbnRlcmVzdGVkIHVzZXIgKGluIGtlcm5lbCkgdG8gYmUKPiBub3RpZmll
ZCB3aGVuIG1heCBmcmVxdWVuY3kgY2hhbmdlcy4KCmluIHRoaXMgY2FzZSwgdGhlIGNvb2xpbmcg
ZGV2aWNlIHNob3VsZCBiZSB1cGRhdGVkLgpTYXkgYWxsIHRoZSB0YXJnZXQgb2YgdGhlIHRoZXJt
YWxfaW5zdGFuY2VzIG9mIGEgY29vbGluZyBkZXZpY2VzIGlzIDAsCndoaWNoIG1lYW5zIHRoZXkg
d2FudCB0aGUgY3B1IHRvIHJ1biBhdCBtYXhpbXVtIGZyZXF1ZW5jeSwgd2hlbiB0aGUgbWF4CmZy
ZXF1ZW5jeSBjaGFuZ2VzLCB3ZSBzaG91bGQgc2V0IHRoZSBwcm9jZXNzb3IgdG8gdGhlIG5ldyBt
YXggZnJlcXVlbmN5CmFzIHdlbGwuClVzaW5nIG5vdGlmaWNhdGlvbiBpcyBub3QgYSBnb29kIGlk
ZWEgYXMgdXNlciBjYW4gbm90IGhhbmRsZSB0aGlzCndpdGhvdXQgaW50ZXJhY3Rpbmcgd2l0aCB0
aGUgdGhlcm1hbCBmcmFtZXdvcmsuCgpJTU8sIHdlIHNob3VsZCBpbnRyb2R1Y2UgYSBuZXcgQVBJ
IHRvIGhhbmRsZSB0aGlzLCByYXRoZXIgdGhhbiBqdXN0Cm5vdGlmaWNhdGlvbnMgdG8gdXNlcnMu
Cgo+ICBBY3R1YWxseSwgdGhlIHVzZSBjYXNlIGJlaGluZAo+IHRoaXMgaXMgdG8gYWxsb3cgc3Vj
aCB1c2VycyB0byBwZXJmb3JtIHNvbWUgaGFuZHNoYWtpbmcgb3Igc3RvcCB0aGVpcgo+IGFjdGl2
aXRpZXMgb3IgZXZlbiBjaGFuZ2Ugc29tZSBwYXJhbWVudGVycywgaW4gY2FzZSB0aGUgbWF4IGZy
ZXF1ZW5jeQo+IHdvdWxkIGNoYW5nZS4KCkl0IGlzIHRoZSBjb29saW5nIGRldmljZSBkcml2ZXIg
dGhhdCBub3RpY2UgdGhpcyBjaGFuZ2UgZmlyc3QsIGFuZCBpdApzaG91bGQgaW52b2tlIHNvbWV0
aGluZyBsaWtlIHRoZXJtYWxfY29vbGluZ19kZXZpY2VfdXBkYXRlL3JlYmluZCgpIHRvCnRlbGwg
dGhlIHRoZXJtYWwgZnJhbWV3b3JrIHRoaXMgY2hhbmdlLgoKPiAgSWRlYWxseSBpdCB3b3VsZCBi
ZSBwb3NzaWJsZSB0byBuYWNrIHRoZSBjb29saW5nCj4gdHJhbnNpdGlvbi4gQnV0IHRoYXQgaXMg
eWV0IGEgd2lkZXIgZGlzY3Vzc2lvbi4gU28gZmFyIHdlIGRvbid0IGhhdmUKPiB1c2VycyBmb3Ig
dGhpcy4KPiAKeWVwLgpJIHRob3VnaHQgYWJvdXQgdGhpcyBiZWZvcmUsIGJ1dCBJJ2QgcHJlZmVy
IHRvIGRvIHRoaXMgd2hlbiB0aGVyZSBpcyBhCnJlYWwgdXNlci4gT3IgZWxzZSwgd2UgYXJlIGtp
bmQgb2Ygb3Zlci1kZXNpZ25pbmcgaGVyZS4KaG93IGFib3V0IHJlbW92aW5nIHRoaXMgcGllY2Ug
b2YgY29kZSBmb3Igbm93PwoKdGhhbmtzLApydWkKCj4gPj4KPiA+Pj4gZGlmZiAtLWdpdCBhL2Ry
aXZlcnMvdGhlcm1hbC9LY29uZmlnIGIvZHJpdmVycy90aGVybWFsL0tjb25maWcKPiA+Pj4gaW5k
ZXggN2RkOGMzNC4uOTk2MDAzYiAxMDA2NDQKPiA+Pj4gLS0tIGEvZHJpdmVycy90aGVybWFsL0tj
b25maWcKPiA+Pj4gKysrIGIvZHJpdmVycy90aGVybWFsL0tjb25maWcKPiA+Pj4gQEAgLTE5LDYg
KzE5LDE3IEBAIGNvbmZpZyBUSEVSTUFMX0hXTU9OCj4gPj4+ICAgICAgIGRlcGVuZHMgb24gSFdN
T049eSB8fCBIV01PTj1USEVSTUFMCj4gPj4+ICAgICAgIGRlZmF1bHQgeQo+ID4+Pgo+ID4+PiAr
Y29uZmlnIENQVV9USEVSTUFMCj4gPj4+ICsgICAgIGJvb2wgImdlbmVyaWMgY3B1IGNvb2xpbmcg
c3VwcG9ydCIKPiA+Pj4gKyAgICAgZGVwZW5kcyBvbiBUSEVSTUFMICYmIENQVV9GUkVRCj4gPj4+
ICsgICAgIGhlbHAKPiA+Pj4gKyAgICAgICBUaGlzIGltcGxlbWVudHMgdGhlIGdlbmVyaWMgY3B1
IGNvb2xpbmcgbWVjaGFuaXNtIHRocm91Z2ggZnJlcXVlbmN5Cj4gPj4+ICsgICAgICAgcmVkdWN0
aW9uLCBjcHUgaG90cGx1ZyBhbmQgYW55IG90aGVyIHdheXMgb2YgcmVkdWNpbmcgdGVtcGVyYXR1
cmUuIEFuCj4gPj4+ICsgICAgICAgQUNQSSB2ZXJzaW9uIG9mIHRoaXMgYWxyZWFkeSBleGlzdHMo
ZHJpdmVycy9hY3BpL3Byb2Nlc3Nvcl90aGVybWFsLmMpLgo+ID4+PiArICAgICAgIFRoaXMgd2ls
bCBiZSB1c2VmdWwgZm9yIHBsYXRmb3JtcyB1c2luZyB0aGUgZ2VuZXJpYyB0aGVybWFsIGludGVy
ZmFjZQo+ID4+PiArICAgICAgIGFuZCBub3QgdGhlIEFDUEkgaW50ZXJmYWNlLgo+ID4+PiArICAg
ICAgIElmIHlvdSB3YW50IHRoaXMgc3VwcG9ydCwgeW91IHNob3VsZCBzYXkgWSBoZXJlLgo+ID4+
PiArCj4gPj4+ICBjb25maWcgU1BFQVJfVEhFUk1BTAo+ID4+PiAgICAgICBib29sICJTUEVBciB0
aGVybWFsIHNlbnNvciBkcml2ZXIiCj4gPj4+ICAgICAgIGRlcGVuZHMgb24gVEhFUk1BTAo+ID4+
PiBkaWZmIC0tZ2l0IGEvZHJpdmVycy90aGVybWFsL01ha2VmaWxlIGIvZHJpdmVycy90aGVybWFs
L01ha2VmaWxlCj4gPj4+IGluZGV4IGZkOTM2OWEuLmFhZTU5YWQgMTAwNjQ0Cj4gPj4+IC0tLSBh
L2RyaXZlcnMvdGhlcm1hbC9NYWtlZmlsZQo+ID4+PiArKysgYi9kcml2ZXJzL3RoZXJtYWwvTWFr
ZWZpbGUKPiA+Pj4gQEAgLTMsNSArMyw2IEBACj4gPj4+ICAjCj4gPj4+Cj4gPj4+ICBvYmotJChD
T05GSUdfVEhFUk1BTCkgICAgICAgICAgICAgICAgKz0gdGhlcm1hbF9zeXMubwo+ID4+PiArb2Jq
LSQoQ09ORklHX0NQVV9USEVSTUFMKSAgICAgICAgICAgICs9IGNwdV9jb29saW5nLm8KPiA+Pj4g
IG9iai0kKENPTkZJR19TUEVBUl9USEVSTUFMKSAgICAgICAgICArPSBzcGVhcl90aGVybWFsLm8K
PiA+Pj4gIG9iai0kKENPTkZJR19SQ0FSX1RIRVJNQUwpICAgKz0gcmNhcl90aGVybWFsLm8KPiA+
Pj4gZGlmZiAtLWdpdCBhL2RyaXZlcnMvdGhlcm1hbC9jcHVfY29vbGluZy5jIGIvZHJpdmVycy90
aGVybWFsL2NwdV9jb29saW5nLmMKPiA+Pj4gbmV3IGZpbGUgbW9kZSAxMDA2NDQKPiA+Pj4gaW5k
ZXggMDAwMDAwMC4uYzQyZTU1Nwo+ID4+PiAtLS0gL2Rldi9udWxsCj4gPj4+ICsrKyBiL2RyaXZl
cnMvdGhlcm1hbC9jcHVfY29vbGluZy5jCj4gPj4+IEBAIC0wLDAgKzEsNTEyIEBACj4gPj4+ICsv
Kgo+ID4+PiArICogIGxpbnV4L2RyaXZlcnMvdGhlcm1hbC9jcHVfY29vbGluZy5jCj4gPj4+ICsg
Kgo+ID4+PiArICogIENvcHlyaWdodCAoQykgMjAxMiAgICAgICBTYW1zdW5nIEVsZWN0cm9uaWNz
IENvLiwgTHRkKGh0dHA6Ly93d3cuc2Ftc3VuZy5jb20pCj4gPj4+ICsgKiAgQ29weXJpZ2h0IChD
KSAyMDEyICBBbWl0IERhbmllbCA8YW1pdC5rYWNoaGFwQGxpbmFyby5vcmc+Cj4gPj4+ICsgKgo+
ID4+PiArICogfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+
fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4KPiA+Pj4gKyAqICBUaGlzIHByb2dyYW0gaXMgZnJl
ZSBzb2Z0d2FyZTsgeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeQo+ID4+PiAr
ICogIGl0IHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljIExpY2Vuc2Ug
YXMgcHVibGlzaGVkIGJ5Cj4gPj4+ICsgKiAgdGhlIEZyZWUgU29mdHdhcmUgRm91bmRhdGlvbjsg
dmVyc2lvbiAyIG9mIHRoZSBMaWNlbnNlLgo+ID4+PiArICoKPiA+Pj4gKyAqICBUaGlzIHByb2dy
YW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCwgYnV0
Cj4gPj4+ICsgKiAgV0lUSE9VVCBBTlkgV0FSUkFOVFk7IHdpdGhvdXQgZXZlbiB0aGUgaW1wbGll
ZCB3YXJyYW50eSBvZgo+ID4+PiArICogIE1FUkNIQU5UQUJJTElUWSBvciBGSVRORVNTIEZPUiBB
IFBBUlRJQ1VMQVIgUFVSUE9TRS4gIFNlZSB0aGUgR05VCj4gPj4+ICsgKiAgR2VuZXJhbCBQdWJs
aWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLgo+ID4+PiArICoKPiA+Pj4gKyAqICBZb3Ugc2hv
dWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5z
ZSBhbG9uZwo+ID4+PiArICogIHdpdGggdGhpcyBwcm9ncmFtOyBpZiBub3QsIHdyaXRlIHRvIHRo
ZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIEluYy4sCj4gPj4+ICsgKiAgNTkgVGVtcGxlIFBs
YWNlLCBTdWl0ZSAzMzAsIEJvc3RvbiwgTUEgMDIxMTEtMTMwNyBVU0EuCj4gPj4+ICsgKgo+ID4+
PiArICogfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+
fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4KPiA+Pj4gKyAqLwo+ID4+PiArI2luY2x1ZGUgPGxpbnV4
L2tlcm5lbC5oPgo+ID4+PiArI2luY2x1ZGUgPGxpbnV4L21vZHVsZS5oPgo+ID4+PiArI2luY2x1
ZGUgPGxpbnV4L3RoZXJtYWwuaD4KPiA+Pj4gKyNpbmNsdWRlIDxsaW51eC9wbGF0Zm9ybV9kZXZp
Y2UuaD4KPiA+Pj4gKyNpbmNsdWRlIDxsaW51eC9jcHVmcmVxLmg+Cj4gPj4+ICsjaW5jbHVkZSA8
bGludXgvZXJyLmg+Cj4gPj4+ICsjaW5jbHVkZSA8bGludXgvc2xhYi5oPgo+ID4+PiArI2luY2x1
ZGUgPGxpbnV4L2NwdS5oPgo+ID4+PiArI2luY2x1ZGUgPGxpbnV4L2NwdV9jb29saW5nLmg+Cj4g
Pj4+ICsKPiA+Pj4gKy8qKgo+ID4+PiArICogc3RydWN0IGNwdWZyZXFfY29vbGluZ19kZXZpY2UK
PiA+Pj4gKyAqIEBpZDogdW5pcXVlIGludGVnZXIgdmFsdWUgY29ycmVzcG9uZGluZyB0byBlYWNo
IGNwdWZyZXFfY29vbGluZ19kZXZpY2UKPiA+Pj4gKyAqICAgcmVnaXN0ZXJlZC4KPiA+Pj4gKyAq
IEBjb29sX2RldjogdGhlcm1hbF9jb29saW5nX2RldmljZSBwb2ludGVyIHRvIGtlZXAgdHJhY2sg
b2YgdGhlIHRoZQo+ID4+PiArICogICBlZ2lzdGVyZWQgY29vbGluZyBkZXZpY2UuCj4gPj4+ICsg
KiBAY3B1ZnJlcV9zdGF0ZTogaW50ZWdlciB2YWx1ZSByZXByZXNlbnRpbmcgdGhlIGN1cnJlbnQg
c3RhdGUgb2YgY3B1ZnJlcQo+ID4+PiArICogICBjb29saW5nIGRldmljZXMuCj4gPj4+ICsgKiBA
Y3B1ZnJlcV92YWw6IGludGVnZXIgdmFsdWUgcmVwcmVzZW50aW5nIHRoZSBhYnNvbHV0ZSB2YWx1
ZSBvZiB0aGUgY2xpcHBlZAo+ID4+PiArICogICBmcmVxdWVuY3kuCj4gPj4+ICsgKiBAYWxsb3dl
ZF9jcHVzOiBhbGwgdGhlIGNwdXMgaW52b2x2ZWQgZm9yIHRoaXMgY3B1ZnJlcV9jb29saW5nX2Rl
dmljZS4KPiA+Pj4gKyAqIEBub2RlOiBsaXN0X2hlYWQgdG8gbGluayBhbGwgY3B1ZnJlcV9jb29s
aW5nX2RldmljZSB0b2dldGhlci4KPiA+Pj4gKyAqCj4gPj4+ICsgKiBUaGlzIHN0cnVjdHVyZSBp
cyByZXF1aXJlZCBmb3Iga2VlcGluZyBpbmZvcm1hdGlvbiBvZiBlYWNoCj4gPj4+ICsgKiBjcHVm
cmVxX2Nvb2xpbmdfZGV2aWNlIHJlZ2lzdGVyZWQgYXMgYSBsaXN0IHdob3NlIGhlYWQgaXMgcmVw
cmVzZW50ZWQgYnkKPiA+Pj4gKyAqIGNvb2xpbmdfY3B1ZnJlcV9saXN0LiBJbiBvcmRlciB0byBw
cmV2ZW50IGNvcnJ1cHRpb24gb2YgdGhpcyBsaXN0IGEKPiA+Pj4gKyAqIG11dGV4IGxvY2sgY29v
bGluZ19jcHVmcmVxX2xvY2sgaXMgdXNlZC4KPiA+Pj4gKyAqLwo+ID4+PiArc3RydWN0IGNwdWZy
ZXFfY29vbGluZ19kZXZpY2Ugewo+ID4+PiArICAgICBpbnQgaWQ7Cj4gPj4+ICsgICAgIHN0cnVj
dCB0aGVybWFsX2Nvb2xpbmdfZGV2aWNlICpjb29sX2RldjsKPiA+Pj4gKyAgICAgdW5zaWduZWQg
aW50IGNwdWZyZXFfc3RhdGU7Cj4gPj4+ICsgICAgIHVuc2lnbmVkIGludCBjcHVmcmVxX3ZhbDsK
PiA+Pj4gKyAgICAgc3RydWN0IGNwdW1hc2sgYWxsb3dlZF9jcHVzOwo+ID4+PiArICAgICBzdHJ1
Y3QgbGlzdF9oZWFkIG5vZGU7Cj4gPj4+ICt9Owo+ID4+PiArc3RhdGljIExJU1RfSEVBRChjb29s
aW5nX2NwdWZyZXFfbGlzdCk7Cj4gPj4+ICtzdGF0aWMgREVGSU5FX0lEUihjcHVmcmVxX2lkcik7
Cj4gPj4+ICsKPiA+Pj4gK3N0YXRpYyBzdHJ1Y3QgbXV0ZXggY29vbGluZ19jcHVmcmVxX2xvY2s7
Cj4gPj4+ICsKPiA+Pj4gKy8qIG5vdGlmeV90YWJsZSBwYXNzZXMgdmFsdWUgdG8gdGhlIENQVUZS
RVFfQURKVVNUIGNhbGxiYWNrIGZ1bmN0aW9uLiAqLwo+ID4+PiArI2RlZmluZSBOT1RJRllfSU5W
QUxJRCBOVUxMCj4gPj4+ICtzdHJ1Y3QgY3B1ZnJlcV9jb29saW5nX2RldmljZSAqbm90aWZ5X2Rl
dmljZTsKPiA+Pj4gKwo+ID4+PiArLyogSGVhZCBvZiB0aGUgYmxvY2tpbmcgbm90aWZpZXIgY2hh
aW4gdG8gaW5mb3JtIGFib3V0IGZyZXF1ZW5jeSBjbGFtcGluZyAqLwo+ID4+PiArc3RhdGljIEJM
T0NLSU5HX05PVElGSUVSX0hFQUQoY3B1dGhlcm1fc3RhdGVfbm90aWZpZXJfbGlzdCk7Cj4gPj4+
ICsKPiA+Pj4gKy8qKgo+ID4+PiArICogZ2V0X2lkciAtIGZ1bmN0aW9uIHRvIGdldCBhIHVuaXF1
ZSBpZC4KPiA+Pj4gKyAqIEBpZHI6IHN0cnVjdCBpZHIgKiBoYW5kbGUgdXNlZCB0byBjcmVhdGUg
YSBpZC4KPiA+Pj4gKyAqIEBpZDogaW50ICogdmFsdWUgZ2VuZXJhdGVkIGJ5IHRoaXMgZnVuY3Rp
b24uCj4gPj4+ICsgKi8KPiA+Pj4gK3N0YXRpYyBpbnQgZ2V0X2lkcihzdHJ1Y3QgaWRyICppZHIs
IGludCAqaWQpCj4gPj4+ICt7Cj4gPj4+ICsgICAgIGludCBlcnI7Cj4gPj4+ICthZ2FpbjoKPiA+
Pj4gKyAgICAgaWYgKHVubGlrZWx5KGlkcl9wcmVfZ2V0KGlkciwgR0ZQX0tFUk5FTCkgPT0gMCkp
Cj4gPj4+ICsgICAgICAgICAgICAgcmV0dXJuIC1FTk9NRU07Cj4gPj4+ICsKPiA+Pj4gKyAgICAg
bXV0ZXhfbG9jaygmY29vbGluZ19jcHVmcmVxX2xvY2spOwo+ID4+PiArICAgICBlcnIgPSBpZHJf
Z2V0X25ldyhpZHIsIE5VTEwsIGlkKTsKPiA+Pj4gKyAgICAgbXV0ZXhfdW5sb2NrKCZjb29saW5n
X2NwdWZyZXFfbG9jayk7Cj4gPj4+ICsKPiA+Pj4gKyAgICAgaWYgKHVubGlrZWx5KGVyciA9PSAt
RUFHQUlOKSkKPiA+Pj4gKyAgICAgICAgICAgICBnb3RvIGFnYWluOwo+ID4+PiArICAgICBlbHNl
IGlmICh1bmxpa2VseShlcnIpKQo+ID4+PiArICAgICAgICAgICAgIHJldHVybiBlcnI7Cj4gPj4+
ICsKPiA+Pj4gKyAgICAgKmlkID0gKmlkICYgTUFYX0lEX01BU0s7Cj4gPj4+ICsgICAgIHJldHVy
biAwOwo+ID4+PiArfQo+ID4+PiArCj4gPj4+ICsvKioKPiA+Pj4gKyAqIHJlbGVhc2VfaWRyIC0g
ZnVuY3Rpb24gdG8gZnJlZSB0aGUgdW5pcXVlIGlkLgo+ID4+PiArICogQGlkcjogc3RydWN0IGlk
ciAqIGhhbmRsZSB1c2VkIGZvciBjcmVhdGluZyB0aGUgaWQuCj4gPj4+ICsgKiBAaWQ6IGludCB2
YWx1ZSByZXByZXNlbnRpbmcgdGhlIHVuaXF1ZSBpZC4KPiA+Pj4gKyAqLwo+ID4+PiArc3RhdGlj
IHZvaWQgcmVsZWFzZV9pZHIoc3RydWN0IGlkciAqaWRyLCBpbnQgaWQpCj4gPj4+ICt7Cj4gPj4+
ICsgICAgIG11dGV4X2xvY2soJmNvb2xpbmdfY3B1ZnJlcV9sb2NrKTsKPiA+Pj4gKyAgICAgaWRy
X3JlbW92ZShpZHIsIGlkKTsKPiA+Pj4gKyAgICAgbXV0ZXhfdW5sb2NrKCZjb29saW5nX2NwdWZy
ZXFfbG9jayk7Cj4gPj4+ICt9Cj4gPj4+ICsKPiA+Pj4gKy8qKgo+ID4+PiArICogY3B1dGhlcm1f
cmVnaXN0ZXJfbm90aWZpZXIgLSBSZWdpc3RlciBhIG5vdGlmaWVyIHdpdGggY3B1IGNvb2xpbmcg
aW50ZXJmYWNlLgo+ID4+PiArICogQG5iOiAgICAgIHN0cnVjdCBub3RpZmllcl9ibG9jayAqIHdp
dGggY2FsbGJhY2sgaW5mby4KPiA+Pj4gKyAqIEBsaXN0OiBpbnRlZ2VyIHZhbHVlIGZvciB3aGlj
aCBub3RpZmljYXRpb24gaXMgbmVlZGVkLiBwb3NzaWJsZSB2YWx1ZXMgYXJlCj4gPj4+ICsgKiAg
IENQVUZSRVFfQ09PTElOR19TVEFSVCBhbmQgQ1BVRlJFUV9DT09MSU5HX1NUT1AuCj4gPj4+ICsg
Kgo+ID4+PiArICogVGhpcyBleHBvcnRlZCBmdW5jdGlvbiByZWdpc3RlcnMgYSBkcml2ZXIgd2l0
aCBjcHUgY29vbGluZyBsYXllci4gVGhlIGRyaXZlcgo+ID4+PiArICogd2lsbCBiZSBub3RpZmll
ZCB3aGVuIGFueSBjcHUgY29vbGluZyBhY3Rpb24gaXMgY2FsbGVkLgo+ID4+PiArICovCj4gPj4+
ICtpbnQgY3B1dGhlcm1fcmVnaXN0ZXJfbm90aWZpZXIoc3RydWN0IG5vdGlmaWVyX2Jsb2NrICpu
YiwgdW5zaWduZWQgaW50IGxpc3QpCj4gPj4+ICt7Cj4gPj4+ICsgICAgIGludCByZXQgPSAwOwo+
ID4+PiArCj4gPj4+ICsgICAgIHN3aXRjaCAobGlzdCkgewo+ID4+PiArICAgICBjYXNlIENQVUZS
RVFfQ09PTElOR19TVEFSVDoKPiA+Pj4gKyAgICAgY2FzZSBDUFVGUkVRX0NPT0xJTkdfU1RPUDoK
PiA+Pj4gKyAgICAgICAgICAgICByZXQgPSBibG9ja2luZ19ub3RpZmllcl9jaGFpbl9yZWdpc3Rl
cigKPiA+Pj4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJmNwdXRoZXJtX3N0YXRlX25v
dGlmaWVyX2xpc3QsIG5iKTsKPiA+Pj4gKyAgICAgICAgICAgICBicmVhazsKPiA+Pj4gKyAgICAg
ZGVmYXVsdDoKPiA+Pj4gKyAgICAgICAgICAgICByZXQgPSAtRUlOVkFMOwo+ID4+PiArICAgICB9
Cj4gPj4+ICsgICAgIHJldHVybiByZXQ7Cj4gPj4+ICt9Cj4gPj4+ICtFWFBPUlRfU1lNQk9MKGNw
dXRoZXJtX3JlZ2lzdGVyX25vdGlmaWVyKTsKPiA+Pj4gKwo+ID4+PiArLyoqCj4gPj4+ICsgKiBj
cHV0aGVybV91bnJlZ2lzdGVyX25vdGlmaWVyIC0gVW4tcmVnaXN0ZXIgYSBub3RpZmllci4KPiA+
Pj4gKyAqIEBuYjogICAgICBzdHJ1Y3Qgbm90aWZpZXJfYmxvY2sgKiB3aXRoIGNhbGxiYWNrIGlu
Zm8uCj4gPj4+ICsgKiBAbGlzdDogaW50ZWdlciB2YWx1ZSBmb3Igd2hpY2ggbm90aWZpY2F0aW9u
IGlzIG5lZWRlZC4gdmFsdWVzIHBvc3NpYmxlIGFyZQo+ID4+PiArICogICBDUFVGUkVRX0NPT0xJ
TkdfU1RBUlQgb3IgQ1BVRlJFUV9DT09MSU5HX1NUT1AuCj4gPj4+ICsgKgo+ID4+PiArICogVGhp
cyBleHBvcnRlZCBmdW5jdGlvbiB1bi1yZWdpc3RlcnMgYSBkcml2ZXIgd2l0aCBjcHUgY29vbGlu
ZyBsYXllci4KPiA+Pj4gKyAqLwo+ID4+PiAraW50IGNwdXRoZXJtX3VucmVnaXN0ZXJfbm90aWZp
ZXIoc3RydWN0IG5vdGlmaWVyX2Jsb2NrICpuYiwgdW5zaWduZWQgaW50IGxpc3QpCj4gPj4+ICt7
Cj4gPj4+ICsgICAgIGludCByZXQgPSAwOwo+ID4+PiArCj4gPj4+ICsgICAgIHN3aXRjaCAobGlz
dCkgewo+ID4+PiArICAgICBjYXNlIENQVUZSRVFfQ09PTElOR19TVEFSVDoKPiA+Pj4gKyAgICAg
Y2FzZSBDUFVGUkVRX0NPT0xJTkdfU1RPUDoKPiA+Pj4gKyAgICAgICAgICAgICByZXQgPSBibG9j
a2luZ19ub3RpZmllcl9jaGFpbl91bnJlZ2lzdGVyKAo+ID4+PiArICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAmY3B1dGhlcm1fc3RhdGVfbm90aWZpZXJfbGlzdCwgbmIpOwo+ID4+PiArICAg
ICAgICAgICAgIGJyZWFrOwo+ID4+PiArICAgICBkZWZhdWx0Ogo+ID4+PiArICAgICAgICAgICAg
IHJldCA9IC1FSU5WQUw7Cj4gPj4+ICsgICAgIH0KPiA+Pj4gKyAgICAgcmV0dXJuIHJldDsKPiA+
Pj4gK30KPiA+Pj4gK0VYUE9SVF9TWU1CT0woY3B1dGhlcm1fdW5yZWdpc3Rlcl9ub3RpZmllcik7
Cj4gPj4+ICsKPiA+Pj4gKy8qIEJlbG93IGNvZGUgZGVmaW5lcyBmdW5jdGlvbnMgdG8gYmUgdXNl
ZCBmb3IgY3B1ZnJlcSBhcyBjb29saW5nIGRldmljZSAqLwo+ID4+PiArCj4gPj4+ICsvKioKPiA+
Pj4gKyAqIGlzX2NwdWZyZXFfdmFsaWQgLSBmdW5jdGlvbiB0byBjaGVjayBpZiBhIGNwdSBoYXMg
ZnJlcXVlbmN5IHRyYW5zaXRpb24gcG9saWN5Lgo+ID4+PiArICogQGNwdTogY3B1IGZvciB3aGlj
aCBjaGVjayBpcyBuZWVkZWQuCj4gPj4+ICsgKi8KPiA+Pj4gK3N0YXRpYyBpbnQgaXNfY3B1ZnJl
cV92YWxpZChpbnQgY3B1KQo+ID4+PiArewo+ID4+PiArICAgICBzdHJ1Y3QgY3B1ZnJlcV9wb2xp
Y3kgcG9saWN5Owo+ID4+PiArICAgICByZXR1cm4gIWNwdWZyZXFfZ2V0X3BvbGljeSgmcG9saWN5
LCBjcHUpOwo+ID4+PiArfQo+ID4+PiArCj4gPj4+ICsvKioKPiA+Pj4gKyAqIGdldF9jcHVfZnJl
cXVlbmN5IC0gZ2V0IHRoZSBhYnNvbHV0ZSB2YWx1ZSBvZiBmcmVxdWVuY3kgZnJvbSBsZXZlbC4K
PiA+Pj4gKyAqIEBjcHU6IGNwdSBmb3Igd2hpY2ggZnJlcXVlbmN5IGlzIGZldGNoZWQuCj4gPj4+
ICsgKiBAbGV2ZWw6IGxldmVsIG9mIGZyZXF1ZW5jeSBvZiB0aGUgQ1BVCj4gPj4+ICsgKiAgIGUu
ZyBsZXZlbD0xIC0tPiAxc3QgTUFYIEZSRVEsIExFVkVMPTIgLS0tPiAybmQgTUFYIEZSRVEsIC4u
Li4gZXRjCj4gPj4+ICsgKi8KPiA+Pj4gK3N0YXRpYyB1bnNpZ25lZCBpbnQgZ2V0X2NwdV9mcmVx
dWVuY3kodW5zaWduZWQgaW50IGNwdSwgdW5zaWduZWQgbG9uZyBsZXZlbCkKPiA+Pj4gK3sKPiA+
Pj4gKyAgICAgaW50IHJldCA9IDAsIGkgPSAwOwo+ID4+PiArICAgICB1bnNpZ25lZCBsb25nIGxl
dmVsX2luZGV4Owo+ID4+PiArICAgICBib29sIGRlc2NlbmQgPSBmYWxzZTsKPiA+Pj4gKyAgICAg
c3RydWN0IGNwdWZyZXFfZnJlcXVlbmN5X3RhYmxlICp0YWJsZSA9Cj4gPj4+ICsgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgY3B1ZnJlcV9mcmVxdWVuY3lfZ2V0X3RhYmxlKGNw
dSk7Cj4gPj4+ICsgICAgIGlmICghdGFibGUpCj4gPj4+ICsgICAgICAgICAgICAgcmV0dXJuIHJl
dDsKPiA+Pj4gKwo+ID4+PiArICAgICB3aGlsZSAodGFibGVbaV0uZnJlcXVlbmN5ICE9IENQVUZS
RVFfVEFCTEVfRU5EKSB7Cj4gPj4+ICsgICAgICAgICAgICAgaWYgKHRhYmxlW2ldLmZyZXF1ZW5j
eSA9PSBDUFVGUkVRX0VOVFJZX0lOVkFMSUQpCj4gPj4+ICsgICAgICAgICAgICAgICAgICAgICBj
b250aW51ZTsKPiA+Pj4gKwo+ID4+PiArICAgICAgICAgICAgIC8qY2hlY2sgaWYgdGFibGUgaW4g
YXNjZW5kaW5nIG9yIGRlc2NlbmRpbmcgb3JkZXIqLwo+ID4+PiArICAgICAgICAgICAgIGlmICgo
dGFibGVbaSArIDFdLmZyZXF1ZW5jeSAhPSBDUFVGUkVRX1RBQkxFX0VORCkgJiYKPiA+Pj4gKyAg
ICAgICAgICAgICAgICAgICAgICh0YWJsZVtpICsgMV0uZnJlcXVlbmN5IDwgdGFibGVbaV0uZnJl
cXVlbmN5KQo+ID4+PiArICAgICAgICAgICAgICAgICAgICAgJiYgIWRlc2NlbmQpIHsKPiA+Pj4g
KyAgICAgICAgICAgICAgICAgICAgIGRlc2NlbmQgPSB0cnVlOwo+ID4+PiArICAgICAgICAgICAg
IH0KPiA+Pj4gKwo+ID4+PiArICAgICAgICAgICAgIC8qcmV0dXJuIGlmIGxldmVsIG1hdGNoZWQg
YW5kIHRhYmxlIGluIGRlc2NlbmRpbmcgb3JkZXIqLwo+ID4+PiArICAgICAgICAgICAgIGlmIChk
ZXNjZW5kICYmIGkgPT0gbGV2ZWwpCj4gPj4+ICsgICAgICAgICAgICAgICAgICAgICByZXR1cm4g
dGFibGVbaV0uZnJlcXVlbmN5Owo+ID4+PiArICAgICAgICAgICAgIGkrKzsKPiA+Pj4gKyAgICAg
fQo+ID4+PiArICAgICBpLS07Cj4gPj4+ICsKPiA+Pj4gKyAgICAgaWYgKGxldmVsID4gaSB8fCBk
ZXNjZW5kKQo+ID4+PiArICAgICAgICAgICAgIHJldHVybiByZXQ7Cj4gPj4+ICsgICAgIGxldmVs
X2luZGV4ID0gaSAtIGxldmVsOwo+ID4+PiArCj4gPj4+ICsgICAgIC8qU2NhbiB0aGUgdGFibGUg
aW4gcmV2ZXJzZSBvcmRlciBhbmQgbWF0Y2ggdGhlIGxldmVsKi8KPiA+Pj4gKyAgICAgd2hpbGUg
KGkgPj0gMCkgewo+ID4+PiArICAgICAgICAgICAgIGlmICh0YWJsZVtpXS5mcmVxdWVuY3kgPT0g
Q1BVRlJFUV9FTlRSWV9JTlZBTElEKQo+ID4+PiArICAgICAgICAgICAgICAgICAgICAgY29udGlu
dWU7Cj4gPj4+ICsgICAgICAgICAgICAgLypyZXR1cm4gaWYgbGV2ZWwgbWF0Y2hlZCovCj4gPj4+
ICsgICAgICAgICAgICAgaWYgKGkgPT0gbGV2ZWxfaW5kZXgpCj4gPj4+ICsgICAgICAgICAgICAg
ICAgICAgICByZXR1cm4gdGFibGVbaV0uZnJlcXVlbmN5Owo+ID4+PiArICAgICAgICAgICAgIGkt
LTsKPiA+Pj4gKyAgICAgfQo+ID4+PiArICAgICByZXR1cm4gcmV0Owo+ID4+PiArfQo+ID4+PiAr
Cj4gPj4+ICsvKioKPiA+Pj4gKyAqIGNwdWZyZXFfYXBwbHlfY29vbGluZyAtIGZ1bmN0aW9uIHRv
IGFwcGx5IGZyZXF1ZW5jeSBjbGlwcGluZy4KPiA+Pj4gKyAqIEBjcHVmcmVxX2RldmljZTogY3B1
ZnJlcV9jb29saW5nX2RldmljZSBwb2ludGVyIGNvbnRhaW5pbmcgZnJlcXVlbmN5Cj4gPj4+ICsg
KiAgIGNsaXBwaW5nIGRhdGEuCj4gPj4+ICsgKiBAY29vbGluZ19zdGF0ZTogdmFsdWUgb2YgdGhl
IGNvb2xpbmcgc3RhdGUuCj4gPj4+ICsgKi8KPiA+Pj4gK3N0YXRpYyBpbnQgY3B1ZnJlcV9hcHBs
eV9jb29saW5nKHN0cnVjdCBjcHVmcmVxX2Nvb2xpbmdfZGV2aWNlICpjcHVmcmVxX2RldmljZSwK
PiA+Pj4gKyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5zaWduZWQgbG9uZyBjb29saW5n
X3N0YXRlKQo+ID4+PiArewo+ID4+PiArICAgICB1bnNpZ25lZCBpbnQgZXZlbnQsIGNwdWlkLCBj
bGlwX2ZyZXE7Cj4gPj4+ICsgICAgIHN0cnVjdCBjcHVtYXNrICptYXNrUHRyID0gJmNwdWZyZXFf
ZGV2aWNlLT5hbGxvd2VkX2NwdXM7Cj4gPj4+ICsgICAgIHVuc2lnbmVkIGludCBjcHUgPSBjcHVt
YXNrX2FueShtYXNrUHRyKTsKPiA+Pj4gKwo+ID4+PiArCj4gPj4+ICsgICAgIC8qIENoZWNrIGlm
IHRoZSBvbGQgY29vbGluZyBhY3Rpb24gaXMgc2FtZSBhcyBuZXcgY29vbGluZyBhY3Rpb24gKi8K
PiA+Pj4gKyAgICAgaWYgKGNwdWZyZXFfZGV2aWNlLT5jcHVmcmVxX3N0YXRlID09IGNvb2xpbmdf
c3RhdGUpCj4gPj4+ICsgICAgICAgICAgICAgcmV0dXJuIDA7Cj4gPj4+ICsKPiA+Pj4gKyAgICAg
Y2xpcF9mcmVxID0gZ2V0X2NwdV9mcmVxdWVuY3koY3B1LCBjb29saW5nX3N0YXRlKTsKPiA+Pj4g
KyAgICAgaWYgKCFjbGlwX2ZyZXEpCj4gPj4+ICsgICAgICAgICAgICAgcmV0dXJuIC1FSU5WQUw7
Cj4gPj4+ICsKPiA+Pj4gKyAgICAgY3B1ZnJlcV9kZXZpY2UtPmNwdWZyZXFfc3RhdGUgPSBjb29s
aW5nX3N0YXRlOwo+ID4+PiArICAgICBjcHVmcmVxX2RldmljZS0+Y3B1ZnJlcV92YWwgPSBjbGlw
X2ZyZXE7Cj4gPj4+ICsgICAgIG5vdGlmeV9kZXZpY2UgPSBjcHVmcmVxX2RldmljZTsKPiA+Pj4g
Kwo+ID4+PiArICAgICBpZiAoY29vbGluZ19zdGF0ZSAhPSAwKQo+ID4+PiArICAgICAgICAgICAg
IGV2ZW50ID0gQ1BVRlJFUV9DT09MSU5HX1NUQVJUOwo+ID4+PiArICAgICBlbHNlCj4gPj4+ICsg
ICAgICAgICAgICAgZXZlbnQgPSBDUFVGUkVRX0NPT0xJTkdfU1RPUDsKPiA+Pj4gKwo+ID4+PiAr
ICAgICBibG9ja2luZ19ub3RpZmllcl9jYWxsX2NoYWluKCZjcHV0aGVybV9zdGF0ZV9ub3RpZmll
cl9saXN0LAo+ID4+PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgZXZlbnQsICZjbGlwX2ZyZXEpOwo+ID4+PiArCj4gPj4+ICsgICAgIGZvcl9lYWNoX2NwdShj
cHVpZCwgbWFza1B0cikgewo+ID4+PiArICAgICAgICAgICAgIGlmIChpc19jcHVmcmVxX3ZhbGlk
KGNwdWlkKSkKPiA+Pj4gKyAgICAgICAgICAgICAgICAgICAgIGNwdWZyZXFfdXBkYXRlX3BvbGlj
eShjcHVpZCk7Cj4gPj4+ICsgICAgIH0KPiA+Pj4gKwo+ID4+PiArICAgICBub3RpZnlfZGV2aWNl
ID0gTk9USUZZX0lOVkFMSUQ7Cj4gPj4+ICsKPiA+Pj4gKyAgICAgcmV0dXJuIDA7Cj4gPj4+ICt9
Cj4gPj4+ICsKPiA+Pj4gKy8qKgo+ID4+PiArICogY3B1ZnJlcV90aGVybWFsX25vdGlmaWVyIC0g
bm90aWZpZXIgY2FsbGJhY2sgZm9yIGNwdWZyZXEgcG9saWN5IGNoYW5nZS4KPiA+Pj4gKyAqIEBu
YjogICAgICBzdHJ1Y3Qgbm90aWZpZXJfYmxvY2sgKiB3aXRoIGNhbGxiYWNrIGluZm8uCj4gPj4+
ICsgKiBAZXZlbnQ6IHZhbHVlIHNob3dpbmcgY3B1ZnJlcSBldmVudCBmb3Igd2hpY2ggdGhpcyBm
dW5jdGlvbiBpbnZva2VkLgo+ID4+PiArICogQGRhdGE6IGNhbGxiYWNrLXNwZWNpZmljIGRhdGEK
PiA+Pj4gKyAqLwo+ID4+PiArc3RhdGljIGludCBjcHVmcmVxX3RoZXJtYWxfbm90aWZpZXIoc3Ry
dWN0IG5vdGlmaWVyX2Jsb2NrICpuYiwKPiA+Pj4gKyAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICB1bnNpZ25lZCBsb25nIGV2ZW50LCB2b2lkICpkYXRhKQo+ID4+PiArewo+ID4+
PiArICAgICBzdHJ1Y3QgY3B1ZnJlcV9wb2xpY3kgKnBvbGljeSA9IGRhdGE7Cj4gPj4+ICsgICAg
IHVuc2lnbmVkIGxvbmcgbWF4X2ZyZXEgPSAwOwo+ID4+PiArCj4gPj4+ICsgICAgIGlmIChldmVu
dCAhPSBDUFVGUkVRX0FESlVTVCB8fCBub3RpZnlfZGV2aWNlID09IE5PVElGWV9JTlZBTElEKQo+
ID4+PiArICAgICAgICAgICAgIHJldHVybiAwOwo+ID4+PiArCj4gPj4+ICsgICAgIGlmIChjcHVt
YXNrX3Rlc3RfY3B1KHBvbGljeS0+Y3B1LCAmbm90aWZ5X2RldmljZS0+YWxsb3dlZF9jcHVzKSkK
PiA+Pj4gKyAgICAgICAgICAgICBtYXhfZnJlcSA9IG5vdGlmeV9kZXZpY2UtPmNwdWZyZXFfdmFs
Owo+ID4+PiArCj4gPj4+ICsgICAgIC8qIE5ldmVyIGV4Y2VlZCB1c2VyX3BvbGljeS5tYXgqLwo+
ID4+PiArICAgICBpZiAobWF4X2ZyZXEgPiBwb2xpY3ktPnVzZXJfcG9saWN5Lm1heCkKPiA+Pj4g
KyAgICAgICAgICAgICBtYXhfZnJlcSA9IHBvbGljeS0+dXNlcl9wb2xpY3kubWF4Owo+ID4+PiAr
Cj4gPj4+ICsgICAgIGlmIChwb2xpY3ktPm1heCAhPSBtYXhfZnJlcSkKPiA+Pj4gKyAgICAgICAg
ICAgICBjcHVmcmVxX3ZlcmlmeV93aXRoaW5fbGltaXRzKHBvbGljeSwgMCwgbWF4X2ZyZXEpOwo+
ID4+PiArCj4gPj4+ICsgICAgIHJldHVybiAwOwo+ID4+PiArfQo+ID4+PiArCj4gPj4+ICsvKgo+
ID4+PiArICogY3B1ZnJlcSBjb29saW5nIGRldmljZSBjYWxsYmFjayBmdW5jdGlvbnMgYXJlIGRl
ZmluZWQgYmVsb3cKPiA+Pj4gKyAqLwo+ID4+PiArCj4gPj4+ICsvKioKPiA+Pj4gKyAqIGNwdWZy
ZXFfZ2V0X21heF9zdGF0ZSAtIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGdldCB0aGUgbWF4IGNvb2xp
bmcgc3RhdGUuCj4gPj4+ICsgKiBAY2RldjogdGhlcm1hbCBjb29saW5nIGRldmljZSBwb2ludGVy
Lgo+ID4+PiArICogQHN0YXRlOiBmaWxsIHRoaXMgdmFyaWFibGUgd2l0aCB0aGUgbWF4IGNvb2xp
bmcgc3RhdGUuCj4gPj4+ICsgKi8KPiA+Pj4gK3N0YXRpYyBpbnQgY3B1ZnJlcV9nZXRfbWF4X3N0
YXRlKHN0cnVjdCB0aGVybWFsX2Nvb2xpbmdfZGV2aWNlICpjZGV2LAo+ID4+PiArICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgdW5zaWduZWQgbG9uZyAqc3RhdGUpCj4gPj4+ICt7Cj4gPj4+
ICsgICAgIGludCByZXQgPSAtRUlOVkFMLCBpID0gMDsKPiA+Pj4gKyAgICAgc3RydWN0IGNwdWZy
ZXFfY29vbGluZ19kZXZpY2UgKmNwdWZyZXFfZGV2aWNlOwo+ID4+PiArICAgICBzdHJ1Y3QgY3B1
bWFzayAqbWFza1B0cjsKPiA+Pj4gKyAgICAgdW5zaWduZWQgaW50IGNwdTsKPiA+Pj4gKyAgICAg
c3RydWN0IGNwdWZyZXFfZnJlcXVlbmN5X3RhYmxlICp0YWJsZTsKPiA+Pj4gKwo+ID4+PiArICAg
ICBtdXRleF9sb2NrKCZjb29saW5nX2NwdWZyZXFfbG9jayk7Cj4gPj4+ICsgICAgIGxpc3RfZm9y
X2VhY2hfZW50cnkoY3B1ZnJlcV9kZXZpY2UsICZjb29saW5nX2NwdWZyZXFfbGlzdCwgbm9kZSkg
ewo+ID4+PiArICAgICAgICAgICAgIGlmIChjcHVmcmVxX2RldmljZSAmJiBjcHVmcmVxX2Rldmlj
ZS0+Y29vbF9kZXYgPT0gY2RldikKPiA+Pj4gKyAgICAgICAgICAgICAgICAgICAgIGJyZWFrOwo+
ID4+PiArICAgICB9Cj4gPj4+ICsgICAgIGlmIChjcHVmcmVxX2RldmljZSA9PSBOVUxMKQo+ID4+
PiArICAgICAgICAgICAgIGdvdG8gcmV0dXJuX2dldF9tYXhfc3RhdGU7Cj4gPj4+ICsKPiA+Pj4g
KyAgICAgbWFza1B0ciA9ICZjcHVmcmVxX2RldmljZS0+YWxsb3dlZF9jcHVzOwo+ID4+PiArICAg
ICBjcHUgPSBjcHVtYXNrX2FueShtYXNrUHRyKTsKPiA+Pj4gKyAgICAgdGFibGUgPSBjcHVmcmVx
X2ZyZXF1ZW5jeV9nZXRfdGFibGUoY3B1KTsKPiA+Pj4gKyAgICAgaWYgKCF0YWJsZSkgewo+ID4+
PiArICAgICAgICAgICAgICpzdGF0ZSA9IDA7Cj4gPj4+ICsgICAgICAgICAgICAgcmV0ID0gMDsK
PiA+Pj4gKyAgICAgICAgICAgICBnb3RvIHJldHVybl9nZXRfbWF4X3N0YXRlOwo+ID4+PiArICAg
ICB9Cj4gPj4+ICsKPiA+Pj4gKyAgICAgd2hpbGUgKHRhYmxlW2ldLmZyZXF1ZW5jeSAhPSBDUFVG
UkVRX1RBQkxFX0VORCkgewo+ID4+PiArICAgICAgICAgICAgIGlmICh0YWJsZVtpXS5mcmVxdWVu
Y3kgPT0gQ1BVRlJFUV9FTlRSWV9JTlZBTElEKQo+ID4+PiArICAgICAgICAgICAgICAgICAgICAg
Y29udGludWU7Cj4gPj4+ICsgICAgICAgICAgICAgaSsrOwo+ID4+PiArICAgICB9Cj4gPj4+ICsg
ICAgIGlmIChpID4gMCkgewo+ID4+PiArICAgICAgICAgICAgICpzdGF0ZSA9IC0taTsKPiA+Pj4g
KyAgICAgICAgICAgICByZXQgPSAwOwo+ID4+PiArICAgICB9Cj4gPj4+ICsKPiA+Pj4gK3JldHVy
bl9nZXRfbWF4X3N0YXRlOgo+ID4+PiArICAgICBtdXRleF91bmxvY2soJmNvb2xpbmdfY3B1ZnJl
cV9sb2NrKTsKPiA+Pj4gKyAgICAgcmV0dXJuIHJldDsKPiA+Pj4gK30KPiA+Pj4gKwo+ID4+PiAr
LyoqCj4gPj4+ICsgKiBjcHVmcmVxX2dldF9jdXJfc3RhdGUgLSBjYWxsYmFjayBmdW5jdGlvbiB0
byBnZXQgdGhlIGN1cnJlbnQgY29vbGluZyBzdGF0ZS4KPiA+Pj4gKyAqIEBjZGV2OiB0aGVybWFs
IGNvb2xpbmcgZGV2aWNlIHBvaW50ZXIuCj4gPj4+ICsgKiBAc3RhdGU6IGZpbGwgdGhpcyB2YXJp
YWJsZSB3aXRoIHRoZSBjdXJyZW50IGNvb2xpbmcgc3RhdGUuCj4gPj4+ICsgKi8KPiA+Pj4gK3N0
YXRpYyBpbnQgY3B1ZnJlcV9nZXRfY3VyX3N0YXRlKHN0cnVjdCB0aGVybWFsX2Nvb2xpbmdfZGV2
aWNlICpjZGV2LAo+ID4+PiArICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5zaWduZWQg
bG9uZyAqc3RhdGUpCj4gPj4+ICt7Cj4gPj4+ICsgICAgIGludCByZXQgPSAtRUlOVkFMOwo+ID4+
PiArICAgICBzdHJ1Y3QgY3B1ZnJlcV9jb29saW5nX2RldmljZSAqY3B1ZnJlcV9kZXZpY2U7Cj4g
Pj4+ICsKPiA+Pj4gKyAgICAgbXV0ZXhfbG9jaygmY29vbGluZ19jcHVmcmVxX2xvY2spOwo+ID4+
PiArICAgICBsaXN0X2Zvcl9lYWNoX2VudHJ5KGNwdWZyZXFfZGV2aWNlLCAmY29vbGluZ19jcHVm
cmVxX2xpc3QsIG5vZGUpIHsKPiA+Pj4gKyAgICAgICAgICAgICBpZiAoY3B1ZnJlcV9kZXZpY2Ug
JiYgY3B1ZnJlcV9kZXZpY2UtPmNvb2xfZGV2ID09IGNkZXYpIHsKPiA+Pj4gKyAgICAgICAgICAg
ICAgICAgICAgICpzdGF0ZSA9IGNwdWZyZXFfZGV2aWNlLT5jcHVmcmVxX3N0YXRlOwo+ID4+PiAr
ICAgICAgICAgICAgICAgICAgICAgcmV0ID0gMDsKPiA+Pj4gKyAgICAgICAgICAgICAgICAgICAg
IGJyZWFrOwo+ID4+PiArICAgICAgICAgICAgIH0KPiA+Pj4gKyAgICAgfQo+ID4+PiArICAgICBt
dXRleF91bmxvY2soJmNvb2xpbmdfY3B1ZnJlcV9sb2NrKTsKPiA+Pj4gKwo+ID4+Cj4gPj4gYXMg
Y3B1ZnJlcSBtYXkgYmUgY2hhbmdlZCBpbiBvdGhlciBwbGFjZXMsIGUuZy4gdmlhIHN5c2ZzIEkv
Riwgd2Ugc2hvdWxkCj4gPj4gdXNlIHRoZSBjdXJyZW50IGNwdSBmcmVxdWVuY3kgdG8gZ2V0IHRo
ZSBSRUFMIGNvb2xpbmcgc3RhdGUsIHJhdGhlciB0aGFuCj4gPj4gdXNpbmcgYSBjYWNoZWQgdmFs
dWUuCj4gPgo+ID4gWWVzIGFncmVlZCAsIEkgd2lsbCByZXBvc3Qgd2l0aCB5b3VyIHN1Z2dlc3Rp
b24uCj4gPgo+ID4gVGhhbmtzLAo+ID4gQW1pdAo+ID4+Cj4gPj4gdGhhbmtzLAo+ID4+IHJ1aQo+
ID4+Cj4gPj4KPiA+IC0tCj4gPiBUbyB1bnN1YnNjcmliZSBmcm9tIHRoaXMgbGlzdDogc2VuZCB0
aGUgbGluZSAidW5zdWJzY3JpYmUgbGludXgtYWNwaSIgaW4KPiA+IHRoZSBib2R5IG9mIGEgbWVz
c2FnZSB0byBtYWpvcmRvbW9Admdlci5rZXJuZWwub3JnCj4gPiBNb3JlIG1ham9yZG9tbyBpbmZv
IGF0ICBodHRwOi8vdmdlci5rZXJuZWwub3JnL21ham9yZG9tby1pbmZvLmh0bWwKPiAKPiAKPiAK
CgoKX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18KbG0tc2Vu
c29ycyBtYWlsaW5nIGxpc3QKbG0tc2Vuc29yc0BsbS1zZW5zb3JzLm9yZwpodHRwOi8vbGlzdHMu
bG0tc2Vuc29ycy5vcmcvbWFpbG1hbi9saXN0aW5mby9sbS1zZW5zb3Jz

WARNING: multiple messages have this Message-ID (diff)
From: Zhang Rui <rui.zhang@intel.com>
To: "Valentin, Eduardo" <eduardo.valentin@ti.com>
Cc: Amit Kachhap <amit.kachhap@linaro.org>,
	linux-pm@lists.linux-foundation.org,
	Andrew Morton <akpm@linux-foundation.org>,
	Len Brown <lenb@kernel.org>,
	linux-samsung-soc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-acpi@vger.kernel.org, lm-sensors@lm-sensors.org,
	Guenter Roeck <guenter.roeck@ericsson.com>,
	SangWook Ju <sw.ju@samsung.com>,
	Durgadoss <durgadoss.r@intel.com>,
	Jean Delvare <khali@linux-fr.org>,
	Kyungmin Park <kmpark@infradead.org>,
	Kukjin Kim <kgene.kim@samsung.com>
Subject: Re: [PATCH v6 1/6] thermal: add generic cpufreq cooling implementation
Date: Mon, 20 Aug 2012 10:16:03 +0800	[thread overview]
Message-ID: <1345428963.1682.899.camel@rui.sh.intel.com> (raw)
In-Reply-To: <CAGF5oy_uhgbzTQeXPyJP51JXxbszX1cL+B=V0mzfRt7bcSi_sQ@mail.gmail.com>

On 五, 2012-08-17 at 11:56 +0300, Valentin, Eduardo wrote:
> Hello,

> >>> +
> >>> +
> >>> +1.2 CPU cooling action notifier register/unregister interface
> >>> +1.2.1 int cputherm_register_notifier(struct notifier_block *nb,
> >>> +     unsigned int list)
> >>> +
> >>> +    This interface registers a driver with cpu cooling layer. The driver will
> >>> +    be notified when any cpu cooling action is called.
> >>> +
> >>> +    nb: notifier function to register
> >>> +    list: CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP
> >>> +
> >>> +1.2.2 int cputherm_unregister_notifier(struct notifier_block *nb,
> >>> +     unsigned int list)
> >>> +
> >>> +    This interface registers a driver with cpu cooling layer. The driver will
> >>> +    be notified when any cpu cooling action is called.
> >>> +
> >>> +    nb: notifier function to register
> >>> +    list: CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP
> >>
> >> what are these two APIs used for?
> >> I did not see they are used in your patch set, do I miss something?
> > No currently they are not used by my patches. I added them on request
> > from Eduardo and others
> 
> Yeah, this was a suggestion as we didn't really know how the FW part
> would evolve by that time.
> 
> The reasoning is to allow any interested user (in kernel) to be
> notified when max frequency changes.

in this case, the cooling device should be updated.
Say all the target of the thermal_instances of a cooling devices is 0,
which means they want the cpu to run at maximum frequency, when the max
frequency changes, we should set the processor to the new max frequency
as well.
Using notification is not a good idea as user can not handle this
without interacting with the thermal framework.

IMO, we should introduce a new API to handle this, rather than just
notifications to users.

>  Actually, the use case behind
> this is to allow such users to perform some handshaking or stop their
> activities or even change some paramenters, in case the max frequency
> would change.

It is the cooling device driver that notice this change first, and it
should invoke something like thermal_cooling_device_update/rebind() to
tell the thermal framework this change.

>  Ideally it would be possible to nack the cooling
> transition. But that is yet a wider discussion. So far we don't have
> users for this.
> 
yep.
I thought about this before, but I'd prefer to do this when there is a
real user. Or else, we are kind of over-designing here.
how about removing this piece of code for now?

thanks,
rui

> >>
> >>> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> >>> index 7dd8c34..996003b 100644
> >>> --- a/drivers/thermal/Kconfig
> >>> +++ b/drivers/thermal/Kconfig
> >>> @@ -19,6 +19,17 @@ config THERMAL_HWMON
> >>>       depends on HWMON=y || HWMON=THERMAL
> >>>       default y
> >>>
> >>> +config CPU_THERMAL
> >>> +     bool "generic cpu cooling support"
> >>> +     depends on THERMAL && CPU_FREQ
> >>> +     help
> >>> +       This implements the generic cpu cooling mechanism through frequency
> >>> +       reduction, cpu hotplug and any other ways of reducing temperature. 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.
> >>> +
> >>>  config SPEAR_THERMAL
> >>>       bool "SPEAr thermal sensor driver"
> >>>       depends on THERMAL
> >>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> >>> index fd9369a..aae59ad 100644
> >>> --- a/drivers/thermal/Makefile
> >>> +++ b/drivers/thermal/Makefile
> >>> @@ -3,5 +3,6 @@
> >>>  #
> >>>
> >>>  obj-$(CONFIG_THERMAL)                += thermal_sys.o
> >>> +obj-$(CONFIG_CPU_THERMAL)            += cpu_cooling.o
> >>>  obj-$(CONFIG_SPEAR_THERMAL)          += spear_thermal.o
> >>>  obj-$(CONFIG_RCAR_THERMAL)   += rcar_thermal.o
> >>> diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
> >>> new file mode 100644
> >>> index 0000000..c42e557
> >>> --- /dev/null
> >>> +++ b/drivers/thermal/cpu_cooling.c
> >>> @@ -0,0 +1,512 @@
> >>> +/*
> >>> + *  linux/drivers/thermal/cpu_cooling.c
> >>> + *
> >>> + *  Copyright (C) 2012       Samsung Electronics Co., Ltd(http://www.samsung.com)
> >>> + *  Copyright (C) 2012  Amit Daniel <amit.kachhap@linaro.org>
> >>> + *
> >>> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >>> + *  This program is free software; you can redistribute it and/or modify
> >>> + *  it under the terms of the GNU General Public License as published by
> >>> + *  the Free Software Foundation; version 2 of the License.
> >>> + *
> >>> + *  This program is distributed in the hope that it will be useful, but
> >>> + *  WITHOUT ANY WARRANTY; without even the implied warranty of
> >>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> >>> + *  General Public License for more details.
> >>> + *
> >>> + *  You should have received a copy of the GNU General Public License along
> >>> + *  with this program; if not, write to the Free Software Foundation, Inc.,
> >>> + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> >>> + *
> >>> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> >>> + */
> >>> +#include <linux/kernel.h>
> >>> +#include <linux/module.h>
> >>> +#include <linux/thermal.h>
> >>> +#include <linux/platform_device.h>
> >>> +#include <linux/cpufreq.h>
> >>> +#include <linux/err.h>
> >>> +#include <linux/slab.h>
> >>> +#include <linux/cpu.h>
> >>> +#include <linux/cpu_cooling.h>
> >>> +
> >>> +/**
> >>> + * struct cpufreq_cooling_device
> >>> + * @id: unique integer value corresponding to each cpufreq_cooling_device
> >>> + *   registered.
> >>> + * @cool_dev: thermal_cooling_device pointer to keep track of the the
> >>> + *   egistered cooling device.
> >>> + * @cpufreq_state: integer value representing the current state of cpufreq
> >>> + *   cooling devices.
> >>> + * @cpufreq_val: integer value representing the absolute value of the clipped
> >>> + *   frequency.
> >>> + * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device.
> >>> + * @node: list_head to link all cpufreq_cooling_device together.
> >>> + *
> >>> + * This structure is required for keeping information of each
> >>> + * cpufreq_cooling_device registered as a list whose head is represented by
> >>> + * cooling_cpufreq_list. In order to prevent corruption of this list a
> >>> + * mutex lock cooling_cpufreq_lock is used.
> >>> + */
> >>> +struct cpufreq_cooling_device {
> >>> +     int id;
> >>> +     struct thermal_cooling_device *cool_dev;
> >>> +     unsigned int cpufreq_state;
> >>> +     unsigned int cpufreq_val;
> >>> +     struct cpumask allowed_cpus;
> >>> +     struct list_head node;
> >>> +};
> >>> +static LIST_HEAD(cooling_cpufreq_list);
> >>> +static DEFINE_IDR(cpufreq_idr);
> >>> +
> >>> +static struct mutex cooling_cpufreq_lock;
> >>> +
> >>> +/* notify_table passes value to the CPUFREQ_ADJUST callback function. */
> >>> +#define NOTIFY_INVALID NULL
> >>> +struct cpufreq_cooling_device *notify_device;
> >>> +
> >>> +/* Head of the blocking notifier chain to inform about frequency clamping */
> >>> +static BLOCKING_NOTIFIER_HEAD(cputherm_state_notifier_list);
> >>> +
> >>> +/**
> >>> + * get_idr - function to get a unique id.
> >>> + * @idr: struct idr * handle used to create a id.
> >>> + * @id: int * value generated by this function.
> >>> + */
> >>> +static int get_idr(struct idr *idr, int *id)
> >>> +{
> >>> +     int err;
> >>> +again:
> >>> +     if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
> >>> +             return -ENOMEM;
> >>> +
> >>> +     mutex_lock(&cooling_cpufreq_lock);
> >>> +     err = idr_get_new(idr, NULL, id);
> >>> +     mutex_unlock(&cooling_cpufreq_lock);
> >>> +
> >>> +     if (unlikely(err == -EAGAIN))
> >>> +             goto again;
> >>> +     else if (unlikely(err))
> >>> +             return err;
> >>> +
> >>> +     *id = *id & MAX_ID_MASK;
> >>> +     return 0;
> >>> +}
> >>> +
> >>> +/**
> >>> + * release_idr - function to free the unique id.
> >>> + * @idr: struct idr * handle used for creating the id.
> >>> + * @id: int value representing the unique id.
> >>> + */
> >>> +static void release_idr(struct idr *idr, int id)
> >>> +{
> >>> +     mutex_lock(&cooling_cpufreq_lock);
> >>> +     idr_remove(idr, id);
> >>> +     mutex_unlock(&cooling_cpufreq_lock);
> >>> +}
> >>> +
> >>> +/**
> >>> + * cputherm_register_notifier - Register a notifier with cpu cooling interface.
> >>> + * @nb:      struct notifier_block * with callback info.
> >>> + * @list: integer value for which notification is needed. possible values are
> >>> + *   CPUFREQ_COOLING_START and CPUFREQ_COOLING_STOP.
> >>> + *
> >>> + * This exported function registers a driver with cpu cooling layer. The driver
> >>> + * will be notified when any cpu cooling action is called.
> >>> + */
> >>> +int cputherm_register_notifier(struct notifier_block *nb, unsigned int list)
> >>> +{
> >>> +     int ret = 0;
> >>> +
> >>> +     switch (list) {
> >>> +     case CPUFREQ_COOLING_START:
> >>> +     case CPUFREQ_COOLING_STOP:
> >>> +             ret = blocking_notifier_chain_register(
> >>> +                             &cputherm_state_notifier_list, nb);
> >>> +             break;
> >>> +     default:
> >>> +             ret = -EINVAL;
> >>> +     }
> >>> +     return ret;
> >>> +}
> >>> +EXPORT_SYMBOL(cputherm_register_notifier);
> >>> +
> >>> +/**
> >>> + * cputherm_unregister_notifier - Un-register a notifier.
> >>> + * @nb:      struct notifier_block * with callback info.
> >>> + * @list: integer value for which notification is needed. values possible are
> >>> + *   CPUFREQ_COOLING_START or CPUFREQ_COOLING_STOP.
> >>> + *
> >>> + * This exported function un-registers a driver with cpu cooling layer.
> >>> + */
> >>> +int cputherm_unregister_notifier(struct notifier_block *nb, unsigned int list)
> >>> +{
> >>> +     int ret = 0;
> >>> +
> >>> +     switch (list) {
> >>> +     case CPUFREQ_COOLING_START:
> >>> +     case CPUFREQ_COOLING_STOP:
> >>> +             ret = blocking_notifier_chain_unregister(
> >>> +                             &cputherm_state_notifier_list, nb);
> >>> +             break;
> >>> +     default:
> >>> +             ret = -EINVAL;
> >>> +     }
> >>> +     return ret;
> >>> +}
> >>> +EXPORT_SYMBOL(cputherm_unregister_notifier);
> >>> +
> >>> +/* Below code defines functions to be used for cpufreq as cooling device */
> >>> +
> >>> +/**
> >>> + * is_cpufreq_valid - function to check if a cpu has frequency transition policy.
> >>> + * @cpu: cpu for which check is needed.
> >>> + */
> >>> +static int is_cpufreq_valid(int cpu)
> >>> +{
> >>> +     struct cpufreq_policy policy;
> >>> +     return !cpufreq_get_policy(&policy, cpu);
> >>> +}
> >>> +
> >>> +/**
> >>> + * get_cpu_frequency - get the absolute value of frequency from level.
> >>> + * @cpu: cpu for which frequency is fetched.
> >>> + * @level: level of frequency of the CPU
> >>> + *   e.g level=1 --> 1st MAX FREQ, LEVEL=2 ---> 2nd MAX FREQ, .... etc
> >>> + */
> >>> +static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level)
> >>> +{
> >>> +     int ret = 0, i = 0;
> >>> +     unsigned long level_index;
> >>> +     bool descend = false;
> >>> +     struct cpufreq_frequency_table *table =
> >>> +                                     cpufreq_frequency_get_table(cpu);
> >>> +     if (!table)
> >>> +             return ret;
> >>> +
> >>> +     while (table[i].frequency != CPUFREQ_TABLE_END) {
> >>> +             if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
> >>> +                     continue;
> >>> +
> >>> +             /*check if table in ascending or descending order*/
> >>> +             if ((table[i + 1].frequency != CPUFREQ_TABLE_END) &&
> >>> +                     (table[i + 1].frequency < table[i].frequency)
> >>> +                     && !descend) {
> >>> +                     descend = true;
> >>> +             }
> >>> +
> >>> +             /*return if level matched and table in descending order*/
> >>> +             if (descend && i == level)
> >>> +                     return table[i].frequency;
> >>> +             i++;
> >>> +     }
> >>> +     i--;
> >>> +
> >>> +     if (level > i || descend)
> >>> +             return ret;
> >>> +     level_index = i - level;
> >>> +
> >>> +     /*Scan the table in reverse order and match the level*/
> >>> +     while (i >= 0) {
> >>> +             if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
> >>> +                     continue;
> >>> +             /*return if level matched*/
> >>> +             if (i == level_index)
> >>> +                     return table[i].frequency;
> >>> +             i--;
> >>> +     }
> >>> +     return ret;
> >>> +}
> >>> +
> >>> +/**
> >>> + * cpufreq_apply_cooling - function to apply frequency clipping.
> >>> + * @cpufreq_device: cpufreq_cooling_device pointer containing frequency
> >>> + *   clipping data.
> >>> + * @cooling_state: value of the cooling state.
> >>> + */
> >>> +static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
> >>> +                             unsigned long cooling_state)
> >>> +{
> >>> +     unsigned int event, cpuid, clip_freq;
> >>> +     struct cpumask *maskPtr = &cpufreq_device->allowed_cpus;
> >>> +     unsigned int cpu = cpumask_any(maskPtr);
> >>> +
> >>> +
> >>> +     /* Check if the old cooling action is same as new cooling action */
> >>> +     if (cpufreq_device->cpufreq_state == cooling_state)
> >>> +             return 0;
> >>> +
> >>> +     clip_freq = get_cpu_frequency(cpu, cooling_state);
> >>> +     if (!clip_freq)
> >>> +             return -EINVAL;
> >>> +
> >>> +     cpufreq_device->cpufreq_state = cooling_state;
> >>> +     cpufreq_device->cpufreq_val = clip_freq;
> >>> +     notify_device = cpufreq_device;
> >>> +
> >>> +     if (cooling_state != 0)
> >>> +             event = CPUFREQ_COOLING_START;
> >>> +     else
> >>> +             event = CPUFREQ_COOLING_STOP;
> >>> +
> >>> +     blocking_notifier_call_chain(&cputherm_state_notifier_list,
> >>> +                                             event, &clip_freq);
> >>> +
> >>> +     for_each_cpu(cpuid, maskPtr) {
> >>> +             if (is_cpufreq_valid(cpuid))
> >>> +                     cpufreq_update_policy(cpuid);
> >>> +     }
> >>> +
> >>> +     notify_device = NOTIFY_INVALID;
> >>> +
> >>> +     return 0;
> >>> +}
> >>> +
> >>> +/**
> >>> + * cpufreq_thermal_notifier - notifier callback for cpufreq policy change.
> >>> + * @nb:      struct notifier_block * with callback info.
> >>> + * @event: value showing cpufreq event for which this function invoked.
> >>> + * @data: callback-specific data
> >>> + */
> >>> +static int cpufreq_thermal_notifier(struct notifier_block *nb,
> >>> +                                     unsigned long event, void *data)
> >>> +{
> >>> +     struct cpufreq_policy *policy = data;
> >>> +     unsigned long max_freq = 0;
> >>> +
> >>> +     if (event != CPUFREQ_ADJUST || notify_device == NOTIFY_INVALID)
> >>> +             return 0;
> >>> +
> >>> +     if (cpumask_test_cpu(policy->cpu, &notify_device->allowed_cpus))
> >>> +             max_freq = notify_device->cpufreq_val;
> >>> +
> >>> +     /* Never exceed user_policy.max*/
> >>> +     if (max_freq > policy->user_policy.max)
> >>> +             max_freq = policy->user_policy.max;
> >>> +
> >>> +     if (policy->max != max_freq)
> >>> +             cpufreq_verify_within_limits(policy, 0, max_freq);
> >>> +
> >>> +     return 0;
> >>> +}
> >>> +
> >>> +/*
> >>> + * cpufreq cooling device callback functions are defined below
> >>> + */
> >>> +
> >>> +/**
> >>> + * cpufreq_get_max_state - callback function to get the max cooling state.
> >>> + * @cdev: thermal cooling device pointer.
> >>> + * @state: fill this variable with the max cooling state.
> >>> + */
> >>> +static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
> >>> +                              unsigned long *state)
> >>> +{
> >>> +     int ret = -EINVAL, i = 0;
> >>> +     struct cpufreq_cooling_device *cpufreq_device;
> >>> +     struct cpumask *maskPtr;
> >>> +     unsigned int cpu;
> >>> +     struct cpufreq_frequency_table *table;
> >>> +
> >>> +     mutex_lock(&cooling_cpufreq_lock);
> >>> +     list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
> >>> +             if (cpufreq_device && cpufreq_device->cool_dev == cdev)
> >>> +                     break;
> >>> +     }
> >>> +     if (cpufreq_device == NULL)
> >>> +             goto return_get_max_state;
> >>> +
> >>> +     maskPtr = &cpufreq_device->allowed_cpus;
> >>> +     cpu = cpumask_any(maskPtr);
> >>> +     table = cpufreq_frequency_get_table(cpu);
> >>> +     if (!table) {
> >>> +             *state = 0;
> >>> +             ret = 0;
> >>> +             goto return_get_max_state;
> >>> +     }
> >>> +
> >>> +     while (table[i].frequency != CPUFREQ_TABLE_END) {
> >>> +             if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
> >>> +                     continue;
> >>> +             i++;
> >>> +     }
> >>> +     if (i > 0) {
> >>> +             *state = --i;
> >>> +             ret = 0;
> >>> +     }
> >>> +
> >>> +return_get_max_state:
> >>> +     mutex_unlock(&cooling_cpufreq_lock);
> >>> +     return ret;
> >>> +}
> >>> +
> >>> +/**
> >>> + * cpufreq_get_cur_state - callback function to get the current cooling state.
> >>> + * @cdev: thermal cooling device pointer.
> >>> + * @state: fill this variable with the current cooling state.
> >>> + */
> >>> +static int cpufreq_get_cur_state(struct thermal_cooling_device *cdev,
> >>> +                              unsigned long *state)
> >>> +{
> >>> +     int ret = -EINVAL;
> >>> +     struct cpufreq_cooling_device *cpufreq_device;
> >>> +
> >>> +     mutex_lock(&cooling_cpufreq_lock);
> >>> +     list_for_each_entry(cpufreq_device, &cooling_cpufreq_list, node) {
> >>> +             if (cpufreq_device && cpufreq_device->cool_dev == cdev) {
> >>> +                     *state = cpufreq_device->cpufreq_state;
> >>> +                     ret = 0;
> >>> +                     break;
> >>> +             }
> >>> +     }
> >>> +     mutex_unlock(&cooling_cpufreq_lock);
> >>> +
> >>
> >> as cpufreq may be changed in other places, e.g. via sysfs I/F, we should
> >> use the current cpu frequency to get the REAL cooling state, rather than
> >> using a cached value.
> >
> > Yes agreed , I will repost with your suggestion.
> >
> > Thanks,
> > Amit
> >>
> >> thanks,
> >> rui
> >>
> >>
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 
> 



  reply	other threads:[~2012-08-20  2:15 UTC|newest]

Thread overview: 50+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-16 11:41 [PATCH v6 0/6] thermal: Add kernel thermal support for exynos platform Amit Daniel Kachhap
2012-08-16 11:53 ` [lm-sensors] " Amit Daniel Kachhap
2012-08-16 11:41 ` [PATCH v6 1/6] thermal: add generic cpufreq cooling implementation Amit Daniel Kachhap
2012-08-16 11:53   ` [lm-sensors] " Amit Daniel Kachhap
2012-08-16 11:41   ` Amit Daniel Kachhap
2012-08-16 14:52   ` Valentin, Eduardo
2012-08-16 14:52     ` [linux-pm] " Valentin, Eduardo
2012-08-16 14:52     ` [lm-sensors] " Valentin, Eduardo
2012-08-17  3:43     ` Amit Kachhap
2012-08-17  3:55       ` [lm-sensors] " Amit Kachhap
2012-08-17  7:24   ` Zhang Rui
2012-08-17  7:24     ` Zhang Rui
2012-08-17  7:24     ` [lm-sensors] " Zhang Rui
2012-08-17  7:58     ` Amit Kachhap
2012-08-17  8:10       ` [lm-sensors] " Amit Kachhap
2012-08-17  7:58       ` Amit Kachhap
2012-08-17  8:56       ` Valentin, Eduardo
2012-08-17  8:56         ` Valentin, Eduardo
2012-08-17  8:56         ` [lm-sensors] " Valentin, Eduardo
2012-08-20  2:16         ` Zhang Rui [this message]
2012-08-20  2:16           ` Zhang Rui
2012-08-20  2:16           ` [lm-sensors] " Zhang Rui
2012-08-20  9:36           ` Valentin, Eduardo
2012-08-20  9:36             ` Valentin, Eduardo
2012-08-20  9:36             ` [lm-sensors] " Valentin, Eduardo
2012-08-17 13:29       ` [RESEND PATCH " Amit Daniel Kachhap
2012-08-17 13:41         ` [lm-sensors] " Amit Daniel Kachhap
2012-08-17 13:29         ` Amit Daniel Kachhap
2012-08-17 13:32         ` Amit Kachhap
2012-08-17 13:44           ` [lm-sensors] " Amit Kachhap
2012-08-17 13:32           ` Amit Kachhap
2012-08-16 11:41 ` [PATCH v6 2/6] hwmon: exynos4: move thermal sensor driver to driver/thermal directory Amit Daniel Kachhap
2012-08-16 11:53   ` [lm-sensors] " Amit Daniel Kachhap
2012-08-16 11:41   ` Amit Daniel Kachhap
2012-08-16 11:41 ` [PATCH v6 3/6] thermal: exynos5: add exynos5250 thermal sensor driver support Amit Daniel Kachhap
2012-08-16 11:53   ` [lm-sensors] " Amit Daniel Kachhap
2012-08-16 11:41   ` Amit Daniel Kachhap
2012-08-16 11:41 ` [PATCH v6 4/6] thermal: exynos: register the tmu sensor with the kernel thermal layer Amit Daniel Kachhap
2012-08-16 11:53   ` [lm-sensors] " Amit Daniel Kachhap
2012-08-16 11:41   ` Amit Daniel Kachhap
2012-08-16 11:41 ` [PATCH v6 5/6] ARM: exynos: add thermal sensor driver platform data support Amit Daniel Kachhap
2012-08-16 11:53   ` [lm-sensors] " Amit Daniel Kachhap
2012-08-16 11:41   ` Amit Daniel Kachhap
2012-08-17  3:55   ` Thomas Abraham
2012-08-17  4:07     ` [lm-sensors] " Thomas Abraham
2012-08-16 11:41 ` [PATCH v6 6/6] thermal: exynos: Use devm_* functions Amit Daniel Kachhap
2012-08-16 11:53   ` [lm-sensors] " Amit Daniel Kachhap
2012-08-16 11:41   ` Amit Daniel Kachhap
     [not found] <0MAO00DCVFKI4NS0@ms2.samsung.com>
2012-09-21  2:23 ` [PATCH v6 1/6] thermal: add generic cpufreq cooling implementation jonghwa3.lee
2012-09-21  2:23   ` jonghwa3.lee

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1345428963.1682.899.camel@rui.sh.intel.com \
    --to=rui.zhang@intel.com \
    --cc=akpm@linux-foundation.org \
    --cc=amit.kachhap@linaro.org \
    --cc=durgadoss.r@intel.com \
    --cc=eduardo.valentin@ti.com \
    --cc=guenter.roeck@ericsson.com \
    --cc=kgene.kim@samsung.com \
    --cc=khali@linux-fr.org \
    --cc=kmpark@infradead.org \
    --cc=lenb@kernel.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@lists.linux-foundation.org \
    --cc=linux-samsung-soc@vger.kernel.org \
    --cc=lm-sensors@lm-sensors.org \
    --cc=sw.ju@samsung.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.