Commit 4f19b880 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 apic updates from Ingo Molnar:
 "The main changes in this cycle were:

   - introduce optimized single IPI sending methods on modern APICs
     (Linus Torvalds, Thomas Gleixner)

   - kexec/crash APIC handling fixes and enhancements (Hidehiro Kawai)

   - extend lapic vector saving/restoring to the CMCI (MCE) vector as
     well (Juergen Gross)

   - various fixes and enhancements (Jake Oshins, Len Brown)"

* 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (23 commits)
  x86/irq: Export functions to allow MSI domains in modules
  Documentation: Document kernel.panic_on_io_nmi sysctl
  x86/nmi: Save regs in crash dump on external NMI
  x86/apic: Introduce apic_extnmi command line parameter
  kexec: Fix race between panic() and crash_kexec()
  panic, x86: Allow CPUs to save registers even if looping in NMI context
  panic, x86: Fix re-entrance problem due to panic on NMI
  x86/apic: Fix the saving and restoring of lapic vectors during suspend/resume
  x86/smpboot: Re-enable init_udelay=0 by default on modern CPUs
  x86/smp: Remove single IPI wrapper
  x86/apic: Use default send single IPI wrapper
  x86/apic: Provide default send single IPI wrapper
  x86/apic: Implement single IPI for apic_noop
  x86/apic: Wire up single IPI for apic_numachip
  x86/apic: Wire up single IPI for x2apic_uv
  x86/apic: Implement single IPI for x2apic_phys
  x86/apic: Wire up single IPI for bigsmp_apic
  x86/apic: Remove pointless indirections from bigsmp_apic
  x86/apic: Wire up single IPI for apic_physflat
  x86/apic: Remove pointless indirections from apic_physflat
  ...
parents af345201 c8f3e518
...@@ -472,6 +472,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -472,6 +472,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Change the amount of debugging information output Change the amount of debugging information output
when initialising the APIC and IO-APIC components. when initialising the APIC and IO-APIC components.
apic_extnmi= [APIC,X86] External NMI delivery setting
Format: { bsp (default) | all | none }
bsp: External NMI is delivered only to CPU 0
all: External NMIs are broadcast to all CPUs as a
backup of CPU 0
none: External NMI is masked for all CPUs. This is
useful so that a dump capture kernel won't be
shot down by NMI
autoconf= [IPV6] autoconf= [IPV6]
See Documentation/networking/ipv6.txt. See Documentation/networking/ipv6.txt.
......
...@@ -551,6 +551,21 @@ the recommended setting is 60. ...@@ -551,6 +551,21 @@ the recommended setting is 60.
============================================================== ==============================================================
panic_on_io_nmi:
Controls the kernel's behavior when a CPU receives an NMI caused by
an IO error.
0: try to continue operation (default)
1: panic immediately. The IO error triggered an NMI. This indicates a
serious system condition which could result in IO data corruption.
Rather than continuing, panicking might be a better choice. Some
servers issue this sort of NMI when the dump button is pushed,
and you can use this option to take a crash dump.
==============================================================
panic_on_oops: panic_on_oops:
Controls the kernel's behaviour when an oops or BUG is encountered. Controls the kernel's behaviour when an oops or BUG is encountered.
......
...@@ -23,6 +23,11 @@ ...@@ -23,6 +23,11 @@
#define APIC_VERBOSE 1 #define APIC_VERBOSE 1
#define APIC_DEBUG 2 #define APIC_DEBUG 2
/* Macros for apic_extnmi which controls external NMI masking */
#define APIC_EXTNMI_BSP 0 /* Default */
#define APIC_EXTNMI_ALL 1
#define APIC_EXTNMI_NONE 2
/* /*
* Define the default level of output to be very little * Define the default level of output to be very little
* This can be turned up by using apic=verbose for more * This can be turned up by using apic=verbose for more
...@@ -303,6 +308,7 @@ struct apic { ...@@ -303,6 +308,7 @@ struct apic {
unsigned int *apicid); unsigned int *apicid);
/* ipi */ /* ipi */
void (*send_IPI)(int cpu, int vector);
void (*send_IPI_mask)(const struct cpumask *mask, int vector); void (*send_IPI_mask)(const struct cpumask *mask, int vector);
void (*send_IPI_mask_allbutself)(const struct cpumask *mask, void (*send_IPI_mask_allbutself)(const struct cpumask *mask,
int vector); int vector);
......
...@@ -119,6 +119,8 @@ static inline void ...@@ -119,6 +119,8 @@ static inline void
native_apic_mem_write(APIC_ICR, cfg); native_apic_mem_write(APIC_ICR, cfg);
} }
extern void default_send_IPI_single(int cpu, int vector);
extern void default_send_IPI_single_phys(int cpu, int vector);
extern void default_send_IPI_mask_sequence_phys(const struct cpumask *mask, extern void default_send_IPI_mask_sequence_phys(const struct cpumask *mask,
int vector); int vector);
extern void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask, extern void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask,
......
#ifndef _ASM_X86_MSI_H #ifndef _ASM_X86_MSI_H
#define _ASM_X86_MSI_H #define _ASM_X86_MSI_H
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
#include <asm/irqdomain.h>
typedef struct irq_alloc_info msi_alloc_info_t; typedef struct irq_alloc_info msi_alloc_info_t;
int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
msi_alloc_info_t *arg);
void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc);
#endif /* _ASM_X86_MSI_H */ #endif /* _ASM_X86_MSI_H */
...@@ -25,5 +25,6 @@ void __noreturn machine_real_restart(unsigned int type); ...@@ -25,5 +25,6 @@ void __noreturn machine_real_restart(unsigned int type);
typedef void (*nmi_shootdown_cb)(int, struct pt_regs*); typedef void (*nmi_shootdown_cb)(int, struct pt_regs*);
void nmi_shootdown_cpus(nmi_shootdown_cb callback); void nmi_shootdown_cpus(nmi_shootdown_cb callback);
void run_crash_ipi_callback(struct pt_regs *regs);
#endif /* _ASM_X86_REBOOT_H */ #endif /* _ASM_X86_REBOOT_H */
...@@ -81,6 +81,12 @@ physid_mask_t phys_cpu_present_map; ...@@ -81,6 +81,12 @@ physid_mask_t phys_cpu_present_map;
*/ */
static unsigned int disabled_cpu_apicid __read_mostly = BAD_APICID; static unsigned int disabled_cpu_apicid __read_mostly = BAD_APICID;
/*
* This variable controls which CPUs receive external NMIs. By default,
* external NMIs are delivered only to the BSP.
*/
static int apic_extnmi = APIC_EXTNMI_BSP;
/* /*
* Map cpu index to physical APIC ID * Map cpu index to physical APIC ID
*/ */
...@@ -1161,6 +1167,8 @@ void __init init_bsp_APIC(void) ...@@ -1161,6 +1167,8 @@ void __init init_bsp_APIC(void)
value = APIC_DM_NMI; value = APIC_DM_NMI;
if (!lapic_is_integrated()) /* 82489DX */ if (!lapic_is_integrated()) /* 82489DX */
value |= APIC_LVT_LEVEL_TRIGGER; value |= APIC_LVT_LEVEL_TRIGGER;
if (apic_extnmi == APIC_EXTNMI_NONE)
value |= APIC_LVT_MASKED;
apic_write(APIC_LVT1, value); apic_write(APIC_LVT1, value);
} }
...@@ -1378,9 +1386,11 @@ void setup_local_APIC(void) ...@@ -1378,9 +1386,11 @@ void setup_local_APIC(void)
apic_write(APIC_LVT0, value); apic_write(APIC_LVT0, value);
/* /*
* only the BP should see the LINT1 NMI signal, obviously. * Only the BSP sees the LINT1 NMI signal by default. This can be
* modified by apic_extnmi= boot option.
*/ */
if (!cpu) if ((!cpu && apic_extnmi != APIC_EXTNMI_NONE) ||
apic_extnmi == APIC_EXTNMI_ALL)
value = APIC_DM_NMI; value = APIC_DM_NMI;
else else
value = APIC_DM_NMI | APIC_LVT_MASKED; value = APIC_DM_NMI | APIC_LVT_MASKED;
...@@ -2270,6 +2280,7 @@ static struct { ...@@ -2270,6 +2280,7 @@ static struct {
unsigned int apic_tmict; unsigned int apic_tmict;
unsigned int apic_tdcr; unsigned int apic_tdcr;
unsigned int apic_thmr; unsigned int apic_thmr;
unsigned int apic_cmci;
} apic_pm_state; } apic_pm_state;
static int lapic_suspend(void) static int lapic_suspend(void)
...@@ -2299,6 +2310,10 @@ static int lapic_suspend(void) ...@@ -2299,6 +2310,10 @@ static int lapic_suspend(void)
if (maxlvt >= 5) if (maxlvt >= 5)
apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR); apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
#endif #endif
#ifdef CONFIG_X86_MCE_INTEL
if (maxlvt >= 6)
apic_pm_state.apic_cmci = apic_read(APIC_LVTCMCI);
#endif
local_irq_save(flags); local_irq_save(flags);
disable_local_APIC(); disable_local_APIC();
...@@ -2355,9 +2370,13 @@ static void lapic_resume(void) ...@@ -2355,9 +2370,13 @@ static void lapic_resume(void)
apic_write(APIC_SPIV, apic_pm_state.apic_spiv); apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
apic_write(APIC_LVT0, apic_pm_state.apic_lvt0); apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
apic_write(APIC_LVT1, apic_pm_state.apic_lvt1); apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
#if defined(CONFIG_X86_MCE_INTEL) #ifdef CONFIG_X86_THERMAL_VECTOR
if (maxlvt >= 5) if (maxlvt >= 5)
apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr); apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
#endif
#ifdef CONFIG_X86_MCE_INTEL
if (maxlvt >= 6)
apic_write(APIC_LVTCMCI, apic_pm_state.apic_cmci);
#endif #endif
if (maxlvt >= 4) if (maxlvt >= 4)
apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc); apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
...@@ -2548,3 +2567,23 @@ static int __init apic_set_disabled_cpu_apicid(char *arg) ...@@ -2548,3 +2567,23 @@ static int __init apic_set_disabled_cpu_apicid(char *arg)
return 0; return 0;
} }
early_param("disable_cpu_apicid", apic_set_disabled_cpu_apicid); early_param("disable_cpu_apicid", apic_set_disabled_cpu_apicid);
static int __init apic_set_extnmi(char *arg)
{
if (!arg)
return -EINVAL;
if (!strncmp("all", arg, 3))
apic_extnmi = APIC_EXTNMI_ALL;
else if (!strncmp("none", arg, 4))
apic_extnmi = APIC_EXTNMI_NONE;
else if (!strncmp("bsp", arg, 3))
apic_extnmi = APIC_EXTNMI_BSP;
else {
pr_warn("Unknown external NMI delivery mode `%s' ignored\n", arg);
return -EINVAL;
}
return 0;
}
early_param("apic_extnmi", apic_set_extnmi);
...@@ -185,6 +185,7 @@ static struct apic apic_flat = { ...@@ -185,6 +185,7 @@ static struct apic apic_flat = {
.cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and, .cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and,
.send_IPI = default_send_IPI_single,
.send_IPI_mask = flat_send_IPI_mask, .send_IPI_mask = flat_send_IPI_mask,
.send_IPI_mask_allbutself = flat_send_IPI_mask_allbutself, .send_IPI_mask_allbutself = flat_send_IPI_mask_allbutself,
.send_IPI_allbutself = flat_send_IPI_allbutself, .send_IPI_allbutself = flat_send_IPI_allbutself,
...@@ -230,17 +231,6 @@ static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) ...@@ -230,17 +231,6 @@ static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
return 0; return 0;
} }
static void physflat_send_IPI_mask(const struct cpumask *cpumask, int vector)
{
default_send_IPI_mask_sequence_phys(cpumask, vector);
}
static void physflat_send_IPI_mask_allbutself(const struct cpumask *cpumask,
int vector)
{
default_send_IPI_mask_allbutself_phys(cpumask, vector);
}
static void physflat_send_IPI_allbutself(int vector) static void physflat_send_IPI_allbutself(int vector)
{ {
default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector); default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
...@@ -248,7 +238,7 @@ static void physflat_send_IPI_allbutself(int vector) ...@@ -248,7 +238,7 @@ static void physflat_send_IPI_allbutself(int vector)
static void physflat_send_IPI_all(int vector) static void physflat_send_IPI_all(int vector)
{ {
physflat_send_IPI_mask(cpu_online_mask, vector); default_send_IPI_mask_sequence_phys(cpu_online_mask, vector);
} }
static int physflat_probe(void) static int physflat_probe(void)
...@@ -292,8 +282,9 @@ static struct apic apic_physflat = { ...@@ -292,8 +282,9 @@ static struct apic apic_physflat = {
.cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and,
.send_IPI_mask = physflat_send_IPI_mask, .send_IPI = default_send_IPI_single_phys,
.send_IPI_mask_allbutself = physflat_send_IPI_mask_allbutself, .send_IPI_mask = default_send_IPI_mask_sequence_phys,
.send_IPI_mask_allbutself = default_send_IPI_mask_allbutself_phys,
.send_IPI_allbutself = physflat_send_IPI_allbutself, .send_IPI_allbutself = physflat_send_IPI_allbutself,
.send_IPI_all = physflat_send_IPI_all, .send_IPI_all = physflat_send_IPI_all,
.send_IPI_self = apic_send_IPI_self, .send_IPI_self = apic_send_IPI_self,
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <asm/e820.h> #include <asm/e820.h>
static void noop_init_apic_ldr(void) { } static void noop_init_apic_ldr(void) { }
static void noop_send_IPI(int cpu, int vector) { }
static void noop_send_IPI_mask(const struct cpumask *cpumask, int vector) { } static void noop_send_IPI_mask(const struct cpumask *cpumask, int vector) { }
static void noop_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector) { } static void noop_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector) { }
static void noop_send_IPI_allbutself(int vector) { } static void noop_send_IPI_allbutself(int vector) { }
...@@ -144,6 +145,7 @@ struct apic apic_noop = { ...@@ -144,6 +145,7 @@ struct apic apic_noop = {
.cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and, .cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and,
.send_IPI = noop_send_IPI,
.send_IPI_mask = noop_send_IPI_mask, .send_IPI_mask = noop_send_IPI_mask,
.send_IPI_mask_allbutself = noop_send_IPI_mask_allbutself, .send_IPI_mask_allbutself = noop_send_IPI_mask_allbutself,
.send_IPI_allbutself = noop_send_IPI_allbutself, .send_IPI_allbutself = noop_send_IPI_allbutself,
......
...@@ -273,6 +273,7 @@ static const struct apic apic_numachip1 __refconst = { ...@@ -273,6 +273,7 @@ static const struct apic apic_numachip1 __refconst = {
.cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and,
.send_IPI = numachip_send_IPI_one,
.send_IPI_mask = numachip_send_IPI_mask, .send_IPI_mask = numachip_send_IPI_mask,
.send_IPI_mask_allbutself = numachip_send_IPI_mask_allbutself, .send_IPI_mask_allbutself = numachip_send_IPI_mask_allbutself,
.send_IPI_allbutself = numachip_send_IPI_allbutself, .send_IPI_allbutself = numachip_send_IPI_allbutself,
...@@ -324,6 +325,7 @@ static const struct apic apic_numachip2 __refconst = { ...@@ -324,6 +325,7 @@ static const struct apic apic_numachip2 __refconst = {
.cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and,
.send_IPI = numachip_send_IPI_one,
.send_IPI_mask = numachip_send_IPI_mask, .send_IPI_mask = numachip_send_IPI_mask,
.send_IPI_mask_allbutself = numachip_send_IPI_mask_allbutself, .send_IPI_mask_allbutself = numachip_send_IPI_mask_allbutself,
.send_IPI_allbutself = numachip_send_IPI_allbutself, .send_IPI_allbutself = numachip_send_IPI_allbutself,
......
...@@ -96,11 +96,6 @@ static int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb) ...@@ -96,11 +96,6 @@ static int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb)
return cpuid_apic >> index_msb; return cpuid_apic >> index_msb;
} }
static inline void bigsmp_send_IPI_mask(const struct cpumask *mask, int vector)
{
default_send_IPI_mask_sequence_phys(mask, vector);
}
static void bigsmp_send_IPI_allbutself(int vector) static void bigsmp_send_IPI_allbutself(int vector)
{ {
default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector); default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
...@@ -108,7 +103,7 @@ static void bigsmp_send_IPI_allbutself(int vector) ...@@ -108,7 +103,7 @@ static void bigsmp_send_IPI_allbutself(int vector)
static void bigsmp_send_IPI_all(int vector) static void bigsmp_send_IPI_all(int vector)
{ {
bigsmp_send_IPI_mask(cpu_online_mask, vector); default_send_IPI_mask_sequence_phys(cpu_online_mask, vector);
} }
static int dmi_bigsmp; /* can be set by dmi scanners */ static int dmi_bigsmp; /* can be set by dmi scanners */
...@@ -180,7 +175,8 @@ static struct apic apic_bigsmp = { ...@@ -180,7 +175,8 @@ static struct apic apic_bigsmp = {
.cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and,
.send_IPI_mask = bigsmp_send_IPI_mask, .send_IPI = default_send_IPI_single_phys,
.send_IPI_mask = default_send_IPI_mask_sequence_phys,
.send_IPI_mask_allbutself = NULL, .send_IPI_mask_allbutself = NULL,
.send_IPI_allbutself = bigsmp_send_IPI_allbutself, .send_IPI_allbutself = bigsmp_send_IPI_allbutself,
.send_IPI_all = bigsmp_send_IPI_all, .send_IPI_all = bigsmp_send_IPI_all,
......
...@@ -18,6 +18,16 @@ ...@@ -18,6 +18,16 @@
#include <asm/proto.h> #include <asm/proto.h>
#include <asm/ipi.h> #include <asm/ipi.h>
void default_send_IPI_single_phys(int cpu, int vector)
{
unsigned long flags;
local_irq_save(flags);
__default_send_IPI_dest_field(per_cpu(x86_cpu_to_apicid, cpu),
vector, APIC_DEST_PHYSICAL);
local_irq_restore(flags);
}
void default_send_IPI_mask_sequence_phys(const struct cpumask *mask, int vector) void default_send_IPI_mask_sequence_phys(const struct cpumask *mask, int vector)
{ {
unsigned long query_cpu; unsigned long query_cpu;
...@@ -55,6 +65,14 @@ void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask, ...@@ -55,6 +65,14 @@ void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask,
local_irq_restore(flags); local_irq_restore(flags);
} }
/*
* Helper function for APICs which insist on cpumasks
*/
void default_send_IPI_single(int cpu, int vector)
{
apic->send_IPI_mask(cpumask_of(cpu), vector);
}
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
void default_send_IPI_mask_sequence_logical(const struct cpumask *mask, void default_send_IPI_mask_sequence_logical(const struct cpumask *mask,
......
...@@ -96,8 +96,8 @@ static irq_hw_number_t pci_msi_get_hwirq(struct msi_domain_info *info, ...@@ -96,8 +96,8 @@ static irq_hw_number_t pci_msi_get_hwirq(struct msi_domain_info *info,
return arg->msi_hwirq; return arg->msi_hwirq;
} }
static int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
int nvec, msi_alloc_info_t *arg) msi_alloc_info_t *arg)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct msi_desc *desc = first_pci_msi_entry(pdev); struct msi_desc *desc = first_pci_msi_entry(pdev);
...@@ -113,11 +113,13 @@ static int pci_msi_prepare(struct irq_domain *domain, struct device *dev, ...@@ -113,11 +113,13 @@ static int pci_msi_prepare(struct irq_domain *domain, struct device *dev,
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(pci_msi_prepare);
static void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
{ {
arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc); arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc);
} }
EXPORT_SYMBOL_GPL(pci_msi_set_desc);
static struct msi_domain_ops pci_msi_domain_ops = { static struct msi_domain_ops pci_msi_domain_ops = {
.get_hwirq = pci_msi_get_hwirq, .get_hwirq = pci_msi_get_hwirq,
......
...@@ -105,6 +105,7 @@ static struct apic apic_default = { ...@@ -105,6 +105,7 @@ static struct apic apic_default = {
.cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and, .cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and,
.send_IPI = default_send_IPI_single,
.send_IPI_mask = default_send_IPI_mask_logical, .send_IPI_mask = default_send_IPI_mask_logical,
.send_IPI_mask_allbutself = default_send_IPI_mask_allbutself_logical, .send_IPI_mask_allbutself = default_send_IPI_mask_allbutself_logical,
.send_IPI_allbutself = default_send_IPI_allbutself, .send_IPI_allbutself = default_send_IPI_allbutself,
......
...@@ -29,6 +29,7 @@ struct apic_chip_data { ...@@ -29,6 +29,7 @@ struct apic_chip_data {
}; };
struct irq_domain *x86_vector_domain; struct irq_domain *x86_vector_domain;
EXPORT_SYMBOL_GPL(x86_vector_domain);
static DEFINE_RAW_SPINLOCK(vector_lock); static DEFINE_RAW_SPINLOCK(vector_lock);
static cpumask_var_t vector_cpumask; static cpumask_var_t vector_cpumask;
static struct irq_chip lapic_controller; static struct irq_chip lapic_controller;
...@@ -66,6 +67,7 @@ struct irq_cfg *irqd_cfg(struct irq_data *irq_data) ...@@ -66,6 +67,7 @@ struct irq_cfg *irqd_cfg(struct irq_data *irq_data)
return data ? &data->cfg : NULL; return data ? &data->cfg : NULL;
} }
EXPORT_SYMBOL_GPL(irqd_cfg);
struct irq_cfg *irq_cfg(unsigned int irq) struct irq_cfg *irq_cfg(unsigned int irq)
{ {
......
...@@ -23,6 +23,14 @@ static inline u32 x2apic_cluster(int cpu) ...@@ -23,6 +23,14 @@ static inline u32 x2apic_cluster(int cpu)
return per_cpu(x86_cpu_to_logical_apicid, cpu) >> 16; return per_cpu(x86_cpu_to_logical_apicid, cpu) >> 16;
} }
static void x2apic_send_IPI(int cpu, int vector)
{
u32 dest = per_cpu(x86_cpu_to_logical_apicid, cpu);
x2apic_wrmsr_fence();
__x2apic_send_IPI_dest(dest, vector, APIC_DEST_LOGICAL);
}
static void static void
__x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest) __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
{ {
...@@ -266,6 +274,7 @@ static struct apic apic_x2apic_cluster = { ...@@ -266,6 +274,7 @@ static struct apic apic_x2apic_cluster = {
.cpu_mask_to_apicid_and = x2apic_cpu_mask_to_apicid_and, .cpu_mask_to_apicid_and = x2apic_cpu_mask_to_apicid_and,
.send_IPI = x2apic_send_IPI,
.send_IPI_mask = x2apic_send_IPI_mask, .send_IPI_mask = x2apic_send_IPI_mask,
.send_IPI_mask_allbutself = x2apic_send_IPI_mask_allbutself, .send_IPI_mask_allbutself = x2apic_send_IPI_mask_allbutself,
.send_IPI_allbutself = x2apic_send_IPI_allbutself, .send_IPI_allbutself = x2apic_send_IPI_allbutself,
......
...@@ -36,6 +36,14 @@ static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id) ...@@ -36,6 +36,14 @@ static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
return x2apic_enabled() && (x2apic_phys || x2apic_fadt_phys()); return x2apic_enabled() && (x2apic_phys || x2apic_fadt_phys());
} }
static void x2apic_send_IPI(int cpu, int vector)
{
u32 dest = per_cpu(x86_cpu_to_apicid, cpu);
x2apic_wrmsr_fence();
__x2apic_send_IPI_dest(dest, vector, APIC_DEST_PHYSICAL);
}
static void static void
__x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest) __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
{ {
...@@ -122,6 +130,7 @@ static struct apic apic_x2apic_phys = { ...@@ -122,6 +130,7 @@ static struct apic apic_x2apic_phys = {
.cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and, .cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and,
.send_IPI = x2apic_send_IPI,
.send_IPI_mask = x2apic_send_IPI_mask, .send_IPI_mask = x2apic_send_IPI_mask,
.send_IPI_mask_allbutself = x2apic_send_IPI_mask_allbutself, .send_IPI_mask_allbutself = x2apic_send_IPI_mask_allbutself,
.send_IPI_allbutself = x2apic_send_IPI_allbutself, .send_IPI_allbutself = x2apic_send_IPI_allbutself,
......
...@@ -406,6 +406,7 @@ static struct apic __refdata apic_x2apic_uv_x = { ...@@ -406,6 +406,7 @@ static struct apic __refdata apic_x2apic_uv_x = {
.cpu_mask_to_apicid_and = uv_cpu_mask_to_apicid_and, .cpu_mask_to_apicid_and = uv_cpu_mask_to_apicid_and,
.send_IPI = uv_send_IPI_one,
.send_IPI_mask = uv_send_IPI_mask, .send_IPI_mask = uv_send_IPI_mask,
.send_IPI_mask_allbutself = uv_send_IPI_mask_allbutself, .send_IPI_mask_allbutself = uv_send_IPI_mask_allbutself,
.send_IPI_allbutself = uv_send_IPI_allbutself, .send_IPI_allbutself = uv_send_IPI_allbutself,
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <asm/mach_traps.h> #include <asm/mach_traps.h>
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/x86_init.h> #include <asm/x86_init.h>
#include <asm/reboot.h>
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include <trace/events/nmi.h> #include <trace/events/nmi.h>
...@@ -231,7 +232,7 @@ pci_serr_error(unsigned char reason, struct pt_regs *regs) ...@@ -231,7 +232,7 @@ pci_serr_error(unsigned char reason, struct pt_regs *regs)
#endif #endif
if (panic_on_unrecovered_nmi) if (panic_on_unrecovered_nmi)
panic("NMI: Not continuing"); nmi_panic(regs, "NMI: Not continuing");
pr_emerg("Dazed and confused, but trying to continue\n"); pr_emerg("Dazed and confused, but trying to continue\n");
...@@ -255,8 +256,16 @@ io_check_error(unsigned char reason, struct pt_regs *regs) ...@@ -255,8 +256,16 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
reason, smp_processor_id()); reason, smp_processor_id());
show_regs(regs); show_regs(regs);
if (panic_on_io_nmi) if (panic_on_io_nmi) {
panic("NMI IOCK error: Not continuing"); nmi_panic(regs, "NMI IOCK error: Not continuing");
/*
* If we end up here, it means we have received an NMI while
* processing panic(). Simply return without delaying and
* re-enabling NMIs.
*/
return;
}
/* Re-enable the IOCK line, wait for a few seconds */ /* Re-enable the IOCK line, wait for a few seconds */
reason = (reason & NMI_REASON_CLEAR_MASK) | NMI_REASON_CLEAR_IOCHK; reason = (reason & NMI_REASON_CLEAR_MASK) | NMI_REASON_CLEAR_IOCHK;
...@@ -297,7 +306,7 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs) ...@@ -297,7 +306,7 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
pr_emerg("Do you have a strange power saving mode enabled?\n"); pr_emerg("Do you have a strange power saving mode enabled?\n");
if (unknown_nmi_panic || panic_on_unrecovered_nmi) if (unknown_nmi_panic || panic_on_unrecovered_nmi)
panic("NMI: Not continuing"); nmi_panic(regs, "NMI: Not continuing");
pr_emerg("Dazed and confused, but trying to continue\n"); pr_emerg("Dazed and confused, but trying to continue\n");
} }
...@@ -348,8 +357,19 @@ static void default_do_nmi(struct pt_regs *regs) ...@@ -348,8 +357,19 @@ static void default_do_nmi(struct pt_regs *regs)
return; return;
} }
/* Non-CPU-specific NMI: NMI sources can be processed on any CPU */ /*
raw_spin_lock(&nmi_reason_lock); * Non-CPU-specific NMI: NMI sources can be processed on any CPU.
*
* Another CPU may be processing panic routines while holding
* nmi_reason_lock. Check if the CPU issued the IPI for crash dumping,
* and if so, call its callback directly. If there is no CPU preparing
* crash dump, we simply loop here.