mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-15 02:05:33 +00:00
irqdomain changes required for regmap to apply depending patches
-----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAma2f6sTHHRnbHhAbGlu dXRyb25peC5kZQAKCRCmGPVMDXSYodlvEACZPZV71EZBmtMM89cDFf93rVU+MewL ftBaWaBR+vZV5SxH9IDxrECvPeA12WublnHLo88Ch3fj2JtyaDtrb34Gy6YpzexA kjHsMPSdxsdfPITny33X0VraW15OnigdPStRX4hye6dHEFFk0+5NhK/WwwqE7d8u fVLRpF01wrlqlyfLGS9u9QS9uwzVJHjRoPgHTqR4lPLz40RQJIkrA1K3V2XIP35/ 0/KVbf4sgy/5+s2Uot8acBzww0jM2Dh/tkYmUnyw3fOWWY55Ub2gMldHC/Y4aQiO ieGeVQ4qdWUTJ0ZElXFBFYC4/6I6uoWaOFXbVAVRwGuygaezXmskV92uvqCJyh8K 25clO+aA+2aT/cVHT6HPWh+d/mDQajtPbGZ+kMEJ1pZ/tEz3IIM8XTrH3daXy835 2JwJkxgIsfpcqa/dEeQRRlD1ReTOZTezLVzAFl5CnrtPuEyqQ4Py1mq2vCAHaJqN IFQ2IZkLO9cqo5zLmvK1GlLVV/DbqhDk4JJdp27MkAPcRKAPglP0lNivUQIbZWe0 43NzTOFWgB+e86wLVb8cs2XeyEaioFVcdKCdFGMGnAXKdqqt5AxEhnHSYnC31pE7 bgRUfCAWImn5Ev8XrCpAJ9OCGXdRsF128FvM9zPeXsFyC5TTrYra7b7vFKrnK+4x ghlUEjITKfCMoA== =4t42 -----END PGP SIGNATURE----- Merge tag 'irq-domain-24-08-09' into irq/core Merge the irqdomain changes which are required for regmap to apply depending patches and therefore tagged.
This commit is contained in:
commit
46c3e31cb0
@ -291,7 +291,12 @@ struct irq_domain_chip_generic_info;
|
||||
* @hwirq_max: Maximum number of interrupts supported by controller
|
||||
* @direct_max: Maximum value of direct maps;
|
||||
* Use ~0 for no limit; 0 for no direct mapping
|
||||
* @hwirq_base: The first hardware interrupt number (legacy domains only)
|
||||
* @virq_base: The first Linux interrupt number for legacy domains to
|
||||
* immediately associate the interrupts after domain creation
|
||||
* @bus_token: Domain bus token
|
||||
* @name_suffix: Optional name suffix to avoid collisions when multiple
|
||||
* domains are added using same fwnode
|
||||
* @ops: Domain operation callbacks
|
||||
* @host_data: Controller private data pointer
|
||||
* @dgc_info: Geneneric chip information structure pointer used to
|
||||
@ -307,7 +312,10 @@ struct irq_domain_info {
|
||||
unsigned int size;
|
||||
irq_hw_number_t hwirq_max;
|
||||
int direct_max;
|
||||
unsigned int hwirq_base;
|
||||
unsigned int virq_base;
|
||||
enum irq_domain_bus_token bus_token;
|
||||
const char *name_suffix;
|
||||
const struct irq_domain_ops *ops;
|
||||
void *host_data;
|
||||
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
|
||||
|
@ -128,72 +128,92 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_free_fwnode);
|
||||
|
||||
static int irq_domain_set_name(struct irq_domain *domain,
|
||||
const struct fwnode_handle *fwnode,
|
||||
enum irq_domain_bus_token bus_token)
|
||||
static int alloc_name(struct irq_domain *domain, char *base, enum irq_domain_bus_token bus_token)
|
||||
{
|
||||
domain->name = bus_token ? kasprintf(GFP_KERNEL, "%s-%d", base, bus_token) :
|
||||
kasprintf(GFP_KERNEL, "%s", base);
|
||||
if (!domain->name)
|
||||
return -ENOMEM;
|
||||
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alloc_fwnode_name(struct irq_domain *domain, const struct fwnode_handle *fwnode,
|
||||
enum irq_domain_bus_token bus_token, const char *suffix)
|
||||
{
|
||||
const char *sep = suffix ? "-" : "";
|
||||
const char *suf = suffix ? : "";
|
||||
char *name;
|
||||
|
||||
name = bus_token ? kasprintf(GFP_KERNEL, "%pfw-%s%s%d", fwnode, suf, sep, bus_token) :
|
||||
kasprintf(GFP_KERNEL, "%pfw-%s", fwnode, suf);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* fwnode paths contain '/', which debugfs is legitimately unhappy
|
||||
* about. Replace them with ':', which does the trick and is not as
|
||||
* offensive as '\'...
|
||||
*/
|
||||
domain->name = strreplace(name, '/', ':');
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alloc_unknown_name(struct irq_domain *domain, enum irq_domain_bus_token bus_token)
|
||||
{
|
||||
static atomic_t unknown_domains;
|
||||
struct irqchip_fwid *fwid;
|
||||
int id = atomic_inc_return(&unknown_domains);
|
||||
|
||||
domain->name = bus_token ? kasprintf(GFP_KERNEL, "unknown-%d-%d", id, bus_token) :
|
||||
kasprintf(GFP_KERNEL, "unknown-%d", id);
|
||||
|
||||
if (!domain->name)
|
||||
return -ENOMEM;
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int irq_domain_set_name(struct irq_domain *domain, const struct irq_domain_info *info)
|
||||
{
|
||||
enum irq_domain_bus_token bus_token = info->bus_token;
|
||||
const struct fwnode_handle *fwnode = info->fwnode;
|
||||
|
||||
if (is_fwnode_irqchip(fwnode)) {
|
||||
fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
|
||||
struct irqchip_fwid *fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
|
||||
|
||||
/*
|
||||
* The name_suffix is only intended to be used to avoid a name
|
||||
* collision 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 (info->name_suffix)
|
||||
return -EINVAL;
|
||||
|
||||
switch (fwid->type) {
|
||||
case IRQCHIP_FWNODE_NAMED:
|
||||
case IRQCHIP_FWNODE_NAMED_ID:
|
||||
domain->name = bus_token ?
|
||||
kasprintf(GFP_KERNEL, "%s-%d",
|
||||
fwid->name, bus_token) :
|
||||
kstrdup(fwid->name, GFP_KERNEL);
|
||||
if (!domain->name)
|
||||
return -ENOMEM;
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
break;
|
||||
return alloc_name(domain, fwid->name, bus_token);
|
||||
default:
|
||||
domain->name = fwid->name;
|
||||
if (bus_token) {
|
||||
domain->name = kasprintf(GFP_KERNEL, "%s-%d",
|
||||
fwid->name, bus_token);
|
||||
if (!domain->name)
|
||||
return -ENOMEM;
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
}
|
||||
break;
|
||||
if (bus_token)
|
||||
return alloc_name(domain, fwid->name, bus_token);
|
||||
}
|
||||
} else if (is_of_node(fwnode) || is_acpi_device_node(fwnode) ||
|
||||
is_software_node(fwnode)) {
|
||||
char *name;
|
||||
|
||||
/*
|
||||
* fwnode paths contain '/', which debugfs is legitimately
|
||||
* unhappy about. Replace them with ':', which does
|
||||
* the trick and is not as offensive as '\'...
|
||||
*/
|
||||
name = bus_token ?
|
||||
kasprintf(GFP_KERNEL, "%pfw-%d", fwnode, bus_token) :
|
||||
kasprintf(GFP_KERNEL, "%pfw", fwnode);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
domain->name = strreplace(name, '/', ':');
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
} else if (is_of_node(fwnode) || is_acpi_device_node(fwnode) || is_software_node(fwnode)) {
|
||||
return alloc_fwnode_name(domain, fwnode, bus_token, info->name_suffix);
|
||||
}
|
||||
|
||||
if (!domain->name) {
|
||||
if (fwnode)
|
||||
pr_err("Invalid fwnode type for irqdomain\n");
|
||||
domain->name = bus_token ?
|
||||
kasprintf(GFP_KERNEL, "unknown-%d-%d",
|
||||
atomic_inc_return(&unknown_domains),
|
||||
bus_token) :
|
||||
kasprintf(GFP_KERNEL, "unknown-%d",
|
||||
atomic_inc_return(&unknown_domains));
|
||||
if (!domain->name)
|
||||
return -ENOMEM;
|
||||
domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
|
||||
}
|
||||
if (domain->name)
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
if (fwnode)
|
||||
pr_err("Invalid fwnode type for irqdomain\n");
|
||||
return alloc_unknown_name(domain, bus_token);
|
||||
}
|
||||
|
||||
static struct irq_domain *__irq_domain_create(const struct irq_domain_info *info)
|
||||
@ -211,7 +231,7 @@ static struct irq_domain *__irq_domain_create(const struct irq_domain_info *info
|
||||
if (!domain)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
err = irq_domain_set_name(domain, info->fwnode, info->bus_token);
|
||||
err = irq_domain_set_name(domain, info);
|
||||
if (err) {
|
||||
kfree(domain);
|
||||
return ERR_PTR(err);
|
||||
@ -267,13 +287,20 @@ static void irq_domain_free(struct irq_domain *domain)
|
||||
kfree(domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* irq_domain_instantiate() - Instantiate a new irq domain data structure
|
||||
* @info: Domain information pointer pointing to the information for this domain
|
||||
*
|
||||
* Return: A pointer to the instantiated irq domain or an ERR_PTR value.
|
||||
*/
|
||||
struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
|
||||
static void irq_domain_instantiate_descs(const struct irq_domain_info *info)
|
||||
{
|
||||
if (!IS_ENABLED(CONFIG_SPARSE_IRQ))
|
||||
return;
|
||||
|
||||
if (irq_alloc_descs(info->virq_base, info->virq_base, info->size,
|
||||
of_node_to_nid(to_of_node(info->fwnode))) < 0) {
|
||||
pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
|
||||
info->virq_base);
|
||||
}
|
||||
}
|
||||
|
||||
static struct irq_domain *__irq_domain_instantiate(const struct irq_domain_info *info,
|
||||
bool cond_alloc_descs)
|
||||
{
|
||||
struct irq_domain *domain;
|
||||
int err;
|
||||
@ -306,6 +333,15 @@ struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
|
||||
|
||||
__irq_domain_publish(domain);
|
||||
|
||||
if (cond_alloc_descs && info->virq_base > 0)
|
||||
irq_domain_instantiate_descs(info);
|
||||
|
||||
/* Legacy interrupt domains have a fixed Linux interrupt number */
|
||||
if (info->virq_base > 0) {
|
||||
irq_domain_associate_many(domain, info->virq_base, info->hwirq_base,
|
||||
info->size - info->hwirq_base);
|
||||
}
|
||||
|
||||
return domain;
|
||||
|
||||
err_domain_gc_remove:
|
||||
@ -315,6 +351,17 @@ err_domain_free:
|
||||
irq_domain_free(domain);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/**
|
||||
* irq_domain_instantiate() - Instantiate a new irq domain data structure
|
||||
* @info: Domain information pointer pointing to the information for this domain
|
||||
*
|
||||
* Return: A pointer to the instantiated irq domain or an ERR_PTR value.
|
||||
*/
|
||||
struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)
|
||||
{
|
||||
return __irq_domain_instantiate(info, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_instantiate);
|
||||
|
||||
/**
|
||||
@ -413,28 +460,13 @@ struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode,
|
||||
.fwnode = fwnode,
|
||||
.size = size,
|
||||
.hwirq_max = size,
|
||||
.virq_base = first_irq,
|
||||
.ops = ops,
|
||||
.host_data = host_data,
|
||||
};
|
||||
struct irq_domain *domain;
|
||||
struct irq_domain *domain = __irq_domain_instantiate(&info, true);
|
||||
|
||||
domain = irq_domain_instantiate(&info);
|
||||
if (IS_ERR(domain))
|
||||
return NULL;
|
||||
|
||||
if (first_irq > 0) {
|
||||
if (IS_ENABLED(CONFIG_SPARSE_IRQ)) {
|
||||
/* attempt to allocated irq_descs */
|
||||
int rc = irq_alloc_descs(first_irq, first_irq, size,
|
||||
of_node_to_nid(to_of_node(fwnode)));
|
||||
if (rc < 0)
|
||||
pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
|
||||
first_irq);
|
||||
}
|
||||
irq_domain_associate_many(domain, first_irq, 0, size);
|
||||
}
|
||||
|
||||
return domain;
|
||||
return IS_ERR(domain) ? NULL : domain;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_create_simple);
|
||||
|
||||
@ -476,18 +508,14 @@ struct irq_domain *irq_domain_create_legacy(struct fwnode_handle *fwnode,
|
||||
.fwnode = fwnode,
|
||||
.size = first_hwirq + size,
|
||||
.hwirq_max = first_hwirq + size,
|
||||
.hwirq_base = first_hwirq,
|
||||
.virq_base = first_irq,
|
||||
.ops = ops,
|
||||
.host_data = host_data,
|
||||
};
|
||||
struct irq_domain *domain;
|
||||
struct irq_domain *domain = irq_domain_instantiate(&info);
|
||||
|
||||
domain = irq_domain_instantiate(&info);
|
||||
if (IS_ERR(domain))
|
||||
return NULL;
|
||||
|
||||
irq_domain_associate_many(domain, first_irq, first_hwirq, size);
|
||||
|
||||
return domain;
|
||||
return IS_ERR(domain) ? NULL : domain;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_create_legacy);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user