lkml.org 
[lkml]   [2023]   [Mar]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 03/23] interconnect: fix provider registration API
    Date
    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@vger.kernel.org # 5.1
    Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
    Signed-off-by: Johan Hovold <johan+linaro@kernel.org>
    ---
    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 cabb6f5df83e..7a24c1444ace 100644
    --- a/drivers/interconnect/core.c
    +++ b/drivers/interconnect/core.c
    @@ -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[] = {
    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;
    --
    2.39.2
    \
     
     \ /
      Last update: 2023-03-27 00:44    [W:4.135 / U:0.068 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site