linux/drivers/cpufreq/amd-pstate.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * amd-pstate.c - AMD Processor P-state Frequency Driver
 *
 * Copyright (C) 2021 Advanced Micro Devices, Inc. All Rights Reserved.
 *
 * Author: Huang Rui <[email protected]>
 *
 * AMD P-State introduces a new CPU performance scaling design for AMD
 * processors using the ACPI Collaborative Performance and Power Control (CPPC)
 * feature which works with the AMD SMU firmware providing a finer grained
 * frequency control range. It is to replace the legacy ACPI P-States control,
 * allows a flexible, low-latency interface for the Linux kernel to directly
 * communicate the performance hints to hardware.
 *
 * AMD P-State is supported on recent AMD Zen base CPU series include some of
 * Zen2 and Zen3 processors. _CPC needs to be present in the ACPI tables of AMD
 * P-State supported system. And there are two types of hardware implementations
 * for AMD P-State: 1) Full MSR Solution and 2) Shared Memory Solution.
 * X86_FEATURE_CPPC CPU feature flag is used to distinguish the different types.
 */

#define pr_fmt(fmt)

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/sched.h>
#include <linux/cpufreq.h>
#include <linux/compiler.h>
#include <linux/dmi.h>
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/static_call.h>
#include <linux/topology.h>

#include <acpi/processor.h>
#include <acpi/cppc_acpi.h>

#include <asm/msr.h>
#include <asm/processor.h>
#include <asm/cpufeature.h>
#include <asm/cpu_device_id.h>

#include "amd-pstate.h"
#include "amd-pstate-trace.h"

#define AMD_PSTATE_TRANSITION_LATENCY
#define AMD_PSTATE_TRANSITION_DELAY
#define AMD_PSTATE_FAST_CPPC_TRANSITION_DELAY
#define CPPC_HIGHEST_PERF_PERFORMANCE
#define CPPC_HIGHEST_PERF_DEFAULT

#define AMD_CPPC_EPP_PERFORMANCE
#define AMD_CPPC_EPP_BALANCE_PERFORMANCE
#define AMD_CPPC_EPP_BALANCE_POWERSAVE
#define AMD_CPPC_EPP_POWERSAVE

/*
 * enum amd_pstate_mode - driver working mode of amd pstate
 */
enum amd_pstate_mode {};

static const char * const amd_pstate_mode_string[] =;

struct quirk_entry {};

static struct cpufreq_driver *current_pstate_driver;
static struct cpufreq_driver amd_pstate_driver;
static struct cpufreq_driver amd_pstate_epp_driver;
static int cppc_state =;
static bool cppc_enabled;
static bool amd_pstate_prefcore =;
static struct quirk_entry *quirks;

/*
 * AMD Energy Preference Performance (EPP)
 * The EPP is used in the CCLK DPM controller to drive
 * the frequency that a core is going to operate during
 * short periods of activity. EPP values will be utilized for
 * different OS profiles (balanced, performance, power savings)
 * display strings corresponding to EPP index in the
 * energy_perf_strings[]
 *	index		String
 *-------------------------------------
 *	0		default
 *	1		performance
 *	2		balance_performance
 *	3		balance_power
 *	4		power
 */
enum energy_perf_value_index {};

static const char * const energy_perf_strings[] =;

static unsigned int epp_values[] =;

cppc_mode_transition_fn;

static struct quirk_entry quirk_amd_7k62 =;

static int __init dmi_matched_7k62_bios_bug(const struct dmi_system_id *dmi)
{}

static const struct dmi_system_id amd_pstate_quirks_table[] __initconst =;
MODULE_DEVICE_TABLE(dmi, amd_pstate_quirks_table);

static inline int get_mode_idx_from_str(const char *str, size_t size)
{}

static DEFINE_MUTEX(amd_pstate_limits_lock);
static DEFINE_MUTEX(amd_pstate_driver_lock);

static s16 amd_pstate_get_epp(struct amd_cpudata *cpudata, u64 cppc_req_cached)
{}

static int amd_pstate_get_energy_pref_index(struct amd_cpudata *cpudata)
{}

static void pstate_update_perf(struct amd_cpudata *cpudata, u32 min_perf,
			       u32 des_perf, u32 max_perf, bool fast_switch)
{}

DEFINE_STATIC_CALL();

static inline void amd_pstate_update_perf(struct amd_cpudata *cpudata,
					  u32 min_perf, u32 des_perf,
					  u32 max_perf, bool fast_switch)
{}

static int amd_pstate_set_epp(struct amd_cpudata *cpudata, u32 epp)
{}

static int amd_pstate_set_energy_pref_index(struct amd_cpudata *cpudata,
		int pref_index)
{}

static inline int pstate_enable(bool enable)
{}

static int cppc_enable(bool enable)
{}

DEFINE_STATIC_CALL();

static inline int amd_pstate_enable(bool enable)
{}

static u32 amd_pstate_highest_perf_set(struct amd_cpudata *cpudata)
{}

static int pstate_init_perf(struct amd_cpudata *cpudata)
{}

static int cppc_init_perf(struct amd_cpudata *cpudata)
{}

DEFINE_STATIC_CALL();

static inline int amd_pstate_init_perf(struct amd_cpudata *cpudata)
{}

static void cppc_update_perf(struct amd_cpudata *cpudata,
			     u32 min_perf, u32 des_perf,
			     u32 max_perf, bool fast_switch)
{}

static inline bool amd_pstate_sample(struct amd_cpudata *cpudata)
{}

static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf,
			      u32 des_perf, u32 max_perf, bool fast_switch, int gov_flags)
{}

static int amd_pstate_verify(struct cpufreq_policy_data *policy)
{}

static int amd_pstate_update_min_max_limit(struct cpufreq_policy *policy)
{}

static int amd_pstate_update_freq(struct cpufreq_policy *policy,
				  unsigned int target_freq, bool fast_switch)
{}

static int amd_pstate_target(struct cpufreq_policy *policy,
			     unsigned int target_freq,
			     unsigned int relation)
{}

static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy,
				  unsigned int target_freq)
{}

static void amd_pstate_adjust_perf(unsigned int cpu,
				   unsigned long _min_perf,
				   unsigned long target_perf,
				   unsigned long capacity)
{}

static int amd_pstate_cpu_boost_update(struct cpufreq_policy *policy, bool on)
{}

static int amd_pstate_set_boost(struct cpufreq_policy *policy, int state)
{}

static int amd_pstate_init_boost_support(struct amd_cpudata *cpudata)
{}

static void amd_perf_ctl_reset(unsigned int cpu)
{}

/*
 * Set amd-pstate preferred core enable can't be done directly from cpufreq callbacks
 * due to locking, so queue the work for later.
 */
static void amd_pstste_sched_prefcore_workfn(struct work_struct *work)
{}
static DECLARE_WORK(sched_prefcore_work, amd_pstste_sched_prefcore_workfn);

/*
 * Get the highest performance register value.
 * @cpu: CPU from which to get highest performance.
 * @highest_perf: Return address.
 *
 * Return: 0 for success, -EIO otherwise.
 */
static int amd_pstate_get_highest_perf(int cpu, u32 *highest_perf)
{}

#define CPPC_MAX_PERF

static void amd_pstate_init_prefcore(struct amd_cpudata *cpudata)
{}

static void amd_pstate_update_limits(unsigned int cpu)
{}

/*
 * Get pstate transition delay time from ACPI tables that firmware set
 * instead of using hardcode value directly.
 */
static u32 amd_pstate_get_transition_delay_us(unsigned int cpu)
{}

/*
 * Get pstate transition latency value from ACPI tables that firmware
 * set instead of using hardcode value directly.
 */
static u32 amd_pstate_get_transition_latency(unsigned int cpu)
{}

/*
 * amd_pstate_init_freq: Initialize the max_freq, min_freq,
 *                       nominal_freq and lowest_nonlinear_freq for
 *                       the @cpudata object.
 *
 *  Requires: highest_perf, lowest_perf, nominal_perf and
 *            lowest_nonlinear_perf members of @cpudata to be
 *            initialized.
 *
 *  Returns 0 on success, non-zero value on failure.
 */
static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
{}

static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
{}

static void amd_pstate_cpu_exit(struct cpufreq_policy *policy)
{}

static int amd_pstate_cpu_resume(struct cpufreq_policy *policy)
{}

static int amd_pstate_cpu_suspend(struct cpufreq_policy *policy)
{}

/* Sysfs attributes */

/*
 * This frequency is to indicate the maximum hardware frequency.
 * If boost is not active but supported, the frequency will be larger than the
 * one in cpuinfo.
 */
static ssize_t show_amd_pstate_max_freq(struct cpufreq_policy *policy,
					char *buf)
{}

static ssize_t show_amd_pstate_lowest_nonlinear_freq(struct cpufreq_policy *policy,
						     char *buf)
{}

/*
 * In some of ASICs, the highest_perf is not the one in the _CPC table, so we
 * need to expose it to sysfs.
 */
static ssize_t show_amd_pstate_highest_perf(struct cpufreq_policy *policy,
					    char *buf)
{}

static ssize_t show_amd_pstate_prefcore_ranking(struct cpufreq_policy *policy,
						char *buf)
{}

static ssize_t show_amd_pstate_hw_prefcore(struct cpufreq_policy *policy,
					   char *buf)
{}

static ssize_t show_energy_performance_available_preferences(
				struct cpufreq_policy *policy, char *buf)
{}

static ssize_t store_energy_performance_preference(
		struct cpufreq_policy *policy, const char *buf, size_t count)
{}

static ssize_t show_energy_performance_preference(
				struct cpufreq_policy *policy, char *buf)
{}

static void amd_pstate_driver_cleanup(void)
{}

static int amd_pstate_register_driver(int mode)
{}

static int amd_pstate_unregister_driver(int dummy)
{}

static int amd_pstate_change_mode_without_dvr_change(int mode)
{}

static int amd_pstate_change_driver_mode(int mode)
{}

static cppc_mode_transition_fn mode_state_machine[AMD_PSTATE_MAX][AMD_PSTATE_MAX] =;

static ssize_t amd_pstate_show_status(char *buf)
{}

static int amd_pstate_update_status(const char *buf, size_t size)
{}

static ssize_t status_show(struct device *dev,
			   struct device_attribute *attr, char *buf)
{}

static ssize_t status_store(struct device *a, struct device_attribute *b,
			    const char *buf, size_t count)
{}

static ssize_t prefcore_show(struct device *dev,
			     struct device_attribute *attr, char *buf)
{}

cpufreq_freq_attr_ro();
cpufreq_freq_attr_ro();

cpufreq_freq_attr_ro();
cpufreq_freq_attr_ro();
cpufreq_freq_attr_ro();
cpufreq_freq_attr_rw();
cpufreq_freq_attr_ro();
static DEVICE_ATTR_RW(status);
static DEVICE_ATTR_RO(prefcore);

static struct freq_attr *amd_pstate_attr[] =;

static struct freq_attr *amd_pstate_epp_attr[] =;

static struct attribute *pstate_global_attributes[] =;

static const struct attribute_group amd_pstate_global_attr_group =;

static bool amd_pstate_acpi_pm_profile_server(void)
{}

static bool amd_pstate_acpi_pm_profile_undefined(void)
{}

static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
{}

static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
{}

static void amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
{}

static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
{}

static void amd_pstate_epp_reenable(struct amd_cpudata *cpudata)
{}

static int amd_pstate_epp_cpu_online(struct cpufreq_policy *policy)
{}

static void amd_pstate_epp_offline(struct cpufreq_policy *policy)
{}

static int amd_pstate_epp_cpu_offline(struct cpufreq_policy *policy)
{}

static int amd_pstate_epp_verify_policy(struct cpufreq_policy_data *policy)
{}

static int amd_pstate_epp_suspend(struct cpufreq_policy *policy)
{}

static int amd_pstate_epp_resume(struct cpufreq_policy *policy)
{}

static struct cpufreq_driver amd_pstate_driver =;

static struct cpufreq_driver amd_pstate_epp_driver =;

static int __init amd_pstate_set_driver(int mode_idx)
{}

/**
 * CPPC function is not supported for family ID 17H with model_ID ranging from 0x10 to 0x2F.
 * show the debug message that helps to check if the CPU has CPPC support for loading issue.
 */
static bool amd_cppc_supported(void)
{}

static int __init amd_pstate_init(void)
{}
device_initcall(amd_pstate_init);

static int __init amd_pstate_param(char *str)
{}

static int __init amd_prefcore_param(char *str)
{}

early_param();
early_param();

MODULE_AUTHOR();
MODULE_DESCRIPTION();