Commit 8299608f authored by Ingo Molnar's avatar Ingo Molnar

Merge branches 'irq/sparseirq', 'x86/quirks' and 'x86/reboot' into cpus4096

We merge the irq/sparseirq, x86/quirks and x86/reboot trees into the
cpus4096 tree because the io-apic changes in the sparseirq change
conflict with the cpumask changes in the cpumask tree, and we
want to resolve those.
...@@ -241,6 +241,16 @@ config X86_HAS_BOOT_CPU_ID ...@@ -241,6 +241,16 @@ config X86_HAS_BOOT_CPU_ID
def_bool y def_bool y
depends on X86_VOYAGER depends on X86_VOYAGER
config SPARSE_IRQ
bool "Support sparse irq numbering"
depends on (PCI_MSI || HT_IRQ) && SMP
default y
help
This enables support for sparse irq, esp for msi/msi-x. You may need
if you have lots of cards supports msi-x installed.
If you don't know what to do here, say Y.
config X86_FIND_SMP_CONFIG config X86_FIND_SMP_CONFIG
def_bool y def_bool y
depends on X86_MPPARSE || X86_VOYAGER depends on X86_MPPARSE || X86_VOYAGER
...@@ -468,10 +478,6 @@ config X86_CYCLONE_TIMER ...@@ -468,10 +478,6 @@ config X86_CYCLONE_TIMER
def_bool y def_bool y
depends on X86_GENERICARCH depends on X86_GENERICARCH
config ES7000_CLUSTERED_APIC
def_bool y
depends on SMP && X86_ES7000 && MPENTIUMIII
source "arch/x86/Kconfig.cpu" source "arch/x86/Kconfig.cpu"
config HPET_TIMER config HPET_TIMER
...@@ -1635,13 +1641,6 @@ config APM_ALLOW_INTS ...@@ -1635,13 +1641,6 @@ config APM_ALLOW_INTS
many of the newer IBM Thinkpads. If you experience hangs when you many of the newer IBM Thinkpads. If you experience hangs when you
suspend, try setting this to Y. Otherwise, say N. suspend, try setting this to Y. Otherwise, say N.
config APM_REAL_MODE_POWER_OFF
bool "Use real mode APM BIOS call to power off"
help
Use real mode APM BIOS calls to switch off the computer. This is
a work-around for a number of buggy BIOSes. Switch this option on if
your computer crashes instead of powering off properly.
endif # APM endif # APM
source "arch/x86/kernel/cpu/cpufreq/Kconfig" source "arch/x86/kernel/cpu/cpufreq/Kconfig"
......
...@@ -193,6 +193,7 @@ extern u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask); ...@@ -193,6 +193,7 @@ extern u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask);
static inline void lapic_shutdown(void) { } static inline void lapic_shutdown(void) { }
#define local_apic_timer_c2_ok 1 #define local_apic_timer_c2_ok 1
static inline void init_apic_mappings(void) { } static inline void init_apic_mappings(void) { }
static inline void disable_local_APIC(void) { }
#endif /* !CONFIG_X86_LOCAL_APIC */ #endif /* !CONFIG_X86_LOCAL_APIC */
......
...@@ -24,8 +24,6 @@ static inline cpumask_t target_cpus(void) ...@@ -24,8 +24,6 @@ static inline cpumask_t target_cpus(void)
#define INT_DELIVERY_MODE (dest_Fixed) #define INT_DELIVERY_MODE (dest_Fixed)
#define INT_DEST_MODE (0) /* phys delivery to target proc */ #define INT_DEST_MODE (0) /* phys delivery to target proc */
#define NO_BALANCE_IRQ (0) #define NO_BALANCE_IRQ (0)
#define WAKE_SECONDARY_VIA_INIT
static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid) static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
{ {
......
...@@ -8,7 +8,9 @@ enum reboot_type { ...@@ -8,7 +8,9 @@ enum reboot_type {
BOOT_BIOS = 'b', BOOT_BIOS = 'b',
#endif #endif
BOOT_ACPI = 'a', BOOT_ACPI = 'a',
BOOT_EFI = 'e' BOOT_EFI = 'e',
BOOT_CF9 = 'p',
BOOT_CF9_COND = 'q',
}; };
extern enum reboot_type reboot_type; extern enum reboot_type reboot_type;
......
...@@ -9,31 +9,27 @@ static inline int apic_id_registered(void) ...@@ -9,31 +9,27 @@ static inline int apic_id_registered(void)
return (1); return (1);
} }
static inline cpumask_t target_cpus(void) static inline cpumask_t target_cpus_cluster(void)
{ {
#if defined CONFIG_ES7000_CLUSTERED_APIC
return CPU_MASK_ALL; return CPU_MASK_ALL;
#else }
static inline cpumask_t target_cpus(void)
{
return cpumask_of_cpu(smp_processor_id()); return cpumask_of_cpu(smp_processor_id());
#endif
} }
#if defined CONFIG_ES7000_CLUSTERED_APIC #define APIC_DFR_VALUE_CLUSTER (APIC_DFR_CLUSTER)
#define APIC_DFR_VALUE (APIC_DFR_CLUSTER) #define INT_DELIVERY_MODE_CLUSTER (dest_LowestPrio)
#define INT_DELIVERY_MODE (dest_LowestPrio) #define INT_DEST_MODE_CLUSTER (1) /* logical delivery broadcast to all procs */
#define INT_DEST_MODE (1) /* logical delivery broadcast to all procs */ #define NO_BALANCE_IRQ_CLUSTER (1)
#define NO_BALANCE_IRQ (1)
#undef WAKE_SECONDARY_VIA_INIT
#define WAKE_SECONDARY_VIA_MIP
#else
#define APIC_DFR_VALUE (APIC_DFR_FLAT) #define APIC_DFR_VALUE (APIC_DFR_FLAT)
#define INT_DELIVERY_MODE (dest_Fixed) #define INT_DELIVERY_MODE (dest_Fixed)
#define INT_DEST_MODE (0) /* phys delivery to target procs */ #define INT_DEST_MODE (0) /* phys delivery to target procs */
#define NO_BALANCE_IRQ (0) #define NO_BALANCE_IRQ (0)
#undef APIC_DEST_LOGICAL #undef APIC_DEST_LOGICAL
#define APIC_DEST_LOGICAL 0x0 #define APIC_DEST_LOGICAL 0x0
#define WAKE_SECONDARY_VIA_INIT
#endif
static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid) static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
{ {
...@@ -60,6 +56,16 @@ static inline unsigned long calculate_ldr(int cpu) ...@@ -60,6 +56,16 @@ static inline unsigned long calculate_ldr(int cpu)
* an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel * an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
* document number 292116). So here it goes... * document number 292116). So here it goes...
*/ */
static inline void init_apic_ldr_cluster(void)
{
unsigned long val;
int cpu = smp_processor_id();
apic_write(APIC_DFR, APIC_DFR_VALUE_CLUSTER);
val = calculate_ldr(cpu);
apic_write(APIC_LDR, val);
}
static inline void init_apic_ldr(void) static inline void init_apic_ldr(void)
{ {
unsigned long val; unsigned long val;
...@@ -70,10 +76,6 @@ static inline void init_apic_ldr(void) ...@@ -70,10 +76,6 @@ static inline void init_apic_ldr(void)
apic_write(APIC_LDR, val); apic_write(APIC_LDR, val);
} }
#ifndef CONFIG_X86_GENERICARCH
extern void enable_apic_mode(void);
#endif
extern int apic_version [MAX_APICS]; extern int apic_version [MAX_APICS];
static inline void setup_apic_routing(void) static inline void setup_apic_routing(void)
{ {
...@@ -144,7 +146,7 @@ static inline int check_phys_apicid_present(int cpu_physical_apicid) ...@@ -144,7 +146,7 @@ static inline int check_phys_apicid_present(int cpu_physical_apicid)
return (1); return (1);
} }
static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) static inline unsigned int cpu_mask_to_apicid_cluster(cpumask_t cpumask)
{ {
int num_bits_set; int num_bits_set;
int cpus_found = 0; int cpus_found = 0;
...@@ -154,11 +156,7 @@ static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) ...@@ -154,11 +156,7 @@ static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
num_bits_set = cpus_weight(cpumask); num_bits_set = cpus_weight(cpumask);
/* Return id to all */ /* Return id to all */
if (num_bits_set == NR_CPUS) if (num_bits_set == NR_CPUS)
#if defined CONFIG_ES7000_CLUSTERED_APIC
return 0xFF; return 0xFF;
#else
return cpu_to_logical_apicid(0);
#endif
/* /*
* The cpus in the mask must all be on the apic cluster. If are not * The cpus in the mask must all be on the apic cluster. If are not
* on the same apicid cluster return default value of TARGET_CPUS. * on the same apicid cluster return default value of TARGET_CPUS.
...@@ -171,11 +169,40 @@ static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask) ...@@ -171,11 +169,40 @@ static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
if (apicid_cluster(apicid) != if (apicid_cluster(apicid) !=
apicid_cluster(new_apicid)){ apicid_cluster(new_apicid)){
printk ("%s: Not a valid mask!\n", __func__); printk ("%s: Not a valid mask!\n", __func__);
#if defined CONFIG_ES7000_CLUSTERED_APIC
return 0xFF; return 0xFF;
#else }
apicid = new_apicid;
cpus_found++;
}
cpu++;
}
return apicid;
}
static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
{
int num_bits_set;
int cpus_found = 0;
int cpu;
int apicid;
num_bits_set = cpus_weight(cpumask);
/* Return id to all */
if (num_bits_set == NR_CPUS)
return cpu_to_logical_apicid(0);
/*
* The cpus in the mask must all be on the apic cluster. If are not
* on the same apicid cluster return default value of TARGET_CPUS.
*/
cpu = first_cpu(cpumask);
apicid = cpu_to_logical_apicid(cpu);
while (cpus_found < num_bits_set) {
if (cpu_isset(cpu, cpumask)) {
int new_apicid = cpu_to_logical_apicid(cpu);
if (apicid_cluster(apicid) !=
apicid_cluster(new_apicid)){
printk ("%s: Not a valid mask!\n", __func__);
return cpu_to_logical_apicid(0); return cpu_to_logical_apicid(0);
#endif
} }
apicid = new_apicid; apicid = new_apicid;
cpus_found++; cpus_found++;
......
#ifndef __ASM_ES7000_WAKECPU_H #ifndef __ASM_ES7000_WAKECPU_H
#define __ASM_ES7000_WAKECPU_H #define __ASM_ES7000_WAKECPU_H
/* #define TRAMPOLINE_PHYS_LOW 0x467
* This file copes with machines that wakeup secondary CPUs by the #define TRAMPOLINE_PHYS_HIGH 0x469
* INIT, INIT, STARTUP sequence.
*/
#ifdef CONFIG_ES7000_CLUSTERED_APIC
#define WAKE_SECONDARY_VIA_MIP
#else
#define WAKE_SECONDARY_VIA_INIT
#endif
#ifdef WAKE_SECONDARY_VIA_MIP
extern int es7000_start_cpu(int cpu, unsigned long eip);
static inline int
wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
{
int boot_error = 0;
boot_error = es7000_start_cpu(phys_apicid, start_eip);
return boot_error;
}
#endif
#define TRAMPOLINE_LOW phys_to_virt(0x467)
#define TRAMPOLINE_HIGH phys_to_virt(0x469)
#define boot_cpu_apicid boot_cpu_physical_apicid
static inline void wait_for_init_deassert(atomic_t *deassert) static inline void wait_for_init_deassert(atomic_t *deassert)
{ {
#ifdef WAKE_SECONDARY_VIA_INIT #ifndef CONFIG_ES7000_CLUSTERED_APIC
while (!atomic_read(deassert)) while (!atomic_read(deassert))
cpu_relax(); cpu_relax();
#endif #endif
...@@ -50,9 +26,12 @@ static inline void restore_NMI_vector(unsigned short *high, unsigned short *low) ...@@ -50,9 +26,12 @@ static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
{ {
} }
#define inquire_remote_apic(apicid) do { \ extern void __inquire_remote_apic(int apicid);
if (apic_verbosity >= APIC_DEBUG) \
__inquire_remote_apic(apicid); \ static inline void inquire_remote_apic(int apicid)
} while (0) {
if (apic_verbosity >= APIC_DEBUG)
__inquire_remote_apic(apicid);
}
#endif /* __ASM_MACH_WAKECPU_H */ #endif /* __ASM_MACH_WAKECPU_H */
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#define _ASM_X86_GENAPIC_32_H #define _ASM_X86_GENAPIC_32_H
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/atomic.h>
/* /*
* Generic APIC driver interface. * Generic APIC driver interface.
...@@ -65,6 +66,14 @@ struct genapic { ...@@ -65,6 +66,14 @@ struct genapic {
void (*send_IPI_allbutself)(int vector); void (*send_IPI_allbutself)(int vector);
void (*send_IPI_all)(int vector); void (*send_IPI_all)(int vector);
#endif #endif
int (*wakeup_cpu)(int apicid, unsigned long start_eip);
int trampoline_phys_low;
int trampoline_phys_high;
void (*wait_for_init_deassert)(atomic_t *deassert);
void (*smp_callin_clear_local_apic)(void);
void (*store_NMI_vector)(unsigned short *high, unsigned short *low);
void (*restore_NMI_vector)(unsigned short *high, unsigned short *low);
void (*inquire_remote_apic)(int apicid);
}; };
#define APICFUNC(x) .x = x, #define APICFUNC(x) .x = x,
...@@ -112,9 +121,17 @@ struct genapic { ...@@ -112,9 +121,17 @@ struct genapic {
IPIFUNC(send_IPI_all) \ IPIFUNC(send_IPI_all) \
APICFUNC(enable_apic_mode) \ APICFUNC(enable_apic_mode) \
APICFUNC(phys_pkg_id) \ APICFUNC(phys_pkg_id) \
.trampoline_phys_low = TRAMPOLINE_PHYS_LOW, \
.trampoline_phys_high = TRAMPOLINE_PHYS_HIGH, \
APICFUNC(wait_for_init_deassert) \
APICFUNC(smp_callin_clear_local_apic) \
APICFUNC(store_NMI_vector) \
APICFUNC(restore_NMI_vector) \
APICFUNC(inquire_remote_apic) \
} }
extern struct genapic *genapic; extern struct genapic *genapic;
extern void es7000_update_genapic_to_cluster(void);
enum uv_system_type {UV_NONE, UV_LEGACY_APIC, UV_X2APIC, UV_NON_UNIQUE_APIC}; enum uv_system_type {UV_NONE, UV_LEGACY_APIC, UV_X2APIC, UV_NON_UNIQUE_APIC};
#define get_uv_system_type() UV_NONE #define get_uv_system_type() UV_NONE
......
...@@ -32,6 +32,8 @@ struct genapic { ...@@ -32,6 +32,8 @@ struct genapic {
unsigned int (*get_apic_id)(unsigned long x); unsigned int (*get_apic_id)(unsigned long x);
unsigned long (*set_apic_id)(unsigned int id); unsigned long (*set_apic_id)(unsigned int id);
unsigned long apic_id_mask; unsigned long apic_id_mask;
/* wakeup_secondary_cpu */
int (*wakeup_cpu)(int apicid, unsigned long start_eip);
}; };
extern struct genapic *genapic; extern struct genapic *genapic;
......
...@@ -188,17 +188,14 @@ extern void restore_IO_APIC_setup(void); ...@@ -188,17 +188,14 @@ extern void restore_IO_APIC_setup(void);
extern void reinit_intr_remapped_IO_APIC(int); extern void reinit_intr_remapped_IO_APIC(int);
#endif #endif
extern int probe_nr_irqs(void); extern void probe_nr_irqs_gsi(void);
#else /* !CONFIG_X86_IO_APIC */ #else /* !CONFIG_X86_IO_APIC */
#define io_apic_assign_pci_irqs 0 #define io_apic_assign_pci_irqs 0
static const int timer_through_8259 = 0; static const int timer_through_8259 = 0;
static inline void ioapic_init_mappings(void) { } static inline void ioapic_init_mappings(void) { }
static inline int probe_nr_irqs(void) static inline void probe_nr_irqs_gsi(void) { }
{
return NR_IRQS;
}
#endif #endif
#endif /* _ASM_X86_IO_APIC_H */ #endif /* _ASM_X86_IO_APIC_H */
...@@ -101,12 +101,23 @@ ...@@ -101,12 +101,23 @@
#define LAST_VM86_IRQ 15 #define LAST_VM86_IRQ 15
#define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15) #define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15)
#define NR_IRQS_LEGACY 16
#if defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_VOYAGER) #if defined(CONFIG_X86_IO_APIC) && !defined(CONFIG_X86_VOYAGER)
#ifndef CONFIG_SPARSE_IRQ
# if NR_CPUS < MAX_IO_APICS # if NR_CPUS < MAX_IO_APICS
# define NR_IRQS (NR_VECTORS + (32 * NR_CPUS)) # define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))
# else # else
# define NR_IRQS (NR_VECTORS + (32 * MAX_IO_APICS)) # define NR_IRQS (NR_VECTORS + (32 * MAX_IO_APICS))
# endif # endif
#else
# if (8 * NR_CPUS) > (32 * MAX_IO_APICS)
# define NR_IRQS (NR_VECTORS + (8 * NR_CPUS))
# else
# define NR_IRQS (NR_VECTORS + (32 * MAX_IO_APICS))
# endif
#endif
#elif defined(CONFIG_X86_VOYAGER) #elif defined(CONFIG_X86_VOYAGER)
......
...@@ -32,11 +32,13 @@ static inline cpumask_t target_cpus(void) ...@@ -32,11 +32,13 @@ static inline cpumask_t target_cpus(void)
#define vector_allocation_domain (genapic->vector_allocation_domain) #define vector_allocation_domain (genapic->vector_allocation_domain)
#define read_apic_id() (GET_APIC_ID(apic_read(APIC_ID))) #define read_apic_id() (GET_APIC_ID(apic_read(APIC_ID)))
#define send_IPI_self (genapic->send_IPI_self) #define send_IPI_self (genapic->send_IPI_self)
#define wakeup_secondary_cpu (genapic->wakeup_cpu)
extern void setup_apic_routing(void); extern void setup_apic_routing(void);
#else #else
#define INT_DELIVERY_MODE dest_LowestPrio #define INT_DELIVERY_MODE dest_LowestPrio
#define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */ #define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */
#define TARGET_CPUS (target_cpus()) #define TARGET_CPUS (target_cpus())
#define wakeup_secondary_cpu wakeup_secondary_cpu_via_init
/* /*
* Set up the logical destination ID. * Set up the logical destination ID.
* *
......
#ifndef _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H #ifndef _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H
#define _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H #define _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H
/* #define TRAMPOLINE_PHYS_LOW (0x467)
* This file copes with machines that wakeup secondary CPUs by the #define TRAMPOLINE_PHYS_HIGH (0x469)
* INIT, INIT, STARTUP sequence.
*/
#define WAKE_SECONDARY_VIA_INIT
#define TRAMPOLINE_LOW phys_to_virt(0x467)
#define TRAMPOLINE_HIGH phys_to_virt(0x469)
#define boot_cpu_apicid boot_cpu_physical_apicid
static inline void wait_for_init_deassert(atomic_t *deassert) static inline void wait_for_init_deassert(atomic_t *deassert)
{ {
...@@ -33,9 +24,12 @@ static inline void restore_NMI_vector(unsigned short *high, unsigned short *low) ...@@ -33,9 +24,12 @@ static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
{ {
} }
#define inquire_remote_apic(apicid) do { \ extern void __inquire_remote_apic(int apicid);
if (apic_verbosity >= APIC_DEBUG) \
__inquire_remote_apic(apicid); \ static inline void inquire_remote_apic(int apicid)
} while (0) {
if (apic_verbosity >= APIC_DEBUG)
__inquire_remote_apic(apicid);
}
#endif /* _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H */ #endif /* _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H */
...@@ -13,9 +13,11 @@ static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip) ...@@ -13,9 +13,11 @@ static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
CMOS_WRITE(0xa, 0xf); CMOS_WRITE(0xa, 0xf);
local_flush_tlb(); local_flush_tlb();
pr_debug("1.\n"); pr_debug("1.\n");
*((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4; *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) =
start_eip >> 4;
pr_debug("2.\n"); pr_debug("2.\n");
*((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf; *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) =
start_eip & 0xf;
pr_debug("3.\n"); pr_debug("3.\n");
} }
...@@ -32,7 +34,7 @@ static inline void smpboot_restore_warm_reset_vector(void) ...@@ -32,7 +34,7 @@ static inline void smpboot_restore_warm_reset_vector(void)
*/ */
CMOS_WRITE(0, 0xf); CMOS_WRITE(0, 0xf);
*((volatile long *) phys_to_virt(0x467)) = 0; *((volatile long *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) = 0;
} }
static inline void __init smpboot_setup_io_apic(void) static inline void __init smpboot_setup_io_apic(void)
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#define vector_allocation_domain (genapic->vector_allocation_domain) #define vector_allocation_domain (genapic->vector_allocation_domain)
#define enable_apic_mode (genapic->enable_apic_mode) #define enable_apic_mode (genapic->enable_apic_mode)
#define phys_pkg_id (genapic->phys_pkg_id) #define phys_pkg_id (genapic->phys_pkg_id)
#define wakeup_secondary_cpu (genapic->wakeup_cpu)
extern void generic_bigsmp_probe(void); extern void generic_bigsmp_probe(void);
......
#ifndef _ASM_X86_MACH_GENERIC_MACH_WAKECPU_H
#define _ASM_X86_MACH_GENERIC_MACH_WAKECPU_H
#define TRAMPOLINE_PHYS_LOW (genapic->trampoline_phys_low)
#define TRAMPOLINE_PHYS_HIGH (genapic->trampoline_phys_high)
#define wait_for_init_deassert (genapic->wait_for_init_deassert)
#define smp_callin_clear_local_apic (genapic->smp_callin_clear_local_apic)
#define store_NMI_vector (genapic->store_NMI_vector)
#define restore_NMI_vector (genapic->restore_NMI_vector)
#define inquire_remote_apic (genapic->inquire_remote_apic)
#endif /* _ASM_X86_MACH_GENERIC_MACH_APIC_H */
...@@ -3,12 +3,8 @@ ...@@ -3,12 +3,8 @@
/* This file copes with machines that wakeup secondary CPUs by NMIs */ /* This file copes with machines that wakeup secondary CPUs by NMIs */
#define WAKE_SECONDARY_VIA_NMI #define TRAMPOLINE_PHYS_LOW (0x8)
#define TRAMPOLINE_PHYS_HIGH (0xa)
#define TRAMPOLINE_LOW phys_to_virt(0x8)
#define TRAMPOLINE_HIGH phys_to_virt(0xa)
#define boot_cpu_apicid boot_cpu_logical_apicid
/* We don't do anything here because we use NMI's to boot instead */ /* We don't do anything here because we use NMI's to boot instead */
static inline void wait_for_init_deassert(atomic_t *deassert) static inline void wait_for_init_deassert(atomic_t *deassert)
...@@ -27,17 +23,23 @@ static inline void smp_callin_clear_local_apic(void) ...@@ -27,17 +23,23 @@ static inline void smp_callin_clear_local_apic(void)
static inline void store_NMI_vector(unsigned short *high, unsigned short *low) static inline void store_NMI_vector(unsigned short *high, unsigned short *low)
{ {
printk("Storing NMI vector\n"); printk("Storing NMI vector\n");
*high = *((volatile unsigned short *) TRAMPOLINE_HIGH); *high =
*low = *((volatile unsigned short *) TRAMPOLINE_LOW); *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH));
*low =
*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW));
} }
static inline void restore_NMI_vector(unsigned short *high, unsigned short *low) static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
{ {
printk("Restoring NMI vector\n"); printk("Restoring NMI vector\n");
*((volatile unsigned short *) TRAMPOLINE_HIGH) = *high; *((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) =
*((volatile unsigned short *) TRAMPOLINE_LOW) = *low; *high;
*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) =
*low;
} }
#define inquire_remote_apic(apicid) {} static inline void inquire_remote_apic(int apicid)
{
}
#endif /* __ASM_NUMAQ_WAKECPU_H */ #endif /* __ASM_NUMAQ_WAKECPU_H */
...@@ -16,6 +16,8 @@ static inline void visws_early_detect(void) { } ...@@ -16,6 +16,8 @@ static inline void visws_early_detect(void) { }
static inline int is_visws_box(void) { return 0; } static inline int is_visws_box(void) { return 0; }
#endif #endif
extern int wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip);
extern int wakeup_secondary_cpu_via_init(int apicid, unsigned long start_eip);
/* /*
* Any setup quirks to be performed? * Any setup quirks to be performed?
*/ */
...@@ -39,6 +41,7 @@ struct x86_quirks { ...@@ -39,6 +41,7 @@ struct x86_quirks {
void (*smp_read_mpc_oem)(struct mp_config_oemtable *oemtable, void (*smp_read_mpc_oem)(struct mp_config_oemtable *oemtable,
unsigned short oemsize); unsigned short oemsize);
int (*setup_ioapic_ids)(void); int (*setup_ioapic_ids)(void);
int (*update_genapic)(void);
}; };
extern struct x86_quirks *x86_quirks; extern struct x86_quirks *x86_quirks;
......
...@@ -314,6 +314,8 @@ extern void free_init_pages(char *what, unsigned long begin, unsigned long end); ...@@ -314,6 +314,8 @@ extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
void default_idle(void); void default_idle(void);
void stop_this_cpu(void *dummy);
/* /*
* Force strict CPU ordering. * Force strict CPU ordering.
* And yes, this is required on UP too when we're talking * And yes, this is required on UP too when we're talking
......
...@@ -1360,6 +1360,17 @@ static void __init acpi_process_madt(void) ...@@ -1360,6 +1360,17 @@ static void __init acpi_process_madt(void)
disable_acpi(); disable_acpi();
} }
} }
/*
* ACPI supports both logical (e.g. Hyper-Threading) and physical
* processors, where MPS only supports physical.
*/
if (acpi_lapic && acpi_ioapic)
printk(KERN_INFO "Using ACPI (MADT) for SMP configuration "
"information\n");
else if (acpi_lapic)
printk(KERN_INFO "Using ACPI for processor (LAPIC) "
"configuration information\n");
#endif #endif
return; return;
} }
......
...@@ -391,11 +391,7 @@ static int power_off; ...@@ -391,11 +391,7 @@ static int power_off;
#else #else
static int power_off = 1; static int power_off = 1;
#endif #endif
#ifdef CONFIG_APM_REAL_MODE_POWER_OFF
static int realmode_power_off = 1;
#else
static int realmode_power_off; static int realmode_power_off;
#endif
#ifdef CONFIG_APM_ALLOW_INTS #ifdef CONFIG_APM_ALLOW_INTS
static int allow_ints = 1; static int allow_ints = 1;
#else #else
......
...@@ -38,8 +38,11 @@ ...@@ -38,8 +38,11 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/nmi.h> #include <asm/nmi.h>
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/atomic.h>
#include <asm/apicdef.h> #include <asm/apicdef.h>
#include <mach_mpparse.h> #include <mach_mpparse.h>
#include <asm/genapic.h>
#include <asm/setup.h>
/* /*
* ES7000 chipsets * ES7000 chipsets
...@@ -161,6 +164,43 @@ es7000_rename_gsi(int ioapic, int gsi) ...@@ -161,6 +164,43 @@ es7000_rename_gsi(int ioapic, int gsi)
return gsi; return gsi;
} }
static int wakeup_secondary_cpu_via_mip(int cpu, unsigned long eip)
{
unsigned long vect = 0, psaival = 0;
if (psai == NULL)
return -1;
vect = ((unsigned long)__pa(eip)/0x1000) << 16;
psaival = (0x1000000 | vect | cpu);
while (*psai & 0x1000000)
;
*psai = psaival;
return 0;
}
static void noop_wait_for_deassert(atomic_t *deassert_not_used)
{
}
static int __init es7000_update_genapic(void)
{
genapic->wakeup_cpu = wakeup_secondary_cpu_via_mip;
/* MPENTIUMIII */
if (boot_cpu_data.x86 == 6 &&
(boot_cpu_data.x86_model >= 7 || boot_cpu_data.x86_model <= 11)) {
es7000_update_genapic_to_cluster();
genapic->wait_for_init_deassert = noop_wait_for_deassert;
genapic->wakeup_cpu = wakeup_secondary_cpu_via_mip;
}
return 0;
}
void __init void __init
setup_unisys(void) setup_unisys(void)
{ {
...@@ -176,6 +216,8 @@ setup_unisys(void) ...@@ -176,6 +216,8 @@ setup_unisys(void)
else else
es7000_plat = ES7000_CLASSIC; es7000_plat = ES7000_CLASSIC;
ioapic_renumber_irq = es7000_rename_gsi; ioapic_renumber_irq = es7000_rename_gsi;
x86_quirks->update_genapic = es7000_update_genapic;
} }
/* /*
...@@ -317,26 +359,6 @@ es7000_mip_write(struct mip_reg *mip_reg) ...@@ -317,26 +359,6 @@ es7000_mip_write(struct mip_reg *mip_reg)
return status; return status;
} }
int
es7000_start_cpu(int cpu, unsigned long eip)
{
unsigned long vect = 0, psaival = 0;
if (psai == NULL)
return -1;
vect = ((unsigned long)__pa(eip)/0x1000) << 16;
psaival = (0x1000000 | vect | cpu);
while (*psai & 0x1000000)
;
*psai = psaival;
return 0;
}
void __init void __init
es7000_sw_apic(void) es7000_sw_apic(void)
{ {
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <asm/smp.h> #include <asm/smp.h>
#include <asm/ipi.h> #include <asm/ipi.h>
#include <asm/genapic.h> #include <asm/genapic.h>
#include <asm/setup.h>
extern struct genapic apic_flat; extern struct genapic apic_flat;
extern struct genapic apic_physflat; extern struct genapic apic_physflat;
...@@ -53,6 +54,9 @@ void __init setup_apic_routing(void) ...@@ -53,6 +54,9 @@ void __init setup_apic_routing(void)
genapic = &apic_physflat; genapic = &apic_physflat;
printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name); printk(KERN_INFO "Setting APIC routing to %s\n", genapic->name);
} }
if (x86_quirks->update_genapic)
x86_quirks->update_genapic();
} }
/* Same for both flat and physical. */ /* Same for both flat and physical. */
......
...@@ -108,8 +108,33 @@ static int __init parse_noapic(char *str) ...@@ -108,8 +108,33 @@ static int __init parse_noapic(char *str)
early_param("noapic", parse_noapic); early_param("noapic", parse_noapic);
struct irq_pin_list; struct irq_pin_list;
/*
* This is performance-critical, we want to do it O(1)
*
* the indexing order of this array favors 1:1 mappings
* between pins and IRQs.
*/
struct irq_pin_list {
int apic, pin;
struct irq_pin_list *next;
};
static struct irq_pin_list *get_one_free_irq_2_pin(int cpu)
{
struct irq_pin_list *pin;
int node;
node = cpu_to_node(cpu);
pin = kzalloc_node(sizeof(*pin), GFP_ATOMIC, node);
printk(KERN_DEBUG " alloc irq_2_pin on cpu %d node %d\n", cpu, node);
return pin;
}
struct irq_cfg { struct irq_cfg {
unsigned int irq;
struct irq_pin_list *irq_2_pin; struct irq_pin_list *irq_2_pin;
cpumask_t domain; cpumask_t domain;
cpumask_t old_domain; cpumask_t old_domain;
...@@ -119,81 +144,95 @@ struct irq_cfg { ...@@ -119,81 +144,95 @@ struct irq_cfg {
}; };
/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
#ifdef CONFIG_SPARSE_IRQ
static struct irq_cfg irq_cfgx[] = {
#else
static struct irq_cfg irq_cfgx[NR_IRQS] = { static struct irq_cfg irq_cfgx[NR_IRQS] = {
[0] = { .irq = 0, .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR, }, #endif
[1] = { .irq = 1, .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR, }, [0] = { .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR, },
[2] = { .irq = 2, .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR, }, [1] = { .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR, },
[3] = { .irq = 3, .domain = CPU_MASK_ALL, .vector = IRQ3_VECTOR, }, [2] = { .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR, },
[4] = { .irq = 4, .domain = CPU_MASK_ALL, .vector = IRQ4_VECTOR, }, [3] = { .domain = CPU_MASK_ALL, .vector = IRQ3_VECTOR, },
[5] = { .irq = 5, .domain = CPU_MASK_ALL, .vector = IRQ5_VECTOR, }, [4] = { .domain = CPU_MASK_ALL, .vector = IRQ4_VECTOR, },
[6] = { .irq = 6, .domain = CPU_MASK_ALL, .vector = IRQ6_VECTOR, }, [5] = { .domain = CPU_MASK_ALL, .vector = IRQ5_VECTOR, },
[7] = { .irq = 7, .domain = CPU_MASK_ALL, .vector = IRQ7_VECTOR, }, [6] = { .domain = CPU_MASK_ALL, .vector = IRQ6_VECTOR, },
[8] = { .irq = 8, .domain = CPU_MASK_ALL, .vector = IRQ8_VECTOR, }, [7] = { .domain = CPU_MASK_ALL, .vector = IRQ7_VECTOR, },
[9] = { .irq = 9, .domain = CPU_MASK_ALL, .vector = IRQ9_VECTOR, }, [8] = { .domain = CPU_MASK_ALL, .vector = IRQ8_VECTOR, },
[10] = { .irq = 10, .domain = CPU_MASK_ALL, .vector = IRQ10_VECTOR, }, [9] = { .domain = CPU_MASK_ALL, .vector = IRQ9_VECTOR, },
[11] = { .irq = 11, .domain = CPU_MASK_ALL, .vector = IRQ11_VECTOR, }, [10] = { .domain = CPU_MASK_ALL, .vector = IRQ10_VECTOR, },
[12] = { .irq = 12, .domain = CPU_MASK_ALL, .vector = IRQ12_VECTOR, }, [11] = { .domain = CPU_MASK_ALL, .vector = IRQ11_VECTOR, },
[13] = { .irq = 13, .domain = CPU_MASK_ALL, .vector = IRQ13_VECTOR, }, [12] = { .domain = CPU_MASK_ALL, .vector = IRQ12_VECTOR, },
[14] = { .irq = 14, .domain = CPU_MASK_ALL, .vector = IRQ14_VECTOR, }, [13] = { .domain = CPU_MASK_ALL, .vector = IRQ13_VECTOR, },
[15] = { .irq = 15, .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, }, [14] = { .domain = CPU_MASK_ALL, .vector = IRQ14_VECTOR, },
[15] = { .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, },
}; };
#define for_each_irq_cfg(irq, cfg) \ void __init arch_early_irq_init(void)
for (irq = 0, cfg = irq_cfgx; irq < nr_irqs; irq++, cfg++)
static struct irq_cfg *irq_cfg(unsigned int irq)
{ {
return irq < nr_irqs ? irq_cfgx + irq : NULL; struct irq_cfg *cfg;
struct irq_desc *desc;
int count;
int i;
cfg = irq_cfgx;
count = ARRAY_SIZE(irq_cfgx);
for (i = 0; i < count; i++) {
desc = irq_to_desc(i);
desc->chip_data = &cfg[i];
}
} }
static struct irq_cfg *irq_cfg_alloc(unsigned int irq) #ifdef CONFIG_SPARSE_IRQ
static struct irq_cfg *irq_cfg(unsigned int irq)
{ {
return irq_cfg(irq); struct irq_cfg *cfg = NULL;
struct irq_desc *desc;
desc = irq_to_desc(irq);
if (desc)
cfg = desc->chip_data;
return cfg;
} }
/* static struct irq_cfg *get_one_free_irq_cfg(int cpu)
* Rough estimation of how many shared IRQs there are, can be changed {
* anytime. struct irq_cfg *cfg;
*/ int node;
#define MAX_PLUS_SHARED_IRQS NR_IRQS
#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
/* node = cpu_to_node(cpu);
* This is performance-critical, we want to do it O(1)
*
* the indexing order of this array favors 1:1 mappings
* between pins and IRQs.
*/
struct irq_pin_list { cfg = kzalloc_node(sizeof(*cfg), GFP_ATOMIC, node);
int apic, pin; printk(KERN_DEBUG " alloc irq_cfg on cpu %d node %d\n", cpu, node);
struct irq_pin_list *next;
};
static struct irq_pin_list irq_2_pin_head[PIN_MAP_SIZE]; return cfg;
static struct irq_pin_list *irq_2_pin_ptr; }
static void __init irq_2_pin_init(void) void arch_init_chip_data(struct irq_desc *desc, int cpu)
{ {
struct irq_pin_list *pin = irq_2_pin_head; struct irq_cfg *cfg;
int i;
for (i = 1; i < PIN_MAP_SIZE; i++)
pin[i-1].next = &pin[i];
irq_2_pin_ptr = &pin[0]; cfg = desc->chip_data;
if (!cfg) {
desc->chip_data = get_one_free_irq_cfg(cpu);
if (!desc->chip_data) {
printk(KERN_ERR "can not alloc irq_cfg\n");
BUG_ON(1);
}
}
} }
static struct irq_pin_list *get_one_free_irq_2_pin(void) #else
static struct irq_cfg *irq_cfg(unsigned int irq)
{ {
struct irq_pin_list *pin = irq_2_pin_ptr; return irq < nr_irqs ? irq_cfgx + irq : NULL;
}
if (!pin) #endif
panic("can not get more irq_2_pin\n");
irq_2_pin_ptr = pin->next; static inline void set_extra_move_desc(struct irq_desc *desc, cpumask_t mask)
pin->next = NULL; {
return pin;
} }
struct io_apic { struct io_apic {
...@@ -237,11 +276,10 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned ...@@ -237,11 +276,10 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned
writel(value, &io_apic->data); writel(value, &io_apic->data);
} }
static bool io_apic_level_ack_pending(unsigned int irq) static bool io_apic_level_ack_pending(struct irq_cfg *cfg)
{ {
struct irq_pin_list *entry; struct irq_pin_list *entry;
unsigned long flags; unsigned long flags;
struct irq_cfg *cfg = irq_cfg(irq);
spin_lock_irqsave(&ioapic_lock, flags); spin_lock_irqsave(&ioapic_lock, flags);
entry = cfg->irq_2_pin; entry = cfg->irq_2_pin;
...@@ -323,13 +361,12 @@ static void ioapic_mask_entry(int apic, int pin) ...@@ -323,13 +361,12 @@ static void ioapic_mask_entry(int apic, int pin)
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector) static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
{ {
int apic, pin; int apic, pin;
struct irq_cfg *cfg;
struct irq_pin_list *entry; struct irq_pin_list *entry;
u8 vector = cfg->vector;
cfg = irq_cfg(irq);
entry = cfg->irq_2_pin; entry = cfg->irq_2_pin;
for (;;) { for (;;) {
unsigned int reg; unsigned int reg;
...@@ -359,24 +396,27 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector) ...@@ -359,24 +396,27 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
} }
} }
static int assign_irq_vector(int irq, cpumask_t mask); static int assign_irq_vector(int irq, struct irq_cfg *cfg, cpumask_t mask);
static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) static void set_ioapic_affinity_irq_desc(struct irq_desc *desc, cpumask_t mask)
{ {
struct irq_cfg *cfg; struct irq_cfg *cfg;
unsigned long flags; unsigned long flags;
unsigned int dest; unsigned int dest;
cpumask_t tmp; cpumask_t tmp;
struct irq_desc *desc; unsigned int irq;
cpus_and(tmp, mask, cpu_online_map); cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp)) if (cpus_empty(tmp))
return; return;
cfg = irq_cfg(irq); irq = desc->irq;
if (assign_irq_vector(irq, mask)) cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return; return;
set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask); cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp); dest = cpu_mask_to_apicid(tmp);
/* /*
...@@ -384,12 +424,20 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) ...@@ -384,12 +424,20 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
*/ */
dest = SET_APIC_LOGICAL_ID(dest); dest = SET_APIC_LOGICAL_ID(dest);
desc = irq_to_desc(irq);
spin_lock_irqsave(&ioapic_lock, flags); spin_lock_irqsave(&ioapic_lock, flags);
__target_IO_APIC_irq(irq, dest, cfg->vector); __target_IO_APIC_irq(irq, dest, cfg);
desc->affinity = mask; desc->affinity = mask;
spin_unlock_irqrestore(&ioapic_lock, flags); spin_unlock_irqrestore(&ioapic_lock, flags);
} }
static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
{
struct irq_desc *desc;
desc = irq_to_desc(irq);
set_ioapic_affinity_irq_desc(desc, mask);
}
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
/* /*
...@@ -397,16 +445,18 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) ...@@ -397,16 +445,18 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
* shared ISA-space IRQs, so we have to support them. We are super * shared ISA-space IRQs, so we have to support them. We are super
* fast in the common case, and fast for shared ISA-space IRQs. * fast in the common case, and fast for shared ISA-space IRQs.
*/ */
static void add_pin_to_irq(unsigned int irq, int apic, int pin) static void add_pin_to_irq_cpu(struct irq_cfg *cfg, int cpu, int apic, int pin)
{ {
struct irq_cfg *cfg;
struct irq_pin_list *entry; struct irq_pin_list *entry;
/* first time to refer irq_cfg, so with new */
cfg = irq_cfg_alloc(irq);
entry = cfg->irq_2_pin; entry = cfg->irq_2_pin;
if (!entry) { if (!entry) {
entry = get_one_free_irq_2_pin(); entry = get_one_free_irq_2_pin(cpu);
if (!entry) {
printk(KERN_ERR "can not alloc irq_2_pin to add %d - %d\n",
apic, pin);
return;
}
cfg->irq_2_pin = entry; cfg->irq_2_pin = entry;
entry->apic = apic; entry->apic = apic;
entry->pin = pin; entry->pin = pin;
...@@ -421,7 +471,7 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin) ...@@ -421,7 +471,7 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
entry = entry->next; entry = entry->next;
} }
entry->next = get_one_free_irq_2_pin(); entry->next = get_one_free_irq_2_pin(cpu);
entry = entry->next; entry = entry->next;
entry->apic = apic; entry->apic = apic;
entry->pin = pin; entry->pin = pin;
...@@ -430,11 +480,10 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin) ...@@ -430,11 +480,10 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
/* /*
* Reroute an IRQ to a different pin. * Reroute an IRQ to a different pin.
*/ */
static void __init replace_pin_at_irq(unsigned int irq, static void __init replace_pin_at_irq_cpu(struct irq_cfg *cfg, int cpu,
int oldapic, int oldpin, int oldapic, int oldpin,
int newapic, int newpin) int newapic, int newpin)
{ {
struct irq_cfg *cfg = irq_cfg(irq);
struct irq_pin_list *entry = cfg->irq_2_pin; struct irq_pin_list *entry = cfg->irq_2_pin;
int replaced = 0; int replaced = 0;
...@@ -451,18 +500,16 @@ static void __init replace_pin_at_irq(unsigned int irq, ...@@ -451,18 +500,16 @@ static void __init replace_pin_at_irq(unsigned int irq,
/* why? call replace before add? */ /* why? call replace before add? */
if (!replaced) if (!replaced)
add_pin_to_irq(irq, newapic, newpin); add_pin_to_irq_cpu(cfg, cpu, newapic, newpin);
} }
static inline void io_apic_modify_irq(unsigned int irq, static inline void io_apic_modify_irq(struct irq_cfg *cfg,
int mask_and, int mask_or, int mask_and, int mask_or,
void (*final)(struct irq_pin_list *entry)) void (*final)(struct irq_pin_list *entry))
{ {
int pin; int pin;
struct irq_cfg *cfg;
struct irq_pin_list *entry; struct irq_pin_list *entry;
cfg = irq_cfg(irq);
for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) { for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) {
unsigned int reg; unsigned int reg;
pin = entry->pin; pin = entry->pin;
...@@ -475,9 +522,9 @@ static inline void io_apic_modify_irq(unsigned int irq, ...@@ -475,9 +522,9 @@ static inline void io_apic_modify_irq(unsigned int irq,
} }
} }
static void __unmask_IO_APIC_irq(unsigned int irq) static void __unmask_IO_APIC_irq(struct irq_cfg *cfg)
{ {
io_apic_modify_irq(irq, ~IO_APIC_REDIR_MASKED, 0, NULL); io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED, 0, NULL);
} }
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
...@@ -492,47 +539,64 @@ void io_apic_sync(struct irq_pin_list *entry) ...@@ -492,47 +539,64 @@ void io_apic_sync(struct irq_pin_list *entry)
readl(&io_apic->data); readl(&io_apic->data);
} }
static void __mask_IO_APIC_irq(unsigned int irq) static void __mask_IO_APIC_irq(struct irq_cfg *cfg)
{ {
io_apic_modify_irq(irq, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync); io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
} }
#else /* CONFIG_X86_32 */ #else /* CONFIG_X86_32 */
static void __mask_IO_APIC_irq(unsigned int irq) static void __mask_IO_APIC_irq(struct irq_cfg *cfg)
{ {
io_apic_modify_irq(irq, ~0, IO_APIC_REDIR_MASKED, NULL); io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, NULL);
} }
static void __mask_and_edge_IO_APIC_irq(unsigned int irq) static void __mask_and_edge_IO_APIC_irq(struct irq_cfg *cfg)
{ {
io_apic_modify_irq(irq, ~IO_APIC_REDIR_LEVEL_TRIGGER, io_apic_modify_irq(cfg, ~IO_APIC_REDIR_LEVEL_TRIGGER,
IO_APIC_REDIR_MASKED, NULL); IO_APIC_REDIR_MASKED, NULL);
} }
static void __unmask_and_level_IO_APIC_irq(unsigned int irq) static void __unmask_and_level_IO_APIC_irq(struct irq_cfg *cfg)
{ {
io_apic_modify_irq(irq, ~IO_APIC_REDIR_MASKED, io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED,
IO_APIC_REDIR_LEVEL_TRIGGER, NULL); IO_APIC_REDIR_LEVEL_TRIGGER, NULL);
} }
#endif /* CONFIG_X86_32 */ #endif /* CONFIG_X86_32 */
static void mask_IO_APIC_irq (unsigned int irq) static void mask_IO_APIC_irq_desc(struct irq_desc *desc)
{ {
struct irq_cfg *cfg = desc->chip_data;
unsigned long flags; unsigned long flags;
BUG_ON(!cfg);
spin_lock_irqsave(&ioapic_lock, flags); spin_lock_irqsave(&ioapic_lock, flags);
__mask_IO_APIC_irq(irq); __mask_IO_APIC_irq(cfg);
spin_unlock_irqrestore(&ioapic_lock, flags); spin_unlock_irqrestore(&ioapic_lock, flags);
} }
static void unmask_IO_APIC_irq (unsigned int irq) static void unmask_IO_APIC_irq_desc(struct irq_desc *desc)
{ {
struct irq_cfg *cfg = desc->chip_data;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ioapic_lock, flags); spin_lock_irqsave(&ioapic_lock, flags);
__unmask_IO_APIC_irq(irq); __unmask_IO_APIC_irq(cfg);
spin_unlock_irqrestore(&ioapic_lock, flags); spin_unlock_irqrestore(&ioapic_lock, flags);
} }
static void mask_IO_APIC_irq(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
mask_IO_APIC_irq_desc(desc);
}
static void unmask_IO_APIC_irq(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
unmask_IO_APIC_irq_desc(desc);
}
static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
{ {
struct IO_APIC_route_entry entry; struct IO_APIC_route_entry entry;
...@@ -809,7 +873,7 @@ EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); ...@@ -809,7 +873,7 @@ EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
*/ */
static int EISA_ELCR(unsigned int irq) static int EISA_ELCR(unsigned int irq)
{ {
if (irq < 16) { if (irq < NR_IRQS_LEGACY) {
unsigned int port = 0x4d0 + (irq >> 3); unsigned int port = 0x4d0 + (irq >> 3);
return (inb(port) >> (irq & 7)) & 1; return (inb(port) >> (irq & 7)) & 1;
} }
...@@ -1034,7 +1098,7 @@ void unlock_vector_lock(void) ...@@ -1034,7 +1098,7 @@ void unlock_vector_lock(void)
spin_unlock(&vector_lock); spin_unlock(&vector_lock);
} }
static int __assign_irq_vector(int irq, cpumask_t mask) static int __assign_irq_vector(int irq, struct irq_cfg *cfg, cpumask_t mask)
{ {
/* /*
* NOTE! The local APIC isn't very good at handling * NOTE! The local APIC isn't very good at handling
...@@ -1050,16 +1114,13 @@ static int __assign_irq_vector(int irq, cpumask_t mask) ...@@ -1050,16 +1114,13 @@ static int __assign_irq_vector(int irq, cpumask_t mask)
static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0; static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0;
unsigned int old_vector; unsigned int old_vector;
int cpu; int cpu;
struct irq_cfg *cfg;
cfg = irq_cfg(irq); if ((cfg->move_in_progress) || cfg->move_cleanup_count)
return -EBUSY;
/* Only try and allocate irqs on cpus that are present */ /* Only try and allocate irqs on cpus that are present */
cpus_and(mask, mask, cpu_online_map); cpus_and(mask, mask, cpu_online_map);
if ((cfg->move_in_progress) || cfg->move_cleanup_count)
return -EBUSY;
old_vector = cfg->vector; old_vector = cfg->vector;
if (old_vector) { if (old_vector) {
cpumask_t tmp; cpumask_t tmp;
...@@ -1113,24 +1174,22 @@ static int __assign_irq_vector(int irq, cpumask_t mask) ...@@ -1113,24 +1174,22 @@ static int __assign_irq_vector(int irq, cpumask_t mask)
return -ENOSPC; return -ENOSPC;
} }
static int assign_irq_vector(int irq, cpumask_t mask) static int assign_irq_vector(int irq, struct irq_cfg *cfg, cpumask_t mask)
{ {
int err; int err;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&vector_lock, flags); spin_lock_irqsave(&vector_lock, flags);
err = __assign_irq_vector(irq, mask); err = __assign_irq_vector(irq, cfg, mask);
spin_unlock_irqrestore(&vector_lock, flags); spin_unlock_irqrestore(&vector_lock, flags);
return err; return err;
} }
static void __clear_irq_vector(int irq) static void __clear_irq_vector(int irq, struct irq_cfg *cfg)
{ {
struct irq_cfg *cfg;
cpumask_t mask; cpumask_t mask;
int cpu, vector; int cpu, vector;
cfg = irq_cfg(irq);
BUG_ON(!cfg->vector); BUG_ON(!cfg->vector);
vector = cfg->vector; vector = cfg->vector;
...@@ -1162,9 +1221,13 @@ void __setup_vector_irq(int cpu) ...@@ -1162,9 +1221,13 @@ void __setup_vector_irq(int cpu)
/* This function must be called with vector_lock held */ /* This function must be called with vector_lock held */
int irq, vector; int irq, vector;
struct irq_cfg *cfg; struct irq_cfg *cfg;
struct irq_desc *desc;
/* Mark the inuse vectors */ /* Mark the inuse vectors */
for_each_irq_cfg(irq, cfg) { for_each_irq_desc(irq, desc) {
if (!desc)
continue;
cfg = desc->chip_data;
if (!cpu_isset(cpu, cfg->domain)) if (!cpu_isset(cpu, cfg->domain))
continue; continue;
vector = cfg->vector; vector = cfg->vector;
...@@ -1215,11 +1278,8 @@ static inline int IO_APIC_irq_trigger(int irq) ...@@ -1215,11 +1278,8 @@ static inline int IO_APIC_irq_trigger(int irq)
} }
#endif #endif
static void ioapic_register_intr(int irq, unsigned long trigger) static void ioapic_register_intr(int irq, struct irq_desc *desc, unsigned long trigger)
{ {
struct irq_desc *desc;
desc = irq_to_desc(irq);
if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) || if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
trigger == IOAPIC_LEVEL) trigger == IOAPIC_LEVEL)
...@@ -1311,7 +1371,7 @@ static int setup_ioapic_entry(int apic, int irq, ...@@ -1311,7 +1371,7 @@ static int setup_ioapic_entry(int apic, int irq,
return 0; return 0;
} }
static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq, static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq, struct irq_desc *desc,
int trigger, int polarity) int trigger, int polarity)
{ {
struct irq_cfg *cfg; struct irq_cfg *cfg;
...@@ -1321,10 +1381,10 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq, ...@@ -1321,10 +1381,10 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
if (!IO_APIC_IRQ(irq)) if (!IO_APIC_IRQ(irq))
return; return;
cfg = irq_cfg(irq); cfg = desc->chip_data;
mask = TARGET_CPUS; mask = TARGET_CPUS;
if (assign_irq_vector(irq, mask)) if (assign_irq_vector(irq, cfg, mask))
return; return;
cpus_and(mask, cfg->domain, mask); cpus_and(mask, cfg->domain, mask);
...@@ -1341,12 +1401,12 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq, ...@@ -1341,12 +1401,12 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
cfg->vector)) { cfg->vector)) {
printk("Failed to setup ioapic entry for ioapic %d, pin %d\n", printk("Failed to setup ioapic entry for ioapic %d, pin %d\n",
mp_ioapics[apic].mp_apicid, pin); mp_ioapics[apic].mp_apicid, pin);
__clear_irq_vector(irq); __clear_irq_vector(irq, cfg);
return; return;
} }
ioapic_register_intr(irq, trigger); ioapic_register_intr(irq, desc, trigger);
if (irq < 16) if (irq < NR_IRQS_LEGACY)
disable_8259A_irq(irq); disable_8259A_irq(irq);
ioapic_write_entry(apic, pin, entry); ioapic_write_entry(apic, pin, entry);
...@@ -1356,6 +1416,9 @@ static void __init setup_IO_APIC_irqs(void) ...@@ -1356,6 +1416,9 @@ static void __init setup_IO_APIC_irqs(void)
{ {
int apic, pin, idx, irq; int apic, pin, idx, irq;
int notcon = 0; int notcon = 0;
struct irq_desc *desc;
struct irq_cfg *cfg;
int cpu = boot_cpu_id;
apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n");
...@@ -1387,9 +1450,15 @@ static void __init setup_IO_APIC_irqs(void) ...@@ -1387,9 +1450,15 @@ static void __init setup_IO_APIC_irqs(void)
if (multi_timer_check(apic, irq)) if (multi_timer_check(apic, irq))
continue; continue;
#endif #endif
add_pin_to_irq(irq, apic, pin); desc = irq_to_desc_alloc_cpu(irq, cpu);
if (!desc) {
printk(KERN_INFO "can not get irq_desc for %d\n", irq);
continue;
}
cfg = desc->chip_data;
add_pin_to_irq_cpu(cfg, cpu, apic, pin);
setup_IO_APIC_irq(apic, pin, irq, setup_IO_APIC_irq(apic, pin, irq, desc,
irq_trigger(idx), irq_polarity(idx)); irq_trigger(idx), irq_polarity(idx));
} }
} }
...@@ -1448,6 +1517,7 @@ __apicdebuginit(void) print_IO_APIC(void) ...@@ -1448,6 +1517,7 @@ __apicdebuginit(void) print_IO_APIC(void)
union IO_APIC_reg_03 reg_03; union IO_APIC_reg_03 reg_03;
unsigned long flags; unsigned long flags;
struct irq_cfg *cfg; struct irq_cfg *cfg;
struct irq_desc *desc;
unsigned int irq; unsigned int irq;
if (apic_verbosity == APIC_QUIET) if (apic_verbosity == APIC_QUIET)
...@@ -1537,8 +1607,13 @@ __apicdebuginit(void) print_IO_APIC(void) ...@@ -1537,8 +1607,13 @@ __apicdebuginit(void) print_IO_APIC(void)
} }
} }
printk(KERN_DEBUG "IRQ to pin mappings:\n"); printk(KERN_DEBUG "IRQ to pin mappings:\n");
for_each_irq_cfg(irq, cfg) { for_each_irq_desc(irq, desc) {
struct irq_pin_list *entry = cfg->irq_2_pin; struct irq_pin_list *entry;
if (!desc)
continue;
cfg = desc->chip_data;
entry = cfg->irq_2_pin;
if (!entry) if (!entry)
continue; continue;
printk(KERN_DEBUG "IRQ%d ", irq); printk(KERN_DEBUG "IRQ%d ", irq);
...@@ -2022,14 +2097,16 @@ static unsigned int startup_ioapic_irq(unsigned int irq) ...@@ -2022,14 +2097,16 @@ static unsigned int startup_ioapic_irq(unsigned int irq)
{ {
int was_pending = 0; int was_pending = 0;
unsigned long flags; unsigned long flags;
struct irq_cfg *cfg;
spin_lock_irqsave(&ioapic_lock, flags); spin_lock_irqsave(&ioapic_lock, flags);
if (irq < 16) { if (irq < NR_IRQS_LEGACY) {
disable_8259A_irq(irq); disable_8259A_irq(irq);
if (i8259A_irq_pending(irq)) if (i8259A_irq_pending(irq))
was_pending = 1; was_pending = 1;
} }
__unmask_IO_APIC_irq(irq); cfg = irq_cfg(irq);
__unmask_IO_APIC_irq(cfg);
spin_unlock_irqrestore(&ioapic_lock, flags); spin_unlock_irqrestore(&ioapic_lock, flags);
return was_pending; return was_pending;
...@@ -2092,35 +2169,37 @@ static DECLARE_DELAYED_WORK(ir_migration_work, ir_irq_migration); ...@@ -2092,35 +2169,37 @@ static DECLARE_DELAYED_WORK(ir_migration_work, ir_irq_migration);
* as simple as edge triggered migration and we can do the irq migration * as simple as edge triggered migration and we can do the irq migration
* with a simple atomic update to IO-APIC RTE. * with a simple atomic update to IO-APIC RTE.
*/ */
static void migrate_ioapic_irq(int irq, cpumask_t mask) static void migrate_ioapic_irq_desc(struct irq_desc *desc, cpumask_t mask)
{ {
struct irq_cfg *cfg; struct irq_cfg *cfg;
struct irq_desc *desc;
cpumask_t tmp, cleanup_mask; cpumask_t tmp, cleanup_mask;
struct irte irte; struct irte irte;
int modify_ioapic_rte; int modify_ioapic_rte;
unsigned int dest; unsigned int dest;
unsigned long flags; unsigned long flags;
unsigned int irq;
cpus_and(tmp, mask, cpu_online_map); cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp)) if (cpus_empty(tmp))
return; return;
irq = desc->irq;
if (get_irte(irq, &irte)) if (get_irte(irq, &irte))
return; return;
if (assign_irq_vector(irq, mask)) cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return; return;
cfg = irq_cfg(irq); set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask); cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp); dest = cpu_mask_to_apicid(tmp);
desc = irq_to_desc(irq);
modify_ioapic_rte = desc->status & IRQ_LEVEL; modify_ioapic_rte = desc->status & IRQ_LEVEL;
if (modify_ioapic_rte) { if (modify_ioapic_rte) {
spin_lock_irqsave(&ioapic_lock, flags); spin_lock_irqsave(&ioapic_lock, flags);
__target_IO_APIC_irq(irq, dest, cfg->vector); __target_IO_APIC_irq(irq, dest, cfg);
spin_unlock_irqrestore(&ioapic_lock, flags); spin_unlock_irqrestore(&ioapic_lock, flags);
} }
...@@ -2142,14 +2221,14 @@ static void migrate_ioapic_irq(int irq, cpumask_t mask) ...@@ -2142,14 +2221,14 @@ static void migrate_ioapic_irq(int irq, cpumask_t mask)
desc->affinity = mask; desc->affinity = mask;
} }
static int migrate_irq_remapped_level(int irq) static int migrate_irq_remapped_level_desc(struct irq_desc *desc)
{ {
int ret = -1; int ret = -1;
struct irq_desc *desc = irq_to_desc(irq); struct irq_cfg *cfg = desc->chip_data;
mask_IO_APIC_irq(irq); mask_IO_APIC_irq_desc(desc);
if (io_apic_level_ack_pending(irq)) { if (io_apic_level_ack_pending(cfg)) {
/* /*
* Interrupt in progress. Migrating irq now will change the * Interrupt in progress. Migrating irq now will change the
* vector information in the IO-APIC RTE and that will confuse * vector information in the IO-APIC RTE and that will confuse
...@@ -2161,14 +2240,15 @@ static int migrate_irq_remapped_level(int irq) ...@@ -2161,14 +2240,15 @@ static int migrate_irq_remapped_level(int irq)
} }
/* everthing is clear. we have right of way */ /* everthing is clear. we have right of way */
migrate_ioapic_irq(irq, desc->pending_mask); migrate_ioapic_irq_desc(desc, desc->pending_mask);
ret = 0; ret = 0;
desc->status &= ~IRQ_MOVE_PENDING; desc->status &= ~IRQ_MOVE_PENDING;
cpus_clear(desc->pending_mask); cpus_clear(desc->pending_mask);
unmask: unmask:
unmask_IO_APIC_irq(irq); unmask_IO_APIC_irq_desc(desc);
return ret; return ret;
} }
...@@ -2178,6 +2258,9 @@ static void ir_irq_migration(struct work_struct *work) ...@@ -2178,6 +2258,9 @@ static void ir_irq_migration(struct work_struct *work)
struct irq_desc *desc; struct irq_desc *desc;
for_each_irq_desc(irq, desc) { for_each_irq_desc(irq, desc) {
if (!desc)
continue;
if (desc->status & IRQ_MOVE_PENDING) { if (desc->status & IRQ_MOVE_PENDING) {
unsigned long flags; unsigned long flags;
...@@ -2198,18 +2281,22 @@ static void ir_irq_migration(struct work_struct *work) ...@@ -2198,18 +2281,22 @@ static void ir_irq_migration(struct work_struct *work)
/* /*
* Migrates the IRQ destination in the process context. * Migrates the IRQ destination in the process context.
*/ */
static void set_ir_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) static void set_ir_ioapic_affinity_irq_desc(struct irq_desc *desc, cpumask_t mask)
{ {
struct irq_desc *desc = irq_to_desc(irq);
if (desc->status & IRQ_LEVEL) { if (desc->status & IRQ_LEVEL) {
desc->status |= IRQ_MOVE_PENDING; desc->status |= IRQ_MOVE_PENDING;
desc->pending_mask = mask; desc->pending_mask = mask;
migrate_irq_remapped_level(irq); migrate_irq_remapped_level_desc(desc);
return; return;
} }
migrate_ioapic_irq(irq, mask); migrate_ioapic_irq_desc(desc, mask);
}
static void set_ir_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
{
struct irq_desc *desc = irq_to_desc(irq);
set_ir_ioapic_affinity_irq_desc(desc, mask);
} }
#endif #endif
...@@ -2229,6 +2316,9 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void) ...@@ -2229,6 +2316,9 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
struct irq_cfg *cfg; struct irq_cfg *cfg;
irq = __get_cpu_var(vector_irq)[vector]; irq = __get_cpu_var(vector_irq)[vector];
if (irq == -1)
continue;
desc = irq_to_desc(irq); desc = irq_to_desc(irq);
if (!desc) if (!desc)
continue; continue;
...@@ -2250,9 +2340,10 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void) ...@@ -2250,9 +2340,10 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
irq_exit(); irq_exit();
} }
static void irq_complete_move(unsigned int irq) static void irq_complete_move(struct irq_desc **descp)
{ {
struct irq_cfg *cfg = irq_cfg(irq); struct irq_desc *desc = *descp;
struct irq_cfg *cfg = desc->chip_data;
unsigned vector, me; unsigned vector, me;
if (likely(!cfg->move_in_progress)) if (likely(!cfg->move_in_progress))
...@@ -2270,8 +2361,9 @@ static void irq_complete_move(unsigned int irq) ...@@ -2270,8 +2361,9 @@ static void irq_complete_move(unsigned int irq)
} }
} }
#else #else
static inline void irq_complete_move(unsigned int irq) {} static inline void irq_complete_move(struct irq_desc **descp) {}
#endif #endif
#ifdef CONFIG_INTR_REMAP #ifdef CONFIG_INTR_REMAP
static void ack_x2apic_level(unsigned int irq) static void ack_x2apic_level(unsigned int irq)
{ {
...@@ -2282,11 +2374,14 @@ static void ack_x2apic_edge(unsigned int irq) ...@@ -2282,11 +2374,14 @@ static void ack_x2apic_edge(unsigned int irq)
{ {
ack_x2APIC_irq(); ack_x2APIC_irq();
} }
#endif #endif
static void ack_apic_edge(unsigned int irq) static void ack_apic_edge(unsigned int irq)
{ {
irq_complete_move(irq); struct irq_desc *desc = irq_to_desc(irq);
irq_complete_move(&desc);
move_native_irq(irq); move_native_irq(irq);
ack_APIC_irq(); ack_APIC_irq();
} }
...@@ -2295,18 +2390,21 @@ atomic_t irq_mis_count; ...@@ -2295,18 +2390,21 @@ atomic_t irq_mis_count;
static void ack_apic_level(unsigned int irq) static void ack_apic_level(unsigned int irq)
{ {
struct irq_desc *desc = irq_to_desc(irq);
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
unsigned long v; unsigned long v;
int i; int i;
#endif #endif
struct irq_cfg *cfg;
int do_unmask_irq = 0; int do_unmask_irq = 0;
irq_complete_move(irq); irq_complete_move(&desc);
#ifdef CONFIG_GENERIC_PENDING_IRQ #ifdef CONFIG_GENERIC_PENDING_IRQ
/* If we are moving the irq we need to mask it */ /* If we are moving the irq we need to mask it */
if (unlikely(irq_to_desc(irq)->status & IRQ_MOVE_PENDING)) { if (unlikely(desc->status & IRQ_MOVE_PENDING)) {
do_unmask_irq = 1; do_unmask_irq = 1;
mask_IO_APIC_irq(irq); mask_IO_APIC_irq_desc(desc);
} }
#endif #endif
...@@ -2330,7 +2428,8 @@ static void ack_apic_level(unsigned int irq) ...@@ -2330,7 +2428,8 @@ static void ack_apic_level(unsigned int irq)
* operation to prevent an edge-triggered interrupt escaping meanwhile. * operation to prevent an edge-triggered interrupt escaping meanwhile.
* The idea is from Manfred Spraul. --macro * The idea is from Manfred Spraul. --macro
*/ */
i = irq_cfg(irq)->vector; cfg = desc->chip_data;
i = cfg->vector;
v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1)); v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
#endif #endif
...@@ -2369,17 +2468,18 @@ static void ack_apic_level(unsigned int irq) ...@@ -2369,17 +2468,18 @@ static void ack_apic_level(unsigned int irq)
* accurate and is causing problems then it is a hardware bug * accurate and is causing problems then it is a hardware bug
* and you can go talk to the chipset vendor about it. * and you can go talk to the chipset vendor about it.
*/ */
if (!io_apic_level_ack_pending(irq)) cfg = desc->chip_data;
if (!io_apic_level_ack_pending(cfg))
move_masked_irq(irq); move_masked_irq(irq);
unmask_IO_APIC_irq(irq); unmask_IO_APIC_irq_desc(desc);
} }
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
if (!(v & (1 << (i & 0x1f)))) { if (!(v & (1 << (i & 0x1f)))) {
atomic_inc(&irq_mis_count); atomic_inc(&irq_mis_count);
spin_lock(&ioapic_lock); spin_lock(&ioapic_lock);
__mask_and_edge_IO_APIC_irq(irq); __mask_and_edge_IO_APIC_irq(cfg);
__unmask_and_level_IO_APIC_irq(irq); __unmask_and_level_IO_APIC_irq(cfg);
spin_unlock(&ioapic_lock); spin_unlock(&ioapic_lock);
} }
#endif #endif
...@@ -2430,22 +2530,24 @@ static inline void init_IO_APIC_traps(void) ...@@ -2430,22 +2530,24 @@ static inline void init_IO_APIC_traps(void)
* Also, we've got to be careful not to trash gate * Also, we've got to be careful not to trash gate
* 0x80, because int 0x80 is hm, kind of importantish. ;) * 0x80, because int 0x80 is hm, kind of importantish. ;)
*/ */
for_each_irq_cfg(irq, cfg) { for_each_irq_desc(irq, desc) {
if (IO_APIC_IRQ(irq) && !cfg->vector) { if (!desc)
continue;
cfg = desc->chip_data;
if (IO_APIC_IRQ(irq) && cfg && !cfg->vector) {
/* /*
* Hmm.. We don't have an entry for this, * Hmm.. We don't have an entry for this,
* so default to an old-fashioned 8259 * so default to an old-fashioned 8259
* interrupt if we can.. * interrupt if we can..
*/ */
if (irq < 16) if (irq < NR_IRQS_LEGACY)
make_8259A_irq(irq); make_8259A_irq(irq);
else { else
desc = irq_to_desc(irq);
/* Strange. Oh, well.. */ /* Strange. Oh, well.. */
desc->chip = &no_irq_chip; desc->chip = &no_irq_chip;
} }
} }
}
} }
/* /*
...@@ -2468,7 +2570,7 @@ static void unmask_lapic_irq(unsigned int irq) ...@@ -2468,7 +2570,7 @@ static void unmask_lapic_irq(unsigned int irq)
apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED); apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED);
} }
static void ack_lapic_irq (unsigned int irq) static void ack_lapic_irq(unsigned int irq)
{ {
ack_APIC_irq(); ack_APIC_irq();
} }
...@@ -2480,11 +2582,8 @@ static struct irq_chip lapic_chip __read_mostly = { ...@@ -2480,11 +2582,8 @@ static struct irq_chip lapic_chip __read_mostly = {
.ack = ack_lapic_irq, .ack = ack_lapic_irq,
}; };
static void lapic_register_intr(int irq) static void lapic_register_intr(int irq, struct irq_desc *desc)
{ {
struct irq_desc *desc;
desc = irq_to_desc(irq);
desc->status &= ~IRQ_LEVEL; desc->status &= ~IRQ_LEVEL;
set_irq_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq, set_irq_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq,
"edge"); "edge");
...@@ -2588,7 +2687,9 @@ int timer_through_8259 __initdata; ...@@ -2588,7 +2687,9 @@ int timer_through_8259 __initdata;
*/ */
static inline void __init check_timer(void) static inline void __init check_timer(void)
{ {
struct irq_cfg *cfg = irq_cfg(0); struct irq_desc *desc = irq_to_desc(0);
struct irq_cfg *cfg = desc->chip_data;
int cpu = boot_cpu_id;
int apic1, pin1, apic2, pin2; int apic1, pin1, apic2, pin2;
unsigned long flags; unsigned long flags;
unsigned int ver; unsigned int ver;
...@@ -2603,7 +2704,7 @@ static inline void __init check_timer(void) ...@@ -2603,7 +2704,7 @@ static inline void __init check_timer(void)
* get/set the timer IRQ vector: * get/set the timer IRQ vector:
*/ */
disable_8259A_irq(0); disable_8259A_irq(0);
assign_irq_vector(0, TARGET_CPUS); assign_irq_vector(0, cfg, TARGET_CPUS);
/* /*
* As IRQ0 is to be enabled in the 8259A, the virtual * As IRQ0 is to be enabled in the 8259A, the virtual
...@@ -2654,10 +2755,10 @@ static inline void __init check_timer(void) ...@@ -2654,10 +2755,10 @@ static inline void __init check_timer(void)
* Ok, does IRQ0 through the IOAPIC work? * Ok, does IRQ0 through the IOAPIC work?
*/ */
if (no_pin1) { if (no_pin1) {
add_pin_to_irq(0, apic1, pin1); add_pin_to_irq_cpu(cfg, cpu, apic1, pin1);
setup_timer_IRQ0_pin(apic1, pin1, cfg->vector); setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
} }
unmask_IO_APIC_irq(0); unmask_IO_APIC_irq_desc(desc);
if (timer_irq_works()) { if (timer_irq_works()) {
if (nmi_watchdog == NMI_IO_APIC) { if (nmi_watchdog == NMI_IO_APIC) {
setup_nmi(); setup_nmi();
...@@ -2683,9 +2784,9 @@ static inline void __init check_timer(void) ...@@ -2683,9 +2784,9 @@ static inline void __init check_timer(void)
/* /*
* legacy devices should be connected to IO APIC #0 * legacy devices should be connected to IO APIC #0
*/ */
replace_pin_at_irq(0, apic1, pin1, apic2, pin2); replace_pin_at_irq_cpu(cfg, cpu, apic1, pin1, apic2, pin2);
setup_timer_IRQ0_pin(apic2, pin2, cfg->vector); setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
unmask_IO_APIC_irq(0); unmask_IO_APIC_irq_desc(desc);
enable_8259A_irq(0); enable_8259A_irq(0);
if (timer_irq_works()) { if (timer_irq_works()) {
apic_printk(APIC_QUIET, KERN_INFO "....... works.\n"); apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
...@@ -2717,7 +2818,7 @@ static inline void __init check_timer(void) ...@@ -2717,7 +2818,7 @@ static inline void __init check_timer(void)
apic_printk(APIC_QUIET, KERN_INFO apic_printk(APIC_QUIET, KERN_INFO
"...trying to set up timer as Virtual Wire IRQ...\n"); "...trying to set up timer as Virtual Wire IRQ...\n");
lapic_register_intr(0); lapic_register_intr(0, desc);
apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */ apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */
enable_8259A_irq(0); enable_8259A_irq(0);
...@@ -2902,22 +3003,26 @@ unsigned int create_irq_nr(unsigned int irq_want) ...@@ -2902,22 +3003,26 @@ unsigned int create_irq_nr(unsigned int irq_want)
unsigned int irq; unsigned int irq;
unsigned int new; unsigned int new;
unsigned long flags; unsigned long flags;
struct irq_cfg *cfg_new; struct irq_cfg *cfg_new = NULL;
int cpu = boot_cpu_id;
irq_want = nr_irqs - 1; struct irq_desc *desc_new = NULL;
irq = 0; irq = 0;
spin_lock_irqsave(&vector_lock, flags); spin_lock_irqsave(&vector_lock, flags);
for (new = irq_want; new > 0; new--) { for (new = irq_want; new < NR_IRQS; new++) {
if (platform_legacy_irq(new)) if (platform_legacy_irq(new))
continue; continue;
cfg_new = irq_cfg(new);
if (cfg_new && cfg_new->vector != 0) desc_new = irq_to_desc_alloc_cpu(new, cpu);
if (!desc_new) {
printk(KERN_INFO "can not get irq_desc for %d\n", new);
continue;
}
cfg_new = desc_new->chip_data;
if (cfg_new->vector != 0)
continue; continue;
/* check if need to create one */ if (__assign_irq_vector(new, cfg_new, TARGET_CPUS) == 0)
if (!cfg_new)
cfg_new = irq_cfg_alloc(new);
if (__assign_irq_vector(new, TARGET_CPUS) == 0)
irq = new; irq = new;
break; break;
} }
...@@ -2925,15 +3030,21 @@ unsigned int create_irq_nr(unsigned int irq_want) ...@@ -2925,15 +3030,21 @@ unsigned int create_irq_nr(unsigned int irq_want)
if (irq > 0) { if (irq > 0) {
dynamic_irq_init(irq); dynamic_irq_init(irq);
/* restore it, in case dynamic_irq_init clear it */
if (desc_new)
desc_new->chip_data = cfg_new;
} }
return irq; return irq;
} }
static int nr_irqs_gsi = NR_IRQS_LEGACY;
int create_irq(void) int create_irq(void)
{ {
unsigned int irq_want;
int irq; int irq;
irq = create_irq_nr(nr_irqs - 1); irq_want = nr_irqs_gsi;
irq = create_irq_nr(irq_want);
if (irq == 0) if (irq == 0)
irq = -1; irq = -1;
...@@ -2944,14 +3055,22 @@ int create_irq(void) ...@@ -2944,14 +3055,22 @@ int create_irq(void)
void destroy_irq(unsigned int irq) void destroy_irq(unsigned int irq)
{ {
unsigned long flags; unsigned long flags;
struct irq_cfg *cfg;
struct irq_desc *desc;
/* store it, in case dynamic_irq_cleanup clear it */
desc = irq_to_desc(irq);
cfg = desc->chip_data;
dynamic_irq_cleanup(irq); dynamic_irq_cleanup(irq);
/* connect back irq_cfg */
if (desc)
desc->chip_data = cfg;
#ifdef CONFIG_INTR_REMAP #ifdef CONFIG_INTR_REMAP
free_irte(irq); free_irte(irq);
#endif #endif
spin_lock_irqsave(&vector_lock, flags); spin_lock_irqsave(&vector_lock, flags);
__clear_irq_vector(irq); __clear_irq_vector(irq, cfg);
spin_unlock_irqrestore(&vector_lock, flags); spin_unlock_irqrestore(&vector_lock, flags);
} }
...@@ -2966,12 +3085,12 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms ...@@ -2966,12 +3085,12 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
unsigned dest; unsigned dest;
cpumask_t tmp; cpumask_t tmp;
cfg = irq_cfg(irq);
tmp = TARGET_CPUS; tmp = TARGET_CPUS;
err = assign_irq_vector(irq, tmp); err = assign_irq_vector(irq, cfg, tmp);
if (err) if (err)
return err; return err;
cfg = irq_cfg(irq);
cpus_and(tmp, cfg->domain, tmp); cpus_and(tmp, cfg->domain, tmp);
dest = cpu_mask_to_apicid(tmp); dest = cpu_mask_to_apicid(tmp);
...@@ -3029,35 +3148,35 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms ...@@ -3029,35 +3148,35 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
{ {
struct irq_desc *desc = irq_to_desc(irq);
struct irq_cfg *cfg; struct irq_cfg *cfg;
struct msi_msg msg; struct msi_msg msg;
unsigned int dest; unsigned int dest;
cpumask_t tmp; cpumask_t tmp;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map); cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp)) if (cpus_empty(tmp))
return; return;
if (assign_irq_vector(irq, mask)) cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return; return;
cfg = irq_cfg(irq); set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask); cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp); dest = cpu_mask_to_apicid(tmp);
read_msi_msg(irq, &msg); read_msi_msg_desc(desc, &msg);
msg.data &= ~MSI_DATA_VECTOR_MASK; msg.data &= ~MSI_DATA_VECTOR_MASK;
msg.data |= MSI_DATA_VECTOR(cfg->vector); msg.data |= MSI_DATA_VECTOR(cfg->vector);
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
msg.address_lo |= MSI_ADDR_DEST_ID(dest); msg.address_lo |= MSI_ADDR_DEST_ID(dest);
write_msi_msg(irq, &msg); write_msi_msg_desc(desc, &msg);
desc = irq_to_desc(irq);
desc->affinity = mask; desc->affinity = mask;
} }
#ifdef CONFIG_INTR_REMAP #ifdef CONFIG_INTR_REMAP
/* /*
* Migrate the MSI irq to another cpumask. This migration is * Migrate the MSI irq to another cpumask. This migration is
...@@ -3065,11 +3184,11 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask) ...@@ -3065,11 +3184,11 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
*/ */
static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask) static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
{ {
struct irq_desc *desc = irq_to_desc(irq);
struct irq_cfg *cfg; struct irq_cfg *cfg;
unsigned int dest; unsigned int dest;
cpumask_t tmp, cleanup_mask; cpumask_t tmp, cleanup_mask;
struct irte irte; struct irte irte;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map); cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp)) if (cpus_empty(tmp))
...@@ -3078,10 +3197,12 @@ static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask) ...@@ -3078,10 +3197,12 @@ static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
if (get_irte(irq, &irte)) if (get_irte(irq, &irte))
return; return;
if (assign_irq_vector(irq, mask)) cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return; return;
cfg = irq_cfg(irq); set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask); cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp); dest = cpu_mask_to_apicid(tmp);
...@@ -3105,9 +3226,9 @@ static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask) ...@@ -3105,9 +3226,9 @@ static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
cfg->move_in_progress = 0; cfg->move_in_progress = 0;
} }
desc = irq_to_desc(irq);
desc->affinity = mask; desc->affinity = mask;
} }
#endif #endif
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
...@@ -3166,7 +3287,7 @@ static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec) ...@@ -3166,7 +3287,7 @@ static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec)
} }
#endif #endif
static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq) static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int irq)
{ {
int ret; int ret;
struct msi_msg msg; struct msi_msg msg;
...@@ -3175,7 +3296,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq) ...@@ -3175,7 +3296,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
if (ret < 0) if (ret < 0)
return ret; return ret;
set_irq_msi(irq, desc); set_irq_msi(irq, msidesc);
write_msi_msg(irq, &msg); write_msi_msg(irq, &msg);
#ifdef CONFIG_INTR_REMAP #ifdef CONFIG_INTR_REMAP
...@@ -3195,26 +3316,13 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq) ...@@ -3195,26 +3316,13 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
return 0; return 0;
} }
static unsigned int build_irq_for_pci_dev(struct pci_dev *dev) int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc)
{
unsigned int irq;
irq = dev->bus->number;
irq <<= 8;
irq |= dev->devfn;
irq <<= 12;
return irq;
}
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
{ {
unsigned int irq; unsigned int irq;
int ret; int ret;
unsigned int irq_want; unsigned int irq_want;
irq_want = build_irq_for_pci_dev(dev) + 0x100; irq_want = nr_irqs_gsi;
irq = create_irq_nr(irq_want); irq = create_irq_nr(irq_want);
if (irq == 0) if (irq == 0)
return -1; return -1;
...@@ -3228,7 +3336,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc) ...@@ -3228,7 +3336,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
goto error; goto error;
no_ir: no_ir:
#endif #endif
ret = setup_msi_irq(dev, desc, irq); ret = setup_msi_irq(dev, msidesc, irq);
if (ret < 0) { if (ret < 0) {
destroy_irq(irq); destroy_irq(irq);
return ret; return ret;
...@@ -3246,7 +3354,7 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) ...@@ -3246,7 +3354,7 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{ {
unsigned int irq; unsigned int irq;
int ret, sub_handle; int ret, sub_handle;
struct msi_desc *desc; struct msi_desc *msidesc;
unsigned int irq_want; unsigned int irq_want;
#ifdef CONFIG_INTR_REMAP #ifdef CONFIG_INTR_REMAP
...@@ -3254,10 +3362,11 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) ...@@ -3254,10 +3362,11 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
int index = 0; int index = 0;
#endif #endif
irq_want = build_irq_for_pci_dev(dev) + 0x100; irq_want = nr_irqs_gsi;
sub_handle = 0; sub_handle = 0;
list_for_each_entry(desc, &dev->msi_list, list) { list_for_each_entry(msidesc, &dev->msi_list, list) {
irq = create_irq_nr(irq_want--); irq = create_irq_nr(irq_want);
irq_want++;
if (irq == 0) if (irq == 0)
return -1; return -1;
#ifdef CONFIG_INTR_REMAP #ifdef CONFIG_INTR_REMAP
...@@ -3289,7 +3398,7 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) ...@@ -3289,7 +3398,7 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
} }
no_ir: no_ir:
#endif #endif
ret = setup_msi_irq(dev, desc, irq); ret = setup_msi_irq(dev, msidesc, irq);
if (ret < 0) if (ret < 0)
goto error; goto error;
sub_handle++; sub_handle++;
...@@ -3310,20 +3419,22 @@ void arch_teardown_msi_irq(unsigned int irq) ...@@ -3310,20 +3419,22 @@ void arch_teardown_msi_irq(unsigned int irq)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask) static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask)
{ {
struct irq_desc *desc = irq_to_desc(irq);
struct irq_cfg *cfg; struct irq_cfg *cfg;
struct msi_msg msg; struct msi_msg msg;
unsigned int dest; unsigned int dest;
cpumask_t tmp; cpumask_t tmp;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map); cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp)) if (cpus_empty(tmp))
return; return;
if (assign_irq_vector(irq, mask)) cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return; return;
cfg = irq_cfg(irq); set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask); cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp); dest = cpu_mask_to_apicid(tmp);
...@@ -3335,9 +3446,9 @@ static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask) ...@@ -3335,9 +3446,9 @@ static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask)
msg.address_lo |= MSI_ADDR_DEST_ID(dest); msg.address_lo |= MSI_ADDR_DEST_ID(dest);
dmar_msi_write(irq, &msg); dmar_msi_write(irq, &msg);
desc = irq_to_desc(irq);
desc->affinity = mask; desc->affinity = mask;
} }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
struct irq_chip dmar_msi_type = { struct irq_chip dmar_msi_type = {
...@@ -3371,8 +3482,8 @@ int arch_setup_dmar_msi(unsigned int irq) ...@@ -3371,8 +3482,8 @@ int arch_setup_dmar_msi(unsigned int irq)
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask) static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask)
{ {
struct irq_desc *desc = irq_to_desc(irq);
struct irq_cfg *cfg; struct irq_cfg *cfg;
struct irq_desc *desc;
struct msi_msg msg; struct msi_msg msg;
unsigned int dest; unsigned int dest;
cpumask_t tmp; cpumask_t tmp;
...@@ -3381,10 +3492,12 @@ static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask) ...@@ -3381,10 +3492,12 @@ static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask)
if (cpus_empty(tmp)) if (cpus_empty(tmp))
return; return;
if (assign_irq_vector(irq, mask)) cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return; return;
cfg = irq_cfg(irq); set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask); cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp); dest = cpu_mask_to_apicid(tmp);
...@@ -3396,9 +3509,9 @@ static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask) ...@@ -3396,9 +3509,9 @@ static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask)
msg.address_lo |= MSI_ADDR_DEST_ID(dest); msg.address_lo |= MSI_ADDR_DEST_ID(dest);
hpet_msi_write(irq, &msg); hpet_msi_write(irq, &msg);
desc = irq_to_desc(irq);
desc->affinity = mask; desc->affinity = mask;
} }
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
struct irq_chip hpet_msi_type = { struct irq_chip hpet_msi_type = {
...@@ -3453,26 +3566,28 @@ static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector) ...@@ -3453,26 +3566,28 @@ static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask) static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
{ {
struct irq_desc *desc = irq_to_desc(irq);
struct irq_cfg *cfg; struct irq_cfg *cfg;
unsigned int dest; unsigned int dest;
cpumask_t tmp; cpumask_t tmp;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map); cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp)) if (cpus_empty(tmp))
return; return;
if (assign_irq_vector(irq, mask)) cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return; return;
cfg = irq_cfg(irq); set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask); cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp); dest = cpu_mask_to_apicid(tmp);
target_ht_irq(irq, dest, cfg->vector); target_ht_irq(irq, dest, cfg->vector);
desc = irq_to_desc(irq);
desc->affinity = mask; desc->affinity = mask;
} }
#endif #endif
static struct irq_chip ht_irq_chip = { static struct irq_chip ht_irq_chip = {
...@@ -3492,13 +3607,13 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev) ...@@ -3492,13 +3607,13 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
int err; int err;
cpumask_t tmp; cpumask_t tmp;
cfg = irq_cfg(irq);
tmp = TARGET_CPUS; tmp = TARGET_CPUS;
err = assign_irq_vector(irq, tmp); err = assign_irq_vector(irq, cfg, tmp);
if (!err) { if (!err) {
struct ht_irq_msg msg; struct ht_irq_msg msg;
unsigned dest; unsigned dest;
cfg = irq_cfg(irq);
cpus_and(tmp, cfg->domain, tmp); cpus_and(tmp, cfg->domain, tmp);
dest = cpu_mask_to_apicid(tmp); dest = cpu_mask_to_apicid(tmp);
...@@ -3544,7 +3659,9 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade, ...@@ -3544,7 +3659,9 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
unsigned long flags; unsigned long flags;
int err; int err;
err = assign_irq_vector(irq, *eligible_cpu); cfg = irq_cfg(irq);
err = assign_irq_vector(irq, cfg, *eligible_cpu);
if (err != 0) if (err != 0)
return err; return err;
...@@ -3553,8 +3670,6 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade, ...@@ -3553,8 +3670,6 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
irq_name); irq_name);
spin_unlock_irqrestore(&vector_lock, flags); spin_unlock_irqrestore(&vector_lock, flags);
cfg = irq_cfg(irq);
mmr_value = 0; mmr_value = 0;
entry = (struct uv_IO_APIC_route_entry *)&mmr_value; entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long)); BUG_ON(sizeof(struct uv_IO_APIC_route_entry) != sizeof(unsigned long));
...@@ -3606,9 +3721,16 @@ int __init io_apic_get_redir_entries (int ioapic) ...@@ -3606,9 +3721,16 @@ int __init io_apic_get_redir_entries (int ioapic)
return reg_01.bits.entries; return reg_01.bits.entries;
} }
int __init probe_nr_irqs(void) void __init probe_nr_irqs_gsi(void)
{ {
return NR_IRQS; int idx;
int nr = 0;
for (idx = 0; idx < nr_ioapics; idx++)
nr += io_apic_get_redir_entries(idx) + 1;
if (nr > nr_irqs_gsi)
nr_irqs_gsi = nr;
} }
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
...@@ -3707,19 +3829,31 @@ int __init io_apic_get_version(int ioapic) ...@@ -3707,19 +3829,31 @@ int __init io_apic_get_version(int ioapic)
int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int polarity) int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int polarity)
{ {
struct irq_desc *desc;
struct irq_cfg *cfg;
int cpu = boot_cpu_id;
if (!IO_APIC_IRQ(irq)) { if (!IO_APIC_IRQ(irq)) {
apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n", apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
ioapic); ioapic);
return -EINVAL; return -EINVAL;
} }
desc = irq_to_desc_alloc_cpu(irq, cpu);
if (!desc) {
printk(KERN_INFO "can not get irq_desc %d\n", irq);
return 0;
}
/* /*
* IRQs < 16 are already in the irq_2_pin[] map * IRQs < 16 are already in the irq_2_pin[] map
*/ */
if (irq >= 16) if (irq >= NR_IRQS_LEGACY) {
add_pin_to_irq(irq, ioapic, pin); cfg = desc->chip_data;
add_pin_to_irq_cpu(cfg, cpu, ioapic, pin);
}
setup_IO_APIC_irq(ioapic, pin, irq, triggering, polarity); setup_IO_APIC_irq(ioapic, pin, irq, desc, triggering, polarity);
return 0; return 0;
} }
...@@ -3773,9 +3907,10 @@ void __init setup_ioapic_dest(void) ...@@ -3773,9 +3907,10 @@ void __init setup_ioapic_dest(void)
* when you have too many devices, because at that time only boot * when you have too many devices, because at that time only boot
* cpu is online. * cpu is online.
*/ */
cfg = irq_cfg(irq); desc = irq_to_desc(irq);
cfg = desc->chip_data;
if (!cfg->vector) { if (!cfg->vector) {
setup_IO_APIC_irq(ioapic, pin, irq, setup_IO_APIC_irq(ioapic, pin, irq, desc,
irq_trigger(irq_entry), irq_trigger(irq_entry),
irq_polarity(irq_entry)); irq_polarity(irq_entry));
continue; continue;
...@@ -3785,7 +3920,6 @@ void __init setup_ioapic_dest(void) ...@@ -3785,7 +3920,6 @@ void __init setup_ioapic_dest(void)
/* /*
* Honour affinities which have been set in early boot * Honour affinities which have been set in early boot
*/ */
desc = irq_to_desc(irq);
if (desc->status & if (desc->status &
(IRQ_NO_BALANCING | IRQ_AFFINITY_SET)) (IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
mask = desc->affinity; mask = desc->affinity;
...@@ -3794,10 +3928,10 @@ void __init setup_ioapic_dest(void) ...@@ -3794,10 +3928,10 @@ void __init setup_ioapic_dest(void)
#ifdef CONFIG_INTR_REMAP #ifdef CONFIG_INTR_REMAP
if (intr_remapping_enabled) if (intr_remapping_enabled)
set_ir_ioapic_affinity_irq(irq, mask); set_ir_ioapic_affinity_irq_desc(desc, mask);
else else
#endif #endif
set_ioapic_affinity_irq(irq, mask); set_ioapic_affinity_irq_desc(desc, mask);
} }
} }
...@@ -3846,7 +3980,6 @@ void __init ioapic_init_mappings(void) ...@@ -3846,7 +3980,6 @@ void __init ioapic_init_mappings(void)
struct resource *ioapic_res; struct resource *ioapic_res;
int i; int i;
irq_2_pin_init();
ioapic_res = ioapic_setup_resources(); ioapic_res = ioapic_setup_resources();
for (i = 0; i < nr_ioapics; i++) { for (i = 0; i < nr_ioapics; i++) {
if (smp_found_config) { if (smp_found_config) {
......
...@@ -118,6 +118,9 @@ int show_interrupts(struct seq_file *p, void *v) ...@@ -118,6 +118,9 @@ int show_interrupts(struct seq_file *p, void *v)
} }
desc = irq_to_desc(i); desc = irq_to_desc(i);
if (!desc)
return 0;
spin_lock_irqsave(&desc->lock, flags); spin_lock_irqsave(&desc->lock, flags);
#ifndef CONFIG_SMP #ifndef CONFIG_SMP
any_count = kstat_irqs(i); any_count = kstat_irqs(i);
......
...@@ -242,6 +242,8 @@ void fixup_irqs(cpumask_t map) ...@@ -242,6 +242,8 @@ void fixup_irqs(cpumask_t map)
for_each_irq_desc(irq, desc) { for_each_irq_desc(irq, desc) {
cpumask_t mask; cpumask_t mask;
if (!desc)
continue;
if (irq == 2) if (irq == 2)
continue; continue;
......
...@@ -94,6 +94,8 @@ void fixup_irqs(cpumask_t map) ...@@ -94,6 +94,8 @@ void fixup_irqs(cpumask_t map)
int break_affinity = 0; int break_affinity = 0;
int set_affinity = 1; int set_affinity = 1;
if (!desc)
continue;
if (irq == 2) if (irq == 2)
continue; continue;
......
...@@ -68,8 +68,7 @@ void __init init_ISA_irqs (void) ...@@ -68,8 +68,7 @@ void __init init_ISA_irqs (void)
/* /*
* 16 old-style INTA-cycle interrupts: * 16 old-style INTA-cycle interrupts:
*/ */
for (i = 0; i < 16; i++) { for (i = 0; i < NR_IRQS_LEGACY; i++) {
/* first time call this irq_desc */
struct irq_desc *desc = irq_to_desc(i); struct irq_desc *desc = irq_to_desc(i);
desc->status = IRQ_DISABLED; desc->status = IRQ_DISABLED;
......
...@@ -142,8 +142,7 @@ void __init init_ISA_irqs(void) ...@@ -142,8 +142,7 @@ void __init init_ISA_irqs(void)
init_bsp_APIC(); init_bsp_APIC();
init_8259A(0); init_8259A(0);
for (i = 0; i < 16; i++) { for (i = 0; i < NR_IRQS_LEGACY; i++) {
/* first time call this irq_desc */
struct irq_desc *desc = irq_to_desc(i); struct irq_desc *desc = irq_to_desc(i);
desc->status = IRQ_DISABLED; desc->status = IRQ_DISABLED;
......
...@@ -586,26 +586,23 @@ static void __init __get_smp_config(unsigned int early) ...@@ -586,26 +586,23 @@ static void __init __get_smp_config(unsigned int early)
{ {
struct intel_mp_floating *mpf = mpf_found; struct intel_mp_floating *mpf = mpf_found;
if (x86_quirks->mach_get_smp_config) { if (!mpf)
if (x86_quirks->mach_get_smp_config(early))
return; return;
}
if (acpi_lapic && early) if (acpi_lapic && early)
return; return;
/* /*
* ACPI supports both logical (e.g. Hyper-Threading) and physical * MPS doesn't support hyperthreading, aka only have
* processors, where MPS only supports physical. * thread 0 apic id in MPS table
*/ */
if (acpi_lapic && acpi_ioapic) { if (acpi_lapic && acpi_ioapic)
printk(KERN_INFO "Using ACPI (MADT) for SMP configuration "
"information\n");
return; return;
} else if (acpi_lapic)
printk(KERN_INFO "Using ACPI for processor (LAPIC) "
"configuration information\n");
if (!mpf) if (x86_quirks->mach_get_smp_config) {
if (x86_quirks->mach_get_smp_config(early))
return; return;
}
printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n", printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n",
mpf->mpf_specification); mpf->mpf_specification);
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include <asm/numaq.h> #include <asm/numaq.h>
#include <asm/topology.h> #include <asm/topology.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/mpspec.h> #include <asm/genapic.h>
#include <asm/e820.h> #include <asm/e820.h>
#include <asm/setup.h> #include <asm/setup.h>
...@@ -235,6 +235,13 @@ static int __init numaq_setup_ioapic_ids(void) ...@@ -235,6 +235,13 @@ static int __init numaq_setup_ioapic_ids(void)
return 1; return 1;
} }
static int __init numaq_update_genapic(void)
{
genapic->wakeup_cpu = wakeup_secondary_cpu_via_nmi;
return 0;
}
static struct x86_quirks numaq_x86_quirks __initdata = { static struct x86_quirks numaq_x86_quirks __initdata = {
.arch_pre_time_init = numaq_pre_time_init, .arch_pre_time_init = numaq_pre_time_init,
.arch_time_init = NULL, .arch_time_init = NULL,
...@@ -250,6 +257,7 @@ static struct x86_quirks numaq_x86_quirks __initdata = { ...@@ -250,6 +257,7 @@ static struct x86_quirks numaq_x86_quirks __initdata = {
.mpc_oem_pci_bus = mpc_oem_pci_bus, .mpc_oem_pci_bus = mpc_oem_pci_bus,
.smp_read_mpc_oem = smp_read_mpc_oem, .smp_read_mpc_oem = smp_read_mpc_oem,
.setup_ioapic_ids = numaq_setup_ioapic_ids, .setup_ioapic_ids = numaq_setup_ioapic_ids,
.update_genapic = numaq_update_genapic,
}; };
void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem, void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/clockchips.h> #include <linux/clockchips.h>
#include <linux/ftrace.h> #include <linux/ftrace.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/apic.h>
unsigned long idle_halt; unsigned long idle_halt;
EXPORT_SYMBOL(idle_halt); EXPORT_SYMBOL(idle_halt);
...@@ -127,6 +128,21 @@ void default_idle(void) ...@@ -127,6 +128,21 @@ void default_idle(void)
EXPORT_SYMBOL(default_idle); EXPORT_SYMBOL(default_idle);
#endif #endif
void stop_this_cpu(void *dummy)
{
local_irq_disable();
/*
* Remove this CPU:
*/
cpu_clear(smp_processor_id(), cpu_online_map);
disable_local_APIC();
for (;;) {
if (hlt_works(smp_processor_id()))
halt();
}
}
static void do_nothing(void *unused) static void do_nothing(void *unused)
{ {
} }
......
...@@ -36,7 +36,10 @@ int reboot_force; ...@@ -36,7 +36,10 @@ int reboot_force;
static int reboot_cpu = -1; static int reboot_cpu = -1;
#endif #endif
/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] /* This is set by the PCI code if either type 1 or type 2 PCI is detected */
bool port_cf9_safe = false;
/* reboot=b[ios] | s[mp] | t[riple] | k[bd] | e[fi] [, [w]arm | [c]old] | p[ci]
warm Don't set the cold reboot flag warm Don't set the cold reboot flag
cold Set the cold reboot flag cold Set the cold reboot flag
bios Reboot by jumping through the BIOS (only for X86_32) bios Reboot by jumping through the BIOS (only for X86_32)
...@@ -45,6 +48,7 @@ static int reboot_cpu = -1; ...@@ -45,6 +48,7 @@ static int reboot_cpu = -1;
kbd Use the keyboard controller. cold reset (default) kbd Use the keyboard controller. cold reset (default)
acpi Use the RESET_REG in the FADT acpi Use the RESET_REG in the FADT
efi Use efi reset_system runtime service efi Use efi reset_system runtime service
pci Use the so-called "PCI reset register", CF9
force Avoid anything that could hang. force Avoid anything that could hang.
*/ */
static int __init reboot_setup(char *str) static int __init reboot_setup(char *str)
...@@ -79,6 +83,7 @@ static int __init reboot_setup(char *str) ...@@ -79,6 +83,7 @@ static int __init reboot_setup(char *str)
case 'k': case 'k':
case 't': case 't':
case 'e': case 'e':
case 'p':
reboot_type = *str; reboot_type = *str;
break; break;
...@@ -404,12 +409,27 @@ static void native_machine_emergency_restart(void) ...@@ -404,12 +409,27 @@ static void native_machine_emergency_restart(void)
reboot_type = BOOT_KBD; reboot_type = BOOT_KBD;
break; break;
case BOOT_EFI: case BOOT_EFI:
if (efi_enabled) if (efi_enabled)
efi.reset_system(reboot_mode ? EFI_RESET_WARM : EFI_RESET_COLD, efi.reset_system(reboot_mode ?
EFI_RESET_WARM :
EFI_RESET_COLD,
EFI_SUCCESS, 0, NULL); EFI_SUCCESS, 0, NULL);
reboot_type = BOOT_KBD;
break;
case BOOT_CF9:
port_cf9_safe = true;
/* fall through */
case BOOT_CF9_COND:
if (port_cf9_safe) {
u8 cf9 = inb(0xcf9) & ~6;
outb(cf9|2, 0xcf9); /* Request hard reset */
udelay(50);
outb(cf9|6, 0xcf9); /* Actually do the reset */
udelay(50);
}
reboot_type = BOOT_KBD; reboot_type = BOOT_KBD;
break; break;
} }
...@@ -470,6 +490,11 @@ static void native_machine_restart(char *__unused) ...@@ -470,6 +490,11 @@ static void native_machine_restart(char *__unused)
static void native_machine_halt(void) static void native_machine_halt(void)
{ {
/* stop other cpus and apics */
machine_shutdown();
/* stop this cpu */
stop_this_cpu(NULL);
} }
static void native_machine_power_off(void) static void native_machine_power_off(void)
......
...@@ -583,7 +583,20 @@ static int __init setup_elfcorehdr(char *arg) ...@@ -583,7 +583,20 @@ static int __init setup_elfcorehdr(char *arg)
early_param("elfcorehdr", setup_elfcorehdr); early_param("elfcorehdr", setup_elfcorehdr);
#endif #endif
static struct x86_quirks default_x86_quirks __initdata; static int __init default_update_genapic(void)
{
#ifdef CONFIG_X86_SMP
# if defined(CONFIG_X86_GENERICARCH) || defined(CONFIG_X86_64)
genapic->wakeup_cpu = wakeup_secondary_cpu_via_init;
# endif
#endif
return 0;
}
static struct x86_quirks default_x86_quirks __initdata = {
.update_genapic = default_update_genapic,
};
struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
...@@ -1082,7 +1095,7 @@ void __init setup_arch(char **cmdline_p) ...@@ -1082,7 +1095,7 @@ void __init setup_arch(char **cmdline_p)
ioapic_init_mappings(); ioapic_init_mappings();
/* need to wait for io_apic is mapped */ /* need to wait for io_apic is mapped */
nr_irqs = probe_nr_irqs(); probe_nr_irqs_gsi();
kvm_guest_init(); kvm_guest_init();
......
...@@ -140,19 +140,6 @@ void native_send_call_func_ipi(cpumask_t mask) ...@@ -140,19 +140,6 @@ void native_send_call_func_ipi(cpumask_t mask)
send_IPI_mask(mask, CALL_FUNCTION_VECTOR); send_IPI_mask(mask, CALL_FUNCTION_VECTOR);
} }
static void stop_this_cpu(void *dummy)
{
local_irq_disable();
/*
* Remove this CPU:
*/
cpu_clear(smp_processor_id(), cpu_online_map);
disable_local_APIC();
if (hlt_works(smp_processor_id()))
for (;;) halt();
for (;;);
}
/* /*
* this function calls the 'stop' function on all other CPUs in the system. * this function calls the 'stop' function on all other CPUs in the system.
*/ */
......
...@@ -62,6 +62,7 @@ ...@@ -62,6 +62,7 @@
#include <asm/mtrr.h> #include <asm/mtrr.h>
#include <asm/vmi.h> #include <asm/vmi.h>
#include <asm/genapic.h> #include <asm/genapic.h>
#include <asm/setup.h>
#include <linux/mc146818rtc.h> #include <linux/mc146818rtc.h>
#include <mach_apic.h> #include <mach_apic.h>
...@@ -536,7 +537,7 @@ static void impress_friends(void) ...@@ -536,7 +537,7 @@ static void impress_friends(void)
pr_debug("Before bogocount - setting activated=1.\n"); pr_debug("Before bogocount - setting activated=1.\n");
} }
static inline void __inquire_remote_apic(int apicid) void __inquire_remote_apic(int apicid)
{ {
unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 }; unsigned i, regs[] = { APIC_ID >> 4, APIC_LVR >> 4, APIC_SPIV >> 4 };
char *names[] = { "ID", "VERSION", "SPIV" }; char *names[] = { "ID", "VERSION", "SPIV" };
...@@ -575,14 +576,13 @@ static inline void __inquire_remote_apic(int apicid) ...@@ -575,14 +576,13 @@ static inline void __inquire_remote_apic(int apicid)
} }
} }
#ifdef WAKE_SECONDARY_VIA_NMI
/* /*
* Poke the other CPU in the eye via NMI to wake it up. Remember that the normal * Poke the other CPU in the eye via NMI to wake it up. Remember that the normal
* INIT, INIT, STARTUP sequence will reset the chip hard for us, and this * INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
* won't ... remember to clear down the APIC, etc later. * won't ... remember to clear down the APIC, etc later.
*/ */
static int __devinit int __devinit
wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip)
{ {
unsigned long send_status, accept_status = 0; unsigned long send_status, accept_status = 0;
int maxlvt; int maxlvt;
...@@ -599,7 +599,7 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) ...@@ -599,7 +599,7 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
* Give the other CPU some time to accept the IPI. * Give the other CPU some time to accept the IPI.
*/ */
udelay(200); udelay(200);
if (APIC_INTEGRATED(apic_version[phys_apicid])) { if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
maxlvt = lapic_get_maxlvt(); maxlvt = lapic_get_maxlvt();
if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */ if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
apic_write(APIC_ESR, 0); apic_write(APIC_ESR, 0);
...@@ -614,11 +614,9 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip) ...@@ -614,11 +614,9 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
return (send_status | accept_status); return (send_status | accept_status);
} }
#endif /* WAKE_SECONDARY_VIA_NMI */
#ifdef WAKE_SECONDARY_VIA_INIT int __devinit
static int __devinit wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
{ {
unsigned long send_status, accept_status = 0; unsigned long send_status, accept_status = 0;
int maxlvt, num_starts, j; int maxlvt, num_starts, j;
...@@ -737,7 +735,6 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip) ...@@ -737,7 +735,6 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
return (send_status | accept_status); return (send_status | accept_status);
} }
#endif /* WAKE_SECONDARY_VIA_INIT */
struct create_idle { struct create_idle {
struct work_struct work; struct work_struct work;
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <asm/bigsmp/apic.h> #include <asm/bigsmp/apic.h>
#include <asm/bigsmp/ipi.h> #include <asm/bigsmp/ipi.h>
#include <asm/mach-default/mach_mpparse.h> #include <asm/mach-default/mach_mpparse.h>
#include <asm/mach-default/mach_wakecpu.h>
static int dmi_bigsmp; /* can be set by dmi scanners */ static int dmi_bigsmp; /* can be set by dmi scanners */
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <asm/mach-default/mach_apic.h> #include <asm/mach-default/mach_apic.h>
#include <asm/mach-default/mach_ipi.h> #include <asm/mach-default/mach_ipi.h>
#include <asm/mach-default/mach_mpparse.h> #include <asm/mach-default/mach_mpparse.h>
#include <asm/mach-default/mach_wakecpu.h>
/* should be called last. */ /* should be called last. */
static int probe_default(void) static int probe_default(void)
......
...@@ -16,7 +16,19 @@ ...@@ -16,7 +16,19 @@
#include <asm/es7000/apic.h> #include <asm/es7000/apic.h>
#include <asm/es7000/ipi.h> #include <asm/es7000/ipi.h>
#include <asm/es7000/mpparse.h> #include <asm/es7000/mpparse.h>
#include <asm/es7000/wakecpu.h> #include <asm/mach-default/mach_wakecpu.h>
void __init es7000_update_genapic_to_cluster(void)
{
genapic->target_cpus = target_cpus_cluster;
genapic->int_delivery_mode = INT_DELIVERY_MODE_CLUSTER;
genapic->int_dest_mode = INT_DEST_MODE_CLUSTER;
genapic->no_balance_irq = NO_BALANCE_IRQ_CLUSTER;
genapic->init_apic_ldr = init_apic_ldr_cluster;
genapic->cpu_mask_to_apicid = cpu_mask_to_apicid_cluster;
}
static int probe_es7000(void) static int probe_es7000(void)
{ {
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <asm/mpspec.h> #include <asm/mpspec.h>
#include <asm/apicdef.h> #include <asm/apicdef.h>
#include <asm/genapic.h> #include <asm/genapic.h>
#include <asm/setup.h>
extern struct genapic apic_numaq; extern struct genapic apic_numaq;
extern struct genapic apic_summit; extern struct genapic apic_summit;
...@@ -57,6 +58,9 @@ static int __init parse_apic(char *arg) ...@@ -57,6 +58,9 @@ static int __init parse_apic(char *arg)
} }
} }
if (x86_quirks->update_genapic)
x86_quirks->update_genapic();
/* Parsed again by __setup for debug/verbose */ /* Parsed again by __setup for debug/verbose */
return 0; return 0;
} }
...@@ -72,12 +76,15 @@ void __init generic_bigsmp_probe(void) ...@@ -72,12 +76,15 @@ void __init generic_bigsmp_probe(void)
* - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support * - we find more than 8 CPUs in acpi LAPIC listing with xAPIC support
*/ */
if (!cmdline_apic && genapic == &apic_default) if (!cmdline_apic && genapic == &apic_default) {
if (apic_bigsmp.probe()) { if (apic_bigsmp.probe()) {
genapic = &apic_bigsmp; genapic = &apic_bigsmp;
if (x86_quirks->update_genapic)
x86_quirks->update_genapic();
printk(KERN_INFO "Overriding APIC driver with %s\n", printk(KERN_INFO "Overriding APIC driver with %s\n",
genapic->name); genapic->name);
} }
}
#endif #endif
} }
...@@ -94,6 +101,9 @@ void __init generic_apic_probe(void) ...@@ -94,6 +101,9 @@ void __init generic_apic_probe(void)
/* Not visible without early console */ /* Not visible without early console */
if (!apic_probe[i]) if (!apic_probe[i])
panic("Didn't find an APIC driver"); panic("Didn't find an APIC driver");
if (x86_quirks->update_genapic)
x86_quirks->update_genapic();
} }
printk(KERN_INFO "Using APIC driver %s\n", genapic->name); printk(KERN_INFO "Using APIC driver %s\n", genapic->name);
} }
...@@ -108,6 +118,8 @@ int __init mps_oem_check(struct mp_config_table *mpc, char *oem, ...@@ -108,6 +118,8 @@ int __init mps_oem_check(struct mp_config_table *mpc, char *oem,
if (apic_probe[i]->mps_oem_check(mpc, oem, productid)) { if (apic_probe[i]->mps_oem_check(mpc, oem, productid)) {
if (!cmdline_apic) { if (!cmdline_apic) {
genapic = apic_probe[i]; genapic = apic_probe[i];
if (x86_quirks->update_genapic)
x86_quirks->update_genapic();
printk(KERN_INFO "Switched to APIC driver `%s'.\n", printk(KERN_INFO "Switched to APIC driver `%s'.\n",
genapic->name); genapic->name);
} }
...@@ -124,6 +136,8 @@ int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) ...@@ -124,6 +136,8 @@ int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) { if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) {
if (!cmdline_apic) { if (!cmdline_apic) {
genapic = apic_probe[i]; genapic = apic_probe[i];
if (x86_quirks->update_genapic)
x86_quirks->update_genapic();
printk(KERN_INFO "Switched to APIC driver `%s'.\n", printk(KERN_INFO "Switched to APIC driver `%s'.\n",
genapic->name); genapic->name);
} }
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <asm/summit/apic.h> #include <asm/summit/apic.h>
#include <asm/summit/ipi.h> #include <asm/summit/ipi.h>
#include <asm/summit/mpparse.h> #include <asm/summit/mpparse.h>
#include <asm/mach-default/mach_wakecpu.h>
static int probe_summit(void) static int probe_summit(void)
{ {
......
...@@ -173,7 +173,7 @@ static int pci_conf2_write(unsigned int seg, unsigned int bus, ...@@ -173,7 +173,7 @@ static int pci_conf2_write(unsigned int seg, unsigned int bus,
#undef PCI_CONF2_ADDRESS #undef PCI_CONF2_ADDRESS
static struct pci_raw_ops pci_direct_conf2 = { struct pci_raw_ops pci_direct_conf2 = {
.read = pci_conf2_read, .read = pci_conf2_read,
.write = pci_conf2_write, .write = pci_conf2_write,
}; };
...@@ -289,6 +289,7 @@ int __init pci_direct_probe(void) ...@@ -289,6 +289,7 @@ int __init pci_direct_probe(void)
if (pci_check_type1()) { if (pci_check_type1()) {
raw_pci_ops = &pci_direct_conf1; raw_pci_ops = &pci_direct_conf1;
port_cf9_safe = true;
return 1; return 1;
} }
release_resource(region); release_resource(region);
...@@ -305,6 +306,7 @@ int __init pci_direct_probe(void) ...@@ -305,6 +306,7 @@ int __init pci_direct_probe(void)
if (pci_check_type2()) { if (pci_check_type2()) {
raw_pci_ops = &pci_direct_conf2; raw_pci_ops = &pci_direct_conf2;
port_cf9_safe = true;
return 2; return 2;
} }
......
...@@ -96,6 +96,7 @@ extern struct pci_raw_ops *raw_pci_ops; ...@@ -96,6 +96,7 @@ extern struct pci_raw_ops *raw_pci_ops;
extern struct pci_raw_ops *raw_pci_ext_ops; extern struct pci_raw_ops *raw_pci_ext_ops;
extern struct pci_raw_ops pci_direct_conf1; extern struct pci_raw_ops pci_direct_conf1;
extern bool port_cf9_safe;
/* arch_initcall level */ /* arch_initcall level */
extern int pci_direct_probe(void); extern int pci_direct_probe(void);
......
...@@ -558,23 +558,9 @@ struct timer_rand_state { ...@@ -558,23 +558,9 @@ struct timer_rand_state {
unsigned dont_count_entropy:1; unsigned dont_count_entropy:1;
}; };
static struct timer_rand_state *irq_timer_state[NR_IRQS]; #ifndef CONFIG_SPARSE_IRQ
struct timer_rand_state *irq_timer_state[NR_IRQS];
static struct timer_rand_state *get_timer_rand_state(unsigned int irq) #endif
{
if (irq >= nr_irqs)
return NULL;
return irq_timer_state[irq];
}
static void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
{
if (irq >= nr_irqs)
return;
irq_timer_state[irq] = state;
}
static struct timer_rand_state input_timer_state; static struct timer_rand_state input_timer_state;
...@@ -933,8 +919,10 @@ void rand_initialize_irq(int irq) ...@@ -933,8 +919,10 @@ void rand_initialize_irq(int irq)
{ {
struct timer_rand_state *state; struct timer_rand_state *state;
#ifndef CONFIG_SPARSE_IRQ
if (irq >= nr_irqs) if (irq >= nr_irqs)
return; return;
#endif
state = get_timer_rand_state(irq); state = get_timer_rand_state(irq);
......
...@@ -19,17 +19,75 @@ struct irq_2_iommu { ...@@ -19,17 +19,75 @@ struct irq_2_iommu {
u8 irte_mask; u8 irte_mask;
}; };
static struct irq_2_iommu irq_2_iommuX[NR_IRQS]; #ifdef CONFIG_SPARSE_IRQ
static struct irq_2_iommu *get_one_free_irq_2_iommu(int cpu)
{
struct irq_2_iommu *iommu;
int node;
node = cpu_to_node(cpu);
iommu = kzalloc_node(sizeof(*iommu), GFP_ATOMIC, node);
printk(KERN_DEBUG "alloc irq_2_iommu on cpu %d node %d\n", cpu, node);
return iommu;
}
static struct irq_2_iommu *irq_2_iommu(unsigned int irq) static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
{ {
return (irq < nr_irqs) ? irq_2_iommuX + irq : NULL; struct irq_desc *desc;
desc = irq_to_desc(irq);
if (WARN_ON_ONCE(!desc))
return NULL;
return desc->irq_2_iommu;
}
static struct irq_2_iommu *irq_2_iommu_alloc_cpu(unsigned int irq, int cpu)
{
struct irq_desc *desc;
struct irq_2_iommu *irq_iommu;
/*
* alloc irq desc if not allocated already.
*/
desc = irq_to_desc_alloc_cpu(irq, cpu);
if (!desc) {
printk(KERN_INFO "can not get irq_desc for %d\n", irq);
return NULL;
}
irq_iommu = desc->irq_2_iommu;
if (!irq_iommu)
desc->irq_2_iommu = get_one_free_irq_2_iommu(cpu);
return desc->irq_2_iommu;
} }
static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
{
return irq_2_iommu_alloc_cpu(irq, boot_cpu_id);
}
#else /* !CONFIG_SPARSE_IRQ */
static struct irq_2_iommu irq_2_iommuX[NR_IRQS];
static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
{
if (irq < nr_irqs)
return &irq_2_iommuX[irq];
return NULL;
}
static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq) static struct irq_2_iommu *irq_2_iommu_alloc(unsigned int irq)
{ {
return irq_2_iommu(irq); return irq_2_iommu(irq);
} }
#endif
static DEFINE_SPINLOCK(irq_2_ir_lock); static DEFINE_SPINLOCK(irq_2_ir_lock);
...@@ -86,9 +144,11 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) ...@@ -86,9 +144,11 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
if (!count) if (!count)
return -1; return -1;
#ifndef CONFIG_SPARSE_IRQ
/* protect irq_2_iommu_alloc later */ /* protect irq_2_iommu_alloc later */
if (irq >= nr_irqs) if (irq >= nr_irqs)
return -1; return -1;
#endif
/* /*
* start the IRTE search from index 0. * start the IRTE search from index 0.
...@@ -130,6 +190,12 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) ...@@ -130,6 +190,12 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
table->base[i].present = 1; table->base[i].present = 1;
irq_iommu = irq_2_iommu_alloc(irq); irq_iommu = irq_2_iommu_alloc(irq);
if (!irq_iommu) {
spin_unlock(&irq_2_ir_lock);
printk(KERN_ERR "can't allocate irq_2_iommu\n");
return -1;
}
irq_iommu->iommu = iommu; irq_iommu->iommu = iommu;
irq_iommu->irte_index = index; irq_iommu->irte_index = index;
irq_iommu->sub_handle = 0; irq_iommu->sub_handle = 0;
...@@ -177,6 +243,12 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) ...@@ -177,6 +243,12 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle)
irq_iommu = irq_2_iommu_alloc(irq); irq_iommu = irq_2_iommu_alloc(irq);
if (!irq_iommu) {
spin_unlock(&irq_2_ir_lock);
printk(KERN_ERR "can't allocate irq_2_iommu\n");
return -1;
}
irq_iommu->iommu = iommu; irq_iommu->iommu = iommu;
irq_iommu->irte_index = index; irq_iommu->irte_index = index;
irq_iommu->sub_handle = subhandle; irq_iommu->sub_handle = subhandle;
......
...@@ -103,11 +103,11 @@ static void msix_set_enable(struct pci_dev *dev, int enable) ...@@ -103,11 +103,11 @@ static void msix_set_enable(struct pci_dev *dev, int enable)
} }
} }
static void msix_flush_writes(unsigned int irq) static void msix_flush_writes(struct irq_desc *desc)
{ {
struct msi_desc *entry; struct msi_desc *entry;
entry = get_irq_msi(irq); entry = get_irq_desc_msi(desc);
BUG_ON(!entry || !entry->dev); BUG_ON(!entry || !entry->dev);
switch (entry->msi_attrib.type) { switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI: case PCI_CAP_ID_MSI:
...@@ -135,11 +135,11 @@ static void msix_flush_writes(unsigned int irq) ...@@ -135,11 +135,11 @@ static void msix_flush_writes(unsigned int irq)
* Returns 1 if it succeeded in masking the interrupt and 0 if the device * Returns 1 if it succeeded in masking the interrupt and 0 if the device
* doesn't support MSI masking. * doesn't support MSI masking.
*/ */
static int msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) static int msi_set_mask_bits(struct irq_desc *desc, u32 mask, u32 flag)
{ {
struct msi_desc *entry; struct msi_desc *entry;
entry = get_irq_msi(irq); entry = get_irq_desc_msi(desc);
BUG_ON(!entry || !entry->dev); BUG_ON(!entry || !entry->dev);
switch (entry->msi_attrib.type) { switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI: case PCI_CAP_ID_MSI:
...@@ -172,9 +172,9 @@ static int msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag) ...@@ -172,9 +172,9 @@ static int msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag)
return 1; return 1;
} }
void read_msi_msg(unsigned int irq, struct msi_msg *msg) void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
{ {
struct msi_desc *entry = get_irq_msi(irq); struct msi_desc *entry = get_irq_desc_msi(desc);
switch(entry->msi_attrib.type) { switch(entry->msi_attrib.type) {
case PCI_CAP_ID_MSI: case PCI_CAP_ID_MSI:
{ {
...@@ -211,9 +211,16 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg) ...@@ -211,9 +211,16 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
} }
} }
void write_msi_msg(unsigned int irq, struct msi_msg *msg) void read_msi_msg(unsigned int irq, struct msi_msg *msg)
{ {
struct msi_desc *entry = get_irq_msi(irq); struct irq_desc *desc = irq_to_desc(irq);
read_msi_msg_desc(desc, msg);
}
void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
{
struct msi_desc *entry = get_irq_desc_msi(desc);
switch (entry->msi_attrib.type) { switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI: case PCI_CAP_ID_MSI:
{ {
...@@ -252,21 +259,31 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg) ...@@ -252,21 +259,31 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
entry->msg = *msg; entry->msg = *msg;
} }
void write_msi_msg(unsigned int irq, struct msi_msg *msg)
{
struct irq_desc *desc = irq_to_desc(irq);
write_msi_msg_desc(desc, msg);
}
void mask_msi_irq(unsigned int irq) void mask_msi_irq(unsigned int irq)
{ {
msi_set_mask_bits(irq, 1, 1); struct irq_desc *desc = irq_to_desc(irq);
msix_flush_writes(irq);
msi_set_mask_bits(desc, 1, 1);
msix_flush_writes(desc);
} }
void unmask_msi_irq(unsigned int irq) void unmask_msi_irq(unsigned int irq)
{ {
msi_set_mask_bits(irq, 1, 0); struct irq_desc *desc = irq_to_desc(irq);
msix_flush_writes(irq);
msi_set_mask_bits(desc, 1, 0);
msix_flush_writes(desc);
} }
static int msi_free_irqs(struct pci_dev* dev); static int msi_free_irqs(struct pci_dev* dev);
static struct msi_desc* alloc_msi_entry(void) static struct msi_desc* alloc_msi_entry(void)
{ {
struct msi_desc *entry; struct msi_desc *entry;
...@@ -303,9 +320,11 @@ static void __pci_restore_msi_state(struct pci_dev *dev) ...@@ -303,9 +320,11 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
pci_intx_for_msi(dev, 0); pci_intx_for_msi(dev, 0);
msi_set_enable(dev, 0); msi_set_enable(dev, 0);
write_msi_msg(dev->irq, &entry->msg); write_msi_msg(dev->irq, &entry->msg);
if (entry->msi_attrib.maskbit) if (entry->msi_attrib.maskbit) {
msi_set_mask_bits(dev->irq, entry->msi_attrib.maskbits_mask, struct irq_desc *desc = irq_to_desc(dev->irq);
msi_set_mask_bits(desc, entry->msi_attrib.maskbits_mask,
entry->msi_attrib.masked); entry->msi_attrib.masked);
}
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
control &= ~PCI_MSI_FLAGS_QSIZE; control &= ~PCI_MSI_FLAGS_QSIZE;
...@@ -327,8 +346,9 @@ static void __pci_restore_msix_state(struct pci_dev *dev) ...@@ -327,8 +346,9 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
msix_set_enable(dev, 0); msix_set_enable(dev, 0);
list_for_each_entry(entry, &dev->msi_list, list) { list_for_each_entry(entry, &dev->msi_list, list) {
struct irq_desc *desc = irq_to_desc(entry->irq);
write_msi_msg(entry->irq, &entry->msg); write_msi_msg(entry->irq, &entry->msg);
msi_set_mask_bits(entry->irq, 1, entry->msi_attrib.masked); msi_set_mask_bits(desc, 1, entry->msi_attrib.masked);
} }
BUG_ON(list_empty(&dev->msi_list)); BUG_ON(list_empty(&dev->msi_list));
...@@ -596,7 +616,8 @@ void pci_msi_shutdown(struct pci_dev* dev) ...@@ -596,7 +616,8 @@ void pci_msi_shutdown(struct pci_dev* dev)
/* Return the the pci reset with msi irqs unmasked */ /* Return the the pci reset with msi irqs unmasked */
if (entry->msi_attrib.maskbit) { if (entry->msi_attrib.maskbit) {
u32 mask = entry->msi_attrib.maskbits_mask; u32 mask = entry->msi_attrib.maskbits_mask;
msi_set_mask_bits(dev->irq, mask, ~mask); struct irq_desc *desc = irq_to_desc(dev->irq);
msi_set_mask_bits(desc, mask, ~mask);
} }
if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI)
return; return;
......
...@@ -141,8 +141,12 @@ static void init_evtchn_cpu_bindings(void) ...@@ -141,8 +141,12 @@ static void init_evtchn_cpu_bindings(void)
int i; int i;
/* By default all event channels notify CPU#0. */ /* By default all event channels notify CPU#0. */
for_each_irq_desc(i, desc) for_each_irq_desc(i, desc) {
if (!desc)
continue;
desc->affinity = cpumask_of_cpu(0); desc->affinity = cpumask_of_cpu(0);
}
#endif #endif
memset(cpu_evtchn, 0, sizeof(cpu_evtchn)); memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
...@@ -231,7 +235,7 @@ static int find_unbound_irq(void) ...@@ -231,7 +235,7 @@ static int find_unbound_irq(void)
int irq; int irq;
/* Only allocate from dynirq range */ /* Only allocate from dynirq range */
for_each_irq_nr(irq) for (irq = 0; irq < nr_irqs; irq++)
if (irq_bindcount[irq] == 0) if (irq_bindcount[irq] == 0)
break; break;
...@@ -792,7 +796,7 @@ void xen_irq_resume(void) ...@@ -792,7 +796,7 @@ void xen_irq_resume(void)
mask_evtchn(evtchn); mask_evtchn(evtchn);
/* No IRQ <-> event-channel mappings. */ /* No IRQ <-> event-channel mappings. */
for_each_irq_nr(irq) for (irq = 0; irq < nr_irqs; irq++)
irq_info[irq].evtchn = 0; /* zap event-channel binding */ irq_info[irq].evtchn = 0; /* zap event-channel binding */
for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++) for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
...@@ -824,7 +828,7 @@ void __init xen_init_IRQ(void) ...@@ -824,7 +828,7 @@ void __init xen_init_IRQ(void)
mask_evtchn(i); mask_evtchn(i);
/* Dynamic IRQ space is currently unbound. Zero the refcnts. */ /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
for_each_irq_nr(i) for (i = 0; i < nr_irqs; i++)
irq_bindcount[i] = 0; irq_bindcount[i] = 0;
irq_ctx_init(smp_processor_id()); irq_ctx_init(smp_processor_id());
......
...@@ -27,6 +27,7 @@ static int show_stat(struct seq_file *p, void *v) ...@@ -27,6 +27,7 @@ static int show_stat(struct seq_file *p, void *v)
u64 sum = 0; u64 sum = 0;
struct timespec boottime; struct timespec boottime;
unsigned int per_irq_sum; unsigned int per_irq_sum;
struct irq_desc *desc;
user = nice = system = idle = iowait = user = nice = system = idle = iowait =
irq = softirq = steal = cputime64_zero; irq = softirq = steal = cputime64_zero;
...@@ -44,10 +45,14 @@ static int show_stat(struct seq_file *p, void *v) ...@@ -44,10 +45,14 @@ static int show_stat(struct seq_file *p, void *v)
softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq); softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal); steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest); guest = cputime64_add(guest, kstat_cpu(i).cpustat.guest);
for_each_irq_nr(j) {
for_each_irq_nr(j) #ifdef CONFIG_SPARSE_IRQ
desc = irq_to_desc(j);
if (!desc)
continue;
#endif
sum += kstat_irqs_cpu(j, i); sum += kstat_irqs_cpu(j, i);
}
sum += arch_irq_stat_cpu(i); sum += arch_irq_stat_cpu(i);
} }
sum += arch_irq_stat(); sum += arch_irq_stat();
...@@ -92,7 +97,13 @@ static int show_stat(struct seq_file *p, void *v) ...@@ -92,7 +97,13 @@ static int show_stat(struct seq_file *p, void *v)
/* sum again ? it could be updated? */ /* sum again ? it could be updated? */
for_each_irq_nr(j) { for_each_irq_nr(j) {
per_irq_sum = 0; per_irq_sum = 0;
#ifdef CONFIG_SPARSE_IRQ
desc = irq_to_desc(j);
if (!desc) {
seq_printf(p, " %u", per_irq_sum);
continue;
}
#endif
for_each_possible_cpu(i) for_each_possible_cpu(i)
per_irq_sum += kstat_irqs_cpu(j, i); per_irq_sum += kstat_irqs_cpu(j, i);
......
...@@ -313,6 +313,7 @@ unifdef-y += ptrace.h ...@@ -313,6 +313,7 @@ unifdef-y += ptrace.h
unifdef-y += qnx4_fs.h unifdef-y += qnx4_fs.h
unifdef-y += quota.h unifdef-y += quota.h
unifdef-y += random.h unifdef-y += random.h
unifdef-y += irqnr.h
unifdef-y += reboot.h unifdef-y += reboot.h
unifdef-y += reiserfs_fs.h unifdef-y += reiserfs_fs.h
unifdef-y += reiserfs_xattr.h unifdef-y += reiserfs_xattr.h
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include <linux/irqflags.h> #include <linux/irqflags.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/percpu.h> #include <linux/percpu.h>
#include <linux/irqnr.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/ptrace.h> #include <asm/ptrace.h>
#include <asm/system.h> #include <asm/system.h>
......
...@@ -129,6 +129,8 @@ struct irq_chip { ...@@ -129,6 +129,8 @@ struct irq_chip {
const char *typename; const char *typename;
}; };
struct timer_rand_state;
struct irq_2_iommu;
/** /**
* struct irq_desc - interrupt descriptor * struct irq_desc - interrupt descriptor
* @irq: interrupt number for this descriptor * @irq: interrupt number for this descriptor
...@@ -154,6 +156,13 @@ struct irq_chip { ...@@ -154,6 +156,13 @@ struct irq_chip {
*/ */
struct irq_desc { struct irq_desc {
unsigned int irq; unsigned int irq;
#ifdef CONFIG_SPARSE_IRQ
struct timer_rand_state *timer_rand_state;
unsigned int *kstat_irqs;
# ifdef CONFIG_INTR_REMAP
struct irq_2_iommu *irq_2_iommu;
# endif
#endif
irq_flow_handler_t handle_irq; irq_flow_handler_t handle_irq;
struct irq_chip *chip; struct irq_chip *chip;
struct msi_desc *msi_desc; struct msi_desc *msi_desc;
...@@ -181,14 +190,43 @@ struct irq_desc { ...@@ -181,14 +190,43 @@ struct irq_desc {
const char *name; const char *name;
} ____cacheline_internodealigned_in_smp; } ____cacheline_internodealigned_in_smp;
extern void early_irq_init(void);
extern void arch_early_irq_init(void);
extern void arch_init_chip_data(struct irq_desc *desc, int cpu);
extern void arch_init_copy_chip_data(struct irq_desc *old_desc,
struct irq_desc *desc, int cpu);
extern void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc);
#ifndef CONFIG_SPARSE_IRQ
extern struct irq_desc irq_desc[NR_IRQS]; extern struct irq_desc irq_desc[NR_IRQS];
static inline struct irq_desc *irq_to_desc(unsigned int irq) static inline struct irq_desc *irq_to_desc(unsigned int irq)
{ {
return (irq < nr_irqs) ? irq_desc + irq : NULL; return (irq < NR_IRQS) ? irq_desc + irq : NULL;
}
static inline struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu)
{
return irq_to_desc(irq);
} }
#else
extern struct irq_desc *irq_to_desc(unsigned int irq);
extern struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu);
extern struct irq_desc *move_irq_desc(struct irq_desc *old_desc, int cpu);
# define for_each_irq_desc(irq, desc) \
for (irq = 0, desc = irq_to_desc(irq); irq < nr_irqs; irq++, desc = irq_to_desc(irq))
# define for_each_irq_desc_reverse(irq, desc) \
for (irq = nr_irqs - 1, desc = irq_to_desc(irq); irq >= 0; irq--, desc = irq_to_desc(irq))
#define kstat_irqs_this_cpu(DESC) \
((DESC)->kstat_irqs[smp_processor_id()])
#define kstat_incr_irqs_this_cpu(irqno, DESC) \
((DESC)->kstat_irqs[smp_processor_id()]++)
#endif
/* /*
* Migration helpers for obsolete names, they will go away: * Migration helpers for obsolete names, they will go away:
*/ */
...@@ -380,6 +418,11 @@ extern int set_irq_msi(unsigned int irq, struct msi_desc *entry); ...@@ -380,6 +418,11 @@ extern int set_irq_msi(unsigned int irq, struct msi_desc *entry);
#define get_irq_data(irq) (irq_to_desc(irq)->handler_data) #define get_irq_data(irq) (irq_to_desc(irq)->handler_data)
#define get_irq_msi(irq) (irq_to_desc(irq)->msi_desc) #define get_irq_msi(irq) (irq_to_desc(irq)->msi_desc)
#define get_irq_desc_chip(desc) ((desc)->chip)
#define get_irq_desc_chip_data(desc) ((desc)->chip_data)
#define get_irq_desc_data(desc) ((desc)->handler_data)
#define get_irq_desc_msi(desc) ((desc)->msi_desc)
#endif /* CONFIG_GENERIC_HARDIRQS */ #endif /* CONFIG_GENERIC_HARDIRQS */
#endif /* !CONFIG_S390 */ #endif /* !CONFIG_S390 */
......
#ifndef _LINUX_IRQNR_H #ifndef _LINUX_IRQNR_H
#define _LINUX_IRQNR_H #define _LINUX_IRQNR_H
/*
* Generic irq_desc iterators:
*/
#ifdef __KERNEL__
#ifndef CONFIG_GENERIC_HARDIRQS #ifndef CONFIG_GENERIC_HARDIRQS
#include <asm/irq.h> #include <asm/irq.h>
# define nr_irqs NR_IRQS # define nr_irqs NR_IRQS
# define for_each_irq_desc(irq, desc) \ # define for_each_irq_desc(irq, desc) \
for (irq = 0; irq < nr_irqs; irq++) for (irq = 0; irq < nr_irqs; irq++)
# define for_each_irq_desc_reverse(irq, desc) \
for (irq = nr_irqs - 1; irq >= 0; irq--)
#else #else
extern int nr_irqs; extern int nr_irqs;
#ifndef CONFIG_SPARSE_IRQ
struct irq_desc;
# define for_each_irq_desc(irq, desc) \ # define for_each_irq_desc(irq, desc) \
for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++) for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++)
# define for_each_irq_desc_reverse(irq, desc) \ # define for_each_irq_desc_reverse(irq, desc) \
for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1); \ for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1); \
irq >= 0; irq--, desc--) irq >= 0; irq--, desc--)
#endif #endif
#endif
#define for_each_irq_nr(irq) \ #define for_each_irq_nr(irq) \
for (irq = 0; irq < nr_irqs; irq++) for (irq = 0; irq < nr_irqs; irq++)
#endif /* __KERNEL__ */
#endif #endif
...@@ -28,7 +28,9 @@ struct cpu_usage_stat { ...@@ -28,7 +28,9 @@ struct cpu_usage_stat {
struct kernel_stat { struct kernel_stat {
struct cpu_usage_stat cpustat; struct cpu_usage_stat cpustat;
#ifndef CONFIG_SPARSE_IRQ
unsigned int irqs[NR_IRQS]; unsigned int irqs[NR_IRQS];
#endif
}; };
DECLARE_PER_CPU(struct kernel_stat, kstat); DECLARE_PER_CPU(struct kernel_stat, kstat);
...@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, kstat); ...@@ -39,6 +41,10 @@ DECLARE_PER_CPU(struct kernel_stat, kstat);
extern unsigned long long nr_context_switches(void); extern unsigned long long nr_context_switches(void);
#ifndef CONFIG_SPARSE_IRQ
#define kstat_irqs_this_cpu(irq) \
(kstat_this_cpu.irqs[irq])
struct irq_desc; struct irq_desc;
static inline void kstat_incr_irqs_this_cpu(unsigned int irq, static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
...@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq, ...@@ -46,11 +52,17 @@ static inline void kstat_incr_irqs_this_cpu(unsigned int irq,
{ {
kstat_this_cpu.irqs[irq]++; kstat_this_cpu.irqs[irq]++;
} }
#endif
#ifndef CONFIG_SPARSE_IRQ
static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
{ {
return kstat_cpu(cpu).irqs[irq]; return kstat_cpu(cpu).irqs[irq];
} }
#else
extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu);
#endif
/* /*
* Number of interrupts per specific IRQ source, since bootup * Number of interrupts per specific IRQ source, since bootup
......
...@@ -10,8 +10,11 @@ struct msi_msg { ...@@ -10,8 +10,11 @@ struct msi_msg {
}; };
/* Helper functions */ /* Helper functions */
struct irq_desc;
extern void mask_msi_irq(unsigned int irq); extern void mask_msi_irq(unsigned int irq);
extern void unmask_msi_irq(unsigned int irq); extern void unmask_msi_irq(unsigned int irq);
extern void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
extern void write_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg);
extern void read_msi_msg(unsigned int irq, struct msi_msg *msg); extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
extern void write_msi_msg(unsigned int irq, struct msi_msg *msg); extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define _LINUX_RANDOM_H #define _LINUX_RANDOM_H
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/irqnr.h>
/* ioctl()'s for the random number generator */ /* ioctl()'s for the random number generator */
...@@ -44,6 +45,56 @@ struct rand_pool_info { ...@@ -44,6 +45,56 @@ struct rand_pool_info {
extern void rand_initialize_irq(int irq); extern void rand_initialize_irq(int irq);
struct timer_rand_state;
#ifndef CONFIG_SPARSE_IRQ
extern struct timer_rand_state *irq_timer_state[];
static inline struct timer_rand_state *get_timer_rand_state(unsigned int irq)
{
if (irq >= nr_irqs)
return NULL;
return irq_timer_state[irq];
}
static inline void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
{
if (irq >= nr_irqs)
return;
irq_timer_state[irq] = state;
}
#else
#include <linux/irq.h>
static inline struct timer_rand_state *get_timer_rand_state(unsigned int irq)
{
struct irq_desc *desc;
desc = irq_to_desc(irq);
if (!desc)
return NULL;
return desc->timer_rand_state;
}
static inline void set_timer_rand_state(unsigned int irq, struct timer_rand_state *state)
{
struct irq_desc *desc;
desc = irq_to_desc(irq);
if (!desc)
return;
desc->timer_rand_state = state;
}
#endif
extern void add_input_randomness(unsigned int type, unsigned int code, extern void add_input_randomness(unsigned int type, unsigned int code,
unsigned int value); unsigned int value);
extern void add_interrupt_randomness(int irq); extern void add_interrupt_randomness(int irq);
......
...@@ -540,6 +540,15 @@ void __init __weak thread_info_cache_init(void) ...@@ -540,6 +540,15 @@ void __init __weak thread_info_cache_init(void)
{ {
} }
void __init __weak arch_early_irq_init(void)
{
}
void __init __weak early_irq_init(void)
{
arch_early_irq_init();
}
asmlinkage void __init start_kernel(void) asmlinkage void __init start_kernel(void)
{ {
char * command_line; char * command_line;
...@@ -604,6 +613,8 @@ asmlinkage void __init start_kernel(void) ...@@ -604,6 +613,8 @@ asmlinkage void __init start_kernel(void)
sort_main_extable(); sort_main_extable();
trap_init(); trap_init();
rcu_init(); rcu_init();
/* init some links before init_ISA_irqs() */
early_irq_init();
init_IRQ(); init_IRQ();
pidhash_init(); pidhash_init();
init_timers(); init_timers();
......
...@@ -40,6 +40,9 @@ unsigned long probe_irq_on(void) ...@@ -40,6 +40,9 @@ unsigned long probe_irq_on(void)
* flush such a longstanding irq before considering it as spurious. * flush such a longstanding irq before considering it as spurious.
*/ */
for_each_irq_desc_reverse(i, desc) { for_each_irq_desc_reverse(i, desc) {
if (!desc)
continue;
spin_lock_irq(&desc->lock); spin_lock_irq(&desc->lock);
if (!desc->action && !(desc->status & IRQ_NOPROBE)) { if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
/* /*
...@@ -68,6 +71,9 @@ unsigned long probe_irq_on(void) ...@@ -68,6 +71,9 @@ unsigned long probe_irq_on(void)
* happened in the previous stage, it may have masked itself) * happened in the previous stage, it may have masked itself)
*/ */
for_each_irq_desc_reverse(i, desc) { for_each_irq_desc_reverse(i, desc) {
if (!desc)
continue;
spin_lock_irq(&desc->lock); spin_lock_irq(&desc->lock);
if (!desc->action && !(desc->status & IRQ_NOPROBE)) { if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
desc->status |= IRQ_AUTODETECT | IRQ_WAITING; desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
...@@ -86,6 +92,9 @@ unsigned long probe_irq_on(void) ...@@ -86,6 +92,9 @@ unsigned long probe_irq_on(void)
* Now filter out any obviously spurious interrupts * Now filter out any obviously spurious interrupts
*/ */
for_each_irq_desc(i, desc) { for_each_irq_desc(i, desc) {
if (!desc)
continue;
spin_lock_irq(&desc->lock); spin_lock_irq(&desc->lock);
status = desc->status; status = desc->status;
...@@ -124,6 +133,9 @@ unsigned int probe_irq_mask(unsigned long val) ...@@ -124,6 +133,9 @@ unsigned int probe_irq_mask(unsigned long val)
int i; int i;
for_each_irq_desc(i, desc) { for_each_irq_desc(i, desc) {
if (!desc)
continue;
spin_lock_irq(&desc->lock); spin_lock_irq(&desc->lock);
status = desc->status; status = desc->status;
...@@ -166,6 +178,9 @@ int probe_irq_off(unsigned long val) ...@@ -166,6 +178,9 @@ int probe_irq_off(unsigned long val)
unsigned int status; unsigned int status;
for_each_irq_desc(i, desc) { for_each_irq_desc(i, desc) {
if (!desc)
continue;
spin_lock_irq(&desc->lock); spin_lock_irq(&desc->lock);
status = desc->status; status = desc->status;
......
...@@ -24,9 +24,10 @@ ...@@ -24,9 +24,10 @@
*/ */
void dynamic_irq_init(unsigned int irq) void dynamic_irq_init(unsigned int irq)
{ {
struct irq_desc *desc = irq_to_desc(irq); struct irq_desc *desc;
unsigned long flags; unsigned long flags;
desc = irq_to_desc(irq);
if (!desc) { if (!desc) {
WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq); WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
return; return;
......
...@@ -15,9 +15,16 @@ ...@@ -15,9 +15,16 @@
#include <linux/random.h> #include <linux/random.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/kernel_stat.h> #include <linux/kernel_stat.h>
#include <linux/rculist.h>
#include <linux/hash.h>
#include "internals.h" #include "internals.h"
/*
* lockdep: we want to handle all irq_desc locks as a single lock-class:
*/
static struct lock_class_key irq_desc_lock_class;
/** /**
* handle_bad_irq - handle spurious and unhandled irqs * handle_bad_irq - handle spurious and unhandled irqs
* @irq: the interrupt number * @irq: the interrupt number
...@@ -49,6 +56,155 @@ void handle_bad_irq(unsigned int irq, struct irq_desc *desc) ...@@ -49,6 +56,155 @@ void handle_bad_irq(unsigned int irq, struct irq_desc *desc)
int nr_irqs = NR_IRQS; int nr_irqs = NR_IRQS;
EXPORT_SYMBOL_GPL(nr_irqs); EXPORT_SYMBOL_GPL(nr_irqs);
void __init __attribute__((weak)) arch_early_irq_init(void)
{
}
#ifdef CONFIG_SPARSE_IRQ
static struct irq_desc irq_desc_init = {
.irq = -1,
.status = IRQ_DISABLED,
.chip = &no_irq_chip,
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
#ifdef CONFIG_SMP
.affinity = CPU_MASK_ALL
#endif
};
static void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr)
{
unsigned long bytes;
char *ptr;
int node;
/* Compute how many bytes we need per irq and allocate them */
bytes = nr * sizeof(unsigned int);
node = cpu_to_node(cpu);
ptr = kzalloc_node(bytes, GFP_ATOMIC, node);
printk(KERN_DEBUG " alloc kstat_irqs on cpu %d node %d\n", cpu, node);
if (ptr)
desc->kstat_irqs = (unsigned int *)ptr;
}
void __attribute__((weak)) arch_init_chip_data(struct irq_desc *desc, int cpu)
{
}
static void init_one_irq_desc(int irq, struct irq_desc *desc, int cpu)
{
memcpy(desc, &irq_desc_init, sizeof(struct irq_desc));
desc->irq = irq;
#ifdef CONFIG_SMP
desc->cpu = cpu;
#endif
lockdep_set_class(&desc->lock, &irq_desc_lock_class);
init_kstat_irqs(desc, cpu, nr_cpu_ids);
if (!desc->kstat_irqs) {
printk(KERN_ERR "can not alloc kstat_irqs\n");
BUG_ON(1);
}
arch_init_chip_data(desc, cpu);
}
/*
* Protect the sparse_irqs:
*/
static DEFINE_SPINLOCK(sparse_irq_lock);
struct irq_desc *irq_desc_ptrs[NR_IRQS] __read_mostly;
static struct irq_desc irq_desc_legacy[NR_IRQS_LEGACY] __cacheline_aligned_in_smp = {
[0 ... NR_IRQS_LEGACY-1] = {
.irq = -1,
.status = IRQ_DISABLED,
.chip = &no_irq_chip,
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __SPIN_LOCK_UNLOCKED(irq_desc_init.lock),
#ifdef CONFIG_SMP
.affinity = CPU_MASK_ALL
#endif
}
};
/* FIXME: use bootmem alloc ...*/
static unsigned int kstat_irqs_legacy[NR_IRQS_LEGACY][NR_CPUS];
void __init early_irq_init(void)
{
struct irq_desc *desc;
int legacy_count;
int i;
desc = irq_desc_legacy;
legacy_count = ARRAY_SIZE(irq_desc_legacy);
for (i = 0; i < legacy_count; i++) {
desc[i].irq = i;
desc[i].kstat_irqs = kstat_irqs_legacy[i];
irq_desc_ptrs[i] = desc + i;
}
for (i = legacy_count; i < NR_IRQS; i++)
irq_desc_ptrs[i] = NULL;
arch_early_irq_init();
}
struct irq_desc *irq_to_desc(unsigned int irq)
{
return (irq < NR_IRQS) ? irq_desc_ptrs[irq] : NULL;
}
struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu)
{
struct irq_desc *desc;
unsigned long flags;
int node;
if (irq >= NR_IRQS) {
printk(KERN_WARNING "irq >= NR_IRQS in irq_to_desc_alloc: %d %d\n",
irq, NR_IRQS);
WARN_ON(1);
return NULL;
}
desc = irq_desc_ptrs[irq];
if (desc)
return desc;
spin_lock_irqsave(&sparse_irq_lock, flags);
/* We have to check it to avoid races with another CPU */
desc = irq_desc_ptrs[irq];
if (desc)
goto out_unlock;
node = cpu_to_node(cpu);
desc = kzalloc_node(sizeof(*desc), GFP_ATOMIC, node);
printk(KERN_DEBUG " alloc irq_desc for %d on cpu %d node %d\n",
irq, cpu, node);
if (!desc) {
printk(KERN_ERR "can not alloc irq_desc\n");
BUG_ON(1);
}
init_one_irq_desc(irq, desc, cpu);
irq_desc_ptrs[irq] = desc;
out_unlock:
spin_unlock_irqrestore(&sparse_irq_lock, flags);
return desc;
}
#else
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
[0 ... NR_IRQS-1] = { [0 ... NR_IRQS-1] = {
.status = IRQ_DISABLED, .status = IRQ_DISABLED,
...@@ -62,6 +218,8 @@ struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { ...@@ -62,6 +218,8 @@ struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
} }
}; };
#endif
/* /*
* What should we do if we get a hw irq event on an illegal vector? * What should we do if we get a hw irq event on an illegal vector?
* Each architecture has to answer this themself. * Each architecture has to answer this themself.
...@@ -261,17 +419,28 @@ unsigned int __do_IRQ(unsigned int irq) ...@@ -261,17 +419,28 @@ unsigned int __do_IRQ(unsigned int irq)
#ifdef CONFIG_TRACE_IRQFLAGS #ifdef CONFIG_TRACE_IRQFLAGS
/*
* lockdep: we want to handle all irq_desc locks as a single lock-class:
*/
static struct lock_class_key irq_desc_lock_class;
void early_init_irq_lock_class(void) void early_init_irq_lock_class(void)
{ {
#ifndef CONFIG_SPARSE_IRQ
struct irq_desc *desc; struct irq_desc *desc;
int i; int i;
for_each_irq_desc(i, desc) for_each_irq_desc(i, desc) {
if (!desc)
continue;
lockdep_set_class(&desc->lock, &irq_desc_lock_class); lockdep_set_class(&desc->lock, &irq_desc_lock_class);
}
#endif
} }
#endif #endif
#ifdef CONFIG_SPARSE_IRQ
unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
{
struct irq_desc *desc = irq_to_desc(irq);
return desc->kstat_irqs[cpu];
}
#endif
EXPORT_SYMBOL(kstat_irqs_cpu);
...@@ -243,7 +243,11 @@ void init_irq_proc(void) ...@@ -243,7 +243,11 @@ void init_irq_proc(void)
/* /*
* Create entries for all existing IRQs. * Create entries for all existing IRQs.
*/ */
for_each_irq_desc(irq, desc) for_each_irq_desc(irq, desc) {
if (!desc)
continue;
register_irq_proc(irq, desc); register_irq_proc(irq, desc);
}
} }
...@@ -91,6 +91,9 @@ static int misrouted_irq(int irq) ...@@ -91,6 +91,9 @@ static int misrouted_irq(int irq)
int i, ok = 0; int i, ok = 0;
for_each_irq_desc(i, desc) { for_each_irq_desc(i, desc) {
if (!desc)
continue;
if (!i) if (!i)
continue; continue;
...@@ -112,6 +115,8 @@ static void poll_spurious_irqs(unsigned long dummy) ...@@ -112,6 +115,8 @@ static void poll_spurious_irqs(unsigned long dummy)
for_each_irq_desc(i, desc) { for_each_irq_desc(i, desc) {
unsigned int status; unsigned int status;
if (!desc)
continue;
if (!i) if (!i)
continue; continue;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment