This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 4f6a0bd36c53d55cbe9a5ef7b930127e3bdaef7c Author: guanyi3 <[email protected]> AuthorDate: Sat Aug 8 11:35:35 2026 +0800 drivers/devfreq: add ondemand governor Add devfreq ondemand governor that scales device frequency based on CPU load. When CPU load exceeds the configured threshold, frequency is set to maximum; otherwise it is scaled proportionally. Signed-off-by: guanyi3 <[email protected]> --- drivers/devfreq/devfreq_ondemand.c | 209 +++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) diff --git a/drivers/devfreq/devfreq_ondemand.c b/drivers/devfreq/devfreq_ondemand.c new file mode 100644 index 00000000000..7c753c78466 --- /dev/null +++ b/drivers/devfreq/devfreq_ondemand.c @@ -0,0 +1,209 @@ +/**************************************************************************** + * drivers/devfreq/devfreq_ondemand.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include <nuttx/config.h> +#include <nuttx/devfreq.h> +#include <nuttx/kmalloc.h> +#include <nuttx/wqueue.h> +#include <sys/param.h> + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define DEVFREQ_MIN_SAMPLING_INTERVAL (2 * USEC_PER_TICK) +#define DEVFREQ_LOAD_THRESHOLD_MAX (100) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct devfreq_ondemand_s +{ + struct work_s work; + uint32_t threshold; + uint32_t sample_rate; + uint32_t target_freq; + FAR struct qos_request_s *req; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int devfreq_gov_ondemand_init(FAR struct devfreq_s *dev); +static int devfreq_gov_ondemand_exit(FAR struct devfreq_s *dev); +static int devfreq_gov_ondemand_start(FAR struct devfreq_s *dev); +static void devfreq_gov_ondemand_stop(FAR struct devfreq_s *dev); +static uint32_t devfreq_gov_ondemand_limit(FAR struct devfreq_s *dev); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct devfreq_governor_s g_devfreq_gov_ondemand = +{ + .name = "ondemand", + .init = devfreq_gov_ondemand_init, + .exit = devfreq_gov_ondemand_exit, + .start = devfreq_gov_ondemand_start, + .stop = devfreq_gov_ondemand_stop, + .limit = devfreq_gov_ondemand_limit, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint32_t devfreq_gov_ondemand_cpuload(void) +{ + struct cpuload_s loadavg; + uint32_t idleload = 0; + int cpu; + + for (cpu = 0; cpu < CONFIG_SMP_NCPUS; cpu++) + { + clock_cpuload(cpu, &loadavg); + idleload += loadavg.active * 100 / loadavg.total; + } + + return 100 - idleload; +} + +static void devfreq_ondemand_worker(FAR void *arg) +{ + FAR struct devfreq_s *dev = arg; + FAR struct devfreq_ondemand_s *data = dev->governor_data; + uint32_t cpuload; + + cpuload = devfreq_gov_ondemand_cpuload(); + nxmutex_lock(&dev->lock); + if (cpuload > CONFIG_DEVFREQ_LOAD_THRESHOLD) + { + if (dev->cur < dev->max) + { + data->target_freq = dev->max; + } + else + { + data->target_freq = dev->cur; + } + } + else + { + data->target_freq = dev->min + cpuload * + (dev->max - dev->min) / 100; + } + + nxmutex_unlock(&dev->lock); + + devfreq_qos_update_request(dev, data->req, dev->min, dev->max); + work_queue(HPWORK, + &data->work, + devfreq_ondemand_worker, + dev, + data->sample_rate / USEC_PER_TICK); +} + +static int devfreq_gov_ondemand_init(FAR struct devfreq_s *dev) +{ + FAR struct devfreq_ondemand_s *data; + + data = kmm_zalloc(sizeof(struct devfreq_ondemand_s)); + if (!data) + { + return -ENOMEM; + } + + data->req = devfreq_qos_add_request(dev, dev->min, dev->max); + data->threshold = MIN(DEVFREQ_LOAD_THRESHOLD_MAX, + CONFIG_DEVFREQ_LOAD_THRESHOLD); + data->sample_rate = MAX(DEVFREQ_MIN_SAMPLING_INTERVAL, + CONFIG_DEVFREQ_SAMPLE_RATE); + dev->governor_data = data; + return 0; +} + +static int devfreq_gov_ondemand_exit(FAR struct devfreq_s *dev) +{ + FAR struct devfreq_ondemand_s *data = dev->governor_data; + + devfreq_qos_remove_request(dev, data->req); + + kmm_free(data); + return 0; +} + +static int devfreq_gov_ondemand_start(FAR struct devfreq_s *dev) +{ + FAR struct devfreq_ondemand_s *data = dev->governor_data; + + work_queue(HPWORK, + &data->work, + devfreq_ondemand_worker, + dev, + 0); + return 0; +} + +static void devfreq_gov_ondemand_stop(FAR struct devfreq_s *dev) +{ + FAR struct devfreq_ondemand_s *data = dev->governor_data; + + if (sched_idletask()) + { + work_cancel(HPWORK, &data->work); + } + else + { + work_cancel_sync(HPWORK, &data->work); + } +} + +static uint32_t devfreq_gov_ondemand_limit(FAR struct devfreq_s *dev) +{ + FAR struct devfreq_ondemand_s *data = dev->governor_data; + uint32_t freq = data->target_freq; + + if (freq > dev->max) + { + freq = dev->max; + } + + if (freq < dev->min) + { + freq = dev->min; + } + + return freq; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +FAR struct devfreq_governor_s *devfreq_ondemand(void) +{ + return &g_devfreq_gov_ondemand; +}
