c58d580e70
interrupt block). We use the previously hardcoded address as a default only, but will otherwise use whatever ACPI tells us. The address can be found in the MADT table header or in the LAPIC override table entry.
309 lines
7.6 KiB
C
309 lines
7.6 KiB
C
/*-
|
|
* Copyright (c) 2001 Doug Rabson
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD$
|
|
*/
|
|
|
|
#include "acpi.h"
|
|
|
|
#include <machine/cpu.h>
|
|
|
|
extern u_int64_t ia64_lapic_address;
|
|
|
|
struct sapic *sapic_create(int, int, u_int64_t);
|
|
|
|
#pragma pack(1)
|
|
|
|
#define APIC_INTERRUPT_SOURCE_OVERRIDE 2
|
|
#define APIC_NMI 3
|
|
#define APIC_LOCAL_APIC_NMI 4
|
|
#define APIC_LOCAL_APIC_OVERRIDE 5
|
|
#define APIC_IO_SAPIC 6
|
|
#define APIC_LOCAL_SAPIC 7
|
|
#define APIC_PLATFORM_INTERRUPT 8
|
|
|
|
typedef struct /* Interrupt Source Override */
|
|
{
|
|
APIC_HEADER Header;
|
|
UINT8 Bus;
|
|
UINT8 Source;
|
|
UINT32 GlobalSystemInterrupt;
|
|
UINT16 Flags;
|
|
} INTERRUPT_SOURCE_OVERRIDE;
|
|
|
|
typedef struct /* IO SAPIC */
|
|
{
|
|
APIC_HEADER Header;
|
|
UINT8 IoSapicId; /* I/O SAPIC ID */
|
|
UINT8 Reserved; /* reserved - must be zero */
|
|
UINT32 Vector; /* interrupt base */
|
|
UINT64 IoSapicAddress; /* SAPIC's physical address */
|
|
} IO_SAPIC;
|
|
|
|
typedef struct /* LOCAL SAPIC */
|
|
{
|
|
APIC_HEADER Header;
|
|
UINT8 ProcessorId; /* ACPI processor id */
|
|
UINT8 LocalSapicId; /* Processor local SAPIC id */
|
|
UINT8 LocalSapicEid; /* Processor local SAPIC eid */
|
|
UINT8 Reserved[3];
|
|
UINT32 ProcessorEnabled: 1;
|
|
UINT32 FlagsReserved: 31;
|
|
} LOCAL_SAPIC;
|
|
|
|
typedef struct /* LOCAL APIC OVERRIDE */
|
|
{
|
|
APIC_HEADER Header;
|
|
UINT16 Reserved;
|
|
UINT64 LocalApicAddress;
|
|
} LAPIC_OVERRIDE;
|
|
|
|
typedef struct /* PLATFORM INTERRUPT SOURCE */
|
|
{
|
|
APIC_HEADER Header;
|
|
UINT16 Polarity : 2; /* Polarity of input signal */
|
|
UINT16 TriggerMode: 2; /* Trigger mode of input signal */
|
|
UINT16 Reserved1 : 12;
|
|
UINT8 InterruptType; /* 1-PMI, 2-INIT, 3-Error */
|
|
UINT8 ProcessorId; /* Processor ID of destination */
|
|
UINT8 ProcessorEid; /* Processor EID of destination */
|
|
UINT8 IoSapicVector; /* Value for redirection table */
|
|
UINT32 GlobalSystemInterrupt; /* Global System Interrupt */
|
|
UINT32 Reserved2;
|
|
} PLATFORM_INTERRUPT_SOURCE;
|
|
|
|
#pragma pack()
|
|
|
|
static void
|
|
parse_interrupt_override(INTERRUPT_SOURCE_OVERRIDE *override)
|
|
{
|
|
if (bootverbose)
|
|
printf("\t\tBus=%d, Source=%d, Irq=0x%x\n", override->Bus,
|
|
override->Source, override->GlobalSystemInterrupt);
|
|
}
|
|
|
|
static void
|
|
parse_io_sapic(IO_SAPIC *sapic)
|
|
{
|
|
if (bootverbose)
|
|
printf("\t\tId=0x%x, Vector=0x%x, Address=0x%lx\n",
|
|
sapic->IoSapicId, sapic->Vector, sapic->IoSapicAddress);
|
|
sapic_create(sapic->IoSapicId, sapic->Vector, sapic->IoSapicAddress);
|
|
}
|
|
|
|
static void
|
|
parse_local_sapic(LOCAL_SAPIC *sapic)
|
|
{
|
|
if (bootverbose) {
|
|
printf("\t\tProcessorId=0x%x, Id=0x%x, Eid=0x%x",
|
|
sapic->ProcessorId, sapic->LocalSapicId,
|
|
sapic->LocalSapicEid);
|
|
if (!sapic->ProcessorEnabled)
|
|
printf(" (disabled)");
|
|
printf("\n");
|
|
}
|
|
#ifdef SMP
|
|
if (sapic->ProcessorEnabled)
|
|
cpu_mp_add(sapic->ProcessorId, sapic->LocalSapicId,
|
|
sapic->LocalSapicEid);
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
parse_lapic_override(LAPIC_OVERRIDE *lapic)
|
|
{
|
|
if (bootverbose)
|
|
printf("\t\tLocal APIC address=0x%lx\n",
|
|
lapic->LocalApicAddress);
|
|
ia64_lapic_address = lapic->LocalApicAddress;
|
|
}
|
|
|
|
static void
|
|
parse_platform_interrupt(PLATFORM_INTERRUPT_SOURCE *source)
|
|
{
|
|
if (bootverbose)
|
|
printf("\t\tPolarity=%d, TriggerMode=%d, Id=0x%x, "
|
|
"Eid=0x%x, Vector=0x%x, Irq=%d\n", source->Polarity,
|
|
source->TriggerMode, source->ProcessorId,
|
|
source->ProcessorEid, source->IoSapicVector,
|
|
source->GlobalSystemInterrupt);
|
|
}
|
|
|
|
static int
|
|
parse_madt(APIC_TABLE *madt, int countcpus)
|
|
{
|
|
char *end, *p;
|
|
int cpus;
|
|
|
|
end = (char *)madt + madt->Header.Length;
|
|
|
|
/*
|
|
* MADT header is followed by a number of variable length
|
|
* structures.
|
|
*/
|
|
|
|
if (countcpus) {
|
|
cpus = 0;
|
|
|
|
for (p = (char *)(madt + 1); p < end; ) {
|
|
APIC_HEADER *head = (APIC_HEADER *)p;
|
|
|
|
if (head->Type == APIC_LOCAL_SAPIC) {
|
|
LOCAL_SAPIC *sapic = (LOCAL_SAPIC *) head;
|
|
if (sapic->ProcessorEnabled)
|
|
cpus++;
|
|
}
|
|
p = p + head->Length;
|
|
}
|
|
|
|
return (cpus);
|
|
}
|
|
|
|
/* Save the address of the processor interrupt block. */
|
|
if (bootverbose)
|
|
printf("\tLocal APIC address=0x%x\n",
|
|
madt->LocalApicAddress);
|
|
ia64_lapic_address = madt->LocalApicAddress;
|
|
|
|
for (p = (char *)(madt + 1); p < end; ) {
|
|
APIC_HEADER *head = (APIC_HEADER *)p;
|
|
|
|
if (bootverbose)
|
|
printf("\t");
|
|
|
|
switch (head->Type) {
|
|
case APIC_PROC:
|
|
if (bootverbose)
|
|
printf("Local APIC entry\n");
|
|
break;
|
|
|
|
case APIC_IO:
|
|
if (bootverbose)
|
|
printf("I/O APIC entry\n");
|
|
break;
|
|
|
|
case APIC_INTERRUPT_SOURCE_OVERRIDE:
|
|
if (bootverbose)
|
|
printf("Interrupt source override entry\n");
|
|
parse_interrupt_override
|
|
((INTERRUPT_SOURCE_OVERRIDE *) head);
|
|
break;
|
|
|
|
case APIC_NMI:
|
|
if (bootverbose)
|
|
printf("NMI entry\n");
|
|
break;
|
|
|
|
case APIC_LOCAL_APIC_NMI:
|
|
if (bootverbose)
|
|
printf("Local APIC NMI entry\n");
|
|
break;
|
|
|
|
|
|
case APIC_LOCAL_APIC_OVERRIDE:
|
|
if (bootverbose)
|
|
printf("Local APIC override entry\n");
|
|
parse_lapic_override((LAPIC_OVERRIDE*)head);
|
|
break;
|
|
|
|
case APIC_IO_SAPIC:
|
|
if (bootverbose)
|
|
printf("I/O SAPIC entry\n");
|
|
parse_io_sapic((IO_SAPIC *) head);
|
|
break;
|
|
|
|
case APIC_LOCAL_SAPIC:
|
|
if (bootverbose)
|
|
printf("Local SAPIC entry\n");
|
|
parse_local_sapic((LOCAL_SAPIC *) head);
|
|
break;
|
|
|
|
case APIC_PLATFORM_INTERRUPT:
|
|
if (bootverbose)
|
|
printf("Platform interrupt entry\n");
|
|
parse_platform_interrupt
|
|
((PLATFORM_INTERRUPT_SOURCE *) head);
|
|
break;
|
|
|
|
default:
|
|
if (bootverbose)
|
|
printf("Unknown type %d entry\n", head->Type);
|
|
break;
|
|
}
|
|
|
|
p = p + head->Length;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static int
|
|
parse_table(int countcpus)
|
|
{
|
|
ACPI_POINTER rsdp_ptr;
|
|
RSDP_DESCRIPTOR *rsdp;
|
|
XSDT_DESCRIPTOR *xsdt;
|
|
ACPI_TABLE_HEADER *table;
|
|
int i, count;
|
|
|
|
if (AcpiOsGetRootPointer(ACPI_LOGICAL_ADDRESSING, &rsdp_ptr) != AE_OK)
|
|
return 0;
|
|
|
|
rsdp = (RSDP_DESCRIPTOR *)IA64_PHYS_TO_RR7(rsdp_ptr.Pointer.Physical);
|
|
xsdt = (XSDT_DESCRIPTOR *)IA64_PHYS_TO_RR7(rsdp->XsdtPhysicalAddress);
|
|
|
|
count = (UINT64 *)((char *)xsdt + xsdt->Header.Length)
|
|
- xsdt->TableOffsetEntry;
|
|
for (i = 0; i < count; i++) {
|
|
table = (ACPI_TABLE_HEADER *)
|
|
IA64_PHYS_TO_RR7(xsdt->TableOffsetEntry[i]);
|
|
|
|
if (bootverbose && !countcpus)
|
|
printf("Table '%c%c%c%c' at %p\n", table->Signature[0],
|
|
table->Signature[1], table->Signature[2],
|
|
table->Signature[3], table);
|
|
|
|
if (!strncmp(table->Signature, APIC_SIG, 4))
|
|
return (parse_madt((APIC_TABLE *) table, countcpus));
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
ia64_probe_sapics(void)
|
|
{
|
|
parse_table(0);
|
|
}
|
|
|
|
/*
|
|
* Count the number of local SAPIC entries in the APIC table. Every enabled
|
|
* entry corresponds to a processor.
|
|
*/
|
|
int
|
|
ia64_count_cpus(void)
|
|
{
|
|
return (parse_table(1));
|
|
}
|