ioapic: Setup I/O APIC according to the saved information. Stage 1/2
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 17 Mar 2011 10:55:41 +0000 (18:55 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 17 Mar 2011 11:07:11 +0000 (19:07 +0800)
sys/platform/pc32/apic/mpapic.c
sys/platform/pc32/include/smp.h
sys/platform/pc64/apic/mpapic.c
sys/platform/pc64/include/smp.h

index c81b36f..708bf85 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/bus.h>
 #include <machine/globaldata.h>
 #include <machine/smp.h>
 #include <machine/cputypes.h>
@@ -78,6 +79,12 @@ 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 void    ioapic_setup(const struct ioapic_info *);
+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 struct cputimer_intr lapic_cputimer_intr = {
        .freq = 0,
        .reload = lapic_timer_intr_reload,
@@ -1096,6 +1103,9 @@ ioapic_config(void)
        if (!ioapic_use_old) {
                struct ioapic_info *info;
 
+               /*
+                * Fixup the rest of the fields of ioapic_info
+                */
                i = 0;
                TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
                        const struct ioapic_info *prev_info;
@@ -1103,8 +1113,6 @@ ioapic_config(void)
                        info->io_idx = i++;
                        info->io_apic_id = info->io_idx + lapic_id_max + 1;
 
-                       /* TODO set apic id, config all pins */
-
                        if (bootverbose) {
                                kprintf("IOAPIC: idx %d, apic id %d, "
                                        "gsi base %d, npin %d\n",
@@ -1127,6 +1135,13 @@ ioapic_config(void)
                                }
                        }
                }
+
+               /*
+                * Setup all I/O APIC
+                */
+               TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link)
+                       ioapic_setup(info);
+
                panic("ioapic_config: new ioapic not working yet\n");
        }
 }
@@ -1196,3 +1211,101 @@ ioapic_intsrc(int irq, int gsi)
        }
        ioapic_conf.ioc_intsrc[irq] = gsi;
 }
+
+static void
+ioapic_set_apic_id(const struct ioapic_info *info)
+{
+       uint32_t 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);
+       if (((id & APIC_ID_MASK) >> 24) != info->io_apic_id) {
+               panic("ioapic_set_apic_id: can't set apic id to %d\n",
+                     info->io_apic_id);
+       }
+}
+
+static void
+ioapic_gsi_setup(int gsi)
+{
+       enum intr_trigger trig;
+       enum intr_polarity pola;
+       int irq;
+
+       for (irq = 0; irq < 16; ++irq) {
+               if (gsi == ioapic_conf.ioc_intsrc[irq]) {
+                       trig = INTR_TRIGGER_EDGE;
+                       pola = INTR_POLARITY_HIGH;
+                       break;
+               }
+       }
+
+       if (irq == 16) {
+               if (gsi == 0) {
+                       /* TODO Program EXTINT */
+                       return;
+               } else if (gsi < 16) {
+                       trig = INTR_TRIGGER_EDGE;
+                       pola = INTR_POLARITY_HIGH;
+               } else {
+                       trig = INTR_TRIGGER_LEVEL;
+                       pola = INTR_POLARITY_LOW;
+               }
+               irq = gsi;
+       }
+
+#if 0
+       ioapic_abi_set_irqmap(irq, gsi, trig, pola);
+#endif
+}
+
+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");
+}
+
+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);
+}
index bf6503a..609c998 100644 (file)
@@ -161,6 +161,9 @@ void        ioapic_config(void);
 void   ioapic_enumerator_register(struct ioapic_enumerator *);
 void   ioapic_add(void *, int, int);
 void   ioapic_intsrc(int, int);
+void   *ioapic_gsi_ioaddr(int);
+int    ioapic_gsi_pin(int);
+
 extern int apic_io_enable;
 extern int ioapic_use_old;
 
index 50ef94b..cfef0ac 100644 (file)
@@ -28,6 +28,7 @@
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/bus.h>
 #include <machine/globaldata.h>
 #include <machine/smp.h>
 #include <machine/md_var.h>
@@ -79,6 +80,12 @@ 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 void    ioapic_setup(const struct ioapic_info *);
+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 struct cputimer_intr lapic_cputimer_intr = {
        .freq = 0,
        .reload = lapic_timer_intr_reload,
@@ -1158,6 +1165,9 @@ ioapic_config(void)
        if (!ioapic_use_old) {
                struct ioapic_info *info;
 
+               /*
+                * Fixup the rest of the fields of ioapic_info
+                */
                i = 0;
                TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
                        const struct ioapic_info *prev_info;
@@ -1165,8 +1175,6 @@ ioapic_config(void)
                        info->io_idx = i++;
                        info->io_apic_id = info->io_idx + lapic_id_max + 1;
 
-                       /* TODO set apic id, config all pins */
-
                        if (bootverbose) {
                                kprintf("IOAPIC: idx %d, apic id %d, "
                                        "gsi base %d, npin %d\n",
@@ -1189,6 +1197,13 @@ ioapic_config(void)
                                }
                        }
                }
+
+               /*
+                * Setup all I/O APIC
+                */
+               TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link)
+                       ioapic_setup(info);
+
                panic("ioapic_config: new ioapic not working yet\n");
        }
 }
@@ -1258,3 +1273,101 @@ ioapic_intsrc(int irq, int gsi)
        }
        ioapic_conf.ioc_intsrc[irq] = gsi;
 }
+
+static void
+ioapic_set_apic_id(const struct ioapic_info *info)
+{
+       uint32_t 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);
+       if (((id & APIC_ID_MASK) >> 24) != info->io_apic_id) {
+               panic("ioapic_set_apic_id: can't set apic id to %d\n",
+                     info->io_apic_id);
+       }
+}
+
+static void
+ioapic_gsi_setup(int gsi)
+{
+       enum intr_trigger trig;
+       enum intr_polarity pola;
+       int irq;
+
+       for (irq = 0; irq < 16; ++irq) {
+               if (gsi == ioapic_conf.ioc_intsrc[irq]) {
+                       trig = INTR_TRIGGER_EDGE;
+                       pola = INTR_POLARITY_HIGH;
+                       break;
+               }
+       }
+
+       if (irq == 16) {
+               if (gsi == 0) {
+                       /* TODO Program EXTINT */
+                       return;
+               } else if (gsi < 16) {
+                       trig = INTR_TRIGGER_EDGE;
+                       pola = INTR_POLARITY_HIGH;
+               } else {
+                       trig = INTR_TRIGGER_LEVEL;
+                       pola = INTR_POLARITY_LOW;
+               }
+               irq = gsi;
+       }
+
+#if 0
+       ioapic_abi_set_irqmap(irq, gsi, trig, pola);
+#endif
+}
+
+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");
+}
+
+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);
+}
index 5a4d3b2..623bd32 100644 (file)
@@ -172,6 +172,8 @@ void        ioapic_config(void);
 void   ioapic_enumerator_register(struct ioapic_enumerator *);
 void   ioapic_add(void *, int, int);
 void   ioapic_intsrc(int, int);
+void   *ioapic_gsi_ioaddr(int);
+int    ioapic_gsi_pin(int);
 
 #if defined(READY)
 void   clr_io_apic_mask24      (int, u_int32_t);