summaryrefslogtreecommitdiffstats
path: root/sys/amd64
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/amd64
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/amd64')
-rw-r--r--sys/amd64/amd64/io_apic.c73
-rw-r--r--sys/amd64/amd64/local_apic.c2
-rw-r--r--sys/amd64/include/apicvar.h2
3 files changed, 77 insertions, 0 deletions
diff --git a/sys/amd64/amd64/io_apic.c b/sys/amd64/amd64/io_apic.c
index 4bf4161..88b8d4c 100644
--- a/sys/amd64/amd64/io_apic.c
+++ b/sys/amd64/amd64/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,73 @@ 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;
+
+ 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/amd64/amd64/local_apic.c b/sys/amd64/amd64/local_apic.c
index 0fe1ffe..04ff976 100644
--- a/sys/amd64/amd64/local_apic.c
+++ b/sys/amd64/amd64/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_SYSIGT, SEL_KPL, 0);
/* Perform basic initialization of the BSP's local APIC. */
diff --git a/sys/amd64/include/apicvar.h b/sys/amd64/include/apicvar.h
index 6836c10..9ffe17c 100644
--- a/sys/amd64/include/apicvar.h
+++ b/sys/amd64/include/apicvar.h
@@ -174,6 +174,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