x86/irq: Move private data in struct irq_cfg into dedicated data structure
Several fields in struct irq_cfg are private to vector.c, so move it into dedicated data structure. This helps to hide implementation details. Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: David Cohen <david.a.cohen@linux.intel.com> Cc: Sander Eikelenboom <linux@eikelenboom.it> Cc: David Vrabel <david.vrabel@citrix.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Joerg Roedel <joro@8bytes.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: Yinghai Lu <yinghai@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Dimitri Sivanich <sivanich@sgi.com> Link: http://lkml.kernel.org/r/1428978610-28986-27-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Joerg Roedel <joro@8bytes.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: Yinghai Lu <yinghai@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Link: http://lkml.kernel.org/r/1416901802-24211-35-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Joerg Roedel <jroedel@suse.de>
This commit is contained in:
parent
c6c2002b74
commit
7f3262edcd
@ -171,11 +171,8 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct irq_cfg {
|
struct irq_cfg {
|
||||||
cpumask_var_t domain;
|
|
||||||
cpumask_var_t old_domain;
|
|
||||||
unsigned int dest_apicid;
|
unsigned int dest_apicid;
|
||||||
u8 vector;
|
u8 vector;
|
||||||
u8 move_in_progress : 1;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct irq_domain *x86_vector_domain;
|
extern struct irq_domain *x86_vector_domain;
|
||||||
|
@ -21,11 +21,18 @@
|
|||||||
#include <asm/desc.h>
|
#include <asm/desc.h>
|
||||||
#include <asm/irq_remapping.h>
|
#include <asm/irq_remapping.h>
|
||||||
|
|
||||||
|
struct apic_chip_data {
|
||||||
|
struct irq_cfg cfg;
|
||||||
|
cpumask_var_t domain;
|
||||||
|
cpumask_var_t old_domain;
|
||||||
|
u8 move_in_progress : 1;
|
||||||
|
};
|
||||||
|
|
||||||
struct irq_domain *x86_vector_domain;
|
struct irq_domain *x86_vector_domain;
|
||||||
static DEFINE_RAW_SPINLOCK(vector_lock);
|
static DEFINE_RAW_SPINLOCK(vector_lock);
|
||||||
static struct irq_chip lapic_controller;
|
static struct irq_chip lapic_controller;
|
||||||
#ifdef CONFIG_X86_IO_APIC
|
#ifdef CONFIG_X86_IO_APIC
|
||||||
static struct irq_cfg *legacy_irq_cfgs[NR_IRQS_LEGACY];
|
static struct apic_chip_data *legacy_irq_data[NR_IRQS_LEGACY];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void lock_vector_lock(void)
|
void lock_vector_lock(void)
|
||||||
@ -41,12 +48,7 @@ void unlock_vector_lock(void)
|
|||||||
raw_spin_unlock(&vector_lock);
|
raw_spin_unlock(&vector_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct irq_cfg *irq_cfg(unsigned int irq)
|
static struct apic_chip_data *apic_chip_data(struct irq_data *irq_data)
|
||||||
{
|
|
||||||
return irqd_cfg(irq_get_irq_data(irq));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct irq_cfg *irqd_cfg(struct irq_data *irq_data)
|
|
||||||
{
|
{
|
||||||
if (!irq_data)
|
if (!irq_data)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -57,36 +59,48 @@ struct irq_cfg *irqd_cfg(struct irq_data *irq_data)
|
|||||||
return irq_data->chip_data;
|
return irq_data->chip_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irq_cfg *alloc_irq_cfg(int node)
|
struct irq_cfg *irqd_cfg(struct irq_data *irq_data)
|
||||||
{
|
{
|
||||||
struct irq_cfg *cfg;
|
struct apic_chip_data *data = apic_chip_data(irq_data);
|
||||||
|
|
||||||
cfg = kzalloc_node(sizeof(*cfg), GFP_KERNEL, node);
|
return data ? &data->cfg : NULL;
|
||||||
if (!cfg)
|
}
|
||||||
|
|
||||||
|
struct irq_cfg *irq_cfg(unsigned int irq)
|
||||||
|
{
|
||||||
|
return irqd_cfg(irq_get_irq_data(irq));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct apic_chip_data *alloc_apic_chip_data(int node)
|
||||||
|
{
|
||||||
|
struct apic_chip_data *data;
|
||||||
|
|
||||||
|
data = kzalloc_node(sizeof(*data), GFP_KERNEL, node);
|
||||||
|
if (!data)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!zalloc_cpumask_var_node(&cfg->domain, GFP_KERNEL, node))
|
if (!zalloc_cpumask_var_node(&data->domain, GFP_KERNEL, node))
|
||||||
goto out_cfg;
|
goto out_data;
|
||||||
if (!zalloc_cpumask_var_node(&cfg->old_domain, GFP_KERNEL, node))
|
if (!zalloc_cpumask_var_node(&data->old_domain, GFP_KERNEL, node))
|
||||||
goto out_domain;
|
goto out_domain;
|
||||||
return cfg;
|
return data;
|
||||||
out_domain:
|
out_domain:
|
||||||
free_cpumask_var(cfg->domain);
|
free_cpumask_var(data->domain);
|
||||||
out_cfg:
|
out_data:
|
||||||
kfree(cfg);
|
kfree(data);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void free_irq_cfg(struct irq_cfg *cfg)
|
static void free_apic_chip_data(struct apic_chip_data *data)
|
||||||
{
|
{
|
||||||
if (cfg) {
|
if (data) {
|
||||||
free_cpumask_var(cfg->domain);
|
free_cpumask_var(data->domain);
|
||||||
free_cpumask_var(cfg->old_domain);
|
free_cpumask_var(data->old_domain);
|
||||||
kfree(cfg);
|
kfree(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int __assign_irq_vector(int irq, struct apic_chip_data *d,
|
||||||
__assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
|
const struct cpumask *mask)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* NOTE! The local APIC isn't very good at handling
|
* NOTE! The local APIC isn't very good at handling
|
||||||
@ -104,7 +118,7 @@ __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
|
|||||||
int cpu, err;
|
int cpu, err;
|
||||||
cpumask_var_t tmp_mask;
|
cpumask_var_t tmp_mask;
|
||||||
|
|
||||||
if (cfg->move_in_progress)
|
if (d->move_in_progress)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
if (!alloc_cpumask_var(&tmp_mask, GFP_ATOMIC))
|
if (!alloc_cpumask_var(&tmp_mask, GFP_ATOMIC))
|
||||||
@ -112,26 +126,26 @@ __assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
|
|||||||
|
|
||||||
/* Only try and allocate irqs on cpus that are present */
|
/* Only try and allocate irqs on cpus that are present */
|
||||||
err = -ENOSPC;
|
err = -ENOSPC;
|
||||||
cpumask_clear(cfg->old_domain);
|
cpumask_clear(d->old_domain);
|
||||||
cpu = cpumask_first_and(mask, cpu_online_mask);
|
cpu = cpumask_first_and(mask, cpu_online_mask);
|
||||||
while (cpu < nr_cpu_ids) {
|
while (cpu < nr_cpu_ids) {
|
||||||
int new_cpu, vector, offset;
|
int new_cpu, vector, offset;
|
||||||
|
|
||||||
apic->vector_allocation_domain(cpu, tmp_mask, mask);
|
apic->vector_allocation_domain(cpu, tmp_mask, mask);
|
||||||
|
|
||||||
if (cpumask_subset(tmp_mask, cfg->domain)) {
|
if (cpumask_subset(tmp_mask, d->domain)) {
|
||||||
err = 0;
|
err = 0;
|
||||||
if (cpumask_equal(tmp_mask, cfg->domain))
|
if (cpumask_equal(tmp_mask, d->domain))
|
||||||
break;
|
break;
|
||||||
/*
|
/*
|
||||||
* New cpumask using the vector is a proper subset of
|
* New cpumask using the vector is a proper subset of
|
||||||
* the current in use mask. So cleanup the vector
|
* the current in use mask. So cleanup the vector
|
||||||
* allocation for the members that are not used anymore.
|
* allocation for the members that are not used anymore.
|
||||||
*/
|
*/
|
||||||
cpumask_andnot(cfg->old_domain, cfg->domain, tmp_mask);
|
cpumask_andnot(d->old_domain, d->domain, tmp_mask);
|
||||||
cfg->move_in_progress =
|
d->move_in_progress =
|
||||||
cpumask_intersects(cfg->old_domain, cpu_online_mask);
|
cpumask_intersects(d->old_domain, cpu_online_mask);
|
||||||
cpumask_and(cfg->domain, cfg->domain, tmp_mask);
|
cpumask_and(d->domain, d->domain, tmp_mask);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,8 +159,8 @@ next:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (unlikely(current_vector == vector)) {
|
if (unlikely(current_vector == vector)) {
|
||||||
cpumask_or(cfg->old_domain, cfg->old_domain, tmp_mask);
|
cpumask_or(d->old_domain, d->old_domain, tmp_mask);
|
||||||
cpumask_andnot(tmp_mask, mask, cfg->old_domain);
|
cpumask_andnot(tmp_mask, mask, d->old_domain);
|
||||||
cpu = cpumask_first_and(tmp_mask, cpu_online_mask);
|
cpu = cpumask_first_and(tmp_mask, cpu_online_mask);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -162,15 +176,15 @@ next:
|
|||||||
/* Found one! */
|
/* Found one! */
|
||||||
current_vector = vector;
|
current_vector = vector;
|
||||||
current_offset = offset;
|
current_offset = offset;
|
||||||
if (cfg->vector) {
|
if (d->cfg.vector) {
|
||||||
cpumask_copy(cfg->old_domain, cfg->domain);
|
cpumask_copy(d->old_domain, d->domain);
|
||||||
cfg->move_in_progress =
|
d->move_in_progress =
|
||||||
cpumask_intersects(cfg->old_domain, cpu_online_mask);
|
cpumask_intersects(d->old_domain, cpu_online_mask);
|
||||||
}
|
}
|
||||||
for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask)
|
for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask)
|
||||||
per_cpu(vector_irq, new_cpu)[vector] = irq;
|
per_cpu(vector_irq, new_cpu)[vector] = irq;
|
||||||
cfg->vector = vector;
|
d->cfg.vector = vector;
|
||||||
cpumask_copy(cfg->domain, tmp_mask);
|
cpumask_copy(d->domain, tmp_mask);
|
||||||
err = 0;
|
err = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -178,46 +192,46 @@ next:
|
|||||||
|
|
||||||
if (!err) {
|
if (!err) {
|
||||||
/* cache destination APIC IDs into cfg->dest_apicid */
|
/* cache destination APIC IDs into cfg->dest_apicid */
|
||||||
err = apic->cpu_mask_to_apicid_and(mask, cfg->domain,
|
err = apic->cpu_mask_to_apicid_and(mask, d->domain,
|
||||||
&cfg->dest_apicid);
|
&d->cfg.dest_apicid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int assign_irq_vector(int irq, struct irq_cfg *cfg,
|
static int assign_irq_vector(int irq, struct apic_chip_data *data,
|
||||||
const struct cpumask *mask)
|
const struct cpumask *mask)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&vector_lock, flags);
|
raw_spin_lock_irqsave(&vector_lock, flags);
|
||||||
err = __assign_irq_vector(irq, cfg, mask);
|
err = __assign_irq_vector(irq, data, mask);
|
||||||
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear_irq_vector(int irq, struct irq_cfg *cfg)
|
static void clear_irq_vector(int irq, struct apic_chip_data *data)
|
||||||
{
|
{
|
||||||
int cpu, vector;
|
int cpu, vector;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&vector_lock, flags);
|
raw_spin_lock_irqsave(&vector_lock, flags);
|
||||||
BUG_ON(!cfg->vector);
|
BUG_ON(!data->cfg.vector);
|
||||||
|
|
||||||
vector = cfg->vector;
|
vector = data->cfg.vector;
|
||||||
for_each_cpu_and(cpu, cfg->domain, cpu_online_mask)
|
for_each_cpu_and(cpu, data->domain, cpu_online_mask)
|
||||||
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
|
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
|
||||||
|
|
||||||
cfg->vector = 0;
|
data->cfg.vector = 0;
|
||||||
cpumask_clear(cfg->domain);
|
cpumask_clear(data->domain);
|
||||||
|
|
||||||
if (likely(!cfg->move_in_progress)) {
|
if (likely(!data->move_in_progress)) {
|
||||||
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) {
|
for_each_cpu_and(cpu, data->old_domain, cpu_online_mask) {
|
||||||
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
|
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS;
|
||||||
vector++) {
|
vector++) {
|
||||||
if (per_cpu(vector_irq, cpu)[vector] != irq)
|
if (per_cpu(vector_irq, cpu)[vector] != irq)
|
||||||
@ -226,7 +240,7 @@ static void clear_irq_vector(int irq, struct irq_cfg *cfg)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cfg->move_in_progress = 0;
|
data->move_in_progress = 0;
|
||||||
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,10 +275,10 @@ static void x86_vector_free_irqs(struct irq_domain *domain,
|
|||||||
irq_data = irq_domain_get_irq_data(x86_vector_domain, virq + i);
|
irq_data = irq_domain_get_irq_data(x86_vector_domain, virq + i);
|
||||||
if (irq_data && irq_data->chip_data) {
|
if (irq_data && irq_data->chip_data) {
|
||||||
clear_irq_vector(virq + i, irq_data->chip_data);
|
clear_irq_vector(virq + i, irq_data->chip_data);
|
||||||
free_irq_cfg(irq_data->chip_data);
|
free_apic_chip_data(irq_data->chip_data);
|
||||||
#ifdef CONFIG_X86_IO_APIC
|
#ifdef CONFIG_X86_IO_APIC
|
||||||
if (virq + i < nr_legacy_irqs())
|
if (virq + i < nr_legacy_irqs())
|
||||||
legacy_irq_cfgs[virq + i] = NULL;
|
legacy_irq_data[virq + i] = NULL;
|
||||||
#endif
|
#endif
|
||||||
irq_domain_reset_irq_data(irq_data);
|
irq_domain_reset_irq_data(irq_data);
|
||||||
}
|
}
|
||||||
@ -275,9 +289,9 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
|
|||||||
unsigned int nr_irqs, void *arg)
|
unsigned int nr_irqs, void *arg)
|
||||||
{
|
{
|
||||||
struct irq_alloc_info *info = arg;
|
struct irq_alloc_info *info = arg;
|
||||||
|
struct apic_chip_data *data;
|
||||||
const struct cpumask *mask;
|
const struct cpumask *mask;
|
||||||
struct irq_data *irq_data;
|
struct irq_data *irq_data;
|
||||||
struct irq_cfg *cfg;
|
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
if (disable_apic)
|
if (disable_apic)
|
||||||
@ -292,20 +306,20 @@ static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
|
|||||||
irq_data = irq_domain_get_irq_data(domain, virq + i);
|
irq_data = irq_domain_get_irq_data(domain, virq + i);
|
||||||
BUG_ON(!irq_data);
|
BUG_ON(!irq_data);
|
||||||
#ifdef CONFIG_X86_IO_APIC
|
#ifdef CONFIG_X86_IO_APIC
|
||||||
if (virq + i < nr_legacy_irqs() && legacy_irq_cfgs[virq + i])
|
if (virq + i < nr_legacy_irqs() && legacy_irq_data[virq + i])
|
||||||
cfg = legacy_irq_cfgs[virq + i];
|
data = legacy_irq_data[virq + i];
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
cfg = alloc_irq_cfg(irq_data->node);
|
data = alloc_apic_chip_data(irq_data->node);
|
||||||
if (!cfg) {
|
if (!data) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq_data->chip = &lapic_controller;
|
irq_data->chip = &lapic_controller;
|
||||||
irq_data->chip_data = cfg;
|
irq_data->chip_data = data;
|
||||||
irq_data->hwirq = virq + i;
|
irq_data->hwirq = virq + i;
|
||||||
err = assign_irq_vector(virq, cfg, mask);
|
err = assign_irq_vector(virq, data, mask);
|
||||||
if (err)
|
if (err)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
@ -349,22 +363,22 @@ int __init arch_probe_nr_irqs(void)
|
|||||||
static void init_legacy_irqs(void)
|
static void init_legacy_irqs(void)
|
||||||
{
|
{
|
||||||
int i, node = cpu_to_node(0);
|
int i, node = cpu_to_node(0);
|
||||||
struct irq_cfg *cfg;
|
struct apic_chip_data *data;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For legacy IRQ's, start with assigning irq0 to irq15 to
|
* For legacy IRQ's, start with assigning irq0 to irq15 to
|
||||||
* IRQ0_VECTOR to IRQ15_VECTOR for all cpu's.
|
* IRQ0_VECTOR to IRQ15_VECTOR for all cpu's.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < nr_legacy_irqs(); i++) {
|
for (i = 0; i < nr_legacy_irqs(); i++) {
|
||||||
cfg = legacy_irq_cfgs[i] = alloc_irq_cfg(node);
|
data = legacy_irq_data[i] = alloc_apic_chip_data(node);
|
||||||
BUG_ON(!cfg);
|
BUG_ON(!data);
|
||||||
/*
|
/*
|
||||||
* For legacy IRQ's, start with assigning irq0 to irq15 to
|
* For legacy IRQ's, start with assigning irq0 to irq15 to
|
||||||
* IRQ0_VECTOR to IRQ15_VECTOR for all cpu's.
|
* IRQ0_VECTOR to IRQ15_VECTOR for all cpu's.
|
||||||
*/
|
*/
|
||||||
cfg->vector = IRQ0_VECTOR + i;
|
data->cfg.vector = IRQ0_VECTOR + i;
|
||||||
cpumask_setall(cfg->domain);
|
cpumask_setall(data->domain);
|
||||||
irq_set_chip_data(i, cfg);
|
irq_set_chip_data(i, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -390,7 +404,7 @@ static void __setup_vector_irq(int cpu)
|
|||||||
{
|
{
|
||||||
/* Initialize vector_irq on a new cpu */
|
/* Initialize vector_irq on a new cpu */
|
||||||
int irq, vector;
|
int irq, vector;
|
||||||
struct irq_cfg *cfg;
|
struct apic_chip_data *data;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* vector_lock will make sure that we don't run into irq vector
|
* vector_lock will make sure that we don't run into irq vector
|
||||||
@ -400,13 +414,13 @@ static void __setup_vector_irq(int cpu)
|
|||||||
raw_spin_lock(&vector_lock);
|
raw_spin_lock(&vector_lock);
|
||||||
/* Mark the inuse vectors */
|
/* Mark the inuse vectors */
|
||||||
for_each_active_irq(irq) {
|
for_each_active_irq(irq) {
|
||||||
cfg = irq_cfg(irq);
|
data = apic_chip_data(irq_get_irq_data(irq));
|
||||||
if (!cfg)
|
if (!data)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!cpumask_test_cpu(cpu, cfg->domain))
|
if (!cpumask_test_cpu(cpu, data->domain))
|
||||||
continue;
|
continue;
|
||||||
vector = cfg->vector;
|
vector = data->cfg.vector;
|
||||||
per_cpu(vector_irq, cpu)[vector] = irq;
|
per_cpu(vector_irq, cpu)[vector] = irq;
|
||||||
}
|
}
|
||||||
/* Mark the free vectors */
|
/* Mark the free vectors */
|
||||||
@ -415,8 +429,8 @@ static void __setup_vector_irq(int cpu)
|
|||||||
if (irq <= VECTOR_UNDEFINED)
|
if (irq <= VECTOR_UNDEFINED)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cfg = irq_cfg(irq);
|
data = apic_chip_data(irq_get_irq_data(irq));
|
||||||
if (!cpumask_test_cpu(cpu, cfg->domain))
|
if (!cpumask_test_cpu(cpu, data->domain))
|
||||||
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
|
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
|
||||||
}
|
}
|
||||||
raw_spin_unlock(&vector_lock);
|
raw_spin_unlock(&vector_lock);
|
||||||
@ -442,15 +456,15 @@ void setup_vector_irq(int cpu)
|
|||||||
__setup_vector_irq(cpu);
|
__setup_vector_irq(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apic_retrigger_irq(struct irq_data *data)
|
static int apic_retrigger_irq(struct irq_data *irq_data)
|
||||||
{
|
{
|
||||||
struct irq_cfg *cfg = irqd_cfg(data);
|
struct apic_chip_data *data = apic_chip_data(irq_data);
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&vector_lock, flags);
|
raw_spin_lock_irqsave(&vector_lock, flags);
|
||||||
cpu = cpumask_first_and(cfg->domain, cpu_online_mask);
|
cpu = cpumask_first_and(data->domain, cpu_online_mask);
|
||||||
apic->send_IPI_mask(cpumask_of(cpu), cfg->vector);
|
apic->send_IPI_mask(cpumask_of(cpu), data->cfg.vector);
|
||||||
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -466,7 +480,7 @@ void apic_ack_edge(struct irq_data *data)
|
|||||||
static int apic_set_affinity(struct irq_data *irq_data,
|
static int apic_set_affinity(struct irq_data *irq_data,
|
||||||
const struct cpumask *dest, bool force)
|
const struct cpumask *dest, bool force)
|
||||||
{
|
{
|
||||||
struct irq_cfg *cfg = irq_data->chip_data;
|
struct apic_chip_data *data = irq_data->chip_data;
|
||||||
int err, irq = irq_data->irq;
|
int err, irq = irq_data->irq;
|
||||||
|
|
||||||
if (!config_enabled(CONFIG_SMP))
|
if (!config_enabled(CONFIG_SMP))
|
||||||
@ -475,11 +489,11 @@ static int apic_set_affinity(struct irq_data *irq_data,
|
|||||||
if (!cpumask_intersects(dest, cpu_online_mask))
|
if (!cpumask_intersects(dest, cpu_online_mask))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
err = assign_irq_vector(irq, cfg, dest);
|
err = assign_irq_vector(irq, data, dest);
|
||||||
if (err) {
|
if (err) {
|
||||||
struct irq_data *top = irq_get_irq_data(irq);
|
struct irq_data *top = irq_get_irq_data(irq);
|
||||||
|
|
||||||
if (assign_irq_vector(irq, cfg, top->affinity))
|
if (assign_irq_vector(irq, data, top->affinity))
|
||||||
pr_err("Failed to recover vector for irq %d\n", irq);
|
pr_err("Failed to recover vector for irq %d\n", irq);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -494,28 +508,31 @@ static struct irq_chip lapic_controller = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
static void __send_cleanup_vector(struct irq_cfg *cfg)
|
static void __send_cleanup_vector(struct apic_chip_data *data)
|
||||||
{
|
{
|
||||||
cpumask_var_t cleanup_mask;
|
cpumask_var_t cleanup_mask;
|
||||||
|
|
||||||
if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
|
if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
|
for_each_cpu_and(i, data->old_domain, cpu_online_mask)
|
||||||
apic->send_IPI_mask(cpumask_of(i),
|
apic->send_IPI_mask(cpumask_of(i),
|
||||||
IRQ_MOVE_CLEANUP_VECTOR);
|
IRQ_MOVE_CLEANUP_VECTOR);
|
||||||
} else {
|
} else {
|
||||||
cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
|
cpumask_and(cleanup_mask, data->old_domain, cpu_online_mask);
|
||||||
apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
|
apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
|
||||||
free_cpumask_var(cleanup_mask);
|
free_cpumask_var(cleanup_mask);
|
||||||
}
|
}
|
||||||
cfg->move_in_progress = 0;
|
data->move_in_progress = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_cleanup_vector(struct irq_cfg *cfg)
|
void send_cleanup_vector(struct irq_cfg *cfg)
|
||||||
{
|
{
|
||||||
if (cfg->move_in_progress)
|
struct apic_chip_data *data;
|
||||||
__send_cleanup_vector(cfg);
|
|
||||||
|
data = container_of(cfg, struct apic_chip_data, cfg);
|
||||||
|
if (data->move_in_progress)
|
||||||
|
__send_cleanup_vector(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
|
asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
|
||||||
@ -531,7 +548,7 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
|
|||||||
int irq;
|
int irq;
|
||||||
unsigned int irr;
|
unsigned int irr;
|
||||||
struct irq_desc *desc;
|
struct irq_desc *desc;
|
||||||
struct irq_cfg *cfg;
|
struct apic_chip_data *data;
|
||||||
|
|
||||||
irq = __this_cpu_read(vector_irq[vector]);
|
irq = __this_cpu_read(vector_irq[vector]);
|
||||||
|
|
||||||
@ -542,8 +559,8 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
|
|||||||
if (!desc)
|
if (!desc)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cfg = irq_cfg(irq);
|
data = apic_chip_data(&desc->irq_data);
|
||||||
if (!cfg)
|
if (!data)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
raw_spin_lock(&desc->lock);
|
raw_spin_lock(&desc->lock);
|
||||||
@ -552,10 +569,11 @@ asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
|
|||||||
* Check if the irq migration is in progress. If so, we
|
* Check if the irq migration is in progress. If so, we
|
||||||
* haven't received the cleanup request yet for this irq.
|
* haven't received the cleanup request yet for this irq.
|
||||||
*/
|
*/
|
||||||
if (cfg->move_in_progress)
|
if (data->move_in_progress)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
|
if (vector == data->cfg.vector &&
|
||||||
|
cpumask_test_cpu(me, data->domain))
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
|
irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
|
||||||
@ -581,14 +599,15 @@ unlock:
|
|||||||
static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
|
static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
|
||||||
{
|
{
|
||||||
unsigned me;
|
unsigned me;
|
||||||
|
struct apic_chip_data *data;
|
||||||
|
|
||||||
if (likely(!cfg->move_in_progress))
|
data = container_of(cfg, struct apic_chip_data, cfg);
|
||||||
|
if (likely(!data->move_in_progress))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
me = smp_processor_id();
|
me = smp_processor_id();
|
||||||
|
if (vector == data->cfg.vector && cpumask_test_cpu(me, data->domain))
|
||||||
if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
|
__send_cleanup_vector(data);
|
||||||
__send_cleanup_vector(cfg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void irq_complete_move(struct irq_cfg *cfg)
|
void irq_complete_move(struct irq_cfg *cfg)
|
||||||
@ -600,10 +619,8 @@ void irq_force_complete_move(int irq)
|
|||||||
{
|
{
|
||||||
struct irq_cfg *cfg = irq_cfg(irq);
|
struct irq_cfg *cfg = irq_cfg(irq);
|
||||||
|
|
||||||
if (!cfg)
|
if (cfg)
|
||||||
return;
|
__irq_complete_move(cfg, cfg->vector);
|
||||||
|
|
||||||
__irq_complete_move(cfg, cfg->vector);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user