ron minnich has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/43323 )
Change subject: libpayload: allow nonblocking delay and more than one delay ......................................................................
libpayload: allow nonblocking delay and more than one delay
Extend the local APIC timer delay so that it can be started, and waited for, independently.
Add an EOI so that more than one APIC interrupt is possible.
Change-Id: Ib11aeee5b7da81287166ac68fc327e7ae62d1b84 Signed-off-by: Ronald G Minnich rminnich@gmail.com --- M payloads/libpayload/arch/x86/apic.c M payloads/libpayload/include/x86/arch/apic.h 2 files changed, 29 insertions(+), 2 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/23/43323/1
diff --git a/payloads/libpayload/arch/x86/apic.c b/payloads/libpayload/arch/x86/apic.c index a484163..ba7ab99 100644 --- a/payloads/libpayload/arch/x86/apic.c +++ b/payloads/libpayload/arch/x86/apic.c @@ -71,7 +71,7 @@ static int _apic_initialized; // TODO: Build a lookup table to avoid calculating it. static uint32_t ticks_per_ms; -static volatile uint8_t timer_waiting; +volatile uint8_t timer_waiting;
enum APIC_CAPABILITY { DISABLED = 0, @@ -104,7 +104,7 @@ return id; }
-void apic_delay(unsigned int usec) +void apic_start_delay(unsigned int usec) { die_if(!ticks_per_ms, "apic_init_timer was not run."); die_if(timer_waiting, "timer already started."); @@ -124,7 +124,12 @@ timer_waiting = 1;
apic_write32(APIC_TIMER_INIT_COUNT, ticks); + enable_interrupts(); +}
+ +void apic_wait_delay(void) +{ /* Loop in case another interrupt has fired and resumed execution. */ do { asm volatile( @@ -140,9 +145,16 @@ enable_interrupts(); }
+void apic_delay(unsigned int usec) +{ + apic_start_delay(usec); + apic_wait_delay(); +} + static void timer_interrupt_handler(u8 vector) { timer_waiting = 0; + apic_eoi(APIC_TIMER_VECTOR); }
static void suprious_interrupt_handler(u8 vector) {} @@ -204,6 +216,7 @@ uint8_t max = apic_max_lvt_entries(); for (int i = 0; i <= max; ++i) { uint32_t offset = APIC_LVT_TIMER + APIC_LVT_SIZE * i; + apic_eoi(i); apic_write32(offset, APIC_MASKED_BIT); } } @@ -248,6 +261,16 @@ apic_write32(APIC_LVT_TIMER, APIC_TIMER_VECTOR); }
+static void apic_sw_disable(void) +{ + uint32_t reg = apic_read32(APIC_SPURIOUS); + + reg &= ~APIC_SW_ENABLED_BIT; + printf("%s: writing %#x to %#x\n", __func__, reg, APIC_SPURIOUS); + + apic_write32(APIC_SPURIOUS, reg); +} + static void apic_sw_enable(void) { uint32_t reg = apic_read32(APIC_SPURIOUS); @@ -280,6 +303,7 @@ die_if(!(apic_capabilities() & XACPI), "APIC is not supported");
apic_bar_reg = _rdmsr(APIC_BASE_MSR); + printf("apic_bar_reg is 0x%llx\n", apic_bar_reg);
die_if(!(apic_bar_reg & XAPIC_ENABLED_BIT), "APIC is not enabled"); die_if(apic_bar_reg & X2APIC_ENABLED_BIT, @@ -287,6 +311,7 @@
apic_bar = (uint32_t)(apic_bar_reg & APIC_BASE_MASK);
+ apic_sw_disable(); apic_reset_all_lvts(); apic_set_task_priority(0); apic_setup_spurious(); diff --git a/payloads/libpayload/include/x86/arch/apic.h b/payloads/libpayload/include/x86/arch/apic.h index 3c9877c..eedf1b4 100644 --- a/payloads/libpayload/include/x86/arch/apic.h +++ b/payloads/libpayload/include/x86/arch/apic.h @@ -40,5 +40,7 @@ void apic_eoi(uint8_t vector);
void apic_delay(unsigned int usec); +void apic_start_delay(unsigned int usec); +void apic_wait_delay(void);
#endif /* __ARCH_X86_INCLUDES_ARCH_APIC_H__ */