Page MenuHomeFreeBSD

D1943.id3912.diff
No OneTemporary

D1943.id3912.diff

Index: sys/x86/include/apicvar.h
===================================================================
--- sys/x86/include/apicvar.h
+++ sys/x86/include/apicvar.h
@@ -426,6 +426,7 @@
void xen_intr_handle_upcall(struct trapframe *frame);
extern int x2apic_mode;
+extern int lapic_eoi_suppression;
#ifdef _SYS_SYSCTL_H_
SYSCTL_DECL(_hw_apic);
Index: sys/x86/x86/io_apic.c
===================================================================
--- sys/x86/x86/io_apic.c
+++ sys/x86/x86/io_apic.c
@@ -97,6 +97,7 @@
u_int io_apic_id:4;
u_int io_intbase:8; /* System Interrupt base */
u_int io_numintr:8;
+ u_int io_haseoi:1;
volatile ioapic_t *io_addr; /* XXX: should use bus_space */
vm_paddr_t io_paddr;
STAILQ_ENTRY(ioapic) io_next;
@@ -134,10 +135,53 @@
SYSCTL_INT(_hw_apic, OID_AUTO, enable_extint, CTLFLAG_RDTUN, &enable_extint, 0,
"Enable the ExtINT pin in the first I/O APIC");
-static __inline void
-_ioapic_eoi_source(struct intsrc *isrc)
+static void
+_ioapic_eoi_source(struct intsrc *isrc, int locked)
{
+ struct ioapic_intsrc *src;
+ struct ioapic *io;
+ volatile uint32_t *apic_eoi;
+ uint32_t low1;
+
lapic_eoi();
+ if (!lapic_eoi_suppression)
+ return;
+ src = (struct ioapic_intsrc *)isrc;
+ if (src->io_edgetrigger)
+ return;
+ io = (struct ioapic *)isrc->is_pic;
+
+ /*
+ * Handle targeted EOI for level-triggered pins, if broadcast
+ * EOI suppression is supported by LAPICs.
+ */
+ if (io->io_haseoi) {
+ /*
+ * If IOAPIC has EOI Register, simply write vector
+ * number into the reg.
+ */
+ apic_eoi = (volatile uint32_t *)((volatile char *)
+ io->io_addr + IOAPIC_EOIR);
+ *apic_eoi = src->io_vector;
+ } else {
+ /*
+ * Otherwise, if IO-APIC is too old to provide EOIR,
+ * do what Intel did for the Linux kernel. Temporary
+ * switch the pin to edge-trigger and back, masking
+ * the pin during the trick.
+ */
+ if (!locked)
+ mtx_lock_spin(&icu_lock);
+ low1 = src->io_lowreg;
+ low1 &= ~IOART_TRGRLVL;
+ low1 |= IOART_TRGREDG | IOART_INTMSET;
+ ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(src->io_intpin),
+ low1);
+ ioapic_write(io->io_addr, IOAPIC_REDTBL_LO(src->io_intpin),
+ src->io_lowreg);
+ if (!locked)
+ mtx_unlock_spin(&icu_lock);
+ }
}
static u_int
@@ -230,7 +274,7 @@
}
if (eoi == PIC_EOI)
- _ioapic_eoi_source(isrc);
+ _ioapic_eoi_source(isrc, 1);
mtx_unlock_spin(&icu_lock);
}
@@ -239,7 +283,7 @@
ioapic_eoi_source(struct intsrc *isrc)
{
- _ioapic_eoi_source(isrc);
+ _ioapic_eoi_source(isrc, 0);
}
/*
@@ -545,6 +589,23 @@
io->io_addr = apic;
io->io_paddr = addr;
+ if (bootverbose) {
+ printf("ioapic%u: ver 0x%02x maxredir 0x%02x\n", io->io_id,
+ (value & IOART_VER_VERSION), (value & IOART_VER_MAXREDIR)
+ >> MAXREDIRSHIFT);
+ }
+ /*
+ * The summary information about IO-APIC versions is taken from
+ * the Linux kernel source:
+ * 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
+ * IO-APICs with version >= 0x20 have working EOIR register.
+ */
+ if ((value & IOART_VER_VERSION) >= 0x20)
+ io->io_haseoi = 1;
+
/*
* Initialize pins. Start off with interrupts disabled. Default
* to active-hi and edge-triggered for ISA interrupts and active-lo
Index: sys/x86/x86/local_apic.c
===================================================================
--- sys/x86/x86/local_apic.c
+++ sys/x86/x86/local_apic.c
@@ -159,11 +159,14 @@
volatile char *lapic_map;
vm_paddr_t lapic_paddr;
int x2apic_mode;
+int lapic_eoi_suppression;
static u_long lapic_timer_divisor;
static struct eventtimer lapic_et;
SYSCTL_NODE(_hw, OID_AUTO, apic, CTLFLAG_RD, 0, "APIC options");
SYSCTL_INT(_hw_apic, OID_AUTO, x2apic_mode, CTLFLAG_RD, &x2apic_mode, 0, "");
+SYSCTL_INT(_hw_apic, OID_AUTO, eoi_suppression, CTLFLAG_RD,
+ &lapic_eoi_suppression, 0, "");
static uint32_t
lapic_read32(enum LAPIC_REGISTERS reg)
@@ -380,6 +383,7 @@
static void
native_lapic_init(vm_paddr_t addr)
{
+ uint32_t ver;
u_int regs[4];
int i, arat;
@@ -443,6 +447,20 @@
lapic_et.et_priv = NULL;
et_register(&lapic_et);
}
+
+ /*
+ * Set lapic_eoi_suppression after lapic_enable(), to not
+ * enable suppression in the hardware prematurely. Note that
+ * we by default enable suppression even when system only has
+ * one IO-APIC, since EOI is broadcasted to all APIC agents,
+ * including CPUs, otherwise.
+ */
+ ver = lapic_read32(LAPIC_VERSION);
+ if ((ver & APIC_VER_EOI_SUPPRESSION) != 0) {
+ lapic_eoi_suppression = 1;
+ TUNABLE_INT_FETCH("hw.lapic_eoi_suppression",
+ &lapic_eoi_suppression);
+ }
}
/*
@@ -755,6 +773,8 @@
value = lapic_read32(LAPIC_SVR);
value &= ~(APIC_SVR_VECTOR | APIC_SVR_FOCUS);
value |= APIC_SVR_FEN | APIC_SVR_SWEN | APIC_SPURIOUS_INT;
+ if (lapic_eoi_suppression)
+ value |= APIC_SVR_EOI_SUPPRESSION;
lapic_write32(LAPIC_SVR, value);
}
@@ -1562,8 +1582,10 @@
return;
#endif
/*
- * Finish setting up the local APIC on the BSP once we know how to
- * properly program the LINT pins.
+ * Finish setting up the local APIC on the BSP once we know
+ * how to properly program the LINT pins. In particular, this
+ * enables the EOI suppression mode, if LAPIC support it and
+ * user did not disabled the mode.
*/
lapic_setup(1);
if (bootverbose)

File Metadata

Mime Type
text/plain
Expires
Thu, Apr 2, 5:24 AM (6 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30707365
Default Alt Text
D1943.id3912.diff (5 KB)

Event Timeline