mirror of
https://github.com/apache/nuttx.git
synced 2026-08-10 15:05:07 +00:00
driver/devfreq: DVFS framework for devices
This commit introduces a devfreq framework to manage device frequency scaling. The framework includes the following features: 1.devfreq governor - provide governor ops, including init, start, stop, exit - default governor, performance & powersave - customized governor, device can provide governor when register 2.runtime register and unregister - device can runtime register & unregister, search by name 3.suspend and resume - suspend and resume frequency scaling 4.notify - register & unregister notifier callback, notify frequency changes 5.qos support - simplified QoS, manage multiple freq range request - including init, add/remove/update request, get value Signed-off-by: guanyi <guanyi@xiaomi.com>
This commit is contained in:
parent
875e86bd35
commit
e29a7bcb07
12 changed files with 2006 additions and 0 deletions
|
|
@ -11,6 +11,7 @@ source "drivers/crypto/Kconfig"
|
|||
source "drivers/loop/Kconfig"
|
||||
source "drivers/can/Kconfig"
|
||||
source "drivers/clk/Kconfig"
|
||||
source "drivers/devfreq/Kconfig"
|
||||
source "drivers/i2c/Kconfig"
|
||||
source "drivers/i3c/Kconfig"
|
||||
source "drivers/spi/Kconfig"
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ include bch/Make.defs
|
|||
include can/Make.defs
|
||||
include clk/Make.defs
|
||||
include crypto/Make.defs
|
||||
include devfreq/Make.defs
|
||||
include devicetree/Make.defs
|
||||
include dma/Make.defs
|
||||
include math/Make.defs
|
||||
|
|
|
|||
25
drivers/devfreq/CMakeLists.txt
Normal file
25
drivers/devfreq/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
# ##############################################################################
|
||||
# drivers/devfreq/CMakeLists.txt
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# ##############################################################################
|
||||
|
||||
if(CONFIG_DEVFREQ)
|
||||
set(SRCS devfreq.c devfreq_performance.c devfreq_powersave.c devfreq_qos.c)
|
||||
|
||||
target_sources(drivers PRIVATE ${SRCS})
|
||||
endif()
|
||||
36
drivers/devfreq/Kconfig
Normal file
36
drivers/devfreq/Kconfig
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#
|
||||
# For a description of the syntax of this configuration file,
|
||||
# see the file kconfig-language.txt in the NuttX tools repository.
|
||||
#
|
||||
|
||||
config DEVFREQ
|
||||
bool "devfreq"
|
||||
default n
|
||||
---help---
|
||||
devfreq framework, dynamic voltage frequency scaling(DVFS)
|
||||
for device
|
||||
|
||||
if DEVFREQ
|
||||
|
||||
choice
|
||||
prompt "DEVFREQ_DEFAULT_GOVERNOR"
|
||||
default DEVFREQ_DEFAULT_GOV_PERFORMANCE
|
||||
|
||||
config DEVFREQ_DEFAULT_GOV_PERFORMANCE
|
||||
bool "devfreq_performance"
|
||||
---help---
|
||||
devfreq performance governor, always choose the highest frequency
|
||||
|
||||
config DEVFREQ_DEFAULT_GOV_POWERSAVE
|
||||
bool "devfreq_powersave"
|
||||
---help---
|
||||
devfreq powersave governor, always choose the lowest frequency
|
||||
|
||||
config DEVFREQ_DEFAULT_GOV_PASSIVE
|
||||
bool "devfreq_passive"
|
||||
---help---
|
||||
devfreq passive governor, a device-defined governor
|
||||
|
||||
endchoice
|
||||
|
||||
endif
|
||||
30
drivers/devfreq/Make.defs
Normal file
30
drivers/devfreq/Make.defs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
############################################################################
|
||||
# drivers/devfreq/Make.defs
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
# Include devfreq sources
|
||||
|
||||
ifeq ($(CONFIG_DEVFREQ),y)
|
||||
|
||||
CSRCS += devfreq.c devfreq_performance.c devfreq_powersave.c devfreq_qos.c
|
||||
|
||||
DEPPATH += --dep-path devfreq
|
||||
VPATH += devfreq
|
||||
|
||||
endif
|
||||
856
drivers/devfreq/devfreq.c
Normal file
856
drivers/devfreq/devfreq.c
Normal file
|
|
@ -0,0 +1,856 @@
|
|||
/****************************************************************************
|
||||
* drivers/devfreq/devfreq.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 <debug.h>
|
||||
|
||||
#include <nuttx/devfreq.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <nuttx/sched.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static struct list_node g_devfreq_list = LIST_INITIAL_VALUE(g_devfreq_list);
|
||||
static mutex_t g_devfreq_list_lock = NXMUTEX_INITIALIZER;
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static int devfreq_init_governor(FAR struct devfreq_s *devfreq);
|
||||
static void devfreq_exit_governor(FAR struct devfreq_s *devfreq);
|
||||
static int devfreq_start_governor(FAR struct devfreq_s *devfreq);
|
||||
static void devfreq_stop_governor(FAR struct devfreq_s *devfreq);
|
||||
static void devfreq_limit_governor(FAR struct devfreq_s *devfreq);
|
||||
static ssize_t devfreq_table_find_freq(FAR struct devfreq_s *devfreq,
|
||||
uint32_t target_freq,
|
||||
int relation);
|
||||
static int devfreq_table_validate(FAR struct devfreq_s *devfreq);
|
||||
static void devfreq_refresh_limit(FAR struct devfreq_s *devfreq);
|
||||
static int devfreq_driver_target(FAR struct devfreq_s *devfreq,
|
||||
uint32_t target_freq,
|
||||
int relation);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_init_governor
|
||||
*
|
||||
* Description:
|
||||
* Initialize governor
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int devfreq_init_governor(FAR struct devfreq_s *devfreq)
|
||||
{
|
||||
if (!devfreq->governor)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (devfreq->governor->init)
|
||||
{
|
||||
return devfreq->governor->init(devfreq);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_exit_governor
|
||||
*
|
||||
* Description:
|
||||
* Exit governor
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void devfreq_exit_governor(FAR struct devfreq_s *devfreq)
|
||||
{
|
||||
if (!devfreq->governor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (devfreq->governor->exit)
|
||||
{
|
||||
devfreq->governor->exit(devfreq);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_start_governor
|
||||
*
|
||||
* Description:
|
||||
* Start governor
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int devfreq_start_governor(FAR struct devfreq_s *devfreq)
|
||||
{
|
||||
if (devfreq->suspended)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!devfreq->governor)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (devfreq->governor->start)
|
||||
{
|
||||
int ret = devfreq->governor->start(devfreq);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
devfreq_limit_governor(devfreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_stop_governor
|
||||
*
|
||||
* Description:
|
||||
* Stop governor
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void devfreq_stop_governor(FAR struct devfreq_s *devfreq)
|
||||
{
|
||||
if (devfreq->suspended || !devfreq->governor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (devfreq->governor->stop)
|
||||
{
|
||||
devfreq->governor->stop(devfreq);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_limit_governor
|
||||
*
|
||||
* Description:
|
||||
* Limit governor
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void devfreq_limit_governor(FAR struct devfreq_s *devfreq)
|
||||
{
|
||||
if (devfreq->suspended || !devfreq->governor)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (devfreq->governor->limit)
|
||||
{
|
||||
uint32_t freq = devfreq->governor->limit(devfreq);
|
||||
devfreq_driver_target(devfreq, freq, DEVFREQ_RELATION_L);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_table_find_freq
|
||||
*
|
||||
* Description:
|
||||
* Find frequency in table
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
* target_freq - target frequency
|
||||
* relation - relation
|
||||
*
|
||||
* Returned Value:
|
||||
* target index on success; negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static ssize_t devfreq_table_find_freq(FAR struct devfreq_s *devfreq,
|
||||
uint32_t target_freq,
|
||||
int relation)
|
||||
{
|
||||
ssize_t best = -ENOENT;
|
||||
size_t i;
|
||||
|
||||
if (relation == DEVFREQ_RELATION_L)
|
||||
{
|
||||
for (i = 0; devfreq->freq_table[i] != DEVFREQ_ENTRY_END; i++)
|
||||
{
|
||||
if (devfreq->freq_table[i] == DEVFREQ_ENTRY_INVALID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (devfreq->freq_table[i] >= target_freq)
|
||||
{
|
||||
best = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (relation == DEVFREQ_RELATION_H)
|
||||
{
|
||||
for (i = 0; devfreq->freq_table[i] != DEVFREQ_ENTRY_END; i++)
|
||||
{
|
||||
if (devfreq->freq_table[i] == DEVFREQ_ENTRY_INVALID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (devfreq->freq_table[i] > target_freq)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
best = i;
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_table_validate
|
||||
*
|
||||
* Description:
|
||||
* Validate table
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int devfreq_table_validate(FAR struct devfreq_s *devfreq)
|
||||
{
|
||||
FAR const uint32_t *table = devfreq->freq_table;
|
||||
uint32_t prv_freq = 0;
|
||||
uint32_t min_freq = UINT32_MAX;
|
||||
uint32_t max_freq = 0;
|
||||
size_t i;
|
||||
|
||||
if (!table)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; table[i] != DEVFREQ_ENTRY_END; i++)
|
||||
{
|
||||
if (table[i] == DEVFREQ_ENTRY_INVALID)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i && table[i] <= prv_freq)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (table[i] < min_freq)
|
||||
{
|
||||
min_freq = table[i];
|
||||
}
|
||||
|
||||
if (table[i] > max_freq)
|
||||
{
|
||||
max_freq = table[i];
|
||||
}
|
||||
|
||||
prv_freq = table[i];
|
||||
}
|
||||
|
||||
devfreq->min = min_freq;
|
||||
devfreq->max = max_freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_refresh_limit
|
||||
*
|
||||
* Description:
|
||||
* Refresh limit
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void devfreq_refresh_limit(FAR struct devfreq_s *devfreq)
|
||||
{
|
||||
uint32_t min;
|
||||
uint32_t max;
|
||||
ssize_t idx;
|
||||
|
||||
min = qos_get_value(&devfreq->constraints, QOS_REQ_MIN);
|
||||
max = qos_get_value(&devfreq->constraints, QOS_REQ_MAX);
|
||||
|
||||
if (min > max)
|
||||
{
|
||||
min = max;
|
||||
}
|
||||
|
||||
idx = devfreq_table_find_freq(devfreq, min, DEVFREQ_RELATION_L);
|
||||
if (idx >= 0)
|
||||
{
|
||||
devfreq->min = devfreq->freq_table[idx];
|
||||
}
|
||||
|
||||
idx = devfreq_table_find_freq(devfreq, max, DEVFREQ_RELATION_H);
|
||||
if (idx >= 0)
|
||||
{
|
||||
devfreq->max = devfreq->freq_table[idx];
|
||||
}
|
||||
|
||||
devfreq_limit_governor(devfreq);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_driver_target
|
||||
*
|
||||
* Description:
|
||||
* Set target frequency
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
* target_freq - target frequency
|
||||
* relation - relation to target frequency
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static int devfreq_driver_target(FAR struct devfreq_s *devfreq,
|
||||
uint32_t target_freq,
|
||||
int relation)
|
||||
{
|
||||
struct devfreq_notifier_s freq;
|
||||
ssize_t idx;
|
||||
int ret;
|
||||
|
||||
if (!devfreq)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
idx = devfreq_table_find_freq(devfreq, target_freq, relation);
|
||||
if (idx < 0)
|
||||
{
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
target_freq = devfreq->freq_table[idx];
|
||||
if (target_freq == devfreq->cur)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
freq.old = devfreq->cur;
|
||||
freq.new = target_freq;
|
||||
|
||||
blocking_notifier_call_chain(&devfreq->notifier_list,
|
||||
DEVFREQ_PRECHANGE, &freq);
|
||||
ret = devfreq->driver->target_index(devfreq, idx);
|
||||
blocking_notifier_call_chain(&devfreq->notifier_list,
|
||||
DEVFREQ_POSTCHANGE, &freq);
|
||||
if (ret < 0)
|
||||
{
|
||||
freq.old = target_freq;
|
||||
freq.new = devfreq->cur;
|
||||
blocking_notifier_call_chain(&devfreq->notifier_list,
|
||||
DEVFREQ_PRECHANGE, &freq);
|
||||
blocking_notifier_call_chain(&devfreq->notifier_list,
|
||||
DEVFREQ_POSTCHANGE, &freq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
devfreq->cur = target_freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_register
|
||||
*
|
||||
* Description:
|
||||
* Register devfreq device
|
||||
*
|
||||
* Input Parameters:
|
||||
* name - device name
|
||||
* governor - governor
|
||||
* driver - driver
|
||||
* priv - private data
|
||||
*
|
||||
* Returned Value:
|
||||
* devfreq device on success; NULL on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct devfreq_s *devfreq_register(
|
||||
const char *name,
|
||||
FAR struct devfreq_governor_s *governor,
|
||||
FAR struct devfreq_driver_s *driver,
|
||||
FAR void *priv)
|
||||
{
|
||||
FAR struct devfreq_s *devfreq = devfreq_find_by_name(name);
|
||||
|
||||
if (devfreq || !driver)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
devfreq = (FAR struct devfreq_s *)kmm_zalloc(sizeof(struct devfreq_s));
|
||||
if (!devfreq)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qos_constraints_init(&devfreq->constraints);
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&devfreq->notifier_list);
|
||||
nxmutex_init(&devfreq->lock);
|
||||
|
||||
devfreq->driver = driver;
|
||||
devfreq->priv = priv;
|
||||
devfreq->suspended = false;
|
||||
devfreq->freq_table = driver->get_table(devfreq);
|
||||
if (!devfreq->freq_table)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (devfreq_table_validate(devfreq) < 0)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!governor)
|
||||
{
|
||||
devfreq->governor = devfreq_default_governor();
|
||||
}
|
||||
else
|
||||
{
|
||||
devfreq->governor = governor;
|
||||
}
|
||||
|
||||
if (devfreq_init_governor(devfreq) < 0)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
devfreq_start_governor(devfreq);
|
||||
|
||||
nxmutex_lock(&g_devfreq_list_lock);
|
||||
list_add_tail(&g_devfreq_list, &devfreq->node);
|
||||
nxmutex_unlock(&g_devfreq_list_lock);
|
||||
|
||||
return devfreq;
|
||||
|
||||
out:
|
||||
nxmutex_destroy(&devfreq->lock);
|
||||
nxmutex_destroy(&devfreq->notifier_list.mutex);
|
||||
kmm_free(devfreq);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_unregister
|
||||
*
|
||||
* Description:
|
||||
* Unregister devfreq device
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_unregister(FAR struct devfreq_s *devfreq)
|
||||
{
|
||||
if (!devfreq)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nxmutex_lock(&g_devfreq_list_lock);
|
||||
list_delete(&devfreq->node);
|
||||
nxmutex_unlock(&g_devfreq_list_lock);
|
||||
|
||||
devfreq_stop_governor(devfreq);
|
||||
devfreq_exit_governor(devfreq);
|
||||
|
||||
nxmutex_destroy(&devfreq->lock);
|
||||
nxmutex_destroy(&devfreq->notifier_list.mutex);
|
||||
kmm_free(devfreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_suspend
|
||||
*
|
||||
* Description:
|
||||
* Suspend devfreq device
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_suspend(FAR struct devfreq_s *devfreq)
|
||||
{
|
||||
nxmutex_lock(&devfreq->lock);
|
||||
|
||||
devfreq_stop_governor(devfreq);
|
||||
|
||||
if (devfreq->driver->suspend)
|
||||
{
|
||||
int ret = devfreq->driver->suspend(devfreq);
|
||||
if (ret < 0)
|
||||
{
|
||||
nxmutex_unlock(&devfreq->lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
devfreq->suspended = true;
|
||||
nxmutex_unlock(&devfreq->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_resume
|
||||
*
|
||||
* Description:
|
||||
* Resume devfreq device
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_resume(struct devfreq_s *devfreq)
|
||||
{
|
||||
nxmutex_lock(&devfreq->lock);
|
||||
|
||||
if (devfreq->driver->resume)
|
||||
{
|
||||
int ret = devfreq->driver->resume(devfreq);
|
||||
if (ret < 0)
|
||||
{
|
||||
nxmutex_unlock(&devfreq->lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
devfreq->suspended = false;
|
||||
devfreq_start_governor(devfreq);
|
||||
|
||||
nxmutex_unlock(&devfreq->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_register_notifier
|
||||
*
|
||||
* Description:
|
||||
* Register notifier
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
* nb - notifier block
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_register_notifier(FAR struct devfreq_s *devfreq,
|
||||
FAR struct notifier_block *nb)
|
||||
{
|
||||
if (!devfreq || !nb)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
blocking_notifier_chain_register(&devfreq->notifier_list, nb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_unregister_notifier
|
||||
*
|
||||
* Description:
|
||||
* Unregister notifier
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
* nb - notifier block
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_unregister_notifier(FAR struct devfreq_s *devfreq,
|
||||
FAR struct notifier_block *nb)
|
||||
{
|
||||
if (!devfreq || !nb)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
blocking_notifier_chain_unregister(&devfreq->notifier_list, nb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_get_frequency
|
||||
*
|
||||
* Description:
|
||||
* Get current frequency
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
*
|
||||
* Returned Value:
|
||||
* Current frequency
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR uint32_t devfreq_get_frequency(FAR struct devfreq_s *devfreq)
|
||||
{
|
||||
return devfreq->driver->get_frequency(devfreq);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_qos_add_request
|
||||
*
|
||||
* Description:
|
||||
* Add a new request
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq device
|
||||
* min - minimum frequency
|
||||
* max - maximum frequency
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct qos_request_s *devfreq_qos_add_request(
|
||||
FAR struct devfreq_s *devfreq,
|
||||
uint32_t min, uint32_t max)
|
||||
{
|
||||
FAR struct qos_request_s *req;
|
||||
|
||||
if (!devfreq)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nxmutex_lock(&devfreq->lock);
|
||||
|
||||
req = qos_add_request(&devfreq->constraints, min, max);
|
||||
devfreq_refresh_limit(devfreq);
|
||||
|
||||
nxmutex_unlock(&devfreq->lock);
|
||||
return req;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_qos_update_request
|
||||
*
|
||||
* Description:
|
||||
* Update a request
|
||||
*
|
||||
* Input Parameters:
|
||||
* qos - devfreq qos
|
||||
* min - minimum frequency
|
||||
* max - maximum frequency
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_qos_update_request(FAR struct devfreq_s *devfreq,
|
||||
FAR struct qos_request_s *req,
|
||||
uint32_t min, uint32_t max)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!devfreq || !req)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nxmutex_lock(&devfreq->lock);
|
||||
|
||||
ret = qos_update_request(&devfreq->constraints, req, min, max);
|
||||
if (ret < 0)
|
||||
{
|
||||
nxmutex_unlock(&devfreq->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
devfreq_refresh_limit(devfreq);
|
||||
|
||||
nxmutex_unlock(&devfreq->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_qos_remove_request
|
||||
*
|
||||
* Description:
|
||||
* Remove a request
|
||||
*
|
||||
* Input Parameters:
|
||||
* qos - devfreq qos
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_qos_remove_request(FAR struct devfreq_s *devfreq,
|
||||
FAR struct qos_request_s *req)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!devfreq || !req)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
nxmutex_lock(&devfreq->lock);
|
||||
|
||||
ret = qos_remove_request(&devfreq->constraints, req);
|
||||
if (ret < 0)
|
||||
{
|
||||
nxmutex_unlock(&devfreq->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
devfreq_refresh_limit(devfreq);
|
||||
|
||||
nxmutex_unlock(&devfreq->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_find_by_name
|
||||
*
|
||||
* Description:
|
||||
* find a devfreq entry from global list by name
|
||||
*
|
||||
* Input Parameters:
|
||||
* name - devfreq name
|
||||
*
|
||||
* Returned Value:
|
||||
* devfreq handle
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct devfreq_s *devfreq_find_by_name(FAR const char *name)
|
||||
{
|
||||
FAR struct devfreq_s *devfreq;
|
||||
|
||||
if (!name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nxmutex_lock(&g_devfreq_list_lock);
|
||||
|
||||
list_for_every_entry(&g_devfreq_list, devfreq, struct devfreq_s, node)
|
||||
{
|
||||
if (!strcmp(devfreq->name, name))
|
||||
{
|
||||
nxmutex_unlock(&g_devfreq_list_lock);
|
||||
return devfreq;
|
||||
}
|
||||
}
|
||||
|
||||
nxmutex_unlock(&g_devfreq_list_lock);
|
||||
return NULL;
|
||||
}
|
||||
63
drivers/devfreq/devfreq_performance.c
Normal file
63
drivers/devfreq/devfreq_performance.c
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/****************************************************************************
|
||||
* drivers/devfreq/devfreq_performance.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/devfreq.h>
|
||||
|
||||
#ifdef CONFIG_DEVFREQ_DEFAULT_GOV_PERFORMANCE
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t devfreq_performance_limit(FAR struct devfreq_s *devfreq);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static struct devfreq_governor_s g_devfreq_gov_performance =
|
||||
{
|
||||
.name = "performance",
|
||||
.limit = devfreq_performance_limit,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t devfreq_performance_limit(FAR struct devfreq_s *devfreq)
|
||||
{
|
||||
return devfreq->max;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct devfreq_governor_s *devfreq_default_governor(void)
|
||||
{
|
||||
return &g_devfreq_gov_performance;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEVFREQ_DEFAULT_GOV_PERFORMANCE */
|
||||
63
drivers/devfreq/devfreq_powersave.c
Normal file
63
drivers/devfreq/devfreq_powersave.c
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/****************************************************************************
|
||||
* drivers/devfreq/devfreq_powersave.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/devfreq.h>
|
||||
|
||||
#ifdef CONFIG_DEVFREQ_DEFAULT_GOV_POWERSAVE
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t devfreq_powersave_limit(FAR struct devfreq_s *devfreq);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static struct devfreq_governor_s g_devfreq_gov_powersave =
|
||||
{
|
||||
.name = "powersave",
|
||||
.limit = devfreq_powersave_limit,
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static uint32_t devfreq_powersave_limit(FAR struct devfreq_s *devfreq)
|
||||
{
|
||||
return devfreq->min;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct devfreq_governor_s *devfreq_default_governor(void)
|
||||
{
|
||||
return &g_devfreq_gov_powersave;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEVFREQ_DEFAULT_GOV_POWERSAVE */
|
||||
195
drivers/devfreq/devfreq_qos.c
Normal file
195
drivers/devfreq/devfreq_qos.c
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/****************************************************************************
|
||||
* drivers/devfreq/devfreq_qos.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/devfreq/devfreq_qos.h>
|
||||
#include <nuttx/kmalloc.h>
|
||||
#include <errno.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: qos_constraints_init
|
||||
*
|
||||
* Description:
|
||||
* Initialize a qos_constraints_s struct.
|
||||
*
|
||||
* Input Parameters:
|
||||
* qos - The qos constraints struct to initialize.
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void qos_constraints_init(FAR struct qos_constraints_s *constraints)
|
||||
{
|
||||
plist_head_init(&constraints->min_requests);
|
||||
plist_head_init(&constraints->max_requests);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: qos_add_request
|
||||
*
|
||||
* Description:
|
||||
* Add a qos request to qos constraints.
|
||||
*
|
||||
* Input Parameters:
|
||||
* qos - The qos constraints to add the request to.
|
||||
* min - The minimum priority/value of the request.
|
||||
* max - The maximum priority/value of the request.
|
||||
*
|
||||
* Returned Value:
|
||||
* A pointer to the new qos_request_s.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct qos_request_s *qos_add_request(
|
||||
FAR struct qos_constraints_s *constraints,
|
||||
uint32_t min, uint32_t max)
|
||||
{
|
||||
FAR struct qos_request_s *req;
|
||||
|
||||
if (!constraints)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
req = kmm_zalloc(sizeof(struct qos_request_s));
|
||||
if (!req)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
plist_node_init(&req->min_req, min);
|
||||
plist_node_init(&req->max_req, max);
|
||||
|
||||
plist_add(&req->min_req, &constraints->min_requests);
|
||||
plist_add(&req->max_req, &constraints->max_requests);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: qos_remove_request
|
||||
*
|
||||
* Description:
|
||||
* Remove qos request from qos constraints.
|
||||
*
|
||||
* Input Parameters:
|
||||
* qos - The qos_constraints_s to remove the request from.
|
||||
* req - The qos_request_s to remove.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int qos_remove_request(FAR struct qos_constraints_s *constraints,
|
||||
FAR struct qos_request_s *req)
|
||||
{
|
||||
if (!req || !constraints)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
plist_del(&req->min_req, &constraints->min_requests);
|
||||
plist_del(&req->max_req, &constraints->max_requests);
|
||||
|
||||
kmm_free(req);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: qos_update_request
|
||||
*
|
||||
* Description:
|
||||
* Update qos request.
|
||||
*
|
||||
* Input Parameters:
|
||||
* qos - The qos constraints.
|
||||
* req - The qos request to update.
|
||||
* min - The new minimum priority/value of the request.
|
||||
* max - The new maximum priority/value of the request.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int qos_update_request(FAR struct qos_constraints_s *constraints,
|
||||
FAR struct qos_request_s *req,
|
||||
uint32_t min, uint32_t max)
|
||||
{
|
||||
if (!req || !constraints)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
req->min_req.prio = min;
|
||||
req->max_req.prio = max;
|
||||
|
||||
plist_del(&req->min_req, &constraints->min_requests);
|
||||
plist_del(&req->max_req, &constraints->max_requests);
|
||||
plist_add(&req->min_req, &constraints->min_requests);
|
||||
plist_add(&req->max_req, &constraints->max_requests);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: qos_get_value
|
||||
*
|
||||
* Description:
|
||||
* Get min or max value of qos constraints.
|
||||
*
|
||||
* Input Parameters:
|
||||
* qos - The qos constraints.
|
||||
* type - The type of request to get the value of.
|
||||
*
|
||||
* Returned Value:
|
||||
* The value of the qos request.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t qos_get_value(FAR struct qos_constraints_s *constraints,
|
||||
enum qos_req_type_e type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case QOS_REQ_MIN:
|
||||
{
|
||||
return plist_first(&constraints->min_requests)->prio;
|
||||
}
|
||||
|
||||
case QOS_REQ_MAX:
|
||||
{
|
||||
return plist_last(&constraints->max_requests)->prio;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
324
include/nuttx/devfreq.h
Normal file
324
include/nuttx/devfreq.h
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
/****************************************************************************
|
||||
* include/nuttx/devfreq.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_DEVFREQ_H
|
||||
#define __INCLUDE_NUTTX_DEVFREQ_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/devfreq/devfreq_qos.h>
|
||||
#include <nuttx/list.h>
|
||||
#include <nuttx/notifier.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define DEVFREQ_PRECHANGE 0
|
||||
#define DEVFREQ_POSTCHANGE 1
|
||||
|
||||
/* Special Values of .frequency field */
|
||||
|
||||
#define DEVFREQ_ENTRY_INVALID ~0u
|
||||
#define DEVFREQ_ENTRY_END ~1u
|
||||
|
||||
#define DEVFREQ_RELATION_L 0 /* lowest frequency at or above target */
|
||||
#define DEVFREQ_RELATION_H 1 /* highest frequency below or at target */
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
struct devfreq_s
|
||||
{
|
||||
char name[NAME_MAX];
|
||||
struct list_node node;
|
||||
|
||||
FAR struct devfreq_governor_s *governor;
|
||||
FAR struct devfreq_driver_s *driver;
|
||||
|
||||
FAR const uint32_t *freq_table;
|
||||
|
||||
struct qos_constraints_s constraints;
|
||||
|
||||
struct blocking_notifier_head notifier_list;
|
||||
|
||||
uint32_t min; /* in kHz */
|
||||
uint32_t max; /* in kHz */
|
||||
uint32_t cur; /* in kHz */
|
||||
|
||||
bool suspended;
|
||||
|
||||
mutex_t lock;
|
||||
|
||||
FAR void *priv;
|
||||
};
|
||||
|
||||
struct devfreq_governor_s
|
||||
{
|
||||
char name[NAME_MAX];
|
||||
CODE int (*init)(FAR struct devfreq_s *devfreq);
|
||||
CODE int (*exit)(FAR struct devfreq_s *devfreq);
|
||||
CODE int (*start)(FAR struct devfreq_s *devfreq);
|
||||
CODE void (*stop)(FAR struct devfreq_s *devfreq);
|
||||
CODE uint32_t (*limit)(FAR struct devfreq_s *devfreq);
|
||||
};
|
||||
|
||||
struct devfreq_driver_s
|
||||
{
|
||||
CODE FAR const uint32_t *
|
||||
(*get_table)(FAR struct devfreq_s *devfreq);
|
||||
CODE int (*target_index)(FAR struct devfreq_s *devfreq,
|
||||
size_t index);
|
||||
CODE uint32_t (*get_frequency)(FAR struct devfreq_s *devfreq);
|
||||
CODE int (*suspend)(FAR struct devfreq_s *devfreq);
|
||||
CODE int (*resume)(FAR struct devfreq_s *devfreq);
|
||||
};
|
||||
|
||||
struct devfreq_notifier_s
|
||||
{
|
||||
uint32_t old;
|
||||
uint32_t new;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
#define EXTERN extern "C"
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_register
|
||||
*
|
||||
* Description:
|
||||
* Register devfreq device
|
||||
*
|
||||
* Input Parameters:
|
||||
* name - device name
|
||||
* governor - governor
|
||||
* driver - driver
|
||||
* priv - private data
|
||||
*
|
||||
* Returned Value:
|
||||
* devfreq device on success; NULL on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct devfreq_s *devfreq_register(
|
||||
FAR const char *name,
|
||||
FAR struct devfreq_governor_s *governor,
|
||||
FAR struct devfreq_driver_s *driver,
|
||||
FAR void *priv);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_unregister
|
||||
*
|
||||
* Description:
|
||||
* unregister devfreq
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq_s handle
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_unregister(FAR struct devfreq_s *devfreq);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_suspend
|
||||
*
|
||||
* Description:
|
||||
* suspend devfreq governors
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq_s handle
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_suspend(FAR struct devfreq_s *devfreq);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_resume
|
||||
*
|
||||
* Description:
|
||||
* resume devfreq governors
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq_s handle
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_resume(FAR struct devfreq_s *devfreq);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_set_governor
|
||||
*
|
||||
* Description:
|
||||
* set devfreq governor
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq_s handle
|
||||
* governor - governor handle
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_register_notifier(FAR struct devfreq_s *devfreq,
|
||||
FAR struct notifier_block *nb);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_unregister_notifier
|
||||
*
|
||||
* Description:
|
||||
* unregister devfreq notifier
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq_s handle
|
||||
* nb - notifier block
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_unregister_notifier(FAR struct devfreq_s *devfreq,
|
||||
FAR struct notifier_block *nb);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_get
|
||||
*
|
||||
* Description:
|
||||
* get the current device frequency (in kHz)
|
||||
*
|
||||
* Input Parameters:
|
||||
* devfreq - devfreq_s handle
|
||||
*
|
||||
* Returned Value:
|
||||
* a non-negative value
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
uint32_t devfreq_get_frequency(FAR struct devfreq_s *devfreq);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_qos_add_request
|
||||
*
|
||||
* Description:
|
||||
* Insert new frequency QoS request
|
||||
*
|
||||
* Input Parameters:
|
||||
* policy - devfreq_policy handle
|
||||
* min - min freq
|
||||
* max - max freq
|
||||
*
|
||||
* Returned Value:
|
||||
* qos handle for update and remove, or NULL if fail
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct qos_request_s *devfreq_qos_add_request(
|
||||
FAR struct devfreq_s *devfreq,
|
||||
uint32_t min, uint32_t max);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_qos_update_request
|
||||
*
|
||||
* Description:
|
||||
* Update frequency QoS request from its list.
|
||||
*
|
||||
* Input Parameters:
|
||||
* qos - Request to remove.
|
||||
* min - min freq
|
||||
* max - max freq
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_qos_update_request(FAR struct devfreq_s *devfreq,
|
||||
FAR struct qos_request_s *qos,
|
||||
uint32_t min, uint32_t max);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_qos_remove_request
|
||||
*
|
||||
* Description:
|
||||
* Remove frequency QoS request from its list.
|
||||
*
|
||||
* Input Parameters:
|
||||
* qos - Request to remove.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero on success; a negated errno value on failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int devfreq_qos_remove_request(FAR struct devfreq_s *devfreq,
|
||||
FAR struct qos_request_s *req);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: devfreq_find_by_name
|
||||
*
|
||||
* Description:
|
||||
* find a devfreq entry from global list by name
|
||||
*
|
||||
* Input Parameters:
|
||||
* name - devfreq name
|
||||
*
|
||||
* Returned Value:
|
||||
* devfreq handle
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct devfreq_s *devfreq_find_by_name(FAR const char *name);
|
||||
|
||||
#ifdef CONFIG_DEVFREQ_DEFAULT_GOV_PASSIVE
|
||||
#define devfreq_default_governor() NULL
|
||||
#else
|
||||
FAR struct devfreq_governor_s *devfreq_default_governor(void);
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_DEVFREQ_H */
|
||||
66
include/nuttx/devfreq/devfreq_qos.h
Normal file
66
include/nuttx/devfreq/devfreq_qos.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/****************************************************************************
|
||||
* include/nuttx/devfreq/devfreq_qos.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_DEVFREQ_DEVFREQ_QOS_H
|
||||
#define __INCLUDE_NUTTX_DEVFREQ_DEVFREQ_OQS_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/plist.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
||||
enum qos_req_type_e
|
||||
{
|
||||
QOS_REQ_MIN,
|
||||
QOS_REQ_MAX
|
||||
};
|
||||
|
||||
struct qos_request_s
|
||||
{
|
||||
struct plist_node min_req;
|
||||
struct plist_node max_req;
|
||||
};
|
||||
|
||||
struct qos_constraints_s
|
||||
{
|
||||
struct plist_head min_requests;
|
||||
struct plist_head max_requests;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
void qos_constraints_init(FAR struct qos_constraints_s *constraints);
|
||||
FAR struct qos_request_s *qos_add_request(FAR struct qos_constraints_s *qos,
|
||||
uint32_t min, uint32_t max);
|
||||
int qos_remove_request(FAR struct qos_constraints_s *constraints,
|
||||
FAR struct qos_request_s *req);
|
||||
int qos_update_request(FAR struct qos_constraints_s *constraints,
|
||||
FAR struct qos_request_s *req,
|
||||
uint32_t min, uint32_t max);
|
||||
uint32_t qos_get_value(FAR struct qos_constraints_s *constraints,
|
||||
enum qos_req_type_e type);
|
||||
#endif
|
||||
346
include/nuttx/plist.h
Normal file
346
include/nuttx/plist.h
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
/****************************************************************************
|
||||
* include/nuttx/plist.h
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __INCLUDE_NUTTX_PLIST_H
|
||||
#define __INCLUDE_NUTTX_PLIST_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <nuttx/nuttx.h>
|
||||
#include <nuttx/list.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
struct plist_head
|
||||
{
|
||||
struct list_node node_list;
|
||||
};
|
||||
|
||||
struct plist_node
|
||||
{
|
||||
uint32_t prio;
|
||||
struct list_node prio_list;
|
||||
struct list_node node_list;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* PLIST_HEAD_INIT - static struct plist_head initializer
|
||||
* head: struct plist_head variable name
|
||||
*/
|
||||
|
||||
#define PLIST_HEAD_INIT(head) \
|
||||
{ \
|
||||
.node_list = LIST_HEAD_INIT((head).node_list) \
|
||||
}
|
||||
|
||||
/* PLIST_HEAD - declare and init plist_head
|
||||
* head: name for struct plist_head variable
|
||||
*/
|
||||
|
||||
#define PLIST_HEAD(head) \
|
||||
struct plist_head head = PLIST_HEAD_INIT(head)
|
||||
|
||||
/* PLIST_NODE_INIT - static struct plist_node initializer
|
||||
* node: struct plist_node variable name
|
||||
* prio: initial node priority
|
||||
*/
|
||||
|
||||
#define PLIST_NODE_INIT(node, val) \
|
||||
{ \
|
||||
.prio = (val), \
|
||||
.prio_list = LIST_HEAD_INIT((node).prio_list), \
|
||||
.node_list = LIST_HEAD_INIT((node).node_list), \
|
||||
}
|
||||
|
||||
/* plist_head_init - dynamic struct plist_head initializer
|
||||
* head: struct plist_head pointer
|
||||
*/
|
||||
|
||||
#define plist_head_init(head) \
|
||||
list_initialize(&(head)->node_list)
|
||||
|
||||
/* plist_node_init - Dynamic struct plist_node initializer
|
||||
* node: struct plist_node pointer
|
||||
* prio: initial node priority
|
||||
*/
|
||||
|
||||
#define plist_node_init(node, val) \
|
||||
do \
|
||||
{ \
|
||||
(node)->prio = (val); \
|
||||
list_initialize(&(node)->prio_list); \
|
||||
list_initialize(&(node)->node_list); \
|
||||
} \
|
||||
while(0)
|
||||
|
||||
/* plist_for_each - iterate over the plist
|
||||
* pos: the type * to use as a loop counter
|
||||
* head: the head for your list
|
||||
*/
|
||||
|
||||
#define plist_for_each(pos, head) \
|
||||
list_for_every_entry(&(head)->node_list, pos, typeof(*pos), node_list)
|
||||
|
||||
/* plist_for_each_continue - continue iteration over the plist
|
||||
* pos: the type * to use as a loop cursor
|
||||
* head: the head for your list
|
||||
*
|
||||
* Continue to iterate over plist, continuing after the current position.
|
||||
*/
|
||||
|
||||
#define plist_for_each_continue(pos, head) \
|
||||
list_for_every_entry_continue(pos, &(head)->node_list, typeof(*pos), node_list)
|
||||
|
||||
/* plist_for_each_safe - iterate safely over a plist of given type
|
||||
* pos: the type * to use as a loop counter
|
||||
* n: another type * to use as temporary storage
|
||||
* head: the head for your list
|
||||
*
|
||||
* Iterate over a plist of given type, safe against removal of list entry.
|
||||
*/
|
||||
|
||||
#define plist_for_each_safe(pos, n, head) \
|
||||
list_for_every_entry_safe(&(head)->node_list, pos, n, typeof(*pos), node_list)
|
||||
|
||||
/* plist_for_each_entry - iterate over list of given type
|
||||
* pos: the type * to use as a loop counter
|
||||
* head: the head for your list
|
||||
* mem: the name of the list_node within the struct
|
||||
*/
|
||||
|
||||
#define plist_for_each_entry(pos, head, mem) \
|
||||
list_for_every_entry(&(head)->node_list, pos, typeof(*pos), mem.node_list)
|
||||
|
||||
/* plist_for_each_entry_continue - continue iteration over list of given type
|
||||
* pos: the type * to use as a loop cursor
|
||||
* head: the head for your list
|
||||
* m: the name of the list_node within the struct
|
||||
*
|
||||
* Continue to iterate over list of given type, continuing after
|
||||
* the current position.
|
||||
*/
|
||||
#define plist_for_each_entry_continue(pos, head, m) \
|
||||
list_for_every_entry_continue(pos, &(head)->node_list, typeof(*pos), m.node_list)
|
||||
|
||||
/* plist_for_each_entry_safe - iterate safely over list of given type
|
||||
* pos: the type * to use as a loop counter
|
||||
* n: another type * to use as temporary storage
|
||||
* head: the head for your list
|
||||
* m: the name of the list_node within the struct
|
||||
*
|
||||
* Iterate over list of given type, safe against removal of list entry.
|
||||
*/
|
||||
#define plist_for_each_entry_safe(pos, n, head, m) \
|
||||
list_for_every_entry_safe(&(head)->node_list, pos, n, typeof(*pos), m.node_list)
|
||||
|
||||
/* All functions below assume the plist_head is not empty. */
|
||||
|
||||
/* plist_first_entry - get the struct for the first entry
|
||||
* head: the struct plist_head pointer
|
||||
* type: the type of the struct this is embedded in
|
||||
* member: the name of the list_node within the struct
|
||||
*/
|
||||
|
||||
#define plist_first_entry(head, type, member) \
|
||||
container_of(plist_first(head), type, member)
|
||||
|
||||
/* plist_last_entry - get the struct for the last entry
|
||||
* head: the struct plist_head pointer
|
||||
* type: the type of the struct this is embedded in
|
||||
* member: the name of the list_node within the struct
|
||||
*/
|
||||
|
||||
#define plist_last_entry(head, type, member) \
|
||||
container_of(plist_last(head), type, member)
|
||||
|
||||
/* plist_next - get the next entry in list
|
||||
* pos: the type * to cursor
|
||||
*/
|
||||
|
||||
#define plist_next(pos) list_next_entry(pos, typeof(*(pos)), node_list)
|
||||
|
||||
/* plist_prev - get the prev entry in list
|
||||
* pos: the type * to cursor
|
||||
*/
|
||||
|
||||
#define plist_prev(pos) list_prev_entry(pos, typeof(*(pos)), node_list)
|
||||
|
||||
/* plist_head_empty - return !0 if a plist_head is empty
|
||||
* head: struct plist_head pointer
|
||||
*/
|
||||
|
||||
#define plist_head_empty(head) list_is_empty(&(head)->node_list)
|
||||
|
||||
/* plist_node_empty - return !0 if plist_node is not on a list
|
||||
* node: struct plist_node pointer
|
||||
*/
|
||||
|
||||
#define plist_node_empty(node) list_is_empty(&(node)->node_list)
|
||||
|
||||
/* plist_first - return the first node (and thus, highest priority)
|
||||
* head: the struct plist_head pointer
|
||||
*
|
||||
* Assumes the plist is _not_ empty.
|
||||
*/
|
||||
|
||||
#define plist_first(head) \
|
||||
list_entry((head)->node_list.next, struct plist_node, node_list)
|
||||
|
||||
/* plist_last - return the last node (and thus, lowest priority)
|
||||
* head: the struct plist_head pointer
|
||||
*
|
||||
* Assumes the plist is _not_ empty.
|
||||
*/
|
||||
|
||||
#define plist_last(head) \
|
||||
list_entry((head)->node_list.prev, struct plist_node, node_list)
|
||||
|
||||
/* plist_add - add node to head
|
||||
* node: struct plist_node pointer
|
||||
* head: struct plist_head pointer
|
||||
*/
|
||||
|
||||
#define plist_add(node, head) \
|
||||
do \
|
||||
{ \
|
||||
FAR struct plist_head *head_ = (head); \
|
||||
FAR struct plist_node *node_ = (node); \
|
||||
FAR struct list_node *node_next_ = &head_->node_list; \
|
||||
\
|
||||
DEBUGASSERT(plist_node_empty(node_)); \
|
||||
DEBUGASSERT(list_is_empty(&node_->prio_list)); \
|
||||
\
|
||||
if (!plist_head_empty(head_)) \
|
||||
{ \
|
||||
FAR struct plist_node *first_ = plist_first(head_); \
|
||||
FAR struct plist_node *iter_ = first_; \
|
||||
FAR struct plist_node *prev_ = NULL; \
|
||||
\
|
||||
do \
|
||||
{ \
|
||||
if (node_->prio < iter_->prio) \
|
||||
{ \
|
||||
node_next_ = &iter_->node_list; \
|
||||
break; \
|
||||
} \
|
||||
\
|
||||
prev_ = iter_; \
|
||||
iter_ = list_entry(iter_->prio_list.next, \
|
||||
struct plist_node, prio_list); \
|
||||
} \
|
||||
while (iter_ != first_); \
|
||||
\
|
||||
if (!prev_ || prev_->prio != node_->prio) \
|
||||
{ \
|
||||
list_add_tail(&iter_->prio_list, &node_->prio_list); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
list_add_tail(node_next_, &node_->node_list); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* plist_del - Remove a node from plist.
|
||||
* node: struct plist_node pointer - entry to be removed
|
||||
* head: struct plist_head pointer - list head
|
||||
*/
|
||||
|
||||
#define plist_del(node, head) \
|
||||
do \
|
||||
{ \
|
||||
FAR struct plist_head *head_ = (head); \
|
||||
FAR struct plist_node *node_ = (node); \
|
||||
\
|
||||
if (!list_is_empty(&node_->prio_list)) \
|
||||
{ \
|
||||
if (node_->node_list.next != &head_->node_list) \
|
||||
{ \
|
||||
FAR struct plist_node *next_ = \
|
||||
list_entry(node_->node_list.next, \
|
||||
struct plist_node, node_list); \
|
||||
\
|
||||
/* Add the next plist_node into prio_list */ \
|
||||
\
|
||||
if (list_is_empty(&next_->prio_list)) \
|
||||
{ \
|
||||
list_add_head(&node_->prio_list, &next_->prio_list); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
list_delete_init(&node_->prio_list); \
|
||||
} \
|
||||
\
|
||||
list_delete_init(&node_->node_list); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* plist_requeue - Requeue node at end of same-prio entries.
|
||||
*
|
||||
* This is essentially an optimized plist_del() followed by
|
||||
* plist_add(). It moves an entry already in the plist to
|
||||
* after any other same-priority entries.
|
||||
* node: struct plist_node pointer - entry to be moved
|
||||
* head: struct plist_head pointer - list head
|
||||
*/
|
||||
|
||||
#define plist_requeue(node, head) \
|
||||
do \
|
||||
{ \
|
||||
FAR struct plist_head *head_ = (head); \
|
||||
FAR struct plist_node *node_ = (node); \
|
||||
\
|
||||
DEBUGASSERT(!plist_head_empty(head_)); \
|
||||
DEBUGASSERT(!plist_node_empty(node_)); \
|
||||
\
|
||||
if (node_ != plist_last(head_)) \
|
||||
{ \
|
||||
FAR struct plist_node *iter_ = plist_next(node_); \
|
||||
\
|
||||
if (node_->prio == iter_->prio) \
|
||||
{ \
|
||||
FAR struct list_node *node_next_ = &head_->node_list; \
|
||||
\
|
||||
plist_del(node_, head_); \
|
||||
\
|
||||
plist_for_each_continue(iter_, head_) \
|
||||
{ \
|
||||
if (node_->prio != iter_->prio) \
|
||||
{ \
|
||||
node_next_ = &iter_->node_list; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
list_add_tail(node_next_, &node_->node_list); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#endif /* __INCLUDE_NUTTX_PLIST_H */
|
||||
Loading…
Add table
Add a link
Reference in a new issue