[PATCH 03/23] interconnect: fix provider registration API

Konrad Dybcio konrad.dybcio at linaro.org
Thu Feb 2 18:48:47 PST 2023



On 1.02.2023 11:15, Johan Hovold wrote:
> 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: 11f1ceca7031 ("interconnect: Add generic on-chip interconnect API")
> Fixes: 87e3031b6fbd ("interconnect: Allow endpoints translation via DT")
> Cc: stable at vger.kernel.org      # 5.1
> Signed-off-by: Johan Hovold <johan+linaro at kernel.org>
> ---
Reviewed-by: Konrad Dybcio <konrad.dybcio at linaro.org>

Konrad
>  drivers/interconnect/core.c           | 52 +++++++++++++++++++--------
>  include/linux/interconnect-provider.h | 12 +++++++
>  2 files changed, 50 insertions(+), 14 deletions(-)
> 
> diff --git a/drivers/interconnect/core.c b/drivers/interconnect/core.c
> index 43c5c8503ee8..93d27ff8eef6 100644
> --- a/drivers/interconnect/core.c
> +++ b/drivers/interconnect/core.c
> @@ -1030,44 +1030,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[] = {
> diff --git a/include/linux/interconnect-provider.h b/include/linux/interconnect-provider.h
> index cd5c5a27557f..d12cd18aab3f 100644
> --- a/include/linux/interconnect-provider.h
> +++ b/include/linux/interconnect-provider.h
> @@ -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;



More information about the linux-arm-kernel mailing list