From: Tao Zeng Date: Wed, 10 Apr 2019 03:59:24 +0000 (+0800) Subject: ddr: bring up bandwidth support for sm1 [1/1] X-Git-Tag: hardkernel-4.9.236-104~1404 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=62afcb947053ca8802f62e66409526309d727c04;p=platform%2Fkernel%2Flinux-amlogic.git 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 --- diff --git a/arch/arm/boot/dts/amlogic/mesontl1.dtsi b/arch/arm/boot/dts/amlogic/mesontl1.dtsi index cc6dc478..c60d641 100644 --- a/arch/arm/boot/dts/amlogic/mesontl1.dtsi +++ b/arch/arm/boot/dts/amlogic/mesontl1.dtsi @@ -1369,7 +1369,7 @@ dmc_monitor { compatible = "amlogic, dmc_monitor"; status = "okay"; - reg_base = <0xff638800>; + reg_base = <0xff639000>; interrupts = ; }; diff --git a/arch/arm64/boot/dts/amlogic/mesontl1.dtsi b/arch/arm64/boot/dts/amlogic/mesontl1.dtsi index b03c1f7..40d7c54 100644 --- a/arch/arm64/boot/dts/amlogic/mesontl1.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesontl1.dtsi @@ -1350,7 +1350,7 @@ dmc_monitor { compatible = "amlogic, dmc_monitor"; status = "okay"; - reg_base = <0xff638800>; + reg_base = <0xff639000>; interrupts = ; }; diff --git a/drivers/amlogic/ddr_tool/ddr_bandwidth.c b/drivers/amlogic/ddr_tool/ddr_bandwidth.c index fcb4335..0eaea45 100644 --- a/drivers/amlogic/ddr_tool/ddr_bandwidth.c +++ b/drivers/amlogic/ddr_tool/ddr_bandwidth.c @@ -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) do_div(mul, db->bytes_per_cycle); 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; } @@ -270,8 +291,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; @@ -303,24 +324,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; } @@ -468,6 +581,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), @@ -604,6 +718,7 @@ static int __init 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 * aml_db->bytes_per_cycle * diff --git a/drivers/amlogic/ddr_tool/ddr_port_desc.c b/drivers/amlogic/ddr_tool/ddr_port_desc.c index 190d4ea..03d8cc7 100644 --- a/drivers/amlogic/ddr_tool/ddr_port_desc.c +++ b/drivers/amlogic/ddr_tool/ddr_port_desc.c @@ -456,6 +456,44 @@ static struct ddr_port_desc ddr_port_desc_tl1[] __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; @@ -529,6 +567,11 @@ int __init ddr_find_port_desc(int cpu_type, struct ddr_port_desc **desc) desc_size = ARRAY_SIZE(ddr_port_desc_tl1); break; + case MESON_CPU_MAJOR_ID_SM1: + *desc = ddr_port_desc_sm1; + desc_size = ARRAY_SIZE(ddr_port_desc_sm1); + break; + default: return -EINVAL; } diff --git a/drivers/amlogic/ddr_tool/dmc_g12.c b/drivers/amlogic/ddr_tool/dmc_g12.c index 8e35e21..859b76e 100644 --- a/drivers/amlogic/ddr_tool/dmc_g12.c +++ b/drivers/amlogic/ddr_tool/dmc_g12.c @@ -103,12 +103,24 @@ static void check_violation(struct dmc_monitor *mon) int i, port, subport; unsigned long addr, status; 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) { diff --git a/drivers/amlogic/ddr_tool/dmc_monitor.c b/drivers/amlogic/ddr_tool/dmc_monitor.c index 17086aa..d57ce49 100644 --- a/drivers/amlogic/ddr_tool/dmc_monitor.c +++ b/drivers/amlogic/ddr_tool/dmc_monitor.c @@ -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) { diff --git a/include/linux/amlogic/aml_ddr_bandwidth.h b/include/linux/amlogic/aml_ddr_bandwidth.h index 42346db..ba0057d 100644 --- a/include/linux/amlogic/aml_ddr_bandwidth.h +++ b/include/linux/amlogic/aml_ddr_bandwidth.h @@ -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,6 +130,20 @@ 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; @@ -136,13 +151,16 @@ struct ddr_bandwidth { char mode; char bytes_per_cycle; 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;