linux/arch/x86/kernel/apic/io_apic.c

// SPDX-License-Identifier: GPL-2.0
/*
 *	Intel IO-APIC support for multi-Pentium hosts.
 *
 *	Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
 *
 *	Many thanks to Stig Venaas for trying out countless experimental
 *	patches and reporting/debugging problems patiently!
 *
 *	(c) 1999, Multiple IO-APIC support, developed by
 *	Ken-ichi Yaku <[email protected]> and
 *      Hidemi Kishimoto <[email protected]>,
 *	further tested and cleaned up by Zach Brown <[email protected]>
 *	and Ingo Molnar <[email protected]>
 *
 *	Fixes
 *	Maciej W. Rozycki	:	Bits for genuine 82489DX APICs;
 *					thanks to Eric Gilmore
 *					and Rolf G. Tews
 *					for testing these extensively
 *	Paul Diefenbaugh	:	Added full ACPI support
 *
 * Historical information which is worth to be preserved:
 *
 * - SiS APIC rmw bug:
 *
 *	We used to have a workaround for a bug in SiS chips which
 *	required to rewrite the index register for a read-modify-write
 *	operation as the chip lost the index information which was
 *	setup for the read already. We cache the data now, so that
 *	workaround has been removed.
 */

#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>	/* time_after() */
#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;

/* The one past the highest gsi number used */
u32 gsi_top;

/* MP IRQ source entries */
struct mpc_intsrc mp_irqs[MAX_IRQ_SOURCES];

/* # of MP IRQ source entries */
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;

/**
 * disable_ioapic_support() - disables ioapic support at runtime
 */
void disable_ioapic_support(void)
{}

static int __init parse_noapic(char *str)
{}
early_param();

/* Will be called in mpparse/ACPI codes for saving IRQ info */
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)
{}

/*
 * When we write a new IO APIC routing entry, we need to write the high
 * word first! If the mask bit in the low word is clear, we will enable
 * the interrupt, and we need to make sure the entry is fully populated
 * before that happens.
 */
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)
{}

/*
 * When we mask an IO APIC routing entry, we need to write the low
 * word first, in order to set the mask bit before we change the
 * high bits!
 */
static void ioapic_mask_entry(int apic, int pin)
{}

/*
 * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
 * shared ISA-space IRQs, so we have to support them. We are super
 * fast in the common case, and fast for shared ISA-space IRQs.
 */
static 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)
{}

/*
 * 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)
{}

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)
{}

/*
 * IO-APIC versions below 0x20 don't support EOI register.
 * For the record, here is the information about various versions:
 *     0Xh     82489DX
 *     1Xh     I/OAPIC or I/O(x)APIC which are not PCI 2.2 Compliant
 *     2Xh     I/O(x)APIC which is PCI 2.2 Compliant
 *     30h-FFh Reserved
 *
 * Some of the Intel ICH Specs (ICH2 to ICH5) documents the io-apic
 * version as 0x2. This is an error with documentation and these ICH chips
 * use io-apic's of version 0x20.
 *
 * For IO-APIC's with EOI register, we use that to do an explicit EOI.
 * Otherwise, we simulate the EOI message manually by changing the trigger
 * mode to edge and then back to level, with RTE being masked during this.
 */
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
/*
 * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
 * specific CPU-side IRQs.
 */

#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]);
		/*
		 * PIRQs are mapped upside down, usually.
		 */
		pirq_entries[MAX_PIRQS-i-1] = ints[i+1];
	}
	return 1;
}

__setup("pirq=", ioapic_pirq_setup);
#endif /* CONFIG_X86_32 */

/*
 * Saves all the IO-APIC RTE's
 */
int save_ioapic_entries(void)
{}

/*
 * Mask all IO APIC entries.
 */
void mask_ioapic_entries(void)
{}

/*
 * Restore IO APIC entries which was saved in the ioapic structure.
 */
int restore_ioapic_entries(void)
{}

/*
 * Find the IRQ entry number of a certain pin.
 */
static int find_irq_entry(int ioapic_idx, int pin, int type)
{}

/*
 * Find the pin to which IRQ[irq] (ISA) is connected
 */
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
/*
 * EISA Edge/Level control register, ELCR
 */
static bool EISA_ELCR(unsigned int irq)
{}

/*
 * EISA interrupts are always active high and can be edge or level
 * triggered depending on the ELCR value.  If an interrupt is listed as
 * EISA conforming in the MP table, that means its trigger type must be
 * read in from the ELCR.
 */
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)
{}

/*
 * Need special handling for ISA IRQs because there may be multiple IOAPIC pins
 * sharing the same ISA IRQ number and irqdomain only supports 1:1 mapping
 * between IOAPIC pin and IRQ number. A typical IOAPIC has 24 pins, pin 0-15 are
 * used for legacy IRQs and pin 16-23 are used for PCI IRQs (PIRQ A-H).
 * When ACPI is disabled, only legacy IRQ numbers (IRQ0-15) are available, and
 * some BIOSes may use MP Interrupt Source records to override IRQ numbers for
 * PIRQs instead of reprogramming the interrupt routing logic. Thus there may be
 * multiple pins sharing the same legacy IRQ number when ACPI is disabled.
 */
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)
{}

/*
 * Find a specific PCI IRQ entry.
 * Not an __init, possibly needed by modules
 */
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)
{}

/* Where if anywhere is the i8259 connect in external int mode */
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
/*
 * function to set the IO-APIC physical IDs based on the
 * values stored in the MPC table.
 *
 * by Matt Domsch <[email protected]>  Tue Dec 21 12:25:05 CST 1999
 */
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;

	/*
	 * This is broken; anything with a real cpu count has to
	 * circumvent this idiocy regardless.
	 */
	copy_phys_cpu_present_map(phys_id_present_map);

	/*
	 * Set the IOAPIC ID to the value stored in the MPC table.
	 */
	for_each_ioapic(ioapic_idx) {
		/* Read the register 0 value */
		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;
		}

		/*
		 * Sanity check, is the ID really free? Every APIC in a
		 * system must have a unique ID or we get lots of nice
		 * 'stuck on smp_invalidate_needed IPI wait' messages.
		 */
		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);
		}

		/*
		 * We need to adjust the IRQ routing table
		 * if the ID changed.
		 */
		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);

		/*
		 * Update the ID register according to the right value
		 * from the MPC table if they are different.
		 */
		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);

		/*
		 * Sanity check
		 */
		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;
	/*
	 * Don't check I/O APIC IDs for xAPIC systems.  They have
	 * no meaning without the serial APIC bus.
	 */
	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)
{}

/*
 * 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:
 *
 *	- timer IRQ defaults to IO-APIC IRQ
 *	- if this function detects that timer IRQs are defunct, then we fall
 *	  back to ISA timer IRQs
 */
static int __init timer_irq_works(void)
{}

/*
 * In the SMP+IOAPIC case it might happen that there are an unspecified
 * number of pending IRQ events unhandled. These cases are very rare,
 * 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
 * '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...
 */
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)
{}

/*
 * The I/OAPIC is just a device for generating MSI messages from legacy
 * interrupt pins. Various fields of the RTE translate into bits of the
 * resulting MSI which had a historical meaning.
 *
 * With interrupt remapping, many of those bits have different meanings
 * in the underlying MSI, but the way that the I/OAPIC transforms them
 * from its RTE to the MSI message is the same. This function allows
 * the parent IRQ domain to compose the MSI message, then takes the
 * relevant bits to put them in the appropriate places in the RTE in
 * order to generate that message when the IRQ happens.
 *
 * The setup here relies on a preconfigured route entry (is_level,
 * active_low, masked) because the parent domain is merely composing the
 * generic message routing information which is used for the MSI.
 */
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)
{}

/*
 * Interrupt shutdown masks the ioapic pin, but the interrupt might already
 * be in flight, but not yet serviced by the target CPU. That means
 * __synchronize_hardirq() would return and claim that everything is calmed
 * down. So free_irq() would proceed and deactivate the interrupt and free
 * resources.
 *
 * Once the target CPU comes around to service it it will find a cleared
 * vector and complain. While the spurious interrupt is harmless, the full
 * release of resources might prevent the interrupt from being acknowledged
 * which keeps the hardware in a weird state.
 *
 * Verify that the corresponding Remote-IRR bits are clear.
 */
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)
{}

/*
 * The local APIC irq-chip implementation:
 */

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)
{}

/*
 * This looks a bit hackish but it's about the only one way of sending
 * a few INTA cycles to 8259As and any associated glue logic.  ICR does
 * not support the ExtINT mode, unfortunately.  We need to send these
 * cycles as some i82489DX-based boards have glue logic that keeps the
 * 8259A interrupt line asserted until INTA.  --macro
 */
static inline void __init unlock_ExtINT_logic(void)
{}

static int disable_timer_pin_1 __initdata;
/* Actually the next is obsolete, but keep it for paranoid reasons -AK */
static int __init disable_timer_pin_setup(char *arg)
{}
early_param();

static int mp_alloc_timer_irq(int ioapic, int pin)
{}

/*
 * 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
 * is so screwy.  Thanks to Brian Perkins for testing/hacking this beast
 * fanatically on his truly buggy board.
 *
 * FIXME: really need to revamp this for all platforms.
 */
static inline void __init check_timer(void)
{}

/*
 * Traditionally ISA IRQ2 is the cascade IRQ, and is not available
 * to devices.  However there may be an I/O APIC pin available for
 * this interrupt regardless.  The pin may be left unconnected, but
 * typically it will be reused as an ExtINT cascade interrupt for
 * the master 8259A.  In the MPS case such a pin will normally be
 * reported as an ExtINT interrupt in the MP table.  With ACPI
 * there is no provision for ExtINT interrupts, and in the absence
 * of an override it would be treated as an ordinary ISA I/O APIC
 * interrupt, that is edge-triggered and unmasked by default.  We
 * used to do this, but it caused problems on some systems because
 * of the NMI watchdog and sometimes IRQ0 of the 8254 timer using
 * the same ExtINT cascade interrupt to drive the local APIC of the
 * bootstrap processor.  Therefore we refrain from routing IRQ2 to
 * the I/O APIC in all cases now.  No actual device should request
 * it anyway.  --macro
 */
#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;

	/* Initialize the ID map */
	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;
	}

	/* Every APIC in a system must have a unique 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);

		/* Sanity check */
		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)
{}

/*
 * This function updates target affinity of IOAPIC interrupts to include
 * the CPUs which came online during SMP bringup.
 */
#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)
{}

/**
 * mp_register_ioapic - Register an IOAPIC device
 * @id:		hardware IOAPIC ID
 * @address:	physical address of IOAPIC register area
 * @gsi_base:	base of GSI associated with the IOAPIC
 * @cfg:	configuration information for the IOAPIC
 */
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)
{}

/*
 * Configure the I/O-APIC specific fields in the routing entry.
 *
 * This is important to setup the I/O-APIC specific bits (is_level,
 * active_low, masked) because the underlying parent domain will only
 * provide the routing information and is oblivious of the I/O-APIC
 * specific bits.
 *
 * The entry is just preconfigured at this point and not written into the
 * RTE. This happens later during activation which will fill in the actual
 * routing information.
 */
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 =;