ddr: bring up bandwidth support for sm1 [1/1]

PD#SWPL-6865

Problem:
ddr bandwidth measure is not supported on sm1

Solution:
1. Add port description and support for it
2. Record max/average bandwidth support;
3. Support up to 60 continue bandwidth sample
4. Fix bit mismatch of dmc monitor for sm1/tl1.

Verify:
sm1

Change-Id: I0b42db8214099b9cd6d1c3f00174dc65eebfc030
Signed-off-by: Tao Zeng <tao.zeng@amlogic.com>
Signed-off-by: Luan Yuan <luan.yuan@amlogic.com>
This commit is contained in:
Tao Zeng
2019-04-10 11:59:24 +08:00
committed by Luan Yuan
parent 408ded9202
commit 8cf68eb198
6 changed files with 232 additions and 18 deletions

View File

@@ -1389,7 +1389,7 @@
dmc_monitor {
compatible = "amlogic, dmc_monitor";
status = "okay";
reg_base = <0xff638800>;
reg_base = <0xff639000>;
interrupts = <GIC_SPI 51 IRQ_TYPE_EDGE_RISING>;
};

View File

@@ -43,7 +43,7 @@ static const unsigned int bandwidth_cable[] = {
static void cal_ddr_usage(struct ddr_bandwidth *db, struct ddr_grant *dg)
{
u64 mul; /* avoid overflow */
unsigned long i, cnt, freq = 0;
unsigned long i, cnt, freq = 0, flags;
if (db->mode == MODE_AUTODETECT) { /* ignore mali bandwidth */
static int count;
@@ -77,22 +77,43 @@ static void cal_ddr_usage(struct ddr_bandwidth *db, struct ddr_grant *dg)
mul /= 16;
cnt = db->clock_count;
do_div(mul, cnt);
db->total_usage = mul;
db->cur_sample.total_usage = mul;
if (freq) {
/* calculate in KB */
mul = dg->all_grant;
mul *= freq;
mul /= 1024;
do_div(mul, cnt);
db->total_bandwidth = mul;
db->cur_sample.total_bandwidth = mul;
db->cur_sample.tick = sched_clock();
for (i = 0; i < db->channels; i++) {
mul = dg->channel_grant[i];
mul *= freq;
mul /= 1024;
do_div(mul, cnt);
db->bandwidth[i] = mul;
db->cur_sample.bandwidth[i] = mul;
}
}
if (db->stat_flag) /* stop update usage stat if flag set */
return;
spin_lock_irqsave(&aml_db->lock, flags);
/* update max sample */
if (db->cur_sample.total_bandwidth > db->max_sample.total_bandwidth) {
memcpy(&db->max_sample, &db->cur_sample,
sizeof(struct ddr_bandwidth_sample));
}
/* update usage statistics */
db->usage_stat[db->cur_sample.total_usage / 1000]++;
/* collect for average bandwidth calculate */
db->avg.avg_bandwidth += db->cur_sample.total_bandwidth;
db->avg.avg_usage += db->cur_sample.total_usage;
for (i = 0; i < db->channels; i++)
db->avg.avg_port[i] += db->cur_sample.bandwidth[i];
db->avg.sample_count++;
spin_unlock_irqrestore(&aml_db->lock, flags);
}
static irqreturn_t dmc_irq_handler(int irq, void *dev_instance)
@@ -113,7 +134,7 @@ unsigned int aml_get_ddr_usage(void)
unsigned int ret = 0;
if (aml_db)
ret = aml_db->total_usage;
ret = aml_db->cur_sample.total_usage;
return ret;
}
@@ -268,8 +289,8 @@ static ssize_t mode_store(struct class *cla,
aml_db->ops->init(aml_db);
} else if ((aml_db->mode != MODE_DISABLE) && (val == MODE_DISABLE)) {
free_irq(aml_db->irq_num, (void *)aml_db);
aml_db->total_usage = 0;
aml_db->total_bandwidth = 0;
aml_db->cur_sample.total_usage = 0;
aml_db->cur_sample.total_bandwidth = 0;
aml_db->busy = 0;
}
aml_db->mode = val;
@@ -301,24 +322,116 @@ static ssize_t clock_count_store(struct class *cla,
return count;
}
static ssize_t usage_stat_store(struct class *cla,
struct class_attribute *attr, const char *buf, size_t count)
{
unsigned long flags;
int d = -1;
if (kstrtoint(buf, 10, &d))
return count;
aml_db->stat_flag = d;
if (d)
return count;
/* clear flag and start statistics */
spin_lock_irqsave(&aml_db->lock, flags);
memset(&aml_db->max_sample, 0, sizeof(struct ddr_bandwidth_sample));
memset(aml_db->usage_stat, 0, 10 * sizeof(int));
memset(&aml_db->avg, 0, sizeof(struct ddr_avg_bandwidth));
spin_unlock_irqrestore(&aml_db->lock, flags);
return count;
}
static ssize_t usage_stat_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
size_t s = 0;
int percent, rem, i;
unsigned long long tick;
unsigned long total_count = 0;
struct ddr_avg_bandwidth tmp;
#define MAX_PREFIX "MAX bandwidth: %8d KB/s, usage: %2d.%02d%%"
#define AVG_PREFIX "AVG bandwidth: %8lld KB/s, usage: %2d.%02d%%"
if (aml_db->mode != MODE_ENABLE)
return sprintf(buf, "set mode to enable(1) first.\n");
/* show for max bandwidth */
percent = aml_db->max_sample.total_usage / 100;
rem = aml_db->max_sample.total_usage % 100;
tick = aml_db->max_sample.tick;
do_div(tick, 1000);
s += sprintf(buf + s, MAX_PREFIX", tick:%lld us\n",
aml_db->max_sample.total_bandwidth,
percent, rem, tick);
for (i = 0; i < aml_db->channels; i++) {
s += sprintf(buf + s, "ch:%d port:%16llx: %8d KB/s\n",
i, aml_db->port[i],
aml_db->max_sample.bandwidth[i]);
}
/* show for average bandwidth */
if (aml_db->avg.sample_count) {
memcpy(&tmp, &aml_db->avg, sizeof(tmp));
do_div(tmp.avg_bandwidth, tmp.sample_count);
do_div(tmp.avg_usage, tmp.sample_count);
for (i = 0; i < aml_db->channels; i++)
do_div(tmp.avg_port[i], tmp.sample_count);
rem = do_div(tmp.avg_usage, 100);
percent = tmp.avg_usage,
s += sprintf(buf + s, AVG_PREFIX", samples:%d\n",
tmp.avg_bandwidth,
percent, rem, tmp.sample_count);
for (i = 0; i < aml_db->channels; i++) {
s += sprintf(buf + s, "ch:%d port:%16llx: %8lld KB/s\n",
i, aml_db->port[i],
tmp.avg_port[i]);
}
}
/* show for usage statistics */
for (i = 0; i < 10; i++)
total_count += aml_db->usage_stat[i];
s += sprintf(buf + s, "\nusage statistics:\n");
s += sprintf(buf + s, "range, count, proportion\n");
for (i = 0; i < 10; i++) {
percent = aml_db->usage_stat[i] * 10000 / total_count;
rem = percent % 100;
percent = percent / 100;
s += sprintf(buf + s, "%2d%% ~ %3d%%: %8d, %3d.%02d%%\n",
i * 10, (i + 1) * 10,
aml_db->usage_stat[i], percent, rem);
}
return s;
}
static ssize_t bandwidth_show(struct class *cla,
struct class_attribute *attr, char *buf)
{
size_t s = 0;
int percent, rem, i;
unsigned long long tick;
#define BANDWIDTH_PREFIX "Total bandwidth: %8d KB/s, usage: %2d.%02d%%\n"
if (aml_db->mode != MODE_ENABLE)
return sprintf(buf, "set mode to enable(1) first.\n");
percent = aml_db->total_usage / 100;
rem = aml_db->total_usage % 100;
percent = aml_db->cur_sample.total_usage / 100;
rem = aml_db->cur_sample.total_usage % 100;
tick = aml_db->cur_sample.tick;
do_div(tick, 1000);
s += sprintf(buf + s, BANDWIDTH_PREFIX,
aml_db->total_bandwidth, percent, rem);
aml_db->cur_sample.total_bandwidth,
percent, rem);
for (i = 0; i < aml_db->channels; i++) {
s += sprintf(buf + s, "ch:%d port bit:%16llx: %8d KB/s\n",
i, aml_db->port[i], aml_db->bandwidth[i]);
s += sprintf(buf + s, "ch:%d port:%16llx: %8d KB/s\n",
i, aml_db->port[i],
aml_db->cur_sample.bandwidth[i]);
}
return s;
}
@@ -466,6 +579,7 @@ static struct class_attribute aml_ddr_tool_attr[] = {
__ATTR(urgent, 0664, urgent_show, urgent_store),
__ATTR(threshold, 0664, threshold_show, threshold_store),
__ATTR(mode, 0664, mode_show, mode_store),
__ATTR(usage_stat, 0664, usage_stat_show, usage_stat_store),
__ATTR_RO(busy),
__ATTR_RO(bandwidth),
__ATTR_RO(freq),
@@ -597,6 +711,7 @@ static int __ref ddr_bandwidth_probe(struct platform_device *pdev)
aml_db->irq_num = of_irq_get(node, 0);
#endif
spin_lock_init(&aml_db->lock);
aml_db->clock_count = DEFAULT_CLK_CNT;
aml_db->mode = MODE_DISABLE;
aml_db->threshold = DEFAULT_THRESHOLD * 16 *

View File

@@ -421,6 +421,44 @@ static struct ddr_port_desc ddr_port_desc_txhd[] __initdata = {
{ .port_id = 47, .port_name = "DEMOD" }
};
static struct ddr_port_desc ddr_port_desc_sm1[] __initdata = {
{ .port_id = 0, .port_name = "ARM" },
{ .port_id = 1, .port_name = "MALI" },
{ .port_id = 2, .port_name = "PCIE" },
{ .port_id = 3, .port_name = "HDCP" },
{ .port_id = 4, .port_name = "HEVC FRONT" },
{ .port_id = 5, .port_name = "TEST" },
{ .port_id = 6, .port_name = "USB3.0" },
{ .port_id = 7, .port_name = "DEVICE" },
{ .port_id = 8, .port_name = "HEVC BACK" },
{ .port_id = 9, .port_name = "H265ENC" },
{ .port_id = 10, .port_name = "NNA" },
{ .port_id = 16, .port_name = "VPU READ1" },
{ .port_id = 17, .port_name = "VPU READ2" },
{ .port_id = 18, .port_name = "VPU READ3" },
{ .port_id = 19, .port_name = "VPU WRITE1" },
{ .port_id = 20, .port_name = "VPU WRITE2" },
{ .port_id = 21, .port_name = "VDEC" },
{ .port_id = 22, .port_name = "HCODEC" },
{ .port_id = 23, .port_name = "GE2D" },
/* start of each device */
{ .port_id = 32, .port_name = "SPICC1" },
{ .port_id = 33, .port_name = "USB0" },
{ .port_id = 34, .port_name = "DMA" },
{ .port_id = 35, .port_name = "ARB0" },
{ .port_id = 36, .port_name = "SD_EMMC_B" },
{ .port_id = 37, .port_name = "USB1" },
{ .port_id = 38, .port_name = "AUDIO" },
{ .port_id = 39, .port_name = "AIFIFO" },
{ .port_id = 41, .port_name = "PASER" },
{ .port_id = 42, .port_name = "AO CPU" },
{ .port_id = 43, .port_name = "SD_EMMC_C" },
{ .port_id = 44, .port_name = "SPICC2" },
{ .port_id = 45, .port_name = "ETHERNET" },
{ .port_id = 46, .port_name = "SANA" }
};
static struct ddr_port_desc *chip_ddr_port;
static unsigned char chip_ddr_port_num;
@@ -489,6 +527,11 @@ int __init ddr_find_port_desc(int cpu_type, struct ddr_port_desc **desc)
desc_size = ARRAY_SIZE(ddr_port_desc_g12b);
break;
case MESON_CPU_MAJOR_ID_SM1:
*desc = ddr_port_desc_sm1;
desc_size = ARRAY_SIZE(ddr_port_desc_sm1);
break;
default:
return -EINVAL;
}

View File

@@ -83,12 +83,24 @@ static void check_violation(struct dmc_monitor *mon)
struct page *page;
unsigned long *p;
char id_str[4];
char off1 = 21, off2 = 10;
char off1, off2;
if (mon->chip == MESON_CPU_MAJOR_ID_G12B) {
switch (mon->chip) {
case MESON_CPU_MAJOR_ID_G12B:
/* bit fix for G12B */
off1 = 24;
off2 = 13;
break;
case MESON_CPU_MAJOR_ID_SM1:
case MESON_CPU_MAJOR_ID_TL1:
/* bit fix for SM1/TL1 */
off1 = 22;
off2 = 11;
break;
default: /* G12A */
off1 = 21;
off2 = 10;
break;
}
for (i = 1; i < 4; i += 2) {

View File

@@ -109,6 +109,30 @@ unsigned int get_all_dev_mask(void)
return ret;
}
static unsigned int get_other_dev_mask(void)
{
unsigned int ret = 0;
int i;
for (i = 0; i < PORT_MAJOR; i++) {
if (dmc_mon->port[i].port_id >= PORT_MAJOR)
break;
/*
* we don't want id with arm mali and device
* because these devices can access all ddr range
* and generate value-less report
*/
if (strstr(dmc_mon->port[i].port_name, "ARM") ||
strstr(dmc_mon->port[i].port_name, "MALI") ||
strstr(dmc_mon->port[i].port_name, "DEVICE"))
continue;
ret |= (1 << dmc_mon->port[i].port_id);
}
return ret;
}
static size_t dump_reg(char *buf)
{
size_t sz = 0, i;
@@ -220,6 +244,8 @@ static ssize_t dev_store(struct class *cla,
}
if (!strncmp(buf, "all", 3))
dmc_mon->device = get_all_dev_mask();
else if (!strncmp(buf, "other", 5))
dmc_mon->device = get_other_dev_mask();
else {
i = dev_name_to_id(buf);
if (i < 0) {

View File

@@ -114,6 +114,7 @@
struct ddr_bandwidth;
struct ddr_grant {
unsigned long long tick;
unsigned int all_grant, all_req;
unsigned int channel_grant[MAX_CHANNEL];
};
@@ -129,19 +130,36 @@ struct ddr_bandwidth_ops {
#endif
};
struct ddr_bandwidth_sample {
unsigned long long tick;
unsigned int total_usage;
unsigned int total_bandwidth;
unsigned int bandwidth[MAX_CHANNEL];
};
struct ddr_avg_bandwidth {
unsigned long long avg_bandwidth;
unsigned long long avg_usage;
unsigned long long avg_port[MAX_CHANNEL];
unsigned int sample_count;
};
struct ddr_bandwidth {
unsigned short cpu_type;
unsigned short real_ports;
char busy;
char mode;
int mali_port[2];
int stat_flag;
unsigned int threshold;
unsigned int irq_num;
unsigned int clock_count;
unsigned int channels;
unsigned int bandwidth[MAX_CHANNEL];
unsigned int total_usage;
unsigned int total_bandwidth;
unsigned int usage_stat[10];
spinlock_t lock;
struct ddr_bandwidth_sample cur_sample;
struct ddr_bandwidth_sample max_sample;
struct ddr_avg_bandwidth avg;
u64 port[MAX_CHANNEL];
void __iomem *ddr_reg;
void __iomem *pll_reg;