mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-14 10:09:48 +00:00
MFi386: numerous interrupt and acpi updates
This commit is contained in:
parent
4d6bcc8306
commit
463e5aa66e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=129284
@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/specialreg.h>
|
||||
|
||||
#include "acpi.h"
|
||||
#include <contrib/dev/acpica/actables.h>
|
||||
#include <dev/acpica/acpivar.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
@ -69,14 +70,15 @@ struct lapic_info {
|
||||
u_int la_apic_id:8;
|
||||
} lapics[NLAPICS + 1];
|
||||
|
||||
static int madt_found_sci_override;
|
||||
static MULTIPLE_APIC_TABLE *madt;
|
||||
static vm_paddr_t madt_physaddr;
|
||||
static vm_offset_t madt_length;
|
||||
|
||||
MALLOC_DEFINE(M_MADT, "MADT Table", "ACPI MADT Table Items");
|
||||
|
||||
static u_char interrupt_polarity(UINT16 Polarity);
|
||||
static u_char interrupt_trigger(UINT16 TriggerMode);
|
||||
static enum intr_polarity interrupt_polarity(UINT16 Polarity, UINT8 Source);
|
||||
static enum intr_trigger interrupt_trigger(UINT16 TriggerMode, UINT8 Source);
|
||||
static int madt_find_cpu(u_int acpi_id, u_int *apic_id);
|
||||
static int madt_find_interrupt(int intr, void **apic, u_int *pin);
|
||||
static void *madt_map(vm_paddr_t pa, int offset, vm_offset_t length);
|
||||
@ -157,6 +159,7 @@ madt_map_table(vm_paddr_t pa, int offset, const char *sig)
|
||||
{
|
||||
ACPI_TABLE_HEADER *header;
|
||||
vm_offset_t length;
|
||||
void *table;
|
||||
|
||||
header = madt_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
|
||||
if (strncmp(header->Signature, sig, 4) != 0) {
|
||||
@ -165,7 +168,14 @@ madt_map_table(vm_paddr_t pa, int offset, const char *sig)
|
||||
}
|
||||
length = header->Length;
|
||||
madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
|
||||
return (madt_map(pa, offset, length));
|
||||
table = madt_map(pa, offset, length);
|
||||
if (ACPI_FAILURE(AcpiTbVerifyTableChecksum(table))) {
|
||||
if (bootverbose)
|
||||
printf("MADT: Failed checksum for table %s\n", sig);
|
||||
madt_unmap(table, length);
|
||||
return (NULL);
|
||||
}
|
||||
return (table);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -215,6 +225,16 @@ madt_probe(void)
|
||||
* Page 0 is used to map in the headers of candidate ACPI tables.
|
||||
*/
|
||||
if (rsdp->Revision >= 2) {
|
||||
/*
|
||||
* AcpiOsGetRootPointer only verifies the checksum for
|
||||
* the version 1.0 portion of the RSDP. Version 2.0 has
|
||||
* an additional checksum that we verify first.
|
||||
*/
|
||||
if (AcpiTbChecksum(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0) {
|
||||
if (bootverbose)
|
||||
printf("MADT: RSDP failed extended checksum\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
xsdt = madt_map_table(rsdp->XsdtPhysicalAddress, 1, XSDT_SIG);
|
||||
if (xsdt == NULL) {
|
||||
if (bootverbose)
|
||||
@ -251,6 +271,16 @@ madt_probe(void)
|
||||
printf("MADT: Found table at 0x%jx\n",
|
||||
(uintmax_t)madt_physaddr);
|
||||
|
||||
/*
|
||||
* Verify that we can map the full table and that its checksum is
|
||||
* correct, etc.
|
||||
*/
|
||||
madt = madt_map_table(madt_physaddr, 0, APIC_SIG);
|
||||
if (madt == NULL)
|
||||
return (ENXIO);
|
||||
madt_unmap_table(madt);
|
||||
madt = NULL;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -273,7 +303,6 @@ madt_probe_table(vm_paddr_t address)
|
||||
printf("Table '%.4s' at 0x%jx\n", table->Signature,
|
||||
(uintmax_t)address);
|
||||
|
||||
/* XXX: Verify checksum? */
|
||||
if (strncmp(table->Signature, APIC_SIG, 4) != 0) {
|
||||
madt_unmap(table, sizeof(ACPI_TABLE_HEADER));
|
||||
return (0);
|
||||
@ -325,6 +354,8 @@ madt_setup_local(void)
|
||||
static int
|
||||
madt_setup_io(void)
|
||||
{
|
||||
void *ioapic;
|
||||
u_int pin;
|
||||
int i;
|
||||
|
||||
/* Try to initialize ACPI so that we can access the FADT. */
|
||||
@ -337,11 +368,30 @@ madt_setup_io(void)
|
||||
}
|
||||
|
||||
/* First, we run through adding I/O APIC's. */
|
||||
if (madt->PCATCompat)
|
||||
ioapic_enable_mixed_mode();
|
||||
madt_walk_table(madt_parse_apics, NULL);
|
||||
|
||||
/* Second, we run through the table tweaking interrupt sources. */
|
||||
madt_walk_table(madt_parse_ints, NULL);
|
||||
|
||||
/*
|
||||
* If there was not an explicit override entry for the SCI,
|
||||
* force it to use level trigger and active-low polarity.
|
||||
*/
|
||||
if (!madt_found_sci_override) {
|
||||
if (madt_find_interrupt(AcpiGbl_FADT->SciInt, &ioapic, &pin)
|
||||
!= 0)
|
||||
printf("MADT: Could not find APIC for SCI IRQ %d\n",
|
||||
AcpiGbl_FADT->SciInt);
|
||||
else {
|
||||
printf(
|
||||
"MADT: Forcing active-low polarity and level trigger for SCI\n");
|
||||
ioapic_set_polarity(ioapic, pin, INTR_POLARITY_LOW);
|
||||
ioapic_set_triggermode(ioapic, pin, INTR_TRIGGER_LEVEL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Third, we register all the I/O APIC's. */
|
||||
for (i = 0; i < NIOAPICS; i++)
|
||||
if (ioapics[i].io_apic != NULL)
|
||||
@ -446,35 +496,44 @@ madt_parse_apics(APIC_HEADER *entry, void *arg __unused)
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine properties of an interrupt source. Note that for ACPI,
|
||||
* these are only used for ISA interrupts, so we assume ISA bus values
|
||||
* (Active Hi, Edge Triggered) for conforming values.
|
||||
* Determine properties of an interrupt source. Note that for ACPI these
|
||||
* functions are only used for ISA interrupts, so we assume ISA bus values
|
||||
* (Active Hi, Edge Triggered) for conforming values except for the ACPI
|
||||
* SCI for which we use Active Lo, Level Triggered.
|
||||
*/
|
||||
static u_char
|
||||
interrupt_polarity(UINT16 Polarity)
|
||||
static enum intr_polarity
|
||||
interrupt_polarity(UINT16 Polarity, UINT8 Source)
|
||||
{
|
||||
|
||||
switch (Polarity) {
|
||||
case POLARITY_CONFORMS:
|
||||
if (Source == AcpiGbl_FADT->SciInt)
|
||||
return (INTR_POLARITY_LOW);
|
||||
else
|
||||
return (INTR_POLARITY_HIGH);
|
||||
case POLARITY_ACTIVE_HIGH:
|
||||
return (1);
|
||||
return (INTR_POLARITY_HIGH);
|
||||
case POLARITY_ACTIVE_LOW:
|
||||
return (0);
|
||||
return (INTR_POLARITY_LOW);
|
||||
default:
|
||||
panic("Bogus Interrupt Polarity");
|
||||
}
|
||||
}
|
||||
|
||||
static u_char
|
||||
interrupt_trigger(UINT16 TriggerMode)
|
||||
static enum intr_trigger
|
||||
interrupt_trigger(UINT16 TriggerMode, UINT8 Source)
|
||||
{
|
||||
|
||||
switch (TriggerMode) {
|
||||
case TRIGGER_CONFORMS:
|
||||
if (Source == AcpiGbl_FADT->SciInt)
|
||||
return (INTR_TRIGGER_LEVEL);
|
||||
else
|
||||
return (INTR_TRIGGER_EDGE);
|
||||
case TRIGGER_EDGE:
|
||||
return (1);
|
||||
return (INTR_TRIGGER_EDGE);
|
||||
case TRIGGER_LEVEL:
|
||||
return (0);
|
||||
return (INTR_TRIGGER_LEVEL);
|
||||
default:
|
||||
panic("Bogus Interrupt Trigger Mode");
|
||||
}
|
||||
@ -532,7 +591,9 @@ madt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr)
|
||||
{
|
||||
void *new_ioapic, *old_ioapic;
|
||||
u_int new_pin, old_pin;
|
||||
int force_lo;
|
||||
enum intr_trigger trig;
|
||||
enum intr_polarity pol;
|
||||
char buf[64];
|
||||
|
||||
if (bootverbose)
|
||||
printf("MADT: intr override: source %u, irq %u\n",
|
||||
@ -546,18 +607,46 @@ madt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr)
|
||||
}
|
||||
|
||||
/*
|
||||
* If the SCI is remapped to a non-ISA global interrupt,
|
||||
* force it to level trigger and active-lo polarity.
|
||||
* If the SCI is identity mapped but has edge trigger and
|
||||
* active-hi polarity, also force it to use level/lo.
|
||||
* Lookup the appropriate trigger and polarity modes for this
|
||||
* entry.
|
||||
*/
|
||||
force_lo = 0;
|
||||
if (intr->Source == AcpiGbl_FADT->SciInt)
|
||||
if (intr->Interrupt > 15 || (intr->Interrupt == intr->Source &&
|
||||
intr->TriggerMode == TRIGGER_EDGE &&
|
||||
intr->Polarity == POLARITY_ACTIVE_HIGH))
|
||||
force_lo = 1;
|
||||
trig = interrupt_trigger(intr->TriggerMode, intr->Source);
|
||||
pol = interrupt_polarity(intr->Polarity, intr->Source);
|
||||
|
||||
/*
|
||||
* If the SCI is identity mapped but has edge trigger and
|
||||
* active-hi polarity or the force_sci_lo tunable is set,
|
||||
* force it to use level/lo.
|
||||
*/
|
||||
if (intr->Source == AcpiGbl_FADT->SciInt) {
|
||||
madt_found_sci_override = 1;
|
||||
if (getenv_string("hw.acpi.sci.trigger", buf, sizeof(buf))) {
|
||||
if (tolower(buf[0]) == 'e')
|
||||
trig = INTR_TRIGGER_EDGE;
|
||||
else if (tolower(buf[0]) == 'l')
|
||||
trig = INTR_TRIGGER_LEVEL;
|
||||
else
|
||||
panic(
|
||||
"Invalid trigger %s: must be 'edge' or 'level'",
|
||||
buf);
|
||||
printf("MADT: Forcing SCI to %s trigger\n",
|
||||
trig == INTR_TRIGGER_EDGE ? "edge" : "level");
|
||||
}
|
||||
if (getenv_string("hw.acpi.sci.polarity", buf, sizeof(buf))) {
|
||||
if (tolower(buf[0]) == 'h')
|
||||
pol = INTR_POLARITY_HIGH;
|
||||
else if (tolower(buf[0]) == 'l')
|
||||
pol = INTR_POLARITY_LOW;
|
||||
else
|
||||
panic(
|
||||
"Invalid polarity %s: must be 'high' or 'low'",
|
||||
buf);
|
||||
printf("MADT: Forcing SCI to active %s polarity\n",
|
||||
pol == INTR_POLARITY_HIGH ? "high" : "low");
|
||||
}
|
||||
}
|
||||
|
||||
/* Remap the IRQ if it is mapped to a different interrupt vector. */
|
||||
if (intr->Source != intr->Interrupt) {
|
||||
/*
|
||||
* If the SCI is remapped to a non-ISA global interrupt,
|
||||
@ -577,18 +666,10 @@ madt_parse_interrupt_override(MADT_INTERRUPT_OVERRIDE *intr)
|
||||
intr->Source)
|
||||
ioapic_disable_pin(old_ioapic, old_pin);
|
||||
}
|
||||
if (force_lo) {
|
||||
printf(
|
||||
"MADT: Forcing active-lo polarity and level trigger for IRQ %d\n",
|
||||
intr->Source);
|
||||
ioapic_set_polarity(new_ioapic, new_pin, 0);
|
||||
ioapic_set_triggermode(new_ioapic, new_pin, 0);
|
||||
} else {
|
||||
ioapic_set_polarity(new_ioapic, new_pin,
|
||||
interrupt_polarity(intr->Polarity));
|
||||
ioapic_set_triggermode(new_ioapic, new_pin,
|
||||
interrupt_trigger(intr->TriggerMode));
|
||||
}
|
||||
|
||||
/* Program the polarity and trigger mode. */
|
||||
ioapic_set_triggermode(new_ioapic, new_pin, trig);
|
||||
ioapic_set_polarity(new_ioapic, new_pin, pol);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -609,10 +690,10 @@ madt_parse_nmi(MADT_NMI_SOURCE *nmi)
|
||||
ioapic_set_nmi(ioapic, pin);
|
||||
if (nmi->TriggerMode != TRIGGER_CONFORMS)
|
||||
ioapic_set_triggermode(ioapic, pin,
|
||||
interrupt_trigger(nmi->TriggerMode));
|
||||
interrupt_trigger(nmi->TriggerMode, 0));
|
||||
if (nmi->Polarity != TRIGGER_CONFORMS)
|
||||
ioapic_set_polarity(ioapic, pin,
|
||||
interrupt_polarity(nmi->Polarity));
|
||||
interrupt_polarity(nmi->Polarity, 0));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -638,10 +719,10 @@ madt_parse_local_nmi(MADT_LOCAL_APIC_NMI *nmi)
|
||||
lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI);
|
||||
if (nmi->TriggerMode != TRIGGER_CONFORMS)
|
||||
lapic_set_lvt_triggermode(apic_id, pin,
|
||||
interrupt_trigger(nmi->TriggerMode));
|
||||
interrupt_trigger(nmi->TriggerMode, 0));
|
||||
if (nmi->Polarity != POLARITY_CONFORMS)
|
||||
lapic_set_lvt_polarity(apic_id, pin,
|
||||
interrupt_polarity(nmi->Polarity));
|
||||
interrupt_polarity(nmi->Polarity, 0));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -138,6 +138,17 @@ intr_remove_handler(void *cookie)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
intr_config_intr(int vector, enum intr_trigger trig, enum intr_polarity pol)
|
||||
{
|
||||
struct intsrc *isrc;
|
||||
|
||||
isrc = intr_lookup_source(vector);
|
||||
if (isrc == NULL)
|
||||
return (EINVAL);
|
||||
return (isrc->is_pic->pic_config_intr(isrc, trig, pol));
|
||||
}
|
||||
|
||||
void
|
||||
intr_execute_handlers(struct intsrc *isrc, struct intrframe *iframe)
|
||||
{
|
||||
|
@ -51,10 +51,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/apicvar.h>
|
||||
#include <machine/segments.h>
|
||||
|
||||
#if defined(DEV_ISA) && defined(DEV_ATPIC) && !defined(NO_MIXED_MODE)
|
||||
#define MIXED_MODE
|
||||
#endif
|
||||
|
||||
#define IOAPIC_ISA_INTS 16
|
||||
#define IOAPIC_MEM_REGION 32
|
||||
#define IOAPIC_REDTBL_LO(i) (IOAPIC_REDTBL + (i) * 2)
|
||||
@ -117,9 +113,6 @@ struct ioapic {
|
||||
struct ioapic_intsrc io_pins[0];
|
||||
};
|
||||
|
||||
static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
|
||||
static u_int next_id, program_logical_dest;
|
||||
|
||||
static u_int ioapic_read(volatile ioapic_t *apic, int reg);
|
||||
static void ioapic_write(volatile ioapic_t *apic, int reg, u_int val);
|
||||
static void ioapic_enable_source(struct intsrc *isrc);
|
||||
@ -128,19 +121,28 @@ static void ioapic_eoi_source(struct intsrc *isrc);
|
||||
static void ioapic_enable_intr(struct intsrc *isrc);
|
||||
static int ioapic_vector(struct intsrc *isrc);
|
||||
static int ioapic_source_pending(struct intsrc *isrc);
|
||||
static int ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
|
||||
enum intr_polarity pol);
|
||||
static void ioapic_suspend(struct intsrc *isrc);
|
||||
static void ioapic_resume(struct intsrc *isrc);
|
||||
static void ioapic_program_destination(struct ioapic_intsrc *intpin);
|
||||
#ifdef MIXED_MODE
|
||||
static void ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin);
|
||||
#endif
|
||||
|
||||
static STAILQ_HEAD(,ioapic) ioapic_list = STAILQ_HEAD_INITIALIZER(ioapic_list);
|
||||
struct pic ioapic_template = { ioapic_enable_source, ioapic_disable_source,
|
||||
ioapic_eoi_source, ioapic_enable_intr,
|
||||
ioapic_vector, ioapic_source_pending,
|
||||
ioapic_suspend, ioapic_resume };
|
||||
ioapic_suspend, ioapic_resume,
|
||||
ioapic_config_intr };
|
||||
|
||||
static int next_ioapic_base, logical_clusters, current_cluster;
|
||||
static int current_cluster, logical_clusters, next_ioapic_base;
|
||||
static u_int mixed_mode_enabled, next_id, program_logical_dest;
|
||||
#if defined(NO_MIXED_MODE) || !defined(DEV_ATPIC)
|
||||
static int mixed_mode_active = 0;
|
||||
#else
|
||||
static int mixed_mode_active = 1;
|
||||
#endif
|
||||
TUNABLE_INT("hw.apic.mixed_mode", &mixed_mode_active);
|
||||
|
||||
static u_int
|
||||
ioapic_read(volatile ioapic_t *apic, int reg)
|
||||
@ -291,6 +293,41 @@ ioapic_source_pending(struct intsrc *isrc)
|
||||
return (lapic_intr_pending(intpin->io_vector));
|
||||
}
|
||||
|
||||
static int
|
||||
ioapic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
|
||||
enum intr_polarity pol)
|
||||
{
|
||||
struct ioapic_intsrc *intpin = (struct ioapic_intsrc *)isrc;
|
||||
struct ioapic *io = (struct ioapic *)isrc->is_pic;
|
||||
|
||||
KASSERT(!(trig == INTR_TRIGGER_CONFORM || pol == INTR_POLARITY_CONFORM),
|
||||
("%s: Conforming trigger or polarity\n", __func__));
|
||||
|
||||
/*
|
||||
* For now we ignore any requests but do output any changes that
|
||||
* would be made to the console it bootverbose is enabled. The only
|
||||
* known causes of these messages so far is a bug in acpi(4) that
|
||||
* causes the ISA IRQs used for PCI interrupts in PIC mode to be
|
||||
* set to level/low when they aren't being used. There are possibly
|
||||
* legitimate requests, so at some point when the acpi(4) driver is
|
||||
* fixed this code can be changed to actually change the intpin as
|
||||
* requested.
|
||||
*/
|
||||
if (!bootverbose)
|
||||
return (0);
|
||||
if (intpin->io_edgetrigger != (trig == INTR_TRIGGER_EDGE))
|
||||
printf(
|
||||
"ioapic%u: Request to change trigger for pin %u to %s ignored\n",
|
||||
io->io_id, intpin->io_intpin, trig == INTR_TRIGGER_EDGE ?
|
||||
"edge" : "level");
|
||||
if (intpin->io_activehi != (pol == INTR_POLARITY_HIGH))
|
||||
printf(
|
||||
"ioapic%u: Request to change polarity for pin %u to %s ignored\n",
|
||||
io->io_id, intpin->io_intpin, pol == INTR_POLARITY_HIGH ?
|
||||
"high" : "low");
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ioapic_suspend(struct intsrc *isrc)
|
||||
{
|
||||
@ -305,6 +342,17 @@ ioapic_resume(struct intsrc *isrc)
|
||||
TODO;
|
||||
}
|
||||
|
||||
/*
|
||||
* APIC enumerators call this function to indicate that the 8259A AT PICs
|
||||
* are available and that mixed mode can be used.
|
||||
*/
|
||||
void
|
||||
ioapic_enable_mixed_mode(void)
|
||||
{
|
||||
|
||||
mixed_mode_enabled = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate and return a logical cluster ID. Note that the first time
|
||||
* this is called, it returns cluster 0. ioapic_enable_intr() treats
|
||||
@ -380,14 +428,17 @@ ioapic_create(uintptr_t addr, int32_t apic_id, int intbase)
|
||||
* Assume that pin 0 on the first IO APIC is an ExtINT pin by
|
||||
* default. Assume that intpins 1-15 are ISA interrupts and
|
||||
* use suitable defaults for those. Assume that all other
|
||||
* intpins are PCI interrupts. Enable the ExtINT pin by
|
||||
* default but mask all other pins.
|
||||
* intpins are PCI interrupts. Enable the ExtINT pin if
|
||||
* mixed mode is available and active but mask all other pins.
|
||||
*/
|
||||
if (intpin->io_vector == 0) {
|
||||
intpin->io_activehi = 1;
|
||||
intpin->io_edgetrigger = 1;
|
||||
intpin->io_vector = VECTOR_EXTINT;
|
||||
intpin->io_masked = 0;
|
||||
if (mixed_mode_enabled && mixed_mode_active)
|
||||
intpin->io_masked = 0;
|
||||
else
|
||||
intpin->io_masked = 1;
|
||||
} else if (intpin->io_vector < IOAPIC_ISA_INTS) {
|
||||
intpin->io_activehi = 1;
|
||||
intpin->io_edgetrigger = 1;
|
||||
@ -526,36 +577,36 @@ ioapic_set_extint(void *cookie, u_int pin)
|
||||
}
|
||||
|
||||
int
|
||||
ioapic_set_polarity(void *cookie, u_int pin, char activehi)
|
||||
ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol)
|
||||
{
|
||||
struct ioapic *io;
|
||||
|
||||
io = (struct ioapic *)cookie;
|
||||
if (pin >= io->io_numintr)
|
||||
if (pin >= io->io_numintr || pol == INTR_POLARITY_CONFORM)
|
||||
return (EINVAL);
|
||||
if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
|
||||
return (EINVAL);
|
||||
io->io_pins[pin].io_activehi = activehi;
|
||||
io->io_pins[pin].io_activehi = (pol == INTR_POLARITY_HIGH);
|
||||
if (bootverbose)
|
||||
printf("ioapic%u: intpin %d polarity: %s\n", io->io_id, pin,
|
||||
activehi ? "active-hi" : "active-lo");
|
||||
pol == INTR_POLARITY_HIGH ? "high" : "low");
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ioapic_set_triggermode(void *cookie, u_int pin, char edgetrigger)
|
||||
ioapic_set_triggermode(void *cookie, u_int pin, enum intr_trigger trigger)
|
||||
{
|
||||
struct ioapic *io;
|
||||
|
||||
io = (struct ioapic *)cookie;
|
||||
if (pin >= io->io_numintr)
|
||||
if (pin >= io->io_numintr || trigger == INTR_TRIGGER_CONFORM)
|
||||
return (EINVAL);
|
||||
if (io->io_pins[pin].io_vector >= NUM_IO_INTS)
|
||||
return (EINVAL);
|
||||
io->io_pins[pin].io_edgetrigger = edgetrigger;
|
||||
io->io_pins[pin].io_edgetrigger = (trigger == INTR_TRIGGER_EDGE);
|
||||
if (bootverbose)
|
||||
printf("ioapic%u: intpin %d trigger: %s\n", io->io_id, pin,
|
||||
edgetrigger ? "edge" : "level");
|
||||
trigger == INTR_TRIGGER_EDGE ? "edge" : "level");
|
||||
return (0);
|
||||
}
|
||||
|
||||
@ -632,12 +683,15 @@ ioapic_register(void *cookie)
|
||||
ioapic_write(apic, IOAPIC_REDTBL_HI(i), flags);
|
||||
mtx_unlock_spin(&icu_lock);
|
||||
if (pin->io_vector < NUM_IO_INTS) {
|
||||
#ifdef MIXED_MODE
|
||||
/* Route IRQ0 via the 8259A using mixed mode. */
|
||||
if (pin->io_vector == 0)
|
||||
|
||||
/*
|
||||
* Route IRQ0 via the 8259A using mixed mode if
|
||||
* mixed mode is available and turned on.
|
||||
*/
|
||||
if (pin->io_vector == 0 && mixed_mode_active &&
|
||||
mixed_mode_enabled)
|
||||
ioapic_setup_mixed_mode(pin);
|
||||
else
|
||||
#endif
|
||||
intr_register_source(&pin->io_intsrc);
|
||||
}
|
||||
|
||||
@ -664,7 +718,6 @@ ioapic_set_logical_destinations(void *arg __unused)
|
||||
SYSINIT(ioapic_destinations, SI_SUB_SMP, SI_ORDER_SECOND,
|
||||
ioapic_set_logical_destinations, NULL)
|
||||
|
||||
#ifdef MIXED_MODE
|
||||
/*
|
||||
* Support for mixed-mode interrupt sources. These sources route an ISA
|
||||
* IRQ through the 8259A's via the ExtINT on pin 0 of the I/O APIC that
|
||||
@ -673,7 +726,7 @@ SYSINIT(ioapic_destinations, SI_SUB_SMP, SI_ORDER_SECOND,
|
||||
* that IRQ instead.
|
||||
*/
|
||||
|
||||
void
|
||||
static void
|
||||
ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin)
|
||||
{
|
||||
struct ioapic_intsrc *extint;
|
||||
@ -693,5 +746,3 @@ ioapic_setup_mixed_mode(struct ioapic_intsrc *intpin)
|
||||
ioapic_assign_cluster(extint);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* MIXED_MODE */
|
||||
|
@ -41,7 +41,9 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <machine/bus.h>
|
||||
#include <sys/pcpu.h>
|
||||
#include <sys/rman.h>
|
||||
#include <sys/smp.h>
|
||||
|
||||
#include <machine/legacyvar.h>
|
||||
#include <machine/resource.h>
|
||||
@ -138,7 +140,9 @@ legacy_probe(device_t dev)
|
||||
static int
|
||||
legacy_attach(device_t dev)
|
||||
{
|
||||
device_t child;
|
||||
device_t child;
|
||||
int i;
|
||||
struct pcpu *pc;
|
||||
|
||||
/*
|
||||
* First, let our child driver's identify any child devices that
|
||||
@ -148,6 +152,21 @@ legacy_attach(device_t dev)
|
||||
bus_generic_probe(dev);
|
||||
bus_generic_attach(dev);
|
||||
|
||||
/* Attach CPU pseudo-driver. */
|
||||
if (!devclass_get_device(devclass_find("cpu"), 0)) {
|
||||
for (i = 0; i <= mp_maxid; i++)
|
||||
if (!CPU_ABSENT(i)) {
|
||||
pc = pcpu_find(i);
|
||||
KASSERT(pc != NULL, ("pcpu_find failed"));
|
||||
child = BUS_ADD_CHILD(dev, 0, "cpu", i);
|
||||
if (child == NULL)
|
||||
panic("legacy_attach cpu");
|
||||
device_probe_and_attach(child);
|
||||
pc->pc_device = child;
|
||||
device_set_ivars(child, pc);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we didn't see ISA on a pci bridge, create some
|
||||
* connection points now so it shows up "on motherboard".
|
||||
@ -305,3 +324,54 @@ legacy_delete_resource(device_t dev, device_t child, int type, int rid)
|
||||
|
||||
resource_list_delete(rl, type, rid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Legacy CPU attachment when ACPI is not available. Drivers like
|
||||
* cpufreq(4) hang off this.
|
||||
*/
|
||||
static int cpu_read_ivar(device_t dev, device_t child, int index,
|
||||
uintptr_t *result);
|
||||
|
||||
static device_method_t cpu_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, bus_generic_probe),
|
||||
DEVMETHOD(device_attach, bus_generic_attach),
|
||||
DEVMETHOD(device_detach, bus_generic_detach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
||||
/* Bus interface */
|
||||
DEVMETHOD(bus_read_ivar, cpu_read_ivar),
|
||||
DEVMETHOD(bus_print_child, bus_generic_print_child),
|
||||
DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
|
||||
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
|
||||
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
|
||||
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
|
||||
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
|
||||
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static driver_t cpu_driver = {
|
||||
"cpu",
|
||||
cpu_methods,
|
||||
1, /* no softc */
|
||||
};
|
||||
static devclass_t cpu_devclass;
|
||||
DRIVER_MODULE(cpu, legacy, cpu_driver, cpu_devclass, 0, 0);
|
||||
|
||||
static int
|
||||
cpu_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
|
||||
{
|
||||
struct pcpu *pc;
|
||||
|
||||
if (index != 0)
|
||||
return (ENOENT);
|
||||
pc = device_get_ivars(child);
|
||||
if (pc == NULL)
|
||||
return (ENOENT);
|
||||
*result = (uintptr_t)pc;
|
||||
return (0);
|
||||
}
|
||||
|
@ -422,50 +422,52 @@ lapic_set_lvt_mode(u_int apic_id, u_int pin, u_int32_t mode)
|
||||
}
|
||||
|
||||
int
|
||||
lapic_set_lvt_polarity(u_int apic_id, u_int pin, u_char activehi)
|
||||
lapic_set_lvt_polarity(u_int apic_id, u_int pin, enum intr_polarity pol)
|
||||
{
|
||||
|
||||
if (pin > LVT_MAX)
|
||||
if (pin > LVT_MAX || pol == INTR_POLARITY_CONFORM)
|
||||
return (EINVAL);
|
||||
if (apic_id == APIC_ID_ALL) {
|
||||
lvts[pin].lvt_activehi = activehi;
|
||||
lvts[pin].lvt_activehi = (pol == INTR_POLARITY_HIGH);
|
||||
if (bootverbose)
|
||||
printf("lapic:");
|
||||
} else {
|
||||
KASSERT(lapics[apic_id].la_present,
|
||||
("%s: missing APIC %u", __func__, apic_id));
|
||||
lapics[apic_id].la_lvts[pin].lvt_active = 1;
|
||||
lapics[apic_id].la_lvts[pin].lvt_activehi = activehi;
|
||||
lapics[apic_id].la_lvts[pin].lvt_activehi =
|
||||
(pol == INTR_POLARITY_HIGH);
|
||||
if (bootverbose)
|
||||
printf("lapic%u:", apic_id);
|
||||
}
|
||||
if (bootverbose)
|
||||
printf(" LINT%u polarity: active-%s\n", pin,
|
||||
activehi ? "hi" : "lo");
|
||||
pol == INTR_POLARITY_HIGH ? "high" : "low");
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
lapic_set_lvt_triggermode(u_int apic_id, u_int pin, u_char edgetrigger)
|
||||
lapic_set_lvt_triggermode(u_int apic_id, u_int pin, enum intr_trigger trigger)
|
||||
{
|
||||
|
||||
if (pin > LVT_MAX)
|
||||
if (pin > LVT_MAX || trigger == INTR_TRIGGER_CONFORM)
|
||||
return (EINVAL);
|
||||
if (apic_id == APIC_ID_ALL) {
|
||||
lvts[pin].lvt_edgetrigger = edgetrigger;
|
||||
lvts[pin].lvt_edgetrigger = (trigger == INTR_TRIGGER_EDGE);
|
||||
if (bootverbose)
|
||||
printf("lapic:");
|
||||
} else {
|
||||
KASSERT(lapics[apic_id].la_present,
|
||||
("%s: missing APIC %u", __func__, apic_id));
|
||||
lapics[apic_id].la_lvts[pin].lvt_edgetrigger = edgetrigger;
|
||||
lapics[apic_id].la_lvts[pin].lvt_edgetrigger =
|
||||
(trigger == INTR_TRIGGER_EDGE);
|
||||
lapics[apic_id].la_lvts[pin].lvt_active = 1;
|
||||
if (bootverbose)
|
||||
printf("lapic%u:", apic_id);
|
||||
}
|
||||
if (bootverbose)
|
||||
printf(" LINT%u trigger: %s\n", pin,
|
||||
edgetrigger ? "edge" : "level");
|
||||
trigger == INTR_TRIGGER_EDGE ? "edge" : "level");
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -47,10 +47,6 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
||||
/* EISA Edge/Level trigger control registers */
|
||||
#define ELCR0 0x4d0 /* eisa irq 0-7 */
|
||||
#define ELCR1 0x4d1 /* eisa irq 8-15 */
|
||||
|
||||
/* string defined by the Intel MP Spec as identifying the MP table */
|
||||
#define MP_SIG 0x5f504d5f /* _MP_ */
|
||||
|
||||
@ -147,10 +143,11 @@ static int pci0 = -1;
|
||||
|
||||
MALLOC_DEFINE(M_MPTABLE, "MP Table", "MP Table Items");
|
||||
|
||||
static u_char conforming_polarity(u_char src_bus);
|
||||
static u_char conforming_trigger(u_char src_bus, u_char src_bus_irq);
|
||||
static u_char intentry_polarity(int_entry_ptr intr);
|
||||
static u_char intentry_trigger(int_entry_ptr intr);
|
||||
static enum intr_polarity conforming_polarity(u_char src_bus,
|
||||
u_char src_bus_irq);
|
||||
static enum intr_trigger conforming_trigger(u_char src_bus, u_char src_bus_irq);
|
||||
static enum intr_polarity intentry_polarity(int_entry_ptr intr);
|
||||
static enum intr_trigger intentry_trigger(int_entry_ptr intr);
|
||||
static int lookup_bus_type(char *name);
|
||||
static void mptable_count_items(void);
|
||||
static void mptable_count_items_handler(u_char *entry, void *arg);
|
||||
@ -340,6 +337,7 @@ mptable_setup_io(void)
|
||||
busses[i].bus_type = NOBUS;
|
||||
|
||||
/* Second, we run through adding I/O APIC's and busses. */
|
||||
ioapic_enable_mixed_mode();
|
||||
mptable_parse_apics_and_busses();
|
||||
|
||||
/* Third, we run through the table tweaking interrupt sources. */
|
||||
@ -539,19 +537,22 @@ mptable_parse_apics_and_busses(void)
|
||||
/*
|
||||
* Determine conforming polarity for a given bus type.
|
||||
*/
|
||||
static u_char
|
||||
conforming_polarity(u_char src_bus)
|
||||
static enum intr_polarity
|
||||
conforming_polarity(u_char src_bus, u_char src_bus_irq)
|
||||
{
|
||||
|
||||
KASSERT(src_bus <= mptable_maxbusid, ("bus id %d too large", src_bus));
|
||||
switch (busses[src_bus].bus_type) {
|
||||
case ISA:
|
||||
case EISA:
|
||||
/* Active Hi */
|
||||
return (1);
|
||||
return (INTR_POLARITY_HIGH);
|
||||
case PCI:
|
||||
/* Active Lo */
|
||||
return (0);
|
||||
return (INTR_POLARITY_LOW);
|
||||
case EISA:
|
||||
KASSERT(src_bus_irq < 16, ("Invalid EISA IRQ %d", src_bus_irq));
|
||||
if (elcr_read_trigger(src_bus_irq) == INTR_TRIGGER_LEVEL)
|
||||
return (INTR_POLARITY_LOW);
|
||||
else
|
||||
return (INTR_POLARITY_HIGH);
|
||||
default:
|
||||
panic("%s: unknown bus type %d", __func__,
|
||||
busses[src_bus].bus_type);
|
||||
@ -561,52 +562,43 @@ conforming_polarity(u_char src_bus)
|
||||
/*
|
||||
* Determine conforming trigger for a given bus type.
|
||||
*/
|
||||
static u_char
|
||||
static enum intr_trigger
|
||||
conforming_trigger(u_char src_bus, u_char src_bus_irq)
|
||||
{
|
||||
static int eisa_int_control = -1;
|
||||
|
||||
KASSERT(src_bus <= mptable_maxbusid, ("bus id %d too large", src_bus));
|
||||
switch (busses[src_bus].bus_type) {
|
||||
case ISA:
|
||||
/* Edge Triggered */
|
||||
return (1);
|
||||
return (INTR_TRIGGER_EDGE);
|
||||
case PCI:
|
||||
/* Level Triggered */
|
||||
return (0);
|
||||
return (INTR_TRIGGER_LEVEL);
|
||||
case EISA:
|
||||
KASSERT(src_bus_irq < 16, ("Invalid EISA IRQ %d", src_bus_irq));
|
||||
if (eisa_int_control == -1)
|
||||
eisa_int_control = inb(ELCR1) << 8 | inb(ELCR0);
|
||||
if (eisa_int_control & (1 << src_bus_irq))
|
||||
/* Level Triggered */
|
||||
return (0);
|
||||
else
|
||||
/* Edge Triggered */
|
||||
return (1);
|
||||
return (elcr_read_trigger(src_bus_irq));
|
||||
default:
|
||||
panic("%s: unknown bus type %d", __func__,
|
||||
busses[src_bus].bus_type);
|
||||
}
|
||||
}
|
||||
|
||||
static u_char
|
||||
static enum intr_polarity
|
||||
intentry_polarity(int_entry_ptr intr)
|
||||
{
|
||||
|
||||
switch (intr->int_flags & INTENTRY_FLAGS_POLARITY) {
|
||||
case INTENTRY_FLAGS_POLARITY_CONFORM:
|
||||
return (conforming_polarity(intr->src_bus_id));
|
||||
return (conforming_polarity(intr->src_bus_id,
|
||||
intr->src_bus_irq));
|
||||
case INTENTRY_FLAGS_POLARITY_ACTIVEHI:
|
||||
return (1);
|
||||
return (INTR_POLARITY_HIGH);
|
||||
case INTENTRY_FLAGS_POLARITY_ACTIVELO:
|
||||
return (0);
|
||||
return (INTR_POLARITY_LOW);
|
||||
default:
|
||||
panic("Bogus interrupt flags");
|
||||
}
|
||||
}
|
||||
|
||||
static u_char
|
||||
static enum intr_trigger
|
||||
intentry_trigger(int_entry_ptr intr)
|
||||
{
|
||||
|
||||
@ -615,9 +607,9 @@ intentry_trigger(int_entry_ptr intr)
|
||||
return (conforming_trigger(intr->src_bus_id,
|
||||
intr->src_bus_irq));
|
||||
case INTENTRY_FLAGS_TRIGGER_EDGE:
|
||||
return (1);
|
||||
return (INTR_TRIGGER_EDGE);
|
||||
case INTENTRY_FLAGS_TRIGGER_LEVEL:
|
||||
return (0);
|
||||
return (INTR_TRIGGER_LEVEL);
|
||||
default:
|
||||
panic("Bogus interrupt flags");
|
||||
}
|
||||
|
@ -64,10 +64,18 @@ mptable_hostb_probe(device_t dev)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
mptable_hostb_attach(device_t dev)
|
||||
{
|
||||
|
||||
device_add_child(dev, "pci", pcib_get_bus(dev));
|
||||
return (bus_generic_attach(dev));
|
||||
}
|
||||
|
||||
static device_method_t mptable_hostb_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, mptable_hostb_probe),
|
||||
DEVMETHOD(device_attach, legacy_pcib_attach),
|
||||
DEVMETHOD(device_attach, mptable_hostb_attach),
|
||||
DEVMETHOD(device_shutdown, bus_generic_shutdown),
|
||||
DEVMETHOD(device_suspend, bus_generic_suspend),
|
||||
DEVMETHOD(device_resume, bus_generic_resume),
|
||||
|
@ -84,6 +84,8 @@ static device_t nexus_add_child(device_t bus, int order, const char *name,
|
||||
int unit);
|
||||
static struct resource *nexus_alloc_resource(device_t, device_t, int, int *,
|
||||
u_long, u_long, u_long, u_int);
|
||||
static int nexus_config_intr(device_t, int, enum intr_trigger,
|
||||
enum intr_polarity);
|
||||
static int nexus_activate_resource(device_t, device_t, int, int,
|
||||
struct resource *);
|
||||
static int nexus_deactivate_resource(device_t, device_t, int, int,
|
||||
@ -116,6 +118,7 @@ static device_method_t nexus_methods[] = {
|
||||
DEVMETHOD(bus_deactivate_resource, nexus_deactivate_resource),
|
||||
DEVMETHOD(bus_setup_intr, nexus_setup_intr),
|
||||
DEVMETHOD(bus_teardown_intr, nexus_teardown_intr),
|
||||
DEVMETHOD(bus_config_intr, nexus_config_intr),
|
||||
DEVMETHOD(bus_set_resource, nexus_set_resource),
|
||||
DEVMETHOD(bus_get_resource, nexus_get_resource),
|
||||
DEVMETHOD(bus_delete_resource, nexus_delete_resource),
|
||||
@ -452,6 +455,13 @@ nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
|
||||
return (intr_remove_handler(ih));
|
||||
}
|
||||
|
||||
static int
|
||||
nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
|
||||
enum intr_polarity pol)
|
||||
{
|
||||
return (intr_config_intr(irq, trig, pol));
|
||||
}
|
||||
|
||||
static int
|
||||
nexus_set_resource(device_t dev, device_t child, int type, int rid, u_long start, u_long count)
|
||||
{
|
||||
|
@ -138,14 +138,16 @@ u_int apic_idt_to_irq(u_int vector);
|
||||
void apic_register_enumerator(struct apic_enumerator *enumerator);
|
||||
void *ioapic_create(uintptr_t addr, int32_t id, int intbase);
|
||||
int ioapic_disable_pin(void *cookie, u_int pin);
|
||||
void ioapic_enable_mixed_mode(void);
|
||||
int ioapic_get_vector(void *cookie, u_int pin);
|
||||
int ioapic_next_logical_cluster(void);
|
||||
void ioapic_register(void *cookie);
|
||||
int ioapic_remap_vector(void *cookie, u_int pin, int vector);
|
||||
int ioapic_set_extint(void *cookie, u_int pin);
|
||||
int ioapic_set_nmi(void *cookie, u_int pin);
|
||||
int ioapic_set_polarity(void *cookie, u_int pin, char activehi);
|
||||
int ioapic_set_triggermode(void *cookie, u_int pin, char edgetrigger);
|
||||
int ioapic_set_polarity(void *cookie, u_int pin, enum intr_polarity pol);
|
||||
int ioapic_set_triggermode(void *cookie, u_int pin,
|
||||
enum intr_trigger trigger);
|
||||
int ioapic_set_smi(void *cookie, u_int pin);
|
||||
void lapic_create(u_int apic_id, int boot_cpu);
|
||||
void lapic_disable(void);
|
||||
@ -162,8 +164,10 @@ void lapic_handle_intr(void *cookie, struct intrframe frame);
|
||||
void lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id);
|
||||
int lapic_set_lvt_mask(u_int apic_id, u_int lvt, u_char masked);
|
||||
int lapic_set_lvt_mode(u_int apic_id, u_int lvt, u_int32_t mode);
|
||||
int lapic_set_lvt_polarity(u_int apic_id, u_int lvt, u_char activehi);
|
||||
int lapic_set_lvt_triggermode(u_int apic_id, u_int lvt, u_char edgetrigger);
|
||||
int lapic_set_lvt_polarity(u_int apic_id, u_int lvt,
|
||||
enum intr_polarity pol);
|
||||
int lapic_set_lvt_triggermode(u_int apic_id, u_int lvt,
|
||||
enum intr_trigger trigger);
|
||||
void lapic_setup(void);
|
||||
|
||||
#endif /* !LOCORE */
|
||||
|
@ -57,6 +57,8 @@ struct pic {
|
||||
int (*pic_source_pending)(struct intsrc *);
|
||||
void (*pic_suspend)(struct intsrc *);
|
||||
void (*pic_resume)(struct intsrc *);
|
||||
int (*pic_config_intr)(struct intsrc *, enum intr_trigger,
|
||||
enum intr_polarity);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -77,8 +79,15 @@ struct intrframe;
|
||||
|
||||
extern struct mtx icu_lock;
|
||||
|
||||
/* XXX: The elcr_* prototypes probably belong somewhere else. */
|
||||
int elcr_probe(void);
|
||||
enum intr_trigger elcr_read_trigger(u_int irq);
|
||||
void elcr_resume(void);
|
||||
void elcr_write_trigger(u_int irq, enum intr_trigger trigger);
|
||||
int intr_add_handler(const char *name, int vector, driver_intr_t handler,
|
||||
void *arg, enum intr_type flags, void **cookiep);
|
||||
int intr_config_intr(int vector, enum intr_trigger trig,
|
||||
enum intr_polarity pol);
|
||||
void intr_execute_handlers(struct intsrc *isrc, struct intrframe *iframe);
|
||||
struct intsrc *intr_lookup_source(int vector);
|
||||
int intr_register_source(struct intsrc *isrc);
|
||||
|
@ -40,7 +40,6 @@ LEGACY_ACCESSOR(pcibus, PCIBUS, u_int32_t)
|
||||
|
||||
#undef LEGACY_ACCESSOR
|
||||
|
||||
int legacy_pcib_attach(device_t dev);
|
||||
int legacy_pcib_maxslots(device_t dev);
|
||||
u_int32_t legacy_pcib_read_config(device_t dev, int bus, int slot, int func,
|
||||
int reg, int bytes);
|
||||
|
@ -257,7 +257,6 @@ extern struct ppro_vmtrr PPro_vmtrr[NPPROVMTRR];
|
||||
extern caddr_t CADDR1;
|
||||
extern pt_entry_t *CMAP1;
|
||||
extern vm_paddr_t avail_end;
|
||||
extern vm_paddr_t avail_start;
|
||||
extern vm_paddr_t phys_avail[];
|
||||
extern vm_offset_t virtual_avail;
|
||||
extern vm_offset_t virtual_end;
|
||||
|
@ -62,6 +62,16 @@ __FBSDID("$FreeBSD$");
|
||||
#define MASTER 0
|
||||
#define SLAVE 1
|
||||
|
||||
/*
|
||||
* PC-98 machines wire the slave 8259A to pin 7 on the master PIC, and
|
||||
* PC-AT machines wire the slave PIC to pin 2 on the master PIC.
|
||||
*/
|
||||
#ifdef PC98
|
||||
#define ICU_SLAVEID 7
|
||||
#else
|
||||
#define ICU_SLAVEID 2
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Determine the base master and slave modes not including auto EOI support.
|
||||
* All machines that FreeBSD supports use 8086 mode.
|
||||
@ -81,9 +91,15 @@ __FBSDID("$FreeBSD$");
|
||||
#define SLAVE_MODE BASE_SLAVE_MODE
|
||||
#endif
|
||||
|
||||
#define IRQ_MASK(irq) (1 << (irq))
|
||||
#define IMEN_MASK(ai) (IRQ_MASK((ai)->at_irq))
|
||||
|
||||
#define NUM_ISA_IRQS 16
|
||||
|
||||
static void atpic_init(void *dummy);
|
||||
|
||||
unsigned int imen; /* XXX */
|
||||
static int using_elcr;
|
||||
|
||||
inthand_t
|
||||
IDTVEC(atpic_intr0), IDTVEC(atpic_intr1), IDTVEC(atpic_intr2),
|
||||
@ -95,14 +111,15 @@ inthand_t
|
||||
|
||||
#define IRQ(ap, ai) ((ap)->at_irqbase + (ai)->at_irq)
|
||||
|
||||
#define ATPIC(io, base, eoi, imenptr) \
|
||||
#define ATPIC(io, base, eoi, imenptr) \
|
||||
{ { atpic_enable_source, atpic_disable_source, (eoi), \
|
||||
atpic_enable_intr, atpic_vector, atpic_source_pending, NULL, \
|
||||
atpic_resume }, (io), (base), IDT_IO_INTS + (base), (imenptr) }
|
||||
atpic_resume, atpic_config_intr }, (io), (base), \
|
||||
IDT_IO_INTS + (base), (imenptr) }
|
||||
|
||||
#define INTSRC(irq) \
|
||||
{ { &atpics[(irq) / 8].at_pic }, (irq) % 8, \
|
||||
IDTVEC(atpic_intr ## irq ) }
|
||||
{ { &atpics[(irq) / 8].at_pic }, IDTVEC(atpic_intr ## irq ), \
|
||||
(irq) % 8 }
|
||||
|
||||
struct atpic {
|
||||
struct pic at_pic;
|
||||
@ -114,8 +131,9 @@ struct atpic {
|
||||
|
||||
struct atpic_intsrc {
|
||||
struct intsrc at_intsrc;
|
||||
int at_irq; /* Relative to PIC base. */
|
||||
inthand_t *at_intr;
|
||||
int at_irq; /* Relative to PIC base. */
|
||||
enum intr_trigger at_trigger;
|
||||
u_long at_count;
|
||||
u_long at_straycount;
|
||||
};
|
||||
@ -128,6 +146,8 @@ static void atpic_enable_intr(struct intsrc *isrc);
|
||||
static int atpic_vector(struct intsrc *isrc);
|
||||
static void atpic_resume(struct intsrc *isrc);
|
||||
static int atpic_source_pending(struct intsrc *isrc);
|
||||
static int atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
|
||||
enum intr_polarity pol);
|
||||
static void i8259_init(struct atpic *pic, int slave);
|
||||
|
||||
static struct atpic atpics[] = {
|
||||
@ -154,6 +174,8 @@ static struct atpic_intsrc atintrs[] = {
|
||||
INTSRC(15),
|
||||
};
|
||||
|
||||
CTASSERT(sizeof(atintrs) / sizeof(atintrs[0]) == NUM_ISA_IRQS);
|
||||
|
||||
static void
|
||||
atpic_enable_source(struct intsrc *isrc)
|
||||
{
|
||||
@ -161,8 +183,10 @@ atpic_enable_source(struct intsrc *isrc)
|
||||
struct atpic *ap = (struct atpic *)isrc->is_pic;
|
||||
|
||||
mtx_lock_spin(&icu_lock);
|
||||
*ap->at_imen &= ~(1 << ai->at_irq);
|
||||
outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
|
||||
if (*ap->at_imen & IMEN_MASK(ai)) {
|
||||
*ap->at_imen &= ~IMEN_MASK(ai);
|
||||
outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
|
||||
}
|
||||
mtx_unlock_spin(&icu_lock);
|
||||
}
|
||||
|
||||
@ -172,8 +196,10 @@ atpic_disable_source(struct intsrc *isrc)
|
||||
struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
|
||||
struct atpic *ap = (struct atpic *)isrc->is_pic;
|
||||
|
||||
if (ai->at_trigger == INTR_TRIGGER_EDGE)
|
||||
return;
|
||||
mtx_lock_spin(&icu_lock);
|
||||
*ap->at_imen |= (1 << ai->at_irq);
|
||||
*ap->at_imen |= IMEN_MASK(ai);
|
||||
outb(ap->at_ioaddr + ICU_IMR_OFFSET, *ap->at_imen);
|
||||
mtx_unlock_spin(&icu_lock);
|
||||
}
|
||||
@ -186,7 +212,7 @@ atpic_eoi_master(struct intsrc *isrc)
|
||||
("%s: mismatched pic", __func__));
|
||||
#ifndef AUTO_EOI_1
|
||||
mtx_lock_spin(&icu_lock);
|
||||
outb(atpics[MASTER].at_ioaddr, ICU_EOI);
|
||||
outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
|
||||
mtx_unlock_spin(&icu_lock);
|
||||
#endif
|
||||
}
|
||||
@ -203,9 +229,9 @@ atpic_eoi_slave(struct intsrc *isrc)
|
||||
("%s: mismatched pic", __func__));
|
||||
#ifndef AUTO_EOI_2
|
||||
mtx_lock_spin(&icu_lock);
|
||||
outb(atpics[SLAVE].at_ioaddr, ICU_EOI);
|
||||
outb(atpics[SLAVE].at_ioaddr, OCW2_EOI);
|
||||
#ifndef AUTO_EOI_1
|
||||
outb(atpics[MASTER].at_ioaddr, ICU_EOI);
|
||||
outb(atpics[MASTER].at_ioaddr, OCW2_EOI);
|
||||
#endif
|
||||
mtx_unlock_spin(&icu_lock);
|
||||
#endif
|
||||
@ -231,7 +257,7 @@ atpic_source_pending(struct intsrc *isrc)
|
||||
struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
|
||||
struct atpic *ap = (struct atpic *)isrc->is_pic;
|
||||
|
||||
return (inb(ap->at_ioaddr) & (1 << ai->at_irq));
|
||||
return (inb(ap->at_ioaddr) & IMEN_MASK(ai));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -240,8 +266,67 @@ atpic_resume(struct intsrc *isrc)
|
||||
struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
|
||||
struct atpic *ap = (struct atpic *)isrc->is_pic;
|
||||
|
||||
if (ai->at_irq == 0)
|
||||
if (ai->at_irq == 0) {
|
||||
i8259_init(ap, ap == &atpics[SLAVE]);
|
||||
if (ap == &atpics[SLAVE] && using_elcr)
|
||||
elcr_resume();
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
atpic_config_intr(struct intsrc *isrc, enum intr_trigger trig,
|
||||
enum intr_polarity pol)
|
||||
{
|
||||
struct atpic_intsrc *ai = (struct atpic_intsrc *)isrc;
|
||||
u_int vector;
|
||||
|
||||
/* Map conforming values to edge/hi and sanity check the values. */
|
||||
if (trig == INTR_TRIGGER_CONFORM)
|
||||
trig = INTR_TRIGGER_EDGE;
|
||||
if (pol == INTR_POLARITY_CONFORM)
|
||||
pol = INTR_POLARITY_HIGH;
|
||||
vector = atpic_vector(isrc);
|
||||
if ((trig == INTR_TRIGGER_EDGE && pol == INTR_POLARITY_LOW) ||
|
||||
(trig == INTR_TRIGGER_LEVEL && pol == INTR_POLARITY_HIGH)) {
|
||||
printf(
|
||||
"atpic: Mismatched config for IRQ%u: trigger %s, polarity %s\n",
|
||||
vector, trig == INTR_TRIGGER_EDGE ? "edge" : "level",
|
||||
pol == INTR_POLARITY_HIGH ? "high" : "low");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* If there is no change, just return. */
|
||||
if (ai->at_trigger == trig)
|
||||
return (0);
|
||||
|
||||
/*
|
||||
* Certain IRQs can never be level/lo, so don't try to set them
|
||||
* that way if asked. At least some ELCR registers ignore setting
|
||||
* these bits as well.
|
||||
*/
|
||||
if ((vector == 0 || vector == 1 || vector == 2 || vector == 13) &&
|
||||
trig == INTR_TRIGGER_LEVEL) {
|
||||
if (bootverbose)
|
||||
printf(
|
||||
"atpic: Ignoring invalid level/low configuration for IRQ%u\n",
|
||||
vector);
|
||||
return (EINVAL);
|
||||
}
|
||||
if (!using_elcr) {
|
||||
if (bootverbose)
|
||||
printf("atpic: No ELCR to configure IRQ%u as %s\n",
|
||||
vector, trig == INTR_TRIGGER_EDGE ? "edge/high" :
|
||||
"level/low");
|
||||
return (ENXIO);
|
||||
}
|
||||
if (bootverbose)
|
||||
printf("atpic: Programming IRQ%u as %s\n", vector,
|
||||
trig == INTR_TRIGGER_EDGE ? "edge/high" : "level/low");
|
||||
mtx_lock_spin(&icu_lock);
|
||||
elcr_write_trigger(atpic_vector(isrc), trig);
|
||||
ai->at_trigger = trig;
|
||||
mtx_unlock_spin(&icu_lock);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -263,9 +348,9 @@ i8259_init(struct atpic *pic, int slave)
|
||||
* which line on the master we are connected to.
|
||||
*/
|
||||
if (slave)
|
||||
outb(imr_addr, ICU_SLAVEID); /* my slave id is 7 */
|
||||
outb(imr_addr, ICU_SLAVEID);
|
||||
else
|
||||
outb(imr_addr, IRQ_SLAVE); /* slave on line 7 */
|
||||
outb(imr_addr, IRQ_MASK(ICU_SLAVEID));
|
||||
|
||||
/* Set mode. */
|
||||
if (slave)
|
||||
@ -298,27 +383,58 @@ atpic_startup(void)
|
||||
atpic_enable_source((struct intsrc *)&atintrs[ICU_SLAVEID]);
|
||||
|
||||
/* Install low-level interrupt handlers for all of our IRQs. */
|
||||
for (i = 0; i < sizeof(atintrs) / sizeof(struct atpic_intsrc); i++) {
|
||||
for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
|
||||
if (i == ICU_SLAVEID)
|
||||
continue;
|
||||
ai = &atintrs[i];
|
||||
ai->at_intsrc.is_count = &ai->at_count;
|
||||
ai->at_intsrc.is_straycount = &ai->at_straycount;
|
||||
setidt(((struct atpic *)ai->at_intsrc.is_pic)->at_intbase +
|
||||
ai->at_irq, ai->at_intr, SDT_SYSIGT, SEL_KPL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Look for an ELCR. If we find one, update the trigger modes.
|
||||
* If we don't find one, assume that IRQs 0, 1, 2, and 13 are
|
||||
* edge triggered and that everything else is level triggered.
|
||||
* We only use the trigger information to reprogram the ELCR if
|
||||
* we have one and as an optimization to avoid masking edge
|
||||
* triggered interrupts. For the case that we don't have an ELCR,
|
||||
* it doesn't hurt to mask an edge triggered interrupt, so we
|
||||
* assume level trigger for any interrupt that we aren't sure is
|
||||
* edge triggered.
|
||||
*/
|
||||
if (elcr_probe() == 0) {
|
||||
using_elcr = 1;
|
||||
for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
|
||||
ai->at_trigger = elcr_read_trigger(i);
|
||||
} else {
|
||||
for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++)
|
||||
switch (i) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 8:
|
||||
case 13:
|
||||
ai->at_trigger = INTR_TRIGGER_EDGE;
|
||||
break;
|
||||
default:
|
||||
ai->at_trigger = INTR_TRIGGER_LEVEL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
atpic_init(void *dummy __unused)
|
||||
{
|
||||
struct atpic_intsrc *ai;
|
||||
int i;
|
||||
|
||||
/* Loop through all interrupt sources and add them. */
|
||||
for (i = 0; i < sizeof(atintrs) / sizeof(struct atpic_intsrc); i++) {
|
||||
for (i = 0, ai = atintrs; i < NUM_ISA_IRQS; i++, ai++) {
|
||||
if (i == ICU_SLAVEID)
|
||||
continue;
|
||||
intr_register_source(&atintrs[i].at_intsrc);
|
||||
intr_register_source(&ai->at_intsrc);
|
||||
}
|
||||
}
|
||||
SYSINIT(atpic_init, SI_SUB_INTR, SI_ORDER_SECOND + 1, atpic_init, NULL)
|
||||
@ -329,7 +445,7 @@ atpic_handle_intr(void *cookie, struct intrframe iframe)
|
||||
struct intsrc *isrc;
|
||||
int vec = (uintptr_t)cookie;
|
||||
|
||||
KASSERT(vec < ICU_LEN, ("unknown int %d\n", vec));
|
||||
KASSERT(vec < NUM_ISA_IRQS, ("unknown int %d\n", vec));
|
||||
isrc = &atintrs[vec].at_intsrc;
|
||||
|
||||
/*
|
||||
@ -349,7 +465,7 @@ atpic_handle_intr(void *cookie, struct intrframe iframe)
|
||||
isr = inb(port);
|
||||
outb(port, OCW3_SEL | OCW3_RR);
|
||||
mtx_unlock_spin(&icu_lock);
|
||||
if ((isr & IRQ7) == 0)
|
||||
if ((isr & IRQ_MASK(7)) == 0)
|
||||
return;
|
||||
}
|
||||
intr_execute_handlers(isrc, &iframe);
|
||||
|
@ -37,8 +37,6 @@
|
||||
*/
|
||||
|
||||
#include <machine/asmacros.h>
|
||||
#include <amd64/isa/icu.h>
|
||||
#include <amd64/isa/isa.h>
|
||||
|
||||
#include "assym.s"
|
||||
|
||||
|
@ -73,7 +73,6 @@ __FBSDID("$FreeBSD$");
|
||||
#endif
|
||||
#include <machine/specialreg.h>
|
||||
|
||||
#include <amd64/isa/icu.h>
|
||||
#include <amd64/isa/isa.h>
|
||||
#include <isa/rtc.h>
|
||||
#ifdef DEV_ISA
|
||||
@ -107,10 +106,11 @@ struct mtx clock_lock;
|
||||
static int beeping = 0;
|
||||
static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
|
||||
static u_int hardclock_max_count;
|
||||
static struct intsrc *i8254_intsrc;
|
||||
static u_int32_t i8254_lastcount;
|
||||
static u_int32_t i8254_offset;
|
||||
static int (*i8254_pending)(struct intsrc *);
|
||||
static int i8254_ticked;
|
||||
static struct intsrc *i8254_intsrc;
|
||||
static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
|
||||
static u_char rtc_statusb = RTCSB_24HR | RTCSB_PINTR;
|
||||
|
||||
@ -741,6 +741,9 @@ cpu_initclocks()
|
||||
/* Finish initializing 8254 timer 0. */
|
||||
intr_add_handler("clk", 0, (driver_intr_t *)clkintr, NULL,
|
||||
INTR_TYPE_CLK | INTR_FAST, NULL);
|
||||
i8254_intsrc = intr_lookup_source(0);
|
||||
if (i8254_intsrc != NULL)
|
||||
i8254_pending = i8254_intsrc->is_pic->pic_source_pending;
|
||||
|
||||
/* Initialize RTC. */
|
||||
writertc(RTC_STATUSA, rtc_statusa);
|
||||
@ -754,7 +757,6 @@ cpu_initclocks()
|
||||
|
||||
intr_add_handler("rtc", 8, (driver_intr_t *)rtcintr, NULL,
|
||||
INTR_TYPE_CLK | INTR_FAST, NULL);
|
||||
i8254_intsrc = intr_lookup_source(8);
|
||||
|
||||
writertc(RTC_STATUSB, rtc_statusb);
|
||||
}
|
||||
@ -821,8 +823,7 @@ i8254_get_timecount(struct timecounter *tc)
|
||||
if (count < i8254_lastcount ||
|
||||
(!i8254_ticked && (clkintr_pending ||
|
||||
((count < 20 || (!(rflags & PSL_I) && count < timer0_max_count / 2u)) &&
|
||||
i8254_intsrc != NULL &&
|
||||
i8254_intsrc->is_pic->pic_source_pending(i8254_intsrc))))) {
|
||||
i8254_intsrc != NULL && i8254_pending(i8254_intsrc))))) {
|
||||
i8254_ticked = 1;
|
||||
i8254_offset += timer0_max_count;
|
||||
}
|
||||
|
@ -41,39 +41,9 @@
|
||||
#ifndef _AMD64_ISA_ICU_H_
|
||||
#define _AMD64_ISA_ICU_H_
|
||||
|
||||
/*
|
||||
* Interrupt enable bits - in normal order of priority (which we change)
|
||||
*/
|
||||
#define IRQ0 0x0001 /* highest priority - timer */
|
||||
#define IRQ1 0x0002
|
||||
#define IRQ_SLAVE 0x0004
|
||||
#define IRQ8 0x0100
|
||||
#define IRQ9 0x0200
|
||||
#define IRQ2 IRQ9
|
||||
#define IRQ10 0x0400
|
||||
#define IRQ11 0x0800
|
||||
#define IRQ12 0x1000
|
||||
#define IRQ13 0x2000
|
||||
#define IRQ14 0x4000
|
||||
#define IRQ15 0x8000
|
||||
#define IRQ3 0x0008 /* this is highest after rotation */
|
||||
#define IRQ4 0x0010
|
||||
#define IRQ5 0x0020
|
||||
#define IRQ6 0x0040
|
||||
#define IRQ7 0x0080 /* lowest - parallel printer */
|
||||
|
||||
/*
|
||||
* Interrupt Control offset into Interrupt descriptor table (IDT)
|
||||
*/
|
||||
#define ICU_OFFSET 32 /* 0-31 are processor exceptions */
|
||||
#define ICU_LEN 16 /* 32-47 are ISA interrupts */
|
||||
#define ICU_IMR_OFFSET 1
|
||||
#define ICU_SLAVEID 2
|
||||
#define ICU_EOI (OCW2_EOI) /* non-specific EOI */
|
||||
|
||||
#ifndef LOCORE
|
||||
void atpic_handle_intr(void *cookie, struct intrframe iframe);
|
||||
void atpic_startup(void);
|
||||
#endif
|
||||
|
||||
#endif /* !_AMD64_ISA_ICU_H_ */
|
||||
|
@ -43,10 +43,6 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <machine/md_var.h>
|
||||
|
||||
#ifdef DEV_MCA
|
||||
#include <i386/bios/mca_machdep.h>
|
||||
#endif
|
||||
|
||||
#define NMI_PARITY (1 << 7)
|
||||
#define NMI_IOCHAN (1 << 6)
|
||||
#define ENMI_WATCHDOG (1 << 7)
|
||||
@ -65,10 +61,6 @@ isa_nmi(int cd)
|
||||
int eisa_port = inb(0x461);
|
||||
|
||||
log(LOG_CRIT, "NMI ISA %x, EISA %x\n", isa_port, eisa_port);
|
||||
#ifdef DEV_MCA
|
||||
if (MCA_system && mca_bus_nmi())
|
||||
return(0);
|
||||
#endif
|
||||
|
||||
if (isa_port & NMI_PARITY) {
|
||||
log(LOG_CRIT, "RAM parity error, likely hardware failure.");
|
||||
|
@ -225,7 +225,7 @@ legacy_pcib_probe(device_t dev)
|
||||
return -100;
|
||||
}
|
||||
|
||||
int
|
||||
static int
|
||||
legacy_pcib_attach(device_t dev)
|
||||
{
|
||||
int bus;
|
||||
|
@ -81,6 +81,7 @@ amd64/amd64/vm_machdep.c standard
|
||||
amd64/isa/atpic.c optional atpic isa
|
||||
amd64/isa/atpic_vector.S optional atpic isa
|
||||
amd64/isa/clock.c standard
|
||||
amd64/isa/elcr.c standard
|
||||
amd64/isa/isa.c standard
|
||||
amd64/isa/isa_dma.c standard
|
||||
amd64/isa/nmi.c standard
|
||||
|
Loading…
Reference in New Issue
Block a user