18.03.2021 18:23, Krzysztof Kozlowski пишет: ... >> + mc->debugfs.root = debugfs_create_dir("mc", NULL); >> + if (!mc->debugfs.root) >> + dev_err(&pdev->dev, "failed to create debugfs directory\n"); > > It's error pointer, not null, but anyway there is no need for handling > debugfs error. See Greg KH's commits like "remove pointless check for > debugfs_create_dir()". Indeed! >> + >> + if (mc->soc->init) { >> + err = mc->soc->init(mc); >> + if (err < 0) >> + dev_err(&pdev->dev, >> + "failed to register initialize SoC driver: %d\n", > > "failed to initialize SoC driver:...." Good catch! >> + err); >> + } >> + >> err = tegra_mc_reset_setup(mc); >> if (err < 0) >> dev_err(&pdev->dev, "failed to register reset controller: %d\n", >> diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c >> index 29ecf02805a0..513c07104296 100644 >> --- a/drivers/memory/tegra/tegra20.c >> +++ b/drivers/memory/tegra/tegra20.c >> @@ -3,6 +3,8 @@ >> * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. >> */ >> >> +#include <linux/bitfield.h> >> +#include <linux/delay.h> >> #include <linux/of_device.h> >> #include <linux/slab.h> >> #include <linux/string.h> >> @@ -11,6 +13,77 @@ >> >> #include "mc.h" >> >> +#define MC_STAT_CONTROL 0x90 >> +#define MC_STAT_EMC_CLOCK_LIMIT 0xa0 >> +#define MC_STAT_EMC_CLOCKS 0xa4 >> +#define MC_STAT_EMC_CONTROL_0 0xa8 >> +#define MC_STAT_EMC_CONTROL_1 0xac >> +#define MC_STAT_EMC_COUNT_0 0xb8 >> +#define MC_STAT_EMC_COUNT_1 0xbc >> + >> +#define MC_STAT_CONTROL_CLIENT_ID GENMASK(13, 8) >> +#define MC_STAT_CONTROL_EVENT GENMASK(23, 16) >> +#define MC_STAT_CONTROL_PRI_EVENT GENMASK(25, 24) >> +#define MC_STAT_CONTROL_FILTER_CLIENT_ENABLE GENMASK(26, 26) >> +#define MC_STAT_CONTROL_FILTER_PRI GENMASK(29, 28) >> + >> +#define MC_STAT_CONTROL_PRI_EVENT_HP 0 >> +#define MC_STAT_CONTROL_PRI_EVENT_TM 1 >> +#define MC_STAT_CONTROL_PRI_EVENT_BW 2 >> + >> +#define MC_STAT_CONTROL_FILTER_PRI_DISABLE 0 >> +#define MC_STAT_CONTROL_FILTER_PRI_NO 1 >> +#define MC_STAT_CONTROL_FILTER_PRI_YES 2 >> + >> +#define MC_STAT_CONTROL_EVENT_QUALIFIED 0 >> +#define MC_STAT_CONTROL_EVENT_ANY_READ 1 >> +#define MC_STAT_CONTROL_EVENT_ANY_WRITE 2 >> +#define MC_STAT_CONTROL_EVENT_RD_WR_CHANGE 3 >> +#define MC_STAT_CONTROL_EVENT_SUCCESSIVE 4 >> +#define MC_STAT_CONTROL_EVENT_ARB_BANK_AA 5 >> +#define MC_STAT_CONTROL_EVENT_ARB_BANK_BB 6 >> +#define MC_STAT_CONTROL_EVENT_PAGE_MISS 7 >> +#define MC_STAT_CONTROL_EVENT_AUTO_PRECHARGE 8 >> + >> +#define EMC_GATHER_RST (0 << 8) >> +#define EMC_GATHER_CLEAR (1 << 8) >> +#define EMC_GATHER_DISABLE (2 << 8) >> +#define EMC_GATHER_ENABLE (3 << 8) >> + >> +#define MC_STAT_SAMPLE_TIME_USEC 16000 >> + >> +/* we store collected statistics as a fixed point values */ >> +#define MC_FX_FRAC_SCALE 100 >> + >> +struct tegra20_mc_stat_gather { >> + unsigned int pri_filter; >> + unsigned int pri_event; >> + unsigned int result; >> + unsigned int client; >> + unsigned int event; >> + bool client_enb; >> +}; >> + >> +struct tegra20_mc_stat { >> + struct tegra20_mc_stat_gather gather0; >> + struct tegra20_mc_stat_gather gather1; >> + unsigned int sample_time_usec; >> + struct tegra_mc *mc; >> +}; >> + >> +struct tegra20_mc_client_stat { >> + unsigned int events; >> + unsigned int arb_high_prio; >> + unsigned int arb_timeout; >> + unsigned int arb_bandwidth; >> + unsigned int rd_wr_change; >> + unsigned int successive; >> + unsigned int page_miss; >> + unsigned int auto_precharge; >> + unsigned int arb_bank_aa; >> + unsigned int arb_bank_bb; >> +}; >> + >> static const struct tegra_mc_client tegra20_mc_clients[] = { >> { >> .id = 0x00, >> @@ -356,6 +429,274 @@ static const struct tegra_mc_icc_ops tegra20_mc_icc_ops = { >> .set = tegra20_mc_icc_set, >> }; >> >> +static u32 tegra20_mc_stat_gather_control(struct tegra20_mc_stat_gather *g) > > "g" looks like pointer to const here I'll add couple more consts to the code for consistency. >> +{ >> + u32 control; >> + >> + control = FIELD_PREP(MC_STAT_CONTROL_EVENT, g->event); >> + control |= FIELD_PREP(MC_STAT_CONTROL_CLIENT_ID, g->client); >> + control |= FIELD_PREP(MC_STAT_CONTROL_PRI_EVENT, g->pri_event); >> + control |= FIELD_PREP(MC_STAT_CONTROL_FILTER_PRI, g->pri_filter); >> + control |= FIELD_PREP(MC_STAT_CONTROL_FILTER_CLIENT_ENABLE, g->client_enb); >> + >> + return control; >> +} ... >> +static void tegra20_mc_collect_stats(struct tegra_mc *mc, >> + struct tegra20_mc_client_stat *stats) >> +{ >> + const struct tegra_mc_client *client0, *client1; >> + unsigned int i, clienta, clientb; > > Define the clienta and clientb inside the loop, to reduce the scope. > Unless it is used between the loop iterations? okay >> + >> + /* collect memory controller utilization percent for each client */ >> + for (i = 0; i < mc->soc->num_clients; i += 2) { >> + client0 = &mc->soc->clients[i]; >> + client1 = &mc->soc->clients[i + 1]; >> + >> + if (i + 1 == mc->soc->num_clients) >> + client1 = NULL; >> + >> + tegra20_mc_stat_events(mc, client0, client1, >> + MC_STAT_CONTROL_FILTER_PRI_DISABLE, >> + MC_STAT_CONTROL_PRI_EVENT_HP, >> + MC_STAT_CONTROL_EVENT_QUALIFIED, >> + &stats[i + 0].events, >> + &stats[i + 1].events); >> + } >> + >> + /* collect more info from active clients */ >> + for (i = 0; i < mc->soc->num_clients; i++) { >> + clientb = mc->soc->num_clients; >> + >> + for (client0 = NULL; i < mc->soc->num_clients; i++) { >> + if (stats[i].events) { >> + client0 = &mc->soc->clients[i]; >> + clienta = i++; >> + break; >> + } >> + } > > Could all clients have 0 events ending with "clienta" being undefined? > "client0" would be non-NULL because of loop before. As per 6.8.5.3 of C99 standard, the declaration of a for-loop "is reached in the order of execution before the first evaluation of the controlling expression". http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf >> + >> + for (client1 = NULL; i < mc->soc->num_clients; i++) { >> + if (stats[i].events) { >> + client1 = &mc->soc->clients[i]; >> + clientb = i; >> + break; >> + } >> + } >> + >> + if (!client0 && !client1) >> + break; this means that both client0 and client1 are set t0 NULL here if all clients have 0 events.