···291291 * @hwirq_max: Maximum number of interrupts supported by controller292292 * @direct_max: Maximum value of direct maps;293293 * Use ~0 for no limit; 0 for no direct mapping294294+ * @hwirq_base: The first hardware interrupt number (legacy domains only)295295+ * @virq_base: The first Linux interrupt number for legacy domains to296296+ * immediately associate the interrupts after domain creation294297 * @bus_token: Domain bus token298298+ * @name_suffix: Optional name suffix to avoid collisions when multiple299299+ * domains are added using same fwnode295300 * @ops: Domain operation callbacks296301 * @host_data: Controller private data pointer297302 * @dgc_info: Geneneric chip information structure pointer used to···312307 unsigned int size;313308 irq_hw_number_t hwirq_max;314309 int direct_max;310310+ unsigned int hwirq_base;311311+ unsigned int virq_base;315312 enum irq_domain_bus_token bus_token;313313+ const char *name_suffix;316314 const struct irq_domain_ops *ops;317315 void *host_data;318316#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+113-85
kernel/irq/irqdomain.c
···128128}129129EXPORT_SYMBOL_GPL(irq_domain_free_fwnode);130130131131-static int irq_domain_set_name(struct irq_domain *domain,132132- const struct fwnode_handle *fwnode,133133- enum irq_domain_bus_token bus_token)131131+static int alloc_name(struct irq_domain *domain, char *base, enum irq_domain_bus_token bus_token)132132+{133133+ domain->name = bus_token ? kasprintf(GFP_KERNEL, "%s-%d", base, bus_token) :134134+ kasprintf(GFP_KERNEL, "%s", base);135135+ if (!domain->name)136136+ return -ENOMEM;137137+138138+ domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;139139+ return 0;140140+}141141+142142+static int alloc_fwnode_name(struct irq_domain *domain, const struct fwnode_handle *fwnode,143143+ enum irq_domain_bus_token bus_token, const char *suffix)144144+{145145+ const char *sep = suffix ? "-" : "";146146+ const char *suf = suffix ? : "";147147+ char *name;148148+149149+ name = bus_token ? kasprintf(GFP_KERNEL, "%pfw-%s%s%d", fwnode, suf, sep, bus_token) :150150+ kasprintf(GFP_KERNEL, "%pfw-%s", fwnode, suf);151151+ if (!name)152152+ return -ENOMEM;153153+154154+ /*155155+ * fwnode paths contain '/', which debugfs is legitimately unhappy156156+ * about. Replace them with ':', which does the trick and is not as157157+ * offensive as '\'...158158+ */159159+ domain->name = strreplace(name, '/', ':');160160+ domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;161161+ return 0;162162+}163163+164164+static int alloc_unknown_name(struct irq_domain *domain, enum irq_domain_bus_token bus_token)134165{135166 static atomic_t unknown_domains;136136- struct irqchip_fwid *fwid;167167+ int id = atomic_inc_return(&unknown_domains);168168+169169+ domain->name = bus_token ? kasprintf(GFP_KERNEL, "unknown-%d-%d", id, bus_token) :170170+ kasprintf(GFP_KERNEL, "unknown-%d", id);171171+172172+ if (!domain->name)173173+ return -ENOMEM;174174+ domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;175175+ return 0;176176+}177177+178178+static int irq_domain_set_name(struct irq_domain *domain, const struct irq_domain_info *info)179179+{180180+ enum irq_domain_bus_token bus_token = info->bus_token;181181+ const struct fwnode_handle *fwnode = info->fwnode;137182138183 if (is_fwnode_irqchip(fwnode)) {139139- fwid = container_of(fwnode, struct irqchip_fwid, fwnode);184184+ struct irqchip_fwid *fwid = container_of(fwnode, struct irqchip_fwid, fwnode);185185+186186+ /*187187+ * The name_suffix is only intended to be used to avoid a name188188+ * collision when multiple domains are created for a single189189+ * device and the name is picked using a real device node.190190+ * (Typical use-case is regmap-IRQ controllers for devices191191+ * providing more than one physical IRQ.) There should be no192192+ * need to use name_suffix with irqchip-fwnode.193193+ */194194+ if (info->name_suffix)195195+ return -EINVAL;140196141197 switch (fwid->type) {142198 case IRQCHIP_FWNODE_NAMED:143199 case IRQCHIP_FWNODE_NAMED_ID:144144- domain->name = bus_token ?145145- kasprintf(GFP_KERNEL, "%s-%d",146146- fwid->name, bus_token) :147147- kstrdup(fwid->name, GFP_KERNEL);148148- if (!domain->name)149149- return -ENOMEM;150150- domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;151151- break;200200+ return alloc_name(domain, fwid->name, bus_token);152201 default:153202 domain->name = fwid->name;154154- if (bus_token) {155155- domain->name = kasprintf(GFP_KERNEL, "%s-%d",156156- fwid->name, bus_token);157157- if (!domain->name)158158- return -ENOMEM;159159- domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;160160- }161161- break;203203+ if (bus_token)204204+ return alloc_name(domain, fwid->name, bus_token);162205 }163163- } else if (is_of_node(fwnode) || is_acpi_device_node(fwnode) ||164164- is_software_node(fwnode)) {165165- char *name;166206167167- /*168168- * fwnode paths contain '/', which debugfs is legitimately169169- * unhappy about. Replace them with ':', which does170170- * the trick and is not as offensive as '\'...171171- */172172- name = bus_token ?173173- kasprintf(GFP_KERNEL, "%pfw-%d", fwnode, bus_token) :174174- kasprintf(GFP_KERNEL, "%pfw", fwnode);175175- if (!name)176176- return -ENOMEM;177177-178178- domain->name = strreplace(name, '/', ':');179179- domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;207207+ } else if (is_of_node(fwnode) || is_acpi_device_node(fwnode) || is_software_node(fwnode)) {208208+ return alloc_fwnode_name(domain, fwnode, bus_token, info->name_suffix);180209 }181210182182- if (!domain->name) {183183- if (fwnode)184184- pr_err("Invalid fwnode type for irqdomain\n");185185- domain->name = bus_token ?186186- kasprintf(GFP_KERNEL, "unknown-%d-%d",187187- atomic_inc_return(&unknown_domains),188188- bus_token) :189189- kasprintf(GFP_KERNEL, "unknown-%d",190190- atomic_inc_return(&unknown_domains));191191- if (!domain->name)192192- return -ENOMEM;193193- domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;194194- }211211+ if (domain->name)212212+ return 0;195213196196- return 0;214214+ if (fwnode)215215+ pr_err("Invalid fwnode type for irqdomain\n");216216+ return alloc_unknown_name(domain, bus_token);197217}198218199219static struct irq_domain *__irq_domain_create(const struct irq_domain_info *info)···231211 if (!domain)232212 return ERR_PTR(-ENOMEM);233213234234- err = irq_domain_set_name(domain, info->fwnode, info->bus_token);214214+ err = irq_domain_set_name(domain, info);235215 if (err) {236216 kfree(domain);237217 return ERR_PTR(err);···287267 kfree(domain);288268}289269290290-/**291291- * irq_domain_instantiate() - Instantiate a new irq domain data structure292292- * @info: Domain information pointer pointing to the information for this domain293293- *294294- * Return: A pointer to the instantiated irq domain or an ERR_PTR value.295295- */296296-struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)270270+static void irq_domain_instantiate_descs(const struct irq_domain_info *info)271271+{272272+ if (!IS_ENABLED(CONFIG_SPARSE_IRQ))273273+ return;274274+275275+ if (irq_alloc_descs(info->virq_base, info->virq_base, info->size,276276+ of_node_to_nid(to_of_node(info->fwnode))) < 0) {277277+ pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",278278+ info->virq_base);279279+ }280280+}281281+282282+static struct irq_domain *__irq_domain_instantiate(const struct irq_domain_info *info,283283+ bool cond_alloc_descs)297284{298285 struct irq_domain *domain;299286 int err;···333306334307 __irq_domain_publish(domain);335308309309+ if (cond_alloc_descs && info->virq_base > 0)310310+ irq_domain_instantiate_descs(info);311311+312312+ /* Legacy interrupt domains have a fixed Linux interrupt number */313313+ if (info->virq_base > 0) {314314+ irq_domain_associate_many(domain, info->virq_base, info->hwirq_base,315315+ info->size - info->hwirq_base);316316+ }317317+336318 return domain;337319338320err_domain_gc_remove:···350314err_domain_free:351315 irq_domain_free(domain);352316 return ERR_PTR(err);317317+}318318+319319+/**320320+ * irq_domain_instantiate() - Instantiate a new irq domain data structure321321+ * @info: Domain information pointer pointing to the information for this domain322322+ *323323+ * Return: A pointer to the instantiated irq domain or an ERR_PTR value.324324+ */325325+struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)326326+{327327+ return __irq_domain_instantiate(info, false);353328}354329EXPORT_SYMBOL_GPL(irq_domain_instantiate);355330···460413 .fwnode = fwnode,461414 .size = size,462415 .hwirq_max = size,416416+ .virq_base = first_irq,463417 .ops = ops,464418 .host_data = host_data,465419 };466466- struct irq_domain *domain;420420+ struct irq_domain *domain = __irq_domain_instantiate(&info, true);467421468468- domain = irq_domain_instantiate(&info);469469- if (IS_ERR(domain))470470- return NULL;471471-472472- if (first_irq > 0) {473473- if (IS_ENABLED(CONFIG_SPARSE_IRQ)) {474474- /* attempt to allocated irq_descs */475475- int rc = irq_alloc_descs(first_irq, first_irq, size,476476- of_node_to_nid(to_of_node(fwnode)));477477- if (rc < 0)478478- pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",479479- first_irq);480480- }481481- irq_domain_associate_many(domain, first_irq, 0, size);482482- }483483-484484- return domain;422422+ return IS_ERR(domain) ? NULL : domain;485423}486424EXPORT_SYMBOL_GPL(irq_domain_create_simple);487425···508476 .fwnode = fwnode,509477 .size = first_hwirq + size,510478 .hwirq_max = first_hwirq + size,479479+ .hwirq_base = first_hwirq,480480+ .virq_base = first_irq,511481 .ops = ops,512482 .host_data = host_data,513483 };514514- struct irq_domain *domain;484484+ struct irq_domain *domain = irq_domain_instantiate(&info);515485516516- domain = irq_domain_instantiate(&info);517517- if (IS_ERR(domain))518518- return NULL;519519-520520- irq_domain_associate_many(domain, first_irq, first_hwirq, size);521521-522522- return domain;486486+ return IS_ERR(domain) ? NULL : domain;523487}524488EXPORT_SYMBOL_GPL(irq_domain_create_legacy);525489