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
def_bool y
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
def_bool y
depends on X86_MPPARSE || X86_VOYAGER
......@@ -468,10 +478,6 @@ config X86_CYCLONE_TIMER
def_bool y
depends on X86_GENERICARCH
config ES7000_CLUSTERED_APIC
def_bool y
depends on SMP && X86_ES7000 && MPENTIUMIII
source "arch/x86/Kconfig.cpu"
config HPET_TIMER
......@@ -1635,13 +1641,6 @@ config APM_ALLOW_INTS
many of the newer IBM Thinkpads. If you experience hangs when you
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
source "arch/x86/kernel/cpu/cpufreq/Kconfig"
......
......@@ -193,6 +193,7 @@ extern u8 setup_APIC_eilvt_ibs(u8 vector, u8 msg_type, u8 mask);
static inline void lapic_shutdown(void) { }
#define local_apic_timer_c2_ok 1
static inline void init_apic_mappings(void) { }
static inline void disable_local_APIC(void) { }
#endif /* !CONFIG_X86_LOCAL_APIC */
......
......@@ -24,8 +24,6 @@ static inline cpumask_t target_cpus(void)
#define INT_DELIVERY_MODE (dest_Fixed)
#define INT_DEST_MODE (0) /* phys delivery to target proc */
#define NO_BALANCE_IRQ (0)
#define WAKE_SECONDARY_VIA_INIT
static inline unsigned long check_apicid_used(physid_mask_t bitmap, int apicid)
{
......
......@@ -8,7 +8,9 @@ enum reboot_type {
BOOT_BIOS = 'b',
#endif
BOOT_ACPI = 'a',
BOOT_EFI = 'e'
BOOT_EFI = 'e',
BOOT_CF9 = 'p',
BOOT_CF9_COND = 'q',
};
extern enum reboot_type reboot_type;
......
......@@ -9,31 +9,27 @@ static inline int apic_id_registered(void)
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;
#else
}
static inline cpumask_t target_cpus(void)
{
return cpumask_of_cpu(smp_processor_id());
#endif
}
#if defined CONFIG_ES7000_CLUSTERED_APIC
#define APIC_DFR_VALUE (APIC_DFR_CLUSTER)
#define INT_DELIVERY_MODE (dest_LowestPrio)
#define INT_DEST_MODE (1) /* logical delivery broadcast to all procs */
#define NO_BALANCE_IRQ (1)
#undef WAKE_SECONDARY_VIA_INIT
#define WAKE_SECONDARY_VIA_MIP
#else
#define APIC_DFR_VALUE_CLUSTER (APIC_DFR_CLUSTER)
#define INT_DELIVERY_MODE_CLUSTER (dest_LowestPrio)
#define INT_DEST_MODE_CLUSTER (1) /* logical delivery broadcast to all procs */
#define NO_BALANCE_IRQ_CLUSTER (1)
#define APIC_DFR_VALUE (APIC_DFR_FLAT)
#define INT_DELIVERY_MODE (dest_Fixed)
#define INT_DEST_MODE (0) /* phys delivery to target procs */
#define NO_BALANCE_IRQ (0)
#undef APIC_DEST_LOGICAL
#define APIC_DEST_LOGICAL 0x0
#define WAKE_SECONDARY_VIA_INIT
#endif
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)
* an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
* 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)
{
unsigned long val;
......@@ -70,10 +76,6 @@ static inline void init_apic_ldr(void)
apic_write(APIC_LDR, val);
}
#ifndef CONFIG_X86_GENERICARCH
extern void enable_apic_mode(void);
#endif
extern int apic_version [MAX_APICS];
static inline void setup_apic_routing(void)
{
......@@ -144,7 +146,7 @@ static inline int check_phys_apicid_present(int cpu_physical_apicid)
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 cpus_found = 0;
......@@ -154,11 +156,7 @@ static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
num_bits_set = cpus_weight(cpumask);
/* Return id to all */
if (num_bits_set == NR_CPUS)
#if defined CONFIG_ES7000_CLUSTERED_APIC
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
* 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)
if (apicid_cluster(apicid) !=
apicid_cluster(new_apicid)){
printk ("%s: Not a valid mask!\n", __func__);
#if defined CONFIG_ES7000_CLUSTERED_APIC
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);
#endif
}
apicid = new_apicid;
cpus_found++;
......
#ifndef __ASM_ES7000_WAKECPU_H
#define __ASM_ES7000_WAKECPU_H
/*
* This file copes with machines that wakeup secondary CPUs by the
* 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
#define TRAMPOLINE_PHYS_LOW 0x467
#define TRAMPOLINE_PHYS_HIGH 0x469
static inline void wait_for_init_deassert(atomic_t *deassert)
{
#ifdef WAKE_SECONDARY_VIA_INIT
#ifndef CONFIG_ES7000_CLUSTERED_APIC
while (!atomic_read(deassert))
cpu_relax();
#endif
......@@ -50,9 +26,12 @@ static inline void restore_NMI_vector(unsigned short *high, unsigned short *low)
{
}
#define inquire_remote_apic(apicid) do { \
if (apic_verbosity >= APIC_DEBUG) \
__inquire_remote_apic(apicid); \
} while (0)
extern void __inquire_remote_apic(int apicid);
static inline void inquire_remote_apic(int apicid)
{
if (apic_verbosity >= APIC_DEBUG)
__inquire_remote_apic(apicid);
}
#endif /* __ASM_MACH_WAKECPU_H */
......@@ -2,6 +2,7 @@
#define _ASM_X86_GENAPIC_32_H
#include <asm/mpspec.h>
#include <asm/atomic.h>
/*
* Generic APIC driver interface.
......@@ -65,6 +66,14 @@ struct genapic {
void (*send_IPI_allbutself)(int vector);
void (*send_IPI_all)(int vector);
#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,
......@@ -112,9 +121,17 @@ struct genapic {
IPIFUNC(send_IPI_all) \
APICFUNC(enable_apic_mode) \
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 void es7000_update_genapic_to_cluster(void);
enum uv_system_type {UV_NONE, UV_LEGACY_APIC, UV_X2APIC, UV_NON_UNIQUE_APIC};
#define get_uv_system_type() UV_NONE
......
......@@ -32,6 +32,8 @@ struct genapic {
unsigned int (*get_apic_id)(unsigned long x);
unsigned long (*set_apic_id)(unsigned int id);
unsigned long apic_id_mask;
/* wakeup_secondary_cpu */
int (*wakeup_cpu)(int apicid, unsigned long start_eip);
};
extern struct genapic *genapic;
......
......@@ -188,17 +188,14 @@ extern void restore_IO_APIC_setup(void);
extern void reinit_intr_remapped_IO_APIC(int);
#endif
extern int probe_nr_irqs(void);
extern void probe_nr_irqs_gsi(void);
#else /* !CONFIG_X86_IO_APIC */
#define io_apic_assign_pci_irqs 0
static const int timer_through_8259 = 0;
static inline void ioapic_init_mappings(void) { }
static inline int probe_nr_irqs(void)
{
return NR_IRQS;
}
static inline void probe_nr_irqs_gsi(void) { }
#endif
#endif /* _ASM_X86_IO_APIC_H */
......@@ -101,12 +101,23 @@
#define LAST_VM86_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)
#ifndef CONFIG_SPARSE_IRQ
# if NR_CPUS < MAX_IO_APICS
# define NR_IRQS (NR_VECTORS + (32 * NR_CPUS))
# else
# define NR_IRQS (NR_VECTORS + (32 * MAX_IO_APICS))
# 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)
......
......@@ -32,11 +32,13 @@ static inline cpumask_t target_cpus(void)
#define vector_allocation_domain (genapic->vector_allocation_domain)
#define read_apic_id() (GET_APIC_ID(apic_read(APIC_ID)))
#define send_IPI_self (genapic->send_IPI_self)
#define wakeup_secondary_cpu (genapic->wakeup_cpu)
extern void setup_apic_routing(void);
#else
#define INT_DELIVERY_MODE dest_LowestPrio
#define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */
#define TARGET_CPUS (target_cpus())
#define wakeup_secondary_cpu wakeup_secondary_cpu_via_init
/*
* Set up the logical destination ID.
*
......
#ifndef _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H
#define _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H
/*
* This file copes with machines that wakeup secondary CPUs by the
* 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
#define TRAMPOLINE_PHYS_LOW (0x467)
#define TRAMPOLINE_PHYS_HIGH (0x469)
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)
{
}
#define inquire_remote_apic(apicid) do { \
if (apic_verbosity >= APIC_DEBUG) \
__inquire_remote_apic(apicid); \
} while (0)
extern void __inquire_remote_apic(int apicid);
static inline void inquire_remote_apic(int apicid)
{
if (apic_verbosity >= APIC_DEBUG)
__inquire_remote_apic(apicid);
}
#endif /* _ASM_X86_MACH_DEFAULT_MACH_WAKECPU_H */
......@@ -13,9 +13,11 @@ static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
CMOS_WRITE(0xa, 0xf);
local_flush_tlb();
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");
*((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_LOW)) =
start_eip & 0xf;
pr_debug("3.\n");
}
......@@ -32,7 +34,7 @@ static inline void smpboot_restore_warm_reset_vector(void)
*/
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)
......
......@@ -27,6 +27,7 @@
#define vector_allocation_domain (genapic->vector_allocation_domain)
#define enable_apic_mode (genapic->enable_apic_mode)
#define phys_pkg_id (genapic->phys_pkg_id)
#define wakeup_secondary_cpu (genapic->wakeup_cpu)
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 @@
/* This file copes with machines that wakeup secondary CPUs by NMIs */
#define WAKE_SECONDARY_VIA_NMI
#define TRAMPOLINE_LOW phys_to_virt(0x8)
#define TRAMPOLINE_HIGH phys_to_virt(0xa)
#define boot_cpu_apicid boot_cpu_logical_apicid
#define TRAMPOLINE_PHYS_LOW (0x8)
#define TRAMPOLINE_PHYS_HIGH (0xa)
/* We don't do anything here because we use NMI's to boot instead */
static inline void wait_for_init_deassert(atomic_t *deassert)
......@@ -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)
{
printk("Storing NMI vector\n");
*high = *((volatile unsigned short *) TRAMPOLINE_HIGH);
*low = *((volatile unsigned short *) TRAMPOLINE_LOW);
*high =
*((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)
{
printk("Restoring NMI vector\n");
*((volatile unsigned short *) TRAMPOLINE_HIGH) = *high;
*((volatile unsigned short *) TRAMPOLINE_LOW) = *low;
*((volatile unsigned short *)phys_to_virt(TRAMPOLINE_PHYS_HIGH)) =
*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 */
......@@ -16,6 +16,8 @@ static inline void visws_early_detect(void) { }
static inline int is_visws_box(void) { return 0; }
#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?
*/
......@@ -39,6 +41,7 @@ struct x86_quirks {
void (*smp_read_mpc_oem)(struct mp_config_oemtable *oemtable,
unsigned short oemsize);
int (*setup_ioapic_ids)(void);
int (*update_genapic)(void);
};
extern struct x86_quirks *x86_quirks;
......
......@@ -314,6 +314,8 @@ extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
void default_idle(void);
void stop_this_cpu(void *dummy);
/*
* Force strict CPU ordering.
* And yes, this is required on UP too when we're talking
......
......@@ -1360,6 +1360,17 @@ static void __init acpi_process_madt(void)
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
return;
}
......
......@@ -391,11 +391,7 @@ static int power_off;
#else
static int power_off = 1;
#endif
#ifdef CONFIG_APM_REAL_MODE_POWER_OFF
static int realmode_power_off = 1;
#else
static int realmode_power_off;
#endif
#ifdef CONFIG_APM_ALLOW_INTS
static int allow_ints = 1;
#else
......
......@@ -38,8 +38,11 @@
#include <asm/io.h>
#include <asm/nmi.h>
#include <asm/smp.h>
#include <asm/atomic.h>
#include <asm/apicdef.h>
#include <mach_mpparse.h>
#include <asm/genapic.h>
#include <asm/setup.h>
/*
* ES7000 chipsets
......@@ -161,6 +164,43 @@ es7000_rename_gsi(int ioapic, int 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
setup_unisys(void)
{
......@@ -176,6 +216,8 @@ setup_unisys(void)
else
es7000_plat = ES7000_CLASSIC;
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)
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
es7000_sw_apic(void)
{
......
......@@ -21,6 +21,7 @@
#include <asm/smp.h>
#include <asm/ipi.h>
#include <asm/genapic.h>
#include <asm/setup.h>
extern struct genapic apic_flat;
extern struct genapic apic_physflat;
......@@ -53,6 +54,9 @@ void __init setup_apic_routing(void)
genapic = &apic_physflat;
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. */
......
......@@ -108,8 +108,33 @@ static int __init parse_noapic(char *str)
early_param("noapic", parse_noapic);
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 {
unsigned int irq;
struct irq_pin_list *irq_2_pin;
cpumask_t domain;
cpumask_t old_domain;
......@@ -119,81 +144,95 @@ struct irq_cfg {
};
/* 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] = {
[0] = { .irq = 0, .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR, },
[1] = { .irq = 1, .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR, },
[2] = { .irq = 2, .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR, },
[3] = { .irq = 3, .domain = CPU_MASK_ALL, .vector = IRQ3_VECTOR, },
[4] = { .irq = 4, .domain = CPU_MASK_ALL, .vector = IRQ4_VECTOR, },
[5] = { .irq = 5, .domain = CPU_MASK_ALL, .vector = IRQ5_VECTOR, },
[6] = { .irq = 6, .domain = CPU_MASK_ALL, .vector = IRQ6_VECTOR, },
[7] = { .irq = 7, .domain = CPU_MASK_ALL, .vector = IRQ7_VECTOR, },
[8] = { .irq = 8, .domain = CPU_MASK_ALL, .vector = IRQ8_VECTOR, },
[9] = { .irq = 9, .domain = CPU_MASK_ALL, .vector = IRQ9_VECTOR, },
[10] = { .irq = 10, .domain = CPU_MASK_ALL, .vector = IRQ10_VECTOR, },
[11] = { .irq = 11, .domain = CPU_MASK_ALL, .vector = IRQ11_VECTOR, },
[12] = { .irq = 12, .domain = CPU_MASK_ALL, .vector = IRQ12_VECTOR, },
[13] = { .irq = 13, .domain = CPU_MASK_ALL, .vector = IRQ13_VECTOR, },
[14] = { .irq = 14, .domain = CPU_MASK_ALL, .vector = IRQ14_VECTOR, },
[15] = { .irq = 15, .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, },
#endif
[0] = { .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR, },
[1] = { .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR, },
[2] = { .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR, },
[3] = { .domain = CPU_MASK_ALL, .vector = IRQ3_VECTOR, },
[4] = { .domain = CPU_MASK_ALL, .vector = IRQ4_VECTOR, },
[5] = { .domain = CPU_MASK_ALL, .vector = IRQ5_VECTOR, },
[6] = { .domain = CPU_MASK_ALL, .vector = IRQ6_VECTOR, },
[7] = { .domain = CPU_MASK_ALL, .vector = IRQ7_VECTOR, },
[8] = { .domain = CPU_MASK_ALL, .vector = IRQ8_VECTOR, },
[9] = { .domain = CPU_MASK_ALL, .vector = IRQ9_VECTOR, },
[10] = { .domain = CPU_MASK_ALL, .vector = IRQ10_VECTOR, },
[11] = { .domain = CPU_MASK_ALL, .vector = IRQ11_VECTOR, },
[12] = { .domain = CPU_MASK_ALL, .vector = IRQ12_VECTOR, },
[13] = { .domain = CPU_MASK_ALL, .vector = IRQ13_VECTOR, },
[14] = { .domain = CPU_MASK_ALL, .vector = IRQ14_VECTOR, },
[15] = { .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, },
};
#define for_each_irq_cfg(irq, cfg) \
for (irq = 0, cfg = irq_cfgx; irq < nr_irqs; irq++, cfg++)
static struct irq_cfg *irq_cfg(unsigned int irq)
void __init arch_early_irq_init(void)
{
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;
}
/*
* Rough estimation of how many shared IRQs there are, can be changed
* anytime.
*/
#define MAX_PLUS_SHARED_IRQS NR_IRQS
#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
static struct irq_cfg *get_one_free_irq_cfg(int cpu)
{
struct irq_cfg *cfg;
int node;
/*
* 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.
*/
node = cpu_to_node(cpu);
struct irq_pin_list {
int apic, pin;
struct irq_pin_list *next;
};
cfg = kzalloc_node(sizeof(*cfg), GFP_ATOMIC, node);
printk(KERN_DEBUG " alloc irq_cfg on cpu %d node %d\n", cpu, node);
static struct irq_pin_list irq_2_pin_head[PIN_MAP_SIZE];
static struct irq_pin_list *irq_2_pin_ptr;
return cfg;
}
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;
int i;
for (i = 1; i < PIN_MAP_SIZE; i++)
pin[i-1].next = &pin[i];
struct irq_cfg *cfg;
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)
panic("can not get more irq_2_pin\n");
#endif
irq_2_pin_ptr = pin->next;
pin->next = NULL;
return pin;
static inline void set_extra_move_desc(struct irq_desc *desc, cpumask_t mask)
{
}
struct io_apic {
......@@ -237,11 +276,10 @@ static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned
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;
unsigned long flags;
struct irq_cfg *cfg = irq_cfg(irq);
spin_lock_irqsave(&ioapic_lock, flags);
entry = cfg->irq_2_pin;
......@@ -323,13 +361,12 @@ static void ioapic_mask_entry(int apic, int pin)
}
#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;
struct irq_cfg *cfg;
struct irq_pin_list *entry;
u8 vector = cfg->vector;
cfg = irq_cfg(irq);
entry = cfg->irq_2_pin;
for (;;) {
unsigned int reg;
......@@ -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;
unsigned long flags;
unsigned int dest;
cpumask_t tmp;
struct irq_desc *desc;
unsigned int irq;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
return;
cfg = irq_cfg(irq);
if (assign_irq_vector(irq, mask))
irq = desc->irq;
cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return;
set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp);
/*
......@@ -384,12 +424,20 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
*/
dest = SET_APIC_LOGICAL_ID(dest);
desc = irq_to_desc(irq);
spin_lock_irqsave(&ioapic_lock, flags);
__target_IO_APIC_irq(irq, dest, cfg->vector);
__target_IO_APIC_irq(irq, dest, cfg);
desc->affinity = mask;
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 */
/*
......@@ -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
* 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;
/* first time to refer irq_cfg, so with new */
cfg = irq_cfg_alloc(irq);
entry = cfg->irq_2_pin;
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;
entry->apic = apic;
entry->pin = pin;
......@@ -421,7 +471,7 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
entry = entry->next;
}
entry->next = get_one_free_irq_2_pin();
entry->next = get_one_free_irq_2_pin(cpu);
entry = entry->next;
entry->apic = apic;
entry->pin = 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.
*/
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 newapic, int newpin)
{
struct irq_cfg *cfg = irq_cfg(irq);
struct irq_pin_list *entry = cfg->irq_2_pin;
int replaced = 0;
......@@ -451,18 +500,16 @@ static void __init replace_pin_at_irq(unsigned int irq,
/* why? call replace before add? */
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,
void (*final)(struct irq_pin_list *entry))
{
int pin;
struct irq_cfg *cfg;
struct irq_pin_list *entry;
cfg = irq_cfg(irq);
for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) {
unsigned int reg;
pin = entry->pin;
......@@ -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
......@@ -492,47 +539,64 @@ void io_apic_sync(struct irq_pin_list *entry)
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 */
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);
}
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);
}
#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;
BUG_ON(!cfg);
spin_lock_irqsave(&ioapic_lock, flags);
__mask_IO_APIC_irq(irq);
__mask_IO_APIC_irq(cfg);
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;
spin_lock_irqsave(&ioapic_lock, flags);
__unmask_IO_APIC_irq(irq);
__unmask_IO_APIC_irq(cfg);
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)
{
struct IO_APIC_route_entry entry;
......@@ -809,7 +873,7 @@ EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
*/
static int EISA_ELCR(unsigned int irq)
{
if (irq < 16) {
if (irq < NR_IRQS_LEGACY) {
unsigned int port = 0x4d0 + (irq >> 3);
return (inb(port) >> (irq & 7)) & 1;
}
......@@ -1034,7 +1098,7 @@ void unlock_vector_lock(void)
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
......@@ -1050,16 +1114,13 @@ static int __assign_irq_vector(int irq, cpumask_t mask)
static int current_vector = FIRST_DEVICE_VECTOR, current_offset = 0;
unsigned int old_vector;
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 */
cpus_and(mask, mask, cpu_online_map);
if ((cfg->move_in_progress) || cfg->move_cleanup_count)
return -EBUSY;
old_vector = cfg->vector;
if (old_vector) {
cpumask_t tmp;
......@@ -1113,24 +1174,22 @@ static int __assign_irq_vector(int irq, cpumask_t mask)
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;
unsigned long 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);
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;
int cpu, vector;
cfg = irq_cfg(irq);
BUG_ON(!cfg->vector);
vector = cfg->vector;
......@@ -1162,9 +1221,13 @@ void __setup_vector_irq(int cpu)
/* This function must be called with vector_lock held */
int irq, vector;
struct irq_cfg *cfg;
struct irq_desc *desc;
/* 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))
continue;
vector = cfg->vector;
......@@ -1215,11 +1278,8 @@ static inline int IO_APIC_irq_trigger(int irq)
}
#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)) ||
trigger == IOAPIC_LEVEL)
......@@ -1311,7 +1371,7 @@ static int setup_ioapic_entry(int apic, int irq,
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)
{
struct irq_cfg *cfg;
......@@ -1321,10 +1381,10 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
if (!IO_APIC_IRQ(irq))
return;
cfg = irq_cfg(irq);
cfg = desc->chip_data;
mask = TARGET_CPUS;
if (assign_irq_vector(irq, mask))
if (assign_irq_vector(irq, cfg, mask))
return;
cpus_and(mask, cfg->domain, mask);
......@@ -1341,12 +1401,12 @@ static void setup_IO_APIC_irq(int apic, int pin, unsigned int irq,
cfg->vector)) {
printk("Failed to setup ioapic entry for ioapic %d, pin %d\n",
mp_ioapics[apic].mp_apicid, pin);
__clear_irq_vector(irq);
__clear_irq_vector(irq, cfg);
return;
}
ioapic_register_intr(irq, trigger);
if (irq < 16)
ioapic_register_intr(irq, desc, trigger);
if (irq < NR_IRQS_LEGACY)
disable_8259A_irq(irq);
ioapic_write_entry(apic, pin, entry);
......@@ -1356,6 +1416,9 @@ static void __init setup_IO_APIC_irqs(void)
{
int apic, pin, idx, irq;
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");
......@@ -1387,9 +1450,15 @@ static void __init setup_IO_APIC_irqs(void)
if (multi_timer_check(apic, irq))
continue;
#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));
}
}
......@@ -1448,6 +1517,7 @@ __apicdebuginit(void) print_IO_APIC(void)
union IO_APIC_reg_03 reg_03;
unsigned long flags;
struct irq_cfg *cfg;
struct irq_desc *desc;
unsigned int irq;
if (apic_verbosity == APIC_QUIET)
......@@ -1537,8 +1607,13 @@ __apicdebuginit(void) print_IO_APIC(void)
}
}
printk(KERN_DEBUG "IRQ to pin mappings:\n");
for_each_irq_cfg(irq, cfg) {
struct irq_pin_list *entry = cfg->irq_2_pin;
for_each_irq_desc(irq, desc) {
struct irq_pin_list *entry;
if (!desc)
continue;
cfg = desc->chip_data;
entry = cfg->irq_2_pin;
if (!entry)
continue;
printk(KERN_DEBUG "IRQ%d ", irq);
......@@ -2022,14 +2097,16 @@ static unsigned int startup_ioapic_irq(unsigned int irq)
{
int was_pending = 0;
unsigned long flags;
struct irq_cfg *cfg;
spin_lock_irqsave(&ioapic_lock, flags);
if (irq < 16) {
if (irq < NR_IRQS_LEGACY) {
disable_8259A_irq(irq);
if (i8259A_irq_pending(irq))
was_pending = 1;
}
__unmask_IO_APIC_irq(irq);
cfg = irq_cfg(irq);
__unmask_IO_APIC_irq(cfg);
spin_unlock_irqrestore(&ioapic_lock, flags);
return was_pending;
......@@ -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
* 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_desc *desc;
cpumask_t tmp, cleanup_mask;
struct irte irte;
int modify_ioapic_rte;
unsigned int dest;
unsigned long flags;
unsigned int irq;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
return;
irq = desc->irq;
if (get_irte(irq, &irte))
return;
if (assign_irq_vector(irq, mask))
cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return;
cfg = irq_cfg(irq);
set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp);
desc = irq_to_desc(irq);
modify_ioapic_rte = desc->status & IRQ_LEVEL;
if (modify_ioapic_rte) {
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);
}
......@@ -2142,14 +2221,14 @@ static void migrate_ioapic_irq(int irq, cpumask_t 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;
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
* vector information in the IO-APIC RTE and that will confuse
......@@ -2161,14 +2240,15 @@ static int migrate_irq_remapped_level(int irq)
}
/* 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;
desc->status &= ~IRQ_MOVE_PENDING;
cpus_clear(desc->pending_mask);
unmask:
unmask_IO_APIC_irq(irq);
unmask_IO_APIC_irq_desc(desc);
return ret;
}
......@@ -2178,6 +2258,9 @@ static void ir_irq_migration(struct work_struct *work)
struct irq_desc *desc;
for_each_irq_desc(irq, desc) {
if (!desc)
continue;
if (desc->status & IRQ_MOVE_PENDING) {
unsigned long flags;
......@@ -2198,18 +2281,22 @@ static void ir_irq_migration(struct work_struct *work)
/*
* 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) {
desc->status |= IRQ_MOVE_PENDING;
desc->pending_mask = mask;
migrate_irq_remapped_level(irq);
migrate_irq_remapped_level_desc(desc);
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
......@@ -2229,6 +2316,9 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
struct irq_cfg *cfg;
irq = __get_cpu_var(vector_irq)[vector];
if (irq == -1)
continue;
desc = irq_to_desc(irq);
if (!desc)
continue;
......@@ -2250,9 +2340,10 @@ asmlinkage void smp_irq_move_cleanup_interrupt(void)
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;
if (likely(!cfg->move_in_progress))
......@@ -2270,8 +2361,9 @@ static void irq_complete_move(unsigned int irq)
}
}
#else
static inline void irq_complete_move(unsigned int irq) {}
static inline void irq_complete_move(struct irq_desc **descp) {}
#endif
#ifdef CONFIG_INTR_REMAP
static void ack_x2apic_level(unsigned int irq)
{
......@@ -2282,11 +2374,14 @@ static void ack_x2apic_edge(unsigned int irq)
{
ack_x2APIC_irq();
}
#endif
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);
ack_APIC_irq();
}
......@@ -2295,18 +2390,21 @@ atomic_t irq_mis_count;
static void ack_apic_level(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
#ifdef CONFIG_X86_32
unsigned long v;
int i;
#endif
struct irq_cfg *cfg;
int do_unmask_irq = 0;
irq_complete_move(irq);
irq_complete_move(&desc);
#ifdef CONFIG_GENERIC_PENDING_IRQ
/* 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;
mask_IO_APIC_irq(irq);
mask_IO_APIC_irq_desc(desc);
}
#endif
......@@ -2330,7 +2428,8 @@ static void ack_apic_level(unsigned int irq)
* operation to prevent an edge-triggered interrupt escaping meanwhile.
* 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));
#endif
......@@ -2369,17 +2468,18 @@ static void ack_apic_level(unsigned int irq)
* accurate and is causing problems then it is a hardware bug
* 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);
unmask_IO_APIC_irq(irq);
unmask_IO_APIC_irq_desc(desc);
}
#ifdef CONFIG_X86_32
if (!(v & (1 << (i & 0x1f)))) {
atomic_inc(&irq_mis_count);
spin_lock(&ioapic_lock);
__mask_and_edge_IO_APIC_irq(irq);
__unmask_and_level_IO_APIC_irq(irq);
__mask_and_edge_IO_APIC_irq(cfg);
__unmask_and_level_IO_APIC_irq(cfg);
spin_unlock(&ioapic_lock);
}
#endif
......@@ -2430,22 +2530,24 @@ static inline void init_IO_APIC_traps(void)
* Also, we've got to be careful not to trash gate
* 0x80, because int 0x80 is hm, kind of importantish. ;)
*/
for_each_irq_cfg(irq, cfg) {
if (IO_APIC_IRQ(irq) && !cfg->vector) {
for_each_irq_desc(irq, desc) {
if (!desc)
continue;
cfg = desc->chip_data;
if (IO_APIC_IRQ(irq) && cfg && !cfg->vector) {
/*
* Hmm.. We don't have an entry for this,
* so default to an old-fashioned 8259
* interrupt if we can..
*/
if (irq < 16)
if (irq < NR_IRQS_LEGACY)
make_8259A_irq(irq);
else {
desc = irq_to_desc(irq);
else
/* Strange. Oh, well.. */
desc->chip = &no_irq_chip;
}
}
}
}
/*
......@@ -2468,7 +2570,7 @@ static void unmask_lapic_irq(unsigned int irq)
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();
}
......@@ -2480,11 +2582,8 @@ static struct irq_chip lapic_chip __read_mostly = {
.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;
set_irq_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq,
"edge");
......@@ -2588,7 +2687,9 @@ int timer_through_8259 __initdata;
*/
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;
unsigned long flags;
unsigned int ver;
......@@ -2603,7 +2704,7 @@ static inline void __init check_timer(void)
* get/set the timer IRQ vector:
*/
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
......@@ -2654,10 +2755,10 @@ static inline void __init check_timer(void)
* Ok, does IRQ0 through the IOAPIC work?
*/
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);
}
unmask_IO_APIC_irq(0);
unmask_IO_APIC_irq_desc(desc);
if (timer_irq_works()) {
if (nmi_watchdog == NMI_IO_APIC) {
setup_nmi();
......@@ -2683,9 +2784,9 @@ static inline void __init check_timer(void)
/*
* 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);
unmask_IO_APIC_irq(0);
unmask_IO_APIC_irq_desc(desc);
enable_8259A_irq(0);
if (timer_irq_works()) {
apic_printk(APIC_QUIET, KERN_INFO "....... works.\n");
......@@ -2717,7 +2818,7 @@ static inline void __init check_timer(void)
apic_printk(APIC_QUIET, KERN_INFO
"...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 */
enable_8259A_irq(0);
......@@ -2902,22 +3003,26 @@ unsigned int create_irq_nr(unsigned int irq_want)
unsigned int irq;
unsigned int new;
unsigned long flags;
struct irq_cfg *cfg_new;
irq_want = nr_irqs - 1;
struct irq_cfg *cfg_new = NULL;
int cpu = boot_cpu_id;
struct irq_desc *desc_new = NULL;
irq = 0;
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))
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;
/* check if need to create one */
if (!cfg_new)
cfg_new = irq_cfg_alloc(new);
if (__assign_irq_vector(new, TARGET_CPUS) == 0)
if (__assign_irq_vector(new, cfg_new, TARGET_CPUS) == 0)
irq = new;
break;
}
......@@ -2925,15 +3030,21 @@ unsigned int create_irq_nr(unsigned int irq_want)
if (irq > 0) {
dynamic_irq_init(irq);
/* restore it, in case dynamic_irq_init clear it */
if (desc_new)
desc_new->chip_data = cfg_new;
}
return irq;
}
static int nr_irqs_gsi = NR_IRQS_LEGACY;
int create_irq(void)
{
unsigned int irq_want;
int irq;
irq = create_irq_nr(nr_irqs - 1);
irq_want = nr_irqs_gsi;
irq = create_irq_nr(irq_want);
if (irq == 0)
irq = -1;
......@@ -2944,14 +3055,22 @@ int create_irq(void)
void destroy_irq(unsigned int irq)
{
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);
/* connect back irq_cfg */
if (desc)
desc->chip_data = cfg;
#ifdef CONFIG_INTR_REMAP
free_irte(irq);
#endif
spin_lock_irqsave(&vector_lock, flags);
__clear_irq_vector(irq);
__clear_irq_vector(irq, cfg);
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
unsigned dest;
cpumask_t tmp;
cfg = irq_cfg(irq);
tmp = TARGET_CPUS;
err = assign_irq_vector(irq, tmp);
err = assign_irq_vector(irq, cfg, tmp);
if (err)
return err;
cfg = irq_cfg(irq);
cpus_and(tmp, cfg->domain, 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
#ifdef CONFIG_SMP
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 msi_msg msg;
unsigned int dest;
cpumask_t tmp;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
return;
if (assign_irq_vector(irq, mask))
cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return;
cfg = irq_cfg(irq);
set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask);
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(cfg->vector);
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
write_msi_msg(irq, &msg);
desc = irq_to_desc(irq);
write_msi_msg_desc(desc, &msg);
desc->affinity = mask;
}
#ifdef CONFIG_INTR_REMAP
/*
* 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)
*/
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;
unsigned int dest;
cpumask_t tmp, cleanup_mask;
struct irte irte;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
......@@ -3078,10 +3197,12 @@ static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
if (get_irte(irq, &irte))
return;
if (assign_irq_vector(irq, mask))
cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return;
cfg = irq_cfg(irq);
set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp);
......@@ -3105,9 +3226,9 @@ static void ir_set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
cfg->move_in_progress = 0;
}
desc = irq_to_desc(irq);
desc->affinity = mask;
}
#endif
#endif /* CONFIG_SMP */
......@@ -3166,7 +3287,7 @@ static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec)
}
#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;
struct msi_msg msg;
......@@ -3175,7 +3296,7 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
if (ret < 0)
return ret;
set_irq_msi(irq, desc);
set_irq_msi(irq, msidesc);
write_msi_msg(irq, &msg);
#ifdef CONFIG_INTR_REMAP
......@@ -3195,26 +3316,13 @@ static int setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc, int irq)
return 0;
}
static unsigned int build_irq_for_pci_dev(struct pci_dev *dev)
{
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)
int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc)
{
unsigned int irq;
int ret;
unsigned int irq_want;
irq_want = build_irq_for_pci_dev(dev) + 0x100;
irq_want = nr_irqs_gsi;
irq = create_irq_nr(irq_want);
if (irq == 0)
return -1;
......@@ -3228,7 +3336,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
goto error;
no_ir:
#endif
ret = setup_msi_irq(dev, desc, irq);
ret = setup_msi_irq(dev, msidesc, irq);
if (ret < 0) {
destroy_irq(irq);
return ret;
......@@ -3246,7 +3354,7 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
unsigned int irq;
int ret, sub_handle;
struct msi_desc *desc;
struct msi_desc *msidesc;
unsigned int irq_want;
#ifdef CONFIG_INTR_REMAP
......@@ -3254,10 +3362,11 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
int index = 0;
#endif
irq_want = build_irq_for_pci_dev(dev) + 0x100;
irq_want = nr_irqs_gsi;
sub_handle = 0;
list_for_each_entry(desc, &dev->msi_list, list) {
irq = create_irq_nr(irq_want--);
list_for_each_entry(msidesc, &dev->msi_list, list) {
irq = create_irq_nr(irq_want);
irq_want++;
if (irq == 0)
return -1;
#ifdef CONFIG_INTR_REMAP
......@@ -3289,7 +3398,7 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
}
no_ir:
#endif
ret = setup_msi_irq(dev, desc, irq);
ret = setup_msi_irq(dev, msidesc, irq);
if (ret < 0)
goto error;
sub_handle++;
......@@ -3310,20 +3419,22 @@ void arch_teardown_msi_irq(unsigned int irq)
#ifdef CONFIG_SMP
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 msi_msg msg;
unsigned int dest;
cpumask_t tmp;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
return;
if (assign_irq_vector(irq, mask))
cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return;
cfg = irq_cfg(irq);
set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp);
......@@ -3335,9 +3446,9 @@ static void dmar_msi_set_affinity(unsigned int irq, cpumask_t mask)
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
dmar_msi_write(irq, &msg);
desc = irq_to_desc(irq);
desc->affinity = mask;
}
#endif /* CONFIG_SMP */
struct irq_chip dmar_msi_type = {
......@@ -3371,8 +3482,8 @@ int arch_setup_dmar_msi(unsigned int irq)
#ifdef CONFIG_SMP
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_desc *desc;
struct msi_msg msg;
unsigned int dest;
cpumask_t tmp;
......@@ -3381,10 +3492,12 @@ static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask)
if (cpus_empty(tmp))
return;
if (assign_irq_vector(irq, mask))
cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return;
cfg = irq_cfg(irq);
set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp);
......@@ -3396,9 +3509,9 @@ static void hpet_msi_set_affinity(unsigned int irq, cpumask_t mask)
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
hpet_msi_write(irq, &msg);
desc = irq_to_desc(irq);
desc->affinity = mask;
}
#endif /* CONFIG_SMP */
struct irq_chip hpet_msi_type = {
......@@ -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)
{
struct irq_desc *desc = irq_to_desc(irq);
struct irq_cfg *cfg;
unsigned int dest;
cpumask_t tmp;
struct irq_desc *desc;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
return;
if (assign_irq_vector(irq, mask))
cfg = desc->chip_data;
if (assign_irq_vector(irq, cfg, mask))
return;
cfg = irq_cfg(irq);
set_extra_move_desc(desc, mask);
cpus_and(tmp, cfg->domain, mask);
dest = cpu_mask_to_apicid(tmp);
target_ht_irq(irq, dest, cfg->vector);
desc = irq_to_desc(irq);
desc->affinity = mask;
}
#endif
static struct irq_chip ht_irq_chip = {
......@@ -3492,13 +3607,13 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
int err;
cpumask_t tmp;
cfg = irq_cfg(irq);
tmp = TARGET_CPUS;
err = assign_irq_vector(irq, tmp);
err = assign_irq_vector(irq, cfg, tmp);
if (!err) {
struct ht_irq_msg msg;
unsigned dest;
cfg = irq_cfg(irq);
cpus_and(tmp, cfg->domain, 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,
unsigned long flags;
int err;
err = assign_irq_vector(irq, *eligible_cpu);
cfg = irq_cfg(irq);
err = assign_irq_vector(irq, cfg, *eligible_cpu);
if (err != 0)
return err;
......@@ -3553,8 +3670,6 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
irq_name);
spin_unlock_irqrestore(&vector_lock, flags);
cfg = irq_cfg(irq);
mmr_value = 0;
entry = (struct uv_IO_APIC_route_entry *)&mmr_value;
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)
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)
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)) {
apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
ioapic);
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
*/
if (irq >= 16)
add_pin_to_irq(irq, ioapic, pin);
if (irq >= NR_IRQS_LEGACY) {
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;
}
......@@ -3773,9 +3907,10 @@ void __init setup_ioapic_dest(void)
* when you have too many devices, because at that time only boot
* cpu is online.
*/
cfg = irq_cfg(irq);
desc = irq_to_desc(irq);
cfg = desc->chip_data;
if (!cfg->vector) {
setup_IO_APIC_irq(ioapic, pin, irq,
setup_IO_APIC_irq(ioapic, pin, irq, desc,
irq_trigger(irq_entry),
irq_polarity(irq_entry));
continue;
......@@ -3785,7 +3920,6 @@ void __init setup_ioapic_dest(void)
/*
* Honour affinities which have been set in early boot
*/
desc = irq_to_desc(irq);
if (desc->status &
(IRQ_NO_BALANCING | IRQ_AFFINITY_SET))
mask = desc->affinity;
......@@ -3794,10 +3928,10 @@ void __init setup_ioapic_dest(void)
#ifdef CONFIG_INTR_REMAP
if (intr_remapping_enabled)
set_ir_ioapic_affinity_irq(irq, mask);
set_ir_ioapic_affinity_irq_desc(desc, mask);
else
#endif
set_ioapic_affinity_irq(irq, mask);
set_ioapic_affinity_irq_desc(desc, mask);
}
}
......@@ -3846,7 +3980,6 @@ void __init ioapic_init_mappings(void)
struct resource *ioapic_res;
int i;
irq_2_pin_init();
ioapic_res = ioapic_setup_resources();
for (i = 0; i < nr_ioapics; i++) {
if (smp_found_config) {
......
......@@ -118,6 +118,9 @@ int show_interrupts(struct seq_file *p, void *v)
}
desc = irq_to_desc(i);
if (!desc)
return 0;
spin_lock_irqsave(&desc->lock, flags);
#ifndef CONFIG_SMP
any_count = kstat_irqs(i);
......
......@@ -242,6 +242,8 @@ void fixup_irqs(cpumask_t map)
for_each_irq_desc(irq, desc) {
cpumask_t mask;
if (!desc)
continue;
if (irq == 2)
continue;
......
......@@ -94,6 +94,8 @@ void fixup_irqs(cpumask_t map)
int break_affinity = 0;
int set_affinity = 1;
if (!desc)
continue;
if (irq == 2)
continue;
......
......@@ -68,8 +68,7 @@ void __init init_ISA_irqs (void)
/*
* 16 old-style INTA-cycle interrupts:
*/
for (i = 0; i < 16; i++) {
/* first time call this irq_desc */
for (i = 0; i < NR_IRQS_LEGACY; i++) {
struct irq_desc *desc = irq_to_desc(i);
desc->status = IRQ_DISABLED;
......
......@@ -142,8 +142,7 @@ void __init init_ISA_irqs(void)
init_bsp_APIC();
init_8259A(0);
for (i = 0; i < 16; i++) {
/* first time call this irq_desc */
for (i = 0; i < NR_IRQS_LEGACY; i++) {
struct irq_desc *desc = irq_to_desc(i);
desc->status = IRQ_DISABLED;
......
......@@ -586,26 +586,23 @@ static void __init __get_smp_config(unsigned int early)
{
struct intel_mp_floating *mpf = mpf_found;
if (x86_quirks->mach_get_smp_config) {
if (x86_quirks->mach_get_smp_config(early))
if (!mpf)
return;
}
if (acpi_lapic && early)
return;
/*
* ACPI supports both logical (e.g. Hyper-Threading) and physical
* processors, where MPS only supports physical.
* MPS doesn't support hyperthreading, aka only have
* thread 0 apic id in MPS table
*/
if (acpi_lapic && acpi_ioapic) {
printk(KERN_INFO "Using ACPI (MADT) for SMP configuration "
"information\n");
if (acpi_lapic && acpi_ioapic)
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;
}
printk(KERN_INFO "Intel MultiProcessor Specification v1.%d\n",
mpf->mpf_specification);
......
......@@ -31,7 +31,7 @@
#include <asm/numaq.h>
#include <asm/topology.h>
#include <asm/processor.h>
#include <asm/mpspec.h>
#include <asm/genapic.h>
#include <asm/e820.h>
#include <asm/setup.h>
......@@ -235,6 +235,13 @@ static int __init numaq_setup_ioapic_ids(void)
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 = {
.arch_pre_time_init = numaq_pre_time_init,
.arch_time_init = NULL,
......@@ -250,6 +257,7 @@ static struct x86_quirks numaq_x86_quirks __initdata = {
.mpc_oem_pci_bus = mpc_oem_pci_bus,
.smp_read_mpc_oem = smp_read_mpc_oem,
.setup_ioapic_ids = numaq_setup_ioapic_ids,
.update_genapic = numaq_update_genapic,
};
void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
......
......@@ -9,6 +9,7 @@
#include <linux/clockchips.h>
#include <linux/ftrace.h>
#include <asm/system.h>
#include <asm/apic.h>
unsigned long idle_halt;
EXPORT_SYMBOL(idle_halt);
......@@ -127,6 +128,21 @@ void default_idle(void)
EXPORT_SYMBOL(default_idle);
#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)
{
}
......
......@@ -36,7 +36,10 @@ int reboot_force;
static int reboot_cpu = -1;
#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
cold Set the cold reboot flag
bios Reboot by jumping through the BIOS (only for X86_32)
......@@ -45,6 +48,7 @@ static int reboot_cpu = -1;
kbd Use the keyboard controller. cold reset (default)
acpi Use the RESET_REG in the FADT
efi Use efi reset_system runtime service
pci Use the so-called "PCI reset register", CF9
force Avoid anything that could hang.
*/
static int __init reboot_setup(char *str)
......@@ -79,6 +83,7 @@ static int __init reboot_setup(char *str)
case 'k':
case 't':
case 'e':
case 'p':
reboot_type = *str;
break;
......@@ -404,12 +409,27 @@ static void native_machine_emergency_restart(void)
reboot_type = BOOT_KBD;
break;
case BOOT_EFI:
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);
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;
break;
}
......@@ -470,6 +490,11 @@ static void native_machine_restart(char *__unused)
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)
......
......@@ -583,7 +583,20 @@ static int __init setup_elfcorehdr(char *arg)
early_param("elfcorehdr", setup_elfcorehdr);
#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;
......@@ -1082,7 +1095,7 @@ void __init setup_arch(char **cmdline_p)
ioapic_init_mappings();
/* need to wait for io_apic is mapped */
nr_irqs = probe_nr_irqs();
probe_nr_irqs_gsi();
kvm_guest_init();
......
......@@ -140,19 +140,6 @@ void native_send_call_func_ipi(cpumask_t mask)
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.
*/
......
......@@ -62,6 +62,7 @@
#include <asm/mtrr.h>
#include <asm/vmi.h>
#include <asm/genapic.h>
#include <asm/setup.h>
#include <linux/mc146818rtc.h>
#include <mach_apic.h>
......@@ -536,7 +537,7 @@ static void impress_friends(void)
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 };
char *names[] = { "ID", "VERSION", "SPIV" };
......@@ -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
* INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
* won't ... remember to clear down the APIC, etc later.
*/
static int __devinit
wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
int __devinit
wakeup_secondary_cpu_via_nmi(int logical_apicid, unsigned long start_eip)
{
unsigned long send_status, accept_status = 0;
int maxlvt;
......@@ -599,7 +599,7 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
* Give the other CPU some time to accept the IPI.
*/
udelay(200);
if (APIC_INTEGRATED(apic_version[phys_apicid])) {
if (APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
maxlvt = lapic_get_maxlvt();
if (maxlvt > 3) /* Due to the Pentium erratum 3AP. */
apic_write(APIC_ESR, 0);
......@@ -614,11 +614,9 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
return (send_status | accept_status);
}
#endif /* WAKE_SECONDARY_VIA_NMI */
#ifdef WAKE_SECONDARY_VIA_INIT
static int __devinit
wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
int __devinit
wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
{
unsigned long send_status, accept_status = 0;
int maxlvt, num_starts, j;
......@@ -737,7 +735,6 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
return (send_status | accept_status);
}
#endif /* WAKE_SECONDARY_VIA_INIT */
struct create_idle {
struct work_struct work;
......
......@@ -17,6 +17,7 @@
#include <asm/bigsmp/apic.h>
#include <asm/bigsmp/ipi.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 */
......
......@@ -16,6 +16,7 @@
#include <asm/mach-default/mach_apic.h>
#include <asm/mach-default/mach_ipi.h>
#include <asm/mach-default/mach_mpparse.h>
#include <asm/mach-default/mach_wakecpu.h>
/* should be called last. */
static int probe_default(void)
......
......@@ -16,7 +16,19 @@
#include <asm/es7000/apic.h>
#include <asm/es7000/ipi.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)
{
......
......@@ -15,6 +15,7 @@
#include <asm/mpspec.h>
#include <asm/apicdef.h>
#include <asm/genapic.h>
#include <asm/setup.h>
extern struct genapic apic_numaq;
extern struct genapic apic_summit;
......@@ -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 */
return 0;
}
......@@ -72,12 +76,15 @@ void __init generic_bigsmp_probe(void)
* - 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()) {
genapic = &apic_bigsmp;
if (x86_quirks->update_genapic)
x86_quirks->update_genapic();
printk(KERN_INFO "Overriding APIC driver with %s\n",
genapic->name);
}
}
#endif
}
......@@ -94,6 +101,9 @@ void __init generic_apic_probe(void)
/* Not visible without early console */
if (!apic_probe[i])
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);
}
......@@ -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 (!cmdline_apic) {
genapic = apic_probe[i];
if (x86_quirks->update_genapic)
x86_quirks->update_genapic();
printk(KERN_INFO "Switched to APIC driver `%s'.\n",
genapic->name);
}
......@@ -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 (!cmdline_apic) {
genapic = apic_probe[i];
if (x86_quirks->update_genapic)
x86_quirks->update_genapic();
printk(KERN_INFO "Switched to APIC driver `%s'.\n",
genapic->name);
}
......
......@@ -16,6 +16,7 @@
#include <asm/summit/apic.h>
#include <asm/summit/ipi.h>
#include <asm/summit/mpparse.h>
#include <asm/mach-default/mach_wakecpu.h>
static int probe_summit(void)
{
......
......@@ -173,7 +173,7 @@ static int pci_conf2_write(unsigned int seg, unsigned int bus,
#undef PCI_CONF2_ADDRESS
static struct pci_raw_ops pci_direct_conf2 = {
struct pci_raw_ops pci_direct_conf2 = {
.read = pci_conf2_read,
.write = pci_conf2_write,
};
......@@ -289,6 +289,7 @@ int __init pci_direct_probe(void)
if (pci_check_type1()) {
raw_pci_ops = &pci_direct_conf1;
port_cf9_safe = true;
return 1;
}
release_resource(region);
......@@ -305,6 +306,7 @@ int __init pci_direct_probe(void)
if (pci_check_type2()) {
raw_pci_ops = &pci_direct_conf2;
port_cf9_safe = true;
return 2;
}
......
......@@ -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 pci_direct_conf1;
extern bool port_cf9_safe;
/* arch_initcall level */
extern int pci_direct_probe(void);
......
......@@ -558,23 +558,9 @@ struct timer_rand_state {
unsigned dont_count_entropy:1;
};
static struct timer_rand_state *irq_timer_state[NR_IRQS];
static struct timer_rand_state *get_timer_rand_state(unsigned int irq)
{
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;
}
#ifndef CONFIG_SPARSE_IRQ
struct timer_rand_state *irq_timer_state[NR_IRQS];
#endif
static struct timer_rand_state input_timer_state;
......@@ -933,8 +919,10 @@ void rand_initialize_irq(int irq)
{
struct timer_rand_state *state;
#ifndef CONFIG_SPARSE_IRQ
if (irq >= nr_irqs)
return;
#endif
state = get_timer_rand_state(irq);
......
......@@ -19,17 +19,75 @@ struct irq_2_iommu {
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)
{
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)
{
return irq_2_iommu(irq);
}
#endif
static DEFINE_SPINLOCK(irq_2_ir_lock);
......@@ -86,9 +144,11 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
if (!count)
return -1;
#ifndef CONFIG_SPARSE_IRQ
/* protect irq_2_iommu_alloc later */
if (irq >= nr_irqs)
return -1;
#endif
/*
* start the IRTE search from index 0.
......@@ -130,6 +190,12 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
table->base[i].present = 1;
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->irte_index = index;
irq_iommu->sub_handle = 0;
......@@ -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);
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->irte_index = index;
irq_iommu->sub_handle = subhandle;
......
......@@ -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;
entry = get_irq_msi(irq);
entry = get_irq_desc_msi(desc);
BUG_ON(!entry || !entry->dev);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
......@@ -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
* 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;
entry = get_irq_msi(irq);
entry = get_irq_desc_msi(desc);
BUG_ON(!entry || !entry->dev);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
......@@ -172,9 +172,9 @@ static int msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag)
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) {
case PCI_CAP_ID_MSI:
{
......@@ -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) {
case PCI_CAP_ID_MSI:
{
......@@ -252,21 +259,31 @@ void write_msi_msg(unsigned int irq, struct msi_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)
{
msi_set_mask_bits(irq, 1, 1);
msix_flush_writes(irq);
struct irq_desc *desc = irq_to_desc(irq);
msi_set_mask_bits(desc, 1, 1);
msix_flush_writes(desc);
}
void unmask_msi_irq(unsigned int irq)
{
msi_set_mask_bits(irq, 1, 0);
msix_flush_writes(irq);
struct irq_desc *desc = irq_to_desc(irq);
msi_set_mask_bits(desc, 1, 0);
msix_flush_writes(desc);
}
static int msi_free_irqs(struct pci_dev* dev);
static struct msi_desc* alloc_msi_entry(void)
{
struct msi_desc *entry;
......@@ -303,9 +320,11 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
pci_intx_for_msi(dev, 0);
msi_set_enable(dev, 0);
write_msi_msg(dev->irq, &entry->msg);
if (entry->msi_attrib.maskbit)
msi_set_mask_bits(dev->irq, entry->msi_attrib.maskbits_mask,
if (entry->msi_attrib.maskbit) {
struct irq_desc *desc = irq_to_desc(dev->irq);
msi_set_mask_bits(desc, entry->msi_attrib.maskbits_mask,
entry->msi_attrib.masked);
}
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
control &= ~PCI_MSI_FLAGS_QSIZE;
......@@ -327,8 +346,9 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
msix_set_enable(dev, 0);
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);
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));
......@@ -596,7 +616,8 @@ void pci_msi_shutdown(struct pci_dev* dev)
/* Return the the pci reset with msi irqs unmasked */
if (entry->msi_attrib.maskbit) {
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)
return;
......
......@@ -141,8 +141,12 @@ static void init_evtchn_cpu_bindings(void)
int i;
/* 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);
}
#endif
memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
......@@ -231,7 +235,7 @@ static int find_unbound_irq(void)
int irq;
/* Only allocate from dynirq range */
for_each_irq_nr(irq)
for (irq = 0; irq < nr_irqs; irq++)
if (irq_bindcount[irq] == 0)
break;
......@@ -792,7 +796,7 @@ void xen_irq_resume(void)
mask_evtchn(evtchn);
/* 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 */
for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
......@@ -824,7 +828,7 @@ void __init xen_init_IRQ(void)
mask_evtchn(i);
/* 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_ctx_init(smp_processor_id());
......
......@@ -27,6 +27,7 @@ static int show_stat(struct seq_file *p, void *v)
u64 sum = 0;
struct timespec boottime;
unsigned int per_irq_sum;
struct irq_desc *desc;
user = nice = system = idle = iowait =
irq = softirq = steal = cputime64_zero;
......@@ -44,10 +45,14 @@ static int show_stat(struct seq_file *p, void *v)
softirq = cputime64_add(softirq, kstat_cpu(i).cpustat.softirq);
steal = cputime64_add(steal, kstat_cpu(i).cpustat.steal);
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 += arch_irq_stat_cpu(i);
}
sum += arch_irq_stat();
......@@ -92,7 +97,13 @@ static int show_stat(struct seq_file *p, void *v)
/* sum again ? it could be updated? */
for_each_irq_nr(j) {
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)
per_irq_sum += kstat_irqs_cpu(j, i);
......
......@@ -313,6 +313,7 @@ unifdef-y += ptrace.h
unifdef-y += qnx4_fs.h
unifdef-y += quota.h
unifdef-y += random.h
unifdef-y += irqnr.h
unifdef-y += reboot.h
unifdef-y += reiserfs_fs.h
unifdef-y += reiserfs_xattr.h
......
......@@ -14,6 +14,8 @@
#include <linux/irqflags.h>
#include <linux/smp.h>
#include <linux/percpu.h>
#include <linux/irqnr.h>
#include <asm/atomic.h>
#include <asm/ptrace.h>
#include <asm/system.h>
......
......@@ -129,6 +129,8 @@ struct irq_chip {
const char *typename;
};
struct timer_rand_state;
struct irq_2_iommu;
/**
* struct irq_desc - interrupt descriptor
* @irq: interrupt number for this descriptor
......@@ -154,6 +156,13 @@ struct irq_chip {
*/
struct irq_desc {
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;
struct irq_chip *chip;
struct msi_desc *msi_desc;
......@@ -181,14 +190,43 @@ struct irq_desc {
const char *name;
} ____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];
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:
*/
......@@ -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_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_S390 */
......
#ifndef _LINUX_IRQNR_H
#define _LINUX_IRQNR_H
/*
* Generic irq_desc iterators:
*/
#ifdef __KERNEL__
#ifndef CONFIG_GENERIC_HARDIRQS
#include <asm/irq.h>
# define nr_irqs NR_IRQS
# define for_each_irq_desc(irq, desc) \
for (irq = 0; irq < nr_irqs; irq++)
# define for_each_irq_desc_reverse(irq, desc) \
for (irq = nr_irqs - 1; irq >= 0; irq--)
#else
extern int nr_irqs;
#ifndef CONFIG_SPARSE_IRQ
struct irq_desc;
# define for_each_irq_desc(irq, desc) \
for (irq = 0, desc = irq_desc; irq < nr_irqs; irq++, desc++)
# define for_each_irq_desc_reverse(irq, desc) \
for (irq = nr_irqs - 1, desc = irq_desc + (nr_irqs - 1); \
irq >= 0; irq--, desc--)
#endif
#endif
#define for_each_irq_nr(irq) \
for (irq = 0; irq < nr_irqs; irq++)
#endif /* __KERNEL__ */
#endif
......@@ -28,7 +28,9 @@ struct cpu_usage_stat {
struct kernel_stat {
struct cpu_usage_stat cpustat;
#ifndef CONFIG_SPARSE_IRQ
unsigned int irqs[NR_IRQS];
#endif
};
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);
#ifndef CONFIG_SPARSE_IRQ
#define kstat_irqs_this_cpu(irq) \
(kstat_this_cpu.irqs[irq])
struct irq_desc;
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]++;
}
#endif
#ifndef CONFIG_SPARSE_IRQ
static inline unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)
{
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
......
......@@ -10,8 +10,11 @@ struct msi_msg {
};
/* Helper functions */
struct irq_desc;
extern void mask_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 write_msi_msg(unsigned int irq, struct msi_msg *msg);
......
......@@ -8,6 +8,7 @@
#define _LINUX_RANDOM_H
#include <linux/ioctl.h>
#include <linux/irqnr.h>
/* ioctl()'s for the random number generator */
......@@ -44,6 +45,56 @@ struct rand_pool_info {
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,
unsigned int value);
extern void add_interrupt_randomness(int irq);
......
......@@ -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)
{
char * command_line;
......@@ -604,6 +613,8 @@ asmlinkage void __init start_kernel(void)
sort_main_extable();
trap_init();
rcu_init();
/* init some links before init_ISA_irqs() */
early_irq_init();
init_IRQ();
pidhash_init();
init_timers();
......
......@@ -40,6 +40,9 @@ unsigned long probe_irq_on(void)
* flush such a longstanding irq before considering it as spurious.
*/
for_each_irq_desc_reverse(i, desc) {
if (!desc)
continue;
spin_lock_irq(&desc->lock);
if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
/*
......@@ -68,6 +71,9 @@ unsigned long probe_irq_on(void)
* happened in the previous stage, it may have masked itself)
*/
for_each_irq_desc_reverse(i, desc) {
if (!desc)
continue;
spin_lock_irq(&desc->lock);
if (!desc->action && !(desc->status & IRQ_NOPROBE)) {
desc->status |= IRQ_AUTODETECT | IRQ_WAITING;
......@@ -86,6 +92,9 @@ unsigned long probe_irq_on(void)
* Now filter out any obviously spurious interrupts
*/
for_each_irq_desc(i, desc) {
if (!desc)
continue;
spin_lock_irq(&desc->lock);
status = desc->status;
......@@ -124,6 +133,9 @@ unsigned int probe_irq_mask(unsigned long val)
int i;
for_each_irq_desc(i, desc) {
if (!desc)
continue;
spin_lock_irq(&desc->lock);
status = desc->status;
......@@ -166,6 +178,9 @@ int probe_irq_off(unsigned long val)
unsigned int status;
for_each_irq_desc(i, desc) {
if (!desc)
continue;
spin_lock_irq(&desc->lock);
status = desc->status;
......
......@@ -24,9 +24,10 @@
*/
void dynamic_irq_init(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
struct irq_desc *desc;
unsigned long flags;
desc = irq_to_desc(irq);
if (!desc) {
WARN(1, KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
return;
......
......@@ -15,9 +15,16 @@
#include <linux/random.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
#include <linux/rculist.h>
#include <linux/hash.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
* @irq: the interrupt number
......@@ -49,6 +56,155 @@ void handle_bad_irq(unsigned int irq, struct irq_desc *desc)
int nr_irqs = 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 = {
[0 ... NR_IRQS-1] = {
.status = IRQ_DISABLED,
......@@ -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?
* Each architecture has to answer this themself.
......@@ -261,17 +419,28 @@ unsigned int __do_IRQ(unsigned int irq)
#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)
{
#ifndef CONFIG_SPARSE_IRQ
struct irq_desc *desc;
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);
}
#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)
/*
* 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);
}
}
......@@ -91,6 +91,9 @@ static int misrouted_irq(int irq)
int i, ok = 0;
for_each_irq_desc(i, desc) {
if (!desc)
continue;
if (!i)
continue;
......@@ -112,6 +115,8 @@ static void poll_spurious_irqs(unsigned long dummy)
for_each_irq_desc(i, desc) {
unsigned int status;
if (!desc)
continue;
if (!i)
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