Commit aaecce4b authored by Charles E. Youse's avatar Charles E. Youse Committed by Anas Nashif
Browse files

drivers/loapic_intr.c: clean up local APIC access



Use new x2APIC-aware accessor functions in loapic.h instead of
locally-defined ones. Remove bitrot #defines (no longer used)
and extraneous comments with information from old data sheets.

Signed-off-by: default avatarCharles E. Youse <charles.youse@intel.com>
parent 53b370a7
Loading
Loading
Loading
Loading
+24 −148
Original line number Diff line number Diff line
/*
 * Copyright (c) 1984-2008, 2011-2015 Wind River Systems, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file
 * @brief LoApicIntr.c - Intel Pentium[234] Local APIC/xAPIC driver
 *
 * This module is a driver for the local APIC/xAPIC (Advanced Programmable
 * Interrupt Controller) in P6 (PentiumPro, II, III) family processors
 * and P7 (Pentium4) family processors.  The local APIC/xAPIC is included
 * in selected P6 (PentiumPro, II, III) and P7 (Pentium4) family processors.
 * Beginning with the P6 family processors, the presence or absence of an
 * on-chip local APIC can be detected using the CPUID instruction.  When the
 * CPUID instruction is executed, bit 9 of the feature flags returned in the
 * EDX register indicates the presence (set) or absence (clear) of an on-chip
 * local APIC.
 *
 * The local APIC performs two main functions for the processor:
 *  - It processes local external interrupts that the processor receives at its
 *    interrupt pins and local internal interrupts that software generates.
 *  - It communicates with an external IO APIC
 *    chip.  The external IO APIC receives external interrupt events from
 *    peripheral and direct them to the local APIC.  The IO APIC is
 *    part of Intel's system chip set.
 * The local APIC controls the dispatching of interrupts (to its associated
 * processor) that it receives either locally or from the IO APIC.  It provides
 * facilities for queuing, nesting and masking of interrupts.  It handles the
 * interrupt delivery protocol with its local processor and accesses to APIC
 * registers.
 * A timer on the local APIC allows local generation of interrupts, and
 * local interrupt pins permit local reception of processor-specific interrupts.
 * The local APIC can be disabled and used in conjunction with a standard 8259A
 * style interrupt controller.  Disabling the local APIC can be done in hardware
 * for the Pentium processors or in software for the P6 and P7 (Pentium4) family
 * processors.
 *
 * The local APIC in the Pentium4 processors (called the xAPIC) is an extension
 * of the local APIC found in the P6 family processors.  The primary difference
 * between the APIC architecture and xAPIC architecture is that with Pentium4
 * processors, the local xAPICs and IO xAPIC communicate with one another
 * through the processors system bus; whereas, with the P6 family processors,
 * communication between the local APICs and the IO APIC is handled through a
 * dedicated 3-wire APIC bus.  Also, some of the architectural features of the
 * local APIC have been extended and/or modified in the local xAPIC.
 *
 * This driver contains three routines for use.  They are:
 * z_loapic_init() initializes the Local APIC for the interrupt mode chosen.
 * _loapic_enable()/disable() enables / disables the Local APIC.
 *
 * Local APIC is used in the Virtual Wire Mode: delivery mode ExtINT.
 *
 * Virtual Wire Mode is one of three interrupt modes defined by the MP
 * specification.  In this mode, interrupts are generated by the 8259A
 * equivalent PICs (if present) and delivered to the Boot Strap Processor by
 * the local APIC that is programmed to act as a "virtual Wire"; that
 * is, the local APIC is logically indistinguishable from a hardware
 * connection.  This is a uniprocessor compatibility mode.
 *
 * The local and IO APICs support interrupts in the range of 32 to 255.
 * Interrupt priority is implied by its vector, according to the following
 * relationship:  "priority = vector / 16".
 * Here the quotient is rounded down to the nearest integer value to determine
 * the priority, with 1 being the lowest and 15 is the highest.  Because vectors
 * 0 through 31 are reserved for exclusive use by the processor, the priority of
 * user defined interrupts range from 2 to 15.  A value of 15 in the Interrupt
 * Class field of the Task Priority Register (TPR) will mask off all interrupts,
 * which require interrupt service.
 * The P6 family processor's local APIC includes an in-service entry and a
 * holding entry for each priority level.  To avoid losing interrupts, software
 * should allocate no more than 2 interrupt vectors per priority.  The Pentium4
 * processor expands this support of all acceptance of two interrupts per vector
 * rather than per priority level.
 *
 * INCLUDE FILES: loapic.h
/*
 * driver for x86 CPU local APIC (as an interrupt controller)
 */

#include <kernel.h>
@@ -90,15 +20,6 @@
#include <init.h>
#include <drivers/sysapic.h>

/* IA32_APIC_BASE MSR Bits */

#define LOAPIC_BASE_MASK 0xfffff000     /* LO APIC Base Addr mask */
#define LOAPIC_GLOBAL_ENABLE 0x00000800 /* LO APIC Global Enable */

/* Local APIC ID Register Bits */

#define LOAPIC_ID_MASK 0x0f000000 /* LO APIC ID mask */

/* Local APIC Version Register Bits */

#define LOAPIC_VERSION_MASK 0x000000ff /* LO APIC Version mask */
@@ -129,33 +50,6 @@
#define LOAPIC_ENABLE 0x100	/* APIC Enabled */
#define LOAPIC_FOCUS_DISABLE 0x200 /* Focus Processor Checking */

/* Local Vector's lock-unlock macro used in loApicIntLock/Unlock */

#define LOCKED_TIMER 0x01
#define LOCKED_PMC 0x02
#define LOCKED_LINT0 0x04
#define LOCKED_LINT1 0x08
#define LOCKED_ERROR 0x10
#define LOCKED_THERMAL 0x20

/* Interrupt Command Register: delivery mode and status */

#define MODE_FIXED 0x0     /* delivery mode: Fixed */
#define MODE_LOWEST 0x1    /* delivery mode: Lowest */
#define MODE_SMI 0x2       /* delivery mode: SMI */
#define MODE_NMI 0x4       /* delivery mode: NMI */
#define MODE_INIT 0x5      /* delivery mode: INIT */
#define MODE_STARTUP 0x6   /* delivery mode: StartUp */
#define STATUS_PEND 0x1000 /* delivery status: Pend */

/* IMCR related bits */

#define IMCR_ADRS 0x22       /* IMCR addr reg */
#define IMCR_DATA 0x23       /* IMCR data reg */
#define IMCR_REG_SEL 0x70    /* IMCR reg select */
#define IMCR_IOAPIC_ON 0x01  /* IMCR IOAPIC route enable */
#define IMCR_IOAPIC_OFF 0x00 /* IMCR IOAPIC route disable */

#if CONFIG_LOAPIC_SPURIOUS_VECTOR_ID == -1
#define LOAPIC_SPURIOUS_VECTOR_ID (CONFIG_IDT_NUM_VECTORS - 1)
#else
@@ -170,24 +64,6 @@ u32_t loapic_suspend_buf[LOPIC_SUSPEND_BITS_REQD / 32] = {0};
static u32_t loapic_device_power_state = DEVICE_PM_ACTIVE_STATE;
#endif

static ALWAYS_INLINE u32_t LOAPIC_READ(mem_addr_t addr)
{
#ifndef CONFIG_X2APIC
	return sys_read32(CONFIG_LOAPIC_BASE_ADDRESS + addr);
#else
	return read_x2apic(addr >> 4);
#endif
}

static ALWAYS_INLINE void LOAPIC_WRITE(mem_addr_t addr, u32_t data)
{
#ifndef CONFIG_X2APIC
	sys_write32(data, CONFIG_LOAPIC_BASE_ADDRESS + addr);
#else
	write_x2apic(addr >> 4, data);
#endif
}

/**
 *
 * @brief Initialize the Local APIC or xAPIC
@@ -204,18 +80,18 @@ static int loapic_init(struct device *unused)
	s32_t loApicMaxLvt; /* local APIC Max LVT */

	/* enable the Local APIC */
	LOAPIC_WRITE(LOAPIC_SVR, LOAPIC_READ(LOAPIC_SVR) | LOAPIC_ENABLE);
	loApicMaxLvt = (LOAPIC_READ(LOAPIC_VER) & LOAPIC_MAXLVT_MASK) >> 16;
	x86_write_loapic(LOAPIC_SVR, x86_read_loapic(LOAPIC_SVR) | LOAPIC_ENABLE);
	loApicMaxLvt = (x86_read_loapic(LOAPIC_VER) & LOAPIC_MAXLVT_MASK) >> 16;

	/* reset the DFR, TPR, TIMER_CONFIG, and TIMER_ICR */

#ifndef CONFIG_X2APIC
	LOAPIC_WRITE(LOAPIC_DFR, 0xffffffff);	/* no DFR in x2APIC mode */
	x86_write_loapic(LOAPIC_DFR, 0xffffffff);  /* no DFR in x2APIC mode */
#endif

	LOAPIC_WRITE(LOAPIC_TPR, 0x0);
	LOAPIC_WRITE(LOAPIC_TIMER_CONFIG, 0x0);
	LOAPIC_WRITE(LOAPIC_TIMER_ICR, 0x0);
	x86_write_loapic(LOAPIC_TPR, 0x0);
	x86_write_loapic(LOAPIC_TIMER_CONFIG, 0x0);
	x86_write_loapic(LOAPIC_TIMER_ICR, 0x0);

	/* program Local Vector Table for the Virtual Wire Mode */

@@ -224,33 +100,33 @@ static int loapic_init(struct device *unused)
	 */
	/* set LINT0: extInt, high-polarity, edge-trigger, not-masked */

	LOAPIC_WRITE(LOAPIC_LINT0, (LOAPIC_READ(LOAPIC_LINT0) &
	x86_write_loapic(LOAPIC_LINT0, (x86_read_loapic(LOAPIC_LINT0) &
		~(LOAPIC_MODE | LOAPIC_LOW |
		  LOAPIC_LEVEL | LOAPIC_LVT_MASKED)) |
		(LOAPIC_EXT | LOAPIC_HIGH | LOAPIC_EDGE));

	/* set LINT1: NMI, high-polarity, edge-trigger, not-masked */

	LOAPIC_WRITE(LOAPIC_LINT1, (LOAPIC_READ(LOAPIC_LINT1) &
	x86_write_loapic(LOAPIC_LINT1, (x86_read_loapic(LOAPIC_LINT1) &
		~(LOAPIC_MODE | LOAPIC_LOW |
		  LOAPIC_LEVEL | LOAPIC_LVT_MASKED)) |
		(LOAPIC_NMI | LOAPIC_HIGH | LOAPIC_EDGE));

	/* lock the Local APIC interrupts */

	LOAPIC_WRITE(LOAPIC_TIMER, LOAPIC_LVT_MASKED);
	LOAPIC_WRITE(LOAPIC_ERROR, LOAPIC_LVT_MASKED);
	x86_write_loapic(LOAPIC_TIMER, LOAPIC_LVT_MASKED);
	x86_write_loapic(LOAPIC_ERROR, LOAPIC_LVT_MASKED);

	if (loApicMaxLvt >= LOAPIC_LVT_P6) {
		LOAPIC_WRITE(LOAPIC_PMC, LOAPIC_LVT_MASKED);
		x86_write_loapic(LOAPIC_PMC, LOAPIC_LVT_MASKED);
	}

	if (loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) {
		LOAPIC_WRITE(LOAPIC_THERMAL, LOAPIC_LVT_MASKED);
		x86_write_loapic(LOAPIC_THERMAL, LOAPIC_LVT_MASKED);
	}

#if CONFIG_LOAPIC_SPURIOUS_VECTOR
	LOAPIC_WRITE(LOAPIC_SVR, (LOAPIC_READ(LOAPIC_SVR) & 0xFFFFFF00) |
	x86_write_loapic(LOAPIC_SVR, (x86_read_loapic(LOAPIC_SVR) & 0xFFFFFF00) |
		     (LOAPIC_SPURIOUS_VECTOR_ID & 0xFF));
#endif

@@ -258,7 +134,7 @@ static int loapic_init(struct device *unused)
#if CONFIG_EOI_FORWARDING_BUG
	z_lakemont_eoi();
#else
	LOAPIC_WRITE(LOAPIC_EOI, 0);
	x86_write_loapic(LOAPIC_EOI, 0);
#endif

	return 0;
@@ -295,8 +171,8 @@ void z_loapic_int_vec_set(unsigned int irq, /* IRQ number of the interrupt */
	/* update the 'vector' bits in the LVT */

	oldLevel = irq_lock();
	LOAPIC_WRITE(LOAPIC_TIMER + (irq * 0x10),
		     (LOAPIC_READ(LOAPIC_TIMER + (irq * 0x10)) &
	x86_write_loapic(LOAPIC_TIMER + (irq * 0x10),
		     (x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) &
		      ~LOAPIC_VECTOR) | vector);
	irq_unlock(oldLevel);
}
@@ -324,8 +200,8 @@ void z_loapic_irq_enable(unsigned int irq)
	/* clear the mask bit in the LVT */

	oldLevel = irq_lock();
	LOAPIC_WRITE(LOAPIC_TIMER + (irq * 0x10),
		     LOAPIC_READ(LOAPIC_TIMER + (irq * 0x10)) &
	x86_write_loapic(LOAPIC_TIMER + (irq * 0x10),
		     x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) &
		     ~LOAPIC_LVT_MASKED);
	irq_unlock(oldLevel);
}
@@ -353,8 +229,8 @@ void z_loapic_irq_disable(unsigned int irq)
	/* set the mask bit in the LVT */

	oldLevel = irq_lock();
	LOAPIC_WRITE(LOAPIC_TIMER + (irq * 0x10),
		     LOAPIC_READ(LOAPIC_TIMER + (irq * 0x10)) |
	x86_write_loapic(LOAPIC_TIMER + (irq * 0x10),
		     x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) |
		     LOAPIC_LVT_MASKED);
	irq_unlock(oldLevel);
}
@@ -395,7 +271,7 @@ int __irq_controller_isr_vector_get(void)
	 * vectors
	 */
	for (block = 7; likely(block > 0); block--) {
		pReg = LOAPIC_READ(LOAPIC_ISR + (block * 0x10));
		pReg = x86_read_loapic(LOAPIC_ISR + (block * 0x10));
		if (pReg) {
			return (block * 32) + (find_msb_set(pReg) - 1);
		}
@@ -421,7 +297,7 @@ static int loapic_suspend(struct device *port)
			/* Since vector numbers are already present in RAM/ROM,
			 * We save only the mask bits here.
			 */
			lvt = LOAPIC_READ(LOAPIC_TIMER + (loapic_irq * 0x10));
			lvt = x86_read_loapic(LOAPIC_TIMER + (loapic_irq * 0x10));

			if ((lvt & LOAPIC_LVT_MASKED) == 0U) {
				sys_bitfield_set_bit((mem_addr_t)loapic_suspend_buf,