Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3804f265 authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman
Browse files

irqdomain: Look for existing mapping only once



commit 6e6f75c9c98d2d246d90411ff2b6f0cd271f4cba upstream.

Avoid looking for an existing mapping twice when creating a new mapping
using irq_create_fwspec_mapping() by factoring out the actual allocation
which is shared with irq_create_mapping_affinity().

The new helper function will also be used to fix a shared-interrupt
mapping race, hence the Fixes tag.

Fixes: b62b2cf5 ("irqdomain: Fix handling of type settings for existing mappings")
Cc: stable@vger.kernel.org      # 4.8
Tested-by: default avatarHsin-Yi Wang <hsinyi@chromium.org>
Tested-by: default avatarMark-PK Tsai <mark-pk.tsai@mediatek.com>
Signed-off-by: default avatarJohan Hovold <johan+linaro@kernel.org>
Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20230213104302.17307-5-johan+linaro@kernel.org


Signed-off-by: default avatarMark-PK Tsai <mark-pk.tsai@mediatek.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent e7bba7dd
Loading
Loading
Loading
Loading
+34 −28
Original line number Original line Diff line number Diff line
@@ -672,6 +672,34 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
}
}
EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
EXPORT_SYMBOL_GPL(irq_create_direct_mapping);


static unsigned int __irq_create_mapping_affinity(struct irq_domain *domain,
						  irq_hw_number_t hwirq,
						  const struct irq_affinity_desc *affinity)
{
	struct device_node *of_node = irq_domain_get_of_node(domain);
	int virq;

	pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);

	/* Allocate a virtual interrupt number */
	virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node),
				      affinity);
	if (virq <= 0) {
		pr_debug("-> virq allocation failed\n");
		return 0;
	}

	if (irq_domain_associate(domain, virq, hwirq)) {
		irq_free_desc(virq);
		return 0;
	}

	pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
		hwirq, of_node_full_name(of_node), virq);

	return virq;
}

/**
/**
 * irq_create_mapping_affinity() - Map a hardware interrupt into linux irq space
 * irq_create_mapping_affinity() - Map a hardware interrupt into linux irq space
 * @domain: domain owning this hardware interrupt or NULL for default domain
 * @domain: domain owning this hardware interrupt or NULL for default domain
@@ -687,46 +715,24 @@ unsigned int irq_create_mapping_affinity(struct irq_domain *domain,
					 irq_hw_number_t hwirq,
					 irq_hw_number_t hwirq,
					 const struct irq_affinity_desc *affinity)
					 const struct irq_affinity_desc *affinity)
{
{
	struct device_node *of_node;
	int virq;
	int virq;


	pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
	/* Look for default domain if necessary */

	/* Look for default domain if nececssary */
	if (domain == NULL)
	if (domain == NULL)
		domain = irq_default_domain;
		domain = irq_default_domain;
	if (domain == NULL) {
	if (domain == NULL) {
		WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
		WARN(1, "%s(, %lx) called with NULL domain\n", __func__, hwirq);
		return 0;
		return 0;
	}
	}
	pr_debug("-> using domain @%p\n", domain);

	of_node = irq_domain_get_of_node(domain);


	/* Check if mapping already exists */
	/* Check if mapping already exists */
	virq = irq_find_mapping(domain, hwirq);
	virq = irq_find_mapping(domain, hwirq);
	if (virq) {
	if (virq) {
		pr_debug("-> existing mapping on virq %d\n", virq);
		pr_debug("existing mapping on virq %d\n", virq);
		return virq;
		return virq;
	}
	}


	/* Allocate a virtual interrupt number */
	return __irq_create_mapping_affinity(domain, hwirq, affinity);
	virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node),
				      affinity);
	if (virq <= 0) {
		pr_debug("-> virq allocation failed\n");
		return 0;
	}

	if (irq_domain_associate(domain, virq, hwirq)) {
		irq_free_desc(virq);
		return 0;
	}

	pr_debug("irq %lu on domain %s mapped to virtual irq %u\n",
		hwirq, of_node_full_name(of_node), virq);

	return virq;
}
}
EXPORT_SYMBOL_GPL(irq_create_mapping_affinity);
EXPORT_SYMBOL_GPL(irq_create_mapping_affinity);


@@ -866,7 +872,7 @@ unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
			return 0;
			return 0;
	} else {
	} else {
		/* Create mapping */
		/* Create mapping */
		virq = irq_create_mapping(domain, hwirq);
		virq = __irq_create_mapping_affinity(domain, hwirq, NULL);
		if (!virq)
		if (!virq)
			return virq;
			return virq;
	}
	}