summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-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
6 files changed, 162 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);
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