On Mon Jul 13, 2026 at 5:11 PM CEST, Bartosz Golaszewski wrote:
> @@ -599,6 +599,7 @@ static void platform_device_release(struct device *dev)
>       struct platform_object *pa = container_of(dev, struct platform_object,
>                                                 pdev.dev);
>  
> +     device_remove_software_node(dev);
>       fwnode_handle_put(pa->pdev.dev.fwnode);

This technically changes the semantics of platform_device_set_fwnode():

Previously it took an additional reference count for the fwnode pointer passed
to it. But now, *iff* the fwnode is a software node it consumes the callers
reference count, which for obvious reasons isn't great.

Now, platform_device_set_fwnode() is unused now, so we could just get rid of it,
which also gets us rid of its asymmetric semantics.

However, couldn't we also just move the if (is_software_node(pdevinfo->fwnode))
conditional up here, such that we have:

        device_remove_software_node(dev);
        if (!is_software_node(dev->fwnode))
            fwnode_handle_put(pa->pdev.dev.fwnode);

This way, the swnode special case would go away. Well, at least the "two
reference counts" special case.

Another special case I just noticed still remains, but is independent of this
change:

If platform_device_set_fwnode() or platform_device_set_of_node() is called for a
device that already has a swnode set, we only call fwnode_handle_put(), but
software_node_notify_remove() etc. isn't called.

Of course that never happens, but it is an inconsistency in the API. Now, it
seems that neither platform_device_set_fwnode() (which we should remove anyway),
nor platform_device_set_of_node() is ever called with a fwnode already set.

So, either we have to special case platform_device_set_of_node() too (for the
case that a swnode is set already), or just require that the function must only
be called when no node has been set, as all users already do; I'd go for the
latter.

If my proposal about moving the is_software_node() check into
platform_device_release() holds, it would probably be good to just add those
patches in a subsequent version, otherwise I'm happy to pull this in as is and
address the other stuff subsequently.

>       kfree(pa->pdev.dev.platform_data);
>       kfree(pa->pdev.mfd_cell);
> @@ -606,12 +607,6 @@ static void platform_device_release(struct device *dev)
>       kfree(pa);
>  }
>  
> -static void platform_device_release_full(struct device *dev)
> -{
> -     device_remove_software_node(dev);
> -     platform_device_release(dev);
> -}
> -
>  /**
>   * platform_device_alloc - create a platform device
>   * @name: base name of the device we're adding
> @@ -933,6 +928,16 @@ struct platform_device 
> *platform_device_register_full(const struct platform_devi
>               pdev->dev.coherent_dma_mask = pdevinfo->dma_mask;
>       }
>  
> +     /*
> +      * If the primary firmware node is a software node and there's no
> +      * secondary firmware node, the primary will be affected by the call
> +      * to device_remove_software_node() in platform_device_release() and
> +      * its reference count will be dropped by one. Take another reference
> +      * here to make it have no effect.
> +      */
> +     if (is_software_node(pdevinfo->fwnode))
> +             fwnode_handle_get(pdevinfo->fwnode);
> +
>       ret = platform_device_add_resources(pdev, pdevinfo->res, 
> pdevinfo->num_res);
>       if (ret)
>               goto err;
> @@ -945,8 +950,6 @@ struct platform_device 
> *platform_device_register_full(const struct platform_devi
>               ret = device_add_software_node(&pdev->dev, pdevinfo->swnode);
>               if (ret)
>                       goto err;
> -
> -             pdev->dev.release = platform_device_release_full;
>       } else if (pdevinfo->properties) {
>               ret = device_create_managed_software_node(&pdev->dev,
>                                                         pdevinfo->properties, 
> NULL);
>
> -- 
> 2.47.3

Reply via email to