]> Zhao Yanbai Git Server - minix.git/commitdiff
APIC mode uses IO APICs
authorTomas Hruby <tom@minix3.org>
Tue, 7 Sep 2010 07:18:11 +0000 (07:18 +0000)
committerTomas Hruby <tom@minix3.org>
Tue, 7 Sep 2010 07:18:11 +0000 (07:18 +0000)
- 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

17 files changed:
drivers/acpi/acpi.c
drivers/acpi/osminixxf.c
drivers/pci/pci.c
kernel/Makefile
kernel/arch/i386/acpi.c
kernel/arch/i386/acpi.h
kernel/arch/i386/apic.c
kernel/arch/i386/apic.h
kernel/arch/i386/apic_asm.S
kernel/arch/i386/apic_asm.h
kernel/arch/i386/arch_system.c
kernel/arch/i386/i8259.c
kernel/arch/i386/include/hw_intr.h
kernel/arch/i386/klib.S
kernel/arch/i386/memory.c
kernel/interrupt.c
kernel/main.c

index 8581e17865e25b75a6a5fb687728619b18d9586c..bac095b6097372f623540c8152a1cb1c8b7c1063 100644 (file)
@@ -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)
index 4d55acd1a3562536096bf1b9a7ab4face7c02bef..97e6d54d80cd22d15b268ab283d61acaedfc20fe 100644 (file)
@@ -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);
 }
 
index c75198972686f26157ace4a6c71e680741e81d74..e64e91edd50528cf56781276ed30d14f1625b24c 100644 (file)
@@ -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,
index 4a3d3160f973b6a354aff1905c122d75b4246540..6a4cf359d5f9812735db54bf22a26ec2e6b7221e 100644 (file)
@@ -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
index a3342214c450cab6f84f2ff2ba9f445c00d804ce..159f15b98d154d531fa6585c1d7164b1b4acd6f0 100644 (file)
@@ -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;
+}
index c273ac4ec6690a5a79c9c5995746d285d963f11e..e2cf352170a3a20a9e02d27ae6e1c0fffc5b460d 100644 (file)
@@ -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__ */
index 4b0804cfe6ff93e304c7772417c90e1ad2c71bfa..54680df30a2cd74e197a40d1d4752b57d2586eed 100644 (file)
@@ -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"
 #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)
 
 
 #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)
 {
-       u32_t val;
+       u64_t msr;
+       u32_t addr;
 
-       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);
+       ia32_msr_read(IA32_APIC_BASE, &msr.hi, &msr.lo);
 
-       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 */
+       msr.lo &= ~(1 << IA32_APIC_BASE_ENABLE_BIT);
+       ia32_msr_write(IA32_APIC_BASE, msr.hi, msr.lo);
 
-       lapic_write (LAPIC_LINT0, val);
+       return 1;
+}
 
-       val = lapic_read(LAPIC_LINT1);
-       val &= ~(APIC_ICR_DM_MASK|APIC_ICR_INT_MASK);
+PUBLIC void lapic_disable(void)
+{
+       /* Disable current APIC and close interrupts from PIC */
+       u32_t val;
 
-       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 */
+       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) & 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");
+}
index 3810ad65cdcbed7601a061147cdc41c658a559c6..49adaa8b9679cbf4cc4f43d7ce6801ed1cce29c2 100644 (file)
@@ -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)
 #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"
 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 int ioapic_enabled;
 
-EXTERN u8_t apicid2cpuid[MAX_NR_APICIDS+1];
+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__ */
index ddbd30f59243041d840b8689626b9493ffd9d95c..8a9f7b87c2697963ee1235a5de14e71af7dc8eef 100644 (file)
@@ -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)                                             ;\
        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)
index fdb3eb8503a2c9aa3bd55a581ff6bedb5871b2f7..8086100d98ebfea021c83b368bb799f12a9db194 100644 (file)
@@ -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));
index b966742070d72cc7af6f54e7ab147d0c041a378d..438791d2d92c75c363996378737783fdc5188cdd 100644 (file)
@@ -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;
index 42674bb5a612280caed9395ba18877208e98603a..c76d68468de742b7d2e26ed610b457319d44a45a 100644 (file)
@@ -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();
+}
index 6f70495c9a01e2aa9a3a46c5923f25380f2337d3..eaf2c808ec0389da011aabb8b2d4799ea3706b7b 100644 (file)
@@ -2,14 +2,48 @@
 #define __HW_INTR_X86_H__
 
 #include "kernel/kernel.h"
+_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));
 
-/* legacy PIC */
+/* 
+ * 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"
 
-_PROTOTYPE(void irq_8259_unmask,(int irq));
-_PROTOTYPE(void irq_8259_mask,(int irq));
-_PROTOTYPE(void irq_handle,(int irq));
+#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__ */
index 467fd518aec8b1149f42341782135dfa65f9bfbd..7f0f93d3c9ad9a5f201a1b0d81e116e74e890bb5 100644 (file)
@@ -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:
index d1d08082cdd7a6130051840a925b6667d2443b10..0feca6814c039081a0130ef29b478a853ba36a1a 100644 (file)
@@ -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
        /*
index 61a4a6c17655d6675edb1ba2952c6d3159f5f42b..661a4e1c81cef4bb055871fd990ab03321bae27b 100644 (file)
@@ -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.  */
index b95ca5bef281e8ef64a74399b898b47303cc8320..df88e040cb792a407faa2dc1d8e62e8e9501852c 100644 (file)
@@ -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);
 }