2014-10-27 16:12:00 +08:00
|
|
|
/*
|
2017-11-23 06:13:37 +08:00
|
|
|
* Local APIC related interfaces to support IOAPIC, MSI, etc.
|
2014-10-27 16:12:00 +08:00
|
|
|
*
|
|
|
|
* Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
|
|
|
|
* Moved from arch/x86/kernel/apic/io_apic.c.
|
2015-04-13 14:11:24 +08:00
|
|
|
* Jiang Liu <jiang.liu@linux.intel.com>
|
|
|
|
* Enable support of hierarchical irqdomains
|
2014-10-27 16:12:00 +08:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*/
|
|
|
|
#include <linux/interrupt.h>
|
2017-09-14 05:29:39 +08:00
|
|
|
#include <linux/seq_file.h>
|
2014-10-27 16:12:00 +08:00
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/compiler.h>
|
|
|
|
#include <linux/slab.h>
|
2015-04-14 10:30:09 +08:00
|
|
|
#include <asm/irqdomain.h>
|
2014-10-27 16:12:00 +08:00
|
|
|
#include <asm/hw_irq.h>
|
|
|
|
#include <asm/apic.h>
|
|
|
|
#include <asm/i8259.h>
|
|
|
|
#include <asm/desc.h>
|
|
|
|
#include <asm/irq_remapping.h>
|
|
|
|
|
2017-09-14 05:29:41 +08:00
|
|
|
#include <asm/trace/irq_vectors.h>
|
|
|
|
|
2015-04-14 10:30:03 +08:00
|
|
|
struct apic_chip_data {
|
2017-09-14 05:29:45 +08:00
|
|
|
struct irq_cfg hw_irq_cfg;
|
|
|
|
unsigned int vector;
|
|
|
|
unsigned int prev_vector;
|
2017-09-14 05:29:31 +08:00
|
|
|
unsigned int cpu;
|
|
|
|
unsigned int prev_cpu;
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
unsigned int irq;
|
2017-09-14 05:29:32 +08:00
|
|
|
struct hlist_node clist;
|
2017-09-14 05:29:50 +08:00
|
|
|
unsigned int move_in_progress : 1,
|
2017-09-14 05:29:51 +08:00
|
|
|
is_managed : 1,
|
|
|
|
can_reserve : 1,
|
|
|
|
has_reserved : 1;
|
2015-04-14 10:30:03 +08:00
|
|
|
};
|
|
|
|
|
2015-04-13 14:11:24 +08:00
|
|
|
struct irq_domain *x86_vector_domain;
|
2015-12-11 01:52:59 +08:00
|
|
|
EXPORT_SYMBOL_GPL(x86_vector_domain);
|
2014-10-27 16:12:00 +08:00
|
|
|
static DEFINE_RAW_SPINLOCK(vector_lock);
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
static cpumask_var_t vector_searchmask;
|
2015-04-13 14:11:24 +08:00
|
|
|
static struct irq_chip lapic_controller;
|
2017-09-14 05:29:38 +08:00
|
|
|
static struct irq_matrix *vector_matrix;
|
2017-09-14 05:29:32 +08:00
|
|
|
#ifdef CONFIG_SMP
|
|
|
|
static DEFINE_PER_CPU(struct hlist_head, cleanup_list);
|
|
|
|
#endif
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
void lock_vector_lock(void)
|
|
|
|
{
|
|
|
|
/* Used to the online set of cpus does not change
|
|
|
|
* during assign_irq_vector.
|
|
|
|
*/
|
|
|
|
raw_spin_lock(&vector_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void unlock_vector_lock(void)
|
|
|
|
{
|
|
|
|
raw_spin_unlock(&vector_lock);
|
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:36 +08:00
|
|
|
void init_irq_alloc_info(struct irq_alloc_info *info,
|
|
|
|
const struct cpumask *mask)
|
|
|
|
{
|
|
|
|
memset(info, 0, sizeof(*info));
|
|
|
|
info->mask = mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
void copy_irq_alloc_info(struct irq_alloc_info *dst, struct irq_alloc_info *src)
|
|
|
|
{
|
|
|
|
if (src)
|
|
|
|
*dst = *src;
|
|
|
|
else
|
|
|
|
memset(dst, 0, sizeof(*dst));
|
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:30 +08:00
|
|
|
static struct apic_chip_data *apic_chip_data(struct irq_data *irqd)
|
2014-10-27 16:12:00 +08:00
|
|
|
{
|
2017-09-14 05:29:30 +08:00
|
|
|
if (!irqd)
|
2015-04-13 14:11:24 +08:00
|
|
|
return NULL;
|
|
|
|
|
2017-09-14 05:29:30 +08:00
|
|
|
while (irqd->parent_data)
|
|
|
|
irqd = irqd->parent_data;
|
2015-04-13 14:11:24 +08:00
|
|
|
|
2017-09-14 05:29:30 +08:00
|
|
|
return irqd->chip_data;
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:30 +08:00
|
|
|
struct irq_cfg *irqd_cfg(struct irq_data *irqd)
|
2015-04-14 10:30:03 +08:00
|
|
|
{
|
2017-09-14 05:29:30 +08:00
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
2015-04-14 10:30:03 +08:00
|
|
|
|
2017-09-14 05:29:45 +08:00
|
|
|
return apicd ? &apicd->hw_irq_cfg : NULL;
|
2015-04-14 10:30:03 +08:00
|
|
|
}
|
2015-12-11 01:52:59 +08:00
|
|
|
EXPORT_SYMBOL_GPL(irqd_cfg);
|
2015-04-14 10:30:03 +08:00
|
|
|
|
|
|
|
struct irq_cfg *irq_cfg(unsigned int irq)
|
2014-10-27 16:12:00 +08:00
|
|
|
{
|
2015-04-14 10:30:03 +08:00
|
|
|
return irqd_cfg(irq_get_irq_data(irq));
|
|
|
|
}
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2015-04-14 10:30:03 +08:00
|
|
|
static struct apic_chip_data *alloc_apic_chip_data(int node)
|
|
|
|
{
|
2017-09-14 05:29:30 +08:00
|
|
|
struct apic_chip_data *apicd;
|
2015-04-14 10:30:03 +08:00
|
|
|
|
2017-09-14 05:29:30 +08:00
|
|
|
apicd = kzalloc_node(sizeof(*apicd), GFP_KERNEL, node);
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
if (apicd)
|
|
|
|
INIT_HLIST_NODE(&apicd->clist);
|
2017-09-14 05:29:30 +08:00
|
|
|
return apicd;
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:30 +08:00
|
|
|
static void free_apic_chip_data(struct apic_chip_data *apicd)
|
2014-10-27 16:12:00 +08:00
|
|
|
{
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
kfree(apicd);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:45 +08:00
|
|
|
static void apic_update_irq_cfg(struct irq_data *irqd, unsigned int vector,
|
|
|
|
unsigned int cpu)
|
2014-10-27 16:12:00 +08:00
|
|
|
{
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
lockdep_assert_held(&vector_lock);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2017-09-14 05:29:45 +08:00
|
|
|
apicd->hw_irq_cfg.vector = vector;
|
|
|
|
apicd->hw_irq_cfg.dest_apicid = apic->calc_dest_apicid(cpu);
|
|
|
|
irq_data_update_effective_affinity(irqd, cpumask_of(cpu));
|
|
|
|
trace_vector_config(irqd->irq, vector, cpu,
|
|
|
|
apicd->hw_irq_cfg.dest_apicid);
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
}
|
2014-10-27 16:12:00 +08:00
|
|
|
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
static void apic_update_vector(struct irq_data *irqd, unsigned int newvec,
|
|
|
|
unsigned int newcpu)
|
|
|
|
{
|
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
|
|
|
struct irq_desc *desc = irq_data_to_desc(irqd);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
lockdep_assert_held(&vector_lock);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2017-09-14 05:29:45 +08:00
|
|
|
trace_vector_update(irqd->irq, newvec, newcpu, apicd->vector,
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
apicd->cpu);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
/* Setup the vector move, if required */
|
2017-09-14 05:29:45 +08:00
|
|
|
if (apicd->vector && cpu_online(apicd->cpu)) {
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
apicd->move_in_progress = true;
|
2017-09-14 05:29:45 +08:00
|
|
|
apicd->prev_vector = apicd->vector;
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
apicd->prev_cpu = apicd->cpu;
|
|
|
|
} else {
|
2017-09-14 05:29:45 +08:00
|
|
|
apicd->prev_vector = 0;
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
}
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2017-09-14 05:29:45 +08:00
|
|
|
apicd->vector = newvec;
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
apicd->cpu = newcpu;
|
|
|
|
BUG_ON(!IS_ERR_OR_NULL(per_cpu(vector_irq, newcpu)[newvec]));
|
|
|
|
per_cpu(vector_irq, newcpu)[newvec] = desc;
|
|
|
|
}
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2017-09-14 05:29:50 +08:00
|
|
|
static void vector_assign_managed_shutdown(struct irq_data *irqd)
|
|
|
|
{
|
|
|
|
unsigned int cpu = cpumask_first(cpu_online_mask);
|
|
|
|
|
|
|
|
apic_update_irq_cfg(irqd, MANAGED_IRQ_SHUTDOWN_VECTOR, cpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int reserve_managed_vector(struct irq_data *irqd)
|
|
|
|
{
|
|
|
|
const struct cpumask *affmsk = irq_data_get_affinity_mask(irqd);
|
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
|
|
|
unsigned long flags;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
raw_spin_lock_irqsave(&vector_lock, flags);
|
|
|
|
apicd->is_managed = true;
|
|
|
|
ret = irq_matrix_reserve_managed(vector_matrix, affmsk);
|
|
|
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
|
|
|
trace_vector_reserve_managed(irqd->irq, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:51 +08:00
|
|
|
static void reserve_irq_vector_locked(struct irq_data *irqd)
|
|
|
|
{
|
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
|
|
|
|
|
|
|
irq_matrix_reserve(vector_matrix);
|
|
|
|
apicd->can_reserve = true;
|
|
|
|
apicd->has_reserved = true;
|
2017-12-29 23:57:00 +08:00
|
|
|
irqd_set_can_reserve(irqd);
|
2017-09-14 05:29:51 +08:00
|
|
|
trace_vector_reserve(irqd->irq, 0);
|
|
|
|
vector_assign_managed_shutdown(irqd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int reserve_irq_vector(struct irq_data *irqd)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
raw_spin_lock_irqsave(&vector_lock, flags);
|
|
|
|
reserve_irq_vector_locked(irqd);
|
|
|
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
static int allocate_vector(struct irq_data *irqd, const struct cpumask *dest)
|
|
|
|
{
|
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
2017-09-14 05:29:51 +08:00
|
|
|
bool resvd = apicd->has_reserved;
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
unsigned int cpu = apicd->cpu;
|
2017-09-14 05:29:45 +08:00
|
|
|
int vector = apicd->vector;
|
|
|
|
|
|
|
|
lockdep_assert_held(&vector_lock);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2016-01-01 00:30:48 +08:00
|
|
|
/*
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
* If the current target CPU is online and in the new requested
|
|
|
|
* affinity mask, there is no point in moving the interrupt from
|
|
|
|
* one CPU to another.
|
2016-01-01 00:30:48 +08:00
|
|
|
*/
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
if (vector && cpu_online(cpu) && cpumask_test_cpu(cpu, dest))
|
|
|
|
return 0;
|
|
|
|
|
2017-09-14 05:29:51 +08:00
|
|
|
vector = irq_matrix_alloc(vector_matrix, dest, resvd, &cpu);
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
if (vector > 0)
|
|
|
|
apic_update_vector(irqd, vector, cpu);
|
2017-09-14 05:29:51 +08:00
|
|
|
trace_vector_alloc(irqd->irq, vector, resvd, vector);
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
return vector;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int assign_vector_locked(struct irq_data *irqd,
|
|
|
|
const struct cpumask *dest)
|
|
|
|
{
|
2017-09-14 05:29:45 +08:00
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
int vector = allocate_vector(irqd, dest);
|
|
|
|
|
|
|
|
if (vector < 0)
|
|
|
|
return vector;
|
|
|
|
|
2017-09-14 05:29:45 +08:00
|
|
|
apic_update_irq_cfg(irqd, apicd->vector, apicd->cpu);
|
2016-01-01 00:30:48 +08:00
|
|
|
return 0;
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
static int assign_irq_vector(struct irq_data *irqd, const struct cpumask *dest)
|
2014-10-27 16:12:00 +08:00
|
|
|
{
|
|
|
|
unsigned long flags;
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
int ret;
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
raw_spin_lock_irqsave(&vector_lock, flags);
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
cpumask_and(vector_searchmask, dest, cpu_online_mask);
|
|
|
|
ret = assign_vector_locked(irqd, vector_searchmask);
|
2014-10-27 16:12:00 +08:00
|
|
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
return ret;
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:50 +08:00
|
|
|
static int assign_irq_vector_any_locked(struct irq_data *irqd)
|
|
|
|
{
|
2017-09-14 05:29:54 +08:00
|
|
|
/* Get the affinity mask - either irq_default_affinity or (user) set */
|
|
|
|
const struct cpumask *affmsk = irq_data_get_affinity_mask(irqd);
|
2017-09-14 05:29:50 +08:00
|
|
|
int node = irq_data_get_node(irqd);
|
|
|
|
|
2017-09-14 05:29:54 +08:00
|
|
|
if (node == NUMA_NO_NODE)
|
|
|
|
goto all;
|
|
|
|
/* Try the intersection of @affmsk and node mask */
|
|
|
|
cpumask_and(vector_searchmask, cpumask_of_node(node), affmsk);
|
|
|
|
if (!assign_vector_locked(irqd, vector_searchmask))
|
|
|
|
return 0;
|
|
|
|
/* Try the node mask */
|
|
|
|
if (!assign_vector_locked(irqd, cpumask_of_node(node)))
|
|
|
|
return 0;
|
|
|
|
all:
|
|
|
|
/* Try the full affinity mask */
|
|
|
|
cpumask_and(vector_searchmask, affmsk, cpu_online_mask);
|
|
|
|
if (!assign_vector_locked(irqd, vector_searchmask))
|
|
|
|
return 0;
|
|
|
|
/* Try the full online mask */
|
2017-09-14 05:29:50 +08:00
|
|
|
return assign_vector_locked(irqd, cpu_online_mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
assign_irq_vector_policy(struct irq_data *irqd, struct irq_alloc_info *info)
|
2015-05-07 10:53:56 +08:00
|
|
|
{
|
2017-09-14 05:29:50 +08:00
|
|
|
if (irqd_affinity_is_managed(irqd))
|
|
|
|
return reserve_managed_vector(irqd);
|
2017-09-14 05:29:35 +08:00
|
|
|
if (info->mask)
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
return assign_irq_vector(irqd, info->mask);
|
2017-09-14 05:29:52 +08:00
|
|
|
/*
|
|
|
|
* Make only a global reservation with no guarantee. A real vector
|
|
|
|
* is associated at activation time.
|
|
|
|
*/
|
2017-09-14 05:29:51 +08:00
|
|
|
return reserve_irq_vector(irqd);
|
2017-09-14 05:29:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
assign_managed_vector(struct irq_data *irqd, const struct cpumask *dest)
|
|
|
|
{
|
|
|
|
const struct cpumask *affmsk = irq_data_get_affinity_mask(irqd);
|
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
|
|
|
int vector, cpu;
|
|
|
|
|
|
|
|
cpumask_and(vector_searchmask, vector_searchmask, affmsk);
|
|
|
|
cpu = cpumask_first(vector_searchmask);
|
|
|
|
if (cpu >= nr_cpu_ids)
|
|
|
|
return -EINVAL;
|
|
|
|
/* set_affinity might call here for nothing */
|
|
|
|
if (apicd->vector && cpumask_test_cpu(apicd->cpu, vector_searchmask))
|
2015-05-07 10:53:56 +08:00
|
|
|
return 0;
|
2017-09-14 05:29:50 +08:00
|
|
|
vector = irq_matrix_alloc_managed(vector_matrix, cpu);
|
|
|
|
trace_vector_alloc_managed(irqd->irq, vector, vector);
|
|
|
|
if (vector < 0)
|
|
|
|
return vector;
|
|
|
|
apic_update_vector(irqd, vector, cpu);
|
|
|
|
apic_update_irq_cfg(irqd, vector, cpu);
|
|
|
|
return 0;
|
2015-05-07 10:53:56 +08:00
|
|
|
}
|
|
|
|
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
static void clear_irq_vector(struct irq_data *irqd)
|
2014-10-27 16:12:00 +08:00
|
|
|
{
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
2017-09-14 05:29:50 +08:00
|
|
|
bool managed = irqd_affinity_is_managed(irqd);
|
2017-09-14 05:29:45 +08:00
|
|
|
unsigned int vector = apicd->vector;
|
2014-10-27 16:12:00 +08:00
|
|
|
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
lockdep_assert_held(&vector_lock);
|
2017-09-14 05:29:45 +08:00
|
|
|
|
2017-09-14 05:29:32 +08:00
|
|
|
if (!vector)
|
2016-04-28 04:22:32 +08:00
|
|
|
return;
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2017-09-14 05:29:45 +08:00
|
|
|
trace_vector_clear(irqd->irq, vector, apicd->cpu, apicd->prev_vector,
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
apicd->prev_cpu);
|
|
|
|
|
2017-09-14 05:29:32 +08:00
|
|
|
per_cpu(vector_irq, apicd->cpu)[vector] = VECTOR_UNUSED;
|
2017-09-14 05:29:50 +08:00
|
|
|
irq_matrix_free(vector_matrix, apicd->cpu, vector, managed);
|
2017-09-14 05:29:45 +08:00
|
|
|
apicd->vector = 0;
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2017-09-14 05:29:32 +08:00
|
|
|
/* Clean up move in progress */
|
2017-09-14 05:29:45 +08:00
|
|
|
vector = apicd->prev_vector;
|
2017-09-14 05:29:32 +08:00
|
|
|
if (!vector)
|
2014-10-27 16:12:00 +08:00
|
|
|
return;
|
|
|
|
|
2017-09-14 05:29:32 +08:00
|
|
|
per_cpu(vector_irq, apicd->prev_cpu)[vector] = VECTOR_UNUSED;
|
2017-09-14 05:29:50 +08:00
|
|
|
irq_matrix_free(vector_matrix, apicd->prev_cpu, vector, managed);
|
2017-09-14 05:29:45 +08:00
|
|
|
apicd->prev_vector = 0;
|
2017-09-14 05:29:30 +08:00
|
|
|
apicd->move_in_progress = 0;
|
2017-09-14 05:29:32 +08:00
|
|
|
hlist_del_init(&apicd->clist);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:50 +08:00
|
|
|
static void x86_vector_deactivate(struct irq_domain *dom, struct irq_data *irqd)
|
|
|
|
{
|
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
trace_vector_deactivate(irqd->irq, apicd->is_managed,
|
2017-09-14 05:29:51 +08:00
|
|
|
apicd->can_reserve, false);
|
2017-09-14 05:29:50 +08:00
|
|
|
|
2017-09-14 05:29:51 +08:00
|
|
|
/* Regular fixed assigned interrupt */
|
|
|
|
if (!apicd->is_managed && !apicd->can_reserve)
|
|
|
|
return;
|
|
|
|
/* If the interrupt has a global reservation, nothing to do */
|
|
|
|
if (apicd->has_reserved)
|
2017-09-14 05:29:50 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
raw_spin_lock_irqsave(&vector_lock, flags);
|
|
|
|
clear_irq_vector(irqd);
|
2017-09-14 05:29:51 +08:00
|
|
|
if (apicd->can_reserve)
|
|
|
|
reserve_irq_vector_locked(irqd);
|
|
|
|
else
|
|
|
|
vector_assign_managed_shutdown(irqd);
|
2017-09-14 05:29:50 +08:00
|
|
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:51 +08:00
|
|
|
static int activate_reserved(struct irq_data *irqd)
|
|
|
|
{
|
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = assign_irq_vector_any_locked(irqd);
|
|
|
|
if (!ret)
|
|
|
|
apicd->has_reserved = false;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:50 +08:00
|
|
|
static int activate_managed(struct irq_data *irqd)
|
|
|
|
{
|
|
|
|
const struct cpumask *dest = irq_data_get_affinity_mask(irqd);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
cpumask_and(vector_searchmask, dest, cpu_online_mask);
|
|
|
|
if (WARN_ON_ONCE(cpumask_empty(vector_searchmask))) {
|
|
|
|
/* Something in the core code broke! Survive gracefully */
|
|
|
|
pr_err("Managed startup for irq %u, but no CPU\n", irqd->irq);
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = assign_managed_vector(irqd, vector_searchmask);
|
|
|
|
/*
|
|
|
|
* This should not happen. The vector reservation got buggered. Handle
|
|
|
|
* it gracefully.
|
|
|
|
*/
|
|
|
|
if (WARN_ON_ONCE(ret < 0)) {
|
|
|
|
pr_err("Managed startup irq %u, no vector available\n",
|
|
|
|
irqd->irq);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int x86_vector_activate(struct irq_domain *dom, struct irq_data *irqd,
|
|
|
|
bool early)
|
|
|
|
{
|
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
|
|
|
unsigned long flags;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
trace_vector_activate(irqd->irq, apicd->is_managed,
|
2017-09-14 05:29:51 +08:00
|
|
|
apicd->can_reserve, early);
|
2017-09-14 05:29:50 +08:00
|
|
|
|
2017-09-14 05:29:51 +08:00
|
|
|
/* Nothing to do for fixed assigned vectors */
|
|
|
|
if (!apicd->can_reserve && !apicd->is_managed)
|
2017-09-14 05:29:50 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
raw_spin_lock_irqsave(&vector_lock, flags);
|
|
|
|
if (early || irqd_is_managed_and_shutdown(irqd))
|
|
|
|
vector_assign_managed_shutdown(irqd);
|
2017-09-14 05:29:51 +08:00
|
|
|
else if (apicd->is_managed)
|
2017-09-14 05:29:50 +08:00
|
|
|
ret = activate_managed(irqd);
|
2017-09-14 05:29:51 +08:00
|
|
|
else if (apicd->has_reserved)
|
|
|
|
ret = activate_reserved(irqd);
|
2017-09-14 05:29:50 +08:00
|
|
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void vector_free_reserved_and_managed(struct irq_data *irqd)
|
|
|
|
{
|
|
|
|
const struct cpumask *dest = irq_data_get_affinity_mask(irqd);
|
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
|
|
|
|
2017-09-14 05:29:51 +08:00
|
|
|
trace_vector_teardown(irqd->irq, apicd->is_managed,
|
|
|
|
apicd->has_reserved);
|
2017-09-14 05:29:50 +08:00
|
|
|
|
2017-09-14 05:29:51 +08:00
|
|
|
if (apicd->has_reserved)
|
|
|
|
irq_matrix_remove_reserved(vector_matrix);
|
2017-09-14 05:29:50 +08:00
|
|
|
if (apicd->is_managed)
|
|
|
|
irq_matrix_remove_managed(vector_matrix, dest);
|
|
|
|
}
|
|
|
|
|
2015-04-13 14:11:24 +08:00
|
|
|
static void x86_vector_free_irqs(struct irq_domain *domain,
|
|
|
|
unsigned int virq, unsigned int nr_irqs)
|
|
|
|
{
|
2017-09-14 05:29:30 +08:00
|
|
|
struct apic_chip_data *apicd;
|
|
|
|
struct irq_data *irqd;
|
2016-01-01 00:30:44 +08:00
|
|
|
unsigned long flags;
|
2015-04-13 14:11:24 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < nr_irqs; i++) {
|
2017-09-14 05:29:30 +08:00
|
|
|
irqd = irq_domain_get_irq_data(x86_vector_domain, virq + i);
|
|
|
|
if (irqd && irqd->chip_data) {
|
2016-01-01 00:30:44 +08:00
|
|
|
raw_spin_lock_irqsave(&vector_lock, flags);
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
clear_irq_vector(irqd);
|
2017-09-14 05:29:50 +08:00
|
|
|
vector_free_reserved_and_managed(irqd);
|
2017-09-14 05:29:30 +08:00
|
|
|
apicd = irqd->chip_data;
|
|
|
|
irq_domain_reset_irq_data(irqd);
|
2016-01-01 00:30:44 +08:00
|
|
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
2017-09-14 05:29:30 +08:00
|
|
|
free_apic_chip_data(apicd);
|
2015-04-13 14:11:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:52 +08:00
|
|
|
static bool vector_configure_legacy(unsigned int virq, struct irq_data *irqd,
|
|
|
|
struct apic_chip_data *apicd)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
bool realloc = false;
|
|
|
|
|
|
|
|
apicd->vector = ISA_IRQ_VECTOR(virq);
|
|
|
|
apicd->cpu = 0;
|
|
|
|
|
|
|
|
raw_spin_lock_irqsave(&vector_lock, flags);
|
|
|
|
/*
|
|
|
|
* If the interrupt is activated, then it must stay at this vector
|
|
|
|
* position. That's usually the timer interrupt (0).
|
|
|
|
*/
|
|
|
|
if (irqd_is_activated(irqd)) {
|
|
|
|
trace_vector_setup(virq, true, 0);
|
|
|
|
apic_update_irq_cfg(irqd, apicd->vector, apicd->cpu);
|
|
|
|
} else {
|
|
|
|
/* Release the vector */
|
|
|
|
apicd->can_reserve = true;
|
2017-12-29 23:57:00 +08:00
|
|
|
irqd_set_can_reserve(irqd);
|
2017-09-14 05:29:52 +08:00
|
|
|
clear_irq_vector(irqd);
|
|
|
|
realloc = true;
|
|
|
|
}
|
|
|
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
|
|
|
return realloc;
|
|
|
|
}
|
|
|
|
|
2015-04-13 14:11:24 +08:00
|
|
|
static int x86_vector_alloc_irqs(struct irq_domain *domain, unsigned int virq,
|
|
|
|
unsigned int nr_irqs, void *arg)
|
|
|
|
{
|
|
|
|
struct irq_alloc_info *info = arg;
|
2017-09-14 05:29:30 +08:00
|
|
|
struct apic_chip_data *apicd;
|
|
|
|
struct irq_data *irqd;
|
2015-06-01 16:05:14 +08:00
|
|
|
int i, err, node;
|
2015-04-13 14:11:24 +08:00
|
|
|
|
|
|
|
if (disable_apic)
|
|
|
|
return -ENXIO;
|
|
|
|
|
|
|
|
/* Currently vector allocator can't guarantee contiguous allocations */
|
|
|
|
if ((info->flags & X86_IRQ_ALLOC_CONTIGUOUS_VECTORS) && nr_irqs > 1)
|
|
|
|
return -ENOSYS;
|
|
|
|
|
|
|
|
for (i = 0; i < nr_irqs; i++) {
|
2017-09-14 05:29:30 +08:00
|
|
|
irqd = irq_domain_get_irq_data(domain, virq + i);
|
|
|
|
BUG_ON(!irqd);
|
|
|
|
node = irq_data_get_node(irqd);
|
2017-09-14 05:29:34 +08:00
|
|
|
WARN_ON_ONCE(irqd->chip_data);
|
|
|
|
apicd = alloc_apic_chip_data(node);
|
2017-09-14 05:29:30 +08:00
|
|
|
if (!apicd) {
|
2015-04-13 14:11:24 +08:00
|
|
|
err = -ENOMEM;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
apicd->irq = virq + i;
|
2017-09-14 05:29:30 +08:00
|
|
|
irqd->chip = &lapic_controller;
|
|
|
|
irqd->chip_data = apicd;
|
|
|
|
irqd->hwirq = virq + i;
|
|
|
|
irqd_set_single_target(irqd);
|
2017-09-14 05:29:34 +08:00
|
|
|
/*
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
* Legacy vectors are already assigned when the IOAPIC
|
|
|
|
* takes them over. They stay on the same vector. This is
|
|
|
|
* required for check_timer() to work correctly as it might
|
|
|
|
* switch back to legacy mode. Only update the hardware
|
|
|
|
* config.
|
2017-09-14 05:29:34 +08:00
|
|
|
*/
|
|
|
|
if (info->flags & X86_IRQ_ALLOC_LEGACY) {
|
2017-09-14 05:29:52 +08:00
|
|
|
if (!vector_configure_legacy(virq + i, irqd, apicd))
|
|
|
|
continue;
|
2017-09-14 05:29:34 +08:00
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:50 +08:00
|
|
|
err = assign_irq_vector_policy(irqd, info);
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
trace_vector_setup(virq + i, false, err);
|
2015-04-13 14:11:24 +08:00
|
|
|
if (err)
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
x86_vector_free_irqs(domain, virq, i + 1);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:39 +08:00
|
|
|
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
|
2017-12-07 01:33:58 +08:00
|
|
|
static void x86_vector_debug_show(struct seq_file *m, struct irq_domain *d,
|
|
|
|
struct irq_data *irqd, int ind)
|
2017-09-14 05:29:39 +08:00
|
|
|
{
|
2017-09-14 05:29:45 +08:00
|
|
|
unsigned int cpu, vector, prev_cpu, prev_vector;
|
2017-09-14 05:29:39 +08:00
|
|
|
struct apic_chip_data *apicd;
|
|
|
|
unsigned long flags;
|
|
|
|
int irq;
|
|
|
|
|
|
|
|
if (!irqd) {
|
|
|
|
irq_matrix_debug_show(m, vector_matrix, ind);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
irq = irqd->irq;
|
|
|
|
if (irq < nr_legacy_irqs() && !test_bit(irq, &io_apic_irqs)) {
|
|
|
|
seq_printf(m, "%*sVector: %5d\n", ind, "", ISA_IRQ_VECTOR(irq));
|
|
|
|
seq_printf(m, "%*sTarget: Legacy PIC all CPUs\n", ind, "");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
apicd = irqd->chip_data;
|
|
|
|
if (!apicd) {
|
|
|
|
seq_printf(m, "%*sVector: Not assigned\n", ind, "");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
raw_spin_lock_irqsave(&vector_lock, flags);
|
|
|
|
cpu = apicd->cpu;
|
2017-09-14 05:29:45 +08:00
|
|
|
vector = apicd->vector;
|
2017-09-14 05:29:39 +08:00
|
|
|
prev_cpu = apicd->prev_cpu;
|
2017-09-14 05:29:45 +08:00
|
|
|
prev_vector = apicd->prev_vector;
|
2017-09-14 05:29:39 +08:00
|
|
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
2017-09-14 05:29:45 +08:00
|
|
|
seq_printf(m, "%*sVector: %5u\n", ind, "", vector);
|
2017-09-14 05:29:39 +08:00
|
|
|
seq_printf(m, "%*sTarget: %5u\n", ind, "", cpu);
|
2017-09-14 05:29:45 +08:00
|
|
|
if (prev_vector) {
|
|
|
|
seq_printf(m, "%*sPrevious vector: %5u\n", ind, "", prev_vector);
|
2017-09-14 05:29:39 +08:00
|
|
|
seq_printf(m, "%*sPrevious target: %5u\n", ind, "", prev_cpu);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-05-05 17:10:11 +08:00
|
|
|
static const struct irq_domain_ops x86_vector_domain_ops = {
|
2017-09-14 05:29:39 +08:00
|
|
|
.alloc = x86_vector_alloc_irqs,
|
|
|
|
.free = x86_vector_free_irqs,
|
2017-09-14 05:29:50 +08:00
|
|
|
.activate = x86_vector_activate,
|
|
|
|
.deactivate = x86_vector_deactivate,
|
2017-09-14 05:29:39 +08:00
|
|
|
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS
|
|
|
|
.debug_show = x86_vector_debug_show,
|
|
|
|
#endif
|
2015-04-13 14:11:24 +08:00
|
|
|
};
|
|
|
|
|
2014-10-27 16:12:05 +08:00
|
|
|
int __init arch_probe_nr_irqs(void)
|
|
|
|
{
|
|
|
|
int nr;
|
|
|
|
|
|
|
|
if (nr_irqs > (NR_VECTORS * nr_cpu_ids))
|
|
|
|
nr_irqs = NR_VECTORS * nr_cpu_ids;
|
|
|
|
|
|
|
|
nr = (gsi_top + nr_legacy_irqs()) + 8 * nr_cpu_ids;
|
2017-11-23 06:13:37 +08:00
|
|
|
#if defined(CONFIG_PCI_MSI)
|
2014-10-27 16:12:05 +08:00
|
|
|
/*
|
|
|
|
* for MSI and HT dyn irq
|
|
|
|
*/
|
|
|
|
if (gsi_top <= NR_IRQS_LEGACY)
|
|
|
|
nr += 8 * nr_cpu_ids;
|
|
|
|
else
|
|
|
|
nr += gsi_top * 16;
|
|
|
|
#endif
|
|
|
|
if (nr < nr_irqs)
|
|
|
|
nr_irqs = nr;
|
|
|
|
|
2015-11-03 17:40:14 +08:00
|
|
|
/*
|
|
|
|
* We don't know if PIC is present at this point so we need to do
|
|
|
|
* probe() to get the right number of legacy IRQs.
|
|
|
|
*/
|
|
|
|
return legacy_pic->probe();
|
2014-10-27 16:12:05 +08:00
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:38 +08:00
|
|
|
void lapic_assign_legacy_vector(unsigned int irq, bool replace)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Use assign system here so it wont get accounted as allocated
|
|
|
|
* and moveable in the cpu hotplug check and it prevents managed
|
|
|
|
* irq reservation from touching it.
|
|
|
|
*/
|
|
|
|
irq_matrix_assign_system(vector_matrix, ISA_IRQ_VECTOR(irq), replace);
|
|
|
|
}
|
|
|
|
|
|
|
|
void __init lapic_assign_system_vectors(void)
|
|
|
|
{
|
|
|
|
unsigned int i, vector = 0;
|
|
|
|
|
|
|
|
for_each_set_bit_from(vector, system_vectors, NR_VECTORS)
|
|
|
|
irq_matrix_assign_system(vector_matrix, vector, false);
|
|
|
|
|
|
|
|
if (nr_legacy_irqs() > 1)
|
|
|
|
lapic_assign_legacy_vector(PIC_CASCADE_IR, false);
|
|
|
|
|
|
|
|
/* System vectors are reserved, online it */
|
|
|
|
irq_matrix_online(vector_matrix);
|
|
|
|
|
|
|
|
/* Mark the preallocated legacy interrupts */
|
|
|
|
for (i = 0; i < nr_legacy_irqs(); i++) {
|
|
|
|
if (i != PIC_CASCADE_IR)
|
|
|
|
irq_matrix_assign(vector_matrix, ISA_IRQ_VECTOR(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-27 16:12:05 +08:00
|
|
|
int __init arch_early_irq_init(void)
|
|
|
|
{
|
2017-06-20 07:37:06 +08:00
|
|
|
struct fwnode_handle *fn;
|
|
|
|
|
|
|
|
fn = irq_domain_alloc_named_fwnode("VECTOR");
|
|
|
|
BUG_ON(!fn);
|
|
|
|
x86_vector_domain = irq_domain_create_tree(fn, &x86_vector_domain_ops,
|
|
|
|
NULL);
|
2015-04-13 14:11:24 +08:00
|
|
|
BUG_ON(x86_vector_domain == NULL);
|
2017-06-20 07:37:06 +08:00
|
|
|
irq_domain_free_fwnode(fn);
|
2015-04-13 14:11:24 +08:00
|
|
|
irq_set_default_host(x86_vector_domain);
|
|
|
|
|
2015-04-13 14:11:35 +08:00
|
|
|
arch_init_msi_domain(x86_vector_domain);
|
|
|
|
|
2016-01-01 00:30:48 +08:00
|
|
|
BUG_ON(!alloc_cpumask_var(&vector_searchmask, GFP_KERNEL));
|
2015-04-14 10:30:10 +08:00
|
|
|
|
2017-09-14 05:29:38 +08:00
|
|
|
/*
|
|
|
|
* Allocate the vector matrix allocator data structure and limit the
|
|
|
|
* search area.
|
|
|
|
*/
|
|
|
|
vector_matrix = irq_alloc_matrix(NR_VECTORS, FIRST_EXTERNAL_VECTOR,
|
|
|
|
FIRST_SYSTEM_VECTOR);
|
|
|
|
BUG_ON(!vector_matrix);
|
|
|
|
|
2014-10-27 16:12:05 +08:00
|
|
|
return arch_early_ioapic_init();
|
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:44 +08:00
|
|
|
#ifdef CONFIG_SMP
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2017-09-14 05:29:29 +08:00
|
|
|
static struct irq_desc *__setup_vector_irq(int vector)
|
|
|
|
{
|
|
|
|
int isairq = vector - ISA_IRQ_VECTOR(0);
|
|
|
|
|
|
|
|
/* Check whether the irq is in the legacy space */
|
|
|
|
if (isairq < 0 || isairq >= nr_legacy_irqs())
|
|
|
|
return VECTOR_UNUSED;
|
|
|
|
/* Check whether the irq is handled by the IOAPIC */
|
|
|
|
if (test_bit(isairq, &io_apic_irqs))
|
|
|
|
return VECTOR_UNUSED;
|
|
|
|
return irq_to_desc(isairq);
|
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:38 +08:00
|
|
|
/* Online the local APIC infrastructure and initialize the vectors */
|
|
|
|
void lapic_online(void)
|
2014-10-27 16:12:00 +08:00
|
|
|
{
|
2017-09-14 05:29:29 +08:00
|
|
|
unsigned int vector;
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2015-07-06 01:12:32 +08:00
|
|
|
lockdep_assert_held(&vector_lock);
|
2017-09-14 05:29:38 +08:00
|
|
|
|
|
|
|
/* Online the vector matrix array for this CPU */
|
|
|
|
irq_matrix_online(vector_matrix);
|
|
|
|
|
2014-10-27 16:12:00 +08:00
|
|
|
/*
|
2017-09-14 05:29:29 +08:00
|
|
|
* The interrupt affinity logic never targets interrupts to offline
|
|
|
|
* CPUs. The exception are the legacy PIC interrupts. In general
|
|
|
|
* they are only targeted to CPU0, but depending on the platform
|
|
|
|
* they can be distributed to any online CPU in hardware. The
|
|
|
|
* kernel has no influence on that. So all active legacy vectors
|
|
|
|
* must be installed on all CPUs. All non legacy interrupts can be
|
|
|
|
* cleared.
|
2014-10-27 16:12:00 +08:00
|
|
|
*/
|
2017-09-14 05:29:29 +08:00
|
|
|
for (vector = 0; vector < NR_VECTORS; vector++)
|
|
|
|
this_cpu_write(vector_irq[vector], __setup_vector_irq(vector));
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:38 +08:00
|
|
|
void lapic_offline(void)
|
|
|
|
{
|
|
|
|
lock_vector_lock();
|
|
|
|
irq_matrix_offline(vector_matrix);
|
|
|
|
unlock_vector_lock();
|
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:44 +08:00
|
|
|
static int apic_set_affinity(struct irq_data *irqd,
|
|
|
|
const struct cpumask *dest, bool force)
|
|
|
|
{
|
2017-10-12 17:05:28 +08:00
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
2017-09-14 05:29:44 +08:00
|
|
|
int err;
|
|
|
|
|
2017-10-12 17:05:28 +08:00
|
|
|
/*
|
|
|
|
* Core code can call here for inactive interrupts. For inactive
|
|
|
|
* interrupts which use managed or reservation mode there is no
|
|
|
|
* point in going through the vector assignment right now as the
|
|
|
|
* activation will assign a vector which fits the destination
|
|
|
|
* cpumask. Let the core code store the destination mask and be
|
|
|
|
* done with it.
|
|
|
|
*/
|
|
|
|
if (!irqd_is_activated(irqd) &&
|
|
|
|
(apicd->is_managed || apicd->can_reserve))
|
|
|
|
return IRQ_SET_MASK_OK;
|
|
|
|
|
2017-09-14 05:29:50 +08:00
|
|
|
raw_spin_lock(&vector_lock);
|
|
|
|
cpumask_and(vector_searchmask, dest, cpu_online_mask);
|
|
|
|
if (irqd_affinity_is_managed(irqd))
|
|
|
|
err = assign_managed_vector(irqd, vector_searchmask);
|
|
|
|
else
|
|
|
|
err = assign_vector_locked(irqd, vector_searchmask);
|
|
|
|
raw_spin_unlock(&vector_lock);
|
2017-09-14 05:29:44 +08:00
|
|
|
return err ? err : IRQ_SET_MASK_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
# define apic_set_affinity NULL
|
|
|
|
#endif
|
|
|
|
|
2017-09-14 05:29:30 +08:00
|
|
|
static int apic_retrigger_irq(struct irq_data *irqd)
|
2014-10-27 16:12:00 +08:00
|
|
|
{
|
2017-09-14 05:29:30 +08:00
|
|
|
struct apic_chip_data *apicd = apic_chip_data(irqd);
|
2014-10-27 16:12:00 +08:00
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
raw_spin_lock_irqsave(&vector_lock, flags);
|
2017-09-14 05:29:45 +08:00
|
|
|
apic->send_IPI(apicd->cpu, apicd->vector);
|
2014-10-27 16:12:00 +08:00
|
|
|
raw_spin_unlock_irqrestore(&vector_lock, flags);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:30 +08:00
|
|
|
void apic_ack_edge(struct irq_data *irqd)
|
2014-10-27 16:12:00 +08:00
|
|
|
{
|
2017-09-14 05:29:30 +08:00
|
|
|
irq_complete_move(irqd_cfg(irqd));
|
|
|
|
irq_move_irq(irqd);
|
2014-10-27 16:12:00 +08:00
|
|
|
ack_APIC_irq();
|
|
|
|
}
|
|
|
|
|
2015-04-13 14:11:24 +08:00
|
|
|
static struct irq_chip lapic_controller = {
|
2017-06-20 07:37:01 +08:00
|
|
|
.name = "APIC",
|
2015-04-13 14:11:24 +08:00
|
|
|
.irq_ack = apic_ack_edge,
|
2015-04-14 10:30:01 +08:00
|
|
|
.irq_set_affinity = apic_set_affinity,
|
2015-04-13 14:11:24 +08:00
|
|
|
.irq_retrigger = apic_retrigger_irq,
|
|
|
|
};
|
|
|
|
|
2014-10-27 16:12:00 +08:00
|
|
|
#ifdef CONFIG_SMP
|
2015-04-14 10:30:02 +08:00
|
|
|
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
static void free_moved_vector(struct apic_chip_data *apicd)
|
|
|
|
{
|
2017-09-14 05:29:45 +08:00
|
|
|
unsigned int vector = apicd->prev_vector;
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
unsigned int cpu = apicd->prev_cpu;
|
2017-09-14 05:29:50 +08:00
|
|
|
bool managed = apicd->is_managed;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This should never happen. Managed interrupts are not
|
|
|
|
* migrated except on CPU down, which does not involve the
|
|
|
|
* cleanup vector. But try to keep the accounting correct
|
|
|
|
* nevertheless.
|
|
|
|
*/
|
|
|
|
WARN_ON_ONCE(managed);
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
|
2017-10-16 22:16:19 +08:00
|
|
|
trace_vector_free_moved(apicd->irq, cpu, vector, managed);
|
2017-09-14 05:29:50 +08:00
|
|
|
irq_matrix_free(vector_matrix, cpu, vector, managed);
|
2017-10-16 22:16:19 +08:00
|
|
|
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNUSED;
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
hlist_del_init(&apicd->clist);
|
2017-09-14 05:29:45 +08:00
|
|
|
apicd->prev_vector = 0;
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
apicd->move_in_progress = 0;
|
|
|
|
}
|
|
|
|
|
2017-01-04 19:20:33 +08:00
|
|
|
asmlinkage __visible void __irq_entry smp_irq_move_cleanup_interrupt(void)
|
2014-10-27 16:12:00 +08:00
|
|
|
{
|
2017-09-14 05:29:32 +08:00
|
|
|
struct hlist_head *clhead = this_cpu_ptr(&cleanup_list);
|
|
|
|
struct apic_chip_data *apicd;
|
|
|
|
struct hlist_node *tmp;
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2015-05-15 21:48:25 +08:00
|
|
|
entering_ack_irq();
|
2015-08-03 04:38:23 +08:00
|
|
|
/* Prevent vectors vanishing under us */
|
|
|
|
raw_spin_lock(&vector_lock);
|
|
|
|
|
2017-09-14 05:29:32 +08:00
|
|
|
hlist_for_each_entry_safe(apicd, tmp, clhead, clist) {
|
2017-09-14 05:29:45 +08:00
|
|
|
unsigned int irr, vector = apicd->prev_vector;
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
/*
|
2017-09-14 05:29:32 +08:00
|
|
|
* Paranoia: Check if the vector that needs to be cleaned
|
|
|
|
* up is registered at the APICs IRR. If so, then this is
|
|
|
|
* not the best time to clean it up. Clean it up in the
|
2014-10-27 16:12:00 +08:00
|
|
|
* next attempt by sending another IRQ_MOVE_CLEANUP_VECTOR
|
2017-09-14 05:29:32 +08:00
|
|
|
* to this CPU. IRQ_MOVE_CLEANUP_VECTOR is the lowest
|
|
|
|
* priority external vector, so on return from this
|
|
|
|
* interrupt the device interrupt will happen first.
|
2014-10-27 16:12:00 +08:00
|
|
|
*/
|
2017-09-14 05:29:32 +08:00
|
|
|
irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
|
|
|
|
if (irr & (1U << (vector % 32))) {
|
2014-10-27 16:12:00 +08:00
|
|
|
apic->send_IPI_self(IRQ_MOVE_CLEANUP_VECTOR);
|
2017-09-14 05:29:32 +08:00
|
|
|
continue;
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
free_moved_vector(apicd);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
2015-08-03 04:38:23 +08:00
|
|
|
raw_spin_unlock(&vector_lock);
|
2015-05-15 21:48:25 +08:00
|
|
|
exiting_irq();
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
2017-09-14 05:29:32 +08:00
|
|
|
static void __send_cleanup_vector(struct apic_chip_data *apicd)
|
|
|
|
{
|
|
|
|
unsigned int cpu;
|
|
|
|
|
|
|
|
raw_spin_lock(&vector_lock);
|
|
|
|
apicd->move_in_progress = 0;
|
|
|
|
cpu = apicd->prev_cpu;
|
|
|
|
if (cpu_online(cpu)) {
|
|
|
|
hlist_add_head(&apicd->clist, per_cpu_ptr(&cleanup_list, cpu));
|
|
|
|
apic->send_IPI(cpu, IRQ_MOVE_CLEANUP_VECTOR);
|
|
|
|
} else {
|
2017-09-14 05:29:45 +08:00
|
|
|
apicd->prev_vector = 0;
|
2017-09-14 05:29:32 +08:00
|
|
|
}
|
|
|
|
raw_spin_unlock(&vector_lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
void send_cleanup_vector(struct irq_cfg *cfg)
|
|
|
|
{
|
|
|
|
struct apic_chip_data *apicd;
|
|
|
|
|
2017-09-14 05:29:45 +08:00
|
|
|
apicd = container_of(cfg, struct apic_chip_data, hw_irq_cfg);
|
2017-09-14 05:29:32 +08:00
|
|
|
if (apicd->move_in_progress)
|
|
|
|
__send_cleanup_vector(apicd);
|
|
|
|
}
|
|
|
|
|
2014-10-27 16:12:00 +08:00
|
|
|
static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
|
|
|
|
{
|
2017-09-14 05:29:30 +08:00
|
|
|
struct apic_chip_data *apicd;
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2017-09-14 05:29:45 +08:00
|
|
|
apicd = container_of(cfg, struct apic_chip_data, hw_irq_cfg);
|
2017-09-14 05:29:30 +08:00
|
|
|
if (likely(!apicd->move_in_progress))
|
2014-10-27 16:12:00 +08:00
|
|
|
return;
|
|
|
|
|
2017-09-14 05:29:45 +08:00
|
|
|
if (vector == apicd->vector && apicd->cpu == smp_processor_id())
|
2017-09-14 05:29:30 +08:00
|
|
|
__send_cleanup_vector(apicd);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void irq_complete_move(struct irq_cfg *cfg)
|
|
|
|
{
|
|
|
|
__irq_complete_move(cfg, ~get_irq_regs()->orig_ax);
|
|
|
|
}
|
|
|
|
|
2016-01-01 00:30:53 +08:00
|
|
|
/*
|
x86/irq: Cure live lock in fixup_irqs()
Harry reported, that he's able to trigger a system freeze with cpu hot
unplug. The freeze turned out to be a live lock caused by recent changes in
irq_force_complete_move().
When fixup_irqs() and from there irq_force_complete_move() is called on the
dying cpu, then all other cpus are in stop machine an wait for the dying cpu
to complete the teardown. If there is a move of an interrupt pending then
irq_force_complete_move() sends the cleanup IPI to the cpus in the old_domain
mask and waits for them to clear the mask. That's obviously impossible as
those cpus are firmly stuck in stop machine with interrupts disabled.
I should have known that, but I completely overlooked it being concentrated on
the locking issues around the vectors. And the existance of the call to
__irq_complete_move() in the code, which actually sends the cleanup IPI made
it reasonable to wait for that cleanup to complete. That call was bogus even
before the recent changes as it was just a pointless distraction.
We have to look at two cases:
1) The move_in_progress flag of the interrupt is set
This means the ioapic has been updated with the new vector, but it has not
fired yet. In theory there is a race:
set_ioapic(new_vector) <-- Interrupt is raised before update is effective,
i.e. it's raised on the old vector.
So if the target cpu cannot handle that interrupt before the old vector is
cleaned up, we get a spurious interrupt and in the worst case the ioapic
irq line becomes stale, but my experiments so far have only resulted in
spurious interrupts.
But in case of cpu hotplug this should be a non issue because if the
affinity update happens right before all cpus rendevouz in stop machine,
there is no way that the interrupt can be blocked on the target cpu because
all cpus loops first with interrupts enabled in stop machine, so the old
vector is not yet cleaned up when the interrupt fires.
So the only way to run into this issue is if the delivery of the interrupt
on the apic/system bus would be delayed beyond the point where the target
cpu disables interrupts in stop machine. I doubt that it can happen, but at
least there is a theroretical chance. Virtualization might be able to
expose this, but AFAICT the IOAPIC emulation is not as stupid as the real
hardware.
I've spent quite some time over the weekend to enforce that situation,
though I was not able to trigger the delayed case.
2) The move_in_progress flag is not set and the old_domain cpu mask is not
empty.
That means, that an interrupt was delivered after the change and the
cleanup IPI has been sent to the cpus in old_domain, but not all CPUs have
responded to it yet.
In both cases we can assume that the next interrupt will arrive on the new
vector, so we can cleanup the old vectors on the cpus in the old_domain cpu
mask.
Fixes: 98229aa36caa "x86/irq: Plug vector cleanup race"
Reported-by: Harry Junior <harryjr@outlook.fr>
Tested-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Joe Lawrence <joe.lawrence@stratus.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Ben Hutchings <ben@decadent.org.uk>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1603140931430.3657@nanos
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-03-14 16:40:46 +08:00
|
|
|
* Called from fixup_irqs() with @desc->lock held and interrupts disabled.
|
2016-01-01 00:30:53 +08:00
|
|
|
*/
|
|
|
|
void irq_force_complete_move(struct irq_desc *desc)
|
2014-10-27 16:12:00 +08:00
|
|
|
{
|
2017-09-14 05:29:30 +08:00
|
|
|
struct apic_chip_data *apicd;
|
2017-09-14 05:29:32 +08:00
|
|
|
struct irq_data *irqd;
|
|
|
|
unsigned int vector;
|
2016-01-01 00:30:52 +08:00
|
|
|
|
2016-10-03 18:17:08 +08:00
|
|
|
/*
|
|
|
|
* The function is called for all descriptors regardless of which
|
|
|
|
* irqdomain they belong to. For example if an IRQ is provided by
|
|
|
|
* an irq_chip as part of a GPIO driver, the chip data for that
|
|
|
|
* descriptor is specific to the irq_chip in question.
|
|
|
|
*
|
|
|
|
* Check first that the chip_data is what we expect
|
|
|
|
* (apic_chip_data) before touching it any further.
|
|
|
|
*/
|
2017-09-14 05:29:30 +08:00
|
|
|
irqd = irq_domain_get_irq_data(x86_vector_domain,
|
2017-09-14 05:29:32 +08:00
|
|
|
irq_desc_get_irq(desc));
|
2017-09-14 05:29:30 +08:00
|
|
|
if (!irqd)
|
2016-10-03 18:17:08 +08:00
|
|
|
return;
|
|
|
|
|
2017-09-14 05:29:32 +08:00
|
|
|
raw_spin_lock(&vector_lock);
|
2017-09-14 05:29:30 +08:00
|
|
|
apicd = apic_chip_data(irqd);
|
2017-09-14 05:29:32 +08:00
|
|
|
if (!apicd)
|
|
|
|
goto unlock;
|
2016-10-03 18:17:08 +08:00
|
|
|
|
2017-09-14 05:29:32 +08:00
|
|
|
/*
|
2017-09-14 05:29:45 +08:00
|
|
|
* If prev_vector is empty, no action required.
|
2017-09-14 05:29:32 +08:00
|
|
|
*/
|
2017-09-14 05:29:45 +08:00
|
|
|
vector = apicd->prev_vector;
|
2017-09-14 05:29:32 +08:00
|
|
|
if (!vector)
|
|
|
|
goto unlock;
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2016-01-01 00:30:52 +08:00
|
|
|
/*
|
2017-09-14 05:29:32 +08:00
|
|
|
* This is tricky. If the cleanup of the old vector has not been
|
2016-01-01 00:30:54 +08:00
|
|
|
* done yet, then the following setaffinity call will fail with
|
|
|
|
* -EBUSY. This can leave the interrupt in a stale state.
|
|
|
|
*
|
x86/irq: Cure live lock in fixup_irqs()
Harry reported, that he's able to trigger a system freeze with cpu hot
unplug. The freeze turned out to be a live lock caused by recent changes in
irq_force_complete_move().
When fixup_irqs() and from there irq_force_complete_move() is called on the
dying cpu, then all other cpus are in stop machine an wait for the dying cpu
to complete the teardown. If there is a move of an interrupt pending then
irq_force_complete_move() sends the cleanup IPI to the cpus in the old_domain
mask and waits for them to clear the mask. That's obviously impossible as
those cpus are firmly stuck in stop machine with interrupts disabled.
I should have known that, but I completely overlooked it being concentrated on
the locking issues around the vectors. And the existance of the call to
__irq_complete_move() in the code, which actually sends the cleanup IPI made
it reasonable to wait for that cleanup to complete. That call was bogus even
before the recent changes as it was just a pointless distraction.
We have to look at two cases:
1) The move_in_progress flag of the interrupt is set
This means the ioapic has been updated with the new vector, but it has not
fired yet. In theory there is a race:
set_ioapic(new_vector) <-- Interrupt is raised before update is effective,
i.e. it's raised on the old vector.
So if the target cpu cannot handle that interrupt before the old vector is
cleaned up, we get a spurious interrupt and in the worst case the ioapic
irq line becomes stale, but my experiments so far have only resulted in
spurious interrupts.
But in case of cpu hotplug this should be a non issue because if the
affinity update happens right before all cpus rendevouz in stop machine,
there is no way that the interrupt can be blocked on the target cpu because
all cpus loops first with interrupts enabled in stop machine, so the old
vector is not yet cleaned up when the interrupt fires.
So the only way to run into this issue is if the delivery of the interrupt
on the apic/system bus would be delayed beyond the point where the target
cpu disables interrupts in stop machine. I doubt that it can happen, but at
least there is a theroretical chance. Virtualization might be able to
expose this, but AFAICT the IOAPIC emulation is not as stupid as the real
hardware.
I've spent quite some time over the weekend to enforce that situation,
though I was not able to trigger the delayed case.
2) The move_in_progress flag is not set and the old_domain cpu mask is not
empty.
That means, that an interrupt was delivered after the change and the
cleanup IPI has been sent to the cpus in old_domain, but not all CPUs have
responded to it yet.
In both cases we can assume that the next interrupt will arrive on the new
vector, so we can cleanup the old vectors on the cpus in the old_domain cpu
mask.
Fixes: 98229aa36caa "x86/irq: Plug vector cleanup race"
Reported-by: Harry Junior <harryjr@outlook.fr>
Tested-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Joe Lawrence <joe.lawrence@stratus.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Ben Hutchings <ben@decadent.org.uk>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1603140931430.3657@nanos
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-03-14 16:40:46 +08:00
|
|
|
* All CPUs are stuck in stop machine with interrupts disabled so
|
|
|
|
* calling __irq_complete_move() would be completely pointless.
|
2017-09-14 05:29:32 +08:00
|
|
|
*
|
x86/irq: Cure live lock in fixup_irqs()
Harry reported, that he's able to trigger a system freeze with cpu hot
unplug. The freeze turned out to be a live lock caused by recent changes in
irq_force_complete_move().
When fixup_irqs() and from there irq_force_complete_move() is called on the
dying cpu, then all other cpus are in stop machine an wait for the dying cpu
to complete the teardown. If there is a move of an interrupt pending then
irq_force_complete_move() sends the cleanup IPI to the cpus in the old_domain
mask and waits for them to clear the mask. That's obviously impossible as
those cpus are firmly stuck in stop machine with interrupts disabled.
I should have known that, but I completely overlooked it being concentrated on
the locking issues around the vectors. And the existance of the call to
__irq_complete_move() in the code, which actually sends the cleanup IPI made
it reasonable to wait for that cleanup to complete. That call was bogus even
before the recent changes as it was just a pointless distraction.
We have to look at two cases:
1) The move_in_progress flag of the interrupt is set
This means the ioapic has been updated with the new vector, but it has not
fired yet. In theory there is a race:
set_ioapic(new_vector) <-- Interrupt is raised before update is effective,
i.e. it's raised on the old vector.
So if the target cpu cannot handle that interrupt before the old vector is
cleaned up, we get a spurious interrupt and in the worst case the ioapic
irq line becomes stale, but my experiments so far have only resulted in
spurious interrupts.
But in case of cpu hotplug this should be a non issue because if the
affinity update happens right before all cpus rendevouz in stop machine,
there is no way that the interrupt can be blocked on the target cpu because
all cpus loops first with interrupts enabled in stop machine, so the old
vector is not yet cleaned up when the interrupt fires.
So the only way to run into this issue is if the delivery of the interrupt
on the apic/system bus would be delayed beyond the point where the target
cpu disables interrupts in stop machine. I doubt that it can happen, but at
least there is a theroretical chance. Virtualization might be able to
expose this, but AFAICT the IOAPIC emulation is not as stupid as the real
hardware.
I've spent quite some time over the weekend to enforce that situation,
though I was not able to trigger the delayed case.
2) The move_in_progress flag is not set and the old_domain cpu mask is not
empty.
That means, that an interrupt was delivered after the change and the
cleanup IPI has been sent to the cpus in old_domain, but not all CPUs have
responded to it yet.
In both cases we can assume that the next interrupt will arrive on the new
vector, so we can cleanup the old vectors on the cpus in the old_domain cpu
mask.
Fixes: 98229aa36caa "x86/irq: Plug vector cleanup race"
Reported-by: Harry Junior <harryjr@outlook.fr>
Tested-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Joe Lawrence <joe.lawrence@stratus.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Ben Hutchings <ben@decadent.org.uk>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1603140931430.3657@nanos
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-03-14 16:40:46 +08:00
|
|
|
* 1) The interrupt is in move_in_progress state. That means that we
|
|
|
|
* have not seen an interrupt since the io_apic was reprogrammed to
|
|
|
|
* the new vector.
|
|
|
|
*
|
|
|
|
* 2) The interrupt has fired on the new vector, but the cleanup IPIs
|
|
|
|
* have not been processed yet.
|
|
|
|
*/
|
2017-09-14 05:29:30 +08:00
|
|
|
if (apicd->move_in_progress) {
|
2016-01-01 00:30:54 +08:00
|
|
|
/*
|
x86/irq: Cure live lock in fixup_irqs()
Harry reported, that he's able to trigger a system freeze with cpu hot
unplug. The freeze turned out to be a live lock caused by recent changes in
irq_force_complete_move().
When fixup_irqs() and from there irq_force_complete_move() is called on the
dying cpu, then all other cpus are in stop machine an wait for the dying cpu
to complete the teardown. If there is a move of an interrupt pending then
irq_force_complete_move() sends the cleanup IPI to the cpus in the old_domain
mask and waits for them to clear the mask. That's obviously impossible as
those cpus are firmly stuck in stop machine with interrupts disabled.
I should have known that, but I completely overlooked it being concentrated on
the locking issues around the vectors. And the existance of the call to
__irq_complete_move() in the code, which actually sends the cleanup IPI made
it reasonable to wait for that cleanup to complete. That call was bogus even
before the recent changes as it was just a pointless distraction.
We have to look at two cases:
1) The move_in_progress flag of the interrupt is set
This means the ioapic has been updated with the new vector, but it has not
fired yet. In theory there is a race:
set_ioapic(new_vector) <-- Interrupt is raised before update is effective,
i.e. it's raised on the old vector.
So if the target cpu cannot handle that interrupt before the old vector is
cleaned up, we get a spurious interrupt and in the worst case the ioapic
irq line becomes stale, but my experiments so far have only resulted in
spurious interrupts.
But in case of cpu hotplug this should be a non issue because if the
affinity update happens right before all cpus rendevouz in stop machine,
there is no way that the interrupt can be blocked on the target cpu because
all cpus loops first with interrupts enabled in stop machine, so the old
vector is not yet cleaned up when the interrupt fires.
So the only way to run into this issue is if the delivery of the interrupt
on the apic/system bus would be delayed beyond the point where the target
cpu disables interrupts in stop machine. I doubt that it can happen, but at
least there is a theroretical chance. Virtualization might be able to
expose this, but AFAICT the IOAPIC emulation is not as stupid as the real
hardware.
I've spent quite some time over the weekend to enforce that situation,
though I was not able to trigger the delayed case.
2) The move_in_progress flag is not set and the old_domain cpu mask is not
empty.
That means, that an interrupt was delivered after the change and the
cleanup IPI has been sent to the cpus in old_domain, but not all CPUs have
responded to it yet.
In both cases we can assume that the next interrupt will arrive on the new
vector, so we can cleanup the old vectors on the cpus in the old_domain cpu
mask.
Fixes: 98229aa36caa "x86/irq: Plug vector cleanup race"
Reported-by: Harry Junior <harryjr@outlook.fr>
Tested-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Joe Lawrence <joe.lawrence@stratus.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Ben Hutchings <ben@decadent.org.uk>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1603140931430.3657@nanos
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-03-14 16:40:46 +08:00
|
|
|
* In theory there is a race:
|
|
|
|
*
|
|
|
|
* set_ioapic(new_vector) <-- Interrupt is raised before update
|
|
|
|
* is effective, i.e. it's raised on
|
|
|
|
* the old vector.
|
|
|
|
*
|
|
|
|
* So if the target cpu cannot handle that interrupt before
|
|
|
|
* the old vector is cleaned up, we get a spurious interrupt
|
|
|
|
* and in the worst case the ioapic irq line becomes stale.
|
|
|
|
*
|
|
|
|
* But in case of cpu hotplug this should be a non issue
|
|
|
|
* because if the affinity update happens right before all
|
|
|
|
* cpus rendevouz in stop machine, there is no way that the
|
|
|
|
* interrupt can be blocked on the target cpu because all cpus
|
|
|
|
* loops first with interrupts enabled in stop machine, so the
|
|
|
|
* old vector is not yet cleaned up when the interrupt fires.
|
|
|
|
*
|
|
|
|
* So the only way to run into this issue is if the delivery
|
|
|
|
* of the interrupt on the apic/system bus would be delayed
|
|
|
|
* beyond the point where the target cpu disables interrupts
|
|
|
|
* in stop machine. I doubt that it can happen, but at least
|
|
|
|
* there is a theroretical chance. Virtualization might be
|
|
|
|
* able to expose this, but AFAICT the IOAPIC emulation is not
|
|
|
|
* as stupid as the real hardware.
|
|
|
|
*
|
|
|
|
* Anyway, there is nothing we can do about that at this point
|
|
|
|
* w/o refactoring the whole fixup_irq() business completely.
|
|
|
|
* We print at least the irq number and the old vector number,
|
|
|
|
* so we have the necessary information when a problem in that
|
|
|
|
* area arises.
|
2016-01-01 00:30:54 +08:00
|
|
|
*/
|
x86/irq: Cure live lock in fixup_irqs()
Harry reported, that he's able to trigger a system freeze with cpu hot
unplug. The freeze turned out to be a live lock caused by recent changes in
irq_force_complete_move().
When fixup_irqs() and from there irq_force_complete_move() is called on the
dying cpu, then all other cpus are in stop machine an wait for the dying cpu
to complete the teardown. If there is a move of an interrupt pending then
irq_force_complete_move() sends the cleanup IPI to the cpus in the old_domain
mask and waits for them to clear the mask. That's obviously impossible as
those cpus are firmly stuck in stop machine with interrupts disabled.
I should have known that, but I completely overlooked it being concentrated on
the locking issues around the vectors. And the existance of the call to
__irq_complete_move() in the code, which actually sends the cleanup IPI made
it reasonable to wait for that cleanup to complete. That call was bogus even
before the recent changes as it was just a pointless distraction.
We have to look at two cases:
1) The move_in_progress flag of the interrupt is set
This means the ioapic has been updated with the new vector, but it has not
fired yet. In theory there is a race:
set_ioapic(new_vector) <-- Interrupt is raised before update is effective,
i.e. it's raised on the old vector.
So if the target cpu cannot handle that interrupt before the old vector is
cleaned up, we get a spurious interrupt and in the worst case the ioapic
irq line becomes stale, but my experiments so far have only resulted in
spurious interrupts.
But in case of cpu hotplug this should be a non issue because if the
affinity update happens right before all cpus rendevouz in stop machine,
there is no way that the interrupt can be blocked on the target cpu because
all cpus loops first with interrupts enabled in stop machine, so the old
vector is not yet cleaned up when the interrupt fires.
So the only way to run into this issue is if the delivery of the interrupt
on the apic/system bus would be delayed beyond the point where the target
cpu disables interrupts in stop machine. I doubt that it can happen, but at
least there is a theroretical chance. Virtualization might be able to
expose this, but AFAICT the IOAPIC emulation is not as stupid as the real
hardware.
I've spent quite some time over the weekend to enforce that situation,
though I was not able to trigger the delayed case.
2) The move_in_progress flag is not set and the old_domain cpu mask is not
empty.
That means, that an interrupt was delivered after the change and the
cleanup IPI has been sent to the cpus in old_domain, but not all CPUs have
responded to it yet.
In both cases we can assume that the next interrupt will arrive on the new
vector, so we can cleanup the old vectors on the cpus in the old_domain cpu
mask.
Fixes: 98229aa36caa "x86/irq: Plug vector cleanup race"
Reported-by: Harry Junior <harryjr@outlook.fr>
Tested-by: Tony Luck <tony.luck@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Joe Lawrence <joe.lawrence@stratus.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Ben Hutchings <ben@decadent.org.uk>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1603140931430.3657@nanos
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
2016-03-14 16:40:46 +08:00
|
|
|
pr_warn("IRQ fixup: irq %d move in progress, old vector %d\n",
|
2017-09-14 05:29:32 +08:00
|
|
|
irqd->irq, vector);
|
2016-01-01 00:30:54 +08:00
|
|
|
}
|
x86/vector: Use matrix allocator for vector assignment
Replace the magic vector allocation code by a simple bitmap matrix
allocator. This avoids loops and hoops over CPUs and vector arrays, so in
case of densly used vector spaces it's way faster.
This also gets rid of the magic 'spread the vectors accross priority
levels' heuristics in the current allocator:
The comment in __asign_irq_vector says:
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
* As the interrupt level is determined by taking the
* vector number and shifting that right by 4, we
* want to spread these out a bit so that they don't
* all fall in the same interrupt level.
After doing some palaeontological research the following was found the
following in the PPro Developer Manual Volume 3:
"7.4.2. Valid Interrupts
The local and I/O APICs support 240 distinct vectors in the range of 16
to 255. Interrupt priority is implied by its vector, according to the
following relationship: priority = vector / 16
One is the lowest priority and 15 is the highest. Vectors 16 through
31 are reserved for exclusive use by the processor. The remaining
vectors are for general use. The processor's local APIC includes an
in-service entry and a holding entry for each priority level. To avoid
losing inter- rupts, software should allocate no more than 2 interrupt
vectors per priority."
The current SDM tells nothing about that, instead it states:
"If more than one interrupt is generated with the same vector number,
the local APIC can set the bit for the vector both in the IRR and the
ISR. This means that for the Pentium 4 and Intel Xeon processors, the
IRR and ISR can queue two interrupts for each interrupt vector: one
in the IRR and one in the ISR. Any additional interrupts issued for
the same interrupt vector are collapsed into the single bit in the
IRR.
For the P6 family and Pentium processors, the IRR and ISR registers
can queue no more than two interrupts per interrupt vector and will
reject other interrupts that are received within the same vector."
Which means, that on P6/Pentium the APIC will reject a new message and
tell the sender to retry, which increases the load on the APIC bus and
nothing more.
There is no affirmative answer from Intel on that, but it's a sane approach
to remove that for the following reasons:
1) No other (relevant Open Source) operating systems bothers to
implement this or mentiones this at all.
2) The current allocator has no enforcement for this and especially the
legacy interrupts, which are the main source of interrupts on these
P6 and older systmes, are allocated linearly in the same priority
level and just work.
3) The current machines have no problem with that at all as verified
with some experiments.
4) AMD at least confirmed that such an issue is unknown.
5) P6 and older are dinosaurs almost 20 years EOL, so there is really
no reason to worry about that too much.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Yu Chen <yu.c.chen@intel.com>
Acked-by: Juergen Gross <jgross@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Alok Kataria <akataria@vmware.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Rui Zhang <rui.zhang@intel.com>
Cc: "K. Y. Srinivasan" <kys@microsoft.com>
Cc: Arjan van de Ven <arjan@linux.intel.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/20170913213155.443678104@linutronix.de
2017-09-14 05:29:42 +08:00
|
|
|
free_moved_vector(apicd);
|
2017-09-14 05:29:32 +08:00
|
|
|
unlock:
|
2016-01-01 00:30:52 +08:00
|
|
|
raw_spin_unlock(&vector_lock);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
2017-09-14 05:29:53 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_HOTPLUG_CPU
|
|
|
|
/*
|
|
|
|
* Note, this is not accurate accounting, but at least good enough to
|
|
|
|
* prevent that the actual interrupt move will run out of vectors.
|
|
|
|
*/
|
|
|
|
int lapic_can_unplug_cpu(void)
|
|
|
|
{
|
|
|
|
unsigned int rsvd, avl, tomove, cpu = smp_processor_id();
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
raw_spin_lock(&vector_lock);
|
|
|
|
tomove = irq_matrix_allocated(vector_matrix);
|
|
|
|
avl = irq_matrix_available(vector_matrix, true);
|
|
|
|
if (avl < tomove) {
|
|
|
|
pr_warn("CPU %u has %u vectors, %u available. Cannot disable CPU\n",
|
|
|
|
cpu, tomove, avl);
|
|
|
|
ret = -ENOSPC;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
rsvd = irq_matrix_reserved(vector_matrix);
|
|
|
|
if (avl < rsvd) {
|
|
|
|
pr_warn("Reserved vectors %u > available %u. IRQ request may fail\n",
|
|
|
|
rsvd, avl);
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
raw_spin_unlock(&vector_lock);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif /* HOTPLUG_CPU */
|
|
|
|
#endif /* SMP */
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
static void __init print_APIC_field(int base)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
printk(KERN_DEBUG);
|
|
|
|
|
|
|
|
for (i = 0; i < 8; i++)
|
|
|
|
pr_cont("%08x", apic_read(base + i*0x10));
|
|
|
|
|
|
|
|
pr_cont("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init print_local_APIC(void *dummy)
|
|
|
|
{
|
|
|
|
unsigned int i, v, ver, maxlvt;
|
|
|
|
u64 icr;
|
|
|
|
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("printing local APIC contents on CPU#%d/%d:\n",
|
|
|
|
smp_processor_id(), hard_smp_processor_id());
|
2014-10-27 16:12:00 +08:00
|
|
|
v = apic_read(APIC_ID);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_info("... APIC ID: %08x (%01x)\n", v, read_apic_id());
|
2014-10-27 16:12:00 +08:00
|
|
|
v = apic_read(APIC_LVR);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_info("... APIC VERSION: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
ver = GET_APIC_VERSION(v);
|
|
|
|
maxlvt = lapic_get_maxlvt();
|
|
|
|
|
|
|
|
v = apic_read(APIC_TASKPRI);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
/* !82489DX */
|
|
|
|
if (APIC_INTEGRATED(ver)) {
|
|
|
|
if (!APIC_XAPIC(ver)) {
|
|
|
|
v = apic_read(APIC_ARBPRI);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC ARBPRI: %08x (%02x)\n",
|
|
|
|
v, v & APIC_ARBPRI_MASK);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
v = apic_read(APIC_PROCPRI);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC PROCPRI: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remote read supported only in the 82489DX and local APIC for
|
|
|
|
* Pentium processors.
|
|
|
|
*/
|
|
|
|
if (!APIC_INTEGRATED(ver) || maxlvt == 3) {
|
|
|
|
v = apic_read(APIC_RRR);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC RRR: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
v = apic_read(APIC_LDR);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC LDR: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
if (!x2apic_enabled()) {
|
|
|
|
v = apic_read(APIC_DFR);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC DFR: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
v = apic_read(APIC_SPIV);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC SPIV: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC ISR field:\n");
|
2014-10-27 16:12:00 +08:00
|
|
|
print_APIC_field(APIC_ISR);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC TMR field:\n");
|
2014-10-27 16:12:00 +08:00
|
|
|
print_APIC_field(APIC_TMR);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC IRR field:\n");
|
2014-10-27 16:12:00 +08:00
|
|
|
print_APIC_field(APIC_IRR);
|
|
|
|
|
|
|
|
/* !82489DX */
|
|
|
|
if (APIC_INTEGRATED(ver)) {
|
|
|
|
/* Due to the Pentium erratum 3AP. */
|
|
|
|
if (maxlvt > 3)
|
|
|
|
apic_write(APIC_ESR, 0);
|
|
|
|
|
|
|
|
v = apic_read(APIC_ESR);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC ESR: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
icr = apic_icr_read();
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC ICR: %08x\n", (u32)icr);
|
|
|
|
pr_debug("... APIC ICR2: %08x\n", (u32)(icr >> 32));
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
v = apic_read(APIC_LVTT);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC LVTT: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
if (maxlvt > 3) {
|
|
|
|
/* PC is LVT#4. */
|
|
|
|
v = apic_read(APIC_LVTPC);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC LVTPC: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
v = apic_read(APIC_LVT0);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC LVT0: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
v = apic_read(APIC_LVT1);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC LVT1: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
if (maxlvt > 2) {
|
|
|
|
/* ERR is LVT#3. */
|
|
|
|
v = apic_read(APIC_LVTERR);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC LVTERR: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
v = apic_read(APIC_TMICT);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC TMICT: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
v = apic_read(APIC_TMCCT);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC TMCCT: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
v = apic_read(APIC_TDCR);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC TDCR: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
if (boot_cpu_has(X86_FEATURE_EXTAPIC)) {
|
|
|
|
v = apic_read(APIC_EFEAT);
|
|
|
|
maxlvt = (v >> 16) & 0xff;
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC EFEAT: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
v = apic_read(APIC_ECTRL);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC ECTRL: %08x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
for (i = 0; i < maxlvt; i++) {
|
|
|
|
v = apic_read(APIC_EILVTn(i));
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... APIC EILVT%d: %08x\n", i, v);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pr_cont("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init print_local_APICs(int maxcpu)
|
|
|
|
{
|
|
|
|
int cpu;
|
|
|
|
|
|
|
|
if (!maxcpu)
|
|
|
|
return;
|
|
|
|
|
|
|
|
preempt_disable();
|
|
|
|
for_each_online_cpu(cpu) {
|
|
|
|
if (cpu >= maxcpu)
|
|
|
|
break;
|
|
|
|
smp_call_function_single(cpu, print_local_APIC, NULL, 1);
|
|
|
|
}
|
|
|
|
preempt_enable();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __init print_PIC(void)
|
|
|
|
{
|
|
|
|
unsigned int v;
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
if (!nr_legacy_irqs())
|
|
|
|
return;
|
|
|
|
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("\nprinting PIC contents\n");
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
raw_spin_lock_irqsave(&i8259A_lock, flags);
|
|
|
|
|
|
|
|
v = inb(0xa1) << 8 | inb(0x21);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... PIC IMR: %04x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
v = inb(0xa0) << 8 | inb(0x20);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... PIC IRR: %04x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
outb(0x0b, 0xa0);
|
|
|
|
outb(0x0b, 0x20);
|
|
|
|
v = inb(0xa0) << 8 | inb(0x20);
|
|
|
|
outb(0x0a, 0xa0);
|
|
|
|
outb(0x0a, 0x20);
|
|
|
|
|
|
|
|
raw_spin_unlock_irqrestore(&i8259A_lock, flags);
|
|
|
|
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... PIC ISR: %04x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
|
|
|
|
v = inb(0x4d1) << 8 | inb(0x4d0);
|
2014-10-27 16:12:01 +08:00
|
|
|
pr_debug("... PIC ELCR: %04x\n", v);
|
2014-10-27 16:12:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int show_lapic __initdata = 1;
|
|
|
|
static __init int setup_show_lapic(char *arg)
|
|
|
|
{
|
|
|
|
int num = -1;
|
|
|
|
|
|
|
|
if (strcmp(arg, "all") == 0) {
|
|
|
|
show_lapic = CONFIG_NR_CPUS;
|
|
|
|
} else {
|
|
|
|
get_option(&arg, &num);
|
|
|
|
if (num >= 0)
|
|
|
|
show_lapic = num;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
__setup("show_lapic=", setup_show_lapic);
|
|
|
|
|
|
|
|
static int __init print_ICs(void)
|
|
|
|
{
|
|
|
|
if (apic_verbosity == APIC_QUIET)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
print_PIC();
|
|
|
|
|
|
|
|
/* don't print out if apic is not there */
|
2016-04-05 04:25:00 +08:00
|
|
|
if (!boot_cpu_has(X86_FEATURE_APIC) && !apic_from_smp_config())
|
2014-10-27 16:12:00 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
print_local_APICs(show_lapic);
|
|
|
|
print_IO_APICs();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
late_initcall(print_ICs);
|