summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2007-03-20 21:53:31 +0000
committerjhb <jhb@FreeBSD.org>2007-03-20 21:53:31 +0000
commitfe7d05b231c935abbf199439d062b19e25bab744 (patch)
tree1e90fdec85dd7dca5c495360ce21ff3544537810 /sys/i386
parentfebce07b1841a6b5680a436c04a0e6ea67af094a (diff)
downloadFreeBSD-src-fe7d05b231c935abbf199439d062b19e25bab744.zip
FreeBSD-src-fe7d05b231c935abbf199439d062b19e25bab744.tar.gz
Add a new apic0 psuedo-device to claim memory resources for the memory
address ranges used by local and I/O APICs in the system. Some systems also reserve these ranges as system resources via either PnPBIOS or ACPI, so this device currently attaches after acpi0 and legacy0 so that the system resources are given precedence.
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/i386/io_apic.c81
-rw-r--r--sys/i386/i386/local_apic.c2
-rw-r--r--sys/i386/include/apicvar.h2
3 files changed, 85 insertions, 0 deletions
diff --git a/sys/i386/i386/io_apic.c b/sys/i386/i386/io_apic.c
index 86dba89..bccacd8 100644
--- a/sys/i386/i386/io_apic.c
+++ b/sys/i386/i386/io_apic.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <machine/frame.h>
#include <machine/intr_machdep.h>
#include <machine/apicvar.h>
+#include <machine/resource.h>
#include <machine/segments.h>
#define IOAPIC_ISA_INTS 16
@@ -100,6 +101,7 @@ struct ioapic {
u_int io_intbase:8; /* System Interrupt base */
u_int io_numintr:8;
volatile ioapic_t *io_addr; /* XXX: should use bus_space */
+ vm_paddr_t io_paddr;
STAILQ_ENTRY(ioapic) io_next;
struct ioapic_intsrc io_pins[0];
};
@@ -479,6 +481,7 @@ ioapic_create(vm_paddr_t addr, int32_t apic_id, int intbase)
next_ioapic_base = intbase + numintr;
io->io_numintr = numintr;
io->io_addr = apic;
+ io->io_paddr = addr;
/*
* Initialize pins. Start off with interrupts disabled. Default
@@ -774,3 +777,81 @@ DEFINE_CLASS_0(ioapic, ioapic_pci_driver, ioapic_pci_methods, 0);
static devclass_t ioapic_devclass;
DRIVER_MODULE(ioapic, pci, ioapic_pci_driver, ioapic_devclass, 0, 0);
+
+/*
+ * A new-bus driver to consume the memory resources associated with
+ * the APICs in the system. On some systems ACPI or PnPBIOS system
+ * resource devices may already claim these resources. To keep from
+ * breaking those devices, we attach ourself to the nexus device after
+ * legacy0 and acpi0 and ignore any allocation failures.
+ */
+static void
+apic_identify(driver_t *driver, device_t parent)
+{
+
+ /*
+ * Add at order 12. acpi0 is probed at order 10 and legacy0
+ * is probed at order 11.
+ */
+ if (lapic_paddr != 0)
+ BUS_ADD_CHILD(parent, 12, "apic", 0);
+}
+
+static int
+apic_probe(device_t dev)
+{
+
+ device_set_desc(dev, "APIC resources");
+ device_quiet(dev);
+ return (0);
+}
+
+static void
+apic_add_resource(device_t dev, int rid, vm_paddr_t base, size_t length)
+{
+ int error;
+
+#ifdef PAE
+ /*
+ * Resources use long's to track resources, so we can't
+ * include memory regions above 4GB.
+ */
+ if (base >= ~0ul)
+ return;
+#endif
+ error = bus_set_resource(dev, SYS_RES_MEMORY, rid, base, length);
+ if (error)
+ panic("apic_add_resource: resource %d failed set with %d", rid,
+ error);
+ bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 0);
+}
+
+static int
+apic_attach(device_t dev)
+{
+ struct ioapic *io;
+ int i;
+
+ /* Reserve the local APIC. */
+ apic_add_resource(dev, 0, lapic_paddr, sizeof(lapic_t));
+ i = 1;
+ STAILQ_FOREACH(io, &ioapic_list, io_next) {
+ apic_add_resource(dev, i, io->io_paddr, IOAPIC_MEM_REGION);
+ i++;
+ }
+ return (0);
+}
+
+static device_method_t apic_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_identify, apic_identify),
+ DEVMETHOD(device_probe, apic_probe),
+ DEVMETHOD(device_attach, apic_attach),
+
+ { 0, 0 }
+};
+
+DEFINE_CLASS_0(apic, apic_driver, apic_methods, 0);
+
+static devclass_t apic_devclass;
+DRIVER_MODULE(apic, nexus, apic_driver, apic_devclass, 0, 0);
diff --git a/sys/i386/i386/local_apic.c b/sys/i386/i386/local_apic.c
index 6b6d561..dfab397 100644
--- a/sys/i386/i386/local_apic.c
+++ b/sys/i386/i386/local_apic.c
@@ -148,6 +148,7 @@ static u_int32_t lapic_timer_divisors[] = {
};
volatile lapic_t *lapic;
+vm_paddr_t lapic_paddr;
static u_long lapic_timer_divisor, lapic_timer_period, lapic_timer_hz;
static void lapic_enable(void);
@@ -212,6 +213,7 @@ lapic_init(vm_paddr_t addr)
KASSERT(trunc_page(addr) == addr,
("local APIC not aligned on a page boundary"));
lapic = pmap_mapdev(addr, sizeof(lapic_t));
+ lapic_paddr = addr;
setidt(APIC_SPURIOUS_INT, IDTVEC(spuriousint), SDT_SYS386IGT, SEL_KPL,
GSEL(GCODE_SEL, SEL_KPL));
diff --git a/sys/i386/include/apicvar.h b/sys/i386/include/apicvar.h
index 23f83b2..00339b4 100644
--- a/sys/i386/include/apicvar.h
+++ b/sys/i386/include/apicvar.h
@@ -173,6 +173,8 @@ inthand_t
IDTVEC(apic_isr4), IDTVEC(apic_isr5), IDTVEC(apic_isr6),
IDTVEC(apic_isr7), IDTVEC(spuriousint), IDTVEC(timerint);
+extern vm_paddr_t lapic_paddr;
+
u_int apic_alloc_vector(u_int irq);
u_int apic_alloc_vectors(u_int *irqs, u_int count, u_int align);
void apic_enable_vector(u_int vector);
OpenPOWER on IntegriCloud