[PATCH v3 04/26] platform: Add firmware-agnostic irq and affinity retrieval interface

Marc Zyngier posted 26 patches 4 months, 2 weeks ago
There is a newer version of this series
[PATCH v3 04/26] platform: Add firmware-agnostic irq and affinity retrieval interface
Posted by Marc Zyngier 4 months, 2 weeks ago
Expand platform_get_irq_optional() to also return an affinity if
available, renaming it to platform_get_irq_affinity() in the
process.

platform_get_irq_optional() is preserved with its current semantics
by calling into the new helper with a NULL affinity pointer.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 drivers/base/platform.c         | 60 +++++++++++++++++++++++++++------
 include/linux/platform_device.h |  2 ++
 2 files changed, 52 insertions(+), 10 deletions(-)

diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 09450349cf323..3a058f63ef0d3 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -150,25 +150,37 @@ devm_platform_ioremap_resource_byname(struct platform_device *pdev,
 EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname);
 #endif /* CONFIG_HAS_IOMEM */
 
+static const struct cpumask *get_irq_affinity(struct platform_device *dev,
+					      unsigned int num)
+{
+	const struct cpumask *mask = NULL;
+#ifndef CONFIG_SPARC
+	struct fwnode_handle *fwnode = dev_fwnode(&dev->dev);
+
+	if (is_of_node(fwnode))
+		mask = of_irq_get_affinity(to_of_node(fwnode), num);
+	else if (is_acpi_device_node(fwnode))
+		mask = acpi_irq_get_affinity(ACPI_HANDLE_FWNODE(fwnode), num);
+#endif
+
+	return mask ?: cpu_possible_mask;
+}
+
 /**
- * platform_get_irq_optional - get an optional IRQ for a device
+ * platform_get_irq_affinity - get an optional IRQ and its affinity for a device
  * @dev: platform device
  * @num: IRQ number index
+ * @affinity: optional cpumask pointer to get the affinity of a per-cpu IRQ
  *
  * Gets an IRQ for a platform device. Device drivers should check the return
  * value for errors so as to not pass a negative integer value to the
- * request_irq() APIs. This is the same as platform_get_irq(), except that it
- * does not print an error message if an IRQ can not be obtained.
- *
- * For example::
- *
- *		int irq = platform_get_irq_optional(pdev, 0);
- *		if (irq < 0)
- *			return irq;
+ * request_irq() APIs. Optional affinity information is provided in the
+ * affinity pointer if available, and NULL otherwise.
  *
  * Return: non-zero IRQ number on success, negative error number on failure.
  */
-int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
+int platform_get_irq_affinity(struct platform_device *dev, unsigned int num,
+			      const struct cpumask **affinity)
 {
 	int ret;
 #ifdef CONFIG_SPARC
@@ -236,8 +248,36 @@ int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
 out:
 	if (WARN(!ret, "0 is an invalid IRQ number\n"))
 		return -EINVAL;
+
+	if (ret > 0 && affinity)
+		*affinity = get_irq_affinity(dev, num);
+
 	return ret;
 }
+EXPORT_SYMBOL_GPL(platform_get_irq_affinity);
+
+/**
+ * platform_get_irq_optional - get an optional IRQ for a device
+ * @dev: platform device
+ * @num: IRQ number index
+ *
+ * Gets an IRQ for a platform device. Device drivers should check the return
+ * value for errors so as to not pass a negative integer value to the
+ * request_irq() APIs. This is the same as platform_get_irq(), except that it
+ * does not print an error message if an IRQ can not be obtained.
+ *
+ * For example::
+ *
+ *		int irq = platform_get_irq_optional(pdev, 0);
+ *		if (irq < 0)
+ *			return irq;
+ *
+ * Return: non-zero IRQ number on success, negative error number on failure.
+ */
+int platform_get_irq_optional(struct platform_device *dev, unsigned int num)
+{
+	return platform_get_irq_affinity(dev, num, NULL);
+}
 EXPORT_SYMBOL_GPL(platform_get_irq_optional);
 
 /**
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 074754c23d330..ad66333ce85ce 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -102,6 +102,8 @@ devm_platform_ioremap_resource_byname(struct platform_device *pdev,
 
 extern int platform_get_irq(struct platform_device *, unsigned int);
 extern int platform_get_irq_optional(struct platform_device *, unsigned int);
+extern int platform_get_irq_affinity(struct platform_device *, unsigned int,
+				     const struct cpumask **);
 extern int platform_irq_count(struct platform_device *);
 extern int devm_platform_get_irqs_affinity(struct platform_device *dev,
 					   struct irq_affinity *affd,
-- 
2.47.3
Re: [PATCH v3 04/26] platform: Add firmware-agnostic irq and affinity retrieval interface
Posted by Jonathan Cameron 4 months ago
On Mon, 22 Sep 2025 09:28:11 +0100
Marc Zyngier <maz@kernel.org> wrote:

> Expand platform_get_irq_optional() to also return an affinity if
> available, renaming it to platform_get_irq_affinity() in the
> process.
> 
> platform_get_irq_optional() is preserved with its current semantics
> by calling into the new helper with a NULL affinity pointer.
> 
> Signed-off-by: Marc Zyngier <maz@kernel.org>

Maybe a breadcrumb of a comment for those of us who can't be bothered
to figure out why this needs the ifndef CONFIG_SPARC?

Otherwise a question on whether it's worth spinning a fwnode.h handler
to hide away the fwnode type in get_irq_affinity.
I think not given the complexity already there for the platform device
irq stuff, but thought I'd mention it.

Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>

> ---
>  drivers/base/platform.c         | 60 +++++++++++++++++++++++++++------
>  include/linux/platform_device.h |  2 ++
>  2 files changed, 52 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> index 09450349cf323..3a058f63ef0d3 100644
> --- a/drivers/base/platform.c
> +++ b/drivers/base/platform.c
> @@ -150,25 +150,37 @@ devm_platform_ioremap_resource_byname(struct platform_device *pdev,
>  EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname);
>  #endif /* CONFIG_HAS_IOMEM */
>  
> +static const struct cpumask *get_irq_affinity(struct platform_device *dev,
> +					      unsigned int num)
> +{
> +	const struct cpumask *mask = NULL;
> +#ifndef CONFIG_SPARC
> +	struct fwnode_handle *fwnode = dev_fwnode(&dev->dev);
> +
> +	if (is_of_node(fwnode))
> +		mask = of_irq_get_affinity(to_of_node(fwnode), num);
> +	else if (is_acpi_device_node(fwnode))
> +		mask = acpi_irq_get_affinity(ACPI_HANDLE_FWNODE(fwnode), num);

Not sure how useful it will be more generally, but maybe use fwnode.h and
appropriate callback rather than opencoding here?

Mind you the extra handling in existing platform_get_irq_optional()
for corner cases doesn't really fit with that model.

> +#endif
> +
> +	return mask ?: cpu_possible_mask;
> +}
Re: [PATCH v3 04/26] platform: Add firmware-agnostic irq and affinity retrieval interface
Posted by Marc Zyngier 3 months, 2 weeks ago
On Thu, 09 Oct 2025 18:03:51 +0100,
Jonathan Cameron <jonathan.cameron@huawei.com> wrote:
> 
> On Mon, 22 Sep 2025 09:28:11 +0100
> Marc Zyngier <maz@kernel.org> wrote:
> 
> > Expand platform_get_irq_optional() to also return an affinity if
> > available, renaming it to platform_get_irq_affinity() in the
> > process.
> > 
> > platform_get_irq_optional() is preserved with its current semantics
> > by calling into the new helper with a NULL affinity pointer.
> > 
> > Signed-off-by: Marc Zyngier <maz@kernel.org>
> 
> Maybe a breadcrumb of a comment for those of us who can't be bothered
> to figure out why this needs the ifndef CONFIG_SPARC?

The main issue is that SPARC, despite using OpenFirmware, does not use
the OF infrastructure (which is basically DT only). This means that
SPARC has its own firmware interface and parses interrupts its own
way, storing them as archdata in the device. Sad state of things,
unfortunately.

> Otherwise a question on whether it's worth spinning a fwnode.h handler
> to hide away the fwnode type in get_irq_affinity.
> I think not given the complexity already there for the platform device
> irq stuff, but thought I'd mention it.

I don't think it'd be worth the hassle at this stage. The platform
code is already a weird mix of DT and ACPI, without any clear
delineation.

If we wanted to do something useful, we'd split that into generic code
on one side (the actual Linux platform device code), and the firmware
specific backend. The main problem is to find a common abstraction,
and ISTR that people found that rather hard, hence the current state.

> 
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>

Thanks for that.

> > ---
> >  drivers/base/platform.c         | 60 +++++++++++++++++++++++++++------
> >  include/linux/platform_device.h |  2 ++
> >  2 files changed, 52 insertions(+), 10 deletions(-)
> > 
> > diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> > index 09450349cf323..3a058f63ef0d3 100644
> > --- a/drivers/base/platform.c
> > +++ b/drivers/base/platform.c
> > @@ -150,25 +150,37 @@ devm_platform_ioremap_resource_byname(struct platform_device *pdev,
> >  EXPORT_SYMBOL_GPL(devm_platform_ioremap_resource_byname);
> >  #endif /* CONFIG_HAS_IOMEM */
> >  
> > +static const struct cpumask *get_irq_affinity(struct platform_device *dev,
> > +					      unsigned int num)
> > +{
> > +	const struct cpumask *mask = NULL;
> > +#ifndef CONFIG_SPARC
> > +	struct fwnode_handle *fwnode = dev_fwnode(&dev->dev);
> > +
> > +	if (is_of_node(fwnode))
> > +		mask = of_irq_get_affinity(to_of_node(fwnode), num);
> > +	else if (is_acpi_device_node(fwnode))
> > +		mask = acpi_irq_get_affinity(ACPI_HANDLE_FWNODE(fwnode), num);
> 
> Not sure how useful it will be more generally, but maybe use fwnode.h and
> appropriate callback rather than opencoding here?
> 
> Mind you the extra handling in existing platform_get_irq_optional()
> for corner cases doesn't really fit with that model.

Indeed, and I find that fwnode.h is currently completely
FW-independent.  I'd rather keep it that way and not expose these
shenanigans outside of the support code *unless* we have a good reason
to do so.

Cheers,

	M.

-- 
Without deviation from the norm, progress is not possible.