[PATCH v2 07/10] irqdomain: Allow giving name suffix for domain

Matti Vaittinen
2024-05-24T08:19:01Z

[-- Attachment #1: Type: text/plain, Size: 10069 bytes --]

When multiple IRQ domains are created from same device-tree node they
will get same name based on the device-tree path. This will cause a
naming collision in debugFS when IRQ domain specific entries are
created.

One use-case for being able to create multiple IRQ domains / single
device node is using regmap-IRQ controller code for devices which
provide more than one physical IRQ. It seems much cleaner to instantiate
own regmap-IRQ controller for each parent IRQ because most of the regmap
IRQ properties are really specific to parent IRQ.

Allow giving a suffix to IRQ domain name to avoid naming collisions.

Signed-off-by: Matti Vaittinen <mazziesaccount@gmail.com>

---
Some devices which could use this are ROHM's BD96801, BD96802 and BD96811
PMICs. BD96801 is being upstreamed, others are on my TODO list - but I
believe this may be beneficial to any other devices as well. Especially
for those which provide IRQs that are clearly different form each
other.

Some discussion about this can be found from:
https://lore.kernel.org/all/Zjzt8mOW6dO_7XNV@finisterre.sirena.org.uk/
---
include/linux/irqdomain.h | 28 ++++++++++++++++-----
kernel/irq/irqdomain.c | 53 +++++++++++++++++++++++++++++++--------
2 files changed, 65 insertions(+), 16 deletions(-)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 21ecf582a0fe..7b1123fbd453 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -260,7 +260,7 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode);
struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size,
irq_hw_number_t hwirq_max, int direct_max,
const struct irq_domain_ops *ops,
- void *host_data);
+ void *host_data, const char *name_suffix);
struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode,
unsigned int size,
unsigned int first_irq,
@@ -272,6 +272,12 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
irq_hw_number_t first_hwirq,
const struct irq_domain_ops *ops,
void *host_data);
+struct irq_domain *irq_domain_create_legacy_named(struct fwnode_handle *fwnode,
+ unsigned int size,
+ unsigned int first_irq,
+ irq_hw_number_t first_hwirq,
+ const struct irq_domain_ops *ops,
+ void *host_data, const char *name_suffix);
struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode,
unsigned int size,
unsigned int first_irq,
@@ -350,7 +356,8 @@ static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_no
const struct irq_domain_ops *ops,
void *host_data)
{
- return __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops, host_data);
+ return __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops,
+ host_data, NULL);
}

#ifdef CONFIG_IRQ_DOMAIN_NOMAP
@@ -359,7 +366,8 @@ static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_nod
const struct irq_domain_ops *ops,
void *host_data)
{
- return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq, ops, host_data);
+ return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq,
+ ops, host_data, NULL);
}

extern unsigned int irq_create_direct_mapping(struct irq_domain *host);
@@ -369,7 +377,7 @@ static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node
const struct irq_domain_ops *ops,
void *host_data)
{
- return __irq_domain_add(of_node_to_fwnode(of_node), 0, ~0, 0, ops, host_data);
+ return __irq_domain_add(of_node_to_fwnode(of_node), 0, ~0, 0, ops, host_data, NULL);
}

static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *fwnode,
@@ -377,14 +385,22 @@ static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *
const struct irq_domain_ops *ops,
void *host_data)
{
- return __irq_domain_add(fwnode, size, size, 0, ops, host_data);
+ return __irq_domain_add(fwnode, size, size, 0, ops, host_data, NULL);
+}
+
+static inline struct irq_domain *irq_domain_create_linear_named(struct fwnode_handle *fwnode,
+ unsigned int size,
+ const struct irq_domain_ops *ops,
+ void *host_data, const char *name_suffix)
+{
+ return __irq_domain_add(fwnode, size, size, 0, ops, host_data, name_suffix);
}

static inline struct irq_domain *irq_domain_create_tree(struct fwnode_handle *fwnode,
const struct irq_domain_ops *ops,
void *host_data)
{
- return __irq_domain_add(fwnode, 0, ~0, 0, ops, host_data);
+ return __irq_domain_add(fwnode, 0, ~0, 0, ops, host_data, NULL);
}

extern void irq_domain_remove(struct irq_domain *host);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 3dd1c871e091..07802c48bade 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -132,7 +132,8 @@ static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode,
irq_hw_number_t hwirq_max,
int direct_max,
const struct irq_domain_ops *ops,
- void *host_data)
+ void *host_data,
+ const char *name_suffix)
{
struct irqchip_fwid *fwid;
struct irq_domain *domain;
@@ -150,6 +151,17 @@ static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode,
return NULL;

if (is_fwnode_irqchip(fwnode)) {
+ /*
+ * The name_suffix is only intended to be used to avoid a name
+ * collison, when multiple domains are created for a single
+ * device and the name is picked using a real device node.
+ * (Typical use-case is regmap-IRQ controllers for devices
+ * providing more than one physical IRQ.) There should be no
+ * need to use name_suffix with irqchip-fwnode.
+ */
+ if (name_suffix)
+ return NULL;
+
fwid = container_of(fwnode, struct irqchip_fwid, fwnode);

switch (fwid->type) {
@@ -177,7 +189,11 @@ static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode,
* unhappy about. Replace them with ':', which does
* the trick and is not as offensive as '\'...
*/
- name = kasprintf(GFP_KERNEL, "%pfw", fwnode);
+ if (!name_suffix)
+ name = kasprintf(GFP_KERNEL, "%pfw", fwnode);
+ else
+ name = kasprintf(GFP_KERNEL, "%pfw-%s", fwnode,
+ name_suffix);
if (!name) {
kfree(domain);
return NULL;
@@ -249,6 +265,8 @@ static void __irq_domain_publish(struct irq_domain *domain)
* direct mapping
* @ops: domain callbacks
* @host_data: Controller private data pointer
+ * @name_suffix: Optional name suffix to avoid collisions when multiple domains
+ * are added using same fwnode
*
* Allocates and initializes an irq_domain structure.
* Returns pointer to IRQ domain, or NULL on failure.
@@ -256,12 +274,12 @@ static void __irq_domain_publish(struct irq_domain *domain)
struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size,
irq_hw_number_t hwirq_max, int direct_max,
const struct irq_domain_ops *ops,
- void *host_data)
+ void *host_data, const char *name_suffix)
{
struct irq_domain *domain;

domain = __irq_domain_create(fwnode, size, hwirq_max, direct_max,
- ops, host_data);
+ ops, host_data, name_suffix);
if (domain)
__irq_domain_publish(domain);

@@ -362,7 +380,7 @@ struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode,
{
struct irq_domain *domain;

- domain = __irq_domain_add(fwnode, size, size, 0, ops, host_data);
+ domain = __irq_domain_add(fwnode, size, size, 0, ops, host_data, NULL);
if (!domain)
return NULL;

@@ -409,21 +427,34 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
}
EXPORT_SYMBOL_GPL(irq_domain_add_legacy);

-struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode,
+struct irq_domain *irq_domain_create_legacy_named(struct fwnode_handle *fwnode,
unsigned int size,
unsigned int first_irq,
irq_hw_number_t first_hwirq,
const struct irq_domain_ops *ops,
- void *host_data)
+ void *host_data, const char *name_suffix)
{
struct irq_domain *domain;

- domain = __irq_domain_add(fwnode, first_hwirq + size, first_hwirq + size, 0, ops, host_data);
+ domain = __irq_domain_add(fwnode, first_hwirq + size, first_hwirq + size,
+ 0, ops, host_data, name_suffix);
if (domain)
irq_domain_associate_many(domain, first_irq, first_hwirq, size);

return domain;
}
+EXPORT_SYMBOL_GPL(irq_domain_create_legacy_named);
+
+struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode,
+ unsigned int size,
+ unsigned int first_irq,
+ irq_hw_number_t first_hwirq,
+ const struct irq_domain_ops *ops,
+ void *host_data)
+{
+ return irq_domain_create_legacy_named(fwnode, size, first_irq,
+ first_hwirq, ops, host_data, NULL);
+}
EXPORT_SYMBOL_GPL(irq_domain_create_legacy);

/**
@@ -1146,9 +1177,11 @@ struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent,
struct irq_domain *domain;

if (size)
- domain = __irq_domain_create(fwnode, size, size, 0, ops, host_data);
+ domain = __irq_domain_create(fwnode, size, size, 0, ops,
+ host_data, NULL);
else
- domain = __irq_domain_create(fwnode, 0, ~0, 0, ops, host_data);
+ domain = __irq_domain_create(fwnode, 0, ~0, 0, ops, host_data,
+ NULL);

if (domain) {
if (parent)