mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 02:01:36 +03:00
Bug 3680143 Change-Id: I1092b85239222b6af9a9ecfc536801f298706e60 Signed-off-by: Sanjay Chandrashekara <sanjayc@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2774586 Reviewed-by: Bitan Biswas <bbiswas@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
462 lines
10 KiB
C
462 lines
10 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
|
|
#include <linux/debugfs.h>
|
|
#include <linux/init.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform/tegra/tegra-mce.h>
|
|
#include <asm/smp_plat.h>
|
|
|
|
static struct tegra_mce_ops *mce_ops;
|
|
|
|
void tegra_mce_set_ops(struct tegra_mce_ops *tegra_mce_plat_ops)
|
|
{
|
|
mce_ops = tegra_mce_plat_ops;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_set_ops);
|
|
|
|
/**
|
|
* Specify power state and wake time for entering upon STANDBYWFI
|
|
*
|
|
* @state: requested core power state
|
|
* @wake_time: wake time in TSC ticks
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_enter_cstate(u32 state, u32 wake_time)
|
|
{
|
|
if (mce_ops && mce_ops->enter_cstate)
|
|
return mce_ops->enter_cstate(state, wake_time);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_enter_cstate);
|
|
|
|
/**
|
|
* Specify deepest cluster/ccplex/system states allowed.
|
|
*
|
|
* @cluster: deepest cluster-wide state
|
|
* @ccplex: deepest ccplex-wide state
|
|
* @system: deepest system-wide state
|
|
* @force: forced system state
|
|
* @wake_mask: wake mask to be updated
|
|
* @valid: is wake_mask applicable?
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_update_cstate_info(u32 cluster, u32 ccplex, u32 system,
|
|
u8 force, u32 wake_mask, bool valid)
|
|
{
|
|
if (mce_ops && mce_ops->update_cstate_info)
|
|
return mce_ops->update_cstate_info(cluster, ccplex, system,
|
|
force, wake_mask, valid);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_update_cstate_info);
|
|
|
|
/**
|
|
* Update threshold for one specific c-state crossover
|
|
*
|
|
* @type: type of state crossover.
|
|
* @time: idle time threshold.
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_update_crossover_time(u32 type, u32 time)
|
|
{
|
|
if (mce_ops && mce_ops->update_crossover_time)
|
|
return mce_ops->update_crossover_time(type, time);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_update_crossover_time);
|
|
|
|
/**
|
|
* Query the runtime stats of a specific cstate
|
|
*
|
|
* @state: c-state of the stats.
|
|
* @stats: output integer to hold the stats.
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_read_cstate_stats(u32 state, u64 *stats)
|
|
{
|
|
if (mce_ops && mce_ops->read_cstate_stats)
|
|
return mce_ops->read_cstate_stats(state, stats);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_read_cstate_stats);
|
|
|
|
/**
|
|
* Overwrite the runtime stats of a specific c-state
|
|
*
|
|
* @state: c-state of the stats.
|
|
* @stats: integer represents the new stats.
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_write_cstate_stats(u32 state, u32 stats)
|
|
{
|
|
if (mce_ops && mce_ops->write_cstate_stats)
|
|
return mce_ops->write_cstate_stats(state, stats);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_write_cstate_stats);
|
|
|
|
/**
|
|
* Query MCE to determine if SC7 is allowed
|
|
* given a target core's C-state and wake time
|
|
*
|
|
* @state: c-state of the stats.
|
|
* @stats: integer represents the new stats.
|
|
* @allowed: pointer to result
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_is_sc7_allowed(u32 state, u32 wake, u32 *allowed)
|
|
{
|
|
if (mce_ops && mce_ops->is_sc7_allowed)
|
|
return mce_ops->is_sc7_allowed(state, wake, allowed);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_is_sc7_allowed);
|
|
|
|
/**
|
|
* Bring another offlined core back online to C0 state.
|
|
*
|
|
* @cpu: logical cpuid from smp_processor_id()
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_online_core(int cpu)
|
|
{
|
|
if (mce_ops && mce_ops->online_core)
|
|
return mce_ops->online_core(cpu);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_online_core);
|
|
|
|
/**
|
|
* Program Auto-CC3 feature.
|
|
*
|
|
* @ndiv: ndiv of IDLE voltage/freq register
|
|
* @vindex: vindex of IDLE voltage/freq register
|
|
* (Not used on tegra19x)
|
|
* @enable: enable bit for Auto-CC3
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_cc3_ctrl(u32 ndiv, u32 vindex, u8 enable)
|
|
{
|
|
if (mce_ops && mce_ops->cc3_ctrl)
|
|
return mce_ops->cc3_ctrl(ndiv, vindex, enable);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_cc3_ctrl);
|
|
|
|
/**
|
|
* Send data to MCE which echoes it back.
|
|
*
|
|
* @data: data to be sent to MCE.
|
|
* @out: output data to hold the response.
|
|
* @matched: pointer to matching result
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_echo_data(u64 data, u64 *matched)
|
|
{
|
|
if (mce_ops && mce_ops->echo_data)
|
|
return mce_ops->echo_data(data, matched);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_echo_data);
|
|
|
|
/**
|
|
* Read out MCE API major/minor versions
|
|
*
|
|
* @major: output for major number.
|
|
* @minor: output for minor number.
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_read_versions(u32 *major, u32 *minor)
|
|
{
|
|
if (mce_ops && mce_ops->read_versions)
|
|
return mce_ops->read_versions(major, minor);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_read_versions);
|
|
|
|
/**
|
|
* Read out RT Safe Mask
|
|
*
|
|
* @rt_safe_mask: output for rt safe mask.
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_read_rt_safe_mask(u64 *rt_safe_mask)
|
|
{
|
|
if (mce_ops && mce_ops->read_rt_safe_mask)
|
|
return mce_ops->read_rt_safe_mask(rt_safe_mask);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_read_rt_safe_mask);
|
|
|
|
/**
|
|
* Write RT Safe Mask
|
|
*
|
|
* @rt_safe_mask: rt safe mask value to be written
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_write_rt_safe_mask(u64 rt_safe_mask)
|
|
{
|
|
if (mce_ops && mce_ops->write_rt_safe_mask)
|
|
return mce_ops->write_rt_safe_mask(rt_safe_mask);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_write_rt_safe_mask);
|
|
|
|
/**
|
|
* Read out RT Window US
|
|
*
|
|
* @rt_window_us: output for rt window us
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_read_rt_window_us(u64 *rt_window_us)
|
|
{
|
|
if (mce_ops && mce_ops->read_rt_window_us)
|
|
return mce_ops->read_rt_window_us(rt_window_us);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_read_rt_window_us);
|
|
|
|
|
|
/**
|
|
* Write RT Window US
|
|
*
|
|
* @rt_window_us: rt window us value to be written
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_write_rt_window_us(u64 rt_window_us)
|
|
{
|
|
if (mce_ops && mce_ops->write_rt_window_us)
|
|
return mce_ops->write_rt_window_us(rt_window_us);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_write_rt_window_us);
|
|
|
|
|
|
/**
|
|
* Read out RT Fwd Progress US
|
|
*
|
|
* @rt_fwd_progress_us: output for rt fwd progress us
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_read_rt_fwd_progress_us(u64 *rt_fwd_progress_us)
|
|
{
|
|
if (mce_ops && mce_ops->read_rt_fwd_progress_us)
|
|
return mce_ops->read_rt_fwd_progress_us(rt_fwd_progress_us);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_read_rt_fwd_progress_us);
|
|
|
|
|
|
/**
|
|
* Write RT Fwd Progress US
|
|
*
|
|
* @rt_fwd_progress_us: rt fwd progress us value to be written
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_write_rt_fwd_progress_us(u64 rt_fwd_progress_us)
|
|
{
|
|
if (mce_ops && mce_ops->write_rt_fwd_progress_us)
|
|
return mce_ops->write_rt_fwd_progress_us(rt_fwd_progress_us);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_write_rt_fwd_progress_us);
|
|
|
|
|
|
/**
|
|
* Enumerate MCE API features
|
|
*
|
|
* @features: output feature vector (4bits each)
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_enum_features(u64 *features)
|
|
{
|
|
if (mce_ops && mce_ops->enum_features)
|
|
return mce_ops->enum_features(features);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_enum_features);
|
|
|
|
/**
|
|
* Read uncore MCA errors.
|
|
*
|
|
* @cmd: MCA command
|
|
* @data: output data for the command
|
|
* @error: error from MCA
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_read_uncore_mca(mca_cmd_t cmd, u64 *data, u32 *error)
|
|
{
|
|
if (mce_ops && mce_ops->read_uncore_mca)
|
|
return mce_ops->read_uncore_mca(cmd, data, error);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_read_uncore_mca);
|
|
|
|
/**
|
|
* Write uncore MCA errors.
|
|
*
|
|
* @cmd: MCA command
|
|
* @data: input data for the command
|
|
* @error: error from MCA
|
|
*
|
|
* Returns 0 if success.
|
|
*/
|
|
int tegra_mce_write_uncore_mca(mca_cmd_t cmd, u64 data, u32 *error)
|
|
{
|
|
if (mce_ops && mce_ops->write_uncore_mca)
|
|
return mce_ops->write_uncore_mca(cmd, data, error);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_write_uncore_mca);
|
|
|
|
/**
|
|
* Query PMU for uncore perfmon counter
|
|
*
|
|
* @req input command and counter index
|
|
* @data output counter value
|
|
*
|
|
* Returns status of read request.
|
|
*/
|
|
int tegra_mce_read_uncore_perfmon(u32 req, u32 *data)
|
|
{
|
|
if (mce_ops && mce_ops->read_uncore_perfmon)
|
|
return mce_ops->read_uncore_perfmon(req, data);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_read_uncore_perfmon);
|
|
|
|
/**
|
|
* Write PMU reg for uncore perfmon counter
|
|
*
|
|
* @req input command and counter index
|
|
* @data data to be written
|
|
*
|
|
* Returns status of write request.
|
|
*/
|
|
int tegra_mce_write_uncore_perfmon(u32 req, u32 data)
|
|
{
|
|
if (mce_ops && mce_ops->write_uncore_perfmon)
|
|
return mce_ops->write_uncore_perfmon(req, data);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_write_uncore_perfmon);
|
|
|
|
int tegra_mce_enable_latic(void)
|
|
{
|
|
if (mce_ops && mce_ops->enable_latic)
|
|
return mce_ops->enable_latic();
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_enable_latic);
|
|
|
|
/**
|
|
* Write to NVG DDA registers
|
|
*
|
|
* @index: NVG communication channel id
|
|
* @value: Register value to be written
|
|
*
|
|
* Returns 0 on success
|
|
*/
|
|
int tegra_mce_write_dda_ctrl(u32 index, u64 value)
|
|
{
|
|
if(mce_ops && mce_ops->write_dda_ctrl)
|
|
return mce_ops->write_dda_ctrl(index, value);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_write_dda_ctrl);
|
|
|
|
/**
|
|
* Read NVG DDA registers
|
|
*
|
|
* @index: NVG communication channel id
|
|
* @value: Associated register value read
|
|
*
|
|
* Returns 0 on success
|
|
*/
|
|
int tegra_mce_read_dda_ctrl(u32 index, u64 *value)
|
|
{
|
|
if(mce_ops && mce_ops->read_dda_ctrl)
|
|
return mce_ops->read_dda_ctrl(index, value);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_read_dda_ctrl);
|
|
|
|
/**
|
|
* Read NVG L3 cache control register
|
|
*
|
|
* @value: Fill L3 cache ways
|
|
*
|
|
* Returns 0 on success
|
|
*/
|
|
int tegra_mce_read_l3_cache_ways(u64 *value)
|
|
{
|
|
if (mce_ops && mce_ops->read_l3_cache_ways)
|
|
return mce_ops->read_l3_cache_ways(value);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_read_l3_cache_ways);
|
|
|
|
/**
|
|
* Write L3 cache ways and read back the l3 cache ways written
|
|
*
|
|
* @data: L3 cache ways to be writtein
|
|
* @value: L3 cache ways returrned back
|
|
*
|
|
* Returns 0 on success
|
|
*/
|
|
int tegra_mce_write_l3_cache_ways(u64 data, u64 *value)
|
|
{
|
|
if (mce_ops && mce_ops->write_l3_cache_ways)
|
|
return mce_ops->write_l3_cache_ways(data, value);
|
|
else
|
|
return -ENOTSUPP;
|
|
}
|
|
EXPORT_SYMBOL_GPL(tegra_mce_write_l3_cache_ways);
|
|
|
|
MODULE_AUTHOR("NVIDIA Corporation");
|
|
MODULE_LICENSE("GPL v2");
|