Skip to content

Commit d59f661

Browse files
committed
genirq: Allow fwnode to carry name information only
In order to provide proper debug interface it's required to have domain names available when the domain is added. Non fwnode based architectures like x86 have no way to do so. It's not possible to use domain ops or host data for this as domain ops might be the same for several instances, but the names have to be unique. Extend the irqchip fwnode to allow transporting the domain name. If no node is supplied, create a 'unknown-N' placeholder. Warn if an invalid node is supplied and treat it like no node. This happens e.g. with i2 devices on x86 which hand in an ACPI type node which has no interface for retrieving the name. [ Folded a fix from Marc to make DT name parsing work ] Signed-off-by: Thomas Gleixner <[email protected]> Acked-by: Marc Zyngier <[email protected]> Cc: Jens Axboe <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Keith Busch <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Christoph Hellwig <[email protected]> Link: http://lkml.kernel.org/r/[email protected]
1 parent 0165308 commit d59f661

File tree

2 files changed

+122
-14
lines changed

2 files changed

+122
-14
lines changed

include/linux/irqdomain.h

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,9 @@ enum {
189189
/* Irq domain implements MSI remapping */
190190
IRQ_DOMAIN_FLAG_MSI_REMAP = (1 << 5),
191191

192+
/* Irq domain name was allocated in __irq_domain_add() */
193+
IRQ_DOMAIN_NAME_ALLOCATED = (1 << 6),
194+
192195
/*
193196
* Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
194197
* for implementation specific purposes and ignored by the
@@ -203,7 +206,33 @@ static inline struct device_node *irq_domain_get_of_node(struct irq_domain *d)
203206
}
204207

205208
#ifdef CONFIG_IRQ_DOMAIN
206-
struct fwnode_handle *irq_domain_alloc_fwnode(void *data);
209+
struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id,
210+
const char *name, void *data);
211+
212+
enum {
213+
IRQCHIP_FWNODE_REAL,
214+
IRQCHIP_FWNODE_NAMED,
215+
IRQCHIP_FWNODE_NAMED_ID,
216+
};
217+
218+
static inline
219+
struct fwnode_handle *irq_domain_alloc_named_fwnode(const char *name)
220+
{
221+
return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED, 0, name, NULL);
222+
}
223+
224+
static inline
225+
struct fwnode_handle *irq_domain_alloc_named_id_fwnode(const char *name, int id)
226+
{
227+
return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_NAMED_ID, id, name,
228+
NULL);
229+
}
230+
231+
static inline struct fwnode_handle *irq_domain_alloc_fwnode(void *data)
232+
{
233+
return __irq_domain_alloc_fwnode(IRQCHIP_FWNODE_REAL, 0, NULL, data);
234+
}
235+
207236
void irq_domain_free_fwnode(struct fwnode_handle *fwnode);
208237
struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
209238
irq_hw_number_t hwirq_max, int direct_max,

kernel/irq/irqdomain.c

Lines changed: 92 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,39 +26,61 @@ static struct irq_domain *irq_default_domain;
2626
static void irq_domain_check_hierarchy(struct irq_domain *domain);
2727

2828
struct irqchip_fwid {
29-
struct fwnode_handle fwnode;
30-
char *name;
31-
void *data;
29+
struct fwnode_handle fwnode;
30+
unsigned int type;
31+
char *name;
32+
void *data;
3233
};
3334

3435
/**
3536
* irq_domain_alloc_fwnode - Allocate a fwnode_handle suitable for
3637
* identifying an irq domain
37-
* @data: optional user-provided data
38+
* @type: Type of irqchip_fwnode. See linux/irqdomain.h
39+
* @name: Optional user provided domain name
40+
* @id: Optional user provided id if name != NULL
41+
* @data: Optional user-provided data
3842
*
39-
* Allocate a struct device_node, and return a poiner to the embedded
43+
* Allocate a struct irqchip_fwid, and return a poiner to the embedded
4044
* fwnode_handle (or NULL on failure).
45+
*
46+
* Note: The types IRQCHIP_FWNODE_NAMED and IRQCHIP_FWNODE_NAMED_ID are
47+
* solely to transport name information to irqdomain creation code. The
48+
* node is not stored. For other types the pointer is kept in the irq
49+
* domain struct.
4150
*/
42-
struct fwnode_handle *irq_domain_alloc_fwnode(void *data)
51+
struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id,
52+
const char *name, void *data)
4353
{
4454
struct irqchip_fwid *fwid;
45-
char *name;
55+
char *n;
4656

4757
fwid = kzalloc(sizeof(*fwid), GFP_KERNEL);
48-
name = kasprintf(GFP_KERNEL, "irqchip@%p", data);
4958

50-
if (!fwid || !name) {
59+
switch (type) {
60+
case IRQCHIP_FWNODE_NAMED:
61+
n = kasprintf(GFP_KERNEL, "%s", name);
62+
break;
63+
case IRQCHIP_FWNODE_NAMED_ID:
64+
n = kasprintf(GFP_KERNEL, "%s-%d", name, id);
65+
break;
66+
default:
67+
n = kasprintf(GFP_KERNEL, "irqchip@%p", data);
68+
break;
69+
}
70+
71+
if (!fwid || !n) {
5172
kfree(fwid);
52-
kfree(name);
73+
kfree(n);
5374
return NULL;
5475
}
5576

56-
fwid->name = name;
77+
fwid->type = type;
78+
fwid->name = n;
5779
fwid->data = data;
5880
fwid->fwnode.type = FWNODE_IRQCHIP;
5981
return &fwid->fwnode;
6082
}
61-
EXPORT_SYMBOL_GPL(irq_domain_alloc_fwnode);
83+
EXPORT_SYMBOL_GPL(__irq_domain_alloc_fwnode);
6284

6385
/**
6486
* irq_domain_free_fwnode - Free a non-OF-backed fwnode_handle
@@ -97,20 +119,75 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
97119
void *host_data)
98120
{
99121
struct device_node *of_node = to_of_node(fwnode);
122+
struct irqchip_fwid *fwid;
100123
struct irq_domain *domain;
101124

125+
static atomic_t unknown_domains;
126+
102127
domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
103128
GFP_KERNEL, of_node_to_nid(of_node));
104129
if (WARN_ON(!domain))
105130
return NULL;
106131

132+
if (fwnode && is_fwnode_irqchip(fwnode)) {
133+
fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
134+
135+
switch (fwid->type) {
136+
case IRQCHIP_FWNODE_NAMED:
137+
case IRQCHIP_FWNODE_NAMED_ID:
138+
domain->name = kstrdup(fwid->name, GFP_KERNEL);
139+
if (!domain->name) {
140+
kfree(domain);
141+
return NULL;
142+
}
143+
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
144+
break;
145+
default:
146+
domain->fwnode = fwnode;
147+
domain->name = fwid->name;
148+
break;
149+
}
150+
} else if (of_node) {
151+
char *name;
152+
153+
/*
154+
* DT paths contain '/', which debugfs is legitimately
155+
* unhappy about. Replace them with ':', which does
156+
* the trick and is not as offensive as '\'...
157+
*/
158+
name = kstrdup(of_node_full_name(of_node), GFP_KERNEL);
159+
if (!name) {
160+
kfree(domain);
161+
return NULL;
162+
}
163+
164+
strreplace(name, '/', ':');
165+
166+
domain->name = name;
167+
domain->fwnode = fwnode;
168+
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
169+
}
170+
171+
if (!domain->name) {
172+
if (fwnode) {
173+
pr_err("Invalid fwnode type (%d) for irqdomain\n",
174+
fwnode->type);
175+
}
176+
domain->name = kasprintf(GFP_KERNEL, "unknown-%d",
177+
atomic_inc_return(&unknown_domains));
178+
if (!domain->name) {
179+
kfree(domain);
180+
return NULL;
181+
}
182+
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
183+
}
184+
107185
of_node_get(of_node);
108186

109187
/* Fill structure */
110188
INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL);
111189
domain->ops = ops;
112190
domain->host_data = host_data;
113-
domain->fwnode = fwnode;
114191
domain->hwirq_max = hwirq_max;
115192
domain->revmap_size = size;
116193
domain->revmap_direct_max_irq = direct_max;
@@ -152,6 +229,8 @@ void irq_domain_remove(struct irq_domain *domain)
152229
pr_debug("Removed domain %s\n", domain->name);
153230

154231
of_node_put(irq_domain_get_of_node(domain));
232+
if (domain->flags & IRQ_DOMAIN_NAME_ALLOCATED)
233+
kfree(domain->name);
155234
kfree(domain);
156235
}
157236
EXPORT_SYMBOL_GPL(irq_domain_remove);

0 commit comments

Comments
 (0)