// SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. #include #include #include #include #include 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");