#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/mc146818rtc.h>
#include <linux/compiler.h>
#include <linux/acpi.h>
#include <linux/export.h>
#include <linux/syscore_ops.h>
#include <linux/freezer.h>
#include <linux/kthread.h>
#include <linux/jiffies.h>
#include <linux/slab.h>
#include <linux/memblock.h>
#include <linux/msi.h>
#include <asm/irqdomain.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/cpu.h>
#include <asm/desc.h>
#include <asm/proto.h>
#include <asm/acpi.h>
#include <asm/dma.h>
#include <asm/timer.h>
#include <asm/time.h>
#include <asm/i8259.h>
#include <asm/setup.h>
#include <asm/irq_remapping.h>
#include <asm/hw_irq.h>
#include <asm/apic.h>
#include <asm/pgtable.h>
#include <asm/x86_init.h>
#define for_each_ioapic(idx) …
#define for_each_ioapic_reverse(idx) …
#define for_each_pin(idx, pin) …
#define for_each_ioapic_pin(idx, pin) …
#define for_each_irq_pin(entry, head) …
static DEFINE_RAW_SPINLOCK(ioapic_lock);
static DEFINE_MUTEX(ioapic_mutex);
static unsigned int ioapic_dynirq_base;
static int ioapic_initialized;
struct irq_pin_list { … };
struct mp_chip_data { … };
struct mp_ioapic_gsi { … };
static struct ioapic { … } ioapics[MAX_IO_APICS];
#define mpc_ioapic_ver(ioapic_idx) …
int mpc_ioapic_id(int ioapic_idx)
{ … }
unsigned int mpc_ioapic_addr(int ioapic_idx)
{ … }
static inline struct mp_ioapic_gsi *mp_ioapic_gsi_routing(int ioapic_idx)
{ … }
static inline int mp_ioapic_pin_count(int ioapic)
{ … }
static inline u32 mp_pin_to_gsi(int ioapic, int pin)
{ … }
static inline bool mp_is_legacy_irq(int irq)
{ … }
static inline struct irq_domain *mp_ioapic_irqdomain(int ioapic)
{ … }
int nr_ioapics;
u32 gsi_top;
struct mpc_intsrc mp_irqs[MAX_IRQ_SOURCES];
int mp_irq_entries;
#ifdef CONFIG_EISA
int mp_bus_id_to_type[MAX_MP_BUSSES];
#endif
DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
bool ioapic_is_disabled __ro_after_init;
void disable_ioapic_support(void)
{ … }
static int __init parse_noapic(char *str)
{ … }
early_param(…);
void mp_save_irq(struct mpc_intsrc *m)
{ … }
static void alloc_ioapic_saved_registers(int idx)
{ … }
static void free_ioapic_saved_registers(int idx)
{ … }
int __init arch_early_ioapic_init(void)
{ … }
struct io_apic { … };
static __attribute_const__ struct io_apic __iomem *io_apic_base(int idx)
{ … }
static inline void io_apic_eoi(unsigned int apic, unsigned int vector)
{ … }
unsigned int native_io_apic_read(unsigned int apic, unsigned int reg)
{ … }
static void io_apic_write(unsigned int apic, unsigned int reg,
unsigned int value)
{ … }
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 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_mask_entry(int apic, int pin)
{ … }
static int __add_pin_to_irq_node(struct mp_chip_data *data,
int node, int apic, int pin)
{ … }
static void __remove_pin_from_irq(struct mp_chip_data *data, int apic, int pin)
{ … }
static void add_pin_to_irq_node(struct mp_chip_data *data,
int node, int apic, int pin)
{ … }
static void __init replace_pin_at_irq_node(struct mp_chip_data *data, int node,
int oldapic, int oldpin,
int newapic, int newpin)
{ … }
static void io_apic_modify_irq(struct mp_chip_data *data, bool masked,
void (*final)(struct irq_pin_list *entry))
{ … }
static void io_apic_sync(struct irq_pin_list *entry)
{ … }
static void mask_ioapic_irq(struct irq_data *irq_data)
{ … }
static void __unmask_ioapic(struct mp_chip_data *data)
{ … }
static void unmask_ioapic_irq(struct irq_data *irq_data)
{ … }
static void __eoi_ioapic_pin(int apic, int pin, int vector)
{ … }
static void eoi_ioapic_pin(int vector, struct mp_chip_data *data)
{ … }
static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
{ … }
void clear_IO_APIC (void)
{ … }
#ifdef CONFIG_X86_32
#define MAX_PIRQS …
static int pirq_entries[MAX_PIRQS] = {
[0 ... MAX_PIRQS - 1] = -1
};
static int __init ioapic_pirq_setup(char *str)
{
int i, max;
int ints[MAX_PIRQS+1];
get_options(str, ARRAY_SIZE(ints), ints);
apic_printk(APIC_VERBOSE, KERN_INFO
"PIRQ redirection, working around broken MP-BIOS.\n");
max = MAX_PIRQS;
if (ints[0] < MAX_PIRQS)
max = ints[0];
for (i = 0; i < max; i++) {
apic_printk(APIC_VERBOSE, KERN_DEBUG
"... PIRQ%d -> IRQ %d\n", i, ints[i+1]);
pirq_entries[MAX_PIRQS-i-1] = ints[i+1];
}
return 1;
}
__setup("pirq=", ioapic_pirq_setup);
#endif
int save_ioapic_entries(void)
{ … }
void mask_ioapic_entries(void)
{ … }
int restore_ioapic_entries(void)
{ … }
static int find_irq_entry(int ioapic_idx, int pin, int type)
{ … }
static int __init find_isa_irq_pin(int irq, int type)
{ … }
static int __init find_isa_irq_apic(int irq, int type)
{ … }
static bool irq_active_low(int idx)
{ … }
#ifdef CONFIG_EISA
static bool EISA_ELCR(unsigned int irq)
{ … }
static bool eisa_irq_is_level(int idx, int bus, bool level)
{ … }
#else
static inline int eisa_irq_is_level(int idx, int bus, bool level)
{
return level;
}
#endif
static bool irq_is_level(int idx)
{ … }
static int __acpi_get_override_irq(u32 gsi, bool *trigger, bool *polarity)
{ … }
#ifdef CONFIG_ACPI
int acpi_get_override_irq(u32 gsi, int *is_level, int *active_low)
{ … }
#endif
void ioapic_set_alloc_attr(struct irq_alloc_info *info, int node,
int trigger, int polarity)
{ … }
static void ioapic_copy_alloc_attr(struct irq_alloc_info *dst,
struct irq_alloc_info *src,
u32 gsi, int ioapic_idx, int pin)
{ … }
static int ioapic_alloc_attr_node(struct irq_alloc_info *info)
{ … }
static void mp_register_handler(unsigned int irq, bool level)
{ … }
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,
struct irq_alloc_info *info)
{ … }
static int alloc_isa_irq_from_domain(struct irq_domain *domain,
int irq, int ioapic, int pin,
struct irq_alloc_info *info)
{ … }
static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin,
unsigned int flags, struct irq_alloc_info *info)
{ … }
static int pin_2_irq(int idx, int ioapic, int pin, unsigned int flags)
{ … }
int mp_map_gsi_to_irq(u32 gsi, unsigned int flags, struct irq_alloc_info *info)
{ … }
void mp_unmap_irq(int irq)
{ … }
int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
{ … }
EXPORT_SYMBOL(…);
static struct irq_chip ioapic_chip, ioapic_ir_chip;
static void __init setup_IO_APIC_irqs(void)
{ … }
void ioapic_zap_locks(void)
{ … }
static void io_apic_print_entries(unsigned int apic, unsigned int nr_entries)
{ … }
static void __init print_IO_APIC(int ioapic_idx)
{ … }
void __init print_IO_APICs(void)
{ … }
static struct { … } ioapic_i8259 = …;
void __init enable_IO_APIC(void)
{ … }
void native_restore_boot_irq_mode(void)
{ … }
void restore_boot_irq_mode(void)
{ … }
#ifdef CONFIG_X86_32
static void __init setup_ioapic_ids_from_mpc_nocheck(void)
{
DECLARE_BITMAP(phys_id_present_map, MAX_LOCAL_APIC);
const u32 broadcast_id = 0xF;
union IO_APIC_reg_00 reg_00;
unsigned char old_id;
unsigned long flags;
int ioapic_idx, i;
copy_phys_cpu_present_map(phys_id_present_map);
for_each_ioapic(ioapic_idx) {
raw_spin_lock_irqsave(&ioapic_lock, flags);
reg_00.raw = io_apic_read(ioapic_idx, 0);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
old_id = mpc_ioapic_id(ioapic_idx);
if (mpc_ioapic_id(ioapic_idx) >= broadcast_id) {
pr_err(FW_BUG "IO-APIC#%d ID is %d in the MPC table!...\n",
ioapic_idx, mpc_ioapic_id(ioapic_idx));
pr_err("... fixing up to %d. (tell your hw vendor)\n", reg_00.bits.ID);
ioapics[ioapic_idx].mp_config.apicid = reg_00.bits.ID;
}
if (test_bit(mpc_ioapic_id(ioapic_idx), phys_id_present_map)) {
pr_err(FW_BUG "IO-APIC#%d ID %d is already used!...\n",
ioapic_idx, mpc_ioapic_id(ioapic_idx));
for (i = 0; i < broadcast_id; i++)
if (!test_bit(i, phys_id_present_map))
break;
if (i >= broadcast_id)
panic("Max APIC ID exceeded!\n");
pr_err("... fixing up to %d. (tell your hw vendor)\n", i);
set_bit(i, phys_id_present_map);
ioapics[ioapic_idx].mp_config.apicid = i;
} else {
apic_printk(APIC_VERBOSE, "Setting %d in the phys_id_present_map\n",
mpc_ioapic_id(ioapic_idx));
set_bit(mpc_ioapic_id(ioapic_idx), phys_id_present_map);
}
if (old_id != mpc_ioapic_id(ioapic_idx))
for (i = 0; i < mp_irq_entries; i++)
if (mp_irqs[i].dstapic == old_id)
mp_irqs[i].dstapic
= mpc_ioapic_id(ioapic_idx);
if (mpc_ioapic_id(ioapic_idx) == reg_00.bits.ID)
continue;
apic_printk(APIC_VERBOSE, KERN_INFO
"...changing IO-APIC physical APIC ID to %d ...",
mpc_ioapic_id(ioapic_idx));
reg_00.bits.ID = mpc_ioapic_id(ioapic_idx);
raw_spin_lock_irqsave(&ioapic_lock, flags);
io_apic_write(ioapic_idx, 0, reg_00.raw);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
raw_spin_lock_irqsave(&ioapic_lock, flags);
reg_00.raw = io_apic_read(ioapic_idx, 0);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
if (reg_00.bits.ID != mpc_ioapic_id(ioapic_idx))
pr_cont("could not set ID!\n");
else
apic_printk(APIC_VERBOSE, " ok.\n");
}
}
void __init setup_ioapic_ids_from_mpc(void)
{
if (acpi_ioapic)
return;
if (!(boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
|| APIC_XAPIC(boot_cpu_apic_version))
return;
setup_ioapic_ids_from_mpc_nocheck();
}
#endif
int no_timer_check __initdata;
static int __init notimercheck(char *s)
{ … }
__setup(…);
static void __init delay_with_tsc(void)
{ … }
static void __init delay_without_tsc(void)
{ … }
static int __init timer_irq_works(void)
{ … }
static unsigned int startup_ioapic_irq(struct irq_data *data)
{ … }
atomic_t irq_mis_count;
#ifdef CONFIG_GENERIC_PENDING_IRQ
static bool io_apic_level_ack_pending(struct mp_chip_data *data)
{ … }
static inline bool ioapic_prepare_move(struct irq_data *data)
{ … }
static inline void ioapic_finish_move(struct irq_data *data, bool moveit)
{ … }
#else
static inline bool ioapic_prepare_move(struct irq_data *data)
{
return false;
}
static inline void ioapic_finish_move(struct irq_data *data, bool moveit)
{
}
#endif
static void ioapic_ack_level(struct irq_data *irq_data)
{ … }
static void ioapic_ir_ack_level(struct irq_data *irq_data)
{ … }
static void ioapic_setup_msg_from_msi(struct irq_data *irq_data,
struct IO_APIC_route_entry *entry)
{ … }
static void ioapic_configure_entry(struct irq_data *irqd)
{ … }
static int ioapic_set_affinity(struct irq_data *irq_data,
const struct cpumask *mask, bool force)
{ … }
static int ioapic_irq_get_chip_state(struct irq_data *irqd,
enum irqchip_irq_state which,
bool *state)
{ … }
static struct irq_chip ioapic_chip __read_mostly = …;
static struct irq_chip ioapic_ir_chip __read_mostly = …;
static inline void init_IO_APIC_traps(void)
{ … }
static void mask_lapic_irq(struct irq_data *data)
{ … }
static void unmask_lapic_irq(struct irq_data *data)
{ … }
static void ack_lapic_irq(struct irq_data *data)
{ … }
static struct irq_chip lapic_chip __read_mostly = …;
static void lapic_register_intr(int irq)
{ … }
static inline void __init unlock_ExtINT_logic(void)
{ … }
static int disable_timer_pin_1 __initdata;
static int __init disable_timer_pin_setup(char *arg)
{ … }
early_param(…);
static int mp_alloc_timer_irq(int ioapic, int pin)
{ … }
static inline void __init check_timer(void)
{ … }
#define PIC_IRQS …
static int mp_irqdomain_create(int ioapic)
{ … }
static void ioapic_destroy_irqdomain(int idx)
{ … }
void __init setup_IO_APIC(void)
{ … }
static void resume_ioapic_id(int ioapic_idx)
{ … }
static void ioapic_resume(void)
{ … }
static struct syscore_ops ioapic_syscore_ops = …;
static int __init ioapic_init_ops(void)
{ … }
device_initcall(ioapic_init_ops);
static int io_apic_get_redir_entries(int ioapic)
{ … }
unsigned int arch_dynirq_lower_bound(unsigned int from)
{ … }
#ifdef CONFIG_X86_32
static int io_apic_get_unique_id(int ioapic, int apic_id)
{
static DECLARE_BITMAP(apic_id_map, MAX_LOCAL_APIC);
const u32 broadcast_id = 0xF;
union IO_APIC_reg_00 reg_00;
unsigned long flags;
int i = 0;
if (bitmap_empty(apic_id_map, MAX_LOCAL_APIC))
copy_phys_cpu_present_map(apic_id_map);
raw_spin_lock_irqsave(&ioapic_lock, flags);
reg_00.raw = io_apic_read(ioapic, 0);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
if (apic_id >= broadcast_id) {
pr_warn("IOAPIC[%d]: Invalid apic_id %d, trying %d\n",
ioapic, apic_id, reg_00.bits.ID);
apic_id = reg_00.bits.ID;
}
if (test_bit(apic_id, apic_id_map)) {
for (i = 0; i < broadcast_id; i++) {
if (!test_bit(i, apic_id_map))
break;
}
if (i == broadcast_id)
panic("Max apic_id exceeded!\n");
pr_warn("IOAPIC[%d]: apic_id %d already used, trying %d\n", ioapic, apic_id, i);
apic_id = i;
}
set_bit(apic_id, apic_id_map);
if (reg_00.bits.ID != apic_id) {
reg_00.bits.ID = apic_id;
raw_spin_lock_irqsave(&ioapic_lock, flags);
io_apic_write(ioapic, 0, reg_00.raw);
reg_00.raw = io_apic_read(ioapic, 0);
raw_spin_unlock_irqrestore(&ioapic_lock, flags);
if (reg_00.bits.ID != apic_id) {
pr_err("IOAPIC[%d]: Unable to change apic_id!\n",
ioapic);
return -1;
}
}
apic_printk(APIC_VERBOSE, KERN_INFO
"IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id);
return apic_id;
}
static u8 io_apic_unique_id(int idx, u8 id)
{
if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && !APIC_XAPIC(boot_cpu_apic_version))
return io_apic_get_unique_id(idx, id);
return id;
}
#else
static u8 io_apic_unique_id(int idx, u8 id)
{ … }
#endif
static int io_apic_get_version(int ioapic)
{ … }
#define IOAPIC_RESOURCE_NAME_SIZE …
static struct resource *ioapic_resources;
static struct resource * __init ioapic_setup_resources(void)
{ … }
static void io_apic_set_fixmap(enum fixed_addresses idx, phys_addr_t phys)
{ … }
void __init io_apic_init_mappings(void)
{ … }
void __init ioapic_insert_resources(void)
{ … }
int mp_find_ioapic(u32 gsi)
{ … }
int mp_find_ioapic_pin(int ioapic, u32 gsi)
{ … }
static int bad_ioapic_register(int idx)
{ … }
static int find_free_ioapic_entry(void)
{ … }
int mp_register_ioapic(int id, u32 address, u32 gsi_base,
struct ioapic_domain_cfg *cfg)
{ … }
int mp_unregister_ioapic(u32 gsi_base)
{ … }
int mp_ioapic_registered(u32 gsi_base)
{ … }
static void mp_irqdomain_get_attr(u32 gsi, struct mp_chip_data *data,
struct irq_alloc_info *info)
{ … }
static void mp_preconfigure_entry(struct mp_chip_data *data)
{ … }
int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *arg)
{ … }
void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs)
{ … }
int mp_irqdomain_activate(struct irq_domain *domain,
struct irq_data *irq_data, bool reserve)
{ … }
void mp_irqdomain_deactivate(struct irq_domain *domain,
struct irq_data *irq_data)
{ … }
int mp_irqdomain_ioapic_idx(struct irq_domain *domain)
{ … }
const struct irq_domain_ops mp_ioapic_irqdomain_ops = …;