APIC mode uses IO APICs
- kernel turns on IO APICs if no_apic is _not_ set or is equal 0 - pci driver must use the acpi driver to setup IRQ routing otherwise the system cannot work correctly except systems like KVM that use only legacy (E)ISA IRQs 0-15
This commit is contained in:
		
							parent
							
								
									5cc29a6c7e
								
							
						
					
					
						commit
						e6ebac015d
					
				@ -12,6 +12,7 @@ PUBLIC struct machine machine;
 | 
			
		||||
#define IRQ_TABLE_ENTRIES	(PCI_MAX_DEVICES * PCI_MAX_PINS)
 | 
			
		||||
 | 
			
		||||
PRIVATE int irqtable[IRQ_TABLE_ENTRIES];
 | 
			
		||||
PRIVATE ACPI_HANDLE pci_root_handle; 
 | 
			
		||||
 | 
			
		||||
/* don't know where ACPI tables are, we may need to access any memory */
 | 
			
		||||
PRIVATE int init_mem_priv(void)
 | 
			
		||||
@ -93,7 +94,7 @@ PRIVATE ACPI_STATUS get_irq_resource(ACPI_RESOURCE *res, void *context)
 | 
			
		||||
		irq = &res->Data.Irq;
 | 
			
		||||
		add_irq(tbl->Address >> 16, tbl->Pin,
 | 
			
		||||
				irq->Interrupts[tbl->SourceIndex]);
 | 
			
		||||
	} if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
 | 
			
		||||
	} else if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
 | 
			
		||||
		ACPI_RESOURCE_EXTENDED_IRQ *irq;
 | 
			
		||||
		
 | 
			
		||||
		add_irq(tbl->Address >> 16, tbl->Pin,
 | 
			
		||||
@ -103,32 +104,18 @@ PRIVATE ACPI_STATUS get_irq_resource(ACPI_RESOURCE *res, void *context)
 | 
			
		||||
	return AE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE ACPI_STATUS add_pci_dev(ACPI_HANDLE handle,
 | 
			
		||||
				UINT32 level,
 | 
			
		||||
				void *context,
 | 
			
		||||
				void **retval)
 | 
			
		||||
PRIVATE ACPI_STATUS get_pci_irq_routing(ACPI_HANDLE handle)
 | 
			
		||||
{
 | 
			
		||||
	ACPI_STATUS status;
 | 
			
		||||
	ACPI_BUFFER abuff;
 | 
			
		||||
	char buff[4096];
 | 
			
		||||
	ACPI_PCI_ROUTING_TABLE *tbl;
 | 
			
		||||
	int i;
 | 
			
		||||
	static unsigned called;
 | 
			
		||||
 | 
			
		||||
	if (++called > 1) {
 | 
			
		||||
		printf("ACPI: Warning! Multi rooted PCI is not supported!\n");
 | 
			
		||||
		return AE_OK;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	abuff.Length = sizeof(buff);
 | 
			
		||||
	abuff.Pointer = buff;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < IRQ_TABLE_ENTRIES; i++)
 | 
			
		||||
		irqtable[i] = -1;
 | 
			
		||||
 | 
			
		||||
	status = AcpiGetIrqRoutingTable(handle, &abuff);
 | 
			
		||||
	if (ACPI_FAILURE(status)) {
 | 
			
		||||
		printf("ACPI: ACPI no routing table\n");
 | 
			
		||||
		return AE_OK;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -154,15 +141,51 @@ PRIVATE ACPI_STATUS add_pci_dev(ACPI_HANDLE handle,
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	
 | 
			
		||||
	return AE_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE ACPI_STATUS add_pci_root_dev(ACPI_HANDLE handle,
 | 
			
		||||
				UINT32 level,
 | 
			
		||||
				void *context,
 | 
			
		||||
				void **retval)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	static unsigned called;
 | 
			
		||||
 | 
			
		||||
	if (++called > 1) {
 | 
			
		||||
		printf("ACPI: Warning! Multi rooted PCI is not supported!\n");
 | 
			
		||||
		return AE_OK;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < IRQ_TABLE_ENTRIES; i++)
 | 
			
		||||
		irqtable[i] = -1;
 | 
			
		||||
 | 
			
		||||
	return get_pci_irq_routing(handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE ACPI_STATUS add_pci_dev(ACPI_HANDLE handle,
 | 
			
		||||
				UINT32 level,
 | 
			
		||||
				void *context,
 | 
			
		||||
				void **retval)
 | 
			
		||||
{
 | 
			
		||||
	/* skip pci root when we get to it again */
 | 
			
		||||
	if (handle == pci_root_handle)
 | 
			
		||||
		return AE_OK;
 | 
			
		||||
 | 
			
		||||
	return get_pci_irq_routing(handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE void scan_devices(void)
 | 
			
		||||
{
 | 
			
		||||
	ACPI_STATUS(status);
 | 
			
		||||
	
 | 
			
		||||
	/* get the root first */
 | 
			
		||||
	status = AcpiGetDevices("PNP0A03", add_pci_root_dev, NULL, NULL);
 | 
			
		||||
	assert(ACPI_SUCCESS(status));
 | 
			
		||||
 | 
			
		||||
	status = AcpiGetDevices("PNP0A03", add_pci_dev, NULL, NULL);
 | 
			
		||||
	/* get the rest of the devices that implement _PRT */
 | 
			
		||||
	status = AcpiGetDevices(NULL, add_pci_dev, NULL, NULL);
 | 
			
		||||
	assert(ACPI_SUCCESS(status));
 | 
			
		||||
}
 | 
			
		||||
PRIVATE ACPI_STATUS init_acpica(void)
 | 
			
		||||
 | 
			
		||||
@ -883,7 +883,9 @@ AcpiOsReadMemory (
 | 
			
		||||
    UINT32                  *Value,
 | 
			
		||||
    UINT32                  Width)
 | 
			
		||||
{
 | 
			
		||||
	panic("NOTIMPLEMENTED %s\n", __func__);
 | 
			
		||||
	/* FIXME this operation is ignored */
 | 
			
		||||
	*Value = 0;
 | 
			
		||||
 | 
			
		||||
	return (AE_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -908,7 +910,7 @@ AcpiOsWriteMemory (
 | 
			
		||||
    UINT32                  Value,
 | 
			
		||||
    UINT32                  Width)
 | 
			
		||||
{
 | 
			
		||||
	panic("NOTIMPLEMENTED %s\n", __func__);
 | 
			
		||||
	/* FIXME this operation is ignored */
 | 
			
		||||
	return (AE_OK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -962,10 +962,10 @@ PRIVATE int acpi_get_irq(unsigned dev, unsigned pin)
 | 
			
		||||
 | 
			
		||||
PRIVATE int derive_irq(struct pcidev * dev, int pin)
 | 
			
		||||
{
 | 
			
		||||
	struct pcidev * parent_brige;
 | 
			
		||||
	struct pcidev * parent_bridge;
 | 
			
		||||
	int slot;
 | 
			
		||||
	
 | 
			
		||||
	parent_brige = &pcidev[pcibus[get_busind(dev->pd_busnr)].pb_devind];
 | 
			
		||||
	parent_bridge = &pcidev[pcibus[get_busind(dev->pd_busnr)].pb_devind];
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * We don't support PCI-Express, no ARI, decode the slot of the device
 | 
			
		||||
@ -973,7 +973,7 @@ PRIVATE int derive_irq(struct pcidev * dev, int pin)
 | 
			
		||||
	 */
 | 
			
		||||
	slot = ((dev->pd_func) >> 3) & 0x1f;
 | 
			
		||||
 | 
			
		||||
	return acpi_get_irq(parent_brige->pd_dev, (pin + slot) % 4);
 | 
			
		||||
	return acpi_get_irq(parent_bridge->pd_dev, (pin + slot) % 4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*
 | 
			
		||||
@ -998,15 +998,16 @@ int devind;
 | 
			
		||||
		if (irq >= 0) {
 | 
			
		||||
			ilr = irq;
 | 
			
		||||
			pci_attr_w8(devind, PCI_ILR, ilr);
 | 
			
		||||
			printf("PCI: ACPI IRQ %d for "
 | 
			
		||||
					"device %d.%d.%d INT%c\n",
 | 
			
		||||
					irq,
 | 
			
		||||
					pcidev[devind].pd_busnr,
 | 
			
		||||
					pcidev[devind].pd_dev,
 | 
			
		||||
					pcidev[devind].pd_func,
 | 
			
		||||
					'A' + ipr-1);
 | 
			
		||||
			if (debug)
 | 
			
		||||
				printf("PCI: ACPI IRQ %d for "
 | 
			
		||||
						"device %d.%d.%d INT%c\n",
 | 
			
		||||
						irq,
 | 
			
		||||
						pcidev[devind].pd_busnr,
 | 
			
		||||
						pcidev[devind].pd_dev,
 | 
			
		||||
						pcidev[devind].pd_func,
 | 
			
		||||
						'A' + ipr-1);
 | 
			
		||||
		}
 | 
			
		||||
		else {
 | 
			
		||||
		else if (debug) {
 | 
			
		||||
			printf("PCI: no ACPI IRQ routing for "
 | 
			
		||||
					"device %d.%d.%d INT%c\n",
 | 
			
		||||
					pcidev[devind].pd_busnr,
 | 
			
		||||
 | 
			
		||||
@ -23,8 +23,8 @@ DPADD+=	${LIBC}
 | 
			
		||||
LDADD+=	-lc
 | 
			
		||||
.endif
 | 
			
		||||
 | 
			
		||||
CPPFLAGS+=	-I${.CURDIR}/arch/${ARCH}/include -I${MINIXSRCDIR}
 | 
			
		||||
AFLAGS+=	-I${.CURDIR}/arch/${ARCH}/include -I${MINIXSRCDIR}
 | 
			
		||||
CPPFLAGS+=	-I${.CURDIR} -I${.CURDIR}/arch/${ARCH}/include -I${MINIXSRCDIR}
 | 
			
		||||
AFLAGS+=	-I${.CURDIR} -I${.CURDIR}/arch/${ARCH}/include -I${MINIXSRCDIR}
 | 
			
		||||
 | 
			
		||||
INSTALLFLAGS+=	-S 0
 | 
			
		||||
BINDIR=	/usr/sbin
 | 
			
		||||
 | 
			
		||||
@ -1,83 +1,5 @@
 | 
			
		||||
#include "kernel/kernel.h"
 | 
			
		||||
 | 
			
		||||
/* ACPI root system description pointer */
 | 
			
		||||
struct acpi_rsdp {
 | 
			
		||||
	char	signature[8]; /* must be "RSD PTR " */
 | 
			
		||||
	u8_t	checksum;
 | 
			
		||||
	char	oemid[6];
 | 
			
		||||
	u8_t	revision;
 | 
			
		||||
	u32_t	rsdt_addr;
 | 
			
		||||
	u32_t	length;
 | 
			
		||||
}; 
 | 
			
		||||
 | 
			
		||||
#define ACPI_SDT_SIGNATURE_LEN	4
 | 
			
		||||
 | 
			
		||||
#define ACPI_SDT_SIGNATURE(name)	#name
 | 
			
		||||
 | 
			
		||||
/* header common to all system description tables */
 | 
			
		||||
struct acpi_sdt_header {
 | 
			
		||||
	char	signature[ACPI_SDT_SIGNATURE_LEN];
 | 
			
		||||
	u32_t	length;
 | 
			
		||||
	u8_t	revision;
 | 
			
		||||
	u8_t	checksum;
 | 
			
		||||
	char	oemid[6];
 | 
			
		||||
	char	oem_table_id[8];
 | 
			
		||||
	u32_t	oem_revision;
 | 
			
		||||
	u32_t	creator_id;
 | 
			
		||||
	u32_t	creator_revision;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct acpi_madt_hdr {
 | 
			
		||||
	struct acpi_sdt_header	hdr;
 | 
			
		||||
	u32_t			local_apic_address;
 | 
			
		||||
	u32_t			flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define ACPI_MADT_TYPE_LAPIC		0
 | 
			
		||||
#define ACPI_MADT_TYPE_IOAPIC		1
 | 
			
		||||
#define ACPI_MADT_TYPE_INT_SRC		2
 | 
			
		||||
#define ACPI_MADT_TYPE_NMI_SRC		3
 | 
			
		||||
#define ACPI_MADT_TYPE_LAPIC_NMI	4
 | 
			
		||||
#define ACPI_MADT_TYPE_LAPIC_ADRESS	5
 | 
			
		||||
#define ACPI_MADT_TYPE_IOSAPIC		6
 | 
			
		||||
#define ACPI_MADT_TYPE_LSAPIC		7
 | 
			
		||||
#define ACPI_MADT_TYPE_PLATFORM_INT_SRC	8
 | 
			
		||||
#define ACPI_MADT_TYPE_Lx2APIC		9
 | 
			
		||||
#define ACPI_MADT_TYPE_Lx2APIC_NMI	10
 | 
			
		||||
 | 
			
		||||
struct acpi_madt_item_hdr{
 | 
			
		||||
	u8_t	type;
 | 
			
		||||
	u8_t	length;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct acpi_madt_lapic {
 | 
			
		||||
	struct acpi_madt_item_hdr hdr;
 | 
			
		||||
	u8_t	acpi_cpu_id;
 | 
			
		||||
	u8_t	apic_id;
 | 
			
		||||
	u32_t	flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct acpi_madt_ioapic {
 | 
			
		||||
	struct acpi_madt_item_hdr hdr;
 | 
			
		||||
	u8_t	id;
 | 
			
		||||
	u8_t	__reserved;
 | 
			
		||||
	u32_t	address;
 | 
			
		||||
	u32_t	global_int_base;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct acpi_madt_int_src {
 | 
			
		||||
	struct acpi_madt_item_hdr hdr;
 | 
			
		||||
	u8_t	bus;
 | 
			
		||||
	u8_t	bus_int;
 | 
			
		||||
	u32_t	global_int;
 | 
			
		||||
	u16_t	mps_flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct acpi_madt_nmi {
 | 
			
		||||
	struct acpi_madt_item_hdr hdr;
 | 
			
		||||
	u16_t	flags;
 | 
			
		||||
	u32_t	global_int;
 | 
			
		||||
};
 | 
			
		||||
#include "acpi.h"
 | 
			
		||||
 | 
			
		||||
typedef int ((* acpi_read_t)(phys_bytes addr, void * buff, size_t size));
 | 
			
		||||
 | 
			
		||||
@ -299,3 +221,25 @@ PUBLIC void acpi_init(void)
 | 
			
		||||
		sdt_trans[i].length = hdr.length;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC struct acpi_madt_ioapic * acpi_get_ioapic_next(void)
 | 
			
		||||
{
 | 
			
		||||
	static unsigned idx = 0;
 | 
			
		||||
	static struct acpi_madt_hdr * madt_hdr;
 | 
			
		||||
 | 
			
		||||
	struct acpi_madt_ioapic * ret;
 | 
			
		||||
 | 
			
		||||
	if (idx == 0) {
 | 
			
		||||
		madt_hdr = (struct acpi_madt_hdr *)
 | 
			
		||||
			phys2vir(acpi_get_table_base("APIC"));
 | 
			
		||||
		if (madt_hdr == NULL)
 | 
			
		||||
			return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = (struct acpi_madt_ioapic *)
 | 
			
		||||
		acpi_madt_get_typed_item(madt_hdr, ACPI_MADT_TYPE_IOAPIC, idx);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		idx++;
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,92 @@
 | 
			
		||||
 | 
			
		||||
#include "kernel/kernel.h"
 | 
			
		||||
 | 
			
		||||
/* ACPI root system description pointer */
 | 
			
		||||
struct acpi_rsdp {
 | 
			
		||||
	char	signature[8]; /* must be "RSD PTR " */
 | 
			
		||||
	u8_t	checksum;
 | 
			
		||||
	char	oemid[6];
 | 
			
		||||
	u8_t	revision;
 | 
			
		||||
	u32_t	rsdt_addr;
 | 
			
		||||
	u32_t	length;
 | 
			
		||||
}; 
 | 
			
		||||
 | 
			
		||||
#define ACPI_SDT_SIGNATURE_LEN	4
 | 
			
		||||
 | 
			
		||||
#define ACPI_SDT_SIGNATURE(name)	#name
 | 
			
		||||
 | 
			
		||||
/* header common to all system description tables */
 | 
			
		||||
struct acpi_sdt_header {
 | 
			
		||||
	char	signature[ACPI_SDT_SIGNATURE_LEN];
 | 
			
		||||
	u32_t	length;
 | 
			
		||||
	u8_t	revision;
 | 
			
		||||
	u8_t	checksum;
 | 
			
		||||
	char	oemid[6];
 | 
			
		||||
	char	oem_table_id[8];
 | 
			
		||||
	u32_t	oem_revision;
 | 
			
		||||
	u32_t	creator_id;
 | 
			
		||||
	u32_t	creator_revision;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct acpi_madt_hdr {
 | 
			
		||||
	struct acpi_sdt_header	hdr;
 | 
			
		||||
	u32_t			local_apic_address;
 | 
			
		||||
	u32_t			flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define ACPI_MADT_TYPE_LAPIC		0
 | 
			
		||||
#define ACPI_MADT_TYPE_IOAPIC		1
 | 
			
		||||
#define ACPI_MADT_TYPE_INT_SRC		2
 | 
			
		||||
#define ACPI_MADT_TYPE_NMI_SRC		3
 | 
			
		||||
#define ACPI_MADT_TYPE_LAPIC_NMI	4
 | 
			
		||||
#define ACPI_MADT_TYPE_LAPIC_ADRESS	5
 | 
			
		||||
#define ACPI_MADT_TYPE_IOSAPIC		6
 | 
			
		||||
#define ACPI_MADT_TYPE_LSAPIC		7
 | 
			
		||||
#define ACPI_MADT_TYPE_PLATFORM_INT_SRC	8
 | 
			
		||||
#define ACPI_MADT_TYPE_Lx2APIC		9
 | 
			
		||||
#define ACPI_MADT_TYPE_Lx2APIC_NMI	10
 | 
			
		||||
 | 
			
		||||
struct acpi_madt_item_hdr{
 | 
			
		||||
	u8_t	type;
 | 
			
		||||
	u8_t	length;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct acpi_madt_lapic {
 | 
			
		||||
	struct acpi_madt_item_hdr hdr;
 | 
			
		||||
	u8_t	acpi_cpu_id;
 | 
			
		||||
	u8_t	apic_id;
 | 
			
		||||
	u32_t	flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct acpi_madt_ioapic {
 | 
			
		||||
	struct acpi_madt_item_hdr hdr;
 | 
			
		||||
	u8_t	id;
 | 
			
		||||
	u8_t	__reserved;
 | 
			
		||||
	u32_t	address;
 | 
			
		||||
	u32_t	global_int_base;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct acpi_madt_int_src {
 | 
			
		||||
	struct acpi_madt_item_hdr hdr;
 | 
			
		||||
	u8_t	bus;
 | 
			
		||||
	u8_t	bus_int;
 | 
			
		||||
	u32_t	global_int;
 | 
			
		||||
	u16_t	mps_flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct acpi_madt_nmi {
 | 
			
		||||
	struct acpi_madt_item_hdr hdr;
 | 
			
		||||
	u16_t	flags;
 | 
			
		||||
	u32_t	global_int;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
_PROTOTYPE(void acpi_init, (void));
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * Returns a pointer to the io acpi structure in the MADT table in ACPI. The
 | 
			
		||||
 * pointer is valid only until paging is turned off. No memory is allocated in
 | 
			
		||||
 * this function thus no memory needs to be freed
 | 
			
		||||
 */
 | 
			
		||||
_PROTOTYPE(struct acpi_madt_ioapic * acpi_get_ioapic_next, (void));
 | 
			
		||||
 | 
			
		||||
#endif /* __ACPI_H__ */
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,13 @@
 | 
			
		||||
 * APIC handling routines. APIC is a requirement for SMP
 | 
			
		||||
 */
 | 
			
		||||
#include "kernel/kernel.h"
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include <minix/portio.h>
 | 
			
		||||
 | 
			
		||||
#include <minix/syslib.h>
 | 
			
		||||
#include <machine/cmos.h>
 | 
			
		||||
 | 
			
		||||
#include "kernel/proc.h"
 | 
			
		||||
#include "kernel/glo.h"
 | 
			
		||||
@ -18,25 +20,111 @@
 | 
			
		||||
#include "apic_asm.h"
 | 
			
		||||
#include "kernel/clock.h"
 | 
			
		||||
#include "glo.h"
 | 
			
		||||
#include "hw_intr.h"
 | 
			
		||||
 | 
			
		||||
#include "acpi.h"
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_WATCHDOG
 | 
			
		||||
#include "kernel/watchdog.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define APIC_ENABLE		0x100
 | 
			
		||||
#define APIC_FOCUS_DISABLED	(1 << 9)
 | 
			
		||||
#define APIC_SIV		0xFF
 | 
			
		||||
 | 
			
		||||
#define APIC_TDCR_2	0x00
 | 
			
		||||
#define APIC_TDCR_4	0x01
 | 
			
		||||
#define APIC_TDCR_8	0x02
 | 
			
		||||
#define APIC_TDCR_16	0x03
 | 
			
		||||
#define APIC_TDCR_32	0x08
 | 
			
		||||
#define APIC_TDCR_64	0x09
 | 
			
		||||
#define APIC_TDCR_128	0x0a
 | 
			
		||||
#define APIC_TDCR_1	0x0b
 | 
			
		||||
 | 
			
		||||
#define IS_SET(mask)		(mask)
 | 
			
		||||
#define IS_CLEAR(mask)		0
 | 
			
		||||
 | 
			
		||||
#define APIC_LVTT_VECTOR_MASK	0x000000FF
 | 
			
		||||
#define APIC_LVTT_DS_PENDING	(1 << 12)
 | 
			
		||||
#define APIC_LVTT_MASK		(1 << 16)
 | 
			
		||||
#define APIC_LVTT_TM		(1 << 17)
 | 
			
		||||
 | 
			
		||||
#define APIC_LVT_IIPP_MASK	0x00002000
 | 
			
		||||
#define APIC_LVT_IIPP_AH	0x00002000
 | 
			
		||||
#define APIC_LVT_IIPP_AL	0x00000000
 | 
			
		||||
 | 
			
		||||
#define APIC_LVT_TM_ONESHOT	IS_CLEAR(APIC_LVTT_TM)
 | 
			
		||||
#define APIC_LVT_TM_PERIODIC	IS_SET(APIC_LVTT_TM)
 | 
			
		||||
 | 
			
		||||
#define IOAPIC_REGSEL		0x0
 | 
			
		||||
#define IOAPIC_RW		0x10
 | 
			
		||||
 | 
			
		||||
#define APIC_ICR_DM_MASK		0x00000700
 | 
			
		||||
#define APIC_ICR_VECTOR			APIC_LVTT_VECTOR_MASK
 | 
			
		||||
#define APIC_ICR_DM_FIXED		(0 << 8)
 | 
			
		||||
#define APIC_ICR_DM_LOWEST_PRIORITY	(1 << 8)
 | 
			
		||||
#define APIC_ICR_DM_SMI			(2 << 8)
 | 
			
		||||
#define APIC_ICR_DM_RESERVED		(3 << 8)
 | 
			
		||||
#define APIC_ICR_DM_NMI			(4 << 8)
 | 
			
		||||
#define APIC_ICR_DM_INIT		(5 << 8)
 | 
			
		||||
#define APIC_ICR_DM_STARTUP		(6 << 8)
 | 
			
		||||
#define APIC_ICR_DM_EXTINT		(7 << 8)
 | 
			
		||||
 | 
			
		||||
#define APIC_ICR_DM_PHYSICAL		(0 << 11)
 | 
			
		||||
#define APIC_ICR_DM_LOGICAL		(1 << 11)
 | 
			
		||||
 | 
			
		||||
#define APIC_ICR_DELIVERY_PENDING	(1 << 12)
 | 
			
		||||
 | 
			
		||||
#define APIC_ICR_INT_POLARITY		(1 << 13)
 | 
			
		||||
#define APIC_ICR_INTPOL_LOW		IS_SET(APIC_ICR_INT_POLARITY)
 | 
			
		||||
#define APIC_ICR_INTPOL_HIGH		IS_CLEAR(APIC_ICR_INT_POLARITY)
 | 
			
		||||
 | 
			
		||||
#define APIC_ICR_LEVEL_ASSERT		(1 << 14)
 | 
			
		||||
#define APIC_ICR_LEVEL_DEASSERT		(0 << 14)
 | 
			
		||||
 | 
			
		||||
#define APIC_ICR_TRIGGER		(1 << 15)
 | 
			
		||||
#define APIC_ICR_TM_LEVEL		IS_CLEAR(APIC_ICR_TRIGGER)
 | 
			
		||||
#define APIC_ICR_TM_EDGE		IS_CLEAR(APIC_ICR_TRIGGER)
 | 
			
		||||
 | 
			
		||||
#define APIC_ICR_INT_MASK		(1 << 16)
 | 
			
		||||
 | 
			
		||||
#define APIC_ICR_DEST_FIELD		(0 << 18)
 | 
			
		||||
#define APIC_ICR_DEST_SELF		(1 << 18)
 | 
			
		||||
#define APIC_ICR_DEST_ALL		(2 << 18)
 | 
			
		||||
#define APIC_ICR_DEST_ALL_BUT_SELF	(3 << 18)
 | 
			
		||||
 | 
			
		||||
#define IA32_APIC_BASE	0x1b
 | 
			
		||||
#define IA32_APIC_BASE_ENABLE_BIT	11
 | 
			
		||||
 | 
			
		||||
/* FIXME we should spread the irqs across as many priority levels as possible
 | 
			
		||||
 * due to buggy hw */
 | 
			
		||||
#define LAPIC_VECTOR(irq)	(IRQ0_VECTOR +(irq))
 | 
			
		||||
 | 
			
		||||
#define IOAPIC_IRQ_STATE_MASKED 0x1
 | 
			
		||||
 | 
			
		||||
/* currently only 2 interrupt priority levels are used */
 | 
			
		||||
#define SPL0				0x0
 | 
			
		||||
#define	SPLHI				0xF
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * to make APIC work if SMP is not configured, we need to set the maximal number
 | 
			
		||||
 * of CPUS to 1, cpuid to return 0 and the current cpu is always BSP
 | 
			
		||||
 */
 | 
			
		||||
#define CONFIG_MAX_CPUS 1
 | 
			
		||||
#define cpu_is_bsp(x) 1
 | 
			
		||||
 | 
			
		||||
PUBLIC struct io_apic io_apic[MAX_NR_IOAPICS];
 | 
			
		||||
PUBLIC unsigned nioapics;
 | 
			
		||||
 | 
			
		||||
struct irq;
 | 
			
		||||
typedef void (* eoi_method_t)(struct irq *);
 | 
			
		||||
 | 
			
		||||
struct irq {
 | 
			
		||||
	struct io_apic * 	ioa;
 | 
			
		||||
	unsigned		pin;
 | 
			
		||||
	unsigned		vector;
 | 
			
		||||
	eoi_method_t		eoi;
 | 
			
		||||
	unsigned		state;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
PRIVATE struct irq io_apic_irq[NR_IRQ_VECTORS];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define lapic_write_icr1(val)	lapic_write(LAPIC_ICR1, val)
 | 
			
		||||
#define lapic_write_icr2(val)	lapic_write(LAPIC_ICR2, val)
 | 
			
		||||
 | 
			
		||||
@ -45,23 +133,20 @@
 | 
			
		||||
 | 
			
		||||
#define VERBOSE_APIC(x) x
 | 
			
		||||
 | 
			
		||||
PRIVATE int ioapic_enabled;
 | 
			
		||||
PRIVATE u32_t ioapic_id_mask[8];
 | 
			
		||||
PUBLIC int ioapic_enabled;
 | 
			
		||||
PUBLIC u32_t lapic_addr_vaddr;
 | 
			
		||||
PUBLIC vir_bytes lapic_addr;
 | 
			
		||||
PUBLIC vir_bytes lapic_eoi_addr;
 | 
			
		||||
 | 
			
		||||
PRIVATE volatile int probe_ticks;
 | 
			
		||||
PRIVATE volatile unsigned probe_ticks;
 | 
			
		||||
PRIVATE	u64_t tsc0, tsc1;
 | 
			
		||||
PRIVATE	u32_t lapic_tctr0, lapic_tctr1;
 | 
			
		||||
 | 
			
		||||
/* FIXME: this is only accessed from assembly, never from C. Move to asm? */
 | 
			
		||||
PUBLIC u8_t apicid2cpuid[MAX_NR_APICIDS+1];  /* Accessed from asm */
 | 
			
		||||
 | 
			
		||||
PRIVATE unsigned apic_imcrp;
 | 
			
		||||
PRIVATE unsigned nintrs;
 | 
			
		||||
PRIVATE const unsigned nlints = 0;
 | 
			
		||||
 | 
			
		||||
#define apic_eoi() do { *((volatile u32_t *) lapic_eoi_addr) = 0; } while(0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * FIXME this should be a cpulocal variable but there are some problems with
 | 
			
		||||
 * arch specific cpulocals. As this variable is write-once-read-only it is ok to
 | 
			
		||||
@ -71,8 +156,224 @@ PRIVATE u32_t lapic_bus_freq[CONFIG_MAX_CPUS];
 | 
			
		||||
/* the probe period will be roughly 100ms */
 | 
			
		||||
#define PROBE_TICKS	(system_hz / 10)
 | 
			
		||||
 | 
			
		||||
PRIVATE u32_t pci_config_intr_data;
 | 
			
		||||
PRIVATE int lapic_extint_assigned = 0;
 | 
			
		||||
#define IOAPIC_IOREGSEL	0x0
 | 
			
		||||
#define IOAPIC_IOWIN	0x10
 | 
			
		||||
 | 
			
		||||
PUBLIC u32_t ioapic_read(u32_t ioa_base, u32_t reg)
 | 
			
		||||
{
 | 
			
		||||
	*((u32_t *)(ioa_base + IOAPIC_IOREGSEL)) = (reg & 0xff);
 | 
			
		||||
	return *(u32_t *)(ioa_base + IOAPIC_IOWIN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE void ioapic_write(u32_t ioa_base, u8_t reg, u32_t val)
 | 
			
		||||
{
 | 
			
		||||
	*((u32_t *)(ioa_base + IOAPIC_IOREGSEL)) = reg;
 | 
			
		||||
	*((u32_t *)(ioa_base + IOAPIC_IOWIN)) = val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FORWARD _PROTOTYPE(void lapic_microsec_sleep, (unsigned count));
 | 
			
		||||
FORWARD _PROTOTYPE(void apic_idt_init, (const int reset));
 | 
			
		||||
 | 
			
		||||
PRIVATE void ioapic_enable_pin(vir_bytes ioapic_addr, int pin)
 | 
			
		||||
{
 | 
			
		||||
	u32_t lo = ioapic_read(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2);
 | 
			
		||||
 | 
			
		||||
	lo &= ~APIC_ICR_INT_MASK;
 | 
			
		||||
	ioapic_write(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2, lo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE void ioapic_disable_pin(vir_bytes ioapic_addr, int pin)
 | 
			
		||||
{
 | 
			
		||||
	u32_t lo = ioapic_read(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2);
 | 
			
		||||
 | 
			
		||||
	lo |= APIC_ICR_INT_MASK;
 | 
			
		||||
	ioapic_write(ioapic_addr, IOAPIC_REDIR_TABLE + pin * 2, lo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE void ioapic_redirt_entry_read(void * ioapic_addr,
 | 
			
		||||
					int entry,
 | 
			
		||||
					u32_t *hi,
 | 
			
		||||
					u32_t *lo)
 | 
			
		||||
{
 | 
			
		||||
	*lo = ioapic_read((u32_t)ioapic_addr, (u8_t) (IOAPIC_REDIR_TABLE + entry * 2));
 | 
			
		||||
	*hi = ioapic_read((u32_t)ioapic_addr, (u8_t) (IOAPIC_REDIR_TABLE + entry * 2 + 1));
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE void ioapic_redirt_entry_write(void * ioapic_addr,
 | 
			
		||||
					int entry,
 | 
			
		||||
					u32_t hi,
 | 
			
		||||
					u32_t lo)
 | 
			
		||||
{
 | 
			
		||||
#if 0
 | 
			
		||||
	VERBOSE_APIC(printf("IO apic redir entry %3d "
 | 
			
		||||
				"write 0x%08x 0x%08x\n", entry, hi, lo));
 | 
			
		||||
#endif
 | 
			
		||||
	ioapic_write((u32_t)ioapic_addr, (u8_t) (IOAPIC_REDIR_TABLE + entry * 2 + 1), hi);
 | 
			
		||||
	ioapic_write((u32_t)ioapic_addr, (u8_t) (IOAPIC_REDIR_TABLE + entry * 2), lo);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define apic_read_tmr_vector(vec) \
 | 
			
		||||
		lapic_read(LAPIC_TMR + 0x10 * ((vec) >> 5))
 | 
			
		||||
 | 
			
		||||
#define apic_read_irr_vector(vec) \
 | 
			
		||||
		lapic_read(LAPIC_IRR + 0x10 * ((vec) >> 5))
 | 
			
		||||
 | 
			
		||||
#define apic_read_isr_vector(vec) \
 | 
			
		||||
		lapic_read(LAPIC_ISR + 0x10 * ((vec) >> 5))
 | 
			
		||||
 | 
			
		||||
#define lapic_test_delivery_val(val, vector) ((val) & (1 << ((vector) & 0x1f)))
 | 
			
		||||
 | 
			
		||||
PRIVATE void ioapic_eoi_level(struct irq * irq)
 | 
			
		||||
{
 | 
			
		||||
	reg_t tmr;
 | 
			
		||||
 | 
			
		||||
	tmr = apic_read_tmr_vector(irq->vector);
 | 
			
		||||
	apic_eoi();
 | 
			
		||||
 | 
			
		||||
	/* 
 | 
			
		||||
	 * test if it was a level or edge triggered interrupt. If delivered as
 | 
			
		||||
	 * edge exec the workaround for broken chipsets
 | 
			
		||||
	 */
 | 
			
		||||
	if (!lapic_test_delivery_val(tmr, irq->vector)) {
 | 
			
		||||
		int is_masked;
 | 
			
		||||
		u32_t lo;
 | 
			
		||||
		
 | 
			
		||||
		panic("EDGE instead of LEVEL!");
 | 
			
		||||
 | 
			
		||||
		lo = ioapic_read(irq->ioa->addr,
 | 
			
		||||
				IOAPIC_REDIR_TABLE + irq->pin * 2);
 | 
			
		||||
 | 
			
		||||
		is_masked = lo & APIC_ICR_INT_MASK;
 | 
			
		||||
 | 
			
		||||
		/* set mask and edge */
 | 
			
		||||
		lo |= APIC_ICR_INT_MASK;
 | 
			
		||||
		lo &= ~APIC_ICR_TRIGGER;
 | 
			
		||||
		ioapic_write(irq->ioa->addr,
 | 
			
		||||
				IOAPIC_REDIR_TABLE + irq->pin * 2, lo);
 | 
			
		||||
 | 
			
		||||
		/* set back to level and restore the mask bit */
 | 
			
		||||
		lo = ioapic_read(irq->ioa->addr,
 | 
			
		||||
				IOAPIC_REDIR_TABLE + irq->pin * 2);
 | 
			
		||||
 | 
			
		||||
		lo |= APIC_ICR_TRIGGER;
 | 
			
		||||
		if (is_masked)
 | 
			
		||||
			lo |= APIC_ICR_INT_MASK;
 | 
			
		||||
		else
 | 
			
		||||
			lo &= ~APIC_ICR_INT_MASK;
 | 
			
		||||
		ioapic_write(irq->ioa->addr,
 | 
			
		||||
				IOAPIC_REDIR_TABLE + irq->pin * 2, lo);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE void ioapic_eoi_edge(__unused struct irq * irq)
 | 
			
		||||
{
 | 
			
		||||
	apic_eoi();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC void ioapic_eoi(int irq)
 | 
			
		||||
{
 | 
			
		||||
	if (ioapic_enabled) {
 | 
			
		||||
		io_apic_irq[irq].eoi(&io_apic_irq[irq]);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
		irq_8259_eoi(irq);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
PUBLIC int ioapic_enable_all(void)
 | 
			
		||||
{
 | 
			
		||||
	i8259_disable();
 | 
			
		||||
 | 
			
		||||
	if (apic_imcrp) {
 | 
			
		||||
		/* Select IMCR and disconnect 8259s. */
 | 
			
		||||
		outb(0x22, 0x70);
 | 
			
		||||
		outb(0x23, 0x01);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ioapic_enabled = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* disables a single IO APIC */
 | 
			
		||||
PRIVATE void ioapic_disable(struct io_apic * ioapic)
 | 
			
		||||
{
 | 
			
		||||
	unsigned p;
 | 
			
		||||
	
 | 
			
		||||
	for (p = 0; p < io_apic->pins; p++) {
 | 
			
		||||
		u32_t low_32, hi_32;
 | 
			
		||||
		low_32 = ioapic_read((u32_t)ioapic->addr,
 | 
			
		||||
				(uint8_t) (IOAPIC_REDIR_TABLE + p * 2));
 | 
			
		||||
		hi_32 = ioapic_read((u32_t)ioapic->addr,
 | 
			
		||||
				(uint8_t) (IOAPIC_REDIR_TABLE + p * 2 + 1));
 | 
			
		||||
 | 
			
		||||
		if (!(low_32 & APIC_ICR_INT_MASK)) {
 | 
			
		||||
			low_32 |= APIC_ICR_INT_MASK;
 | 
			
		||||
			ioapic_write((u32_t)ioapic->addr,
 | 
			
		||||
				(uint8_t) (IOAPIC_REDIR_TABLE + p * 2 + 1), hi_32);
 | 
			
		||||
			ioapic_write((u32_t)ioapic->addr,
 | 
			
		||||
				(uint8_t) (IOAPIC_REDIR_TABLE + p * 2), low_32);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* disables all IO APICs */
 | 
			
		||||
PUBLIC void ioapic_disable_all(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned ioa;
 | 
			
		||||
	if (!ioapic_enabled)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	for (ioa = 0 ; ioa < nioapics; ioa++) 
 | 
			
		||||
		ioapic_disable(&io_apic[ioa]);
 | 
			
		||||
 | 
			
		||||
	ioapic_enabled = 0; /* io apic, disabled */
 | 
			
		||||
 | 
			
		||||
	/* Enable 8259 - write 0x00 in OCW1 master and slave.  */
 | 
			
		||||
	if (apic_imcrp) {
 | 
			
		||||
		outb(0x22, 0x70);
 | 
			
		||||
		outb(0x23, 0x00);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	lapic_microsec_sleep(200); /* to enable APIC to switch to PIC */
 | 
			
		||||
 | 
			
		||||
	apic_idt_init(TRUE); /* reset */
 | 
			
		||||
	idt_reload();
 | 
			
		||||
 | 
			
		||||
	intr_init(INTS_ORIG, 0); /* no auto eoi */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE void ioapic_disable_irq(unsigned irq)
 | 
			
		||||
{
 | 
			
		||||
	assert(io_apic_irq[irq].ioa);
 | 
			
		||||
 | 
			
		||||
	ioapic_disable_pin(io_apic_irq[irq].ioa->addr, io_apic_irq[irq].pin);
 | 
			
		||||
	io_apic_irq[irq].state |= IOAPIC_IRQ_STATE_MASKED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE void ioapic_enable_irq(unsigned irq)
 | 
			
		||||
{
 | 
			
		||||
	assert(io_apic_irq[irq].ioa);
 | 
			
		||||
 | 
			
		||||
	ioapic_enable_pin(io_apic_irq[irq].ioa->addr, io_apic_irq[irq].pin);
 | 
			
		||||
	io_apic_irq[irq].state &= ~IOAPIC_IRQ_STATE_MASKED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC void ioapic_unmask_irq(unsigned irq)
 | 
			
		||||
{
 | 
			
		||||
	if (ioapic_enabled)
 | 
			
		||||
		ioapic_enable_irq(irq);
 | 
			
		||||
	else
 | 
			
		||||
		/* FIXME unlikely */
 | 
			
		||||
		irq_8259_unmask(irq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC void ioapic_mask_irq(unsigned irq)
 | 
			
		||||
{
 | 
			
		||||
	if (ioapic_enabled)
 | 
			
		||||
		ioapic_disable_irq(irq);
 | 
			
		||||
	else
 | 
			
		||||
		/* FIXME unlikely */
 | 
			
		||||
		irq_8259_mask(irq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE int calib_clk_handler(irq_hook_t * UNUSED(hook))
 | 
			
		||||
{
 | 
			
		||||
@ -91,6 +392,7 @@ PRIVATE int calib_clk_handler(irq_hook_t * UNUSED(hook))
 | 
			
		||||
	else if (probe_ticks == PROBE_TICKS) {
 | 
			
		||||
		lapic_tctr1 = tcrt;
 | 
			
		||||
		tsc1 = tsc;
 | 
			
		||||
		stop_8253A_timer();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
@ -136,8 +438,8 @@ PRIVATE void apic_calibrate_clocks(void)
 | 
			
		||||
	put_irq_handler(&calib_clk, CLOCK_IRQ, calib_clk_handler);
 | 
			
		||||
 | 
			
		||||
	/* set the PIC timer to get some time */
 | 
			
		||||
	intr_enable();
 | 
			
		||||
	init_8253A_timer(system_hz);
 | 
			
		||||
	intr_enable();
 | 
			
		||||
 | 
			
		||||
	/* loop for some time to get a sample */
 | 
			
		||||
	while(probe_ticks < PROBE_TICKS) {
 | 
			
		||||
@ -145,7 +447,6 @@ PRIVATE void apic_calibrate_clocks(void)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	intr_disable();
 | 
			
		||||
	stop_8253A_timer();
 | 
			
		||||
 | 
			
		||||
	/* remove the probe */
 | 
			
		||||
	rm_irq_handler(&calib_clk);
 | 
			
		||||
@ -210,7 +511,7 @@ PUBLIC void lapic_stop_timer(void)
 | 
			
		||||
PRIVATE void lapic_microsec_sleep(unsigned count)
 | 
			
		||||
{
 | 
			
		||||
	lapic_set_timer_one_shot(count);
 | 
			
		||||
	while (lapic_read (LAPIC_TIMER_CCR));
 | 
			
		||||
	while (lapic_read(LAPIC_TIMER_CCR));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE  u32_t lapic_errstatus(void)
 | 
			
		||||
@ -219,29 +520,49 @@ PRIVATE  u32_t lapic_errstatus(void)
 | 
			
		||||
	return lapic_read(LAPIC_ESR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE void lapic_enable_no_lints(void)
 | 
			
		||||
PRIVATE int lapic_disable_in_msr(void)
 | 
			
		||||
{
 | 
			
		||||
	u64_t msr;
 | 
			
		||||
	u32_t addr;
 | 
			
		||||
 | 
			
		||||
	ia32_msr_read(IA32_APIC_BASE, &msr.hi, &msr.lo);
 | 
			
		||||
 | 
			
		||||
	msr.lo &= ~(1 << IA32_APIC_BASE_ENABLE_BIT);
 | 
			
		||||
	ia32_msr_write(IA32_APIC_BASE, msr.hi, msr.lo);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC void lapic_disable(void)
 | 
			
		||||
{
 | 
			
		||||
	/* Disable current APIC and close interrupts from PIC */
 | 
			
		||||
	u32_t val;
 | 
			
		||||
 | 
			
		||||
	val = lapic_read(LAPIC_LINT0);
 | 
			
		||||
	lapic_extint_assigned =	(val & APIC_ICR_DM_MASK) == APIC_ICR_DM_EXTINT;
 | 
			
		||||
	val &= ~(APIC_ICR_DM_MASK|APIC_ICR_INT_MASK);
 | 
			
		||||
 | 
			
		||||
	if (!ioapic_enabled && cpu_is_bsp(cpuid))
 | 
			
		||||
		val |= (APIC_ICR_DM_EXTINT); /* ExtINT at LINT0 */
 | 
			
		||||
	else
 | 
			
		||||
		val |= (APIC_ICR_DM_EXTINT|APIC_ICR_INT_MASK); /* Masked ExtINT at LINT0 */
 | 
			
		||||
	if (!lapic_addr)
 | 
			
		||||
		return;
 | 
			
		||||
	
 | 
			
		||||
	if (!apic_imcrp) {
 | 
			
		||||
		/* leave it enabled if imcr is not set */
 | 
			
		||||
		val = lapic_read(LAPIC_LINT0);
 | 
			
		||||
		val &= ~(APIC_ICR_DM_MASK|APIC_ICR_INT_MASK);
 | 
			
		||||
		val |= APIC_ICR_DM_EXTINT; /* ExtINT at LINT0 */
 | 
			
		||||
		lapic_write (LAPIC_LINT0, val);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	val = lapic_read(LAPIC_LINT0) & 0xFFFE58FF;
 | 
			
		||||
	val |= APIC_ICR_INT_MASK;
 | 
			
		||||
	lapic_write (LAPIC_LINT0, val);
 | 
			
		||||
 | 
			
		||||
	val = lapic_read(LAPIC_LINT1);
 | 
			
		||||
	val &= ~(APIC_ICR_DM_MASK|APIC_ICR_INT_MASK);
 | 
			
		||||
 | 
			
		||||
	if (!ioapic_enabled && cpu_is_bsp(cpuid))
 | 
			
		||||
		val |= APIC_ICR_DM_NMI;
 | 
			
		||||
	else
 | 
			
		||||
		val |= (APIC_ICR_DM_NMI | APIC_ICR_INT_MASK); /* NMI at LINT1 */
 | 
			
		||||
	val = lapic_read(LAPIC_LINT1) & 0xFFFE58FF;
 | 
			
		||||
	val |= APIC_ICR_INT_MASK;
 | 
			
		||||
	lapic_write (LAPIC_LINT1, val);
 | 
			
		||||
 | 
			
		||||
	val = lapic_read(LAPIC_SIVR) & 0xFFFFFF00;
 | 
			
		||||
	val &= ~APIC_ENABLE;
 | 
			
		||||
	lapic_write(LAPIC_SIVR, val);
 | 
			
		||||
 | 
			
		||||
	lapic_disable_in_msr();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE int lapic_enable_in_msr(void)
 | 
			
		||||
@ -270,9 +591,13 @@ PRIVATE int lapic_enable_in_msr(void)
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE int lapic_enable(void)
 | 
			
		||||
PUBLIC int lapic_enable(void)
 | 
			
		||||
{
 | 
			
		||||
	u32_t val, nlvt;
 | 
			
		||||
#if 0
 | 
			
		||||
	u32_t timeout = 0xFFFF;
 | 
			
		||||
	u32_t errstatus = 0;
 | 
			
		||||
#endif
 | 
			
		||||
	unsigned cpu = cpuid;
 | 
			
		||||
 | 
			
		||||
	if (!lapic_addr)
 | 
			
		||||
@ -288,19 +613,21 @@ PRIVATE int lapic_enable(void)
 | 
			
		||||
	if (!lapic_enable_in_msr())
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	/* set the highest priority for ever */
 | 
			
		||||
	lapic_write(LAPIC_TPR, 0x0);
 | 
			
		||||
 | 
			
		||||
	lapic_eoi_addr = LAPIC_EOI;
 | 
			
		||||
	/* clear error state register. */
 | 
			
		||||
	val = lapic_errstatus ();
 | 
			
		||||
 | 
			
		||||
	/* Enable Local APIC and set the spurious vector to 0xff. */
 | 
			
		||||
 | 
			
		||||
	val = lapic_read(LAPIC_SIVR) & 0xFFFFFF00;
 | 
			
		||||
	val = lapic_read(LAPIC_SIVR);
 | 
			
		||||
	val |= APIC_ENABLE | APIC_SPURIOUS_INT_VECTOR;
 | 
			
		||||
	val &= ~APIC_FOCUS_DISABLED;
 | 
			
		||||
	lapic_write(LAPIC_SIVR, val);
 | 
			
		||||
	(void) lapic_read(LAPIC_SIVR);
 | 
			
		||||
 | 
			
		||||
	*((u32_t *)lapic_eoi_addr) = 0;
 | 
			
		||||
	apic_eoi();
 | 
			
		||||
 | 
			
		||||
	cpu = cpuid;
 | 
			
		||||
 | 
			
		||||
@ -313,10 +640,6 @@ PRIVATE int lapic_enable(void)
 | 
			
		||||
	val = lapic_read(LAPIC_DFR) | 0xF0000000;
 | 
			
		||||
	lapic_write (LAPIC_DFR, val);
 | 
			
		||||
 | 
			
		||||
	if (nlints == 0) {
 | 
			
		||||
		lapic_enable_no_lints();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	val = lapic_read (LAPIC_LVTER) & 0xFFFFFF00;
 | 
			
		||||
	lapic_write (LAPIC_LVTER, val);
 | 
			
		||||
 | 
			
		||||
@ -338,7 +661,7 @@ PRIVATE int lapic_enable(void)
 | 
			
		||||
	lapic_write (LAPIC_TPR, val & ~0xFF);
 | 
			
		||||
 | 
			
		||||
	(void) lapic_read (LAPIC_SIVR);
 | 
			
		||||
	*((u32_t *)lapic_eoi_addr) = 0;
 | 
			
		||||
	apic_eoi();
 | 
			
		||||
 | 
			
		||||
	apic_calibrate_clocks();
 | 
			
		||||
	BOOT_VERBOSE(printf("APIC timer calibrated\n"));
 | 
			
		||||
@ -352,24 +675,79 @@ PRIVATE void apic_spurios_intr(void)
 | 
			
		||||
	for(;;);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE void apic_error_intr(void)
 | 
			
		||||
{
 | 
			
		||||
	printf("WARNING local apic error interrupt\n");
 | 
			
		||||
	for(;;);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE struct gate_table_s gate_table_ioapic[] = {
 | 
			
		||||
	{ apic_hwint00, VECTOR( 0), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint01, VECTOR( 1), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint02, VECTOR( 2), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint03, VECTOR( 3), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint04, VECTOR( 4), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint05, VECTOR( 5), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint06, VECTOR( 6), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint07, VECTOR( 7), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint08, VECTOR( 8), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint09, VECTOR( 9), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint10, VECTOR(10), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint11, VECTOR(11), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint12, VECTOR(12), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint13, VECTOR(13), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint14, VECTOR(14), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint15, VECTOR(15), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint0, LAPIC_VECTOR( 0), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint1, LAPIC_VECTOR( 1), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint2, LAPIC_VECTOR( 2), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint3, LAPIC_VECTOR( 3), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint4, LAPIC_VECTOR( 4), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint5, LAPIC_VECTOR( 5), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint6, LAPIC_VECTOR( 6), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint7, LAPIC_VECTOR( 7), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint8, LAPIC_VECTOR( 8), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint9, LAPIC_VECTOR( 9), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint10, LAPIC_VECTOR(10), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint11, LAPIC_VECTOR(11), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint12, LAPIC_VECTOR(12), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint13, LAPIC_VECTOR(13), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint14, LAPIC_VECTOR(14), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint15, LAPIC_VECTOR(15), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint16, LAPIC_VECTOR(16), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint17, LAPIC_VECTOR(17), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint18, LAPIC_VECTOR(18), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint19, LAPIC_VECTOR(19), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint20, LAPIC_VECTOR(20), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint21, LAPIC_VECTOR(21), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint22, LAPIC_VECTOR(22), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint23, LAPIC_VECTOR(23), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint24, LAPIC_VECTOR(24), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint25, LAPIC_VECTOR(25), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint26, LAPIC_VECTOR(26), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint27, LAPIC_VECTOR(27), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint28, LAPIC_VECTOR(28), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint29, LAPIC_VECTOR(29), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint30, LAPIC_VECTOR(30), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint31, LAPIC_VECTOR(31), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint32, LAPIC_VECTOR(32), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint33, LAPIC_VECTOR(33), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint34, LAPIC_VECTOR(34), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint35, LAPIC_VECTOR(35), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint36, LAPIC_VECTOR(36), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint37, LAPIC_VECTOR(37), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint38, LAPIC_VECTOR(38), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint39, LAPIC_VECTOR(39), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint40, LAPIC_VECTOR(40), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint41, LAPIC_VECTOR(41), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint42, LAPIC_VECTOR(42), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint43, LAPIC_VECTOR(43), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint44, LAPIC_VECTOR(44), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint45, LAPIC_VECTOR(45), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint46, LAPIC_VECTOR(46), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint47, LAPIC_VECTOR(47), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint48, LAPIC_VECTOR(48), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint49, LAPIC_VECTOR(49), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint50, LAPIC_VECTOR(50), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint51, LAPIC_VECTOR(51), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint52, LAPIC_VECTOR(52), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint53, LAPIC_VECTOR(53), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint54, LAPIC_VECTOR(54), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint55, LAPIC_VECTOR(55), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint56, LAPIC_VECTOR(56), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint57, LAPIC_VECTOR(57), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint58, LAPIC_VECTOR(58), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint59, LAPIC_VECTOR(59), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint60, LAPIC_VECTOR(60), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint61, LAPIC_VECTOR(61), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint62, LAPIC_VECTOR(62), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_hwint63, LAPIC_VECTOR(63), INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_spurios_intr, APIC_SPURIOUS_INT_VECTOR, INTR_PRIVILEGE },
 | 
			
		||||
	{ apic_error_intr, APIC_ERROR_INT_VECTOR, INTR_PRIVILEGE },
 | 
			
		||||
	{ NULL, 0, 0}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -379,11 +757,21 @@ PRIVATE struct gate_table_s gate_table_common[] = {
 | 
			
		||||
	{ NULL, 0, 0}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_SMP
 | 
			
		||||
PRIVATE struct gate_table_s gate_table_smp[] = {
 | 
			
		||||
	{ smp_ipi_sched, SMP_SCHED_PROC, INTR_PRIVILEGE },
 | 
			
		||||
	{ smp_ipi_dequeue, SMP_DEQUEUE_PROC, INTR_PRIVILEGE },
 | 
			
		||||
	{ smp_ipi_reboot,SMP_CPU_REBOOT, INTR_PRIVILEGE },
 | 
			
		||||
	{ smp_ipi_stop,  SMP_CPU_HALT, INTR_PRIVILEGE },
 | 
			
		||||
	{ NULL, 0, 0}
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_APIC_DEBUG
 | 
			
		||||
PRIVATE void lapic_set_dummy_handlers(void)
 | 
			
		||||
{
 | 
			
		||||
	char * handler;
 | 
			
		||||
	int vect = 32;
 | 
			
		||||
	int vect = 32; /* skip the reserved vectors */
 | 
			
		||||
 | 
			
		||||
	handler = &lapic_intr_dummy_handles_start;
 | 
			
		||||
	handler += vect * LAPIC_INTR_DUMMY_HANDLER_SIZE;
 | 
			
		||||
@ -399,6 +787,8 @@ PRIVATE void lapic_set_dummy_handlers(void)
 | 
			
		||||
/* Build descriptors for interrupt gates in IDT. */
 | 
			
		||||
PRIVATE void apic_idt_init(const int reset)
 | 
			
		||||
{
 | 
			
		||||
	u32_t val;
 | 
			
		||||
 | 
			
		||||
	/* Set up idt tables for smp mode.
 | 
			
		||||
	 */
 | 
			
		||||
	vir_bytes local_timer_intr_handler;
 | 
			
		||||
@ -423,6 +813,17 @@ PRIVATE void apic_idt_init(const int reset)
 | 
			
		||||
 | 
			
		||||
	idt_copy_vectors(gate_table_common);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_SMP
 | 
			
		||||
	idt_copy_vectors(gate_table_smp);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/* Setup error interrupt vector */
 | 
			
		||||
	val = lapic_read(LAPIC_LVTER);
 | 
			
		||||
	val |= APIC_ERROR_INT_VECTOR;
 | 
			
		||||
	val &= ~ APIC_ICR_INT_MASK;
 | 
			
		||||
	lapic_write(LAPIC_LVTER, val);
 | 
			
		||||
	(void) lapic_read(LAPIC_LVTER);
 | 
			
		||||
 | 
			
		||||
	/* configure the timer interupt handler */
 | 
			
		||||
	if (cpu_is_bsp(cpuid)) {
 | 
			
		||||
		local_timer_intr_handler = (vir_bytes) lapic_bsp_timer_int_handler;
 | 
			
		||||
@ -437,6 +838,47 @@ PRIVATE void apic_idt_init(const int reset)
 | 
			
		||||
		PRESENT | INT_GATE_TYPE | (INTR_PRIVILEGE << DPL_SHIFT));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE int acpi_get_ioapics(struct io_apic * ioa, unsigned * nioa, unsigned max)
 | 
			
		||||
{
 | 
			
		||||
	unsigned n = 0;
 | 
			
		||||
	struct acpi_madt_ioapic * acpi_ioa;
 | 
			
		||||
 | 
			
		||||
	while (n < max) {
 | 
			
		||||
		acpi_ioa = acpi_get_ioapic_next();
 | 
			
		||||
		if (acpi_ioa == NULL)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		ioa[n].id = acpi_ioa->id;
 | 
			
		||||
		ioa[n].addr = phys2vir(acpi_ioa->address);
 | 
			
		||||
		ioa[n].paddr = (phys_bytes) acpi_ioa->address;
 | 
			
		||||
		ioa[n].gsi_base = acpi_ioa->global_int_base;
 | 
			
		||||
		ioa[n].pins = ((ioapic_read(ioa[n].addr,
 | 
			
		||||
				IOAPIC_VERSION) & 0xff0000) >> 16)+1;
 | 
			
		||||
		printf("IO APIC %d addr 0x%x paddr 0x%x pins %d\n",
 | 
			
		||||
				acpi_ioa->id, ioa[n].addr, ioa[n].paddr,
 | 
			
		||||
				ioa[n].pins);
 | 
			
		||||
 | 
			
		||||
		n++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	*nioa = n;
 | 
			
		||||
	return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE int detect_ioapics(void)
 | 
			
		||||
{
 | 
			
		||||
	int status;
 | 
			
		||||
 | 
			
		||||
	if (machine.acpi_rsdp)
 | 
			
		||||
		status = acpi_get_ioapics(io_apic, &nioapics, MAX_NR_IOAPICS);
 | 
			
		||||
	if (!status) {
 | 
			
		||||
		/* try something different like MPS */
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	printf("nioapics %d\n", nioapics);
 | 
			
		||||
	return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC int apic_single_cpu_init(void)
 | 
			
		||||
{
 | 
			
		||||
	if (!cpu_feature_apic_on_chip())
 | 
			
		||||
@ -450,7 +892,168 @@ PUBLIC int apic_single_cpu_init(void)
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	acpi_init();
 | 
			
		||||
 | 
			
		||||
	if (!detect_ioapics()) {
 | 
			
		||||
		lapic_disable();
 | 
			
		||||
		lapic_addr = 0x0;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ioapic_enable_all();
 | 
			
		||||
 | 
			
		||||
	if (ioapic_enabled)
 | 
			
		||||
		machine.apic_enabled = 1;
 | 
			
		||||
 | 
			
		||||
	apic_idt_init(0); /* Not a reset ! */
 | 
			
		||||
	idt_reload();
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE eoi_method_t set_eoi_method(unsigned irq)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * in APIC mode the lowest 16 IRQs are reserved for legacy (E)ISA edge
 | 
			
		||||
	 * triggered interrupts. All the rest is for PCI level triggered
 | 
			
		||||
	 * interrupts
 | 
			
		||||
	 */
 | 
			
		||||
	if (irq < 16)
 | 
			
		||||
		return ioapic_eoi_edge;
 | 
			
		||||
	else
 | 
			
		||||
		return ioapic_eoi_level;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC void set_irq_redir_low(unsigned irq, u32_t * low)
 | 
			
		||||
{
 | 
			
		||||
	u32_t val = 0;
 | 
			
		||||
 | 
			
		||||
	/* clear the polarity, trigger, mask and vector fields */
 | 
			
		||||
	val &= ~(APIC_ICR_VECTOR | APIC_ICR_INT_MASK |
 | 
			
		||||
			APIC_ICR_TRIGGER | APIC_ICR_INT_POLARITY);
 | 
			
		||||
 | 
			
		||||
	if (irq < 16) {
 | 
			
		||||
		/* ISA active-high */
 | 
			
		||||
		val &= ~APIC_ICR_INT_POLARITY;
 | 
			
		||||
		/* ISA edge triggered */
 | 
			
		||||
		val &= ~APIC_ICR_TRIGGER;
 | 
			
		||||
	}
 | 
			
		||||
	else {
 | 
			
		||||
		/* PCI active-low */
 | 
			
		||||
		val |= APIC_ICR_INT_POLARITY;
 | 
			
		||||
		/* PCI level triggered */
 | 
			
		||||
		val |= APIC_ICR_TRIGGER;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	val |= io_apic_irq[irq].vector;
 | 
			
		||||
 | 
			
		||||
	*low = val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC void ioapic_set_irq(unsigned irq)
 | 
			
		||||
{
 | 
			
		||||
	unsigned ioa;
 | 
			
		||||
 | 
			
		||||
	assert(irq < NR_IRQ_VECTORS);
 | 
			
		||||
	
 | 
			
		||||
	/* shared irq, already set */
 | 
			
		||||
	if (io_apic_irq[irq].ioa && io_apic_irq[irq].eoi)
 | 
			
		||||
		return;
 | 
			
		||||
	
 | 
			
		||||
	assert(!io_apic_irq[irq].ioa || !io_apic_irq[irq].eoi);
 | 
			
		||||
 | 
			
		||||
	for (ioa = 0; ioa < nioapics; ioa++) {
 | 
			
		||||
		if (io_apic[ioa].gsi_base <= irq &&
 | 
			
		||||
				io_apic[ioa].gsi_base +
 | 
			
		||||
				io_apic[ioa].pins > irq) {
 | 
			
		||||
			u32_t hi_32, low_32;
 | 
			
		||||
 | 
			
		||||
			io_apic_irq[irq].ioa = &io_apic[ioa];
 | 
			
		||||
			io_apic_irq[irq].pin = irq - io_apic[ioa].gsi_base;
 | 
			
		||||
			io_apic_irq[irq].eoi = set_eoi_method(irq);
 | 
			
		||||
			io_apic_irq[irq].vector = LAPIC_VECTOR(irq);
 | 
			
		||||
 | 
			
		||||
			set_irq_redir_low(irq, &low_32);
 | 
			
		||||
			/*
 | 
			
		||||
			 * route the interrupts to the bsp by default
 | 
			
		||||
			 */
 | 
			
		||||
			hi_32 = 0;
 | 
			
		||||
			ioapic_redirt_entry_write((void *) io_apic[ioa].addr,
 | 
			
		||||
					io_apic_irq[irq].pin, hi_32, low_32);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC void ioapic_unset_irq(unsigned irq)
 | 
			
		||||
{
 | 
			
		||||
	assert(irq < NR_IRQ_VECTORS);
 | 
			
		||||
 | 
			
		||||
	ioapic_disable_irq(irq);
 | 
			
		||||
	io_apic_irq[irq].ioa = NULL;
 | 
			
		||||
	io_apic_irq[irq].eoi = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC void ioapic_reset_pic(void)
 | 
			
		||||
{       
 | 
			
		||||
	apic_idt_init(TRUE); /* reset */
 | 
			
		||||
	idt_reload();
 | 
			
		||||
 | 
			
		||||
	/* Enable 8259 - write 0x00 in OCW1
 | 
			
		||||
	 * master and slave.  */
 | 
			
		||||
		outb(0x22, 0x70);
 | 
			
		||||
		outb(0x23, 0x00);
 | 
			
		||||
	
 | 
			
		||||
	intr_init(INTS_ORIG, 0); /* no auto eoi */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE void irq_lapic_status(int irq)
 | 
			
		||||
{
 | 
			
		||||
	u32_t lo;
 | 
			
		||||
	reg_t tmr, irr, isr;
 | 
			
		||||
	int vector;
 | 
			
		||||
	struct irq * intr;
 | 
			
		||||
 | 
			
		||||
	intr = &io_apic_irq[irq];
 | 
			
		||||
	
 | 
			
		||||
	if (!intr->ioa)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	vector = LAPIC_VECTOR(irq);
 | 
			
		||||
	tmr =  apic_read_tmr_vector(vector);
 | 
			
		||||
	irr =  apic_read_irr_vector(vector);
 | 
			
		||||
	isr =  apic_read_isr_vector(vector);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	if (lapic_test_delivery_val(isr, vector)) {
 | 
			
		||||
		printf("IRQ %d vec %d trigger %s irr %d isr %d\n",
 | 
			
		||||
				irq, vector,
 | 
			
		||||
				lapic_test_delivery_val(tmr, vector) ?
 | 
			
		||||
				"level" : "edge",
 | 
			
		||||
				lapic_test_delivery_val(irr, vector) ? 1 : 0,
 | 
			
		||||
				lapic_test_delivery_val(isr, vector) ? 1 : 0);
 | 
			
		||||
	} else {
 | 
			
		||||
		printf("IRQ %d vec %d irr %d\n",
 | 
			
		||||
				irq, vector,
 | 
			
		||||
				lapic_test_delivery_val(irr, vector) ? 1 : 0);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	lo = ioapic_read(intr->ioa->addr,
 | 
			
		||||
			IOAPIC_REDIR_TABLE + intr->pin * 2);
 | 
			
		||||
	printf("\tpin %2d vec 0x%02x ioa %d redir_lo 0x%08x %s\n",
 | 
			
		||||
			intr->pin,
 | 
			
		||||
			intr->vector,
 | 
			
		||||
			intr->ioa->id,
 | 
			
		||||
			lo,
 | 
			
		||||
			intr->state & IOAPIC_IRQ_STATE_MASKED ?
 | 
			
		||||
			"masked" : "unmasked");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC void dump_apic_irq_state(void)
 | 
			
		||||
{
 | 
			
		||||
	int irq;
 | 
			
		||||
 | 
			
		||||
	printf("--- IRQs state dump ---\n");
 | 
			
		||||
	for (irq = 0; irq < NR_IRQ_VECTORS; irq++) {
 | 
			
		||||
		irq_lapic_status(irq);
 | 
			
		||||
	}
 | 
			
		||||
	printf("--- all ---\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -66,6 +66,9 @@
 | 
			
		||||
#define LAPIC_LDR	(lapic_addr + 0x0d0)
 | 
			
		||||
#define LAPIC_DFR	(lapic_addr + 0x0e0)
 | 
			
		||||
#define LAPIC_SIVR	(lapic_addr + 0x0f0)
 | 
			
		||||
#define LAPIC_ISR	(lapic_addr + 0x100)
 | 
			
		||||
#define LAPIC_TMR	(lapic_addr + 0x180)
 | 
			
		||||
#define LAPIC_IRR	(lapic_addr + 0x200)
 | 
			
		||||
#define LAPIC_ESR	(lapic_addr + 0x280)
 | 
			
		||||
#define LAPIC_ICR1	(lapic_addr + 0x300)
 | 
			
		||||
#define LAPIC_ICR2	(lapic_addr + 0x310)
 | 
			
		||||
@ -84,10 +87,10 @@
 | 
			
		||||
#define IOAPIC_ARB			0x2
 | 
			
		||||
#define IOAPIC_REDIR_TABLE		0x10
 | 
			
		||||
 | 
			
		||||
#define APIC_TIMER_INT_VECTOR		0xfe
 | 
			
		||||
#define APIC_TIMER_INT_VECTOR		0xf0
 | 
			
		||||
#define APIC_ERROR_INT_VECTOR		0xfe
 | 
			
		||||
#define APIC_SPURIOUS_INT_VECTOR	0xff
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef __ASSEMBLY__
 | 
			
		||||
 | 
			
		||||
#include "kernel/kernel.h"
 | 
			
		||||
@ -95,34 +98,50 @@
 | 
			
		||||
EXTERN vir_bytes lapic_addr;
 | 
			
		||||
EXTERN vir_bytes lapic_eoi_addr;
 | 
			
		||||
 | 
			
		||||
#define MAX_NR_IOAPICS			32
 | 
			
		||||
#define MAX_NR_BUSES			32
 | 
			
		||||
#define MAX_NR_APICIDS			255
 | 
			
		||||
#define MAX_NR_LCLINTS			2
 | 
			
		||||
#define MAX_NR_IOAPICS		32
 | 
			
		||||
#define MAX_IOAPIC_IRQS		64
 | 
			
		||||
 | 
			
		||||
EXTERN u8_t apicid2cpuid[MAX_NR_APICIDS+1];
 | 
			
		||||
EXTERN int ioapic_enabled;
 | 
			
		||||
 | 
			
		||||
struct io_apic {
 | 
			
		||||
	unsigned	id;
 | 
			
		||||
	vir_bytes	addr; /* presently used address */
 | 
			
		||||
	phys_bytes	paddr; /* where is it inphys space */
 | 
			
		||||
	vir_bytes	vaddr; /* adress after paging s on */
 | 
			
		||||
	unsigned	pins;
 | 
			
		||||
	unsigned	gsi_base;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
EXTERN struct io_apic io_apic[MAX_NR_IOAPICS];
 | 
			
		||||
EXTERN unsigned nioapics;
 | 
			
		||||
 | 
			
		||||
EXTERN u32_t lapic_addr_vaddr; /* we remember the virtual address here until we
 | 
			
		||||
				  switch to paging */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
_PROTOTYPE (u32_t ioapic_read, (u32_t addr, u32_t offset));
 | 
			
		||||
_PROTOTYPE (void ioapic_write, (u32_t addr, u32_t offset, u32_t data));
 | 
			
		||||
_PROTOTYPE (void lapic_eoi, (void));
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
_PROTOTYPE(int apic_single_cpu_init, (void));
 | 
			
		||||
 | 
			
		||||
_PROTOTYPE(void lapic_set_timer_periodic, (unsigned freq));
 | 
			
		||||
_PROTOTYPE(void lapic_stop_timer, (void));
 | 
			
		||||
 | 
			
		||||
_PROTOTYPE(void ioapic_set_irq, (unsigned irq));
 | 
			
		||||
_PROTOTYPE(void ioapic_unset_irq, (unsigned irq));
 | 
			
		||||
 | 
			
		||||
 /* signal the end of interrupt handler to apic */
 | 
			
		||||
_PROTOTYPE(void ioapic_eoi, (int irq));
 | 
			
		||||
 | 
			
		||||
_PROTOTYPE(void lapic_disable, (void));
 | 
			
		||||
_PROTOTYPE(void ioapic_disable_all, (void));
 | 
			
		||||
_PROTOTYPE(void ioapic_reset_pic, (void));
 | 
			
		||||
 | 
			
		||||
_PROTOTYPE(void dump_apic_irq_state, (void));
 | 
			
		||||
 | 
			
		||||
#include <minix/cpufeature.h>
 | 
			
		||||
 | 
			
		||||
#define cpu_feature_apic_on_chip() _cpufeature(_CPUF_I386_APIC_ON_CHIP)
 | 
			
		||||
 | 
			
		||||
#define lapic_read(what)	(*((u32_t *)((what))))
 | 
			
		||||
#define lapic_read(what)	(*((volatile u32_t *)((what))))
 | 
			
		||||
#define lapic_write(what, data)	do {			\
 | 
			
		||||
	(*((u32_t *)((what)))) = data;			\
 | 
			
		||||
	(*((volatile u32_t *)((what)))) = data;			\
 | 
			
		||||
} while(0)
 | 
			
		||||
 | 
			
		||||
#endif /* __ASSEMBLY__ */
 | 
			
		||||
 | 
			
		||||
@ -5,18 +5,17 @@
 | 
			
		||||
#include <machine/asm.h>
 | 
			
		||||
 | 
			
		||||
#define APIC_IRQ_HANDLER(irq)	\
 | 
			
		||||
	push	$irq							    	;\
 | 
			
		||||
	call	_C_LABEL(irq_handle)	/* intr_handle(irq_handlers[irq]) */	;\
 | 
			
		||||
	add	$4, %esp						    	;\
 | 
			
		||||
	mov	_C_LABEL(lapic_eoi_addr), %eax				    	;\
 | 
			
		||||
	movl	$0, (%eax)						    	;\
 | 
			
		||||
	push	$irq						;\
 | 
			
		||||
	call	_C_LABEL(irq_handle)		/* intr_handle(irq) */	;\
 | 
			
		||||
	add	$4, %esp					;
 | 
			
		||||
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
/*				interrupt handlers			     */
 | 
			
		||||
/*		interrupt handlers for 386 32-bit protected mode	     */
 | 
			
		||||
/*		APIC interrupt handlers for 386 32-bit protected mode	     */
 | 
			
		||||
/*===========================================================================*/
 | 
			
		||||
#define apic_hwint(irq) \
 | 
			
		||||
#define apic_hwint(irq)							\
 | 
			
		||||
ENTRY(apic_hwint##irq)							\
 | 
			
		||||
	TEST_INT_IN_KERNEL(4, 0f)					;\
 | 
			
		||||
									\
 | 
			
		||||
	SAVE_PROCESS_CTX(0)						;\
 | 
			
		||||
@ -35,73 +34,6 @@
 | 
			
		||||
	popa								;\
 | 
			
		||||
	iret								;
 | 
			
		||||
 | 
			
		||||
/*  Handlers for hardware interrupts */
 | 
			
		||||
/*  Each of these entry points is an expansion of the hwint_master macro */
 | 
			
		||||
ENTRY(apic_hwint00)
 | 
			
		||||
/*  Interrupt routine for irq 0 (the clock). */
 | 
			
		||||
	apic_hwint(0)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint01)
 | 
			
		||||
/*  Interrupt routine for irq 1 (keyboard) */
 | 
			
		||||
	apic_hwint(1)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint02)
 | 
			
		||||
/*  Interrupt routine for irq 2 (cascade!) */
 | 
			
		||||
	apic_hwint(2)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint03)
 | 
			
		||||
/*  Interrupt routine for irq 3 (second serial) */
 | 
			
		||||
	apic_hwint(3)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint04)
 | 
			
		||||
/*  Interrupt routine for irq 4 (first serial) */
 | 
			
		||||
	apic_hwint(4)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint05)
 | 
			
		||||
/*  Interrupt routine for irq 5 (XT winchester) */
 | 
			
		||||
	apic_hwint(5)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint06)
 | 
			
		||||
/*  Interrupt routine for irq 6 (floppy) */
 | 
			
		||||
	apic_hwint(6)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint07)
 | 
			
		||||
/*  Interrupt routine for irq 7 (printer) */
 | 
			
		||||
	apic_hwint(7)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint08)
 | 
			
		||||
/*  Interrupt routine for irq 8 (realtime clock) */
 | 
			
		||||
	apic_hwint(8)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint09)
 | 
			
		||||
/*  Interrupt routine for irq 9 (irq 2 redirected) */
 | 
			
		||||
	apic_hwint(9)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint10)
 | 
			
		||||
/*  Interrupt routine for irq 10 */
 | 
			
		||||
	apic_hwint(10)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint11)
 | 
			
		||||
/*  Interrupt routine for irq 11 */
 | 
			
		||||
	apic_hwint(11)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint12)
 | 
			
		||||
/*  Interrupt routine for irq 12 */
 | 
			
		||||
	apic_hwint(12)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint13)
 | 
			
		||||
/*  Interrupt routine for irq 13 (FPU exception) */
 | 
			
		||||
	apic_hwint(13)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint14)
 | 
			
		||||
/*  Interrupt routine for irq 14 (AT winchester) */
 | 
			
		||||
	apic_hwint(14)
 | 
			
		||||
 | 
			
		||||
ENTRY(apic_hwint15)
 | 
			
		||||
/*  Interrupt routine for irq 15 */
 | 
			
		||||
	apic_hwint(15)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define LAPIC_INTR_HANDLER(func)	\
 | 
			
		||||
	movl	$func, %eax						;\
 | 
			
		||||
	call	*%eax           /* call the actual handler */		;\
 | 
			
		||||
@ -142,7 +74,7 @@ ENTRY(lapic_ap_timer_int_handler)
 | 
			
		||||
 | 
			
		||||
.data
 | 
			
		||||
lapic_intr_dummy_handler_msg:
 | 
			
		||||
.ascii "UNHABLED APIC interrupt vector %d\n"
 | 
			
		||||
.ascii "UNHANDLED APIC interrupt vector %d\n"
 | 
			
		||||
 | 
			
		||||
.text
 | 
			
		||||
 | 
			
		||||
@ -156,6 +88,71 @@ lapic_intr_dummy_handler_msg:
 | 
			
		||||
	.balign	LAPIC_INTR_DUMMY_HANDLER_SIZE;		\
 | 
			
		||||
	lapic_intr_dummy_handler_##vect: lapic_intr_dummy_handler(vect)
 | 
			
		||||
 | 
			
		||||
apic_hwint(0)
 | 
			
		||||
apic_hwint(1)
 | 
			
		||||
apic_hwint(2)
 | 
			
		||||
apic_hwint(3)
 | 
			
		||||
apic_hwint(4)
 | 
			
		||||
apic_hwint(5)
 | 
			
		||||
apic_hwint(6)
 | 
			
		||||
apic_hwint(7)
 | 
			
		||||
apic_hwint(8)
 | 
			
		||||
apic_hwint(9)
 | 
			
		||||
apic_hwint(10)
 | 
			
		||||
apic_hwint(11)
 | 
			
		||||
apic_hwint(12)
 | 
			
		||||
apic_hwint(13)
 | 
			
		||||
apic_hwint(14)
 | 
			
		||||
apic_hwint(15)
 | 
			
		||||
apic_hwint(16)
 | 
			
		||||
apic_hwint(17)
 | 
			
		||||
apic_hwint(18)
 | 
			
		||||
apic_hwint(19)
 | 
			
		||||
apic_hwint(20)
 | 
			
		||||
apic_hwint(21)
 | 
			
		||||
apic_hwint(22)
 | 
			
		||||
apic_hwint(23)
 | 
			
		||||
apic_hwint(24)
 | 
			
		||||
apic_hwint(25)
 | 
			
		||||
apic_hwint(26)
 | 
			
		||||
apic_hwint(27)
 | 
			
		||||
apic_hwint(28)
 | 
			
		||||
apic_hwint(29)
 | 
			
		||||
apic_hwint(30)
 | 
			
		||||
apic_hwint(31)
 | 
			
		||||
apic_hwint(32)
 | 
			
		||||
apic_hwint(33)
 | 
			
		||||
apic_hwint(34)
 | 
			
		||||
apic_hwint(35)
 | 
			
		||||
apic_hwint(36)
 | 
			
		||||
apic_hwint(37)
 | 
			
		||||
apic_hwint(38)
 | 
			
		||||
apic_hwint(39)
 | 
			
		||||
apic_hwint(40)
 | 
			
		||||
apic_hwint(41)
 | 
			
		||||
apic_hwint(42)
 | 
			
		||||
apic_hwint(43)
 | 
			
		||||
apic_hwint(44)
 | 
			
		||||
apic_hwint(45)
 | 
			
		||||
apic_hwint(46)
 | 
			
		||||
apic_hwint(47)
 | 
			
		||||
apic_hwint(48)
 | 
			
		||||
apic_hwint(49)
 | 
			
		||||
apic_hwint(50)
 | 
			
		||||
apic_hwint(51)
 | 
			
		||||
apic_hwint(52)
 | 
			
		||||
apic_hwint(53)
 | 
			
		||||
apic_hwint(54)
 | 
			
		||||
apic_hwint(55)
 | 
			
		||||
apic_hwint(56)
 | 
			
		||||
apic_hwint(57)
 | 
			
		||||
apic_hwint(58)
 | 
			
		||||
apic_hwint(59)
 | 
			
		||||
apic_hwint(60)
 | 
			
		||||
apic_hwint(61)
 | 
			
		||||
apic_hwint(62)
 | 
			
		||||
apic_hwint(63)
 | 
			
		||||
 | 
			
		||||
LABEL(lapic_intr_dummy_handles_start)
 | 
			
		||||
	LAPIC_INTR_DUMMY_HANDLER(0)
 | 
			
		||||
	LAPIC_INTR_DUMMY_HANDLER(1)
 | 
			
		||||
 | 
			
		||||
@ -5,22 +5,70 @@
 | 
			
		||||
#ifndef __ASSEMBLY__
 | 
			
		||||
#include "kernel/kernel.h"
 | 
			
		||||
 | 
			
		||||
_PROTOTYPE( void apic_hwint00, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint01, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint02, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint03, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint04, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint05, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint06, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint07, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint08, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint09, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint0, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint1, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint2, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint3, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint4, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint5, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint6, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint7, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint8, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint9, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint10, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint11, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint12, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint13, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint14, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint15, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint16, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint17, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint18, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint19, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint20, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint21, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint22, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint23, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint24, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint25, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint26, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint27, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint28, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint29, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint30, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint31, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint32, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint33, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint34, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint35, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint36, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint37, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint38, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint39, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint40, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint41, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint42, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint43, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint44, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint45, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint46, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint47, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint48, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint49, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint50, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint51, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint52, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint53, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint54, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint55, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint56, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint57, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint58, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint59, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint60, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint61, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint62, (void) );
 | 
			
		||||
_PROTOTYPE( void apic_hwint63, (void) );
 | 
			
		||||
 | 
			
		||||
/* The local APIC timer tick handlers */
 | 
			
		||||
_PROTOTYPE(void lapic_bsp_timer_int_handler, (void));
 | 
			
		||||
 | 
			
		||||
@ -433,6 +433,11 @@ PRIVATE void ser_debug(const int c)
 | 
			
		||||
		}
 | 
			
		||||
	TOGGLECASE('8', VF_SCHEDULING)
 | 
			
		||||
	TOGGLECASE('9', VF_PICKPROC)
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CONFIG_APIC
 | 
			
		||||
	case 'I':
 | 
			
		||||
		dump_apic_irq_state();
 | 
			
		||||
		break;
 | 
			
		||||
#endif
 | 
			
		||||
	}
 | 
			
		||||
	serial_debug_active = 0;
 | 
			
		||||
 | 
			
		||||
@ -84,10 +84,17 @@ PUBLIC void irq_8259_mask(const int irq)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Disable 8259 - write 0xFF in OCW1 master and slave. */
 | 
			
		||||
PRIVATE void i8259_disable(void)
 | 
			
		||||
PUBLIC void i8259_disable(void)
 | 
			
		||||
{
 | 
			
		||||
	outb(INT2_CTLMASK, 0xFF);
 | 
			
		||||
	outb(INT_CTLMASK, 0xFF);
 | 
			
		||||
	inb(INT_CTLMASK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC void irq_8259_eoi(int irq)
 | 
			
		||||
{
 | 
			
		||||
	if (irq < 8)
 | 
			
		||||
		eoi_8259_master();
 | 
			
		||||
	else
 | 
			
		||||
		eoi_8259_slave();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,14 +2,48 @@
 | 
			
		||||
#define __HW_INTR_X86_H__
 | 
			
		||||
 | 
			
		||||
#include "kernel/kernel.h"
 | 
			
		||||
 | 
			
		||||
/* legacy PIC */
 | 
			
		||||
 | 
			
		||||
_PROTOTYPE(void irq_8259_unmask,(int irq));
 | 
			
		||||
_PROTOTYPE(void irq_8259_mask,(int irq));
 | 
			
		||||
_PROTOTYPE(int irq_8259_unmask,(int irq));
 | 
			
		||||
_PROTOTYPE(int irq_8259_mask,(int irq));
 | 
			
		||||
_PROTOTYPE(int irq_8259_eoi, (int irq));
 | 
			
		||||
_PROTOTYPE(void irq_handle,(int irq));
 | 
			
		||||
_PROTOTYPE(void i8259_disable,(void));
 | 
			
		||||
 | 
			
		||||
/* 
 | 
			
		||||
 * we don't use IO APIC if not configured for SMP as we cannot read any info
 | 
			
		||||
 * about it unless we use MPS which is not present on all single CPU
 | 
			
		||||
 * configurations. ACPI would be another option, however we don't support it
 | 
			
		||||
 * either
 | 
			
		||||
 */
 | 
			
		||||
#if defined(CONFIG_APIC)
 | 
			
		||||
#include "arch/i386/apic.h"
 | 
			
		||||
 | 
			
		||||
#define hw_intr_mask(irq)	ioapic_mask_irq(irq)
 | 
			
		||||
#define hw_intr_unmask(irq)	ioapic_unmask_irq(irq)
 | 
			
		||||
#define hw_intr_ack(irq)	ioapic_eoi(irq)
 | 
			
		||||
#define hw_intr_used(irq)	do {					\
 | 
			
		||||
					if (ioapic_enabled)		\
 | 
			
		||||
						ioapic_set_irq(irq);	\
 | 
			
		||||
				} while (0)
 | 
			
		||||
#define hw_intr_not_used(irq)	do {					\
 | 
			
		||||
					if (ioapic_enabled)		\
 | 
			
		||||
						ioapic_unset_irq(irq);	\
 | 
			
		||||
				} while (0)
 | 
			
		||||
#define hw_intr_disable_all() do {					\
 | 
			
		||||
					ioapic_disable_all();		\
 | 
			
		||||
					ioapic_reset_pic();		\
 | 
			
		||||
					lapic_disable();		\
 | 
			
		||||
				} while (0)
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
/* legacy PIC */
 | 
			
		||||
 | 
			
		||||
#define hw_intr_mask(irq)	irq_8259_mask(irq)
 | 
			
		||||
#define hw_intr_unmask(irq)	irq_8259_unmask(irq)
 | 
			
		||||
#define hw_intr_ack(irq)	irq_8259_eoi(irq)
 | 
			
		||||
#define hw_intr_used(irq)
 | 
			
		||||
#define hw_intr_not_used(irq)
 | 
			
		||||
#define hw_intr_disable_all()
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __HW_INTR_X86_H__ */
 | 
			
		||||
 | 
			
		||||
@ -888,6 +888,19 @@ ENTRY(poweroff_jmp)
 | 
			
		||||
	
 | 
			
		||||
	/* Jump to 16-bit code that is copied to below 1MB */
 | 
			
		||||
	ljmp	$MON_CS_SELECTOR, $0
 | 
			
		||||
 | 
			
		||||
/* acknowledge just the master PIC */
 | 
			
		||||
ENTRY(eoi_8259_master)
 | 
			
		||||
	movb	$END_OF_INT, %al
 | 
			
		||||
	outb	$INT_CTL
 | 
			
		||||
	ret
 | 
			
		||||
	
 | 
			
		||||
/* we have to acknowledge both PICs */
 | 
			
		||||
ENTRY(eoi_8259_slave)
 | 
			
		||||
	movb	$END_OF_INT, %al
 | 
			
		||||
	outb	$INT_CTL
 | 
			
		||||
	outb	$INT2_CTL
 | 
			
		||||
	ret
 | 
			
		||||
	
 | 
			
		||||
.data
 | 
			
		||||
idt_ptr:
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include "kernel/kernel.h"
 | 
			
		||||
#include "kernel/proc.h"
 | 
			
		||||
#include "kernel/vm.h"
 | 
			
		||||
@ -955,7 +954,7 @@ void i386_freepde(const int pde)
 | 
			
		||||
	freepdes[nfreepdes++] = pde;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PRIVATE int lapic_mapping_index = -1, oxpcie_mapping_index = -1;
 | 
			
		||||
PRIVATE int oxpcie_mapping_index = -1;
 | 
			
		||||
 | 
			
		||||
PUBLIC int arch_phys_map(const int index, phys_bytes *addr,
 | 
			
		||||
  phys_bytes *len, int *flags)
 | 
			
		||||
@ -967,7 +966,9 @@ PUBLIC int arch_phys_map(const int index, phys_bytes *addr,
 | 
			
		||||
	if(first) {
 | 
			
		||||
#ifdef CONFIG_APIC
 | 
			
		||||
		if(lapic_addr)
 | 
			
		||||
			lapic_mapping_index = freeidx++;
 | 
			
		||||
			freeidx++;
 | 
			
		||||
		if (ioapic_enabled)
 | 
			
		||||
			freeidx += nioapics;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_OXPCIE
 | 
			
		||||
@ -984,12 +985,20 @@ PUBLIC int arch_phys_map(const int index, phys_bytes *addr,
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_APIC
 | 
			
		||||
	/* map the local APIC if enabled */
 | 
			
		||||
	if (index == lapic_mapping_index) {
 | 
			
		||||
	if (index == 0) {
 | 
			
		||||
		if (!lapic_addr)
 | 
			
		||||
			return EINVAL;
 | 
			
		||||
		*addr = vir2phys(lapic_addr);
 | 
			
		||||
		*len = 4 << 10 /* 4kB */;
 | 
			
		||||
		*flags = VMMF_UNCACHED;
 | 
			
		||||
		return OK;
 | 
			
		||||
	}
 | 
			
		||||
	else if (ioapic_enabled && index <= nioapics) {
 | 
			
		||||
		*addr = io_apic[index - 1].paddr;
 | 
			
		||||
		*len = 4 << 10 /* 4kB */;
 | 
			
		||||
		*flags = VMMF_UNCACHED;
 | 
			
		||||
		return OK;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if CONFIG_OXPCIE
 | 
			
		||||
@ -1008,18 +1017,24 @@ PUBLIC int arch_phys_map_reply(const int index, const vir_bytes addr)
 | 
			
		||||
{
 | 
			
		||||
#ifdef CONFIG_APIC
 | 
			
		||||
	/* if local APIC is enabled */
 | 
			
		||||
	if (index == lapic_mapping_index && lapic_addr) {
 | 
			
		||||
	if (index == 0 && lapic_addr) {
 | 
			
		||||
		lapic_addr_vaddr = addr;
 | 
			
		||||
		return OK;
 | 
			
		||||
	}
 | 
			
		||||
	else if (ioapic_enabled && index <= nioapics) {
 | 
			
		||||
		io_apic[index - 1].vaddr = addr;
 | 
			
		||||
		return OK;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if CONFIG_OXPCIE
 | 
			
		||||
	if (index == oxpcie_mapping_index) {
 | 
			
		||||
		oxpcie_set_vaddr((unsigned char *) addr);
 | 
			
		||||
		return OK;
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return OK;
 | 
			
		||||
	return EINVAL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PUBLIC int arch_enable_paging(struct proc * caller, const message * m_ptr)
 | 
			
		||||
@ -1050,11 +1065,21 @@ PUBLIC int arch_enable_paging(struct proc * caller, const message * m_ptr)
 | 
			
		||||
		panic("arch_enable_paging: newmap failed");
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_APIC
 | 
			
		||||
	/* start using the virtual addresses */
 | 
			
		||||
 | 
			
		||||
	/* if local APIC is enabled */
 | 
			
		||||
	if (lapic_addr) {
 | 
			
		||||
		lapic_addr = lapic_addr_vaddr;
 | 
			
		||||
		lapic_eoi_addr = LAPIC_EOI;
 | 
			
		||||
	}
 | 
			
		||||
	/* if IO apics are enabled */
 | 
			
		||||
	if (ioapic_enabled) {
 | 
			
		||||
		int i;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < nioapics; i++) {
 | 
			
		||||
			io_apic[i].addr = io_apic[i].vaddr;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CONFIG_WATCHDOG
 | 
			
		||||
	/*
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@
 | 
			
		||||
#include "archconst.h"
 | 
			
		||||
#include "hw_intr.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* number of lists of IRQ hooks, one list per supported line. */
 | 
			
		||||
PRIVATE irq_hook_t* irq_handlers[NR_IRQ_VECTORS] = {0};
 | 
			
		||||
 | 
			
		||||
@ -58,13 +59,13 @@ PUBLIC void put_irq_handler( irq_hook_t* hook, int irq,
 | 
			
		||||
  hook->irq = irq;
 | 
			
		||||
  hook->id = id;
 | 
			
		||||
  *line = hook;
 | 
			
		||||
  irq_use |= 1 << irq;  /* this does not work for irq >= 32 */
 | 
			
		||||
 | 
			
		||||
  /* And as last enable the irq at the hardware.
 | 
			
		||||
   *
 | 
			
		||||
   * Internal this activates the line or source of the given interrupt.
 | 
			
		||||
   */
 | 
			
		||||
  if((irq_actids[hook->irq] &= ~hook->id) == 0) {
 | 
			
		||||
	  hw_intr_used(irq);
 | 
			
		||||
	  hw_intr_unmask(hook->irq);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -86,8 +87,6 @@ PUBLIC void rm_irq_handler( const irq_hook_t* hook ) {
 | 
			
		||||
  while( (*line) != NULL ) {
 | 
			
		||||
	if((*line)->id == id) {
 | 
			
		||||
		(*line) = (*line)->next;
 | 
			
		||||
		if(!irq_handlers[irq])
 | 
			
		||||
			irq_use &= ~(1 << irq);
 | 
			
		||||
		if (irq_actids[irq] & id)
 | 
			
		||||
			irq_actids[irq] &= ~id;
 | 
			
		||||
    	}
 | 
			
		||||
@ -101,6 +100,7 @@ PUBLIC void rm_irq_handler( const irq_hook_t* hook ) {
 | 
			
		||||
   */
 | 
			
		||||
  if (irq_handlers[irq] == NULL) {
 | 
			
		||||
	hw_intr_mask(irq);
 | 
			
		||||
	hw_intr_not_used(irq);
 | 
			
		||||
  }
 | 
			
		||||
  else if (irq_actids[irq] == 0) {
 | 
			
		||||
	hw_intr_unmask(irq);
 | 
			
		||||
@ -155,6 +155,8 @@ PUBLIC void irq_handle(int irq)
 | 
			
		||||
  /* reenable the IRQ only if there is no active handler */
 | 
			
		||||
  if (irq_actids[irq] == 0)
 | 
			
		||||
	  hw_intr_unmask(irq);
 | 
			
		||||
 | 
			
		||||
  hw_intr_ack(irq);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Enable/Disable a interrupt line.  */
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@
 | 
			
		||||
#include "proc.h"
 | 
			
		||||
#include "debug.h"
 | 
			
		||||
#include "clock.h"
 | 
			
		||||
#include "hw_intr.h"
 | 
			
		||||
 | 
			
		||||
/* Prototype declarations for PRIVATE functions. */
 | 
			
		||||
FORWARD _PROTOTYPE( void announce, (void));	
 | 
			
		||||
@ -323,6 +324,7 @@ PUBLIC void minix_shutdown(timer_t *tp)
 | 
			
		||||
 * monitor), RBT_MONITOR (execute given code), RBT_RESET (hard reset). 
 | 
			
		||||
 */
 | 
			
		||||
  arch_stop_local_timer();
 | 
			
		||||
  hw_intr_disable_all();
 | 
			
		||||
  intr_init(INTS_ORIG, 0);
 | 
			
		||||
  arch_shutdown(tp ? tmr_arg(tp)->ta_int : RBT_PANIC);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user