Commit 61d1ea91 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'x86-apic-2024-09-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 APIC updates from Thomas Gleixner:

 - Handle an allocation failure in the IO/APIC code gracefully instead
   of crashing the machine.

 - Remove support for APIC local destination mode on 64bit

   Logical destination mode of the local APIC is used for systems with
   up to 8 CPUs. It has an advantage over physical destination mode as
   it allows to target multiple CPUs at once with IPIs. That advantage
   was definitely worth it when systems with up to 8 CPUs were state of
   the art for servers and workstations, but that's history.

   In the recent past there were quite some reports of new laptops
   failing to boot with logical destination mode, but they work fine
   with physical destination mode. That's not a suprise because physical
   destination mode is guaranteed to work as it's the only way to get a
   CPU up and running via the INIT/INIT/STARTUP sequence. Some of the
   affected systems were cured by BIOS updates, but not all OEMs provide
   them.

   As the number of CPUs keep increasing, logical destination mode
   becomes less used and the benefit for small systems, like laptops, is
   not really worth the trouble. So just remove logical destination mode
   support for 64bit and be done with it.

 - Code and comment cleanups in the APIC area.

* tag 'x86-apic-2024-09-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/irq: Fix comment on IRQ vector layout
  x86/apic: Remove unused extern declarations
  x86/apic: Remove logical destination mode for 64-bit
  x86/apic: Remove unused inline function apic_set_eoi_cb()
  x86/ioapic: Cleanup remaining coding style issues
  x86/ioapic: Cleanup line breaks
  x86/ioapic: Cleanup bracket usage
  x86/ioapic: Cleanup comments
  x86/ioapic: Move replace_pin_at_irq_node() to the call site
  iommu/vt-d: Cleanup apic_printk()
  x86/mpparse: Cleanup apic_printk()s
  x86/ioapic: Cleanup guarded debug printk()s
  x86/ioapic: Cleanup apic_printk()s
  x86/apic: Cleanup apic_printk()s
  x86/apic: Provide apic_printk() helpers
  x86/ioapic: Use guard() for locking where applicable
  x86/ioapic: Cleanup structs
  x86/ioapic: Mark mp_alloc_timer_irq() __init
  x86/ioapic: Handle allocation failures gracefully
parents 0279aa78 a1fab3e6
...@@ -18,6 +18,11 @@ ...@@ -18,6 +18,11 @@
#define ARCH_APICTIMER_STOPS_ON_C3 1 #define ARCH_APICTIMER_STOPS_ON_C3 1
/* Macros for apic_extnmi which controls external NMI masking */
#define APIC_EXTNMI_BSP 0 /* Default */
#define APIC_EXTNMI_ALL 1
#define APIC_EXTNMI_NONE 2
/* /*
* Debugging macros * Debugging macros
*/ */
...@@ -25,22 +30,22 @@ ...@@ -25,22 +30,22 @@
#define APIC_VERBOSE 1 #define APIC_VERBOSE 1
#define APIC_DEBUG 2 #define APIC_DEBUG 2
/* Macros for apic_extnmi which controls external NMI masking */
#define APIC_EXTNMI_BSP 0 /* Default */
#define APIC_EXTNMI_ALL 1
#define APIC_EXTNMI_NONE 2
/* /*
* Define the default level of output to be very little * Define the default level of output to be very little This can be turned
* This can be turned up by using apic=verbose for more * up by using apic=verbose for more information and apic=debug for _lots_
* information and apic=debug for _lots_ of information. * of information. apic_verbosity is defined in apic.c
* apic_verbosity is defined in apic.c
*/ */
#define apic_printk(v, s, a...) do { \ #define apic_printk(v, s, a...) \
do { \
if ((v) <= apic_verbosity) \ if ((v) <= apic_verbosity) \
printk(s, ##a); \ printk(s, ##a); \
} while (0) } while (0)
#define apic_pr_verbose(s, a...) apic_printk(APIC_VERBOSE, KERN_INFO s, ##a)
#define apic_pr_debug(s, a...) apic_printk(APIC_DEBUG, KERN_DEBUG s, ##a)
#define apic_pr_debug_cont(s, a...) apic_printk(APIC_DEBUG, KERN_CONT s, ##a)
/* Unconditional debug prints for code which is guarded by apic_verbosity already */
#define apic_dbg(s, a...) printk(KERN_DEBUG s, ##a)
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_32) #if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86_32)
extern void x86_32_probe_apic(void); extern void x86_32_probe_apic(void);
...@@ -122,8 +127,6 @@ static inline bool apic_is_x2apic_enabled(void) ...@@ -122,8 +127,6 @@ static inline bool apic_is_x2apic_enabled(void)
extern void enable_IR_x2apic(void); extern void enable_IR_x2apic(void);
extern int get_physical_broadcast(void);
extern int lapic_get_maxlvt(void); extern int lapic_get_maxlvt(void);
extern void clear_local_APIC(void); extern void clear_local_APIC(void);
extern void disconnect_bsp_APIC(int virt_wire_setup); extern void disconnect_bsp_APIC(int virt_wire_setup);
...@@ -345,20 +348,12 @@ extern struct apic *apic; ...@@ -345,20 +348,12 @@ extern struct apic *apic;
* APIC drivers are probed based on how they are listed in the .apicdrivers * APIC drivers are probed based on how they are listed in the .apicdrivers
* section. So the order is important and enforced by the ordering * section. So the order is important and enforced by the ordering
* of different apic driver files in the Makefile. * of different apic driver files in the Makefile.
*
* For the files having two apic drivers, we use apic_drivers()
* to enforce the order with in them.
*/ */
#define apic_driver(sym) \ #define apic_driver(sym) \
static const struct apic *__apicdrivers_##sym __used \ static const struct apic *__apicdrivers_##sym __used \
__aligned(sizeof(struct apic *)) \ __aligned(sizeof(struct apic *)) \
__section(".apicdrivers") = { &sym } __section(".apicdrivers") = { &sym }
#define apic_drivers(sym1, sym2) \
static struct apic *__apicdrivers_##sym1##sym2[2] __used \
__aligned(sizeof(struct apic *)) \
__section(".apicdrivers") = { &sym1, &sym2 }
extern struct apic *__apicdrivers[], *__apicdrivers_end[]; extern struct apic *__apicdrivers[], *__apicdrivers_end[];
/* /*
...@@ -484,7 +479,6 @@ static inline u64 apic_icr_read(void) { return 0; } ...@@ -484,7 +479,6 @@ static inline u64 apic_icr_read(void) { return 0; }
static inline void apic_icr_write(u32 low, u32 high) { } static inline void apic_icr_write(u32 low, u32 high) { }
static inline void apic_wait_icr_idle(void) { } static inline void apic_wait_icr_idle(void) { }
static inline u32 safe_apic_wait_icr_idle(void) { return 0; } static inline u32 safe_apic_wait_icr_idle(void) { return 0; }
static inline void apic_set_eoi_cb(void (*eoi)(void)) {}
static inline void apic_native_eoi(void) { WARN_ON_ONCE(1); } static inline void apic_native_eoi(void) { WARN_ON_ONCE(1); }
static inline void apic_setup_apic_calls(void) { } static inline void apic_setup_apic_calls(void) { }
...@@ -512,8 +506,6 @@ static inline bool is_vector_pending(unsigned int vector) ...@@ -512,8 +506,6 @@ static inline bool is_vector_pending(unsigned int vector)
#define TRAMPOLINE_PHYS_LOW 0x467 #define TRAMPOLINE_PHYS_LOW 0x467
#define TRAMPOLINE_PHYS_HIGH 0x469 #define TRAMPOLINE_PHYS_HIGH 0x469
extern void generic_bigsmp_probe(void);
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
#include <asm/smp.h> #include <asm/smp.h>
...@@ -536,8 +528,6 @@ static inline int default_acpi_madt_oem_check(char *a, char *b) { return 0; } ...@@ -536,8 +528,6 @@ static inline int default_acpi_madt_oem_check(char *a, char *b) { return 0; }
static inline void x86_64_probe_apic(void) { } static inline void x86_64_probe_apic(void) { }
#endif #endif
extern int default_apic_id_valid(u32 apicid);
extern u32 apic_default_calc_apicid(unsigned int cpu); extern u32 apic_default_calc_apicid(unsigned int cpu);
extern u32 apic_flat_calc_apicid(unsigned int cpu); extern u32 apic_flat_calc_apicid(unsigned int cpu);
......
...@@ -18,8 +18,8 @@ ...@@ -18,8 +18,8 @@
* Vectors 0 ... 31 : system traps and exceptions - hardcoded events * Vectors 0 ... 31 : system traps and exceptions - hardcoded events
* Vectors 32 ... 127 : device interrupts * Vectors 32 ... 127 : device interrupts
* Vector 128 : legacy int80 syscall interface * Vector 128 : legacy int80 syscall interface
* Vectors 129 ... LOCAL_TIMER_VECTOR-1 * Vectors 129 ... FIRST_SYSTEM_VECTOR-1 : device interrupts
* Vectors LOCAL_TIMER_VECTOR ... 255 : special interrupts * Vectors FIRST_SYSTEM_VECTOR ... 255 : special interrupts
* *
* 64-bit x86 has per CPU IDT tables, 32-bit has one shared IDT table. * 64-bit x86 has per CPU IDT tables, 32-bit has one shared IDT table.
* *
......
...@@ -677,7 +677,7 @@ calibrate_by_pmtimer(u32 deltapm, long *delta, long *deltatsc) ...@@ -677,7 +677,7 @@ calibrate_by_pmtimer(u32 deltapm, long *delta, long *deltatsc)
return -1; return -1;
#endif #endif
apic_printk(APIC_VERBOSE, "... PM-Timer delta = %u\n", deltapm); apic_pr_verbose("... PM-Timer delta = %u\n", deltapm);
/* Check, if the PM timer is available */ /* Check, if the PM timer is available */
if (!deltapm) if (!deltapm)
...@@ -687,14 +687,14 @@ calibrate_by_pmtimer(u32 deltapm, long *delta, long *deltatsc) ...@@ -687,14 +687,14 @@ calibrate_by_pmtimer(u32 deltapm, long *delta, long *deltatsc)
if (deltapm > (pm_100ms - pm_thresh) && if (deltapm > (pm_100ms - pm_thresh) &&
deltapm < (pm_100ms + pm_thresh)) { deltapm < (pm_100ms + pm_thresh)) {
apic_printk(APIC_VERBOSE, "... PM-Timer result ok\n"); apic_pr_verbose("... PM-Timer result ok\n");
return 0; return 0;
} }
res = (((u64)deltapm) * mult) >> 22; res = (((u64)deltapm) * mult) >> 22;
do_div(res, 1000000); do_div(res, 1000000);
pr_warn("APIC calibration not consistent " pr_warn("APIC calibration not consistent with PM-Timer: %ldms instead of 100ms\n",
"with PM-Timer: %ldms instead of 100ms\n", (long)res); (long)res);
/* Correct the lapic counter value */ /* Correct the lapic counter value */
res = (((u64)(*delta)) * pm_100ms); res = (((u64)(*delta)) * pm_100ms);
...@@ -707,8 +707,7 @@ calibrate_by_pmtimer(u32 deltapm, long *delta, long *deltatsc) ...@@ -707,8 +707,7 @@ calibrate_by_pmtimer(u32 deltapm, long *delta, long *deltatsc)
if (boot_cpu_has(X86_FEATURE_TSC)) { if (boot_cpu_has(X86_FEATURE_TSC)) {
res = (((u64)(*deltatsc)) * pm_100ms); res = (((u64)(*deltatsc)) * pm_100ms);
do_div(res, deltapm); do_div(res, deltapm);
apic_printk(APIC_VERBOSE, "TSC delta adjusted to " apic_pr_verbose("TSC delta adjusted to PM-Timer: %lu (%ld)\n",
"PM-Timer: %lu (%ld)\n",
(unsigned long)res, *deltatsc); (unsigned long)res, *deltatsc);
*deltatsc = (long)res; *deltatsc = (long)res;
} }
...@@ -792,8 +791,7 @@ static int __init calibrate_APIC_clock(void) ...@@ -792,8 +791,7 @@ static int __init calibrate_APIC_clock(void)
* in the clockevent structure and return. * in the clockevent structure and return.
*/ */
if (!lapic_init_clockevent()) { if (!lapic_init_clockevent()) {
apic_printk(APIC_VERBOSE, "lapic timer already calibrated %d\n", apic_pr_verbose("lapic timer already calibrated %d\n", lapic_timer_period);
lapic_timer_period);
/* /*
* Direct calibration methods must have an always running * Direct calibration methods must have an always running
* local APIC timer, no need for broadcast timer. * local APIC timer, no need for broadcast timer.
...@@ -802,8 +800,7 @@ static int __init calibrate_APIC_clock(void) ...@@ -802,8 +800,7 @@ static int __init calibrate_APIC_clock(void)
return 0; return 0;
} }
apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n" apic_pr_verbose("Using local APIC timer interrupts. Calibrating APIC timer ...\n");
"calibrating APIC timer ...\n");
/* /*
* There are platforms w/o global clockevent devices. Instead of * There are platforms w/o global clockevent devices. Instead of
...@@ -866,7 +863,7 @@ static int __init calibrate_APIC_clock(void) ...@@ -866,7 +863,7 @@ static int __init calibrate_APIC_clock(void)
/* Build delta t1-t2 as apic timer counts down */ /* Build delta t1-t2 as apic timer counts down */
delta = lapic_cal_t1 - lapic_cal_t2; delta = lapic_cal_t1 - lapic_cal_t2;
apic_printk(APIC_VERBOSE, "... lapic delta = %ld\n", delta); apic_pr_verbose("... lapic delta = %ld\n", delta);
deltatsc = (long)(lapic_cal_tsc2 - lapic_cal_tsc1); deltatsc = (long)(lapic_cal_tsc2 - lapic_cal_tsc1);
...@@ -877,20 +874,17 @@ static int __init calibrate_APIC_clock(void) ...@@ -877,20 +874,17 @@ static int __init calibrate_APIC_clock(void)
lapic_timer_period = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS; lapic_timer_period = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
lapic_init_clockevent(); lapic_init_clockevent();
apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta); apic_pr_verbose("..... delta %ld\n", delta);
apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult); apic_pr_verbose("..... mult: %u\n", lapic_clockevent.mult);
apic_printk(APIC_VERBOSE, "..... calibration result: %u\n", apic_pr_verbose("..... calibration result: %u\n", lapic_timer_period);
lapic_timer_period);
if (boot_cpu_has(X86_FEATURE_TSC)) { if (boot_cpu_has(X86_FEATURE_TSC)) {
apic_printk(APIC_VERBOSE, "..... CPU clock speed is " apic_pr_verbose("..... CPU clock speed is %ld.%04ld MHz.\n",
"%ld.%04ld MHz.\n",
(deltatsc / LAPIC_CAL_LOOPS) / (1000000 / HZ), (deltatsc / LAPIC_CAL_LOOPS) / (1000000 / HZ),
(deltatsc / LAPIC_CAL_LOOPS) % (1000000 / HZ)); (deltatsc / LAPIC_CAL_LOOPS) % (1000000 / HZ));
} }
apic_printk(APIC_VERBOSE, "..... host bus clock speed is " apic_pr_verbose("..... host bus clock speed is %u.%04u MHz.\n",
"%u.%04u MHz.\n",
lapic_timer_period / (1000000 / HZ), lapic_timer_period / (1000000 / HZ),
lapic_timer_period % (1000000 / HZ)); lapic_timer_period % (1000000 / HZ));
...@@ -911,7 +905,7 @@ static int __init calibrate_APIC_clock(void) ...@@ -911,7 +905,7 @@ static int __init calibrate_APIC_clock(void)
* available. * available.
*/ */
if (!pm_referenced && global_clock_event) { if (!pm_referenced && global_clock_event) {
apic_printk(APIC_VERBOSE, "... verify APIC timer\n"); apic_pr_verbose("... verify APIC timer\n");
/* /*
* Setup the apic timer manually * Setup the apic timer manually
...@@ -932,11 +926,11 @@ static int __init calibrate_APIC_clock(void) ...@@ -932,11 +926,11 @@ static int __init calibrate_APIC_clock(void)
/* Jiffies delta */ /* Jiffies delta */
deltaj = lapic_cal_j2 - lapic_cal_j1; deltaj = lapic_cal_j2 - lapic_cal_j1;
apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj); apic_pr_verbose("... jiffies delta = %lu\n", deltaj);
/* Check, if the jiffies result is consistent */ /* Check, if the jiffies result is consistent */
if (deltaj >= LAPIC_CAL_LOOPS-2 && deltaj <= LAPIC_CAL_LOOPS+2) if (deltaj >= LAPIC_CAL_LOOPS-2 && deltaj <= LAPIC_CAL_LOOPS+2)
apic_printk(APIC_VERBOSE, "... jiffies result ok\n"); apic_pr_verbose("... jiffies result ok\n");
else else
levt->features |= CLOCK_EVT_FEAT_DUMMY; levt->features |= CLOCK_EVT_FEAT_DUMMY;
} }
...@@ -1221,9 +1215,8 @@ void __init sync_Arb_IDs(void) ...@@ -1221,9 +1215,8 @@ void __init sync_Arb_IDs(void)
*/ */
apic_wait_icr_idle(); apic_wait_icr_idle();
apic_printk(APIC_DEBUG, "Synchronizing Arb IDs.\n"); apic_pr_debug("Synchronizing Arb IDs.\n");
apic_write(APIC_ICR, APIC_DEST_ALLINC | apic_write(APIC_ICR, APIC_DEST_ALLINC | APIC_INT_LEVELTRIG | APIC_DM_INIT);
APIC_INT_LEVELTRIG | APIC_DM_INIT);
} }
enum apic_intr_mode_id apic_intr_mode __ro_after_init; enum apic_intr_mode_id apic_intr_mode __ro_after_init;
...@@ -1409,10 +1402,10 @@ static void lapic_setup_esr(void) ...@@ -1409,10 +1402,10 @@ static void lapic_setup_esr(void)
if (maxlvt > 3) if (maxlvt > 3)
apic_write(APIC_ESR, 0); apic_write(APIC_ESR, 0);
value = apic_read(APIC_ESR); value = apic_read(APIC_ESR);
if (value != oldvalue) if (value != oldvalue) {
apic_printk(APIC_VERBOSE, "ESR value before enabling " apic_pr_verbose("ESR value before enabling vector: 0x%08x after: 0x%08x\n",
"vector: 0x%08x after: 0x%08x\n",
oldvalue, value); oldvalue, value);
}
} }
#define APIC_IR_REGS APIC_ISR_NR #define APIC_IR_REGS APIC_ISR_NR
...@@ -1599,10 +1592,10 @@ static void setup_local_APIC(void) ...@@ -1599,10 +1592,10 @@ static void setup_local_APIC(void)
value = apic_read(APIC_LVT0) & APIC_LVT_MASKED; value = apic_read(APIC_LVT0) & APIC_LVT_MASKED;
if (!cpu && (pic_mode || !value || ioapic_is_disabled)) { if (!cpu && (pic_mode || !value || ioapic_is_disabled)) {
value = APIC_DM_EXTINT; value = APIC_DM_EXTINT;
apic_printk(APIC_VERBOSE, "enabled ExtINT on CPU#%d\n", cpu); apic_pr_verbose("Enabled ExtINT on CPU#%d\n", cpu);
} else { } else {
value = APIC_DM_EXTINT | APIC_LVT_MASKED; value = APIC_DM_EXTINT | APIC_LVT_MASKED;
apic_printk(APIC_VERBOSE, "masked ExtINT on CPU#%d\n", cpu); apic_pr_verbose("Masked ExtINT on CPU#%d\n", cpu);
} }
apic_write(APIC_LVT0, value); apic_write(APIC_LVT0, value);
...@@ -2067,8 +2060,7 @@ static __init void apic_set_fixmap(bool read_apic) ...@@ -2067,8 +2060,7 @@ static __init void apic_set_fixmap(bool read_apic)
{ {
set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr); set_fixmap_nocache(FIX_APIC_BASE, mp_lapic_addr);
apic_mmio_base = APIC_BASE; apic_mmio_base = APIC_BASE;
apic_printk(APIC_VERBOSE, "mapped APIC to %16lx (%16lx)\n", apic_pr_verbose("Mapped APIC to %16lx (%16lx)\n", apic_mmio_base, mp_lapic_addr);
apic_mmio_base, mp_lapic_addr);
if (read_apic) if (read_apic)
apic_read_boot_cpu_id(false); apic_read_boot_cpu_id(false);
} }
...@@ -2171,18 +2163,17 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_error_interrupt) ...@@ -2171,18 +2163,17 @@ DEFINE_IDTENTRY_SYSVEC(sysvec_error_interrupt)
apic_eoi(); apic_eoi();
atomic_inc(&irq_err_count); atomic_inc(&irq_err_count);
apic_printk(APIC_DEBUG, KERN_DEBUG "APIC error on CPU%d: %02x", apic_pr_debug("APIC error on CPU%d: %02x", smp_processor_id(), v);
smp_processor_id(), v);
v &= 0xff; v &= 0xff;
while (v) { while (v) {
if (v & 0x1) if (v & 0x1)
apic_printk(APIC_DEBUG, KERN_CONT " : %s", error_interrupt_reason[i]); apic_pr_debug_cont(" : %s", error_interrupt_reason[i]);
i++; i++;
v >>= 1; v >>= 1;
} }
apic_printk(APIC_DEBUG, KERN_CONT "\n"); apic_pr_debug_cont("\n");
trace_error_apic_exit(ERROR_APIC_VECTOR); trace_error_apic_exit(ERROR_APIC_VECTOR);
} }
...@@ -2202,8 +2193,7 @@ static void __init connect_bsp_APIC(void) ...@@ -2202,8 +2193,7 @@ static void __init connect_bsp_APIC(void)
* PIC mode, enable APIC mode in the IMCR, i.e. connect BSP's * PIC mode, enable APIC mode in the IMCR, i.e. connect BSP's
* local APIC to INT and NMI lines. * local APIC to INT and NMI lines.
*/ */
apic_printk(APIC_VERBOSE, "leaving PIC mode, " apic_pr_verbose("Leaving PIC mode, enabling APIC mode.\n");
"enabling APIC mode.\n");
imcr_pic_to_apic(); imcr_pic_to_apic();
} }
#endif #endif
...@@ -2228,8 +2218,7 @@ void disconnect_bsp_APIC(int virt_wire_setup) ...@@ -2228,8 +2218,7 @@ void disconnect_bsp_APIC(int virt_wire_setup)
* IPIs, won't work beyond this point! The only exception are * IPIs, won't work beyond this point! The only exception are
* INIT IPIs. * INIT IPIs.
*/ */
apic_printk(APIC_VERBOSE, "disabling APIC mode, " apic_pr_verbose("Disabling APIC mode, entering PIC mode.\n");
"entering PIC mode.\n");
imcr_apic_to_pic(); imcr_apic_to_pic();
return; return;
} }
......
...@@ -8,129 +8,25 @@ ...@@ -8,129 +8,25 @@
* Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
* James Cleverdon. * James Cleverdon.
*/ */
#include <linux/cpumask.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/acpi.h>
#include <asm/jailhouse_para.h>
#include <asm/apic.h> #include <asm/apic.h>
#include "local.h" #include "local.h"
static struct apic apic_physflat; static u32 physflat_get_apic_id(u32 x)
static struct apic apic_flat;
struct apic *apic __ro_after_init = &apic_flat;
EXPORT_SYMBOL_GPL(apic);
static int flat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{
return 1;
}
static void _flat_send_IPI_mask(unsigned long mask, int vector)
{
unsigned long flags;
local_irq_save(flags);
__default_send_IPI_dest_field(mask, vector, APIC_DEST_LOGICAL);
local_irq_restore(flags);
}
static void flat_send_IPI_mask(const struct cpumask *cpumask, int vector)
{
unsigned long mask = cpumask_bits(cpumask)[0];
_flat_send_IPI_mask(mask, vector);
}
static void
flat_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector)
{
unsigned long mask = cpumask_bits(cpumask)[0];
int cpu = smp_processor_id();
if (cpu < BITS_PER_LONG)
__clear_bit(cpu, &mask);
_flat_send_IPI_mask(mask, vector);
}
static u32 flat_get_apic_id(u32 x)
{ {
return (x >> 24) & 0xFF; return (x >> 24) & 0xFF;
} }
static int flat_probe(void) static int physflat_probe(void)
{ {
return 1; return 1;
} }
static struct apic apic_flat __ro_after_init = {
.name = "flat",
.probe = flat_probe,
.acpi_madt_oem_check = flat_acpi_madt_oem_check,
.dest_mode_logical = true,
.disable_esr = 0,
.init_apic_ldr = default_init_apic_ldr,
.cpu_present_to_apicid = default_cpu_present_to_apicid,
.max_apic_id = 0xFE,
.get_apic_id = flat_get_apic_id,
.calc_dest_apicid = apic_flat_calc_apicid,
.send_IPI = default_send_IPI_single,
.send_IPI_mask = flat_send_IPI_mask,
.send_IPI_mask_allbutself = flat_send_IPI_mask_allbutself,
.send_IPI_allbutself = default_send_IPI_allbutself,
.send_IPI_all = default_send_IPI_all,
.send_IPI_self = default_send_IPI_self,
.nmi_to_offline_cpu = true,
.read = native_apic_mem_read,
.write = native_apic_mem_write,
.eoi = native_apic_mem_eoi,
.icr_read = native_apic_icr_read,
.icr_write = native_apic_icr_write,
.wait_icr_idle = apic_mem_wait_icr_idle,
.safe_wait_icr_idle = apic_mem_wait_icr_idle_timeout,
};
/*
* Physflat mode is used when there are more than 8 CPUs on a system.
* We cannot use logical delivery in this case because the mask
* overflows, so use physical mode.
*/
static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id) static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
{ {
#ifdef CONFIG_ACPI
/*
* Quirk: some x86_64 machines can only use physical APIC mode
* regardless of how many processors are present (x86_64 ES7000
* is an example).
*/
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
(acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL)) {
printk(KERN_DEBUG "system APIC only can use physical flat");
return 1; return 1;
}
if (!strncmp(oem_id, "IBM", 3) && !strncmp(oem_table_id, "EXA", 3)) {
printk(KERN_DEBUG "IBM Summit detected, will use apic physical");
return 1;
}
#endif
return 0;
}
static int physflat_probe(void)
{
return apic == &apic_physflat || num_possible_cpus() > 8 || jailhouse_paravirt();
} }
static struct apic apic_physflat __ro_after_init = { static struct apic apic_physflat __ro_after_init = {
...@@ -146,7 +42,7 @@ static struct apic apic_physflat __ro_after_init = { ...@@ -146,7 +42,7 @@ static struct apic apic_physflat __ro_after_init = {
.cpu_present_to_apicid = default_cpu_present_to_apicid, .cpu_present_to_apicid = default_cpu_present_to_apicid,
.max_apic_id = 0xFE, .max_apic_id = 0xFE,
.get_apic_id = flat_get_apic_id, .get_apic_id = physflat_get_apic_id,
.calc_dest_apicid = apic_default_calc_apicid, .calc_dest_apicid = apic_default_calc_apicid,
...@@ -166,8 +62,7 @@ static struct apic apic_physflat __ro_after_init = { ...@@ -166,8 +62,7 @@ static struct apic apic_physflat __ro_after_init = {
.wait_icr_idle = apic_mem_wait_icr_idle, .wait_icr_idle = apic_mem_wait_icr_idle,
.safe_wait_icr_idle = apic_mem_wait_icr_idle_timeout, .safe_wait_icr_idle = apic_mem_wait_icr_idle_timeout,
}; };
apic_driver(apic_physflat);
/* struct apic *apic __ro_after_init = &apic_physflat;
* We need to check for physflat first, so this order is important. EXPORT_SYMBOL_GPL(apic);
*/
apic_drivers(apic_physflat, apic_flat);
...@@ -105,13 +105,9 @@ struct mp_ioapic_gsi { ...@@ -105,13 +105,9 @@ struct mp_ioapic_gsi {
}; };
static struct ioapic { static struct ioapic {
/* /* # of IRQ routing registers */
* # of IRQ routing registers
*/
int nr_registers; int nr_registers;
/* /* Saved state during suspend/resume, or while enabling intr-remap. */
* Saved state during suspend/resume, or while enabling intr-remap.
*/
struct IO_APIC_route_entry *saved_registers; struct IO_APIC_route_entry *saved_registers;
/* I/O APIC config */ /* I/O APIC config */
struct mpc_ioapic mp_config; struct mpc_ioapic mp_config;
...@@ -205,8 +201,7 @@ void mp_save_irq(struct mpc_intsrc *m) ...@@ -205,8 +201,7 @@ void mp_save_irq(struct mpc_intsrc *m)
{ {
int i; int i;
apic_printk(APIC_VERBOSE, "Int: type %d, pol %d, trig %d, bus %02x," apic_pr_verbose("Int: type %d, pol %d, trig %d, bus %02x, IRQ %02x, APIC ID %x, APIC INT %02x\n",
" IRQ %02x, APIC ID %x, APIC INT %02x\n",
m->irqtype, m->irqflag & 3, (m->irqflag >> 2) & 3, m->srcbus, m->irqtype, m->irqflag & 3, (m->irqflag >> 2) & 3, m->srcbus,
m->srcbusirq, m->dstapic, m->dstirq); m->srcbusirq, m->dstapic, m->dstirq);
...@@ -269,12 +264,14 @@ static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx) ...@@ -269,12 +264,14 @@ static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
static inline void io_apic_eoi(unsigned int apic, unsigned int vector) static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
{ {
struct io_apic __iomem *io_apic = io_apic_base(apic); struct io_apic __iomem *io_apic = io_apic_base(apic);
writel(vector, &io_apic->eoi); writel(vector, &io_apic->eoi);
} }
unsigned int native_io_apic_read(unsigned int apic, unsigned int reg) unsigned int native_io_apic_read(unsigned int apic, unsigned int reg)
{ {
struct io_apic __iomem *io_apic = io_apic_base(apic); struct io_apic __iomem *io_apic = io_apic_base(apic);
writel(reg, &io_apic->index); writel(reg, &io_apic->index);
return readl(&io_apic->data); return readl(&io_apic->data);
} }
...@@ -300,14 +297,8 @@ static struct IO_APIC_route_entry __ioapic_read_entry(int apic, int pin) ...@@ -300,14 +297,8 @@ static struct IO_APIC_route_entry __ioapic_read_entry(int apic, int pin)
static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin) static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
{ {
struct IO_APIC_route_entry entry; guard(raw_spinlock_irqsave)(&ioapic_lock);
unsigned long flags; return __ioapic_read_entry(apic, pin);
raw_spin_lock_irqsave(&ioapic_lock, flags);
entry = __ioapic_read_entry(apic, pin);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
return entry;
} }
/* /*
...@@ -324,11 +315,8 @@ static void __ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e ...@@ -324,11 +315,8 @@ static void __ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e
static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
{ {
unsigned long flags; guard(raw_spinlock_irqsave)(&ioapic_lock);
raw_spin_lock_irqsave(&ioapic_lock, flags);
__ioapic_write_entry(apic, pin, e); __ioapic_write_entry(apic, pin, e);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
} }
/* /*
...@@ -339,12 +327,10 @@ static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e) ...@@ -339,12 +327,10 @@ static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
static void ioapic_mask_entry(int apic, int pin) static void ioapic_mask_entry(int apic, int pin)
{ {
struct IO_APIC_route_entry e = { .masked = true }; struct IO_APIC_route_entry e = { .masked = true };
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags); guard(raw_spinlock_irqsave)(&ioapic_lock);
io_apic_write(apic, 0x10 + 2*pin, e.w1); io_apic_write(apic, 0x10 + 2*pin, e.w1);
io_apic_write(apic, 0x11 + 2*pin, e.w2); io_apic_write(apic, 0x11 + 2*pin, e.w2);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
} }
/* /*
...@@ -352,68 +338,39 @@ static void ioapic_mask_entry(int apic, int pin) ...@@ -352,68 +338,39 @@ static void ioapic_mask_entry(int apic, int pin)
* 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 int __add_pin_to_irq_node(struct mp_chip_data *data, static bool add_pin_to_irq_node(struct mp_chip_data *data, int node, int apic, int pin)
int node, int apic, int pin)
{ {
struct irq_pin_list *entry; struct irq_pin_list *entry;
/* don't allow duplicates */ /* Don't allow duplicates */
for_each_irq_pin(entry, data->irq_2_pin) for_each_irq_pin(entry, data->irq_2_pin) {
if (entry->apic == apic && entry->pin == pin) if (entry->apic == apic && entry->pin == pin)
return 0; return true;
}
entry = kzalloc_node(sizeof(struct irq_pin_list), GFP_ATOMIC, node); entry = kzalloc_node(sizeof(struct irq_pin_list), GFP_ATOMIC, node);
if (!entry) { if (!entry) {
pr_err("can not alloc irq_pin_list (%d,%d,%d)\n", pr_err("Cannot allocate irq_pin_list (%d,%d,%d)\n", node, apic, pin);
node, apic, pin); return false;
return -ENOMEM;
} }
entry->apic = apic; entry->apic = apic;
entry->pin = pin; entry->pin = pin;
list_add_tail(&entry->list, &data->irq_2_pin); list_add_tail(&entry->list, &data->irq_2_pin);
return true;
return 0;
} }
static void __remove_pin_from_irq(struct mp_chip_data *data, int apic, int pin) static void __remove_pin_from_irq(struct mp_chip_data *data, int apic, int pin)
{ {
struct irq_pin_list *tmp, *entry; struct irq_pin_list *tmp, *entry;
list_for_each_entry_safe(entry, tmp, &data->irq_2_pin, list) list_for_each_entry_safe(entry, tmp, &data->irq_2_pin, list) {
if (entry->apic == apic && entry->pin == pin) { if (entry->apic == apic && entry->pin == pin) {
list_del(&entry->list); list_del(&entry->list);
kfree(entry); kfree(entry);
return; return;
} }
}
static void add_pin_to_irq_node(struct mp_chip_data *data,
int node, int apic, int pin)
{
if (__add_pin_to_irq_node(data, node, apic, pin))
panic("IO-APIC: failed to add irq-pin. Can not proceed\n");
}
/*
* Reroute an IRQ to a different pin.
*/
static void __init replace_pin_at_irq_node(struct mp_chip_data *data, int node,
int oldapic, int oldpin,
int newapic, int newpin)
{
struct irq_pin_list *entry;
for_each_irq_pin(entry, data->irq_2_pin) {
if (entry->apic == oldapic && entry->pin == oldpin) {
entry->apic = newapic;
entry->pin = newpin;
/* every one is different, right? */
return;
}
} }
/* old apic/pin didn't exist, so just add new ones */
add_pin_to_irq_node(data, node, newapic, newpin);
} }
static void io_apic_modify_irq(struct mp_chip_data *data, bool masked, static void io_apic_modify_irq(struct mp_chip_data *data, bool masked,
...@@ -430,12 +387,12 @@ static void io_apic_modify_irq(struct mp_chip_data *data, bool masked, ...@@ -430,12 +387,12 @@ static void io_apic_modify_irq(struct mp_chip_data *data, bool masked,
} }
} }
/*
* Synchronize the IO-APIC and the CPU by doing a dummy read from the
* IO-APIC
*/
static void io_apic_sync(struct irq_pin_list *entry) static void io_apic_sync(struct irq_pin_list *entry)
{ {
/*
* Synchronize the IO-APIC and the CPU by doing
* a dummy read from the IO-APIC
*/
struct io_apic __iomem *io_apic; struct io_apic __iomem *io_apic;
io_apic = io_apic_base(entry->apic); io_apic = io_apic_base(entry->apic);
...@@ -445,11 +402,9 @@ static void io_apic_sync(struct irq_pin_list *entry) ...@@ -445,11 +402,9 @@ static void io_apic_sync(struct irq_pin_list *entry)
static void mask_ioapic_irq(struct irq_data *irq_data) static void mask_ioapic_irq(struct irq_data *irq_data)
{ {
struct mp_chip_data *data = irq_data->chip_data; struct mp_chip_data *data = irq_data->chip_data;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags); guard(raw_spinlock_irqsave)(&ioapic_lock);
io_apic_modify_irq(data, true, &io_apic_sync); io_apic_modify_irq(data, true, &io_apic_sync);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
} }
static void __unmask_ioapic(struct mp_chip_data *data) static void __unmask_ioapic(struct mp_chip_data *data)
...@@ -460,11 +415,9 @@ static void __unmask_ioapic(struct mp_chip_data *data) ...@@ -460,11 +415,9 @@ static void __unmask_ioapic(struct mp_chip_data *data)
static void unmask_ioapic_irq(struct irq_data *irq_data) static void unmask_ioapic_irq(struct irq_data *irq_data)
{ {
struct mp_chip_data *data = irq_data->chip_data; struct mp_chip_data *data = irq_data->chip_data;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags); guard(raw_spinlock_irqsave)(&ioapic_lock);
__unmask_ioapic(data); __unmask_ioapic(data);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
} }
/* /*
...@@ -492,30 +445,24 @@ static void __eoi_ioapic_pin(int apic, int pin, int vector) ...@@ -492,30 +445,24 @@ static void __eoi_ioapic_pin(int apic, int pin, int vector)
entry = entry1 = __ioapic_read_entry(apic, pin); entry = entry1 = __ioapic_read_entry(apic, pin);
/* /* Mask the entry and change the trigger mode to edge. */
* Mask the entry and change the trigger mode to edge.
*/
entry1.masked = true; entry1.masked = true;
entry1.is_level = false; entry1.is_level = false;
__ioapic_write_entry(apic, pin, entry1); __ioapic_write_entry(apic, pin, entry1);
/* /* Restore the previous level triggered entry. */
* Restore the previous level triggered entry.
*/
__ioapic_write_entry(apic, pin, entry); __ioapic_write_entry(apic, pin, entry);
} }
} }
static void eoi_ioapic_pin(int vector, struct mp_chip_data *data) static void eoi_ioapic_pin(int vector, struct mp_chip_data *data)
{ {
unsigned long flags;
struct irq_pin_list *entry; struct irq_pin_list *entry;
raw_spin_lock_irqsave(&ioapic_lock, flags); guard(raw_spinlock_irqsave)(&ioapic_lock);
for_each_irq_pin(entry, data->irq_2_pin) for_each_irq_pin(entry, data->irq_2_pin)
__eoi_ioapic_pin(entry->apic, entry->pin, vector); __eoi_ioapic_pin(entry->apic, entry->pin, vector);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
} }
static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
...@@ -538,8 +485,6 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) ...@@ -538,8 +485,6 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
} }
if (entry.irr) { if (entry.irr) {
unsigned long flags;
/* /*
* Make sure the trigger mode is set to level. Explicit EOI * Make sure the trigger mode is set to level. Explicit EOI
* doesn't clear the remote-IRR if the trigger mode is not * doesn't clear the remote-IRR if the trigger mode is not
...@@ -549,9 +494,8 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) ...@@ -549,9 +494,8 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
entry.is_level = true; entry.is_level = true;
ioapic_write_entry(apic, pin, entry); ioapic_write_entry(apic, pin, entry);
} }
raw_spin_lock_irqsave(&ioapic_lock, flags); guard(raw_spinlock_irqsave)(&ioapic_lock);
__eoi_ioapic_pin(apic, pin, entry.vector); __eoi_ioapic_pin(apic, pin, entry.vector);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
} }
/* /*
...@@ -586,28 +530,23 @@ static int pirq_entries[MAX_PIRQS] = { ...@@ -586,28 +530,23 @@ static int pirq_entries[MAX_PIRQS] = {
static int __init ioapic_pirq_setup(char *str) static int __init ioapic_pirq_setup(char *str)
{ {
int i, max; int i, max, ints[MAX_PIRQS+1];
int ints[MAX_PIRQS+1];
get_options(str, ARRAY_SIZE(ints), ints); get_options(str, ARRAY_SIZE(ints), ints);
apic_printk(APIC_VERBOSE, KERN_INFO apic_pr_verbose("PIRQ redirection, working around broken MP-BIOS.\n");
"PIRQ redirection, working around broken MP-BIOS.\n");
max = MAX_PIRQS; max = MAX_PIRQS;
if (ints[0] < MAX_PIRQS) if (ints[0] < MAX_PIRQS)
max = ints[0]; max = ints[0];
for (i = 0; i < max; i++) { for (i = 0; i < max; i++) {
apic_printk(APIC_VERBOSE, KERN_DEBUG apic_pr_verbose("... PIRQ%d -> IRQ %d\n", i, ints[i + 1]);
"... PIRQ%d -> IRQ %d\n", i, ints[i+1]); /* PIRQs are mapped upside down, usually */
/*
* PIRQs are mapped upside down, usually.
*/
pirq_entries[MAX_PIRQS-i-1] = ints[i+1]; pirq_entries[MAX_PIRQS-i-1] = ints[i+1];
} }
return 1; return 1;
} }
__setup("pirq=", ioapic_pirq_setup); __setup("pirq=", ioapic_pirq_setup);
#endif /* CONFIG_X86_32 */ #endif /* CONFIG_X86_32 */
...@@ -626,8 +565,7 @@ int save_ioapic_entries(void) ...@@ -626,8 +565,7 @@ int save_ioapic_entries(void)
} }
for_each_pin(apic, pin) for_each_pin(apic, pin)
ioapics[apic].saved_registers[pin] = ioapics[apic].saved_registers[pin] = ioapic_read_entry(apic, pin);
ioapic_read_entry(apic, pin);
} }
return err; return err;
...@@ -668,8 +606,7 @@ int restore_ioapic_entries(void) ...@@ -668,8 +606,7 @@ int restore_ioapic_entries(void)
continue; continue;
for_each_pin(apic, pin) for_each_pin(apic, pin)
ioapic_write_entry(apic, pin, ioapic_write_entry(apic, pin, ioapics[apic].saved_registers[pin]);
ioapics[apic].saved_registers[pin]);
} }
return 0; return 0;
} }
...@@ -681,12 +618,13 @@ static int find_irq_entry(int ioapic_idx, int pin, int type) ...@@ -681,12 +618,13 @@ static int find_irq_entry(int ioapic_idx, int pin, int type)
{ {
int i; int i;
for (i = 0; i < mp_irq_entries; i++) for (i = 0; i < mp_irq_entries; i++) {
if (mp_irqs[i].irqtype == type && if (mp_irqs[i].irqtype == type &&
(mp_irqs[i].dstapic == mpc_ioapic_id(ioapic_idx) || (mp_irqs[i].dstapic == mpc_ioapic_id(ioapic_idx) ||
mp_irqs[i].dstapic == MP_APIC_ALL) && mp_irqs[i].dstapic == MP_APIC_ALL) &&
mp_irqs[i].dstirq == pin) mp_irqs[i].dstirq == pin)
return i; return i;
}
return -1; return -1;
} }
...@@ -701,10 +639,8 @@ static int __init find_isa_irq_pin(int irq, int type) ...@@ -701,10 +639,8 @@ static int __init find_isa_irq_pin(int irq, int type)
for (i = 0; i < mp_irq_entries; i++) { for (i = 0; i < mp_irq_entries; i++) {
int lbus = mp_irqs[i].srcbus; int lbus = mp_irqs[i].srcbus;
if (test_bit(lbus, mp_bus_not_pci) && if (test_bit(lbus, mp_bus_not_pci) && (mp_irqs[i].irqtype == type) &&
(mp_irqs[i].irqtype == type) &&
(mp_irqs[i].srcbusirq == irq)) (mp_irqs[i].srcbusirq == irq))
return mp_irqs[i].dstirq; return mp_irqs[i].dstirq;
} }
return -1; return -1;
...@@ -717,8 +653,7 @@ static int __init find_isa_irq_apic(int irq, int type) ...@@ -717,8 +653,7 @@ static int __init find_isa_irq_apic(int irq, int type)
for (i = 0; i < mp_irq_entries; i++) { for (i = 0; i < mp_irq_entries; i++) {
int lbus = mp_irqs[i].srcbus; int lbus = mp_irqs[i].srcbus;
if (test_bit(lbus, mp_bus_not_pci) && if (test_bit(lbus, mp_bus_not_pci) && (mp_irqs[i].irqtype == type) &&
(mp_irqs[i].irqtype == type) &&
(mp_irqs[i].srcbusirq == irq)) (mp_irqs[i].srcbusirq == irq))
break; break;
} }
...@@ -726,10 +661,11 @@ static int __init find_isa_irq_apic(int irq, int type) ...@@ -726,10 +661,11 @@ static int __init find_isa_irq_apic(int irq, int type)
if (i < mp_irq_entries) { if (i < mp_irq_entries) {
int ioapic_idx; int ioapic_idx;
for_each_ioapic(ioapic_idx) for_each_ioapic(ioapic_idx) {
if (mpc_ioapic_id(ioapic_idx) == mp_irqs[i].dstapic) if (mpc_ioapic_id(ioapic_idx) == mp_irqs[i].dstapic)
return ioapic_idx; return ioapic_idx;
} }
}
return -1; return -1;
} }
...@@ -769,8 +705,7 @@ static bool EISA_ELCR(unsigned int irq) ...@@ -769,8 +705,7 @@ static bool EISA_ELCR(unsigned int irq)
unsigned int port = PIC_ELCR1 + (irq >> 3); unsigned int port = PIC_ELCR1 + (irq >> 3);
return (inb(port) >> (irq & 7)) & 1; return (inb(port) >> (irq & 7)) & 1;
} }
apic_printk(APIC_VERBOSE, KERN_INFO apic_pr_verbose("Broken MPtable reports ISA irq %d\n", irq);
"Broken MPtable reports ISA irq %d\n", irq);
return false; return false;
} }
...@@ -947,9 +882,9 @@ static bool mp_check_pin_attr(int irq, struct irq_alloc_info *info) ...@@ -947,9 +882,9 @@ static bool mp_check_pin_attr(int irq, struct irq_alloc_info *info)
static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi, static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi,
struct irq_alloc_info *info) struct irq_alloc_info *info)
{ {
int type = ioapics[ioapic].irqdomain_cfg.type;
bool legacy = false; bool legacy = false;
int irq = -1; int irq = -1;
int type = ioapics[ioapic].irqdomain_cfg.type;
switch (type) { switch (type) {
case IOAPIC_DOMAIN_LEGACY: case IOAPIC_DOMAIN_LEGACY:
...@@ -971,8 +906,7 @@ static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi, ...@@ -971,8 +906,7 @@ static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi,
return -1; return -1;
} }
return __irq_domain_alloc_irqs(domain, irq, 1, return __irq_domain_alloc_irqs(domain, irq, 1, ioapic_alloc_attr_node(info),
ioapic_alloc_attr_node(info),
info, legacy, NULL); info, legacy, NULL);
} }
...@@ -986,13 +920,12 @@ static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi, ...@@ -986,13 +920,12 @@ static int alloc_irq_from_domain(struct irq_domain *domain, int ioapic, u32 gsi,
* PIRQs instead of reprogramming the interrupt routing logic. Thus there may be * PIRQs instead of reprogramming the interrupt routing logic. Thus there may be
* multiple pins sharing the same legacy IRQ number when ACPI is disabled. * multiple pins sharing the same legacy IRQ number when ACPI is disabled.
*/ */
static int alloc_isa_irq_from_domain(struct irq_domain *domain, static int alloc_isa_irq_from_domain(struct irq_domain *domain, int irq, int ioapic, int pin,
int irq, int ioapic, int pin,
struct irq_alloc_info *info) struct irq_alloc_info *info)
{ {
struct mp_chip_data *data;
struct irq_data *irq_data = irq_get_irq_data(irq); struct irq_data *irq_data = irq_get_irq_data(irq);
int node = ioapic_alloc_attr_node(info); int node = ioapic_alloc_attr_node(info);
struct mp_chip_data *data;
/* /*
* Legacy ISA IRQ has already been allocated, just add pin to * Legacy ISA IRQ has already been allocated, just add pin to
...@@ -1002,13 +935,11 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain, ...@@ -1002,13 +935,11 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain,
if (irq_data && irq_data->parent_data) { if (irq_data && irq_data->parent_data) {
if (!mp_check_pin_attr(irq, info)) if (!mp_check_pin_attr(irq, info))
return -EBUSY; return -EBUSY;
if (__add_pin_to_irq_node(irq_data->chip_data, node, ioapic, if (!add_pin_to_irq_node(irq_data->chip_data, node, ioapic, info->ioapic.pin))
info->ioapic.pin))
return -ENOMEM; return -ENOMEM;
} else { } else {
info->flags |= X86_IRQ_ALLOC_LEGACY; info->flags |= X86_IRQ_ALLOC_LEGACY;
irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true, irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true, NULL);
NULL);
if (irq >= 0) { if (irq >= 0) {
irq_data = irq_domain_get_irq_data(domain, irq); irq_data = irq_domain_get_irq_data(domain, irq);
data = irq_data->chip_data; data = irq_data->chip_data;
...@@ -1022,11 +953,11 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain, ...@@ -1022,11 +953,11 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain,
static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin, static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin,
unsigned int flags, struct irq_alloc_info *info) unsigned int flags, struct irq_alloc_info *info)
{ {
int irq; struct irq_domain *domain = mp_ioapic_irqdomain(ioapic);
bool legacy = false;
struct irq_alloc_info tmp; struct irq_alloc_info tmp;
struct mp_chip_data *data; struct mp_chip_data *data;
struct irq_domain *domain = mp_ioapic_irqdomain(ioapic); bool legacy = false;
int irq;
if (!domain) if (!domain)
return -ENOSYS; return -ENOSYS;
...@@ -1046,7 +977,7 @@ static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin, ...@@ -1046,7 +977,7 @@ static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin,
return -EINVAL; return -EINVAL;
} }
mutex_lock(&ioapic_mutex); guard(mutex)(&ioapic_mutex);
if (!(flags & IOAPIC_MAP_ALLOC)) { if (!(flags & IOAPIC_MAP_ALLOC)) {
if (!legacy) { if (!legacy) {
irq = irq_find_mapping(domain, pin); irq = irq_find_mapping(domain, pin);
...@@ -1067,8 +998,6 @@ static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin, ...@@ -1067,8 +998,6 @@ static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin,
data->count++; data->count++;
} }
} }
mutex_unlock(&ioapic_mutex);
return irq; return irq;
} }
...@@ -1076,26 +1005,20 @@ static int pin_2_irq(int idx, int ioapic, int pin, unsigned int flags) ...@@ -1076,26 +1005,20 @@ static int pin_2_irq(int idx, int ioapic, int pin, unsigned int flags)
{ {
u32 gsi = mp_pin_to_gsi(ioapic, pin); u32 gsi = mp_pin_to_gsi(ioapic, pin);
/* /* Debugging check, we are in big trouble if this message pops up! */
* Debugging check, we are in big trouble if this message pops up!
*/
if (mp_irqs[idx].dstirq != pin) if (mp_irqs[idx].dstirq != pin)
pr_err("broken BIOS or MPTABLE parser, ayiee!!\n"); pr_err("broken BIOS or MPTABLE parser, ayiee!!\n");
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
/* /* PCI IRQ command line redirection. Yes, limits are hardcoded. */
* PCI IRQ command line redirection. Yes, limits are hardcoded.
*/
if ((pin >= 16) && (pin <= 23)) { if ((pin >= 16) && (pin <= 23)) {
if (pirq_entries[pin-16] != -1) { if (pirq_entries[pin - 16] != -1) {
if (!pirq_entries[pin-16]) { if (!pirq_entries[pin - 16]) {
apic_printk(APIC_VERBOSE, KERN_DEBUG apic_pr_verbose("Disabling PIRQ%d\n", pin - 16);
"disabling PIRQ%d\n", pin-16);
} else { } else {
int irq = pirq_entries[pin-16]; int irq = pirq_entries[pin-16];
apic_printk(APIC_VERBOSE, KERN_DEBUG
"using PIRQ%d -> IRQ %d\n", apic_pr_verbose("Using PIRQ%d -> IRQ %d\n", pin - 16, irq);
pin-16, irq);
return irq; return irq;
} }
} }
...@@ -1133,10 +1056,9 @@ void mp_unmap_irq(int irq) ...@@ -1133,10 +1056,9 @@ void mp_unmap_irq(int irq)
if (!data || data->isa_irq) if (!data || data->isa_irq)
return; return;
mutex_lock(&ioapic_mutex); guard(mutex)(&ioapic_mutex);
if (--data->count == 0) if (--data->count == 0)
irq_domain_free_irqs(irq, 1); irq_domain_free_irqs(irq, 1);
mutex_unlock(&ioapic_mutex);
} }
/* /*
...@@ -1147,12 +1069,10 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) ...@@ -1147,12 +1069,10 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
{ {
int irq, i, best_ioapic = -1, best_idx = -1; int irq, i, best_ioapic = -1, best_idx = -1;
apic_printk(APIC_DEBUG, apic_pr_debug("Querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
"querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n",
bus, slot, pin); bus, slot, pin);
if (test_bit(bus, mp_bus_not_pci)) { if (test_bit(bus, mp_bus_not_pci)) {
apic_printk(APIC_VERBOSE, apic_pr_verbose("PCI BIOS passed nonexistent PCI bus %d!\n", bus);
"PCI BIOS passed nonexistent PCI bus %d!\n", bus);
return -1; return -1;
} }
...@@ -1197,8 +1117,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin) ...@@ -1197,8 +1117,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
return -1; return -1;
out: out:
return pin_2_irq(best_idx, best_ioapic, mp_irqs[best_idx].dstirq, return pin_2_irq(best_idx, best_ioapic, mp_irqs[best_idx].dstirq, IOAPIC_MAP_ALLOC);
IOAPIC_MAP_ALLOC);
} }
EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
...@@ -1209,17 +1128,16 @@ static void __init setup_IO_APIC_irqs(void) ...@@ -1209,17 +1128,16 @@ static void __init setup_IO_APIC_irqs(void)
unsigned int ioapic, pin; unsigned int ioapic, pin;
int idx; int idx;
apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); apic_pr_verbose("Init IO_APIC IRQs\n");
for_each_ioapic_pin(ioapic, pin) { for_each_ioapic_pin(ioapic, pin) {
idx = find_irq_entry(ioapic, pin, mp_INT); idx = find_irq_entry(ioapic, pin, mp_INT);
if (idx < 0) if (idx < 0) {
apic_printk(APIC_VERBOSE, apic_pr_verbose("apic %d pin %d not connected\n",
KERN_DEBUG " apic %d pin %d not connected\n",
mpc_ioapic_id(ioapic), pin); mpc_ioapic_id(ioapic), pin);
else } else {
pin_2_irq(idx, ioapic, pin, pin_2_irq(idx, ioapic, pin, ioapic ? 0 : IOAPIC_MAP_ALLOC);
ioapic ? 0 : IOAPIC_MAP_ALLOC); }
} }
} }
...@@ -1234,26 +1152,21 @@ static void io_apic_print_entries(unsigned int apic, unsigned int nr_entries) ...@@ -1234,26 +1152,21 @@ static void io_apic_print_entries(unsigned int apic, unsigned int nr_entries)
char buf[256]; char buf[256];
int i; int i;
printk(KERN_DEBUG "IOAPIC %d:\n", apic); apic_dbg("IOAPIC %d:\n", apic);
for (i = 0; i <= nr_entries; i++) { for (i = 0; i <= nr_entries; i++) {
entry = ioapic_read_entry(apic, i); entry = ioapic_read_entry(apic, i);
snprintf(buf, sizeof(buf), snprintf(buf, sizeof(buf), " pin%02x, %s, %s, %s, V(%02X), IRR(%1d), S(%1d)",
" pin%02x, %s, %s, %s, V(%02X), IRR(%1d), S(%1d)", i, entry.masked ? "disabled" : "enabled ",
i,
entry.masked ? "disabled" : "enabled ",
entry.is_level ? "level" : "edge ", entry.is_level ? "level" : "edge ",
entry.active_low ? "low " : "high", entry.active_low ? "low " : "high",
entry.vector, entry.irr, entry.delivery_status); entry.vector, entry.irr, entry.delivery_status);
if (entry.ir_format) { if (entry.ir_format) {
printk(KERN_DEBUG "%s, remapped, I(%04X), Z(%X)\n", apic_dbg("%s, remapped, I(%04X), Z(%X)\n", buf,
buf, (entry.ir_index_15 << 15) | entry.ir_index_0_14, entry.ir_zero);
(entry.ir_index_15 << 15) | entry.ir_index_0_14,
entry.ir_zero);
} else { } else {
printk(KERN_DEBUG "%s, %s, D(%02X%02X), M(%1d)\n", buf, apic_dbg("%s, %s, D(%02X%02X), M(%1d)\n", buf,
entry.dest_mode_logical ? "logical " : "physical", entry.dest_mode_logical ? "logical " : "physic al",
entry.virt_destid_8_14, entry.destid_0_7, entry.virt_destid_8_14, entry.destid_0_7, entry.delivery_mode);
entry.delivery_mode);
} }
} }
} }
...@@ -1264,30 +1177,25 @@ static void __init print_IO_APIC(int ioapic_idx) ...@@ -1264,30 +1177,25 @@ static void __init print_IO_APIC(int ioapic_idx)
union IO_APIC_reg_01 reg_01; union IO_APIC_reg_01 reg_01;
union IO_APIC_reg_02 reg_02; union IO_APIC_reg_02 reg_02;
union IO_APIC_reg_03 reg_03; union IO_APIC_reg_03 reg_03;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags); scoped_guard (raw_spinlock_irqsave, &ioapic_lock) {
reg_00.raw = io_apic_read(ioapic_idx, 0); reg_00.raw = io_apic_read(ioapic_idx, 0);
reg_01.raw = io_apic_read(ioapic_idx, 1); reg_01.raw = io_apic_read(ioapic_idx, 1);
if (reg_01.bits.version >= 0x10) if (reg_01.bits.version >= 0x10)
reg_02.raw = io_apic_read(ioapic_idx, 2); reg_02.raw = io_apic_read(ioapic_idx, 2);
if (reg_01.bits.version >= 0x20) if (reg_01.bits.version >= 0x20)
reg_03.raw = io_apic_read(ioapic_idx, 3); reg_03.raw = io_apic_read(ioapic_idx, 3);
raw_spin_unlock_irqrestore(&ioapic_lock, flags); }
printk(KERN_DEBUG "IO APIC #%d......\n", mpc_ioapic_id(ioapic_idx));
printk(KERN_DEBUG ".... register #00: %08X\n", reg_00.raw);
printk(KERN_DEBUG "....... : physical APIC id: %02X\n", reg_00.bits.ID);
printk(KERN_DEBUG "....... : Delivery Type: %X\n", reg_00.bits.delivery_type);
printk(KERN_DEBUG "....... : LTS : %X\n", reg_00.bits.LTS);
printk(KERN_DEBUG ".... register #01: %08X\n", *(int *)&reg_01);
printk(KERN_DEBUG "....... : max redirection entries: %02X\n",
reg_01.bits.entries);
printk(KERN_DEBUG "....... : PRQ implemented: %X\n", reg_01.bits.PRQ); apic_dbg("IO APIC #%d......\n", mpc_ioapic_id(ioapic_idx));
printk(KERN_DEBUG "....... : IO APIC version: %02X\n", apic_dbg(".... register #00: %08X\n", reg_00.raw);
reg_01.bits.version); apic_dbg("....... : physical APIC id: %02X\n", reg_00.bits.ID);
apic_dbg("....... : Delivery Type: %X\n", reg_00.bits.delivery_type);
apic_dbg("....... : LTS : %X\n", reg_00.bits.LTS);
apic_dbg(".... register #01: %08X\n", *(int *)&reg_01);
apic_dbg("....... : max redirection entries: %02X\n", reg_01.bits.entries);
apic_dbg("....... : PRQ implemented: %X\n", reg_01.bits.PRQ);
apic_dbg("....... : IO APIC version: %02X\n", reg_01.bits.version);
/* /*
* Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02, * Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02,
...@@ -1295,8 +1203,8 @@ static void __init print_IO_APIC(int ioapic_idx) ...@@ -1295,8 +1203,8 @@ static void __init print_IO_APIC(int ioapic_idx)
* value, so ignore it if reg_02 == reg_01. * value, so ignore it if reg_02 == reg_01.
*/ */
if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) { if (reg_01.bits.version >= 0x10 && reg_02.raw != reg_01.raw) {
printk(KERN_DEBUG ".... register #02: %08X\n", reg_02.raw); apic_dbg(".... register #02: %08X\n", reg_02.raw);
printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.bits.arbitration); apic_dbg("....... : arbitration: %02X\n", reg_02.bits.arbitration);
} }
/* /*
...@@ -1306,11 +1214,11 @@ static void __init print_IO_APIC(int ioapic_idx) ...@@ -1306,11 +1214,11 @@ static void __init print_IO_APIC(int ioapic_idx)
*/ */
if (reg_01.bits.version >= 0x20 && reg_03.raw != reg_02.raw && if (reg_01.bits.version >= 0x20 && reg_03.raw != reg_02.raw &&
reg_03.raw != reg_01.raw) { reg_03.raw != reg_01.raw) {
printk(KERN_DEBUG ".... register #03: %08X\n", reg_03.raw); apic_dbg(".... register #03: %08X\n", reg_03.raw);
printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.bits.boot_DT); apic_dbg("....... : Boot DT : %X\n", reg_03.bits.boot_DT);
} }
printk(KERN_DEBUG ".... IRQ redirection table:\n"); apic_dbg(".... IRQ redirection table:\n");
io_apic_print_entries(ioapic_idx, reg_01.bits.entries); io_apic_print_entries(ioapic_idx, reg_01.bits.entries);
} }
...@@ -1319,11 +1227,11 @@ void __init print_IO_APICs(void) ...@@ -1319,11 +1227,11 @@ void __init print_IO_APICs(void)
int ioapic_idx; int ioapic_idx;
unsigned int irq; unsigned int irq;
printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries); apic_dbg("number of MP IRQ sources: %d.\n", mp_irq_entries);
for_each_ioapic(ioapic_idx) for_each_ioapic(ioapic_idx) {
printk(KERN_DEBUG "number of IO-APIC #%d registers: %d.\n", apic_dbg("number of IO-APIC #%d registers: %d.\n",
mpc_ioapic_id(ioapic_idx), mpc_ioapic_id(ioapic_idx), ioapics[ioapic_idx].nr_registers);
ioapics[ioapic_idx].nr_registers); }
/* /*
* We are a bit conservative about what we expect. We have to * We are a bit conservative about what we expect. We have to
...@@ -1334,7 +1242,7 @@ void __init print_IO_APICs(void) ...@@ -1334,7 +1242,7 @@ void __init print_IO_APICs(void)
for_each_ioapic(ioapic_idx) for_each_ioapic(ioapic_idx)
print_IO_APIC(ioapic_idx); print_IO_APIC(ioapic_idx);
printk(KERN_DEBUG "IRQ to pin mappings:\n"); apic_dbg("IRQ to pin mappings:\n");
for_each_active_irq(irq) { for_each_active_irq(irq) {
struct irq_pin_list *entry; struct irq_pin_list *entry;
struct irq_chip *chip; struct irq_chip *chip;
...@@ -1349,7 +1257,7 @@ void __init print_IO_APICs(void) ...@@ -1349,7 +1257,7 @@ void __init print_IO_APICs(void)
if (list_empty(&data->irq_2_pin)) if (list_empty(&data->irq_2_pin))
continue; continue;
printk(KERN_DEBUG "IRQ%d ", irq); apic_dbg("IRQ%d ", irq);
for_each_irq_pin(entry, data->irq_2_pin) for_each_irq_pin(entry, data->irq_2_pin)
pr_cont("-> %d:%d", entry->apic, entry->pin); pr_cont("-> %d:%d", entry->apic, entry->pin);
pr_cont("\n"); pr_cont("\n");
...@@ -1363,8 +1271,7 @@ static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; ...@@ -1363,8 +1271,7 @@ static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
void __init enable_IO_APIC(void) void __init enable_IO_APIC(void)
{ {
int i8259_apic, i8259_pin; int i8259_apic, i8259_pin, apic, pin;
int apic, pin;
if (ioapic_is_disabled) if (ioapic_is_disabled)
nr_ioapics = 0; nr_ioapics = 0;
...@@ -1376,19 +1283,21 @@ void __init enable_IO_APIC(void) ...@@ -1376,19 +1283,21 @@ void __init enable_IO_APIC(void)
/* See if any of the pins is in ExtINT mode */ /* See if any of the pins is in ExtINT mode */
struct IO_APIC_route_entry entry = ioapic_read_entry(apic, pin); struct IO_APIC_route_entry entry = ioapic_read_entry(apic, pin);
/* If the interrupt line is enabled and in ExtInt mode /*
* I have found the pin where the i8259 is connected. * If the interrupt line is enabled and in ExtInt mode I
* have found the pin where the i8259 is connected.
*/ */
if (!entry.masked && if (!entry.masked && entry.delivery_mode == APIC_DELIVERY_MODE_EXTINT) {
entry.delivery_mode == APIC_DELIVERY_MODE_EXTINT) {
ioapic_i8259.apic = apic; ioapic_i8259.apic = apic;
ioapic_i8259.pin = pin; ioapic_i8259.pin = pin;
goto found_i8259; break;
} }
} }
found_i8259:
/* Look to see what if the MP table has reported the ExtINT */ /*
/* If we could not find the appropriate pin by looking at the ioapic * Look to see what if the MP table has reported the ExtINT
*
* If we could not find the appropriate pin by looking at the ioapic
* the i8259 probably is not connected the ioapic but give the * the i8259 probably is not connected the ioapic but give the
* mptable a chance anyway. * mptable a chance anyway.
*/ */
...@@ -1396,29 +1305,24 @@ void __init enable_IO_APIC(void) ...@@ -1396,29 +1305,24 @@ void __init enable_IO_APIC(void)
i8259_apic = find_isa_irq_apic(0, mp_ExtINT); i8259_apic = find_isa_irq_apic(0, mp_ExtINT);
/* Trust the MP table if nothing is setup in the hardware */ /* Trust the MP table if nothing is setup in the hardware */
if ((ioapic_i8259.pin == -1) && (i8259_pin >= 0)) { if ((ioapic_i8259.pin == -1) && (i8259_pin >= 0)) {
printk(KERN_WARNING "ExtINT not setup in hardware but reported by MP table\n"); pr_warn("ExtINT not setup in hardware but reported by MP table\n");
ioapic_i8259.pin = i8259_pin; ioapic_i8259.pin = i8259_pin;
ioapic_i8259.apic = i8259_apic; ioapic_i8259.apic = i8259_apic;
} }
/* Complain if the MP table and the hardware disagree */ /* Complain if the MP table and the hardware disagree */
if (((ioapic_i8259.apic != i8259_apic) || (ioapic_i8259.pin != i8259_pin)) && if (((ioapic_i8259.apic != i8259_apic) || (ioapic_i8259.pin != i8259_pin)) &&
(i8259_pin >= 0) && (ioapic_i8259.pin >= 0)) (i8259_pin >= 0) && (ioapic_i8259.pin >= 0))
{ pr_warn("ExtINT in hardware and MP table differ\n");
printk(KERN_WARNING "ExtINT in hardware and MP table differ\n");
}
/* /* Do not trust the IO-APIC being empty at bootup */
* Do not trust the IO-APIC being empty at bootup
*/
clear_IO_APIC(); clear_IO_APIC();
} }
void native_restore_boot_irq_mode(void) void native_restore_boot_irq_mode(void)
{ {
/* /*
* If the i8259 is routed through an IOAPIC * If the i8259 is routed through an IOAPIC Put that IOAPIC in
* Put that IOAPIC in virtual wire mode * virtual wire mode so legacy interrupts can be delivered.
* so legacy interrupts can be delivered.
*/ */
if (ioapic_i8259.pin != -1) { if (ioapic_i8259.pin != -1) {
struct IO_APIC_route_entry entry; struct IO_APIC_route_entry entry;
...@@ -1433,9 +1337,7 @@ void native_restore_boot_irq_mode(void) ...@@ -1433,9 +1337,7 @@ void native_restore_boot_irq_mode(void)
entry.destid_0_7 = apic_id & 0xFF; entry.destid_0_7 = apic_id & 0xFF;
entry.virt_destid_8_14 = apic_id >> 8; entry.virt_destid_8_14 = apic_id >> 8;
/* /* Add it to the IO-APIC irq-routing table */
* Add it to the IO-APIC irq-routing table:
*/
ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry); ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);
} }
...@@ -1464,7 +1366,6 @@ static void __init setup_ioapic_ids_from_mpc_nocheck(void) ...@@ -1464,7 +1366,6 @@ static void __init setup_ioapic_ids_from_mpc_nocheck(void)
const u32 broadcast_id = 0xF; const u32 broadcast_id = 0xF;
union IO_APIC_reg_00 reg_00; union IO_APIC_reg_00 reg_00;
unsigned char old_id; unsigned char old_id;
unsigned long flags;
int ioapic_idx, i; int ioapic_idx, i;
/* /*
...@@ -1478,9 +1379,8 @@ static void __init setup_ioapic_ids_from_mpc_nocheck(void) ...@@ -1478,9 +1379,8 @@ static void __init setup_ioapic_ids_from_mpc_nocheck(void)
*/ */
for_each_ioapic(ioapic_idx) { for_each_ioapic(ioapic_idx) {
/* Read the register 0 value */ /* Read the register 0 value */
raw_spin_lock_irqsave(&ioapic_lock, flags); scoped_guard (raw_spinlock_irqsave, &ioapic_lock)
reg_00.raw = io_apic_read(ioapic_idx, 0); reg_00.raw = io_apic_read(ioapic_idx, 0);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
old_id = mpc_ioapic_id(ioapic_idx); old_id = mpc_ioapic_id(ioapic_idx);
...@@ -1508,47 +1408,42 @@ static void __init setup_ioapic_ids_from_mpc_nocheck(void) ...@@ -1508,47 +1408,42 @@ static void __init setup_ioapic_ids_from_mpc_nocheck(void)
set_bit(i, phys_id_present_map); set_bit(i, phys_id_present_map);
ioapics[ioapic_idx].mp_config.apicid = i; ioapics[ioapic_idx].mp_config.apicid = i;
} else { } else {
apic_printk(APIC_VERBOSE, "Setting %d in the phys_id_present_map\n", apic_pr_verbose("Setting %d in the phys_id_present_map\n",
mpc_ioapic_id(ioapic_idx)); mpc_ioapic_id(ioapic_idx));
set_bit(mpc_ioapic_id(ioapic_idx), phys_id_present_map); set_bit(mpc_ioapic_id(ioapic_idx), phys_id_present_map);
} }
/* /*
* We need to adjust the IRQ routing table * We need to adjust the IRQ routing table if the ID
* if the ID changed. * changed.
*/ */
if (old_id != mpc_ioapic_id(ioapic_idx)) if (old_id != mpc_ioapic_id(ioapic_idx)) {
for (i = 0; i < mp_irq_entries; i++) for (i = 0; i < mp_irq_entries; i++) {
if (mp_irqs[i].dstapic == old_id) if (mp_irqs[i].dstapic == old_id)
mp_irqs[i].dstapic mp_irqs[i].dstapic = mpc_ioapic_id(ioapic_idx);
= mpc_ioapic_id(ioapic_idx); }
}
/* /*
* Update the ID register according to the right value * Update the ID register according to the right value from
* from the MPC table if they are different. * the MPC table if they are different.
*/ */
if (mpc_ioapic_id(ioapic_idx) == reg_00.bits.ID) if (mpc_ioapic_id(ioapic_idx) == reg_00.bits.ID)
continue; continue;
apic_printk(APIC_VERBOSE, KERN_INFO apic_pr_verbose("...changing IO-APIC physical APIC ID to %d ...",
"...changing IO-APIC physical APIC ID to %d ...",
mpc_ioapic_id(ioapic_idx)); mpc_ioapic_id(ioapic_idx));
reg_00.bits.ID = mpc_ioapic_id(ioapic_idx); reg_00.bits.ID = mpc_ioapic_id(ioapic_idx);
raw_spin_lock_irqsave(&ioapic_lock, flags); scoped_guard (raw_spinlock_irqsave, &ioapic_lock) {
io_apic_write(ioapic_idx, 0, reg_00.raw); io_apic_write(ioapic_idx, 0, reg_00.raw);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
/*
* Sanity check
*/
raw_spin_lock_irqsave(&ioapic_lock, flags);
reg_00.raw = io_apic_read(ioapic_idx, 0); reg_00.raw = io_apic_read(ioapic_idx, 0);
raw_spin_unlock_irqrestore(&ioapic_lock, flags); }
/* Sanity check */
if (reg_00.bits.ID != mpc_ioapic_id(ioapic_idx)) if (reg_00.bits.ID != mpc_ioapic_id(ioapic_idx))
pr_cont("could not set ID!\n"); pr_cont("could not set ID!\n");
else else
apic_printk(APIC_VERBOSE, " ok.\n"); apic_pr_verbose(" ok.\n");
} }
} }
...@@ -1593,8 +1488,7 @@ static void __init delay_with_tsc(void) ...@@ -1593,8 +1488,7 @@ static void __init delay_with_tsc(void)
do { do {
rep_nop(); rep_nop();
now = rdtsc(); now = rdtsc();
} while ((now - start) < 40000000000ULL / HZ && } while ((now - start) < 40000000000ULL / HZ && time_before_eq(jiffies, end));
time_before_eq(jiffies, end));
} }
static void __init delay_without_tsc(void) static void __init delay_without_tsc(void)
...@@ -1655,36 +1549,29 @@ static int __init timer_irq_works(void) ...@@ -1655,36 +1549,29 @@ static int __init timer_irq_works(void)
* so we 'resend' these IRQs via IPIs, to the same CPU. It's much * so we 'resend' these IRQs via IPIs, to the same CPU. It's much
* better to do it this way as thus we do not have to be aware of * better to do it this way as thus we do not have to be aware of
* 'pending' interrupts in the IRQ path, except at this point. * 'pending' interrupts in the IRQ path, except at this point.
*/
/*
* Edge triggered needs to resend any interrupt
* that was delayed but this is now handled in the device
* independent code.
*/
/*
* Starting up a edge-triggered IO-APIC interrupt is
* nasty - we need to make sure that we get the edge.
* If it is already asserted for some reason, we need
* return 1 to indicate that is was pending.
* *
* This is not complete - we should be able to fake *
* an edge even if it isn't on the 8259A... * Edge triggered needs to resend any interrupt that was delayed but this
* is now handled in the device independent code.
*
* Starting up a edge-triggered IO-APIC interrupt is nasty - we need to
* make sure that we get the edge. If it is already asserted for some
* reason, we need return 1 to indicate that is was pending.
*
* This is not complete - we should be able to fake an edge even if it
* isn't on the 8259A...
*/ */
static unsigned int startup_ioapic_irq(struct irq_data *data) static unsigned int startup_ioapic_irq(struct irq_data *data)
{ {
int was_pending = 0, irq = data->irq; int was_pending = 0, irq = data->irq;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags); guard(raw_spinlock_irqsave)(&ioapic_lock);
if (irq < nr_legacy_irqs()) { if (irq < nr_legacy_irqs()) {
legacy_pic->mask(irq); legacy_pic->mask(irq);
if (legacy_pic->irq_pending(irq)) if (legacy_pic->irq_pending(irq))
was_pending = 1; was_pending = 1;
} }
__unmask_ioapic(data->chip_data); __unmask_ioapic(data->chip_data);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
return was_pending; return was_pending;
} }
...@@ -1694,9 +1581,8 @@ atomic_t irq_mis_count; ...@@ -1694,9 +1581,8 @@ atomic_t irq_mis_count;
static bool io_apic_level_ack_pending(struct mp_chip_data *data) static bool io_apic_level_ack_pending(struct mp_chip_data *data)
{ {
struct irq_pin_list *entry; struct irq_pin_list *entry;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags); guard(raw_spinlock_irqsave)(&ioapic_lock);
for_each_irq_pin(entry, data->irq_2_pin) { for_each_irq_pin(entry, data->irq_2_pin) {
struct IO_APIC_route_entry e; struct IO_APIC_route_entry e;
int pin; int pin;
...@@ -1704,13 +1590,9 @@ static bool io_apic_level_ack_pending(struct mp_chip_data *data) ...@@ -1704,13 +1590,9 @@ static bool io_apic_level_ack_pending(struct mp_chip_data *data)
pin = entry->pin; pin = entry->pin;
e.w1 = io_apic_read(entry->apic, 0x10 + pin*2); e.w1 = io_apic_read(entry->apic, 0x10 + pin*2);
/* Is the remote IRR bit set? */ /* Is the remote IRR bit set? */
if (e.irr) { if (e.irr)
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
return true; return true;
} }
}
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
return false; return false;
} }
...@@ -1728,7 +1610,8 @@ static inline bool ioapic_prepare_move(struct irq_data *data) ...@@ -1728,7 +1610,8 @@ static inline bool ioapic_prepare_move(struct irq_data *data)
static inline void ioapic_finish_move(struct irq_data *data, bool moveit) static inline void ioapic_finish_move(struct irq_data *data, bool moveit)
{ {
if (unlikely(moveit)) { if (unlikely(moveit)) {
/* Only migrate the irq if the ack has been received. /*
* Only migrate the irq if the ack has been received.
* *
* On rare occasions the broadcast level triggered ack gets * On rare occasions the broadcast level triggered ack gets
* delayed going to ioapics, and if we reprogram the * delayed going to ioapics, and if we reprogram the
...@@ -1911,18 +1794,16 @@ static void ioapic_configure_entry(struct irq_data *irqd) ...@@ -1911,18 +1794,16 @@ static void ioapic_configure_entry(struct irq_data *irqd)
__ioapic_write_entry(entry->apic, entry->pin, mpd->entry); __ioapic_write_entry(entry->apic, entry->pin, mpd->entry);
} }
static int ioapic_set_affinity(struct irq_data *irq_data, static int ioapic_set_affinity(struct irq_data *irq_data, const struct cpumask *mask, bool force)
const struct cpumask *mask, bool force)
{ {
struct irq_data *parent = irq_data->parent_data; struct irq_data *parent = irq_data->parent_data;
unsigned long flags;
int ret; int ret;
ret = parent->chip->irq_set_affinity(parent, mask, force); ret = parent->chip->irq_set_affinity(parent, mask, force);
raw_spin_lock_irqsave(&ioapic_lock, flags);
guard(raw_spinlock_irqsave)(&ioapic_lock);
if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE) if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE)
ioapic_configure_entry(irq_data); ioapic_configure_entry(irq_data);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
return ret; return ret;
} }
...@@ -1941,8 +1822,7 @@ static int ioapic_set_affinity(struct irq_data *irq_data, ...@@ -1941,8 +1822,7 @@ static int ioapic_set_affinity(struct irq_data *irq_data,
* *
* Verify that the corresponding Remote-IRR bits are clear. * Verify that the corresponding Remote-IRR bits are clear.
*/ */
static int ioapic_irq_get_chip_state(struct irq_data *irqd, static int ioapic_irq_get_chip_state(struct irq_data *irqd, enum irqchip_irq_state which,
enum irqchip_irq_state which,
bool *state) bool *state)
{ {
struct mp_chip_data *mcd = irqd->chip_data; struct mp_chip_data *mcd = irqd->chip_data;
...@@ -1953,7 +1833,8 @@ static int ioapic_irq_get_chip_state(struct irq_data *irqd, ...@@ -1953,7 +1833,8 @@ static int ioapic_irq_get_chip_state(struct irq_data *irqd,
return -EINVAL; return -EINVAL;
*state = false; *state = false;
raw_spin_lock(&ioapic_lock);
guard(raw_spinlock)(&ioapic_lock);
for_each_irq_pin(p, mcd->irq_2_pin) { for_each_irq_pin(p, mcd->irq_2_pin) {
rentry = __ioapic_read_entry(p->apic, p->pin); rentry = __ioapic_read_entry(p->apic, p->pin);
/* /*
...@@ -1967,7 +1848,6 @@ static int ioapic_irq_get_chip_state(struct irq_data *irqd, ...@@ -1967,7 +1848,6 @@ static int ioapic_irq_get_chip_state(struct irq_data *irqd,
break; break;
} }
} }
raw_spin_unlock(&ioapic_lock);
return 0; return 0;
} }
...@@ -2008,14 +1888,13 @@ static inline void init_IO_APIC_traps(void) ...@@ -2008,14 +1888,13 @@ static inline void init_IO_APIC_traps(void)
cfg = irq_cfg(irq); cfg = irq_cfg(irq);
if (IO_APIC_IRQ(irq) && cfg && !cfg->vector) { 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
* so default to an old-fashioned 8259 * default to an old-fashioned 8259 interrupt if we
* interrupt if we can.. * can. Otherwise set the dummy interrupt chip.
*/ */
if (irq < nr_legacy_irqs()) if (irq < nr_legacy_irqs())
legacy_pic->make_irq(irq); legacy_pic->make_irq(irq);
else else
/* Strange. Oh, well.. */
irq_set_chip(irq, &no_irq_chip); irq_set_chip(irq, &no_irq_chip);
} }
} }
...@@ -2024,20 +1903,17 @@ static inline void init_IO_APIC_traps(void) ...@@ -2024,20 +1903,17 @@ static inline void init_IO_APIC_traps(void)
/* /*
* The local APIC irq-chip implementation: * The local APIC irq-chip implementation:
*/ */
static void mask_lapic_irq(struct irq_data *data) static void mask_lapic_irq(struct irq_data *data)
{ {
unsigned long v; unsigned long v = apic_read(APIC_LVT0);
v = apic_read(APIC_LVT0);
apic_write(APIC_LVT0, v | APIC_LVT_MASKED); apic_write(APIC_LVT0, v | APIC_LVT_MASKED);
} }
static void unmask_lapic_irq(struct irq_data *data) static void unmask_lapic_irq(struct irq_data *data)
{ {
unsigned long v; unsigned long v = apic_read(APIC_LVT0);
v = apic_read(APIC_LVT0);
apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED); apic_write(APIC_LVT0, v & ~APIC_LVT_MASKED);
} }
...@@ -2056,8 +1932,7 @@ static struct irq_chip lapic_chip __read_mostly = { ...@@ -2056,8 +1932,7 @@ static struct irq_chip lapic_chip __read_mostly = {
static void lapic_register_intr(int irq) static void lapic_register_intr(int irq)
{ {
irq_clear_status_flags(irq, IRQ_LEVEL); irq_clear_status_flags(irq, IRQ_LEVEL);
irq_set_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq, irq_set_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq, "edge");
"edge");
} }
/* /*
...@@ -2069,9 +1944,9 @@ static void lapic_register_intr(int irq) ...@@ -2069,9 +1944,9 @@ static void lapic_register_intr(int irq)
*/ */
static inline void __init unlock_ExtINT_logic(void) static inline void __init unlock_ExtINT_logic(void)
{ {
int apic, pin, i;
struct IO_APIC_route_entry entry0, entry1;
unsigned char save_control, save_freq_select; unsigned char save_control, save_freq_select;
struct IO_APIC_route_entry entry0, entry1;
int apic, pin, i;
u32 apic_id; u32 apic_id;
pin = find_isa_irq_pin(8, mp_INT); pin = find_isa_irq_pin(8, mp_INT);
...@@ -2131,10 +2006,10 @@ static int __init disable_timer_pin_setup(char *arg) ...@@ -2131,10 +2006,10 @@ static int __init disable_timer_pin_setup(char *arg)
} }
early_param("disable_timer_pin_1", disable_timer_pin_setup); early_param("disable_timer_pin_1", disable_timer_pin_setup);
static int mp_alloc_timer_irq(int ioapic, int pin) static int __init mp_alloc_timer_irq(int ioapic, int pin)
{ {
int irq = -1;
struct irq_domain *domain = mp_ioapic_irqdomain(ioapic); struct irq_domain *domain = mp_ioapic_irqdomain(ioapic);
int irq = -1;
if (domain) { if (domain) {
struct irq_alloc_info info; struct irq_alloc_info info;
...@@ -2142,21 +2017,36 @@ static int mp_alloc_timer_irq(int ioapic, int pin) ...@@ -2142,21 +2017,36 @@ static int mp_alloc_timer_irq(int ioapic, int pin)
ioapic_set_alloc_attr(&info, NUMA_NO_NODE, 0, 0); ioapic_set_alloc_attr(&info, NUMA_NO_NODE, 0, 0);
info.devid = mpc_ioapic_id(ioapic); info.devid = mpc_ioapic_id(ioapic);
info.ioapic.pin = pin; info.ioapic.pin = pin;
mutex_lock(&ioapic_mutex); guard(mutex)(&ioapic_mutex);
irq = alloc_isa_irq_from_domain(domain, 0, ioapic, pin, &info); irq = alloc_isa_irq_from_domain(domain, 0, ioapic, pin, &info);
mutex_unlock(&ioapic_mutex);
} }
return irq; return irq;
} }
static void __init replace_pin_at_irq_node(struct mp_chip_data *data, int node,
int oldapic, int oldpin,
int newapic, int newpin)
{
struct irq_pin_list *entry;
for_each_irq_pin(entry, data->irq_2_pin) {
if (entry->apic == oldapic && entry->pin == oldpin) {
entry->apic = newapic;
entry->pin = newpin;
return;
}
}
/* Old apic/pin didn't exist, so just add a new one */
add_pin_to_irq_node(data, node, newapic, newpin);
}
/* /*
* This code may look a bit paranoid, but it's supposed to cooperate with * This code may look a bit paranoid, but it's supposed to cooperate with
* a wide range of boards and BIOS bugs. Fortunately only the timer IRQ * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
* is so screwy. Thanks to Brian Perkins for testing/hacking this beast * is so screwy. Thanks to Brian Perkins for testing/hacking this beast
* fanatically on his truly buggy board. * fanatically on his truly buggy board.
*
* FIXME: really need to revamp this for all platforms.
*/ */
static inline void __init check_timer(void) static inline void __init check_timer(void)
{ {
...@@ -2194,8 +2084,7 @@ static inline void __init check_timer(void) ...@@ -2194,8 +2084,7 @@ static inline void __init check_timer(void)
pin2 = ioapic_i8259.pin; pin2 = ioapic_i8259.pin;
apic2 = ioapic_i8259.apic; apic2 = ioapic_i8259.apic;
apic_printk(APIC_QUIET, KERN_INFO "..TIMER: vector=0x%02X " pr_info("..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
"apic1=%d pin1=%d apic2=%d pin2=%d\n",
cfg->vector, apic1, pin1, apic2, pin2); cfg->vector, apic1, pin1, apic2, pin2);
/* /*
...@@ -2240,13 +2129,10 @@ static inline void __init check_timer(void) ...@@ -2240,13 +2129,10 @@ static inline void __init check_timer(void)
panic_if_irq_remap("timer doesn't work through Interrupt-remapped IO-APIC"); panic_if_irq_remap("timer doesn't work through Interrupt-remapped IO-APIC");
clear_IO_APIC_pin(apic1, pin1); clear_IO_APIC_pin(apic1, pin1);
if (!no_pin1) if (!no_pin1)
apic_printk(APIC_QUIET, KERN_ERR "..MP-BIOS bug: " pr_err("..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
"8254 timer not connected to IO-APIC\n");
apic_printk(APIC_QUIET, KERN_INFO "...trying to set up timer " pr_info("...trying to set up timer (IRQ0) through the 8259A ...\n");
"(IRQ0) through the 8259A ...\n"); pr_info("..... (found apic %d pin %d) ...\n", apic2, pin2);
apic_printk(APIC_QUIET, KERN_INFO
"..... (found apic %d pin %d) ...\n", apic2, pin2);
/* /*
* legacy devices should be connected to IO APIC #0 * legacy devices should be connected to IO APIC #0
*/ */
...@@ -2255,7 +2141,7 @@ static inline void __init check_timer(void) ...@@ -2255,7 +2141,7 @@ static inline void __init check_timer(void)
irq_domain_activate_irq(irq_data, false); irq_domain_activate_irq(irq_data, false);
legacy_pic->unmask(0); legacy_pic->unmask(0);
if (timer_irq_works()) { if (timer_irq_works()) {
apic_printk(APIC_QUIET, KERN_INFO "....... works.\n"); pr_info("....... works.\n");
goto out; goto out;
} }
/* /*
...@@ -2263,26 +2149,24 @@ static inline void __init check_timer(void) ...@@ -2263,26 +2149,24 @@ static inline void __init check_timer(void)
*/ */
legacy_pic->mask(0); legacy_pic->mask(0);
clear_IO_APIC_pin(apic2, pin2); clear_IO_APIC_pin(apic2, pin2);
apic_printk(APIC_QUIET, KERN_INFO "....... failed.\n"); pr_info("....... failed.\n");
} }
apic_printk(APIC_QUIET, KERN_INFO pr_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);
apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */ apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */
legacy_pic->unmask(0); legacy_pic->unmask(0);
if (timer_irq_works()) { if (timer_irq_works()) {
apic_printk(APIC_QUIET, KERN_INFO "..... works.\n"); pr_info("..... works.\n");
goto out; goto out;
} }
legacy_pic->mask(0); legacy_pic->mask(0);
apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector); apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector);
apic_printk(APIC_QUIET, KERN_INFO "..... failed.\n"); pr_info("..... failed.\n");
apic_printk(APIC_QUIET, KERN_INFO pr_info("...trying to set up timer as ExtINT IRQ...\n");
"...trying to set up timer as ExtINT IRQ...\n");
legacy_pic->init(0); legacy_pic->init(0);
legacy_pic->make_irq(0); legacy_pic->make_irq(0);
...@@ -2292,14 +2176,15 @@ static inline void __init check_timer(void) ...@@ -2292,14 +2176,15 @@ static inline void __init check_timer(void)
unlock_ExtINT_logic(); unlock_ExtINT_logic();
if (timer_irq_works()) { if (timer_irq_works()) {
apic_printk(APIC_QUIET, KERN_INFO "..... works.\n"); pr_info("..... works.\n");
goto out; goto out;
} }
apic_printk(APIC_QUIET, KERN_INFO "..... failed :(.\n");
if (apic_is_x2apic_enabled()) pr_info("..... failed :\n");
apic_printk(APIC_QUIET, KERN_INFO if (apic_is_x2apic_enabled()) {
"Perhaps problem with the pre-enabled x2apic mode\n" pr_info("Perhaps problem with the pre-enabled x2apic mode\n"
"Try booting with x2apic and interrupt-remapping disabled in the bios.\n"); "Try booting with x2apic and interrupt-remapping disabled in the bios.\n");
}
panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a " panic("IO-APIC + timer doesn't work! Boot with apic=debug and send a "
"report. Then try booting with the 'noapic' option.\n"); "report. Then try booting with the 'noapic' option.\n");
out: out:
...@@ -2327,11 +2212,11 @@ static inline void __init check_timer(void) ...@@ -2327,11 +2212,11 @@ static inline void __init check_timer(void)
static int mp_irqdomain_create(int ioapic) static int mp_irqdomain_create(int ioapic)
{ {
struct irq_domain *parent; struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(ioapic);
int hwirqs = mp_ioapic_pin_count(ioapic); int hwirqs = mp_ioapic_pin_count(ioapic);
struct ioapic *ip = &ioapics[ioapic]; struct ioapic *ip = &ioapics[ioapic];
struct ioapic_domain_cfg *cfg = &ip->irqdomain_cfg; struct ioapic_domain_cfg *cfg = &ip->irqdomain_cfg;
struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(ioapic); struct irq_domain *parent;
struct fwnode_handle *fn; struct fwnode_handle *fn;
struct irq_fwspec fwspec; struct irq_fwspec fwspec;
...@@ -2367,10 +2252,8 @@ static int mp_irqdomain_create(int ioapic) ...@@ -2367,10 +2252,8 @@ static int mp_irqdomain_create(int ioapic)
return -ENOMEM; return -ENOMEM;
} }
if (cfg->type == IOAPIC_DOMAIN_LEGACY || if (cfg->type == IOAPIC_DOMAIN_LEGACY || cfg->type == IOAPIC_DOMAIN_STRICT)
cfg->type == IOAPIC_DOMAIN_STRICT) ioapic_dynirq_base = max(ioapic_dynirq_base, gsi_cfg->gsi_end + 1);
ioapic_dynirq_base = max(ioapic_dynirq_base,
gsi_cfg->gsi_end + 1);
return 0; return 0;
} }
...@@ -2397,13 +2280,11 @@ void __init setup_IO_APIC(void) ...@@ -2397,13 +2280,11 @@ void __init setup_IO_APIC(void)
io_apic_irqs = nr_legacy_irqs() ? ~PIC_IRQS : ~0UL; io_apic_irqs = nr_legacy_irqs() ? ~PIC_IRQS : ~0UL;
apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); apic_pr_verbose("ENABLING IO-APIC IRQs\n");
for_each_ioapic(ioapic) for_each_ioapic(ioapic)
BUG_ON(mp_irqdomain_create(ioapic)); BUG_ON(mp_irqdomain_create(ioapic));
/* /* Set up IO-APIC IRQ routing. */
* Set up IO-APIC IRQ routing.
*/
x86_init.mpparse.setup_ioapic_ids(); x86_init.mpparse.setup_ioapic_ids();
sync_Arb_IDs(); sync_Arb_IDs();
...@@ -2417,16 +2298,14 @@ void __init setup_IO_APIC(void) ...@@ -2417,16 +2298,14 @@ void __init setup_IO_APIC(void)
static void resume_ioapic_id(int ioapic_idx) static void resume_ioapic_id(int ioapic_idx)
{ {
unsigned long flags;
union IO_APIC_reg_00 reg_00; union IO_APIC_reg_00 reg_00;
raw_spin_lock_irqsave(&ioapic_lock, flags); guard(raw_spinlock_irqsave)(&ioapic_lock);
reg_00.raw = io_apic_read(ioapic_idx, 0); reg_00.raw = io_apic_read(ioapic_idx, 0);
if (reg_00.bits.ID != mpc_ioapic_id(ioapic_idx)) { if (reg_00.bits.ID != mpc_ioapic_id(ioapic_idx)) {
reg_00.bits.ID = mpc_ioapic_id(ioapic_idx); reg_00.bits.ID = mpc_ioapic_id(ioapic_idx);
io_apic_write(ioapic_idx, 0, reg_00.raw); io_apic_write(ioapic_idx, 0, reg_00.raw);
} }
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
} }
static void ioapic_resume(void) static void ioapic_resume(void)
...@@ -2456,15 +2335,13 @@ device_initcall(ioapic_init_ops); ...@@ -2456,15 +2335,13 @@ device_initcall(ioapic_init_ops);
static int io_apic_get_redir_entries(int ioapic) static int io_apic_get_redir_entries(int ioapic)
{ {
union IO_APIC_reg_01 reg_01; union IO_APIC_reg_01 reg_01;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags); guard(raw_spinlock_irqsave)(&ioapic_lock);
reg_01.raw = io_apic_read(ioapic, 1); reg_01.raw = io_apic_read(ioapic, 1);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
/* The register returns the maximum index redir index /*
* supported, which is one less than the total number of redir * The register returns the maximum index redir index supported,
* entries. * which is one less than the total number of redir entries.
*/ */
return reg_01.bits.entries + 1; return reg_01.bits.entries + 1;
} }
...@@ -2494,16 +2371,14 @@ static int io_apic_get_unique_id(int ioapic, int apic_id) ...@@ -2494,16 +2371,14 @@ static int io_apic_get_unique_id(int ioapic, int apic_id)
static DECLARE_BITMAP(apic_id_map, MAX_LOCAL_APIC); static DECLARE_BITMAP(apic_id_map, MAX_LOCAL_APIC);
const u32 broadcast_id = 0xF; const u32 broadcast_id = 0xF;
union IO_APIC_reg_00 reg_00; union IO_APIC_reg_00 reg_00;
unsigned long flags;
int i = 0; int i = 0;
/* Initialize the ID map */ /* Initialize the ID map */
if (bitmap_empty(apic_id_map, MAX_LOCAL_APIC)) if (bitmap_empty(apic_id_map, MAX_LOCAL_APIC))
copy_phys_cpu_present_map(apic_id_map); copy_phys_cpu_present_map(apic_id_map);
raw_spin_lock_irqsave(&ioapic_lock, flags); scoped_guard (raw_spinlock_irqsave, &ioapic_lock)
reg_00.raw = io_apic_read(ioapic, 0); reg_00.raw = io_apic_read(ioapic, 0);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
if (apic_id >= broadcast_id) { if (apic_id >= broadcast_id) {
pr_warn("IOAPIC[%d]: Invalid apic_id %d, trying %d\n", pr_warn("IOAPIC[%d]: Invalid apic_id %d, trying %d\n",
...@@ -2530,21 +2405,19 @@ static int io_apic_get_unique_id(int ioapic, int apic_id) ...@@ -2530,21 +2405,19 @@ static int io_apic_get_unique_id(int ioapic, int apic_id)
if (reg_00.bits.ID != apic_id) { if (reg_00.bits.ID != apic_id) {
reg_00.bits.ID = apic_id; reg_00.bits.ID = apic_id;
raw_spin_lock_irqsave(&ioapic_lock, flags); scoped_guard (raw_spinlock_irqsave, &ioapic_lock) {
io_apic_write(ioapic, 0, reg_00.raw); io_apic_write(ioapic, 0, reg_00.raw);
reg_00.raw = io_apic_read(ioapic, 0); reg_00.raw = io_apic_read(ioapic, 0);
raw_spin_unlock_irqrestore(&ioapic_lock, flags); }
/* Sanity check */ /* Sanity check */
if (reg_00.bits.ID != apic_id) { if (reg_00.bits.ID != apic_id) {
pr_err("IOAPIC[%d]: Unable to change apic_id!\n", pr_err("IOAPIC[%d]: Unable to change apic_id!\n", ioapic);
ioapic);
return -1; return -1;
} }
} }
apic_printk(APIC_VERBOSE, KERN_INFO apic_pr_verbose("IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id);
"IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id);
return apic_id; return apic_id;
} }
...@@ -2560,7 +2433,6 @@ static u8 io_apic_unique_id(int idx, u8 id) ...@@ -2560,7 +2433,6 @@ static u8 io_apic_unique_id(int idx, u8 id)
{ {
union IO_APIC_reg_00 reg_00; union IO_APIC_reg_00 reg_00;
DECLARE_BITMAP(used, 256); DECLARE_BITMAP(used, 256);
unsigned long flags;
u8 new_id; u8 new_id;
int i; int i;
...@@ -2576,26 +2448,23 @@ static u8 io_apic_unique_id(int idx, u8 id) ...@@ -2576,26 +2448,23 @@ static u8 io_apic_unique_id(int idx, u8 id)
* Read the current id from the ioapic and keep it if * Read the current id from the ioapic and keep it if
* available. * available.
*/ */
raw_spin_lock_irqsave(&ioapic_lock, flags); scoped_guard (raw_spinlock_irqsave, &ioapic_lock)
reg_00.raw = io_apic_read(idx, 0); reg_00.raw = io_apic_read(idx, 0);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
new_id = reg_00.bits.ID; new_id = reg_00.bits.ID;
if (!test_bit(new_id, used)) { if (!test_bit(new_id, used)) {
apic_printk(APIC_VERBOSE, KERN_INFO apic_pr_verbose("IOAPIC[%d]: Using reg apic_id %d instead of %d\n",
"IOAPIC[%d]: Using reg apic_id %d instead of %d\n",
idx, new_id, id); idx, new_id, id);
return new_id; return new_id;
} }
/* /* Get the next free id and write it to the ioapic. */
* Get the next free id and write it to the ioapic.
*/
new_id = find_first_zero_bit(used, 256); new_id = find_first_zero_bit(used, 256);
reg_00.bits.ID = new_id; reg_00.bits.ID = new_id;
raw_spin_lock_irqsave(&ioapic_lock, flags); scoped_guard (raw_spinlock_irqsave, &ioapic_lock) {
io_apic_write(idx, 0, reg_00.raw); io_apic_write(idx, 0, reg_00.raw);
reg_00.raw = io_apic_read(idx, 0); reg_00.raw = io_apic_read(idx, 0);
raw_spin_unlock_irqrestore(&ioapic_lock, flags); }
/* Sanity check */ /* Sanity check */
BUG_ON(reg_00.bits.ID != new_id); BUG_ON(reg_00.bits.ID != new_id);
...@@ -2606,11 +2475,9 @@ static u8 io_apic_unique_id(int idx, u8 id) ...@@ -2606,11 +2475,9 @@ static u8 io_apic_unique_id(int idx, u8 id)
static int io_apic_get_version(int ioapic) static int io_apic_get_version(int ioapic)
{ {
union IO_APIC_reg_01 reg_01; union IO_APIC_reg_01 reg_01;
unsigned long flags;
raw_spin_lock_irqsave(&ioapic_lock, flags); guard(raw_spinlock_irqsave)(&ioapic_lock);
reg_01.raw = io_apic_read(ioapic, 1); reg_01.raw = io_apic_read(ioapic, 1);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
return reg_01.bits.version; return reg_01.bits.version;
} }
...@@ -2625,8 +2492,8 @@ static struct resource *ioapic_resources; ...@@ -2625,8 +2492,8 @@ static struct resource *ioapic_resources;
static struct resource * __init ioapic_setup_resources(void) static struct resource * __init ioapic_setup_resources(void)
{ {
unsigned long n;
struct resource *res; struct resource *res;
unsigned long n;
char *mem; char *mem;
int i; int i;
...@@ -2686,9 +2553,7 @@ void __init io_apic_init_mappings(void) ...@@ -2686,9 +2553,7 @@ void __init io_apic_init_mappings(void)
ioapic_phys = mpc_ioapic_addr(i); ioapic_phys = mpc_ioapic_addr(i);
#ifdef CONFIG_X86_32 #ifdef CONFIG_X86_32
if (!ioapic_phys) { if (!ioapic_phys) {
printk(KERN_ERR pr_err("WARNING: bogus zero IO-APIC address found in MPTABLE, "
"WARNING: bogus zero IO-APIC "
"address found in MPTABLE, "
"disabling IO/APIC support!\n"); "disabling IO/APIC support!\n");
smp_found_config = 0; smp_found_config = 0;
ioapic_is_disabled = true; ioapic_is_disabled = true;
...@@ -2707,9 +2572,8 @@ void __init io_apic_init_mappings(void) ...@@ -2707,9 +2572,8 @@ void __init io_apic_init_mappings(void)
ioapic_phys = __pa(ioapic_phys); ioapic_phys = __pa(ioapic_phys);
} }
io_apic_set_fixmap(idx, ioapic_phys); io_apic_set_fixmap(idx, ioapic_phys);
apic_printk(APIC_VERBOSE, "mapped IOAPIC to %08lx (%08lx)\n", apic_pr_verbose("mapped IOAPIC to %08lx (%08lx)\n",
__fix_to_virt(idx) + (ioapic_phys & ~PAGE_MASK), __fix_to_virt(idx) + (ioapic_phys & ~PAGE_MASK), ioapic_phys);
ioapic_phys);
idx++; idx++;
ioapic_res->start = ioapic_phys; ioapic_res->start = ioapic_phys;
...@@ -2720,13 +2584,12 @@ void __init io_apic_init_mappings(void) ...@@ -2720,13 +2584,12 @@ void __init io_apic_init_mappings(void)
void __init ioapic_insert_resources(void) void __init ioapic_insert_resources(void)
{ {
int i;
struct resource *r = ioapic_resources; struct resource *r = ioapic_resources;
int i;
if (!r) { if (!r) {
if (nr_ioapics > 0) if (nr_ioapics > 0)
printk(KERN_ERR pr_err("IO APIC resources couldn't be allocated.\n");
"IO APIC resources couldn't be allocated.\n");
return; return;
} }
...@@ -2746,11 +2609,12 @@ int mp_find_ioapic(u32 gsi) ...@@ -2746,11 +2609,12 @@ int mp_find_ioapic(u32 gsi)
/* Find the IOAPIC that manages this GSI. */ /* Find the IOAPIC that manages this GSI. */
for_each_ioapic(i) { for_each_ioapic(i) {
struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(i); struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(i);
if (gsi >= gsi_cfg->gsi_base && gsi <= gsi_cfg->gsi_end) if (gsi >= gsi_cfg->gsi_base && gsi <= gsi_cfg->gsi_end)
return i; return i;
} }
printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi); pr_err("ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
return -1; return -1;
} }
...@@ -2789,12 +2653,10 @@ static int bad_ioapic_register(int idx) ...@@ -2789,12 +2653,10 @@ static int bad_ioapic_register(int idx)
static int find_free_ioapic_entry(void) static int find_free_ioapic_entry(void)
{ {
int idx; for (int idx = 0; idx < MAX_IO_APICS; idx++) {
for (idx = 0; idx < MAX_IO_APICS; idx++)
if (ioapics[idx].nr_registers == 0) if (ioapics[idx].nr_registers == 0)
return idx; return idx;
}
return MAX_IO_APICS; return MAX_IO_APICS;
} }
...@@ -2805,8 +2667,7 @@ static int find_free_ioapic_entry(void) ...@@ -2805,8 +2667,7 @@ static int find_free_ioapic_entry(void)
* @gsi_base: base of GSI associated with the IOAPIC * @gsi_base: base of GSI associated with the IOAPIC
* @cfg: configuration information for the IOAPIC * @cfg: configuration information for the IOAPIC
*/ */
int mp_register_ioapic(int id, u32 address, u32 gsi_base, int mp_register_ioapic(int id, u32 address, u32 gsi_base, struct ioapic_domain_cfg *cfg)
struct ioapic_domain_cfg *cfg)
{ {
bool hotplug = !!ioapic_initialized; bool hotplug = !!ioapic_initialized;
struct mp_ioapic_gsi *gsi_cfg; struct mp_ioapic_gsi *gsi_cfg;
...@@ -2817,12 +2678,13 @@ int mp_register_ioapic(int id, u32 address, u32 gsi_base, ...@@ -2817,12 +2678,13 @@ int mp_register_ioapic(int id, u32 address, u32 gsi_base,
pr_warn("Bogus (zero) I/O APIC address found, skipping!\n"); pr_warn("Bogus (zero) I/O APIC address found, skipping!\n");
return -EINVAL; return -EINVAL;
} }
for_each_ioapic(ioapic)
for_each_ioapic(ioapic) {
if (ioapics[ioapic].mp_config.apicaddr == address) { if (ioapics[ioapic].mp_config.apicaddr == address) {
pr_warn("address 0x%x conflicts with IOAPIC%d\n", pr_warn("address 0x%x conflicts with IOAPIC%d\n", address, ioapic);
address, ioapic);
return -EEXIST; return -EEXIST;
} }
}
idx = find_free_ioapic_entry(); idx = find_free_ioapic_entry();
if (idx >= MAX_IO_APICS) { if (idx >= MAX_IO_APICS) {
...@@ -2857,8 +2719,7 @@ int mp_register_ioapic(int id, u32 address, u32 gsi_base, ...@@ -2857,8 +2719,7 @@ int mp_register_ioapic(int id, u32 address, u32 gsi_base,
(gsi_end >= gsi_cfg->gsi_base && (gsi_end >= gsi_cfg->gsi_base &&
gsi_end <= gsi_cfg->gsi_end)) { gsi_end <= gsi_cfg->gsi_end)) {
pr_warn("GSI range [%u-%u] for new IOAPIC conflicts with GSI[%u-%u]\n", pr_warn("GSI range [%u-%u] for new IOAPIC conflicts with GSI[%u-%u]\n",
gsi_base, gsi_end, gsi_base, gsi_end, gsi_cfg->gsi_base, gsi_cfg->gsi_end);
gsi_cfg->gsi_base, gsi_cfg->gsi_end);
clear_fixmap(FIX_IO_APIC_BASE_0 + idx); clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
return -ENOSPC; return -ENOSPC;
} }
...@@ -2892,8 +2753,7 @@ int mp_register_ioapic(int id, u32 address, u32 gsi_base, ...@@ -2892,8 +2753,7 @@ int mp_register_ioapic(int id, u32 address, u32 gsi_base,
ioapics[idx].nr_registers = entries; ioapics[idx].nr_registers = entries;
pr_info("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, GSI %d-%d\n", pr_info("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, GSI %d-%d\n",
idx, mpc_ioapic_id(idx), idx, mpc_ioapic_id(idx), mpc_ioapic_ver(idx), mpc_ioapic_addr(idx),
mpc_ioapic_ver(idx), mpc_ioapic_addr(idx),
gsi_cfg->gsi_base, gsi_cfg->gsi_end); gsi_cfg->gsi_base, gsi_cfg->gsi_end);
return 0; return 0;
...@@ -2904,11 +2764,13 @@ int mp_unregister_ioapic(u32 gsi_base) ...@@ -2904,11 +2764,13 @@ int mp_unregister_ioapic(u32 gsi_base)
int ioapic, pin; int ioapic, pin;
int found = 0; int found = 0;
for_each_ioapic(ioapic) for_each_ioapic(ioapic) {
if (ioapics[ioapic].gsi_config.gsi_base == gsi_base) { if (ioapics[ioapic].gsi_config.gsi_base == gsi_base) {
found = 1; found = 1;
break; break;
} }
}
if (!found) { if (!found) {
pr_warn("can't find IOAPIC for GSI %d\n", gsi_base); pr_warn("can't find IOAPIC for GSI %d\n", gsi_base);
return -ENODEV; return -ENODEV;
...@@ -2922,8 +2784,7 @@ int mp_unregister_ioapic(u32 gsi_base) ...@@ -2922,8 +2784,7 @@ int mp_unregister_ioapic(u32 gsi_base)
if (irq >= 0) { if (irq >= 0) {
data = irq_get_chip_data(irq); data = irq_get_chip_data(irq);
if (data && data->count) { if (data && data->count) {
pr_warn("pin%d on IOAPIC%d is still in use.\n", pr_warn("pin%d on IOAPIC%d is still in use.\n", pin, ioapic);
pin, ioapic);
return -EBUSY; return -EBUSY;
} }
} }
...@@ -2958,8 +2819,7 @@ static void mp_irqdomain_get_attr(u32 gsi, struct mp_chip_data *data, ...@@ -2958,8 +2819,7 @@ static void mp_irqdomain_get_attr(u32 gsi, struct mp_chip_data *data,
if (info && info->ioapic.valid) { if (info && info->ioapic.valid) {
data->is_level = info->ioapic.is_level; data->is_level = info->ioapic.is_level;
data->active_low = info->ioapic.active_low; data->active_low = info->ioapic.active_low;
} else if (__acpi_get_override_irq(gsi, &data->is_level, } else if (__acpi_get_override_irq(gsi, &data->is_level, &data->active_low) < 0) {
&data->active_low) < 0) {
/* PCI interrupts are always active low level triggered. */ /* PCI interrupts are always active low level triggered. */
data->is_level = true; data->is_level = true;
data->active_low = true; data->active_low = true;
...@@ -3017,10 +2877,8 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, ...@@ -3017,10 +2877,8 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
return -ENOMEM; return -ENOMEM;
ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info); ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
if (ret < 0) { if (ret < 0)
kfree(data); goto free_data;
return ret;
}
INIT_LIST_HEAD(&data->irq_2_pin); INIT_LIST_HEAD(&data->irq_2_pin);
irq_data->hwirq = info->ioapic.pin; irq_data->hwirq = info->ioapic.pin;
...@@ -3029,7 +2887,10 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, ...@@ -3029,7 +2887,10 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
irq_data->chip_data = data; irq_data->chip_data = data;
mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info); mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info);
add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin); if (!add_pin_to_irq_node(data, ioapic_alloc_attr_node(info), ioapic, pin)) {
ret = -ENOMEM;
goto free_irqs;
}
mp_preconfigure_entry(data); mp_preconfigure_entry(data);
mp_register_handler(virq, data->is_level); mp_register_handler(virq, data->is_level);
...@@ -3039,11 +2900,15 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq, ...@@ -3039,11 +2900,15 @@ int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
legacy_pic->mask(virq); legacy_pic->mask(virq);
local_irq_restore(flags); local_irq_restore(flags);
apic_printk(APIC_VERBOSE, KERN_DEBUG apic_pr_verbose("IOAPIC[%d]: Preconfigured routing entry (%d-%d -> IRQ %d Level:%i ActiveLow:%i)\n",
"IOAPIC[%d]: Preconfigured routing entry (%d-%d -> IRQ %d Level:%i ActiveLow:%i)\n", ioapic, mpc_ioapic_id(ioapic), pin, virq, data->is_level, data->active_low);
ioapic, mpc_ioapic_id(ioapic), pin, virq,
data->is_level, data->active_low);
return 0; return 0;
free_irqs:
irq_domain_free_irqs_parent(domain, virq, nr_irqs);
free_data:
kfree(data);
return ret;
} }
void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq, void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
...@@ -3056,22 +2921,17 @@ void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq, ...@@ -3056,22 +2921,17 @@ void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
irq_data = irq_domain_get_irq_data(domain, virq); irq_data = irq_domain_get_irq_data(domain, virq);
if (irq_data && irq_data->chip_data) { if (irq_data && irq_data->chip_data) {
data = irq_data->chip_data; data = irq_data->chip_data;
__remove_pin_from_irq(data, mp_irqdomain_ioapic_idx(domain), __remove_pin_from_irq(data, mp_irqdomain_ioapic_idx(domain), (int)irq_data->hwirq);
(int)irq_data->hwirq);
WARN_ON(!list_empty(&data->irq_2_pin)); WARN_ON(!list_empty(&data->irq_2_pin));
kfree(irq_data->chip_data); kfree(irq_data->chip_data);
} }
irq_domain_free_irqs_top(domain, virq, nr_irqs); irq_domain_free_irqs_top(domain, virq, nr_irqs);
} }
int mp_irqdomain_activate(struct irq_domain *domain, int mp_irqdomain_activate(struct irq_domain *domain, struct irq_data *irq_data, bool reserve)
struct irq_data *irq_data, bool reserve)
{ {
unsigned long flags; guard(raw_spinlock_irqsave)(&ioapic_lock);
raw_spin_lock_irqsave(&ioapic_lock, flags);
ioapic_configure_entry(irq_data); ioapic_configure_entry(irq_data);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
return 0; return 0;
} }
...@@ -3079,8 +2939,7 @@ void mp_irqdomain_deactivate(struct irq_domain *domain, ...@@ -3079,8 +2939,7 @@ void mp_irqdomain_deactivate(struct irq_domain *domain,
struct irq_data *irq_data) struct irq_data *irq_data)
{ {
/* It won't be called for IRQ with multiple IOAPIC pins associated */ /* It won't be called for IRQ with multiple IOAPIC pins associated */
ioapic_mask_entry(mp_irqdomain_ioapic_idx(domain), ioapic_mask_entry(mp_irqdomain_ioapic_idx(domain), (int)irq_data->hwirq);
(int)irq_data->hwirq);
} }
int mp_irqdomain_ioapic_idx(struct irq_domain *domain) int mp_irqdomain_ioapic_idx(struct irq_domain *domain)
......
...@@ -68,7 +68,7 @@ static void __init mpc_oem_bus_info(struct mpc_bus *m, char *str) ...@@ -68,7 +68,7 @@ static void __init mpc_oem_bus_info(struct mpc_bus *m, char *str)
{ {
memcpy(str, m->bustype, 6); memcpy(str, m->bustype, 6);
str[6] = 0; str[6] = 0;
apic_printk(APIC_VERBOSE, "Bus #%d is %s\n", m->busid, str); apic_pr_verbose("Bus #%d is %s\n", m->busid, str);
} }
static void __init MP_bus_info(struct mpc_bus *m) static void __init MP_bus_info(struct mpc_bus *m)
...@@ -417,7 +417,7 @@ static unsigned long __init get_mpc_size(unsigned long physptr) ...@@ -417,7 +417,7 @@ static unsigned long __init get_mpc_size(unsigned long physptr)
mpc = early_memremap(physptr, PAGE_SIZE); mpc = early_memremap(physptr, PAGE_SIZE);
size = mpc->length; size = mpc->length;
early_memunmap(mpc, PAGE_SIZE); early_memunmap(mpc, PAGE_SIZE);
apic_printk(APIC_VERBOSE, " mpc: %lx-%lx\n", physptr, physptr + size); apic_pr_verbose(" mpc: %lx-%lx\n", physptr, physptr + size);
return size; return size;
} }
...@@ -560,8 +560,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length) ...@@ -560,8 +560,7 @@ static int __init smp_scan_config(unsigned long base, unsigned long length)
struct mpf_intel *mpf; struct mpf_intel *mpf;
int ret = 0; int ret = 0;
apic_printk(APIC_VERBOSE, "Scan for SMP in [mem %#010lx-%#010lx]\n", apic_pr_verbose("Scan for SMP in [mem %#010lx-%#010lx]\n", base, base + length - 1);
base, base + length - 1);
BUILD_BUG_ON(sizeof(*mpf) != 16); BUILD_BUG_ON(sizeof(*mpf) != 16);
while (length > 0) { while (length > 0) {
...@@ -683,13 +682,13 @@ static void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare) ...@@ -683,13 +682,13 @@ static void __init check_irq_src(struct mpc_intsrc *m, int *nr_m_spare)
{ {
int i; int i;
apic_printk(APIC_VERBOSE, "OLD "); apic_pr_verbose("OLD ");
print_mp_irq_info(m); print_mp_irq_info(m);
i = get_MP_intsrc_index(m); i = get_MP_intsrc_index(m);
if (i > 0) { if (i > 0) {
memcpy(m, &mp_irqs[i], sizeof(*m)); memcpy(m, &mp_irqs[i], sizeof(*m));
apic_printk(APIC_VERBOSE, "NEW "); apic_pr_verbose("NEW ");
print_mp_irq_info(&mp_irqs[i]); print_mp_irq_info(&mp_irqs[i]);
return; return;
} }
...@@ -772,7 +771,7 @@ static int __init replace_intsrc_all(struct mpc_table *mpc, ...@@ -772,7 +771,7 @@ static int __init replace_intsrc_all(struct mpc_table *mpc,
continue; continue;
if (nr_m_spare > 0) { if (nr_m_spare > 0) {
apic_printk(APIC_VERBOSE, "*NEW* found\n"); apic_pr_verbose("*NEW* found\n");
nr_m_spare--; nr_m_spare--;
memcpy(m_spare[nr_m_spare], &mp_irqs[i], sizeof(mp_irqs[i])); memcpy(m_spare[nr_m_spare], &mp_irqs[i], sizeof(mp_irqs[i]));
m_spare[nr_m_spare] = NULL; m_spare[nr_m_spare] = NULL;
......
...@@ -1352,12 +1352,11 @@ static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data, ...@@ -1352,12 +1352,11 @@ static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data,
case X86_IRQ_ALLOC_TYPE_IOAPIC: case X86_IRQ_ALLOC_TYPE_IOAPIC:
/* Set source-id of interrupt request */ /* Set source-id of interrupt request */
set_ioapic_sid(irte, info->devid); set_ioapic_sid(irte, info->devid);
apic_printk(APIC_VERBOSE, KERN_DEBUG "IOAPIC[%d]: Set IRTE entry (P:%d FPD:%d Dst_Mode:%d Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X Avail:%X Vector:%02X Dest:%08X SID:%04X SQ:%X SVT:%X)\n", apic_pr_verbose("IOAPIC[%d]: Set IRTE entry (P:%d FPD:%d Dst_Mode:%d Redir_hint:%d Trig_Mode:%d Dlvry_Mode:%X Avail:%X Vector:%02X Dest:%08X SID:%04X SQ:%X SVT:%X)\n",
info->devid, irte->present, irte->fpd, info->devid, irte->present, irte->fpd, irte->dst_mode,
irte->dst_mode, irte->redir_hint, irte->redir_hint, irte->trigger_mode, irte->dlvry_mode,
irte->trigger_mode, irte->dlvry_mode, irte->avail, irte->vector, irte->dest_id, irte->sid,
irte->avail, irte->vector, irte->dest_id, irte->sq, irte->svt);
irte->sid, irte->sq, irte->svt);
sub_handle = info->ioapic.pin; sub_handle = info->ioapic.pin;
break; break;
case X86_IRQ_ALLOC_TYPE_HPET: case X86_IRQ_ALLOC_TYPE_HPET:
......
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