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.
This commit is contained in:
jhb 2007-03-20 21:53:31 +00:00
parent febce07b18
commit fe7d05b231
6 changed files with 162 additions and 0 deletions

View File

@ -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);

View File

@ -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. */

View File

@ -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);

View File

@ -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);

View File

@ -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));

View File

@ -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);