}
/* Allocate a virtual interrupt number */
- virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node), NULL);
+ virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node),
+ NULL, NULL);
if (virq <= 0) {
pr_debug("-> virq allocation failed\n");
return 0;
EXPORT_SYMBOL_GPL(irq_domain_translate_twocell);
int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq,
- int node, const struct irq_affinity_desc *affinity)
+ int node, const struct irq_affinity_desc *affinity,
+ const struct cpumask *max_affinity)
{
+ cpumask_var_t default_affinity;
unsigned int hint;
+ int i;
+
+ /* Check requested per-IRQ affinities are in the possible range */
+ if (affinity && max_affinity) {
+ for (i = 0; i < cnt; i++)
+ if (!cpumask_subset(&affinity[i].mask, max_affinity))
+ return -EINVAL;
+ }
+
+ /*
+ * Generate default affinity. Either the possible subset of
+ * irq_default_affinity if such a subset is non-empty, or fall
+ * back to the provided max_affinity if there is no intersection.
+ * And just a copy of irq_default_affinity in the
+ * !CONFIG_CPUMASK_OFFSTACK case.
+ */
+ memset(&default_affinity, 0, sizeof(default_affinity));
+ if ((max_affinity &&
+ !cpumask_subset(irq_default_affinity, max_affinity))) {
+ if (!alloc_cpumask_var(&default_affinity, GFP_KERNEL))
+ return -ENOMEM;
+ cpumask_and(default_affinity, max_affinity,
+ irq_default_affinity);
+ if (cpumask_empty(default_affinity))
+ cpumask_copy(default_affinity, max_affinity);
+ } else if (cpumask_available(default_affinity))
+ cpumask_copy(default_affinity, irq_default_affinity);
if (virq >= 0) {
virq = __irq_alloc_descs(virq, virq, cnt, node, THIS_MODULE,
- affinity, NULL);
+ affinity, default_affinity);
} else {
hint = hwirq % nr_irqs;
if (hint == 0)
hint++;
virq = __irq_alloc_descs(-1, hint, cnt, node, THIS_MODULE,
- affinity, NULL);
+ affinity, default_affinity);
if (virq <= 0 && hint > 1) {
virq = __irq_alloc_descs(-1, 1, cnt, node, THIS_MODULE,
- affinity, NULL);
+ affinity, default_affinity);
}
}
+ if (cpumask_available(default_affinity))
+ free_cpumask_var(default_affinity);
+
return virq;
}
virq = irq_base;
} else {
virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node,
- affinity);
+ affinity, NULL);
if (virq < 0) {
pr_debug("cannot allocate IRQ(base %d, count %d)\n",
irq_base, nr_irqs);