Commit f551592f authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'icc-6.3-rc3' of...

Merge tag 'icc-6.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/djakov/icc

 into char-misc-linus

Georgi writes:

interconnect fixes for v6.3-rc

This contains a bunch of fixes with the highlight being fixes for a race
condition that could sometimes occur during the interconnect provider
driver registration. There are also fixes for memory overallocation and
a memory leak.

- interconnect: qcom: osm-l3: fix icc_onecell_data allocation
- interconnect: qcom: sm8450: switch to qcom_icc_rpmh_* function
- interconnect: qcom: sm8550: switch to qcom_icc_rpmh_* function
- interconnect: qcom: qcm2290: Fix MASTER_SNOC_BIMC_NRT
- interconnect: fix mem leak when freeing nodes
- interconnect: fix icc_provider_del() error handling
- interconnect: fix provider registration API
- interconnect: imx: fix registration race
- interconnect: qcom: osm-l3: fix registration race
- interconnect: qcom: rpm: fix probe child-node error handling
- interconnect: qcom: rpm: fix registration race
- interconnect: qcom: rpmh: fix probe child-node error handling
- interconnect: qcom: rpmh: fix registration race
- interconnect: qcom: msm8974: fix registration race
- interconnect: exynos: fix node leak in probe PM QoS error path
- interconnect: exynos: fix registration race
- interconnect: exynos: drop redundant link destroy
- memory: tegra: fix interconnect registration race
- memory: tegra124-emc: fix interconnect registration race
- memory: tegra20-emc: fix interconnect registration race
- memory: tegra30-emc: fix interconnect registration race

Signed-off-by: default avatarGeorgi Djakov <djakov@kernel.org>

* tag 'icc-6.3-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/djakov/icc: (21 commits)
  memory: tegra30-emc: fix interconnect registration race
  memory: tegra20-emc: fix interconnect registration race
  memory: tegra124-emc: fix interconnect registration race
  memory: tegra: fix interconnect registration race
  interconnect: exynos: drop redundant link destroy
  interconnect: exynos: fix registration race
  interconnect: exynos: fix node leak in probe PM QoS error path
  interconnect: qcom: msm8974: fix registration race
  interconnect: qcom: rpmh: fix registration race
  interconnect: qcom: rpmh: fix probe child-node error handling
  interconnect: qcom: rpm: fix registration race
  interconnect: qcom: rpm: fix probe child-node error handling
  interconnect: qcom: osm-l3: fix registration race
  interconnect: imx: fix registration race
  interconnect: fix provider registration API
  interconnect: fix icc_provider_del() error handling
  interconnect: fix mem leak when freeing nodes
  interconnect: qcom: qcm2290: Fix MASTER_SNOC_BIMC_NRT
  interconnect: qcom: sm8550: switch to qcom_icc_rpmh_* function
  interconnect: qcom: sm8450: switch to qcom_icc_rpmh_* function
  ...
parents 06be6208 9db481c9
Loading
Loading
Loading
Loading
+43 −25
Original line number Diff line number Diff line
@@ -850,6 +850,10 @@ void icc_node_destroy(int id)

	mutex_unlock(&icc_lock);

	if (!node)
		return;

	kfree(node->links);
	kfree(node);
}
EXPORT_SYMBOL_GPL(icc_node_destroy);
@@ -1029,53 +1033,67 @@ int icc_nodes_remove(struct icc_provider *provider)
EXPORT_SYMBOL_GPL(icc_nodes_remove);

/**
 * icc_provider_add() - add a new interconnect provider
 * @provider: the interconnect provider that will be added into topology
 * icc_provider_init() - initialize a new interconnect provider
 * @provider: the interconnect provider to initialize
 *
 * Must be called before adding nodes to the provider.
 */
void icc_provider_init(struct icc_provider *provider)
{
	WARN_ON(!provider->set);

	INIT_LIST_HEAD(&provider->nodes);
}
EXPORT_SYMBOL_GPL(icc_provider_init);

/**
 * icc_provider_register() - register a new interconnect provider
 * @provider: the interconnect provider to register
 *
 * Return: 0 on success, or an error code otherwise
 */
int icc_provider_add(struct icc_provider *provider)
int icc_provider_register(struct icc_provider *provider)
{
	if (WARN_ON(!provider->set))
		return -EINVAL;
	if (WARN_ON(!provider->xlate && !provider->xlate_extended))
		return -EINVAL;

	mutex_lock(&icc_lock);

	INIT_LIST_HEAD(&provider->nodes);
	list_add_tail(&provider->provider_list, &icc_providers);

	mutex_unlock(&icc_lock);

	dev_dbg(provider->dev, "interconnect provider added to topology\n");
	dev_dbg(provider->dev, "interconnect provider registered\n");

	return 0;
}
EXPORT_SYMBOL_GPL(icc_provider_add);
EXPORT_SYMBOL_GPL(icc_provider_register);

/**
 * icc_provider_del() - delete previously added interconnect provider
 * @provider: the interconnect provider that will be removed from topology
 * icc_provider_deregister() - deregister an interconnect provider
 * @provider: the interconnect provider to deregister
 */
void icc_provider_del(struct icc_provider *provider)
void icc_provider_deregister(struct icc_provider *provider)
{
	mutex_lock(&icc_lock);
	if (provider->users) {
		pr_warn("interconnect provider still has %d users\n",
			provider->users);
	WARN_ON(provider->users);

	list_del(&provider->provider_list);
	mutex_unlock(&icc_lock);
		return;
}
EXPORT_SYMBOL_GPL(icc_provider_deregister);

	if (!list_empty(&provider->nodes)) {
		pr_warn("interconnect provider still has nodes\n");
		mutex_unlock(&icc_lock);
		return;
int icc_provider_add(struct icc_provider *provider)
{
	icc_provider_init(provider);

	return icc_provider_register(provider);
}
EXPORT_SYMBOL_GPL(icc_provider_add);

	list_del(&provider->provider_list);
	mutex_unlock(&icc_lock);
void icc_provider_del(struct icc_provider *provider)
{
	WARN_ON(!list_empty(&provider->nodes));

	icc_provider_deregister(provider);
}
EXPORT_SYMBOL_GPL(icc_provider_del);

+10 −10
Original line number Diff line number Diff line
@@ -295,6 +295,9 @@ int imx_icc_register(struct platform_device *pdev,
	provider->xlate = of_icc_xlate_onecell;
	provider->data = data;
	provider->dev = dev->parent;

	icc_provider_init(provider);

	platform_set_drvdata(pdev, imx_provider);

	if (settings) {
@@ -306,20 +309,18 @@ int imx_icc_register(struct platform_device *pdev,
		}
	}

	ret = icc_provider_add(provider);
	if (ret) {
		dev_err(dev, "error adding interconnect provider: %d\n", ret);
	ret = imx_icc_register_nodes(imx_provider, nodes, nodes_count, settings);
	if (ret)
		return ret;
	}

	ret = imx_icc_register_nodes(imx_provider, nodes, nodes_count, settings);
	ret = icc_provider_register(provider);
	if (ret)
		goto provider_del;
		goto err_unregister_nodes;

	return 0;

provider_del:
	icc_provider_del(provider);
err_unregister_nodes:
	imx_icc_unregister_nodes(&imx_provider->provider);
	return ret;
}
EXPORT_SYMBOL_GPL(imx_icc_register);
@@ -328,9 +329,8 @@ void imx_icc_unregister(struct platform_device *pdev)
{
	struct imx_icc_provider *imx_provider = platform_get_drvdata(pdev);

	icc_provider_deregister(&imx_provider->provider);
	imx_icc_unregister_nodes(&imx_provider->provider);

	icc_provider_del(&imx_provider->provider);
}
EXPORT_SYMBOL_GPL(imx_icc_unregister);

+16 −13
Original line number Diff line number Diff line
@@ -503,7 +503,6 @@ int qnoc_probe(struct platform_device *pdev)
	}

	provider = &qp->provider;
	INIT_LIST_HEAD(&provider->nodes);
	provider->dev = dev;
	provider->set = qcom_icc_set;
	provider->pre_aggregate = qcom_icc_pre_bw_aggregate;
@@ -511,12 +510,7 @@ int qnoc_probe(struct platform_device *pdev)
	provider->xlate_extended = qcom_icc_xlate_extended;
	provider->data = data;

	ret = icc_provider_add(provider);
	if (ret) {
		dev_err(dev, "error adding interconnect provider: %d\n", ret);
		clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
		return ret;
	}
	icc_provider_init(provider);

	for (i = 0; i < num_nodes; i++) {
		size_t j;
@@ -524,7 +518,7 @@ int qnoc_probe(struct platform_device *pdev)
		node = icc_node_create(qnodes[i]->id);
		if (IS_ERR(node)) {
			ret = PTR_ERR(node);
			goto err;
			goto err_remove_nodes;
		}

		node->name = qnodes[i]->name;
@@ -538,17 +532,26 @@ int qnoc_probe(struct platform_device *pdev)
	}
	data->num_nodes = num_nodes;

	ret = icc_provider_register(provider);
	if (ret)
		goto err_remove_nodes;

	platform_set_drvdata(pdev, qp);

	/* Populate child NoC devices if any */
	if (of_get_child_count(dev->of_node) > 0)
		return of_platform_populate(dev->of_node, NULL, NULL, dev);
	if (of_get_child_count(dev->of_node) > 0) {
		ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
		if (ret)
			goto err_deregister_provider;
	}

	return 0;
err:

err_deregister_provider:
	icc_provider_deregister(provider);
err_remove_nodes:
	icc_nodes_remove(provider);
	clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
	icc_provider_del(provider);

	return ret;
}
@@ -558,9 +561,9 @@ int qnoc_remove(struct platform_device *pdev)
{
	struct qcom_icc_provider *qp = platform_get_drvdata(pdev);

	icc_provider_deregister(&qp->provider);
	icc_nodes_remove(&qp->provider);
	clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
	icc_provider_del(&qp->provider);

	return 0;
}
+19 −11
Original line number Diff line number Diff line
@@ -192,9 +192,10 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
	provider->pre_aggregate = qcom_icc_pre_aggregate;
	provider->aggregate = qcom_icc_aggregate;
	provider->xlate_extended = qcom_icc_xlate_extended;
	INIT_LIST_HEAD(&provider->nodes);
	provider->data = data;

	icc_provider_init(provider);

	qp->dev = dev;
	qp->bcms = desc->bcms;
	qp->num_bcms = desc->num_bcms;
@@ -203,10 +204,6 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
	if (IS_ERR(qp->voter))
		return PTR_ERR(qp->voter);

	ret = icc_provider_add(provider);
	if (ret)
		return ret;

	for (i = 0; i < qp->num_bcms; i++)
		qcom_icc_bcm_init(qp->bcms[i], dev);

@@ -218,7 +215,7 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
		node = icc_node_create(qn->id);
		if (IS_ERR(node)) {
			ret = PTR_ERR(node);
			goto err;
			goto err_remove_nodes;
		}

		node->name = qn->name;
@@ -232,16 +229,27 @@ int qcom_icc_rpmh_probe(struct platform_device *pdev)
	}

	data->num_nodes = num_nodes;

	ret = icc_provider_register(provider);
	if (ret)
		goto err_remove_nodes;

	platform_set_drvdata(pdev, qp);

	/* Populate child NoC devices if any */
	if (of_get_child_count(dev->of_node) > 0)
		return of_platform_populate(dev->of_node, NULL, NULL, dev);
	if (of_get_child_count(dev->of_node) > 0) {
		ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
		if (ret)
			goto err_deregister_provider;
	}

	return 0;
err:

err_deregister_provider:
	icc_provider_deregister(provider);
err_remove_nodes:
	icc_nodes_remove(provider);
	icc_provider_del(provider);

	return ret;
}
EXPORT_SYMBOL_GPL(qcom_icc_rpmh_probe);
@@ -250,8 +258,8 @@ int qcom_icc_rpmh_remove(struct platform_device *pdev)
{
	struct qcom_icc_provider *qp = platform_get_drvdata(pdev);

	icc_provider_deregister(&qp->provider);
	icc_nodes_remove(&qp->provider);
	icc_provider_del(&qp->provider);

	return 0;
}
+8 −12
Original line number Diff line number Diff line
@@ -692,7 +692,6 @@ static int msm8974_icc_probe(struct platform_device *pdev)
		return ret;

	provider = &qp->provider;
	INIT_LIST_HEAD(&provider->nodes);
	provider->dev = dev;
	provider->set = msm8974_icc_set;
	provider->aggregate = icc_std_aggregate;
@@ -700,11 +699,7 @@ static int msm8974_icc_probe(struct platform_device *pdev)
	provider->data = data;
	provider->get_bw = msm8974_get_bw;

	ret = icc_provider_add(provider);
	if (ret) {
		dev_err(dev, "error adding interconnect provider: %d\n", ret);
		goto err_disable_clks;
	}
	icc_provider_init(provider);

	for (i = 0; i < num_nodes; i++) {
		size_t j;
@@ -712,7 +707,7 @@ static int msm8974_icc_probe(struct platform_device *pdev)
		node = icc_node_create(qnodes[i]->id);
		if (IS_ERR(node)) {
			ret = PTR_ERR(node);
			goto err_del_icc;
			goto err_remove_nodes;
		}

		node->name = qnodes[i]->name;
@@ -729,15 +724,16 @@ static int msm8974_icc_probe(struct platform_device *pdev)
	}
	data->num_nodes = num_nodes;

	ret = icc_provider_register(provider);
	if (ret)
		goto err_remove_nodes;

	platform_set_drvdata(pdev, qp);

	return 0;

err_del_icc:
err_remove_nodes:
	icc_nodes_remove(provider);
	icc_provider_del(provider);

err_disable_clks:
	clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);

	return ret;
@@ -747,9 +743,9 @@ static int msm8974_icc_remove(struct platform_device *pdev)
{
	struct msm8974_icc_provider *qp = platform_get_drvdata(pdev);

	icc_provider_deregister(&qp->provider);
	icc_nodes_remove(&qp->provider);
	clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
	icc_provider_del(&qp->provider);

	return 0;
}
Loading