devfreq: use conftest for conditional module build

Some distros might use old kernel source but with some latest upstream
kernel patches backported to their kernel source tree. To deal with this
scenario and avoid kernel compilation failure, use conftest to check the
existence of features against the kernel source tree which the OOT
modules are built upon and do the conditional build based on the test
result generated with the conftest tool.

Use NV_DEVFREQ_HAS_FREQ_TABLE to determine whether freq_table field is
there in struct devfreq data strcuture, and choose the correct path for
building the module.

Use tegra_wmark-specific devfreq_get_freq_range always to avoid kernel
version check and conftest check. Since devfreq_get_freq_range exists in
the devfreq-specific governor.h (e.g. drivers/devfreq/governor.h) file
instead of globabl linux kernel include header files
(e.g. include/linux/devfreq.h), conftest cannot be used to the existence
of devfreq_get_freq_range kernel function.

Bug 4884092

Change-Id: I5bde4c712f59f38de74c1d8d95135c9b25d621b1
Signed-off-by: Johnny Liu <johnliu@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3220896
Tested-by: Paritosh Dixit <paritoshd@nvidia.com>
GVS: buildbot_gerritrpt <buildbot_gerritrpt@nvidia.com>
Reviewed-by: Jon Hunter <jonathanh@nvidia.com>
This commit is contained in:
Johnny Liu
2024-09-30 06:21:03 +00:00
committed by mobile promotions
parent b2db309d50
commit c580fd0d06
2 changed files with 25 additions and 151 deletions

View File

@@ -1,8 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only
/* /*
* Copyright (c) 2023, NVIDIA Corporation. All rights reserved. * SPDX-FileCopyrightText: Copyright (c) 2023-2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/ */
#include <nvidia/conftest.h>
#include <linux/devfreq.h> #include <linux/devfreq.h>
#include <linux/devfreq/tegra_wmark.h> #include <linux/devfreq/tegra_wmark.h>
#include <linux/device.h> #include <linux/device.h>
@@ -13,11 +15,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0)
#include <drivers-private/devfreq/k519/governor.h>
#else
#include <drivers-private/devfreq/governor.h> #include <drivers-private/devfreq/governor.h>
#endif
/** /**
* struct tegra_wmark_data - governor private data stored in struct devfreq * struct tegra_wmark_data - governor private data stored in struct devfreq
@@ -65,12 +63,12 @@ struct tegra_wmark_data {
static int devfreq_get_freq_index(struct devfreq *df, unsigned long freq) static int devfreq_get_freq_index(struct devfreq *df, unsigned long freq)
{ {
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0) #if defined(NV_DEVFREQ_HAS_FREQ_TABLE)
unsigned long *freq_table = df->profile->freq_table;
unsigned int max_state = df->profile->max_state;
#else
unsigned long *freq_table = df->freq_table; unsigned long *freq_table = df->freq_table;
unsigned int max_state = df->max_state; unsigned int max_state = df->max_state;
#else
unsigned long *freq_table = df->profile->freq_table;
unsigned int max_state = df->profile->max_state;
#endif #endif
int i; int i;
@@ -86,12 +84,12 @@ static int devfreq_tegra_wmark_target_freq(struct devfreq *df, unsigned long *fr
{ {
struct tegra_wmark_data *govdata = df->governor_data; struct tegra_wmark_data *govdata = df->governor_data;
struct devfreq_tegra_wmark_data *drvdata = df->data; struct devfreq_tegra_wmark_data *drvdata = df->data;
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0) #if defined(NV_DEVFREQ_HAS_FREQ_TABLE)
unsigned long *freq_table = df->profile->freq_table;
unsigned int max_state = df->profile->max_state;
#else
unsigned long *freq_table = df->freq_table; unsigned long *freq_table = df->freq_table;
unsigned int max_state = df->max_state; unsigned int max_state = df->max_state;
#else
unsigned long *freq_table = df->profile->freq_table;
unsigned int max_state = df->profile->max_state;
#endif #endif
int target_index = 0; int target_index = 0;
@@ -119,7 +117,6 @@ static int devfreq_tegra_wmark_target_freq(struct devfreq *df, unsigned long *fr
return 0; return 0;
} }
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0)
static s32 devfreq_pm_qos_read_value(struct devfreq *df, enum dev_pm_qos_req_type type) static s32 devfreq_pm_qos_read_value(struct devfreq *df, enum dev_pm_qos_req_type type)
{ {
struct device *dev = df->dev.parent; struct device *dev = df->dev.parent;
@@ -153,8 +150,13 @@ static void devfreq_get_freq_range(struct devfreq *df,
{ {
s32 qos_min_freq, qos_max_freq; s32 qos_min_freq, qos_max_freq;
#if defined(NV_DEVFREQ_HAS_FREQ_TABLE)
*min_freq = df->freq_table[0];
*max_freq = df->freq_table[df->max_state - 1];
#else
*min_freq = df->profile->freq_table[0]; *min_freq = df->profile->freq_table[0];
*max_freq = df->profile->freq_table[df->profile->max_state - 1]; *max_freq = df->profile->freq_table[df->profile->max_state - 1];
#endif
qos_min_freq = devfreq_pm_qos_read_value(df, DEV_PM_QOS_MIN_FREQUENCY); qos_min_freq = devfreq_pm_qos_read_value(df, DEV_PM_QOS_MIN_FREQUENCY);
qos_max_freq = devfreq_pm_qos_read_value(df, DEV_PM_QOS_MAX_FREQUENCY); qos_max_freq = devfreq_pm_qos_read_value(df, DEV_PM_QOS_MAX_FREQUENCY);
@@ -168,7 +170,6 @@ static void devfreq_get_freq_range(struct devfreq *df,
*min_freq = max(*min_freq, df->scaling_min_freq); *min_freq = max(*min_freq, df->scaling_min_freq);
*max_freq = min(*max_freq, df->scaling_max_freq); *max_freq = min(*max_freq, df->scaling_max_freq);
} }
#endif
static void devfreq_update_wmark_threshold(struct devfreq *df) static void devfreq_update_wmark_threshold(struct devfreq *df)
{ {
@@ -176,10 +177,10 @@ static void devfreq_update_wmark_threshold(struct devfreq *df)
struct devfreq_tegra_wmark_data *drvdata = df->data; struct devfreq_tegra_wmark_data *drvdata = df->data;
struct devfreq_tegra_wmark_config wmark_config; struct devfreq_tegra_wmark_config wmark_config;
unsigned long curr_freq, prev_freq, min_freq, max_freq; unsigned long curr_freq, prev_freq, min_freq, max_freq;
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0) #if defined(NV_DEVFREQ_HAS_FREQ_TABLE)
unsigned long *freq_table = df->profile->freq_table;
#else
unsigned long *freq_table = df->freq_table; unsigned long *freq_table = df->freq_table;
#else
unsigned long *freq_table = df->profile->freq_table;
#endif #endif
int err; int err;
@@ -225,10 +226,10 @@ static ssize_t up_freq_margin_store(struct device *dev,
struct devfreq *df = to_devfreq(dev); struct devfreq *df = to_devfreq(dev);
struct tegra_wmark_data *govdata; struct tegra_wmark_data *govdata;
unsigned int freq_margin; unsigned int freq_margin;
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0) #if defined(NV_DEVFREQ_HAS_FREQ_TABLE)
unsigned int max_state = df->profile->max_state;
#else
unsigned int max_state = df->max_state; unsigned int max_state = df->max_state;
#else
unsigned int max_state = df->profile->max_state;
#endif #endif
int ret; int ret;
@@ -270,10 +271,10 @@ static ssize_t down_freq_margin_store(struct device *dev,
struct devfreq *df = to_devfreq(dev); struct devfreq *df = to_devfreq(dev);
struct tegra_wmark_data *govdata; struct tegra_wmark_data *govdata;
unsigned int freq_margin; unsigned int freq_margin;
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0) #if defined(NV_DEVFREQ_HAS_FREQ_TABLE)
unsigned int max_state = df->profile->max_state;
#else
unsigned int max_state = df->max_state; unsigned int max_state = df->max_state;
#else
unsigned int max_state = df->profile->max_state;
#endif #endif
int ret; int ret;

View File

@@ -1,127 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* governor.h - internal header for devfreq governors.
*
* Copyright (C) 2011 Samsung Electronics
* MyungJoo Ham <myungjoo.ham@samsung.com>
*
* This header is for devfreq governors in drivers/devfreq/
*/
#ifndef _GOVERNOR_H
#define _GOVERNOR_H
#include <linux/devfreq.h>
#define DEVFREQ_NAME_LEN 16
#define to_devfreq(DEV) container_of((DEV), struct devfreq, dev)
/* Devfreq events */
#define DEVFREQ_GOV_START 0x1
#define DEVFREQ_GOV_STOP 0x2
#define DEVFREQ_GOV_UPDATE_INTERVAL 0x3
#define DEVFREQ_GOV_SUSPEND 0x4
#define DEVFREQ_GOV_RESUME 0x5
#define DEVFREQ_MIN_FREQ 0
#define DEVFREQ_MAX_FREQ ULONG_MAX
/*
* Definition of the governor feature flags
* - DEVFREQ_GOV_FLAG_IMMUTABLE
* : This governor is never changeable to other governors.
* - DEVFREQ_GOV_FLAG_IRQ_DRIVEN
* : The devfreq won't schedule the work for this governor.
*/
#define DEVFREQ_GOV_FLAG_IMMUTABLE BIT(0)
#define DEVFREQ_GOV_FLAG_IRQ_DRIVEN BIT(1)
/*
* Definition of governor attribute flags except for common sysfs attributes
* - DEVFREQ_GOV_ATTR_POLLING_INTERVAL
* : Indicate polling_interval sysfs attribute
* - DEVFREQ_GOV_ATTR_TIMER
* : Indicate timer sysfs attribute
*/
#define DEVFREQ_GOV_ATTR_POLLING_INTERVAL BIT(0)
#define DEVFREQ_GOV_ATTR_TIMER BIT(1)
/**
* struct devfreq_cpu_data - Hold the per-cpu data
* @node: list node
* @dev: reference to cpu device.
* @first_cpu: the cpumask of the first cpu of a policy.
* @opp_table: reference to cpu opp table.
* @cur_freq: the current frequency of the cpu.
* @min_freq: the min frequency of the cpu.
* @max_freq: the max frequency of the cpu.
*
* This structure stores the required cpu_data of a cpu.
* This is auto-populated by the governor.
*/
struct devfreq_cpu_data {
struct list_head node;
struct device *dev;
unsigned int first_cpu;
struct opp_table *opp_table;
unsigned int cur_freq;
unsigned int min_freq;
unsigned int max_freq;
};
/**
* struct devfreq_governor - Devfreq policy governor
* @node: list node - contains registered devfreq governors
* @name: Governor's name
* @attrs: Governor's sysfs attribute flags
* @flags: Governor's feature flags
* @get_target_freq: Returns desired operating frequency for the device.
* Basically, get_target_freq will run
* devfreq_dev_profile.get_dev_status() to get the
* status of the device (load = busy_time / total_time).
* @event_handler: Callback for devfreq core framework to notify events
* to governors. Events include per device governor
* init and exit, opp changes out of devfreq, suspend
* and resume of per device devfreq during device idle.
*
* Note that the callbacks are called with devfreq->lock locked by devfreq.
*/
struct devfreq_governor {
struct list_head node;
const char name[DEVFREQ_NAME_LEN];
const u64 attrs;
const u64 flags;
int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
int (*event_handler)(struct devfreq *devfreq,
unsigned int event, void *data);
};
void devfreq_monitor_start(struct devfreq *devfreq);
void devfreq_monitor_stop(struct devfreq *devfreq);
void devfreq_monitor_suspend(struct devfreq *devfreq);
void devfreq_monitor_resume(struct devfreq *devfreq);
void devfreq_update_interval(struct devfreq *devfreq, unsigned int *delay);
int devfreq_add_governor(struct devfreq_governor *governor);
int devfreq_remove_governor(struct devfreq_governor *governor);
int devm_devfreq_add_governor(struct device *dev,
struct devfreq_governor *governor);
int devfreq_update_status(struct devfreq *devfreq, unsigned long freq);
int devfreq_update_target(struct devfreq *devfreq, unsigned long freq);
void devfreq_get_freq_range(struct devfreq *devfreq, unsigned long *min_freq,
unsigned long *max_freq);
static inline int devfreq_update_stats(struct devfreq *df)
{
if (!df->profile->get_dev_status)
return -EINVAL;
return df->profile->get_dev_status(df->dev.parent, &df->last_status);
}
#endif /* _GOVERNOR_H */