1
0
mirror of https://github.com/physwizz/a155-U-u1.git synced 2024-11-19 13:27:49 +00:00
a155-U-u1/kernel-5.10/drivers/misc/mediatek/qos/mtk_qos_bound.c
2024-03-11 06:53:12 +11:00

325 lines
7.1 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <linux/io.h>
#include <linux/notifier.h>
#include "mtk_qos_bound.h"
#include "mtk_qos_ipi.h"
#include "mtk_qos_common.h"
#include <sspm_define.h>
#include <sspm_reservedmem.h>
#include <sspm_reservedmem_define.h>
#if IS_ENABLED(CONFIG_INTERCONNECT_MTK_MMQOS_COMMON)
#include <soc/mediatek/mmqos.h>
#endif /* CONFIG_INTERCONNECT_MTK_MMQOS_COMMON */
#if IS_ENABLED(CONFIG_MTK_DRAMC)
#include <soc/mediatek/dramc.h>
#endif /* CONFIG_MTK_DRAMC */
#if IS_ENABLED(CONFIG_MTK_EMI)
#include <soc/mediatek/emi.h>
#endif /* CONFIG_MTK_EMI */
static int qos_bound_enabled;
static int qos_bound_stress_enabled;
static int qos_bound_log_enabled;
static unsigned int qos_bound_count;
static unsigned int qos_bound_buf[3];
static BLOCKING_NOTIFIER_HEAD(qos_bound_chain_head);
static struct qos_bound *bound;
static unsigned short *qos_bound_apu;
static unsigned int qos_bound_apu_num;
int is_qos_bound_enabled(void)
{
return qos_bound_enabled;
}
void qos_bound_enable(int enable)
{
#if IS_ENABLED(CONFIG_MTK_TINYSYS_SSPM_V2)
struct qos_ipi_data qos_ipi_d;
if (!is_mtk_qos_enable())
return;
qos_ipi_d.cmd = QOS_IPI_QOS_BOUND_ENABLE;
qos_ipi_d.u.qos_bound_enable.enable = enable;
bound = (struct qos_bound *)
sspm_sbuf_get(qos_ipi_to_sspm_command(&qos_ipi_d, 2));
smp_mb(); /* init bound before flag enabled */
#elif defined(MTK_SCMI)
struct qos_ipi_data qos_ipi_d;
int ack;
if (!is_mtk_qos_enable())
return;
qos_ipi_d.cmd = QOS_IPI_QOS_BOUND_ENABLE;
qos_ipi_d.u.qos_bound_enable.enable = enable;
ack = qos_ipi_to_sspm_scmi_command(qos_ipi_d.cmd,
qos_ipi_d.u.qos_bound_enable.enable, 0, 0, QOS_IPI_SCMI_GET);
if (!ack || ack == -1) {
pr_info("get qos sspm address fail\n");
return;
}
bound = (struct qos_bound *)sspm_sbuf_get(ack);
if (bound == NULL) {
pr_info("mtk_qos: sspm_sbuf_get fail\n");
return;
}
smp_mb(); /* init bound before flag enabled */
#endif
if (bound->ver == QOS_BOUND_VER_TAG) {
qos_bound_apu = (unsigned short *)(bound);
qos_bound_apu += (sizeof(struct qos_bound)/sizeof(unsigned short));
qos_bound_apu_num = bound->apu_num;
pr_info("mtk_qos: bound ver=0x%x apu_num=%d\n",
bound->ver, bound->apu_num);
qos_bound_enabled = enable;
} else {
pr_info("mtk_qos: invalid bound version(0x%x, 0x%x)\n",
bound->ver, bound->apu_num);
qos_bound_enabled = false;
}
}
int is_qos_bound_stress_enabled(void)
{
return qos_bound_stress_enabled;
}
void qos_bound_stress_enable(int enable)
{
#if IS_ENABLED(CONFIG_MTK_TINYSYS_SSPM_V2)
struct qos_ipi_data qos_ipi_d;
if (!is_mtk_qos_enable())
return;
qos_ipi_d.cmd = QOS_IPI_QOS_BOUND_STRESS_ENABLE;
qos_ipi_d.u.qos_bound_stress_enable.enable = enable;
qos_ipi_to_sspm_command(&qos_ipi_d, 2);
#elif defined(MTK_SCMI)
struct qos_ipi_data qos_ipi_d;
if (!is_mtk_qos_enable())
return;
qos_ipi_d.cmd = QOS_IPI_QOS_BOUND_STRESS_ENABLE;
qos_ipi_d.u.qos_bound_stress_enable.enable = enable;
//qos_ipi_to_sspm_command(&qos_ipi_d, 2);
qos_ipi_to_sspm_scmi_command(qos_ipi_d.cmd,
qos_ipi_d.u.qos_bound_stress_enable.enable, 0, 0, 0);
#endif
qos_bound_stress_enabled = enable;
}
int is_qos_bound_log_enabled(void)
{
return qos_bound_log_enabled;
}
void qos_bound_log_enable(int enable)
{
qos_bound_log_enabled = enable;
}
unsigned int get_qos_bound_count(void)
{
return qos_bound_count;
}
EXPORT_SYMBOL_GPL(get_qos_bound_count);
unsigned int *get_qos_bound_buf(void)
{
return qos_bound_buf;
}
EXPORT_SYMBOL_GPL(get_qos_bound_buf);
void qos_bound_init(void)
{
qos_bound_enable(1);
}
struct qos_bound *get_qos_bound(void)
{
return bound;
}
EXPORT_SYMBOL_GPL(get_qos_bound);
int get_qos_bound_bw_threshold(int state)
{
int val = 0;
#if IS_ENABLED(CONFIG_MTK_DRAMC) && IS_ENABLED(CONFIG_MTK_EMI)
val = mtk_dramc_get_steps_freq(0) * mtk_emicen_get_ch_cnt() * 2;
#endif
if (state == QOS_BOUND_BW_FULL)
return val * QOS_BOUND_BW_FULL_PCT / 100;
else if (state == QOS_BOUND_BW_CONGESTIVE)
return val * QOS_BOUND_BW_CONGESTIVE_PCT / 100;
return 0;
}
EXPORT_SYMBOL(get_qos_bound_bw_threshold);
unsigned short get_qos_bound_idx(void)
{
if (!is_qos_bound_enabled())
return 0;
return bound->idx;
}
EXPORT_SYMBOL(get_qos_bound_idx);
int register_qos_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&qos_bound_chain_head, nb);
}
EXPORT_SYMBOL(register_qos_notifier);
int unregister_qos_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&qos_bound_chain_head, nb);
}
EXPORT_SYMBOL(unregister_qos_notifier);
int qos_notifier_call_chain(unsigned long val, void *v)
{
int ret = NOTIFY_DONE;
struct qos_bound *bound;
struct qos_bound_stat *stat;
unsigned short idx, state;
int i;
if (!is_qos_bound_enabled())
return ret;
if (v == NULL) {
pr_info("detect bound null ptr(%d)\n",
is_qos_bound_enabled());
return ret;
}
bound = (struct qos_bound *) v;
state = bound->state;
if (state > 0 && state <= 4) {
for (i = 0; (state & (1 << i)) == 0; i++)
;
qos_bound_count++;
qos_bound_buf[i]++;
}
#if IS_ENABLED(CONFIG_INTERCONNECT_MTK_MMQOS_COMMON)
mtk_mmqos_system_qos_update(state);
#endif
if (is_qos_bound_log_enabled()) {
idx = bound->idx;
stat = &bound->stats[bound->idx];
pr_info("idx: %hu, state: %hu, num: %hu, event: %hu\n",
idx, state,
stat->num, stat->event);
for (i = 0; i < NR_QOS_EMIBM_TYPE; i++)
pr_info("emibw [%d]: mon: %hu\n", i,
stat->emibw_mon[i]);
for (i = 0; i < NR_QOS_SMIBM_TYPE; i++)
pr_info("smibw [%d]: mon: %hu\n", i,
stat->smibw_mon[i]);
}
ret = blocking_notifier_call_chain(&qos_bound_chain_head, val, v);
return notifier_to_errno(ret);
}
unsigned short get_qos_bound_apubw_mon(int idx, int master)
{
unsigned short *bw_val;
if (!is_qos_bound_enabled())
return 0;
if (idx < 0 || idx >= QOS_BOUND_BUF_SIZE)
idx = bound->idx;
if (master < 0 || master >= qos_bound_apu_num)
return 0;
bw_val = qos_bound_apu + (master + idx*qos_bound_apu_num);
return *bw_val;
}
EXPORT_SYMBOL_GPL(get_qos_bound_apubw_mon);
unsigned short get_qos_bound_apulat_mon(int idx, int master)
{
unsigned short *lat_val;
if (!is_qos_bound_enabled())
return 0;
if (idx < 0 || idx >= QOS_BOUND_BUF_SIZE)
idx = bound->idx;
if (master < 0 || master >= qos_bound_apu_num)
return 0;
lat_val = qos_bound_apu + QOS_BOUND_BUF_SIZE*qos_bound_apu_num;
lat_val += (master + idx*qos_bound_apu_num);
return *lat_val;
}
EXPORT_SYMBOL_GPL(get_qos_bound_apulat_mon);
unsigned short get_qos_bound_emibw_mon(int idx, int master)
{
unsigned short val = 0;
if (!is_qos_bound_enabled())
return 0;
if (idx < 0 || idx >= QOS_BOUND_BUF_SIZE)
idx = bound->idx;
if (master < 0 || master >= NR_QOS_EMIBM_TYPE)
master = 0;
if (idx >= 0)
val = bound->stats[idx].emibw_mon[master];
return val;
}
EXPORT_SYMBOL_GPL(get_qos_bound_emibw_mon);
unsigned short get_qos_bound_smibw_mon(int idx, int master)
{
unsigned short val = 0;
if (!is_qos_bound_enabled())
return 0;
if (idx < 0 || idx >= QOS_BOUND_BUF_SIZE)
idx = bound->idx;
if (master < 0 || master >= NR_QOS_SMIBM_TYPE)
master = 0;
if (idx >= 0)
val = bound->stats[idx].smibw_mon[master];
return val;
}
EXPORT_SYMBOL_GPL(get_qos_bound_smibw_mon);