soc: qcom: ddr_stats: Add API to get bandwidth vote on ddr

This change implements API to get bandwidth vote on DDR by
various subsystem.

Change-Id: I798fc6cf8e6035f6f5b54fa8d4f4650dc1a2b24e
Signed-off-by: Tushar Nimkar <tnimkar@codeaurora.org>
This commit is contained in:
Tushar Nimkar 2021-05-06 13:24:15 +05:30
commit 86f4115ac2
2 changed files with 90 additions and 1 deletions

View file

@ -9,6 +9,8 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/mailbox_client.h>
#include <linux/mailbox/qmp.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/types.h>
@ -22,6 +24,12 @@
#define MAGIC_KEY1 0xA1157A75
#define MAX_NUM_MODES 0x14
#define MSM_ARCH_TIMER_FREQ 19200000
#define MAX_DRV 18
#define MAX_MSG_LEN 35
#define DRV_ABSENT 0xdeaddead
#define DRV_INVALID 0xffffdead
#define VOTE_MASK 0x3fff
#define VOTE_X_SHIFT 14
#define GET_PDATA_OF_ATTR(attr) \
(container_of(attr, struct ddr_stats_kobj_attr, ka)->pd)
@ -41,7 +49,10 @@ struct ddr_stats_platform_data {
void __iomem *reg;
int freq_count;
int entry_count;
bool read_ddr_vote;
struct mutex ddr_stats_lock;
struct mbox_client stats_mbox_cl;
struct mbox_chan *stats_mbox_ch;
};
struct stats_entry {
@ -199,6 +210,64 @@ int ddr_stats_get_residency(int freq_count, struct ddr_freq_residency *data)
}
EXPORT_SYMBOL(ddr_stats_get_residency);
int ddr_stats_get_ss_count(void)
{
return ddr_pdata->read_ddr_vote ? MAX_DRV : -EOPNOTSUPP;
}
EXPORT_SYMBOL(ddr_stats_get_ss_count);
int ddr_stats_get_ss_vote_info(int ss_count,
struct ddr_stats_ss_vote_info *vote_info)
{
char buf[MAX_MSG_LEN] = {};
struct qmp_pkt pkt;
void __iomem *reg;
u32 vote_offset, val[MAX_DRV];
int ret, i;
if (!ddr_pdata->read_ddr_vote)
return -EOPNOTSUPP;
if (!vote_info || !(ss_count == MAX_DRV) || !ddr_pdata)
return -ENODEV;
mutex_lock(&ddr_pdata->ddr_stats_lock);
ret = scnprintf(buf, MAX_MSG_LEN, "{class: ddr, res: drvs_ddr_votes}");
pkt.size = (ret + 0x3) & ~0x3;
pkt.data = buf;
ret = mbox_send_message(ddr_pdata->stats_mbox_ch, &pkt);
if (ret < 0) {
pr_err("Error sending mbox message: %d\n", ret);
mutex_unlock(&ddr_pdata->ddr_stats_lock);
return ret;
}
vote_offset = sizeof(u32) + sizeof(u32) +
(ddr_pdata->entry_count * sizeof(struct stats_entry));
reg = ddr_pdata->reg;
for (i = 0; i < ss_count; i++, reg += sizeof(u32)) {
val[i] = readl_relaxed(reg + vote_offset);
if (val[i] == DRV_ABSENT) {
vote_info[i].ab = DRV_ABSENT;
vote_info[i].ib = DRV_ABSENT;
continue;
} else if (val[i] == DRV_INVALID) {
vote_info[i].ab = DRV_INVALID;
vote_info[i].ib = DRV_INVALID;
continue;
}
vote_info[i].ab = (val[i] >> VOTE_X_SHIFT) & VOTE_MASK;
vote_info[i].ib = val[i] & VOTE_MASK;
}
mutex_unlock(&ddr_pdata->ddr_stats_lock);
return 0;
}
EXPORT_SYMBOL(ddr_stats_get_ss_vote_info);
static ssize_t ddr_stats_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
@ -312,6 +381,16 @@ static int ddr_stats_probe(struct platform_device *pdev)
reg += sizeof(struct stats_entry);
}
ddr_pdata->stats_mbox_cl.dev = &pdev->dev;
ddr_pdata->stats_mbox_cl.tx_block = true;
ddr_pdata->stats_mbox_cl.tx_tout = 1000;
ddr_pdata->stats_mbox_cl.knows_txdone = false;
ddr_pdata->read_ddr_vote = true;
ddr_pdata->stats_mbox_ch = mbox_request_channel(&ddr_pdata->stats_mbox_cl, 0);
if (IS_ERR(ddr_pdata->stats_mbox_ch))
ddr_pdata->read_ddr_vote = false;
return ddr_stats_create_sysfs(pdev, ddr_pdata);
}
@ -322,6 +401,9 @@ static int ddr_stats_remove(struct platform_device *pdev)
ddr_stats_ka = (struct ddr_stats_kobj_attr *)
platform_get_drvdata(pdev);
if (ddr_pdata->read_ddr_vote)
mbox_free_channel(ddr_stats_ka->pd->stats_mbox_ch);
sysfs_remove_file(ddr_stats_ka->kobj, &ddr_stats_ka->ka.attr);
kobject_put(ddr_stats_ka->kobj);
platform_set_drvdata(pdev, NULL);

View file

@ -11,7 +11,14 @@ struct ddr_freq_residency {
uint64_t residency;
};
struct ddr_stats_ss_vote_info {
u32 ab; /* vote_x */
u32 ib; /* vote_y */
};
int ddr_stats_get_freq_count(void);
int ddr_stats_get_residency(int freq_count, struct ddr_freq_residency *data);
int ddr_stats_get_ss_count(void);
int ddr_stats_get_ss_vote_info(int ss_count,
struct ddr_stats_ss_vote_info *vote_info);
#endif /*__DDR_STATS_H_ */