summaryrefslogtreecommitdiffstats
path: root/sys/amd64/amd64/apic_vector.S
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2015-02-09 21:00:56 +0000
committerkib <kib@FreeBSD.org>2015-02-09 21:00:56 +0000
commit0754f0eac9d97737274d7b77cb519abb250362b3 (patch)
treed2e88c87f150ce7e0dfe34e37fbc902c5f84fd8a /sys/amd64/amd64/apic_vector.S
parente83a0077986ede1b5481738b285a4612ca8636e1 (diff)
downloadFreeBSD-src-0754f0eac9d97737274d7b77cb519abb250362b3.zip
FreeBSD-src-0754f0eac9d97737274d7b77cb519abb250362b3.tar.gz
Add x2APIC support. Enable it by default if CPU is capable. The
hw.x2apic_enable tunable allows disabling it from the loader prompt. To closely repeat effects of the uncached memory ops when accessing registers in the xAPIC mode, the x2APIC writes to MSRs are preceeded by mfence, except for the EOI notifications. This is probably too strict, only ICR writes to send IPI require serialization to ensure that other CPUs see the previous actions when IPI is delivered. This may be changed later. In vmm justreturn IPI handler, call doreti_iret instead of doing iretd inline, to handle corner conditions. Note that the patch only switches LAPICs into x2APIC mode. It does not enables FreeBSD to support > 255 CPUs, which requires parsing x2APIC MADT entries and doing interrupts remapping, but is the required step on the way. Reviewed by: neel Tested by: pho (real hardware), neel (on bhyve) Discussed with: jhb, grehan Sponsored by: The FreeBSD Foundation MFC after: 2 months
Diffstat (limited to 'sys/amd64/amd64/apic_vector.S')
-rw-r--r--sys/amd64/amd64/apic_vector.S45
1 files changed, 32 insertions, 13 deletions
diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S
index 4c87b4e..d9f2724 100644
--- a/sys/amd64/amd64/apic_vector.S
+++ b/sys/amd64/amd64/apic_vector.S
@@ -39,6 +39,7 @@
#include "opt_smp.h"
#include <machine/asmacros.h>
+#include <machine/specialreg.h>
#include <x86/apicreg.h>
#include "assym.s"
@@ -49,6 +50,22 @@
#define LK
#endif
+ .text
+ SUPERALIGN_TEXT
+ /* End Of Interrupt to APIC */
+as_lapic_eoi:
+ cmpl $0,x2apic_mode
+ jne 1f
+ movq lapic_map,%rax
+ movl $0,LA_EOI(%rax)
+ ret
+1:
+ movl $MSR_APIC_EOI,%ecx
+ xorl %eax,%eax
+ xorl %edx,%edx
+ wrmsr
+ ret
+
/*
* I/O Interrupt Entry Point. Rather than having one entry point for
* each interrupt source, we use one entry point for each 32-bit word
@@ -62,15 +79,22 @@
IDTVEC(vec_name) ; \
PUSH_FRAME ; \
FAKE_MCOUNT(TF_RIP(%rsp)) ; \
- movq lapic, %rdx ; /* pointer to local APIC */ \
+ cmpl $0,x2apic_mode ; \
+ je 1f ; \
+ movl $(MSR_APIC_ISR0 + index),%ecx ; \
+ rdmsr ; \
+ jmp 2f ; \
+1: ; \
+ movq lapic_map, %rdx ; /* pointer to local APIC */ \
movl LA_ISR + 16 * (index)(%rdx), %eax ; /* load ISR */ \
+2: ; \
bsrl %eax, %eax ; /* index of highest set bit in ISR */ \
- jz 1f ; \
+ jz 3f ; \
addl $(32 * index),%eax ; \
movq %rsp, %rsi ; \
movl %eax, %edi ; /* pass the IRQ */ \
call lapic_handle_intr ; \
-1: ; \
+3: ; \
MEXITCOUNT ; \
jmp doreti
@@ -160,8 +184,7 @@ IDTVEC(xen_intr_upcall)
SUPERALIGN_TEXT
invltlb_ret:
- movq lapic, %rax
- movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */
+ call as_lapic_eoi
POP_FRAME
jmp doreti_iret
@@ -228,8 +251,7 @@ IDTVEC(invlcache)
IDTVEC(ipi_intr_bitmap_handler)
PUSH_FRAME
- movq lapic, %rdx
- movl $0, LA_EOI(%rdx) /* End Of Interrupt to APIC */
+ call as_lapic_eoi
FAKE_MCOUNT(TF_RIP(%rsp))
@@ -245,8 +267,7 @@ IDTVEC(ipi_intr_bitmap_handler)
IDTVEC(cpustop)
PUSH_FRAME
- movq lapic, %rax
- movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */
+ call as_lapic_eoi
call cpustop_handler
jmp doreti
@@ -260,8 +281,7 @@ IDTVEC(cpususpend)
PUSH_FRAME
call cpususpend_handler
- movq lapic, %rax
- movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */
+ call as_lapic_eoi
jmp doreti
/*
@@ -279,7 +299,6 @@ IDTVEC(rendezvous)
incq (%rax)
#endif
call smp_rendezvous_action
- movq lapic, %rax
- movl $0, LA_EOI(%rax) /* End Of Interrupt to APIC */
+ call as_lapic_eoi
jmp doreti
#endif /* SMP */
OpenPOWER on IntegriCloud