devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Krzysztof Kozlowski <krzk@kernel.org>
To: webgeek1234@gmail.com, Rob Herring <robh@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Thierry Reding <thierry.reding@gmail.com>,
	Jonathan Hunter <jonathanh@nvidia.com>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	MyungJoo Ham <myungjoo.ham@samsung.com>,
	Kyungmin Park <kyungmin.park@samsung.com>,
	Chanwoo Choi <cw00.choi@samsung.com>,
	Dmitry Osipenko <digetx@gmail.com>
Cc: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-tegra@vger.kernel.org, linux-pm@vger.kernel.org
Subject: Re: [PATCH v3 5/9] memory: tegra210: Support interconnect framework
Date: Wed, 10 Sep 2025 11:39:41 +0200	[thread overview]
Message-ID: <29ec10fa-1ca4-43eb-a865-7219d39c7140@kernel.org> (raw)
In-Reply-To: <20250906-t210-actmon-v3-5-1403365d571e@gmail.com>

On 06/09/2025 22:16, Aaron Kling via B4 Relay wrote:
> +
> +static int tegra_emc_interconnect_init(struct tegra210_emc *emc)
> +{
> +	const struct tegra_mc_soc *soc = emc->mc->soc;
> +	struct icc_node *node;
> +	int err;
> +
> +	emc->icc_provider.dev = emc->dev;
> +	emc->icc_provider.set = emc_icc_set;
> +	emc->icc_provider.data = &emc->icc_provider;
> +	emc->icc_provider.aggregate = soc->icc_ops->aggregate;
> +	emc->icc_provider.xlate_extended = emc_of_icc_xlate_extended;
> +	emc->icc_provider.get_bw = tegra_emc_icc_get_init_bw;
> +
> +	icc_provider_init(&emc->icc_provider);
> +
> +	/* create External Memory Controller node */
> +	node = icc_node_create(TEGRA_ICC_EMC);
> +	if (IS_ERR(node)) {
> +		err = PTR_ERR(node);
> +		goto err_msg;

return dev_err_probe

> +	}
> +
> +	node->name = "External Memory Controller";
> +	icc_node_add(node, &emc->icc_provider);
> +
> +	/* link External Memory Controller to External Memory (DRAM) */
> +	err = icc_link_create(node, TEGRA_ICC_EMEM);
> +	if (err)
> +		goto remove_nodes;
> +
> +	/* create External Memory node */
> +	node = icc_node_create(TEGRA_ICC_EMEM);
> +	if (IS_ERR(node)) {
> +		err = PTR_ERR(node);
> +		goto remove_nodes;
> +	}
> +
> +	node->name = "External Memory (DRAM)";
> +	icc_node_add(node, &emc->icc_provider);
> +
> +	err = icc_provider_register(&emc->icc_provider);
> +	if (err)
> +		goto remove_nodes;
> +
> +	return 0;
> +
> +remove_nodes:
> +	icc_nodes_remove(&emc->icc_provider);
> +err_msg:
> +	dev_err(emc->dev, "failed to initialize ICC: %d\n", err);

Write descriptive error messages or skip it. It's printing errors also
on ENOMEM.

I will send a patch to fix existing code.

> +
> +	return err;
> +}
> +
> +static int tegra_emc_opp_table_init(struct tegra210_emc *emc)
> +{
> +	u32 hw_version = BIT(tegra_sku_info.soc_speedo_id);
> +	struct dev_pm_opp *opp;
> +	unsigned long rate;
> +	int opp_token, err, max_opps, i;
> +
> +	err = dev_pm_opp_set_supported_hw(emc->dev, &hw_version, 1);
> +	if (err < 0) {
> +		dev_err(emc->dev, "failed to set OPP supported HW: %d\n", err);
> +		return err;

return dev_err_probe

> +	}
> +	opp_token = err;
> +
> +	err = dev_pm_opp_of_add_table(emc->dev);
> +	if (err) {
> +		if (err == -ENODEV)
> +			dev_warn(emc->dev, "OPP table not found, please update your device tree\n");
> +		else
> +			dev_err(emc->dev, "failed to add OPP table: %d\n", err);
> +
> +		goto put_hw_table;
> +	}
> +
> +	max_opps = dev_pm_opp_get_opp_count(emc->dev);
> +	if (max_opps <= 0) {
> +		dev_err(emc->dev, "Failed to add OPPs\n");
> +		goto remove_table;
> +	}
> +
> +	if (emc->num_timings != max_opps) {
> +		dev_err(emc->dev, "OPP table does not match emc table\n");
> +		goto remove_table;
> +	}
> +
> +	for (i = 0; i < emc->num_timings; i++) {
> +		rate = emc->timings[i].rate * 1000;
> +		opp = dev_pm_opp_find_freq_exact(emc->dev, rate, true);
> +		if (IS_ERR(opp)) {
> +			dev_err(emc->dev, "Rate %lu not found in OPP table\n", rate);
> +			goto remove_table;
> +		}
> +
> +		dev_pm_opp_put(opp);
> +	}
> +
> +	dev_info_once(emc->dev, "OPP HW ver. 0x%x, current clock rate %lu MHz\n",
> +		      hw_version, clk_get_rate(emc->clk) / 1000000);
> +
> +	return 0;
> +
> +remove_table:
> +	dev_pm_opp_of_remove_table(emc->dev);
> +put_hw_table:
> +	dev_pm_opp_put_supported_hw(opp_token);
> +
> +	return err;
> +}
> +

...

> diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c
> index cfa61dd885577a8fbd79c396a1316101197ca1f2..20828a07d2d0cafa739b534c20c12f065b276669 100644
> --- a/drivers/memory/tegra/tegra210.c
> +++ b/drivers/memory/tegra/tegra210.c
> @@ -3,6 +3,9 @@
>   * Copyright (C) 2015 NVIDIA CORPORATION.  All rights reserved.
>   */
>  
> +#include <linux/of.h>
> +#include <linux/device.h>
> +
>  #include <dt-bindings/memory/tegra210-mc.h>
>  
>  #include "mc.h"
> @@ -1273,6 +1276,83 @@ static const struct tegra_mc_reset tegra210_mc_resets[] = {
>  	TEGRA210_MC_RESET(TSECB,     0x970, 0x974, 13),
>  };
>  
> +static int tegra210_mc_icc_set(struct icc_node *src, struct icc_node *dst)
> +{
> +	/* TODO: program PTSA */
> +	return 0;
> +}
> +
> +static int tegra210_mc_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw,
> +				     u32 peak_bw, u32 *agg_avg, u32 *agg_peak)
> +{
> +	/*
> +	 * ISO clients need to reserve extra bandwidth up-front because
> +	 * there could be high bandwidth pressure during initial filling
> +	 * of the client's FIFO buffers.  Secondly, we need to take into
> +	 * account impurities of the memory subsystem.
> +	 */
> +	if (tag & TEGRA_MC_ICC_TAG_ISO)
> +		peak_bw = tegra_mc_scale_percents(peak_bw, 400);
> +
> +	*agg_avg += avg_bw;
> +	*agg_peak = max(*agg_peak, peak_bw);
> +
> +	return 0;
> +}
> +
> +static struct icc_node_data *
> +tegra210_mc_of_icc_xlate_extended(const struct of_phandle_args *spec, void *data)
> +{
> +	struct tegra_mc *mc = icc_provider_to_tegra_mc(data);
> +	const struct tegra_mc_client *client;
> +	unsigned int i, idx = spec->args[0];
> +	struct icc_node_data *ndata;
> +	struct icc_node *node;
> +
> +	list_for_each_entry(node, &mc->provider.nodes, node_list) {
> +		if (node->id != idx)
> +			continue;
> +
> +		ndata = kzalloc(sizeof(*ndata), GFP_KERNEL);
> +		if (!ndata)
> +			return ERR_PTR(-ENOMEM);
> +
> +		client = &mc->soc->clients[idx];
> +		ndata->node = node;
> +
> +		switch (client->swgroup) {
> +		case TEGRA_SWGROUP_DC:
> +		case TEGRA_SWGROUP_DCB:
> +		case TEGRA_SWGROUP_PTC:
> +		case TEGRA_SWGROUP_VI:
> +			/* these clients are isochronous by default */
> +			ndata->tag = TEGRA_MC_ICC_TAG_ISO;
> +			break;
> +
> +		default:
> +			ndata->tag = TEGRA_MC_ICC_TAG_DEFAULT;
> +			break;
> +		}
> +
> +		return ndata;
> +	}
> +
> +	for (i = 0; i < mc->soc->num_clients; i++) {
> +		if (mc->soc->clients[i].id == idx)
> +			return ERR_PTR(-EPROBE_DEFER);

This feels like more reasonable use of deferred probe, but I wonder how
is this condition possible.

This xlate is called at earliest after MC ICC is registered. At this
tage all nodes are created, so previous list_for_each_entry() should
succeed and return. If previous list_for_each_entry() did not return,
how can you find a matching client for which the node will be added
later, thus deferred probe?

This is again existing code, of course :)



Best regards,
Krzysztof

  reply	other threads:[~2025-09-10  9:39 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-06 20:16 [PATCH v3 0/9] Support Tegra210 actmon for dynamic EMC scaling Aaron Kling via B4 Relay
2025-09-06 20:16 ` [PATCH v3 1/9] dt-bindings: devfreq: tegra30-actmon: Add Tegra124 fallback for Tegra210 Aaron Kling via B4 Relay
2025-09-06 20:16 ` [PATCH v3 2/9] dt-bindings: memory: tegra210: emc: Document OPP table and interconnect Aaron Kling via B4 Relay
2025-09-10  9:41   ` (subset) " Krzysztof Kozlowski
2025-09-06 20:16 ` [PATCH v3 3/9] dt-bindings: memory: tegra210: Add memory client IDs Aaron Kling via B4 Relay
2025-09-10  9:41   ` (subset) " Krzysztof Kozlowski
2025-09-06 20:16 ` [PATCH v3 4/9] memory: tegra210: Use bindings for client ids Aaron Kling via B4 Relay
2025-09-10  9:41   ` (subset) " Krzysztof Kozlowski
2025-09-06 20:16 ` [PATCH v3 5/9] memory: tegra210: Support interconnect framework Aaron Kling via B4 Relay
2025-09-10  9:39   ` Krzysztof Kozlowski [this message]
2025-09-10 10:06     ` Krzysztof Kozlowski
2025-09-15  6:08       ` Aaron Kling
2025-09-15  7:24         ` Krzysztof Kozlowski
2025-09-06 20:16 ` [PATCH v3 6/9] soc: tegra: fuse: speedo-tegra210: Add soc speedo 2 Aaron Kling via B4 Relay
2025-09-06 20:16 ` [PATCH v3 7/9] arm64: tegra: tegra210: Add actmon Aaron Kling via B4 Relay
2025-09-06 20:16 ` [PATCH v3 8/9] arm64: tegra: Add interconnect properties to Tegra210 device-tree Aaron Kling via B4 Relay
2025-09-06 20:16 ` [PATCH v3 9/9] arm64: tegra: Add OPP tables on Tegra210 Aaron Kling via B4 Relay

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=29ec10fa-1ca4-43eb-a865-7219d39c7140@kernel.org \
    --to=krzk@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=cw00.choi@samsung.com \
    --cc=devicetree@vger.kernel.org \
    --cc=digetx@gmail.com \
    --cc=jonathanh@nvidia.com \
    --cc=krzk+dt@kernel.org \
    --cc=kyungmin.park@samsung.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-pm@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=myungjoo.ham@samsung.com \
    --cc=robh@kernel.org \
    --cc=thierry.reding@gmail.com \
    --cc=webgeek1234@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).