[PATCH 01/25] irqdomain: Add firmware info reporting interface

Marc Zyngier posted 25 patches 1 day, 9 hours ago
[PATCH 01/25] irqdomain: Add firmware info reporting interface
Posted by Marc Zyngier 1 day, 9 hours ago
Allow an irqdomain callback to report firmware-provided information
that is otherwise not available in a generic way. This is reported
using a new data structure (struct irq_fwspec_info).

This callback is optional and the only information that can be
reported currently is the affinity of an interrupt. However, the
containing structure is designed to be extensible, allowing other
potentially relevant information to be reported in the future.

Signed-off-by: Marc Zyngier <maz@kernel.org>
---
 include/linux/irqdomain.h | 30 ++++++++++++++++++++++++++++++
 kernel/irq/irqdomain.c    | 33 ++++++++++++++++++++++++++++-----
 2 files changed, 58 insertions(+), 5 deletions(-)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 4a86e6b915dd6..9ec93fb2f5753 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -44,6 +44,27 @@ struct irq_fwspec {
 	u32			param[IRQ_DOMAIN_IRQ_SPEC_PARAMS];
 };
 
+/**
+ * struct irq_fwspec_info - firmware provided IRQ information structure
+ *
+ * @fwspec:		IRQ specifier
+ * @cpumask:		Affinity mask for this interrupt
+ * @flags:		Information validity flags
+ *
+ * This structure reports firmware-specific information about an
+ * interrupt. The only significant information is the affinity of a
+ * per-CPU interrupt, but this is designed to be extended as required.
+ */
+struct irq_fwspec_info {
+	struct irq_fwspec	fwspec;
+	const struct cpumask	*affinity;
+
+#define IRQ_FWSPEC_INFO_FWSPEC_VALID	BIT(0)
+#define IRQ_FWSPEC_INFO_AFFINITY_VALID	BIT(1)
+
+	unsigned long		flags;
+};
+
 /* Conversion function from of_phandle_args fields to fwspec  */
 void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args,
 			       unsigned int count, struct irq_fwspec *fwspec);
@@ -69,6 +90,8 @@ void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args,
  * @translate:	Given @fwspec, decode the hardware irq number (@out_hwirq) and
  *		linux irq type value (@out_type). This is a generalised @xlate
  *		(over struct irq_fwspec) and is preferred if provided.
+ * @get_info: Given @info, report additional firmware-provided information.
+ *            Optional.
  * @debug_show:	For domains to show specific data for an interrupt in debugfs.
  *
  * Functions below are provided by the driver and called whenever a new mapping
@@ -96,6 +119,7 @@ struct irq_domain_ops {
 	void	(*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
 	int	(*translate)(struct irq_domain *d, struct irq_fwspec *fwspec,
 			     unsigned long *out_hwirq, unsigned int *out_type);
+	int (*get_info)(struct irq_fwspec_info *info);
 #endif
 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
 	void	(*debug_show)(struct seq_file *m, struct irq_domain *d,
@@ -602,6 +626,8 @@ void irq_domain_free_irqs_parent(struct irq_domain *domain, unsigned int irq_bas
 
 int irq_domain_disconnect_hierarchy(struct irq_domain *domain, unsigned int virq);
 
+int irq_populate_fwspec_info(struct irq_fwspec_info *info);
+
 static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
 {
 	return domain->flags & IRQ_DOMAIN_FLAG_HIERARCHY;
@@ -685,6 +711,10 @@ static inline bool irq_domain_is_msi_device(struct irq_domain *domain)
 	return false;
 }
 
+static inline int irq_populate_fwspec_info(struct irq_fwspec_info *info)
+{
+	return -EINVAL;
+}
 #endif	/* CONFIG_IRQ_DOMAIN_HIERARCHY */
 
 #ifdef CONFIG_GENERIC_MSI_IRQ
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index dc473faadcc81..f857606e3ffbe 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -867,13 +867,9 @@ void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args,
 }
 EXPORT_SYMBOL_GPL(of_phandle_args_to_fwspec);
 
-unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
+static struct irq_domain *fwspec_to_domain(struct irq_fwspec *fwspec)
 {
 	struct irq_domain *domain;
-	struct irq_data *irq_data;
-	irq_hw_number_t hwirq;
-	unsigned int type = IRQ_TYPE_NONE;
-	int virq;
 
 	if (fwspec->fwnode) {
 		domain = irq_find_matching_fwspec(fwspec, DOMAIN_BUS_WIRED);
@@ -883,6 +879,33 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
 		domain = irq_default_domain;
 	}
 
+	return domain;
+}
+
+#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY
+int irq_populate_fwspec_info(struct irq_fwspec_info *info)
+{
+	struct irq_domain *domain;
+
+	domain = fwspec_to_domain(&info->fwspec);
+	if (!domain || !domain->ops->get_info) {
+		info->flags = 0;
+		return 0;
+	}
+
+	return domain->ops->get_info(info);
+}
+#endif
+
+unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
+{
+	struct irq_domain *domain;
+	struct irq_data *irq_data;
+	irq_hw_number_t hwirq;
+	unsigned int type = IRQ_TYPE_NONE;
+	int virq;
+
+	domain = fwspec_to_domain(fwspec);
 	if (!domain) {
 		pr_warn("no irq domain found for %s !\n",
 			of_node_full_name(to_of_node(fwspec->fwnode)));
-- 
2.39.2
Re: [PATCH 01/25] irqdomain: Add firmware info reporting interface
Posted by Thomas Gleixner 16 hours ago
On Mon, Sep 08 2025 at 17:31, Marc Zyngier wrote:
> +/**
> + * struct irq_fwspec_info - firmware provided IRQ information structure
> + *
> + * @fwspec:		IRQ specifier

s/IRQ/interrupt/g

> + * @cpumask:		Affinity mask for this interrupt
> + * @flags:		Information validity flags
> + *
> + * This structure reports firmware-specific information about an
> + * interrupt. The only significant information is the affinity of a
> + * per-CPU interrupt, but this is designed to be extended as required.
> + */
> +struct irq_fwspec_info {
> +	struct irq_fwspec	fwspec;
> +	const struct cpumask	*affinity;
> +
> +#define IRQ_FWSPEC_INFO_FWSPEC_VALID	BIT(0)
> +#define IRQ_FWSPEC_INFO_AFFINITY_VALID	BIT(1)
> +
> +	unsigned long		flags;

Can you please not stick the defines into the struct. That makes my eyes
bleed.

Also the ordering looks strange as flags should be before the fields it
validates for readability sake, no?

> +};
> +
>  /* Conversion function from of_phandle_args fields to fwspec  */
>  void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args,
>  			       unsigned int count, struct irq_fwspec *fwspec);
> @@ -69,6 +90,8 @@ void of_phandle_args_to_fwspec(struct device_node *np, const u32 *args,
>   * @translate:	Given @fwspec, decode the hardware irq number (@out_hwirq) and
>   *		linux irq type value (@out_type). This is a generalised @xlate
>   *		(over struct irq_fwspec) and is preferred if provided.
> + * @get_info: Given @info, report additional firmware-provided information.
> + *            Optional.

get_info() is pretty generic. Can we have some more descriptive name for
that? Also please keep the tabular formatting of the doc intact.

>   * @debug_show:	For domains to show specific data for an interrupt in debugfs.
>   *
>   * Functions below are provided by the driver and called whenever a new mapping
> @@ -96,6 +119,7 @@ struct irq_domain_ops {
>  	void	(*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
>  	int	(*translate)(struct irq_domain *d, struct irq_fwspec *fwspec,
>  			     unsigned long *out_hwirq, unsigned int *out_type);
> +	int (*get_info)(struct irq_fwspec_info *info);

TAB between int and '(*'

>  #endif
>  #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
>  	void	(*debug_show)(struct seq_file *m, struct irq_domain *d,
> @@ -602,6 +626,8 @@ void irq_domain_free_irqs_parent(struct irq_domain *domain, unsigned int irq_bas
>  
>  int irq_domain_disconnect_hierarchy(struct irq_domain *domain, unsigned int virq);
>  
> +int irq_populate_fwspec_info(struct irq_fwspec_info *info);
> +
> +
> +#ifdef	CONFIG_IRQ_DOMAIN_HIERARCHY

Stray TAB

> +int irq_populate_fwspec_info(struct irq_fwspec_info *info)
> +{
> +	struct irq_domain *domain;
> +
> +	domain = fwspec_to_domain(&info->fwspec);

Just move that to the declaration line

> +	if (!domain || !domain->ops->get_info) {
> +		info->flags = 0;
> +		return 0;
> +	}
> +
> +	return domain->ops->get_info(info);
> +}
> +#endif
> +
> +unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
> +{
> +	struct irq_domain *domain;
> +	struct irq_data *irq_data;
> +	irq_hw_number_t hwirq;
> +	unsigned int type = IRQ_TYPE_NONE;

I know you moved it from the original function, but can you please
reorder it in reverse fir tree order?

> +	int virq;
> +
> +	domain = fwspec_to_domain(fwspec);
>  	if (!domain) {
>  		pr_warn("no irq domain found for %s !\n",
>  			of_node_full_name(to_of_node(fwspec->fwnode)));

Thanks,

        tglx
Re: [PATCH 01/25] irqdomain: Add firmware info reporting interface
Posted by Thomas Gleixner 16 hours ago
On Tue, Sep 09 2025 at 11:18, Thomas Gleixner wrote:
> On Mon, Sep 08 2025 at 17:31, Marc Zyngier wrote:
>> +int irq_populate_fwspec_info(struct irq_fwspec_info *info)
>> +{
>> +	struct irq_domain *domain;
>> +
>> +	domain = fwspec_to_domain(&info->fwspec);
>
> Just move that to the declaration line
>
>> +	if (!domain || !domain->ops->get_info) {
>> +		info->flags = 0;

It looks like @info is not initialized except for info::fwspec. That's a
patently bad idea.

Why has fwspec to be in info in the first place? What's wrong with doing
the obvious:

int irq_populate_fwspec_info(struct irq_fwspec *fwspec, struct irq_fwspec_info *info)
{
        memset(info, 0, sizeof(info));

        ....

No?

Thanks,

        tglx