Commit eb59eca0 authored by Johan Hovold's avatar Johan Hovold Committed by Georgi Djakov

interconnect: fix provider registration API

The current interconnect provider interface is inherently racy as
providers are expected to be added before being fully initialised.

Specifically, nodes are currently not added and the provider data is not
initialised until after registering the provider which can cause racing
DT lookups to fail.

Add a new provider API which will be used to fix up the interconnect
drivers.

The old API is reimplemented using the new interface and will be removed
once all drivers have been fixed.

Fixes: 11f1ceca ("interconnect: Add generic on-chip interconnect API")
Fixes: 87e3031b ("interconnect: Allow endpoints translation via DT")
Cc: stable@vger.kernel.org      # 5.1
Reviewed-by: default avatarKonrad Dybcio <konrad.dybcio@linaro.org>
Signed-off-by: default avatarJohan Hovold <johan+linaro@kernel.org>
Tested-by: Luca Ceresoli <luca.ceresoli@bootlin.com> # i.MX8MP MSC SM2-MB-EP1 Board
Link: https://lore.kernel.org/r/20230306075651.2449-4-johan+linaro@kernel.orgSigned-off-by: default avatarGeorgi Djakov <djakov@kernel.org>
parent e0e7089b
......@@ -1033,44 +1033,68 @@ 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);
WARN_ON(provider->users);
WARN_ON(!list_empty(&provider->nodes));
list_del(&provider->provider_list);
mutex_unlock(&icc_lock);
}
EXPORT_SYMBOL_GPL(icc_provider_deregister);
int icc_provider_add(struct icc_provider *provider)
{
icc_provider_init(provider);
return icc_provider_register(provider);
}
EXPORT_SYMBOL_GPL(icc_provider_add);
void icc_provider_del(struct icc_provider *provider)
{
WARN_ON(!list_empty(&provider->nodes));
icc_provider_deregister(provider);
}
EXPORT_SYMBOL_GPL(icc_provider_del);
static const struct of_device_id __maybe_unused ignore_list[] = {
......
......@@ -122,6 +122,9 @@ int icc_link_destroy(struct icc_node *src, struct icc_node *dst);
void icc_node_add(struct icc_node *node, struct icc_provider *provider);
void icc_node_del(struct icc_node *node);
int icc_nodes_remove(struct icc_provider *provider);
void icc_provider_init(struct icc_provider *provider);
int icc_provider_register(struct icc_provider *provider);
void icc_provider_deregister(struct icc_provider *provider);
int icc_provider_add(struct icc_provider *provider);
void icc_provider_del(struct icc_provider *provider);
struct icc_node_data *of_icc_get_from_provider(struct of_phandle_args *spec);
......@@ -167,6 +170,15 @@ static inline int icc_nodes_remove(struct icc_provider *provider)
return -ENOTSUPP;
}
static inline void icc_provider_init(struct icc_provider *provider) { }
static inline int icc_provider_register(struct icc_provider *provider)
{
return -ENOTSUPP;
}
static inline void icc_provider_deregister(struct icc_provider *provider) { }
static inline int icc_provider_add(struct icc_provider *provider)
{
return -ENOTSUPP;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment