arch/x86/kernel/apic/io_apic.c

Source file repositories/reference/linux-study-clean/arch/x86/kernel/apic/io_apic.c

File Facts

System
Linux kernel
Corpus path
arch/x86/kernel/apic/io_apic.c
Extension
.c
Size
78812 bytes
Lines
2958
Domain
Architecture Layer
Bucket
arch/x86
Inferred role
Architecture Layer: exported/initcall integration point
Status
integration implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

device_initcall(ioapic_init_ops);

static int io_apic_get_redir_entries(int ioapic)
{
	union IO_APIC_reg_01	reg_01;

	guard(raw_spinlock_irqsave)(&ioapic_lock);
	reg_01.raw = io_apic_read(ioapic, 1);

	/*
	 * The register returns the maximum index redir index supported,
	 * which is one less than the total number of redir entries.
	 */
	return reg_01.bits.entries + 1;
}

unsigned int arch_dynirq_lower_bound(unsigned int from)
{
	unsigned int ret;

	/*
	 * dmar_alloc_hwirq() may be called before setup_IO_APIC(), so use
	 * gsi_top if ioapic_dynirq_base hasn't been initialized yet.
	 */
	ret = ioapic_dynirq_base ? : gsi_top;

	/*
	 * For DT enabled machines ioapic_dynirq_base is irrelevant and
	 * always 0. gsi_top can be 0 if there is no IO/APIC registered.
	 * 0 is an invalid interrupt number for dynamic allocations. Return
	 * @from instead.
	 */
	return ret ? : 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;
	int i = 0;

	/* Initialize the ID map */
	if (bitmap_empty(apic_id_map, MAX_LOCAL_APIC))
		copy_phys_cpu_present_map(apic_id_map);

	scoped_guard (raw_spinlock_irqsave, &ioapic_lock)
		reg_00.raw = io_apic_read(ioapic, 0);

	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;

		scoped_guard (raw_spinlock_irqsave, &ioapic_lock) {
			io_apic_write(ioapic, 0, reg_00.raw);
			reg_00.raw = io_apic_read(ioapic, 0);
		}

		/* Sanity check */
		if (reg_00.bits.ID != apic_id) {
			pr_err("IOAPIC[%d]: Unable to change apic_id!\n", ioapic);
			return -1;
		}
	}

	apic_pr_verbose("IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id);

	return apic_id;

Annotation

Implementation Notes