mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 APIC updates from Thomas Gleixner:
"This update provides a major overhaul of the APIC initialization and
vector allocation code:
- Unification of the APIC and interrupt mode setup which was
scattered all over the place and was hard to follow. This also
distangles the timer setup from the APIC initialization which
brings a clear separation of functionality.
Great detective work from Dou Lyiang!
- Refactoring of the x86 vector allocation mechanism. The existing
code was based on nested loops and rather convoluted APIC callbacks
which had a horrible worst case behaviour and tried to serve all
different use cases in one go. This led to quite odd hacks when
supporting the new managed interupt facility for multiqueue devices
and made it more or less impossible to deal with the vector space
exhaustion which was a major roadblock for server hibernation.
Aside of that the code dealing with cpu hotplug and the system
vectors was disconnected from the actual vector management and
allocation code, which made it hard to follow and maintain.
Utilizing the new bitmap matrix allocator core mechanism, the new
allocator and management code consolidates the handling of system
vectors, legacy vectors, cpu hotplug mechanisms and the actual
allocation which needs to be aware of system and legacy vectors and
hotplug constraints into a single consistent entity.
This has one visible change: The support for multi CPU targets of
interrupts, which is only available on a certain subset of
CPUs/APIC variants has been removed in favour of single interrupt
targets. A proper analysis of the multi CPU target feature revealed
that there is no real advantage as the vast majority of interrupts
end up on the CPU with the lowest APIC id in the set of target CPUs
anyway. That change was agreed on by the relevant folks and allowed
to simplify the implementation significantly and to replace rather
fragile constructs like the vector cleanup IPI with straight
forward and solid code.
Furthermore this allowed to cleanly separate the allocation details
for legacy, normal and managed interrupts:
* Legacy interrupts are not longer wasting 16 vectors
unconditionally
* Managed interrupts have now a guaranteed vector reservation, but
the actual vector assignment happens when the interrupt is
requested. It's guaranteed not to fail.
* Normal interrupts no longer allocate vectors unconditionally
when the interrupt is set up (IO/APIC init or MSI(X) enable).
The mechanism has been switched to a best effort reservation
mode. The actual allocation happens when the interrupt is
requested. Contrary to managed interrupts the request can fail
due to vector space exhaustion, but drivers must handle a fail
of request_irq() anyway. When the interrupt is freed, the vector
is handed back as well.
This solves a long standing problem with large unconditional
vector allocations for a certain class of enterprise devices
which prevented server hibernation due to vector space
exhaustion when the unused allocated vectors had to be migrated
to CPU0 while unplugging all non boot CPUs.
The code has been equipped with trace points and detailed debugfs
information to aid analysis of the vector space"
* 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (60 commits)
x86/vector/msi: Select CONFIG_GENERIC_IRQ_RESERVATION_MODE
PCI/MSI: Set MSI_FLAG_MUST_REACTIVATE in core code
genirq: Add config option for reservation mode
x86/vector: Use correct per cpu variable in free_moved_vector()
x86/apic/vector: Ignore set_affinity call for inactive interrupts
x86/apic: Fix spelling mistake: "symmectic" -> "symmetric"
x86/apic: Use dead_cpu instead of current CPU when cleaning up
ACPI/init: Invoke early ACPI initialization earlier
x86/vector: Respect affinity mask in irq descriptor
x86/irq: Simplify hotplug vector accounting
x86/vector: Switch IOAPIC to global reservation mode
x86/vector/msi: Switch to global reservation mode
x86/vector: Handle managed interrupts proper
x86/io_apic: Reevaluate vector configuration on activate()
iommu/amd: Reevaluate vector configuration on activate()
iommu/vt-d: Reevaluate vector configuration on activate()
x86/apic/msi: Force reactivation of interrupts at startup time
x86/vector: Untangle internal state from irq_cfg
x86/vector: Compile SMP only code conditionally
x86/apic: Remove unused callbacks
...
This commit is contained in:
commit
b18d62891a
43 files changed
+1556
-1380
No files matched your search
@@ -93,8 +93,10 @@ config X86
|
||||
select GENERIC_FIND_FIRST_BIT
|
||||
select GENERIC_IOMAP
|
||||
select GENERIC_IRQ_EFFECTIVE_AFF_MASK if SMP
|
||||
select GENERIC_IRQ_MATRIX_ALLOCATOR if X86_LOCAL_APIC
|
||||
select GENERIC_IRQ_MIGRATION if SMP
|
||||
select GENERIC_IRQ_PROBE
|
||||
select GENERIC_IRQ_RESERVATION_MODE
|
||||
select GENERIC_IRQ_SHOW
|
||||
select GENERIC_PENDING_IRQ if SMP
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
|
||||
+78
-176
@@ -53,6 +53,15 @@ extern int local_apic_timer_c2_ok;
|
||||
extern int disable_apic;
|
||||
extern unsigned int lapic_timer_frequency;
|
||||
|
||||
extern enum apic_intr_mode_id apic_intr_mode;
|
||||
enum apic_intr_mode_id {
|
||||
APIC_PIC,
|
||||
APIC_VIRTUAL_WIRE,
|
||||
APIC_VIRTUAL_WIRE_NO_CONFIG,
|
||||
APIC_SYMMETRIC_IO,
|
||||
APIC_SYMMETRIC_IO_NO_ROUTING
|
||||
};
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
extern void __inquire_remote_apic(int apicid);
|
||||
#else /* CONFIG_SMP */
|
||||
@@ -127,14 +136,13 @@ extern void disconnect_bsp_APIC(int virt_wire_setup);
|
||||
extern void disable_local_APIC(void);
|
||||
extern void lapic_shutdown(void);
|
||||
extern void sync_Arb_IDs(void);
|
||||
extern void init_bsp_APIC(void);
|
||||
extern void apic_intr_mode_init(void);
|
||||
extern void setup_local_APIC(void);
|
||||
extern void init_apic_mappings(void);
|
||||
void register_lapic_address(unsigned long address);
|
||||
extern void setup_boot_APIC_clock(void);
|
||||
extern void setup_secondary_APIC_clock(void);
|
||||
extern void lapic_update_tsc_freq(void);
|
||||
extern int APIC_init_uniprocessor(void);
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
static inline int apic_force_enable(unsigned long addr)
|
||||
@@ -145,7 +153,7 @@ static inline int apic_force_enable(unsigned long addr)
|
||||
extern int apic_force_enable(unsigned long addr);
|
||||
#endif
|
||||
|
||||
extern int apic_bsp_setup(bool upmode);
|
||||
extern void apic_bsp_setup(bool upmode);
|
||||
extern void apic_ap_setup(void);
|
||||
|
||||
/*
|
||||
@@ -161,6 +169,10 @@ static inline int apic_is_clustered_box(void)
|
||||
#endif
|
||||
|
||||
extern int setup_APIC_eilvt(u8 lvt_off, u8 vector, u8 msg_type, u8 mask);
|
||||
extern void lapic_assign_system_vectors(void);
|
||||
extern void lapic_assign_legacy_vector(unsigned int isairq, bool replace);
|
||||
extern void lapic_online(void);
|
||||
extern void lapic_offline(void);
|
||||
|
||||
#else /* !CONFIG_X86_LOCAL_APIC */
|
||||
static inline void lapic_shutdown(void) { }
|
||||
@@ -170,6 +182,9 @@ static inline void disable_local_APIC(void) { }
|
||||
# define setup_boot_APIC_clock x86_init_noop
|
||||
# define setup_secondary_APIC_clock x86_init_noop
|
||||
static inline void lapic_update_tsc_freq(void) { }
|
||||
static inline void apic_intr_mode_init(void) { }
|
||||
static inline void lapic_assign_system_vectors(void) { }
|
||||
static inline void lapic_assign_legacy_vector(unsigned int i, bool r) { }
|
||||
#endif /* !CONFIG_X86_LOCAL_APIC */
|
||||
|
||||
#ifdef CONFIG_X86_X2APIC
|
||||
@@ -265,73 +280,63 @@ struct irq_data;
|
||||
* James Cleverdon.
|
||||
*/
|
||||
struct apic {
|
||||
char *name;
|
||||
/* Hotpath functions first */
|
||||
void (*eoi_write)(u32 reg, u32 v);
|
||||
void (*native_eoi_write)(u32 reg, u32 v);
|
||||
void (*write)(u32 reg, u32 v);
|
||||
u32 (*read)(u32 reg);
|
||||
|
||||
int (*probe)(void);
|
||||
int (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id);
|
||||
int (*apic_id_valid)(int apicid);
|
||||
int (*apic_id_registered)(void);
|
||||
/* IPI related functions */
|
||||
void (*wait_icr_idle)(void);
|
||||
u32 (*safe_wait_icr_idle)(void);
|
||||
|
||||
u32 irq_delivery_mode;
|
||||
u32 irq_dest_mode;
|
||||
void (*send_IPI)(int cpu, int vector);
|
||||
void (*send_IPI_mask)(const struct cpumask *mask, int vector);
|
||||
void (*send_IPI_mask_allbutself)(const struct cpumask *msk, int vec);
|
||||
void (*send_IPI_allbutself)(int vector);
|
||||
void (*send_IPI_all)(int vector);
|
||||
void (*send_IPI_self)(int vector);
|
||||
|
||||
const struct cpumask *(*target_cpus)(void);
|
||||
/* dest_logical is used by the IPI functions */
|
||||
u32 dest_logical;
|
||||
u32 disable_esr;
|
||||
u32 irq_delivery_mode;
|
||||
u32 irq_dest_mode;
|
||||
|
||||
int disable_esr;
|
||||
/* Functions and data related to vector allocation */
|
||||
void (*vector_allocation_domain)(int cpu, struct cpumask *retmask,
|
||||
const struct cpumask *mask);
|
||||
int (*cpu_mask_to_apicid)(const struct cpumask *cpumask,
|
||||
struct irq_data *irqdata,
|
||||
unsigned int *apicid);
|
||||
u32 (*calc_dest_apicid)(unsigned int cpu);
|
||||
|
||||
int dest_logical;
|
||||
unsigned long (*check_apicid_used)(physid_mask_t *map, int apicid);
|
||||
/* ICR related functions */
|
||||
u64 (*icr_read)(void);
|
||||
void (*icr_write)(u32 low, u32 high);
|
||||
|
||||
void (*vector_allocation_domain)(int cpu, struct cpumask *retmask,
|
||||
const struct cpumask *mask);
|
||||
void (*init_apic_ldr)(void);
|
||||
/* Probe, setup and smpboot functions */
|
||||
int (*probe)(void);
|
||||
int (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id);
|
||||
int (*apic_id_valid)(int apicid);
|
||||
int (*apic_id_registered)(void);
|
||||
|
||||
void (*ioapic_phys_id_map)(physid_mask_t *phys_map, physid_mask_t *retmap);
|
||||
bool (*check_apicid_used)(physid_mask_t *map, int apicid);
|
||||
void (*init_apic_ldr)(void);
|
||||
void (*ioapic_phys_id_map)(physid_mask_t *phys_map, physid_mask_t *retmap);
|
||||
void (*setup_apic_routing)(void);
|
||||
int (*cpu_present_to_apicid)(int mps_cpu);
|
||||
void (*apicid_to_cpu_present)(int phys_apicid, physid_mask_t *retmap);
|
||||
int (*check_phys_apicid_present)(int phys_apicid);
|
||||
int (*phys_pkg_id)(int cpuid_apic, int index_msb);
|
||||
|
||||
void (*setup_apic_routing)(void);
|
||||
int (*cpu_present_to_apicid)(int mps_cpu);
|
||||
void (*apicid_to_cpu_present)(int phys_apicid, physid_mask_t *retmap);
|
||||
int (*check_phys_apicid_present)(int phys_apicid);
|
||||
int (*phys_pkg_id)(int cpuid_apic, int index_msb);
|
||||
|
||||
unsigned int (*get_apic_id)(unsigned long x);
|
||||
/* Can't be NULL on 64-bit */
|
||||
unsigned long (*set_apic_id)(unsigned int id);
|
||||
|
||||
int (*cpu_mask_to_apicid)(const struct cpumask *cpumask,
|
||||
struct irq_data *irqdata,
|
||||
unsigned int *apicid);
|
||||
|
||||
/* ipi */
|
||||
void (*send_IPI)(int cpu, int vector);
|
||||
void (*send_IPI_mask)(const struct cpumask *mask, int vector);
|
||||
void (*send_IPI_mask_allbutself)(const struct cpumask *mask,
|
||||
int vector);
|
||||
void (*send_IPI_allbutself)(int vector);
|
||||
void (*send_IPI_all)(int vector);
|
||||
void (*send_IPI_self)(int vector);
|
||||
u32 (*get_apic_id)(unsigned long x);
|
||||
u32 (*set_apic_id)(unsigned int id);
|
||||
|
||||
/* wakeup_secondary_cpu */
|
||||
int (*wakeup_secondary_cpu)(int apicid, unsigned long start_eip);
|
||||
int (*wakeup_secondary_cpu)(int apicid, unsigned long start_eip);
|
||||
|
||||
void (*inquire_remote_apic)(int apicid);
|
||||
|
||||
/* apic ops */
|
||||
u32 (*read)(u32 reg);
|
||||
void (*write)(u32 reg, u32 v);
|
||||
/*
|
||||
* ->eoi_write() has the same signature as ->write().
|
||||
*
|
||||
* Drivers can support both ->eoi_write() and ->write() by passing the same
|
||||
* callback value. Kernel can override ->eoi_write() and fall back
|
||||
* on write for EOI.
|
||||
*/
|
||||
void (*eoi_write)(u32 reg, u32 v);
|
||||
void (*native_eoi_write)(u32 reg, u32 v);
|
||||
u64 (*icr_read)(void);
|
||||
void (*icr_write)(u32 low, u32 high);
|
||||
void (*wait_icr_idle)(void);
|
||||
u32 (*safe_wait_icr_idle)(void);
|
||||
void (*inquire_remote_apic)(int apicid);
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
/*
|
||||
@@ -346,6 +351,7 @@ struct apic {
|
||||
*/
|
||||
int (*x86_32_early_logical_apicid)(int cpu);
|
||||
#endif
|
||||
char *name;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -380,6 +386,7 @@ extern struct apic *__apicdrivers[], *__apicdrivers_end[];
|
||||
*/
|
||||
#ifdef CONFIG_SMP
|
||||
extern int wakeup_secondary_cpu_via_nmi(int apicid, unsigned long start_eip);
|
||||
extern int lapic_can_unplug_cpu(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
@@ -463,84 +470,33 @@ static inline unsigned default_get_apic_id(unsigned long x)
|
||||
extern void apic_send_IPI_self(int vector);
|
||||
|
||||
DECLARE_PER_CPU(int, x2apic_extra_bits);
|
||||
|
||||
extern int default_cpu_present_to_apicid(int mps_cpu);
|
||||
extern int default_check_phys_apicid_present(int phys_apicid);
|
||||
#endif
|
||||
|
||||
extern void generic_bigsmp_probe(void);
|
||||
|
||||
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
|
||||
#include <asm/smp.h>
|
||||
|
||||
#define APIC_DFR_VALUE (APIC_DFR_FLAT)
|
||||
|
||||
static inline const struct cpumask *default_target_cpus(void)
|
||||
{
|
||||
#ifdef CONFIG_SMP
|
||||
return cpu_online_mask;
|
||||
#else
|
||||
return cpumask_of(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline const struct cpumask *online_target_cpus(void)
|
||||
{
|
||||
return cpu_online_mask;
|
||||
}
|
||||
|
||||
DECLARE_EARLY_PER_CPU_READ_MOSTLY(u16, x86_bios_cpu_apicid);
|
||||
|
||||
extern struct apic apic_noop;
|
||||
|
||||
static inline unsigned int read_apic_id(void)
|
||||
{
|
||||
unsigned int reg;
|
||||
|
||||
reg = apic_read(APIC_ID);
|
||||
unsigned int reg = apic_read(APIC_ID);
|
||||
|
||||
return apic->get_apic_id(reg);
|
||||
}
|
||||
|
||||
static inline int default_apic_id_valid(int apicid)
|
||||
{
|
||||
return (apicid < 255);
|
||||
}
|
||||
|
||||
extern int default_apic_id_valid(int apicid);
|
||||
extern int default_acpi_madt_oem_check(char *, char *);
|
||||
|
||||
extern void default_setup_apic_routing(void);
|
||||
|
||||
extern struct apic apic_noop;
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
|
||||
static inline int noop_x86_32_early_logical_apicid(int cpu)
|
||||
{
|
||||
return BAD_APICID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the logical destination ID.
|
||||
*
|
||||
* Intel recommends to set DFR, LDR and TPR before enabling
|
||||
* an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
|
||||
* document number 292116). So here it goes...
|
||||
*/
|
||||
extern void default_init_apic_ldr(void);
|
||||
|
||||
static inline int default_apic_id_registered(void)
|
||||
{
|
||||
return physid_isset(read_apic_id(), phys_cpu_present_map);
|
||||
}
|
||||
|
||||
static inline int default_phys_pkg_id(int cpuid_apic, int index_msb)
|
||||
{
|
||||
return cpuid_apic >> index_msb;
|
||||
}
|
||||
|
||||
#endif
|
||||
extern u32 apic_default_calc_apicid(unsigned int cpu);
|
||||
extern u32 apic_flat_calc_apicid(unsigned int cpu);
|
||||
|
||||
extern int flat_cpu_mask_to_apicid(const struct cpumask *cpumask,
|
||||
struct irq_data *irqdata,
|
||||
@@ -548,71 +504,17 @@ extern int flat_cpu_mask_to_apicid(const struct cpumask *cpumask,
|
||||
extern int default_cpu_mask_to_apicid(const struct cpumask *cpumask,
|
||||
struct irq_data *irqdata,
|
||||
unsigned int *apicid);
|
||||
|
||||
static inline void
|
||||
flat_vector_allocation_domain(int cpu, struct cpumask *retmask,
|
||||
const struct cpumask *mask)
|
||||
{
|
||||
/* Careful. Some cpus do not strictly honor the set of cpus
|
||||
* specified in the interrupt destination when using lowest
|
||||
* priority interrupt delivery mode.
|
||||
*
|
||||
* In particular there was a hyperthreading cpu observed to
|
||||
* deliver interrupts to the wrong hyperthread when only one
|
||||
* hyperthread was specified in the interrupt desitination.
|
||||
*/
|
||||
cpumask_clear(retmask);
|
||||
cpumask_bits(retmask)[0] = APIC_ALL_CPUS;
|
||||
}
|
||||
|
||||
static inline void
|
||||
default_vector_allocation_domain(int cpu, struct cpumask *retmask,
|
||||
const struct cpumask *mask)
|
||||
{
|
||||
cpumask_copy(retmask, cpumask_of(cpu));
|
||||
}
|
||||
|
||||
static inline unsigned long default_check_apicid_used(physid_mask_t *map, int apicid)
|
||||
{
|
||||
return physid_isset(apicid, *map);
|
||||
}
|
||||
|
||||
static inline void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
|
||||
{
|
||||
*retmap = *phys_map;
|
||||
}
|
||||
|
||||
static inline int __default_cpu_present_to_apicid(int mps_cpu)
|
||||
{
|
||||
if (mps_cpu < nr_cpu_ids && cpu_present(mps_cpu))
|
||||
return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
|
||||
else
|
||||
return BAD_APICID;
|
||||
}
|
||||
|
||||
static inline int
|
||||
__default_check_phys_apicid_present(int phys_apicid)
|
||||
{
|
||||
return physid_isset(phys_apicid, phys_cpu_present_map);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
static inline int default_cpu_present_to_apicid(int mps_cpu)
|
||||
{
|
||||
return __default_cpu_present_to_apicid(mps_cpu);
|
||||
}
|
||||
|
||||
static inline int
|
||||
default_check_phys_apicid_present(int phys_apicid)
|
||||
{
|
||||
return __default_check_phys_apicid_present(phys_apicid);
|
||||
}
|
||||
#else
|
||||
extern bool default_check_apicid_used(physid_mask_t *map, int apicid);
|
||||
extern void flat_vector_allocation_domain(int cpu, struct cpumask *retmask,
|
||||
const struct cpumask *mask);
|
||||
extern void default_vector_allocation_domain(int cpu, struct cpumask *retmask,
|
||||
const struct cpumask *mask);
|
||||
extern void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap);
|
||||
extern int default_cpu_present_to_apicid(int mps_cpu);
|
||||
extern int default_check_phys_apicid_present(int phys_apicid);
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_X86_LOCAL_APIC */
|
||||
|
||||
extern void irq_enter(void);
|
||||
extern void irq_exit(void);
|
||||
|
||||
|
||||
@@ -393,7 +393,7 @@ static inline void set_desc_limit(struct desc_struct *desc, unsigned long limit)
|
||||
void update_intr_gate(unsigned int n, const void *addr);
|
||||
void alloc_intr_gate(unsigned int n, const void *addr);
|
||||
|
||||
extern unsigned long used_vectors[];
|
||||
extern unsigned long system_vectors[];
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
DECLARE_PER_CPU(u32, debug_idt_ctr);
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
#include <asm/irq_vectors.h>
|
||||
|
||||
#define IRQ_MATRIX_BITS NR_VECTORS
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/percpu.h>
|
||||
@@ -123,15 +125,13 @@ struct irq_alloc_info {
|
||||
|
||||
struct irq_cfg {
|
||||
unsigned int dest_apicid;
|
||||
u8 vector;
|
||||
u8 old_vector;
|
||||
unsigned int vector;
|
||||
};
|
||||
|
||||
extern struct irq_cfg *irq_cfg(unsigned int irq);
|
||||
extern struct irq_cfg *irqd_cfg(struct irq_data *irq_data);
|
||||
extern void lock_vector_lock(void);
|
||||
extern void unlock_vector_lock(void);
|
||||
extern void setup_vector_irq(int cpu);
|
||||
#ifdef CONFIG_SMP
|
||||
extern void send_cleanup_vector(struct irq_cfg *);
|
||||
extern void irq_complete_move(struct irq_cfg *cfg);
|
||||
|
||||
@@ -193,7 +193,6 @@ static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
|
||||
extern void setup_IO_APIC(void);
|
||||
extern void enable_IO_APIC(void);
|
||||
extern void disable_IO_APIC(void);
|
||||
extern void setup_ioapic_dest(void);
|
||||
extern int IO_APIC_get_PCI_irq_vector(int bus, int devfn, int pin);
|
||||
extern void print_IO_APICs(void);
|
||||
#else /* !CONFIG_X86_IO_APIC */
|
||||
@@ -233,7 +232,6 @@ static inline void io_apic_init_mappings(void) { }
|
||||
|
||||
static inline void setup_IO_APIC(void) { }
|
||||
static inline void enable_IO_APIC(void) { }
|
||||
static inline void setup_ioapic_dest(void) { }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -26,11 +26,7 @@ extern void irq_ctx_init(int cpu);
|
||||
|
||||
struct irq_desc;
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
#include <linux/cpumask.h>
|
||||
extern int check_irq_vectors_for_cpu_disable(void);
|
||||
extern void fixup_irqs(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HAVE_KVM
|
||||
extern void kvm_set_posted_intr_wakeup_handler(void (*handler)(void));
|
||||
|
||||
@@ -102,12 +102,8 @@
|
||||
#define POSTED_INTR_NESTED_VECTOR 0xf0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Local APIC timer IRQ vector is on a different priority level,
|
||||
* to work around the 'lost local interrupt if more than 2 IRQ
|
||||
* sources per level' errata.
|
||||
*/
|
||||
#define LOCAL_TIMER_VECTOR 0xef
|
||||
#define MANAGED_IRQ_SHUTDOWN_VECTOR 0xef
|
||||
#define LOCAL_TIMER_VECTOR 0xee
|
||||
|
||||
#define NR_VECTORS 256
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
enum {
|
||||
/* Allocate contiguous CPU vectors */
|
||||
X86_IRQ_ALLOC_CONTIGUOUS_VECTORS = 0x1,
|
||||
X86_IRQ_ALLOC_LEGACY = 0x2,
|
||||
};
|
||||
|
||||
extern struct irq_domain *x86_vector_domain;
|
||||
|
||||
@@ -1419,7 +1419,7 @@ static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {}
|
||||
static inline int kvm_cpu_get_apicid(int mps_cpu)
|
||||
{
|
||||
#ifdef CONFIG_X86_LOCAL_APIC
|
||||
return __default_cpu_present_to_apicid(mps_cpu);
|
||||
return default_cpu_present_to_apicid(mps_cpu);
|
||||
#else
|
||||
WARN_ON_ONCE(1);
|
||||
return BAD_APICID;
|
||||
|
||||
@@ -138,6 +138,254 @@ DEFINE_IRQ_VECTOR_EVENT(deferred_error_apic);
|
||||
DEFINE_IRQ_VECTOR_EVENT(thermal_apic);
|
||||
#endif
|
||||
|
||||
TRACE_EVENT(vector_config,
|
||||
|
||||
TP_PROTO(unsigned int irq, unsigned int vector,
|
||||
unsigned int cpu, unsigned int apicdest),
|
||||
|
||||
TP_ARGS(irq, vector, cpu, apicdest),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, irq )
|
||||
__field( unsigned int, vector )
|
||||
__field( unsigned int, cpu )
|
||||
__field( unsigned int, apicdest )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->irq = irq;
|
||||
__entry->vector = vector;
|
||||
__entry->cpu = cpu;
|
||||
__entry->apicdest = apicdest;
|
||||
),
|
||||
|
||||
TP_printk("irq=%u vector=%u cpu=%u apicdest=0x%08x",
|
||||
__entry->irq, __entry->vector, __entry->cpu,
|
||||
__entry->apicdest)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(vector_mod,
|
||||
|
||||
TP_PROTO(unsigned int irq, unsigned int vector,
|
||||
unsigned int cpu, unsigned int prev_vector,
|
||||
unsigned int prev_cpu),
|
||||
|
||||
TP_ARGS(irq, vector, cpu, prev_vector, prev_cpu),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, irq )
|
||||
__field( unsigned int, vector )
|
||||
__field( unsigned int, cpu )
|
||||
__field( unsigned int, prev_vector )
|
||||
__field( unsigned int, prev_cpu )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->irq = irq;
|
||||
__entry->vector = vector;
|
||||
__entry->cpu = cpu;
|
||||
__entry->prev_vector = prev_vector;
|
||||
__entry->prev_cpu = prev_cpu;
|
||||
|
||||
),
|
||||
|
||||
TP_printk("irq=%u vector=%u cpu=%u prev_vector=%u prev_cpu=%u",
|
||||
__entry->irq, __entry->vector, __entry->cpu,
|
||||
__entry->prev_vector, __entry->prev_cpu)
|
||||
);
|
||||
|
||||
#define DEFINE_IRQ_VECTOR_MOD_EVENT(name) \
|
||||
DEFINE_EVENT_FN(vector_mod, name, \
|
||||
TP_PROTO(unsigned int irq, unsigned int vector, \
|
||||
unsigned int cpu, unsigned int prev_vector, \
|
||||
unsigned int prev_cpu), \
|
||||
TP_ARGS(irq, vector, cpu, prev_vector, prev_cpu), NULL, NULL); \
|
||||
|
||||
DEFINE_IRQ_VECTOR_MOD_EVENT(vector_update);
|
||||
DEFINE_IRQ_VECTOR_MOD_EVENT(vector_clear);
|
||||
|
||||
DECLARE_EVENT_CLASS(vector_reserve,
|
||||
|
||||
TP_PROTO(unsigned int irq, int ret),
|
||||
|
||||
TP_ARGS(irq, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, irq )
|
||||
__field( int, ret )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->irq = irq;
|
||||
__entry->ret = ret;
|
||||
),
|
||||
|
||||
TP_printk("irq=%u ret=%d", __entry->irq, __entry->ret)
|
||||
);
|
||||
|
||||
#define DEFINE_IRQ_VECTOR_RESERVE_EVENT(name) \
|
||||
DEFINE_EVENT_FN(vector_reserve, name, \
|
||||
TP_PROTO(unsigned int irq, int ret), \
|
||||
TP_ARGS(irq, ret), NULL, NULL); \
|
||||
|
||||
DEFINE_IRQ_VECTOR_RESERVE_EVENT(vector_reserve_managed);
|
||||
DEFINE_IRQ_VECTOR_RESERVE_EVENT(vector_reserve);
|
||||
|
||||
TRACE_EVENT(vector_alloc,
|
||||
|
||||
TP_PROTO(unsigned int irq, unsigned int vector, bool reserved,
|
||||
int ret),
|
||||
|
||||
TP_ARGS(irq, vector, ret, reserved),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, irq )
|
||||
__field( unsigned int, vector )
|
||||
__field( bool, reserved )
|
||||
__field( int, ret )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->irq = irq;
|
||||
__entry->vector = ret < 0 ? 0 : vector;
|
||||
__entry->reserved = reserved;
|
||||
__entry->ret = ret > 0 ? 0 : ret;
|
||||
),
|
||||
|
||||
TP_printk("irq=%u vector=%u reserved=%d ret=%d",
|
||||
__entry->irq, __entry->vector,
|
||||
__entry->reserved, __entry->ret)
|
||||
);
|
||||
|
||||
TRACE_EVENT(vector_alloc_managed,
|
||||
|
||||
TP_PROTO(unsigned int irq, unsigned int vector,
|
||||
int ret),
|
||||
|
||||
TP_ARGS(irq, vector, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, irq )
|
||||
__field( unsigned int, vector )
|
||||
__field( int, ret )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->irq = irq;
|
||||
__entry->vector = ret < 0 ? 0 : vector;
|
||||
__entry->ret = ret > 0 ? 0 : ret;
|
||||
),
|
||||
|
||||
TP_printk("irq=%u vector=%u ret=%d",
|
||||
__entry->irq, __entry->vector, __entry->ret)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(vector_activate,
|
||||
|
||||
TP_PROTO(unsigned int irq, bool is_managed, bool can_reserve,
|
||||
bool early),
|
||||
|
||||
TP_ARGS(irq, is_managed, can_reserve, early),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, irq )
|
||||
__field( bool, is_managed )
|
||||
__field( bool, can_reserve )
|
||||
__field( bool, early )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->irq = irq;
|
||||
__entry->is_managed = is_managed;
|
||||
__entry->can_reserve = can_reserve;
|
||||
__entry->early = early;
|
||||
),
|
||||
|
||||
TP_printk("irq=%u is_managed=%d can_reserve=%d early=%d",
|
||||
__entry->irq, __entry->is_managed, __entry->can_reserve,
|
||||
__entry->early)
|
||||
);
|
||||
|
||||
#define DEFINE_IRQ_VECTOR_ACTIVATE_EVENT(name) \
|
||||
DEFINE_EVENT_FN(vector_activate, name, \
|
||||
TP_PROTO(unsigned int irq, bool is_managed, \
|
||||
bool can_reserve, bool early), \
|
||||
TP_ARGS(irq, is_managed, can_reserve, early), NULL, NULL); \
|
||||
|
||||
DEFINE_IRQ_VECTOR_ACTIVATE_EVENT(vector_activate);
|
||||
DEFINE_IRQ_VECTOR_ACTIVATE_EVENT(vector_deactivate);
|
||||
|
||||
TRACE_EVENT(vector_teardown,
|
||||
|
||||
TP_PROTO(unsigned int irq, bool is_managed, bool has_reserved),
|
||||
|
||||
TP_ARGS(irq, is_managed, has_reserved),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, irq )
|
||||
__field( bool, is_managed )
|
||||
__field( bool, has_reserved )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->irq = irq;
|
||||
__entry->is_managed = is_managed;
|
||||
__entry->has_reserved = has_reserved;
|
||||
),
|
||||
|
||||
TP_printk("irq=%u is_managed=%d has_reserved=%d",
|
||||
__entry->irq, __entry->is_managed, __entry->has_reserved)
|
||||
);
|
||||
|
||||
TRACE_EVENT(vector_setup,
|
||||
|
||||
TP_PROTO(unsigned int irq, bool is_legacy, int ret),
|
||||
|
||||
TP_ARGS(irq, is_legacy, ret),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, irq )
|
||||
__field( bool, is_legacy )
|
||||
__field( int, ret )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->irq = irq;
|
||||
__entry->is_legacy = is_legacy;
|
||||
__entry->ret = ret;
|
||||
),
|
||||
|
||||
TP_printk("irq=%u is_legacy=%d ret=%d",
|
||||
__entry->irq, __entry->is_legacy, __entry->ret)
|
||||
);
|
||||
|
||||
TRACE_EVENT(vector_free_moved,
|
||||
|
||||
TP_PROTO(unsigned int irq, unsigned int cpu, unsigned int vector,
|
||||
bool is_managed),
|
||||
|
||||
TP_ARGS(irq, cpu, vector, is_managed),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned int, irq )
|
||||
__field( unsigned int, cpu )
|
||||
__field( unsigned int, vector )
|
||||
__field( bool, is_managed )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->irq = irq;
|
||||
__entry->cpu = cpu;
|
||||
__entry->vector = vector;
|
||||
__entry->is_managed = is_managed;
|
||||
),
|
||||
|
||||
TP_printk("irq=%u cpu=%u vector=%u is_managed=%d",
|
||||
__entry->irq, __entry->cpu, __entry->vector,
|
||||
__entry->is_managed)
|
||||
);
|
||||
|
||||
|
||||
#endif /* CONFIG_X86_LOCAL_APIC */
|
||||
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Common bits for X2APIC cluster/physical modes.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_X86_X2APIC_H
|
||||
#define _ASM_X86_X2APIC_H
|
||||
|
||||
#include <asm/apic.h>
|
||||
#include <asm/ipi.h>
|
||||
#include <linux/cpumask.h>
|
||||
|
||||
static int x2apic_apic_id_valid(int apicid)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int x2apic_apic_id_registered(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
__x2apic_send_IPI_dest(unsigned int apicid, int vector, unsigned int dest)
|
||||
{
|
||||
unsigned long cfg = __prepare_ICR(0, vector, dest);
|
||||
native_x2apic_icr_write(cfg, apicid);
|
||||
}
|
||||
|
||||
static unsigned int x2apic_get_apic_id(unsigned long id)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
static unsigned long x2apic_set_apic_id(unsigned int id)
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
static int x2apic_phys_pkg_id(int initial_apicid, int index_msb)
|
||||
{
|
||||
return initial_apicid >> index_msb;
|
||||
}
|
||||
|
||||
static void x2apic_send_IPI_self(int vector)
|
||||
{
|
||||
apic_write(APIC_SELF_IPI, vector);
|
||||
}
|
||||
|
||||
#endif /* _ASM_X86_X2APIC_H */
|
||||
@@ -51,11 +51,13 @@ struct x86_init_resources {
|
||||
* are set up.
|
||||
* @intr_init: interrupt init code
|
||||
* @trap_init: platform specific trap setup
|
||||
* @intr_mode_init: interrupt delivery mode setup
|
||||
*/
|
||||
struct x86_init_irqs {
|
||||
void (*pre_vector_init)(void);
|
||||
void (*intr_init)(void);
|
||||
void (*trap_init)(void);
|
||||
void (*intr_mode_init)(void);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# In particualr, smp_apic_timer_interrupt() is called in random places.
|
||||
KCOV_INSTRUMENT := n
|
||||
|
||||
obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_noop.o ipi.o vector.o
|
||||
obj-$(CONFIG_X86_LOCAL_APIC) += apic.o apic_common.o apic_noop.o ipi.o vector.o
|
||||
obj-y += hw_nmi.o
|
||||
|
||||
obj-$(CONFIG_X86_IO_APIC) += io_apic.o
|
||||
|
||||
+100
-141
@@ -211,11 +211,7 @@ static inline int lapic_get_version(void)
|
||||
*/
|
||||
static inline int lapic_is_integrated(void)
|
||||
{
|
||||
#ifdef CONFIG_X86_64
|
||||
return 1;
|
||||
#else
|
||||
return APIC_INTEGRATED(lapic_get_version());
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -298,14 +294,11 @@ int get_physical_broadcast(void)
|
||||
*/
|
||||
int lapic_get_maxlvt(void)
|
||||
{
|
||||
unsigned int v;
|
||||
|
||||
v = apic_read(APIC_LVR);
|
||||
/*
|
||||
* - we always have APIC integrated on 64bit mode
|
||||
* - 82489DXs do not report # of LVT entries
|
||||
*/
|
||||
return APIC_INTEGRATED(GET_APIC_VERSION(v)) ? GET_APIC_MAXLVT(v) : 2;
|
||||
return lapic_is_integrated() ? GET_APIC_MAXLVT(apic_read(APIC_LVR)) : 2;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1229,53 +1222,100 @@ void __init sync_Arb_IDs(void)
|
||||
APIC_INT_LEVELTRIG | APIC_DM_INIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* An initial setup of the virtual wire mode.
|
||||
*/
|
||||
void __init init_bsp_APIC(void)
|
||||
enum apic_intr_mode_id apic_intr_mode;
|
||||
|
||||
static int __init apic_intr_mode_select(void)
|
||||
{
|
||||
unsigned int value;
|
||||
/* Check kernel option */
|
||||
if (disable_apic) {
|
||||
pr_info("APIC disabled via kernel command line\n");
|
||||
return APIC_PIC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't do the setup now if we have a SMP BIOS as the
|
||||
* through-I/O-APIC virtual wire mode might be active.
|
||||
*/
|
||||
if (smp_found_config || !boot_cpu_has(X86_FEATURE_APIC))
|
||||
return;
|
||||
/* Check BIOS */
|
||||
#ifdef CONFIG_X86_64
|
||||
/* On 64-bit, the APIC must be integrated, Check local APIC only */
|
||||
if (!boot_cpu_has(X86_FEATURE_APIC)) {
|
||||
disable_apic = 1;
|
||||
pr_info("APIC disabled by BIOS\n");
|
||||
return APIC_PIC;
|
||||
}
|
||||
#else
|
||||
/* On 32-bit, the APIC may be integrated APIC or 82489DX */
|
||||
|
||||
/*
|
||||
* Do not trust the local APIC being empty at bootup.
|
||||
*/
|
||||
clear_local_APIC();
|
||||
/* Neither 82489DX nor integrated APIC ? */
|
||||
if (!boot_cpu_has(X86_FEATURE_APIC) && !smp_found_config) {
|
||||
disable_apic = 1;
|
||||
return APIC_PIC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable APIC.
|
||||
*/
|
||||
value = apic_read(APIC_SPIV);
|
||||
value &= ~APIC_VECTOR_MASK;
|
||||
value |= APIC_SPIV_APIC_ENABLED;
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
/* This bit is reserved on P4/Xeon and should be cleared */
|
||||
if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
|
||||
(boot_cpu_data.x86 == 15))
|
||||
value &= ~APIC_SPIV_FOCUS_DISABLED;
|
||||
else
|
||||
/* If the BIOS pretends there is an integrated APIC ? */
|
||||
if (!boot_cpu_has(X86_FEATURE_APIC) &&
|
||||
APIC_INTEGRATED(boot_cpu_apic_version)) {
|
||||
disable_apic = 1;
|
||||
pr_err(FW_BUG "Local APIC %d not detected, force emulation\n",
|
||||
boot_cpu_physical_apicid);
|
||||
return APIC_PIC;
|
||||
}
|
||||
#endif
|
||||
value |= APIC_SPIV_FOCUS_DISABLED;
|
||||
value |= SPURIOUS_APIC_VECTOR;
|
||||
apic_write(APIC_SPIV, value);
|
||||
|
||||
/*
|
||||
* Set up the virtual wire mode.
|
||||
*/
|
||||
apic_write(APIC_LVT0, APIC_DM_EXTINT);
|
||||
value = APIC_DM_NMI;
|
||||
if (!lapic_is_integrated()) /* 82489DX */
|
||||
value |= APIC_LVT_LEVEL_TRIGGER;
|
||||
if (apic_extnmi == APIC_EXTNMI_NONE)
|
||||
value |= APIC_LVT_MASKED;
|
||||
apic_write(APIC_LVT1, value);
|
||||
/* Check MP table or ACPI MADT configuration */
|
||||
if (!smp_found_config) {
|
||||
disable_ioapic_support();
|
||||
if (!acpi_lapic) {
|
||||
pr_info("APIC: ACPI MADT or MP tables are not detected\n");
|
||||
return APIC_VIRTUAL_WIRE_NO_CONFIG;
|
||||
}
|
||||
return APIC_VIRTUAL_WIRE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/* If SMP should be disabled, then really disable it! */
|
||||
if (!setup_max_cpus) {
|
||||
pr_info("APIC: SMP mode deactivated\n");
|
||||
return APIC_SYMMETRIC_IO_NO_ROUTING;
|
||||
}
|
||||
|
||||
if (read_apic_id() != boot_cpu_physical_apicid) {
|
||||
panic("Boot APIC ID in local APIC unexpected (%d vs %d)",
|
||||
read_apic_id(), boot_cpu_physical_apicid);
|
||||
/* Or can we switch back to PIC here? */
|
||||
}
|
||||
#endif
|
||||
|
||||
return APIC_SYMMETRIC_IO;
|
||||
}
|
||||
|
||||
/* Init the interrupt delivery mode for the BSP */
|
||||
void __init apic_intr_mode_init(void)
|
||||
{
|
||||
bool upmode = IS_ENABLED(CONFIG_UP_LATE_INIT);
|
||||
|
||||
apic_intr_mode = apic_intr_mode_select();
|
||||
|
||||
switch (apic_intr_mode) {
|
||||
case APIC_PIC:
|
||||
pr_info("APIC: Keep in PIC mode(8259)\n");
|
||||
return;
|
||||
case APIC_VIRTUAL_WIRE:
|
||||
pr_info("APIC: Switch to virtual wire mode setup\n");
|
||||
default_setup_apic_routing();
|
||||
break;
|
||||
case APIC_VIRTUAL_WIRE_NO_CONFIG:
|
||||
pr_info("APIC: Switch to virtual wire mode setup with no configuration\n");
|
||||
upmode = true;
|
||||
default_setup_apic_routing();
|
||||
break;
|
||||
case APIC_SYMMETRIC_IO:
|
||||
pr_info("APIC: Switch to symmetric I/O mode setup\n");
|
||||
default_setup_apic_routing();
|
||||
break;
|
||||
case APIC_SYMMETRIC_IO_NO_ROUTING:
|
||||
pr_info("APIC: Switch to symmetric I/O mode setup in no SMP routine\n");
|
||||
break;
|
||||
}
|
||||
|
||||
apic_bsp_setup(upmode);
|
||||
}
|
||||
|
||||
static void lapic_setup_esr(void)
|
||||
@@ -1499,7 +1539,9 @@ void setup_local_APIC(void)
|
||||
value = APIC_DM_NMI;
|
||||
else
|
||||
value = APIC_DM_NMI | APIC_LVT_MASKED;
|
||||
if (!lapic_is_integrated()) /* 82489DX */
|
||||
|
||||
/* Is 82489DX ? */
|
||||
if (!lapic_is_integrated())
|
||||
value |= APIC_LVT_LEVEL_TRIGGER;
|
||||
apic_write(APIC_LVT1, value);
|
||||
|
||||
@@ -1885,8 +1927,8 @@ void __init init_apic_mappings(void)
|
||||
* yeah -- we lie about apic_version
|
||||
* in case if apic was disabled via boot option
|
||||
* but it's not a problem for SMP compiled kernel
|
||||
* since smp_sanity_check is prepared for such a case
|
||||
* and disable smp mode
|
||||
* since apic_intr_mode_select is prepared for such
|
||||
* a case and disable smp mode
|
||||
*/
|
||||
boot_cpu_apic_version = GET_APIC_VERSION(apic_read(APIC_LVR));
|
||||
}
|
||||
@@ -2242,44 +2284,6 @@ int hard_smp_processor_id(void)
|
||||
return read_apic_id();
|
||||
}
|
||||
|
||||
void default_init_apic_ldr(void)
|
||||
{
|
||||
unsigned long val;
|
||||
|
||||
apic_write(APIC_DFR, APIC_DFR_VALUE);
|
||||
val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
|
||||
val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id());
|
||||
apic_write(APIC_LDR, val);
|
||||
}
|
||||
|
||||
int default_cpu_mask_to_apicid(const struct cpumask *mask,
|
||||
struct irq_data *irqdata,
|
||||
unsigned int *apicid)
|
||||
{
|
||||
unsigned int cpu = cpumask_first(mask);
|
||||
|
||||
if (cpu >= nr_cpu_ids)
|
||||
return -EINVAL;
|
||||
*apicid = per_cpu(x86_cpu_to_apicid, cpu);
|
||||
irq_data_update_effective_affinity(irqdata, cpumask_of(cpu));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flat_cpu_mask_to_apicid(const struct cpumask *mask,
|
||||
struct irq_data *irqdata,
|
||||
unsigned int *apicid)
|
||||
|
||||
{
|
||||
struct cpumask *effmsk = irq_data_get_effective_affinity_mask(irqdata);
|
||||
unsigned long cpu_mask = cpumask_bits(mask)[0] & APIC_ALL_CPUS;
|
||||
|
||||
if (!cpu_mask)
|
||||
return -EINVAL;
|
||||
*apicid = (unsigned int)cpu_mask;
|
||||
cpumask_bits(effmsk)[0] = cpu_mask;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Override the generic EOI implementation with an optimized version.
|
||||
* Only called during early boot when only one CPU is active and with
|
||||
@@ -2322,72 +2326,27 @@ static void __init apic_bsp_up_setup(void)
|
||||
* Returns:
|
||||
* apic_id of BSP APIC
|
||||
*/
|
||||
int __init apic_bsp_setup(bool upmode)
|
||||
void __init apic_bsp_setup(bool upmode)
|
||||
{
|
||||
int id;
|
||||
|
||||
connect_bsp_APIC();
|
||||
if (upmode)
|
||||
apic_bsp_up_setup();
|
||||
setup_local_APIC();
|
||||
|
||||
if (x2apic_mode)
|
||||
id = apic_read(APIC_LDR);
|
||||
else
|
||||
id = GET_APIC_LOGICAL_ID(apic_read(APIC_LDR));
|
||||
|
||||
enable_IO_APIC();
|
||||
end_local_APIC_setup();
|
||||
irq_remap_enable_fault_handling();
|
||||
setup_IO_APIC();
|
||||
/* Setup local timer */
|
||||
x86_init.timers.setup_percpu_clockev();
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* This initializes the IO-APIC and APIC hardware if this is
|
||||
* a UP kernel.
|
||||
*/
|
||||
int __init APIC_init_uniprocessor(void)
|
||||
{
|
||||
if (disable_apic) {
|
||||
pr_info("Apic disabled\n");
|
||||
return -1;
|
||||
}
|
||||
#ifdef CONFIG_X86_64
|
||||
if (!boot_cpu_has(X86_FEATURE_APIC)) {
|
||||
disable_apic = 1;
|
||||
pr_info("Apic disabled by BIOS\n");
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
if (!smp_found_config && !boot_cpu_has(X86_FEATURE_APIC))
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Complain if the BIOS pretends there is one.
|
||||
*/
|
||||
if (!boot_cpu_has(X86_FEATURE_APIC) &&
|
||||
APIC_INTEGRATED(boot_cpu_apic_version)) {
|
||||
pr_err("BIOS bug, local APIC 0x%x not detected!...\n",
|
||||
boot_cpu_physical_apicid);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!smp_found_config)
|
||||
disable_ioapic_support();
|
||||
|
||||
default_setup_apic_routing();
|
||||
apic_bsp_setup(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_UP_LATE_INIT
|
||||
void __init up_late_init(void)
|
||||
{
|
||||
APIC_init_uniprocessor();
|
||||
if (apic_intr_mode == APIC_PIC)
|
||||
return;
|
||||
|
||||
/* Setup local timer */
|
||||
x86_init.timers.setup_percpu_clockev();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Common functions shared between the various APIC flavours
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*/
|
||||
#include <linux/irq.h>
|
||||
#include <asm/apic.h>
|
||||
|
||||
u32 apic_default_calc_apicid(unsigned int cpu)
|
||||
{
|
||||
return per_cpu(x86_cpu_to_apicid, cpu);
|
||||
}
|
||||
|
||||
u32 apic_flat_calc_apicid(unsigned int cpu)
|
||||
{
|
||||
return 1U << cpu;
|
||||
}
|
||||
|
||||
bool default_check_apicid_used(physid_mask_t *map, int apicid)
|
||||
{
|
||||
return physid_isset(apicid, *map);
|
||||
}
|
||||
|
||||
void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap)
|
||||
{
|
||||
*retmap = *phys_map;
|
||||
}
|
||||
|
||||
int default_cpu_present_to_apicid(int mps_cpu)
|
||||
{
|
||||
if (mps_cpu < nr_cpu_ids && cpu_present(mps_cpu))
|
||||
return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
|
||||
else
|
||||
return BAD_APICID;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(default_cpu_present_to_apicid);
|
||||
|
||||
int default_check_phys_apicid_present(int phys_apicid)
|
||||
{
|
||||
return physid_isset(phys_apicid, phys_cpu_present_map);
|
||||
}
|
||||
|
||||
int default_apic_id_valid(int apicid)
|
||||
{
|
||||
return (apicid < 255);
|
||||
}
|
||||
@@ -119,7 +119,7 @@ static unsigned int flat_get_apic_id(unsigned long x)
|
||||
return (x >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
static unsigned long set_apic_id(unsigned int id)
|
||||
static u32 set_apic_id(unsigned int id)
|
||||
{
|
||||
return (id & 0xFF) << 24;
|
||||
}
|
||||
@@ -154,12 +154,10 @@ static struct apic apic_flat __ro_after_init = {
|
||||
.irq_delivery_mode = dest_LowestPrio,
|
||||
.irq_dest_mode = 1, /* logical */
|
||||
|
||||
.target_cpus = online_target_cpus,
|
||||
.disable_esr = 0,
|
||||
.dest_logical = APIC_DEST_LOGICAL,
|
||||
.check_apicid_used = NULL,
|
||||
|
||||
.vector_allocation_domain = flat_vector_allocation_domain,
|
||||
.init_apic_ldr = flat_init_apic_ldr,
|
||||
|
||||
.ioapic_phys_id_map = NULL,
|
||||
@@ -172,7 +170,7 @@ static struct apic apic_flat __ro_after_init = {
|
||||
.get_apic_id = flat_get_apic_id,
|
||||
.set_apic_id = set_apic_id,
|
||||
|
||||
.cpu_mask_to_apicid = flat_cpu_mask_to_apicid,
|
||||
.calc_dest_apicid = apic_flat_calc_apicid,
|
||||
|
||||
.send_IPI = default_send_IPI_single,
|
||||
.send_IPI_mask = flat_send_IPI_mask,
|
||||
@@ -249,12 +247,10 @@ static struct apic apic_physflat __ro_after_init = {
|
||||
.irq_delivery_mode = dest_Fixed,
|
||||
.irq_dest_mode = 0, /* physical */
|
||||
|
||||
.target_cpus = online_target_cpus,
|
||||
.disable_esr = 0,
|
||||
.dest_logical = 0,
|
||||
.check_apicid_used = NULL,
|
||||
|
||||
.vector_allocation_domain = default_vector_allocation_domain,
|
||||
/* not needed, but shouldn't hurt: */
|
||||
.init_apic_ldr = flat_init_apic_ldr,
|
||||
|
||||
@@ -268,7 +264,7 @@ static struct apic apic_physflat __ro_after_init = {
|
||||
.get_apic_id = flat_get_apic_id,
|
||||
.set_apic_id = set_apic_id,
|
||||
|
||||
.cpu_mask_to_apicid = default_cpu_mask_to_apicid,
|
||||
.calc_dest_apicid = apic_default_calc_apicid,
|
||||
|
||||
.send_IPI = default_send_IPI_single_phys,
|
||||
.send_IPI_mask = default_send_IPI_mask_sequence_phys,
|
||||
|
||||
@@ -84,20 +84,6 @@ static int noop_apic_id_registered(void)
|
||||
return physid_isset(0, phys_cpu_present_map);
|
||||
}
|
||||
|
||||
static const struct cpumask *noop_target_cpus(void)
|
||||
{
|
||||
/* only BSP here */
|
||||
return cpumask_of(0);
|
||||
}
|
||||
|
||||
static void noop_vector_allocation_domain(int cpu, struct cpumask *retmask,
|
||||
const struct cpumask *mask)
|
||||
{
|
||||
if (cpu != 0)
|
||||
pr_warning("APIC: Vector allocated for non-BSP cpu\n");
|
||||
cpumask_copy(retmask, cpumask_of(cpu));
|
||||
}
|
||||
|
||||
static u32 noop_apic_read(u32 reg)
|
||||
{
|
||||
WARN_ON_ONCE(boot_cpu_has(X86_FEATURE_APIC) && !disable_apic);
|
||||
@@ -109,6 +95,13 @@ static void noop_apic_write(u32 reg, u32 v)
|
||||
WARN_ON_ONCE(boot_cpu_has(X86_FEATURE_APIC) && !disable_apic);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
static int noop_x86_32_early_logical_apicid(int cpu)
|
||||
{
|
||||
return BAD_APICID;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct apic apic_noop __ro_after_init = {
|
||||
.name = "noop",
|
||||
.probe = noop_probe,
|
||||
@@ -121,12 +114,10 @@ struct apic apic_noop __ro_after_init = {
|
||||
/* logical delivery broadcast to all CPUs: */
|
||||
.irq_dest_mode = 1,
|
||||
|
||||
.target_cpus = noop_target_cpus,
|
||||
.disable_esr = 0,
|
||||
.dest_logical = APIC_DEST_LOGICAL,
|
||||
.check_apicid_used = default_check_apicid_used,
|
||||
|
||||
.vector_allocation_domain = noop_vector_allocation_domain,
|
||||
.init_apic_ldr = noop_init_apic_ldr,
|
||||
|
||||
.ioapic_phys_id_map = default_ioapic_phys_id_map,
|
||||
@@ -142,7 +133,7 @@ struct apic apic_noop __ro_after_init = {
|
||||
.get_apic_id = noop_get_apic_id,
|
||||
.set_apic_id = NULL,
|
||||
|
||||
.cpu_mask_to_apicid = flat_cpu_mask_to_apicid,
|
||||
.calc_dest_apicid = apic_flat_calc_apicid,
|
||||
|
||||
.send_IPI = noop_send_IPI,
|
||||
.send_IPI_mask = noop_send_IPI_mask,
|
||||
|
||||
@@ -38,7 +38,7 @@ static unsigned int numachip1_get_apic_id(unsigned long x)
|
||||
return id;
|
||||
}
|
||||
|
||||
static unsigned long numachip1_set_apic_id(unsigned int id)
|
||||
static u32 numachip1_set_apic_id(unsigned int id)
|
||||
{
|
||||
return (id & 0xff) << 24;
|
||||
}
|
||||
@@ -51,7 +51,7 @@ static unsigned int numachip2_get_apic_id(unsigned long x)
|
||||
return ((mcfg >> (28 - 8)) & 0xfff00) | (x >> 24);
|
||||
}
|
||||
|
||||
static unsigned long numachip2_set_apic_id(unsigned int id)
|
||||
static u32 numachip2_set_apic_id(unsigned int id)
|
||||
{
|
||||
return id << 24;
|
||||
}
|
||||
@@ -249,12 +249,10 @@ static const struct apic apic_numachip1 __refconst = {
|
||||
.irq_delivery_mode = dest_Fixed,
|
||||
.irq_dest_mode = 0, /* physical */
|
||||
|
||||
.target_cpus = online_target_cpus,
|
||||
.disable_esr = 0,
|
||||
.dest_logical = 0,
|
||||
.check_apicid_used = NULL,
|
||||
|
||||
.vector_allocation_domain = default_vector_allocation_domain,
|
||||
.init_apic_ldr = flat_init_apic_ldr,
|
||||
|
||||
.ioapic_phys_id_map = NULL,
|
||||
@@ -267,7 +265,7 @@ static const struct apic apic_numachip1 __refconst = {
|
||||
.get_apic_id = numachip1_get_apic_id,
|
||||
.set_apic_id = numachip1_set_apic_id,
|
||||
|
||||
.cpu_mask_to_apicid = default_cpu_mask_to_apicid,
|
||||
.calc_dest_apicid = apic_default_calc_apicid,
|
||||
|
||||
.send_IPI = numachip_send_IPI_one,
|
||||
.send_IPI_mask = numachip_send_IPI_mask,
|
||||
@@ -300,12 +298,10 @@ static const struct apic apic_numachip2 __refconst = {
|
||||
.irq_delivery_mode = dest_Fixed,
|
||||
.irq_dest_mode = 0, /* physical */
|
||||
|
||||
.target_cpus = online_target_cpus,
|
||||
.disable_esr = 0,
|
||||
.dest_logical = 0,
|
||||
.check_apicid_used = NULL,
|
||||
|
||||
.vector_allocation_domain = default_vector_allocation_domain,
|
||||
.init_apic_ldr = flat_init_apic_ldr,
|
||||
|
||||
.ioapic_phys_id_map = NULL,
|
||||
@@ -318,7 +314,7 @@ static const struct apic apic_numachip2 __refconst = {
|
||||
.get_apic_id = numachip2_get_apic_id,
|
||||
.set_apic_id = numachip2_set_apic_id,
|
||||
|
||||
.cpu_mask_to_apicid = default_cpu_mask_to_apicid,
|
||||
.calc_dest_apicid = apic_default_calc_apicid,
|
||||
|
||||
.send_IPI = numachip_send_IPI_one,
|
||||
.send_IPI_mask = numachip_send_IPI_mask,
|
||||
|
||||
@@ -27,9 +27,9 @@ static int bigsmp_apic_id_registered(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static unsigned long bigsmp_check_apicid_used(physid_mask_t *map, int apicid)
|
||||
static bool bigsmp_check_apicid_used(physid_mask_t *map, int apicid)
|
||||
{
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int bigsmp_early_logical_apicid(int cpu)
|
||||
@@ -155,12 +155,10 @@ static struct apic apic_bigsmp __ro_after_init = {
|
||||
/* phys delivery to target CPU: */
|
||||
.irq_dest_mode = 0,
|
||||
|
||||
.target_cpus = default_target_cpus,
|
||||
.disable_esr = 1,
|
||||
.dest_logical = 0,
|
||||
.check_apicid_used = bigsmp_check_apicid_used,
|
||||
|
||||
.vector_allocation_domain = default_vector_allocation_domain,
|
||||
.init_apic_ldr = bigsmp_init_apic_ldr,
|
||||
|
||||
.ioapic_phys_id_map = bigsmp_ioapic_phys_id_map,
|
||||
@@ -173,7 +171,7 @@ static struct apic apic_bigsmp __ro_after_init = {
|
||||
.get_apic_id = bigsmp_get_apic_id,
|
||||
.set_apic_id = NULL,
|
||||
|
||||
.cpu_mask_to_apicid = default_cpu_mask_to_apicid,
|
||||
.calc_dest_apicid = apic_default_calc_apicid,
|
||||
|
||||
.send_IPI = default_send_IPI_single_phys,
|
||||
.send_IPI_mask = default_send_IPI_mask_sequence_phys,
|
||||
|
||||
@@ -1014,6 +1014,7 @@ static int alloc_isa_irq_from_domain(struct irq_domain *domain,
|
||||
info->ioapic_pin))
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
info->flags |= X86_IRQ_ALLOC_LEGACY;
|
||||
irq = __irq_domain_alloc_irqs(domain, irq, 1, node, info, true,
|
||||
NULL);
|
||||
if (irq >= 0) {
|
||||
@@ -1586,6 +1587,43 @@ static int __init notimercheck(char *s)
|
||||
}
|
||||
__setup("no_timer_check", notimercheck);
|
||||
|
||||
static void __init delay_with_tsc(void)
|
||||
{
|
||||
unsigned long long start, now;
|
||||
unsigned long end = jiffies + 4;
|
||||
|
||||
start = rdtsc();
|
||||
|
||||
/*
|
||||
* We don't know the TSC frequency yet, but waiting for
|
||||
* 40000000000/HZ TSC cycles is safe:
|
||||
* 4 GHz == 10 jiffies
|
||||
* 1 GHz == 40 jiffies
|
||||
*/
|
||||
do {
|
||||
rep_nop();
|
||||
now = rdtsc();
|
||||
} while ((now - start) < 40000000000UL / HZ &&
|
||||
time_before_eq(jiffies, end));
|
||||
}
|
||||
|
||||
static void __init delay_without_tsc(void)
|
||||
{
|
||||
unsigned long end = jiffies + 4;
|
||||
int band = 1;
|
||||
|
||||
/*
|
||||
* We don't know any frequency yet, but waiting for
|
||||
* 40940000000/HZ cycles is safe:
|
||||
* 4 GHz == 10 jiffies
|
||||
* 1 GHz == 40 jiffies
|
||||
* 1 << 1 + 1 << 2 +...+ 1 << 11 = 4094
|
||||
*/
|
||||
do {
|
||||
__delay(((1U << band++) * 10000000UL) / HZ);
|
||||
} while (band < 12 && time_before_eq(jiffies, end));
|
||||
}
|
||||
|
||||
/*
|
||||
* There is a nasty bug in some older SMP boards, their mptable lies
|
||||
* about the timer IRQ. We do the following to work around the situation:
|
||||
@@ -1604,8 +1642,12 @@ static int __init timer_irq_works(void)
|
||||
|
||||
local_save_flags(flags);
|
||||
local_irq_enable();
|
||||
/* Let ten ticks pass... */
|
||||
mdelay((10 * 1000) / HZ);
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_TSC))
|
||||
delay_with_tsc();
|
||||
else
|
||||
delay_without_tsc();
|
||||
|
||||
local_irq_restore(flags);
|
||||
|
||||
/*
|
||||
@@ -1821,26 +1863,36 @@ static void ioapic_ir_ack_level(struct irq_data *irq_data)
|
||||
eoi_ioapic_pin(data->entry.vector, data);
|
||||
}
|
||||
|
||||
static void ioapic_configure_entry(struct irq_data *irqd)
|
||||
{
|
||||
struct mp_chip_data *mpd = irqd->chip_data;
|
||||
struct irq_cfg *cfg = irqd_cfg(irqd);
|
||||
struct irq_pin_list *entry;
|
||||
|
||||
/*
|
||||
* Only update when the parent is the vector domain, don't touch it
|
||||
* if the parent is the remapping domain. Check the installed
|
||||
* ioapic chip to verify that.
|
||||
*/
|
||||
if (irqd->chip == &ioapic_chip) {
|
||||
mpd->entry.dest = cfg->dest_apicid;
|
||||
mpd->entry.vector = cfg->vector;
|
||||
}
|
||||
for_each_irq_pin(entry, mpd->irq_2_pin)
|
||||
__ioapic_write_entry(entry->apic, entry->pin, mpd->entry);
|
||||
}
|
||||
|
||||
static int ioapic_set_affinity(struct irq_data *irq_data,
|
||||
const struct cpumask *mask, bool force)
|
||||
{
|
||||
struct irq_data *parent = irq_data->parent_data;
|
||||
struct mp_chip_data *data = irq_data->chip_data;
|
||||
struct irq_pin_list *entry;
|
||||
struct irq_cfg *cfg;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
ret = parent->chip->irq_set_affinity(parent, mask, force);
|
||||
raw_spin_lock_irqsave(&ioapic_lock, flags);
|
||||
if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE) {
|
||||
cfg = irqd_cfg(irq_data);
|
||||
data->entry.dest = cfg->dest_apicid;
|
||||
data->entry.vector = cfg->vector;
|
||||
for_each_irq_pin(entry, data->irq_2_pin)
|
||||
__ioapic_write_entry(entry->apic, entry->pin,
|
||||
data->entry);
|
||||
}
|
||||
if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE)
|
||||
ioapic_configure_entry(irq_data);
|
||||
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
|
||||
|
||||
return ret;
|
||||
@@ -2513,52 +2565,9 @@ int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity)
|
||||
}
|
||||
|
||||
/*
|
||||
* This function currently is only a helper for the i386 smp boot process where
|
||||
* we need to reprogram the ioredtbls to cater for the cpus which have come online
|
||||
* so mask in all cases should simply be apic->target_cpus()
|
||||
* This function updates target affinity of IOAPIC interrupts to include
|
||||
* the CPUs which came online during SMP bringup.
|
||||
*/
|
||||
#ifdef CONFIG_SMP
|
||||
void __init setup_ioapic_dest(void)
|
||||
{
|
||||
int pin, ioapic, irq, irq_entry;
|
||||
const struct cpumask *mask;
|
||||
struct irq_desc *desc;
|
||||
struct irq_data *idata;
|
||||
struct irq_chip *chip;
|
||||
|
||||
if (skip_ioapic_setup == 1)
|
||||
return;
|
||||
|
||||
for_each_ioapic_pin(ioapic, pin) {
|
||||
irq_entry = find_irq_entry(ioapic, pin, mp_INT);
|
||||
if (irq_entry == -1)
|
||||
continue;
|
||||
|
||||
irq = pin_2_irq(irq_entry, ioapic, pin, 0);
|
||||
if (irq < 0 || !mp_init_irq_at_boot(ioapic, irq))
|
||||
continue;
|
||||
|
||||
desc = irq_to_desc(irq);
|
||||
raw_spin_lock_irq(&desc->lock);
|
||||
idata = irq_desc_get_irq_data(desc);
|
||||
|
||||
/*
|
||||
* Honour affinities which have been set in early boot
|
||||
*/
|
||||
if (!irqd_can_balance(idata) || irqd_affinity_was_set(idata))
|
||||
mask = irq_data_get_affinity_mask(idata);
|
||||
else
|
||||
mask = apic->target_cpus();
|
||||
|
||||
chip = irq_data_get_irq_chip(idata);
|
||||
/* Might be lapic_chip for irq 0 */
|
||||
if (chip->irq_set_affinity)
|
||||
chip->irq_set_affinity(idata, mask, false);
|
||||
raw_spin_unlock_irq(&desc->lock);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#define IOAPIC_RESOURCE_NAME_SIZE 11
|
||||
|
||||
static struct resource *ioapic_resources;
|
||||
@@ -2982,12 +2991,9 @@ int mp_irqdomain_activate(struct irq_domain *domain,
|
||||
struct irq_data *irq_data, bool early)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct irq_pin_list *entry;
|
||||
struct mp_chip_data *data = irq_data->chip_data;
|
||||
|
||||
raw_spin_lock_irqsave(&ioapic_lock, flags);
|
||||
for_each_irq_pin(entry, data->irq_2_pin)
|
||||
__ioapic_write_entry(entry->apic, entry->pin, data->entry);
|
||||
ioapic_configure_entry(irq_data);
|
||||
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loaded 20 of 43 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user