Skip to content

Commit

Permalink
genirq: Add affinity hint to irq allocation
Browse files Browse the repository at this point in the history
Add an extra argument to the irq(domain) allocation functions, so we can hand
down affinity hints to the allocator. Thats necessary to implement proper
support for multiqueue devices.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Christoph Hellwig <hch@lst.de>
Cc: linux-block@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: linux-nvme@lists.infradead.org
Cc: axboe@fb.com
Cc: agordeev@redhat.com
Link: http://lkml.kernel.org/r/1467621574-8277-4-git-send-email-hch@lst.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Thomas Gleixner committed Jul 4, 2016
1 parent 9c25558 commit 06ee6d5
Show file tree
Hide file tree
Showing 9 changed files with 41 additions and 25 deletions.
2 changes: 1 addition & 1 deletion arch/sparc/kernel/irq_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ unsigned int irq_alloc(unsigned int dev_handle, unsigned int dev_ino)
{
int irq;

irq = __irq_alloc_descs(-1, 1, 1, numa_node_id(), NULL);
irq = __irq_alloc_descs(-1, 1, 1, numa_node_id(), NULL, NULL);
if (irq <= 0)
goto out;

Expand Down
5 changes: 3 additions & 2 deletions arch/x86/kernel/apic/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,7 @@ static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi,

return __irq_domain_alloc_irqs(domain, irq, 1,
ioapic_alloc_attr_node(info),
info, legacy);
info, legacy, NULL);
}

/*
Expand Down Expand Up @@ -1014,7 +1014,8 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain,
info->ioapic_pin))
return -ENOMEM;
} else {
irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true);
irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true,
NULL);
if (irq >= 0) {
irq_data = irq_domain_get_irq_data(domain, irq);
data = irq_data->chip_data;
Expand Down
4 changes: 2 additions & 2 deletions include/linux/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -708,11 +708,11 @@ static inline struct cpumask *irq_data_get_affinity_mask(struct irq_data *d)
unsigned int arch_dynirq_lower_bound(unsigned int from);

int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
struct module *owner);
struct module *owner, const struct cpumask *affinity);

/* use macros to avoid needing export.h for THIS_MODULE */
#define irq_alloc_descs(irq, from, cnt, node) \
__irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)
__irq_alloc_descs(irq, from, cnt, node, THIS_MODULE, NULL)

#define irq_alloc_desc(node) \
irq_alloc_descs(-1, 0, 1, node)
Expand Down
9 changes: 6 additions & 3 deletions include/linux/irqdomain.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ struct irq_domain;
struct of_device_id;
struct irq_chip;
struct irq_data;
struct cpumask;

/* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16
Expand Down Expand Up @@ -217,7 +218,8 @@ extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec,
enum irq_domain_bus_token bus_token);
extern void irq_set_default_host(struct irq_domain *host);
extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs,
irq_hw_number_t hwirq, int node);
irq_hw_number_t hwirq, int node,
const struct cpumask *affinity);

static inline struct fwnode_handle *of_node_to_fwnode(struct device_node *node)
{
Expand Down Expand Up @@ -389,15 +391,16 @@ static inline struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *par

extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
unsigned int nr_irqs, int node, void *arg,
bool realloc);
bool realloc, const struct cpumask *affinity);
extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs);
extern void irq_domain_activate_irq(struct irq_data *irq_data);
extern void irq_domain_deactivate_irq(struct irq_data *irq_data);

static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
unsigned int nr_irqs, int node, void *arg)
{
return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false);
return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false,
NULL);
}

extern int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
Expand Down
2 changes: 1 addition & 1 deletion kernel/irq/ipi.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ int irq_reserve_ipi(struct irq_domain *domain,
}
}

virq = irq_domain_alloc_descs(-1, nr_irqs, 0, NUMA_NO_NODE);
virq = irq_domain_alloc_descs(-1, nr_irqs, 0, NUMA_NO_NODE, NULL);
if (virq <= 0) {
pr_warn("Can't reserve IPI, failed to alloc descs\n");
return -ENOMEM;
Expand Down
12 changes: 8 additions & 4 deletions kernel/irq/irqdesc.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ static void free_desc(unsigned int irq)
}

static int alloc_descs(unsigned int start, unsigned int cnt, int node,
struct module *owner)
const struct cpumask *affinity, struct module *owner)
{
struct irq_desc *desc;
int i;
Expand Down Expand Up @@ -333,6 +333,7 @@ static void free_desc(unsigned int irq)
}

static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
const struct cpumask *affinity,
struct module *owner)
{
u32 i;
Expand Down Expand Up @@ -453,12 +454,15 @@ EXPORT_SYMBOL_GPL(irq_free_descs);
* @cnt: Number of consecutive irqs to allocate.
* @node: Preferred node on which the irq descriptor should be allocated
* @owner: Owning module (can be NULL)
* @affinity: Optional pointer to an affinity mask which hints where the
* irq descriptors should be allocated and which default
* affinities to use
*
* Returns the first irq number or error code
*/
int __ref
__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
struct module *owner)
struct module *owner, const struct cpumask *affinity)
{
int start, ret;

Expand Down Expand Up @@ -494,7 +498,7 @@ __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,

bitmap_set(allocated_irqs, start, cnt);
mutex_unlock(&sparse_irq_lock);
return alloc_descs(start, cnt, node, owner);
return alloc_descs(start, cnt, node, affinity, owner);

err:
mutex_unlock(&sparse_irq_lock);
Expand All @@ -512,7 +516,7 @@ EXPORT_SYMBOL_GPL(__irq_alloc_descs);
*/
unsigned int irq_alloc_hwirqs(int cnt, int node)
{
int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL);
int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL, NULL);

if (irq < 0)
return 0;
Expand Down
22 changes: 14 additions & 8 deletions kernel/irq/irqdomain.c
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
}

/* Allocate a virtual interrupt number */
virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node));
virq = irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node), NULL);
if (virq <= 0) {
pr_debug("-> virq allocation failed\n");
return 0;
Expand Down Expand Up @@ -835,19 +835,23 @@ const struct irq_domain_ops irq_domain_simple_ops = {
EXPORT_SYMBOL_GPL(irq_domain_simple_ops);

int irq_domain_alloc_descs(int virq, unsigned int cnt, irq_hw_number_t hwirq,
int node)
int node, const struct cpumask *affinity)
{
unsigned int hint;

if (virq >= 0) {
virq = irq_alloc_descs(virq, virq, cnt, node);
virq = __irq_alloc_descs(virq, virq, cnt, node, THIS_MODULE,
affinity);
} else {
hint = hwirq % nr_irqs;
if (hint == 0)
hint++;
virq = irq_alloc_descs_from(hint, cnt, node);
if (virq <= 0 && hint > 1)
virq = irq_alloc_descs_from(1, cnt, node);
virq = __irq_alloc_descs(-1, hint, cnt, node, THIS_MODULE,
affinity);
if (virq <= 0 && hint > 1) {
virq = __irq_alloc_descs(-1, 1, cnt, node, THIS_MODULE,
affinity);
}
}

return virq;
Expand Down Expand Up @@ -1160,6 +1164,7 @@ int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
* @node: NUMA node id for memory allocation
* @arg: domain specific argument
* @realloc: IRQ descriptors have already been allocated if true
* @affinity: Optional irq affinity mask for multiqueue devices
*
* Allocate IRQ numbers and initialized all data structures to support
* hierarchy IRQ domains.
Expand All @@ -1175,7 +1180,7 @@ int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
*/
int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
unsigned int nr_irqs, int node, void *arg,
bool realloc)
bool realloc, const struct cpumask *affinity)
{
int i, ret, virq;

Expand All @@ -1193,7 +1198,8 @@ int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
if (realloc && irq_base >= 0) {
virq = irq_base;
} else {
virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node);
virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node,
affinity);
if (virq < 0) {
pr_debug("cannot allocate IRQ(base %d, count %d)\n",
irq_base, nr_irqs);
Expand Down
7 changes: 4 additions & 3 deletions kernel/irq/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,10 +353,11 @@ static int setup_affinity(struct irq_desc *desc, struct cpumask *mask)
return 0;

/*
* Preserve an userspace affinity setup, but make sure that
* one of the targets is online.
* Preserve the managed affinity setting and an userspace affinity
* setup, but make sure that one of the targets is online.
*/
if (irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) {
if (irqd_affinity_is_managed(&desc->irq_data) ||
irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) {
if (cpumask_intersects(desc->irq_common_data.affinity,
cpu_online_mask))
set = desc->irq_common_data.affinity;
Expand Down
3 changes: 2 additions & 1 deletion kernel/irq/msi.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
ops->set_desc(&arg, desc);

virq = __irq_domain_alloc_irqs(domain, -1, desc->nvec_used,
dev_to_node(dev), &arg, false);
dev_to_node(dev), &arg, false,
NULL);
if (virq < 0) {
ret = -ENOSPC;
if (ops->handle_error)
Expand Down

0 comments on commit 06ee6d5

Please sign in to comment.