i386: Split mpapic.c into lapic.c and ioapic.c
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 4 May 2011 02:25:18 +0000 (10:25 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 4 May 2011 02:25:18 +0000 (10:25 +0800)
sys/platform/pc32/apic/ioapic.c [new file with mode: 0644]
sys/platform/pc32/apic/lapic.c [moved from sys/platform/pc32/apic/mpapic.c with 59% similarity]
sys/platform/pc32/apic/mpapic.h
sys/platform/pc32/conf/files

diff --git a/sys/platform/pc32/apic/ioapic.c b/sys/platform/pc32/apic/ioapic.c
new file mode 100644 (file)
index 0000000..a85e0ae
--- /dev/null
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 1996, by Steve Passe
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. The name of the developer may NOT be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/i386/i386/mpapic.c,v 1.37.2.7 2003/01/25 02:31:47 peter Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/machintr.h>
+#include <machine/globaldata.h>
+#include <machine/smp.h>
+#include <machine/cputypes.h>
+#include <machine/md_var.h>
+#include <machine/pmap.h>
+#include <machine_base/apic/mpapic.h>
+#include <machine_base/apic/ioapic_abi.h>
+#include <machine/segments.h>
+#include <sys/thread2.h>
+
+#include <machine/intr_machdep.h>
+
+#define IOAPIC_COUNT_MAX       16
+#define IOAPIC_ID_MASK         (IOAPIC_COUNT_MAX - 1)
+
+/* XXX */
+extern pt_entry_t *SMPpt;
+
+struct ioapic_info {
+       int             io_idx;
+       int             io_apic_id;
+       void            *io_addr;
+       int             io_npin;
+       int             io_gsi_base;
+
+       TAILQ_ENTRY(ioapic_info) io_link;
+};
+TAILQ_HEAD(ioapic_info_list, ioapic_info);
+
+struct ioapic_intsrc {
+       int             int_gsi;
+       enum intr_trigger int_trig;
+       enum intr_polarity int_pola;
+};
+
+struct ioapic_conf {
+       struct ioapic_info_list ioc_list;
+       struct ioapic_intsrc ioc_intsrc[16];    /* XXX magic number */
+};
+
+static void    ioapic_setup(const struct ioapic_info *);
+static int     ioapic_alloc_apic_id(int);
+static void    ioapic_set_apic_id(const struct ioapic_info *);
+static void    ioapic_gsi_setup(int);
+static const struct ioapic_info *
+               ioapic_gsi_search(int);
+static void    ioapic_pin_prog(void *, int, int,
+                   enum intr_trigger, enum intr_polarity, uint32_t);
+
+static struct ioapic_conf      ioapic_conf;
+
+static TAILQ_HEAD(, ioapic_enumerator) ioapic_enumerators =
+       TAILQ_HEAD_INITIALIZER(ioapic_enumerators);
+
+void
+ioapic_config(void)
+{
+       struct ioapic_info *info;
+       int start_apic_id = 0;
+       struct ioapic_enumerator *e;
+       int error, i;
+       u_long ef = 0;
+
+       TAILQ_INIT(&ioapic_conf.ioc_list);
+       /* XXX magic number */
+       for (i = 0; i < 16; ++i)
+               ioapic_conf.ioc_intsrc[i].int_gsi = -1;
+
+       TAILQ_FOREACH(e, &ioapic_enumerators, ioapic_link) {
+               error = e->ioapic_probe(e);
+               if (!error)
+                       break;
+       }
+       if (e == NULL) {
+#ifdef notyet
+               panic("can't config I/O APIC\n");
+#else
+               kprintf("no I/O APIC\n");
+               return;
+#endif
+       }
+
+       crit_enter();
+
+       ef = read_eflags();
+       cpu_disable_intr();
+
+       /*
+        * Switch to I/O APIC MachIntrABI and reconfigure
+        * the default IDT entries.
+        */
+       MachIntrABI = MachIntrABI_IOAPIC;
+       MachIntrABI.setdefault();
+
+       e->ioapic_enumerate(e);
+
+       /*
+        * Setup index
+        */
+       i = 0;
+       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link)
+               info->io_idx = i++;
+
+       if (i > IOAPIC_COUNT_MAX) /* XXX magic number */
+               panic("ioapic_config: more than 16 I/O APIC\n");
+
+       /*
+        * Setup APIC ID
+        */
+       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
+               int apic_id;
+
+               apic_id = ioapic_alloc_apic_id(start_apic_id);
+               if (apic_id == NAPICID) {
+                       kprintf("IOAPIC: can't alloc APIC ID for "
+                               "%dth I/O APIC\n", info->io_idx);
+                       break;
+               }
+               info->io_apic_id = apic_id;
+
+               start_apic_id = apic_id + 1;
+       }
+       if (info != NULL) {
+               /*
+                * xAPIC allows I/O APIC's APIC ID to be same
+                * as the LAPIC's APIC ID
+                */
+               kprintf("IOAPIC: use xAPIC model to alloc APIC ID "
+                       "for I/O APIC\n");
+
+               TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link)
+                       info->io_apic_id = info->io_idx;
+       }
+
+       /*
+        * Warning about any GSI holes
+        */
+       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
+               const struct ioapic_info *prev_info;
+
+               prev_info = TAILQ_PREV(info, ioapic_info_list, io_link);
+               if (prev_info != NULL) {
+                       if (info->io_gsi_base !=
+                       prev_info->io_gsi_base + prev_info->io_npin) {
+                               kprintf("IOAPIC: warning gsi hole "
+                                       "[%d, %d]\n",
+                                       prev_info->io_gsi_base +
+                                       prev_info->io_npin,
+                                       info->io_gsi_base - 1);
+                       }
+               }
+       }
+
+       if (bootverbose) {
+               TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
+                       kprintf("IOAPIC: idx %d, apic id %d, "
+                               "gsi base %d, npin %d\n",
+                               info->io_idx,
+                               info->io_apic_id,
+                               info->io_gsi_base,
+                               info->io_npin);
+               }
+       }
+
+       /*
+        * Setup all I/O APIC
+        */
+       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link)
+               ioapic_setup(info);
+       ioapic_abi_fixup_irqmap();
+
+       write_eflags(ef);
+
+       MachIntrABI.cleanup();
+
+       crit_exit();
+}
+
+void
+ioapic_enumerator_register(struct ioapic_enumerator *ne)
+{
+       struct ioapic_enumerator *e;
+
+       TAILQ_FOREACH(e, &ioapic_enumerators, ioapic_link) {
+               if (e->ioapic_prio < ne->ioapic_prio) {
+                       TAILQ_INSERT_BEFORE(e, ne, ioapic_link);
+                       return;
+               }
+       }
+       TAILQ_INSERT_TAIL(&ioapic_enumerators, ne, ioapic_link);
+}
+
+void
+ioapic_add(void *addr, int gsi_base, int npin)
+{
+       struct ioapic_info *info, *ninfo;
+       int gsi_end;
+
+       gsi_end = gsi_base + npin - 1;
+       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
+               if ((gsi_base >= info->io_gsi_base &&
+                    gsi_base < info->io_gsi_base + info->io_npin) ||
+                   (gsi_end >= info->io_gsi_base &&
+                    gsi_end < info->io_gsi_base + info->io_npin)) {
+                       panic("ioapic_add: overlapped gsi, base %d npin %d, "
+                             "hit base %d, npin %d\n", gsi_base, npin,
+                             info->io_gsi_base, info->io_npin);
+               }
+               if (info->io_addr == addr)
+                       panic("ioapic_add: duplicated addr %p\n", addr);
+       }
+
+       ninfo = kmalloc(sizeof(*ninfo), M_DEVBUF, M_WAITOK | M_ZERO);
+       ninfo->io_addr = addr;
+       ninfo->io_npin = npin;
+       ninfo->io_gsi_base = gsi_base;
+       ninfo->io_apic_id = -1;
+
+       /*
+        * Create IOAPIC list in ascending order of GSI base
+        */
+       TAILQ_FOREACH_REVERSE(info, &ioapic_conf.ioc_list,
+           ioapic_info_list, io_link) {
+               if (ninfo->io_gsi_base > info->io_gsi_base) {
+                       TAILQ_INSERT_AFTER(&ioapic_conf.ioc_list,
+                           info, ninfo, io_link);
+                       break;
+               }
+       }
+       if (info == NULL)
+               TAILQ_INSERT_HEAD(&ioapic_conf.ioc_list, ninfo, io_link);
+}
+
+void
+ioapic_intsrc(int irq, int gsi, enum intr_trigger trig, enum intr_polarity pola)
+{
+       struct ioapic_intsrc *int_src;
+
+       KKASSERT(irq < 16);
+       int_src = &ioapic_conf.ioc_intsrc[irq];
+
+       if (gsi == 0) {
+               /* Don't allow mixed mode */
+               kprintf("IOAPIC: warning intsrc irq %d -> gsi 0\n", irq);
+               return;
+       }
+
+       if (int_src->int_gsi != -1) {
+               if (int_src->int_gsi != gsi) {
+                       kprintf("IOAPIC: warning intsrc irq %d, gsi "
+                               "%d -> %d\n", irq, int_src->int_gsi, gsi);
+               }
+               if (int_src->int_trig != trig) {
+                       kprintf("IOAPIC: warning intsrc irq %d, trig "
+                               "%s -> %s\n", irq,
+                               intr_str_trigger(int_src->int_trig),
+                               intr_str_trigger(trig));
+               }
+               if (int_src->int_pola != pola) {
+                       kprintf("IOAPIC: warning intsrc irq %d, pola "
+                               "%s -> %s\n", irq,
+                               intr_str_polarity(int_src->int_pola),
+                               intr_str_polarity(pola));
+               }
+       }
+       int_src->int_gsi = gsi;
+       int_src->int_trig = trig;
+       int_src->int_pola = pola;
+}
+
+static void
+ioapic_set_apic_id(const struct ioapic_info *info)
+{
+       uint32_t id;
+       int apic_id;
+
+       id = ioapic_read(info->io_addr, IOAPIC_ID);
+
+       id &= ~APIC_ID_MASK;
+       id |= (info->io_apic_id << 24);
+
+       ioapic_write(info->io_addr, IOAPIC_ID, id);
+
+       /*
+        * Re-read && test
+        */
+       id = ioapic_read(info->io_addr, IOAPIC_ID);
+       apic_id = (id & APIC_ID_MASK) >> 24;
+
+       /*
+        * I/O APIC ID is a 4bits field
+        */
+       if ((apic_id & IOAPIC_ID_MASK) !=
+           (info->io_apic_id & IOAPIC_ID_MASK)) {
+               panic("ioapic_set_apic_id: can't set apic id to %d, "
+                     "currently set to %d\n", info->io_apic_id, apic_id);
+       }
+}
+
+static void
+ioapic_gsi_setup(int gsi)
+{
+       enum intr_trigger trig;
+       enum intr_polarity pola;
+       int irq;
+
+       if (gsi == 0) {
+               /* ExtINT */
+               imen_lock();
+               ioapic_extpin_setup(ioapic_gsi_ioaddr(gsi),
+                   ioapic_gsi_pin(gsi), 0);
+               imen_unlock();
+               return;
+       }
+
+       trig = 0;       /* silence older gcc's */
+       pola = 0;       /* silence older gcc's */
+
+       for (irq = 0; irq < 16; ++irq) {
+               const struct ioapic_intsrc *int_src =
+                   &ioapic_conf.ioc_intsrc[irq];
+
+               if (gsi == int_src->int_gsi) {
+                       trig = int_src->int_trig;
+                       pola = int_src->int_pola;
+                       break;
+               }
+       }
+
+       if (irq == 16) {
+               if (gsi < 16) {
+                       trig = INTR_TRIGGER_EDGE;
+                       pola = INTR_POLARITY_HIGH;
+               } else {
+                       trig = INTR_TRIGGER_LEVEL;
+                       pola = INTR_POLARITY_LOW;
+               }
+               irq = gsi;
+       }
+
+       ioapic_abi_set_irqmap(irq, gsi, trig, pola);
+}
+
+void *
+ioapic_gsi_ioaddr(int gsi)
+{
+       const struct ioapic_info *info;
+
+       info = ioapic_gsi_search(gsi);
+       return info->io_addr;
+}
+
+int
+ioapic_gsi_pin(int gsi)
+{
+       const struct ioapic_info *info;
+
+       info = ioapic_gsi_search(gsi);
+       return gsi - info->io_gsi_base;
+}
+
+static const struct ioapic_info *
+ioapic_gsi_search(int gsi)
+{
+       const struct ioapic_info *info;
+
+       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
+               if (gsi >= info->io_gsi_base &&
+                   gsi < info->io_gsi_base + info->io_npin)
+                       return info;
+       }
+       panic("ioapic_gsi_search: no I/O APIC\n");
+}
+
+int
+ioapic_gsi(int idx, int pin)
+{
+       const struct ioapic_info *info;
+
+       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
+               if (info->io_idx == idx)
+                       break;
+       }
+       if (info == NULL)
+               return -1;
+       if (pin >= info->io_npin)
+               return -1;
+       return info->io_gsi_base + pin;
+}
+
+void
+ioapic_extpin_setup(void *addr, int pin, int vec)
+{
+       ioapic_pin_prog(addr, pin, vec,
+           INTR_TRIGGER_CONFORM, INTR_POLARITY_CONFORM, IOART_DELEXINT);
+}
+
+int
+ioapic_extpin_gsi(void)
+{
+       return 0;
+}
+
+void
+ioapic_pin_setup(void *addr, int pin, int vec,
+    enum intr_trigger trig, enum intr_polarity pola)
+{
+       /*
+        * Always clear an I/O APIC pin before [re]programming it.  This is
+        * particularly important if the pin is set up for a level interrupt
+        * as the IOART_REM_IRR bit might be set.   When we reprogram the
+        * vector any EOI from pending ints on this pin could be lost and
+        * IRR might never get reset.
+        *
+        * To fix this problem, clear the vector and make sure it is 
+        * programmed as an edge interrupt.  This should theoretically
+        * clear IRR so we can later, safely program it as a level 
+        * interrupt.
+        */
+       ioapic_pin_prog(addr, pin, vec, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH,
+           IOART_DELFIXED);
+       ioapic_pin_prog(addr, pin, vec, trig, pola, IOART_DELFIXED);
+}
+
+static void
+ioapic_pin_prog(void *addr, int pin, int vec,
+    enum intr_trigger trig, enum intr_polarity pola, uint32_t del_mode)
+{
+       uint32_t flags, target;
+       int select;
+
+       KKASSERT(del_mode == IOART_DELEXINT || del_mode == IOART_DELFIXED);
+
+       select = IOAPIC_REDTBL0 + (2 * pin);
+
+       flags = ioapic_read(addr, select) & IOART_RESV;
+       flags |= IOART_INTMSET | IOART_DESTPHY;
+#ifdef foo
+       flags |= del_mode;
+#else
+       /*
+        * We only support limited I/O APIC mixed mode,
+        * so even for ExtINT, we still use "fixed"
+        * delivery mode.
+        */
+       flags |= IOART_DELFIXED;
+#endif
+
+       if (del_mode == IOART_DELEXINT) {
+               KKASSERT(trig == INTR_TRIGGER_CONFORM &&
+                        pola == INTR_POLARITY_CONFORM);
+               flags |= IOART_TRGREDG | IOART_INTAHI;
+       } else {
+               switch (trig) {
+               case INTR_TRIGGER_EDGE:
+                       flags |= IOART_TRGREDG;
+                       break;
+
+               case INTR_TRIGGER_LEVEL:
+                       flags |= IOART_TRGRLVL;
+                       break;
+
+               case INTR_TRIGGER_CONFORM:
+                       panic("ioapic_pin_prog: trig conform is not "
+                             "supported\n");
+               }
+               switch (pola) {
+               case INTR_POLARITY_HIGH:
+                       flags |= IOART_INTAHI;
+                       break;
+
+               case INTR_POLARITY_LOW:
+                       flags |= IOART_INTALO;
+                       break;
+
+               case INTR_POLARITY_CONFORM:
+                       panic("ioapic_pin_prog: pola conform is not "
+                             "supported\n");
+               }
+       }
+
+       target = ioapic_read(addr, select + 1) & IOART_HI_DEST_RESV;
+       target |= (CPU_TO_ID(0) << IOART_HI_DEST_SHIFT) &
+                 IOART_HI_DEST_MASK;
+
+       ioapic_write(addr, select, flags | vec);
+       ioapic_write(addr, select + 1, target);
+}
+
+static void
+ioapic_setup(const struct ioapic_info *info)
+{
+       int i;
+
+       ioapic_set_apic_id(info);
+
+       for (i = 0; i < info->io_npin; ++i)
+               ioapic_gsi_setup(info->io_gsi_base + i);
+}
+
+static int
+ioapic_alloc_apic_id(int start)
+{
+       for (;;) {
+               const struct ioapic_info *info;
+               int apic_id, apic_id16;
+
+               apic_id = lapic_unused_apic_id(start);
+               if (apic_id == NAPICID) {
+                       kprintf("IOAPIC: can't find unused APIC ID\n");
+                       return apic_id;
+               }
+               apic_id16 = apic_id & IOAPIC_ID_MASK;
+
+               /*
+                * Check against other I/O APIC's APIC ID's lower 4bits.
+                *
+                * The new APIC ID will have to be different from others
+                * in the lower 4bits, no matter whether xAPIC is used
+                * or not.
+                */
+               TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
+                       if (info->io_apic_id == -1) {
+                               info = NULL;
+                               break;
+                       }
+                       if ((info->io_apic_id & IOAPIC_ID_MASK) == apic_id16)
+                               break;
+               }
+               if (info == NULL)
+                       return apic_id;
+
+               kprintf("IOAPIC: APIC ID %d has same lower 4bits as "
+                       "%dth I/O APIC, keep searching...\n",
+                       apic_id, info->io_idx);
+
+               start = apic_id + 1;
+       }
+       panic("ioapic_unused_apic_id: never reached\n");
+}
similarity index 59%
rename from sys/platform/pc32/apic/mpapic.c
rename to sys/platform/pc32/apic/lapic.c
index 0f93dc7..de06656 100644 (file)
 
 #include <machine/intr_machdep.h>
 
-#define IOAPIC_COUNT_MAX       16
-#define IOAPIC_ID_MASK         (IOAPIC_COUNT_MAX - 1)
-
 /* XXX */
 extern pt_entry_t *SMPpt;
 
-struct ioapic_info {
-       int             io_idx;
-       int             io_apic_id;
-       void            *io_addr;
-       int             io_npin;
-       int             io_gsi_base;
-
-       TAILQ_ENTRY(ioapic_info) io_link;
-};
-TAILQ_HEAD(ioapic_info_list, ioapic_info);
-
-struct ioapic_intsrc {
-       int             int_gsi;
-       enum intr_trigger int_trig;
-       enum intr_polarity int_pola;
-};
-
-struct ioapic_conf {
-       struct ioapic_info_list ioc_list;
-       struct ioapic_intsrc ioc_intsrc[16];    /* XXX magic number */
-};
-
 static void    lapic_timer_calibrate(void);
 static void    lapic_timer_set_divisor(int);
 static void    lapic_timer_fixup_handler(void *);
@@ -86,17 +61,6 @@ static void  lapic_timer_intr_enable(struct cputimer_intr *);
 static void    lapic_timer_intr_restart(struct cputimer_intr *);
 static void    lapic_timer_intr_pmfixup(struct cputimer_intr *);
 
-static int     lapic_unused_apic_id(int);
-
-static void    ioapic_setup(const struct ioapic_info *);
-static int     ioapic_alloc_apic_id(int);
-static void    ioapic_set_apic_id(const struct ioapic_info *);
-static void    ioapic_gsi_setup(int);
-static const struct ioapic_info *
-               ioapic_gsi_search(int);
-static void    ioapic_pin_prog(void *, int, int,
-                   enum intr_trigger, enum intr_polarity, uint32_t);
-
 static struct cputimer_intr lapic_cputimer_intr = {
        .freq = 0,
        .reload = lapic_timer_intr_reload,
@@ -119,8 +83,6 @@ static const uint32_t        lapic_timer_divisors[] = {
 };
 #define APIC_TIMER_NDIVISORS (int)(NELEM(lapic_timer_divisors))
 
-static struct ioapic_conf      ioapic_conf;
-
 /*
  * Enable LAPIC, configure interrupts.
  */
@@ -657,7 +619,7 @@ u_sleep(int count)
                 /* spin */ ;
 }
 
-static int
+int
 lapic_unused_apic_id(int start)
 {
        int i;
@@ -715,493 +677,3 @@ lapic_enumerator_register(struct lapic_enumerator *ne)
        }
        TAILQ_INSERT_TAIL(&lapic_enumerators, ne, lapic_link);
 }
-
-static TAILQ_HEAD(, ioapic_enumerator) ioapic_enumerators =
-       TAILQ_HEAD_INITIALIZER(ioapic_enumerators);
-
-void
-ioapic_config(void)
-{
-       struct ioapic_info *info;
-       int start_apic_id = 0;
-       struct ioapic_enumerator *e;
-       int error, i;
-       u_long ef = 0;
-
-       TAILQ_INIT(&ioapic_conf.ioc_list);
-       /* XXX magic number */
-       for (i = 0; i < 16; ++i)
-               ioapic_conf.ioc_intsrc[i].int_gsi = -1;
-
-       TAILQ_FOREACH(e, &ioapic_enumerators, ioapic_link) {
-               error = e->ioapic_probe(e);
-               if (!error)
-                       break;
-       }
-       if (e == NULL) {
-#ifdef notyet
-               panic("can't config I/O APIC\n");
-#else
-               kprintf("no I/O APIC\n");
-               return;
-#endif
-       }
-
-       crit_enter();
-
-       ef = read_eflags();
-       cpu_disable_intr();
-
-       /*
-        * Switch to I/O APIC MachIntrABI and reconfigure
-        * the default IDT entries.
-        */
-       MachIntrABI = MachIntrABI_IOAPIC;
-       MachIntrABI.setdefault();
-
-       e->ioapic_enumerate(e);
-
-       /*
-        * Setup index
-        */
-       i = 0;
-       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link)
-               info->io_idx = i++;
-
-       if (i > IOAPIC_COUNT_MAX) /* XXX magic number */
-               panic("ioapic_config: more than 16 I/O APIC\n");
-
-       /*
-        * Setup APIC ID
-        */
-       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
-               int apic_id;
-
-               apic_id = ioapic_alloc_apic_id(start_apic_id);
-               if (apic_id == NAPICID) {
-                       kprintf("IOAPIC: can't alloc APIC ID for "
-                               "%dth I/O APIC\n", info->io_idx);
-                       break;
-               }
-               info->io_apic_id = apic_id;
-
-               start_apic_id = apic_id + 1;
-       }
-       if (info != NULL) {
-               /*
-                * xAPIC allows I/O APIC's APIC ID to be same
-                * as the LAPIC's APIC ID
-                */
-               kprintf("IOAPIC: use xAPIC model to alloc APIC ID "
-                       "for I/O APIC\n");
-
-               TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link)
-                       info->io_apic_id = info->io_idx;
-       }
-
-       /*
-        * Warning about any GSI holes
-        */
-       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
-               const struct ioapic_info *prev_info;
-
-               prev_info = TAILQ_PREV(info, ioapic_info_list, io_link);
-               if (prev_info != NULL) {
-                       if (info->io_gsi_base !=
-                       prev_info->io_gsi_base + prev_info->io_npin) {
-                               kprintf("IOAPIC: warning gsi hole "
-                                       "[%d, %d]\n",
-                                       prev_info->io_gsi_base +
-                                       prev_info->io_npin,
-                                       info->io_gsi_base - 1);
-                       }
-               }
-       }
-
-       if (bootverbose) {
-               TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
-                       kprintf("IOAPIC: idx %d, apic id %d, "
-                               "gsi base %d, npin %d\n",
-                               info->io_idx,
-                               info->io_apic_id,
-                               info->io_gsi_base,
-                               info->io_npin);
-               }
-       }
-
-       /*
-        * Setup all I/O APIC
-        */
-       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link)
-               ioapic_setup(info);
-       ioapic_abi_fixup_irqmap();
-
-       write_eflags(ef);
-
-       MachIntrABI.cleanup();
-
-       crit_exit();
-}
-
-void
-ioapic_enumerator_register(struct ioapic_enumerator *ne)
-{
-       struct ioapic_enumerator *e;
-
-       TAILQ_FOREACH(e, &ioapic_enumerators, ioapic_link) {
-               if (e->ioapic_prio < ne->ioapic_prio) {
-                       TAILQ_INSERT_BEFORE(e, ne, ioapic_link);
-                       return;
-               }
-       }
-       TAILQ_INSERT_TAIL(&ioapic_enumerators, ne, ioapic_link);
-}
-
-void
-ioapic_add(void *addr, int gsi_base, int npin)
-{
-       struct ioapic_info *info, *ninfo;
-       int gsi_end;
-
-       gsi_end = gsi_base + npin - 1;
-       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
-               if ((gsi_base >= info->io_gsi_base &&
-                    gsi_base < info->io_gsi_base + info->io_npin) ||
-                   (gsi_end >= info->io_gsi_base &&
-                    gsi_end < info->io_gsi_base + info->io_npin)) {
-                       panic("ioapic_add: overlapped gsi, base %d npin %d, "
-                             "hit base %d, npin %d\n", gsi_base, npin,
-                             info->io_gsi_base, info->io_npin);
-               }
-               if (info->io_addr == addr)
-                       panic("ioapic_add: duplicated addr %p\n", addr);
-       }
-
-       ninfo = kmalloc(sizeof(*ninfo), M_DEVBUF, M_WAITOK | M_ZERO);
-       ninfo->io_addr = addr;
-       ninfo->io_npin = npin;
-       ninfo->io_gsi_base = gsi_base;
-       ninfo->io_apic_id = -1;
-
-       /*
-        * Create IOAPIC list in ascending order of GSI base
-        */
-       TAILQ_FOREACH_REVERSE(info, &ioapic_conf.ioc_list,
-           ioapic_info_list, io_link) {
-               if (ninfo->io_gsi_base > info->io_gsi_base) {
-                       TAILQ_INSERT_AFTER(&ioapic_conf.ioc_list,
-                           info, ninfo, io_link);
-                       break;
-               }
-       }
-       if (info == NULL)
-               TAILQ_INSERT_HEAD(&ioapic_conf.ioc_list, ninfo, io_link);
-}
-
-void
-ioapic_intsrc(int irq, int gsi, enum intr_trigger trig, enum intr_polarity pola)
-{
-       struct ioapic_intsrc *int_src;
-
-       KKASSERT(irq < 16);
-       int_src = &ioapic_conf.ioc_intsrc[irq];
-
-       if (gsi == 0) {
-               /* Don't allow mixed mode */
-               kprintf("IOAPIC: warning intsrc irq %d -> gsi 0\n", irq);
-               return;
-       }
-
-       if (int_src->int_gsi != -1) {
-               if (int_src->int_gsi != gsi) {
-                       kprintf("IOAPIC: warning intsrc irq %d, gsi "
-                               "%d -> %d\n", irq, int_src->int_gsi, gsi);
-               }
-               if (int_src->int_trig != trig) {
-                       kprintf("IOAPIC: warning intsrc irq %d, trig "
-                               "%s -> %s\n", irq,
-                               intr_str_trigger(int_src->int_trig),
-                               intr_str_trigger(trig));
-               }
-               if (int_src->int_pola != pola) {
-                       kprintf("IOAPIC: warning intsrc irq %d, pola "
-                               "%s -> %s\n", irq,
-                               intr_str_polarity(int_src->int_pola),
-                               intr_str_polarity(pola));
-               }
-       }
-       int_src->int_gsi = gsi;
-       int_src->int_trig = trig;
-       int_src->int_pola = pola;
-}
-
-static void
-ioapic_set_apic_id(const struct ioapic_info *info)
-{
-       uint32_t id;
-       int apic_id;
-
-       id = ioapic_read(info->io_addr, IOAPIC_ID);
-
-       id &= ~APIC_ID_MASK;
-       id |= (info->io_apic_id << 24);
-
-       ioapic_write(info->io_addr, IOAPIC_ID, id);
-
-       /*
-        * Re-read && test
-        */
-       id = ioapic_read(info->io_addr, IOAPIC_ID);
-       apic_id = (id & APIC_ID_MASK) >> 24;
-
-       /*
-        * I/O APIC ID is a 4bits field
-        */
-       if ((apic_id & IOAPIC_ID_MASK) !=
-           (info->io_apic_id & IOAPIC_ID_MASK)) {
-               panic("ioapic_set_apic_id: can't set apic id to %d, "
-                     "currently set to %d\n", info->io_apic_id, apic_id);
-       }
-}
-
-static void
-ioapic_gsi_setup(int gsi)
-{
-       enum intr_trigger trig;
-       enum intr_polarity pola;
-       int irq;
-
-       if (gsi == 0) {
-               /* ExtINT */
-               imen_lock();
-               ioapic_extpin_setup(ioapic_gsi_ioaddr(gsi),
-                   ioapic_gsi_pin(gsi), 0);
-               imen_unlock();
-               return;
-       }
-
-       trig = 0;       /* silence older gcc's */
-       pola = 0;       /* silence older gcc's */
-
-       for (irq = 0; irq < 16; ++irq) {
-               const struct ioapic_intsrc *int_src =
-                   &ioapic_conf.ioc_intsrc[irq];
-
-               if (gsi == int_src->int_gsi) {
-                       trig = int_src->int_trig;
-                       pola = int_src->int_pola;
-                       break;
-               }
-       }
-
-       if (irq == 16) {
-               if (gsi < 16) {
-                       trig = INTR_TRIGGER_EDGE;
-                       pola = INTR_POLARITY_HIGH;
-               } else {
-                       trig = INTR_TRIGGER_LEVEL;
-                       pola = INTR_POLARITY_LOW;
-               }
-               irq = gsi;
-       }
-
-       ioapic_abi_set_irqmap(irq, gsi, trig, pola);
-}
-
-void *
-ioapic_gsi_ioaddr(int gsi)
-{
-       const struct ioapic_info *info;
-
-       info = ioapic_gsi_search(gsi);
-       return info->io_addr;
-}
-
-int
-ioapic_gsi_pin(int gsi)
-{
-       const struct ioapic_info *info;
-
-       info = ioapic_gsi_search(gsi);
-       return gsi - info->io_gsi_base;
-}
-
-static const struct ioapic_info *
-ioapic_gsi_search(int gsi)
-{
-       const struct ioapic_info *info;
-
-       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
-               if (gsi >= info->io_gsi_base &&
-                   gsi < info->io_gsi_base + info->io_npin)
-                       return info;
-       }
-       panic("ioapic_gsi_search: no I/O APIC\n");
-}
-
-int
-ioapic_gsi(int idx, int pin)
-{
-       const struct ioapic_info *info;
-
-       TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
-               if (info->io_idx == idx)
-                       break;
-       }
-       if (info == NULL)
-               return -1;
-       if (pin >= info->io_npin)
-               return -1;
-       return info->io_gsi_base + pin;
-}
-
-void
-ioapic_extpin_setup(void *addr, int pin, int vec)
-{
-       ioapic_pin_prog(addr, pin, vec,
-           INTR_TRIGGER_CONFORM, INTR_POLARITY_CONFORM, IOART_DELEXINT);
-}
-
-int
-ioapic_extpin_gsi(void)
-{
-       return 0;
-}
-
-void
-ioapic_pin_setup(void *addr, int pin, int vec,
-    enum intr_trigger trig, enum intr_polarity pola)
-{
-       /*
-        * Always clear an I/O APIC pin before [re]programming it.  This is
-        * particularly important if the pin is set up for a level interrupt
-        * as the IOART_REM_IRR bit might be set.   When we reprogram the
-        * vector any EOI from pending ints on this pin could be lost and
-        * IRR might never get reset.
-        *
-        * To fix this problem, clear the vector and make sure it is 
-        * programmed as an edge interrupt.  This should theoretically
-        * clear IRR so we can later, safely program it as a level 
-        * interrupt.
-        */
-       ioapic_pin_prog(addr, pin, vec, INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH,
-           IOART_DELFIXED);
-       ioapic_pin_prog(addr, pin, vec, trig, pola, IOART_DELFIXED);
-}
-
-static void
-ioapic_pin_prog(void *addr, int pin, int vec,
-    enum intr_trigger trig, enum intr_polarity pola, uint32_t del_mode)
-{
-       uint32_t flags, target;
-       int select;
-
-       KKASSERT(del_mode == IOART_DELEXINT || del_mode == IOART_DELFIXED);
-
-       select = IOAPIC_REDTBL0 + (2 * pin);
-
-       flags = ioapic_read(addr, select) & IOART_RESV;
-       flags |= IOART_INTMSET | IOART_DESTPHY;
-#ifdef foo
-       flags |= del_mode;
-#else
-       /*
-        * We only support limited I/O APIC mixed mode,
-        * so even for ExtINT, we still use "fixed"
-        * delivery mode.
-        */
-       flags |= IOART_DELFIXED;
-#endif
-
-       if (del_mode == IOART_DELEXINT) {
-               KKASSERT(trig == INTR_TRIGGER_CONFORM &&
-                        pola == INTR_POLARITY_CONFORM);
-               flags |= IOART_TRGREDG | IOART_INTAHI;
-       } else {
-               switch (trig) {
-               case INTR_TRIGGER_EDGE:
-                       flags |= IOART_TRGREDG;
-                       break;
-
-               case INTR_TRIGGER_LEVEL:
-                       flags |= IOART_TRGRLVL;
-                       break;
-
-               case INTR_TRIGGER_CONFORM:
-                       panic("ioapic_pin_prog: trig conform is not "
-                             "supported\n");
-               }
-               switch (pola) {
-               case INTR_POLARITY_HIGH:
-                       flags |= IOART_INTAHI;
-                       break;
-
-               case INTR_POLARITY_LOW:
-                       flags |= IOART_INTALO;
-                       break;
-
-               case INTR_POLARITY_CONFORM:
-                       panic("ioapic_pin_prog: pola conform is not "
-                             "supported\n");
-               }
-       }
-
-       target = ioapic_read(addr, select + 1) & IOART_HI_DEST_RESV;
-       target |= (CPU_TO_ID(0) << IOART_HI_DEST_SHIFT) &
-                 IOART_HI_DEST_MASK;
-
-       ioapic_write(addr, select, flags | vec);
-       ioapic_write(addr, select + 1, target);
-}
-
-static void
-ioapic_setup(const struct ioapic_info *info)
-{
-       int i;
-
-       ioapic_set_apic_id(info);
-
-       for (i = 0; i < info->io_npin; ++i)
-               ioapic_gsi_setup(info->io_gsi_base + i);
-}
-
-static int
-ioapic_alloc_apic_id(int start)
-{
-       for (;;) {
-               const struct ioapic_info *info;
-               int apic_id, apic_id16;
-
-               apic_id = lapic_unused_apic_id(start);
-               if (apic_id == NAPICID) {
-                       kprintf("IOAPIC: can't find unused APIC ID\n");
-                       return apic_id;
-               }
-               apic_id16 = apic_id & IOAPIC_ID_MASK;
-
-               /*
-                * Check against other I/O APIC's APIC ID's lower 4bits.
-                *
-                * The new APIC ID will have to be different from others
-                * in the lower 4bits, no matter whether xAPIC is used
-                * or not.
-                */
-               TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
-                       if (info->io_apic_id == -1) {
-                               info = NULL;
-                               break;
-                       }
-                       if ((info->io_apic_id & IOAPIC_ID_MASK) == apic_id16)
-                               break;
-               }
-               if (info == NULL)
-                       return apic_id;
-
-               kprintf("IOAPIC: APIC ID %d has same lower 4bits as "
-                       "%dth I/O APIC, keep searching...\n",
-                       apic_id, info->io_idx);
-
-               start = apic_id + 1;
-       }
-       panic("ioapic_unused_apic_id: never reached\n");
-}
index 8c254fc..81a6178 100644 (file)
@@ -75,5 +75,6 @@ all_but_self_ipi(int vector)
 #endif
 
 void   lapic_map(vm_offset_t /* XXX should be vm_paddr_t */);
+int    lapic_unused_apic_id(int);
 
 #endif /* _MACHINE_MPAPIC_H */
index 4407261..974b3e0 100644 (file)
@@ -193,8 +193,9 @@ platform/pc32/icu/icu_abi.c         standard
 platform/pc32/icu/icu_ipl.s            standard
 platform/pc32/icu/icu_vector.s         standard
 platform/pc32/icu/elcr.c               standard
+platform/pc32/apic/lapic.c             optional        smp
+platform/pc32/apic/ioapic.c            optional        smp
 platform/pc32/apic/ioapic_abi.c                optional        smp
-platform/pc32/apic/mpapic.c            optional        smp
 platform/pc32/apic/ioapic_ipl.s                optional        smp
 platform/pc32/apic/apic_vector.s       optional        smp
 platform/pc32/i386/est.c               optional        cpu_enable_est