ioapic: Save I/O APIC information for later configuration
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 17 Mar 2011 06:45:45 +0000 (14:45 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Thu, 17 Mar 2011 08:14:18 +0000 (16:14 +0800)
sys/platform/pc32/apic/mpapic.c
sys/platform/pc32/i386/mp_machdep.c
sys/platform/pc32/i386/mp_madt.c
sys/platform/pc32/include/smp.h
sys/platform/pc64/apic/mpapic.c
sys/platform/pc64/include/smp.h
sys/platform/pc64/x86_64/mp_machdep.c
sys/platform/pc64/x86_64/mp_madt.c

index 83906b4..a042c39 100644 (file)
@@ -46,6 +46,22 @@ extern pt_entry_t *SMPpt;
 #define ELCR0  0x4d0                   /* eisa irq 0-7 */
 #define ELCR1  0x4d1                   /* eisa irq 8-15 */
 
+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_conf {
+       struct ioapic_info_list ioc_list;
+       int             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 *);
@@ -92,6 +108,8 @@ static const uint32_t        lapic_timer_divisors[] = {
 
 int                    lapic_id_max;
 
+static struct ioapic_conf      ioapic_conf;
+
 /*
  * Enable LAPIC, configure interrupts.
  */
@@ -1052,7 +1070,12 @@ void
 ioapic_config(void)
 {
        struct ioapic_enumerator *e;
-       int error;
+       int error, i;
+
+       TAILQ_INIT(&ioapic_conf.ioc_list);
+       /* XXX magic number */
+       for (i = 0; i < 16; ++i)
+               ioapic_conf.ioc_intsrc[i] = -1;
 
        TAILQ_FOREACH(e, &ioapic_enumerators, ioapic_link) {
                error = e->ioapic_probe(e);
@@ -1070,8 +1093,42 @@ ioapic_config(void)
 
        e->ioapic_enumerate(e);
 
-       if (!ioapic_use_old)
+       if (!ioapic_use_old) {
+               struct ioapic_info *info;
+
+               i = 0;
+               TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
+                       const struct ioapic_info *prev_info;
+
+                       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",
+                                       info->io_idx,
+                                       info->io_apic_id,
+                                       info->io_gsi_base,
+                                       info->io_npin);
+                       }
+
+                       /* Warning about possible GSI hole */
+                       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);
+                               }
+                       }
+               }
                panic("ioapic_config: new ioapic not working yet\n");
+       }
 }
 
 void
@@ -1087,3 +1144,43 @@ ioapic_enumerator_register(struct ioapic_enumerator *ne)
        }
        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;
+
+       /*
+        * 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);
+}
index aa22933..cac2709 100644 (file)
@@ -3633,7 +3633,8 @@ mptable_ioapic_enumerate(struct ioapic_enumerator *e)
                                        prev_ioapic->mio_gsi_base +
                                        prev_ioapic->mio_npin;
                        }
-                       /* TODO */
+                       ioapic_add(addr, ioapic->mio_gsi_base,
+                           ioapic->mio_npin);
                }
                if (bootverbose) {
                        kprintf("MPTABLE: IOAPIC addr 0x%08x, "
index 93a1489..7154ab0 100644 (file)
@@ -852,6 +852,20 @@ madt_ioapic_enum_callback(void *xarg, const struct acpi_madt_ent *ent)
                MADT_VPRINTF("IOAPIC addr 0x%08x, apic id %d, gsi base %u\n",
                             ioapic_ent->mio_addr, ioapic_ent->mio_apic_id,
                             ioapic_ent->mio_gsi_base);
+
+               if (!ioapic_use_old) {
+                       uint32_t ver;
+                       void *addr;
+                       int npin;
+
+                       addr = ioapic_map(ioapic_ent->mio_addr);
+
+                       ver = ioapic_read(addr, IOAPIC_VER);
+                       npin = ((ver & IOART_VER_MAXREDIR) >>
+                               MAXREDIRSHIFT) + 1;
+
+                       ioapic_add(addr, ioapic_ent->mio_gsi_base, npin);
+               }
        }
        return 0;
 }
index bc48ab5..4da1f13 100644 (file)
@@ -159,6 +159,7 @@ void        lapic_config(void);
 void   lapic_enumerator_register(struct lapic_enumerator *);
 void   ioapic_config(void);
 void   ioapic_enumerator_register(struct ioapic_enumerator *);
+void   ioapic_add(void *, int, int);
 extern int apic_io_enable;
 extern int ioapic_use_old;
 
index 7ea6720..1e4d374 100644 (file)
 #define ELCR0  0x4d0                   /* eisa irq 0-7 */
 #define ELCR1  0x4d1                   /* eisa irq 8-15 */
 
+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_conf {
+       struct ioapic_info_list ioc_list;
+       int             ioc_intsrc[16]; /* XXX magic number */
+};
+
 volatile lapic_t *lapic;
 
 static void    lapic_timer_calibrate(void);
@@ -92,6 +108,7 @@ static const uint32_t        lapic_timer_divisors[] = {
 #define APIC_TIMER_NDIVISORS (int)(NELEM(lapic_timer_divisors))
 
 int                    lapic_id_max;
+static struct ioapic_conf      ioapic_conf;
 
 void
 lapic_eoi(void)
@@ -1115,7 +1132,12 @@ void
 ioapic_config(void)
 {
        struct ioapic_enumerator *e;
-       int error;
+       int error, i;
+
+       TAILQ_INIT(&ioapic_conf.ioc_list);
+       /* XXX magic number */
+       for (i = 0; i < 16; ++i)
+               ioapic_conf.ioc_intsrc[i] = -1;
 
        TAILQ_FOREACH(e, &ioapic_enumerators, ioapic_link) {
                error = e->ioapic_probe(e);
@@ -1133,8 +1155,42 @@ ioapic_config(void)
 
        e->ioapic_enumerate(e);
 
-       if (!ioapic_use_old)
+       if (!ioapic_use_old) {
+               struct ioapic_info *info;
+
+               i = 0;
+               TAILQ_FOREACH(info, &ioapic_conf.ioc_list, io_link) {
+                       const struct ioapic_info *prev_info;
+
+                       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",
+                                       info->io_idx,
+                                       info->io_apic_id,
+                                       info->io_gsi_base,
+                                       info->io_npin);
+                       }
+
+                       /* Warning about possible GSI hole */
+                       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);
+                               }
+                       }
+               }
                panic("ioapic_config: new ioapic not working yet\n");
+       }
 }
 
 void
@@ -1150,3 +1206,43 @@ ioapic_enumerator_register(struct ioapic_enumerator *ne)
        }
        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;
+
+       /*
+        * 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);
+}
index 449626c..c2136b5 100644 (file)
@@ -170,6 +170,7 @@ void        lapic_config(void);
 void   lapic_enumerator_register(struct lapic_enumerator *);
 void   ioapic_config(void);
 void   ioapic_enumerator_register(struct ioapic_enumerator *);
+void   ioapic_add(void *, int, int);
 
 #if defined(READY)
 void   clr_io_apic_mask24      (int, u_int32_t);
index 05ed6c2..3f469de 100644 (file)
@@ -3628,7 +3628,8 @@ mptable_ioapic_enumerate(struct ioapic_enumerator *e)
                                        prev_ioapic->mio_gsi_base +
                                        prev_ioapic->mio_npin;
                        }
-                       /* TODO */
+                       ioapic_add(addr, ioapic->mio_gsi_base,
+                           ioapic->mio_npin);
                }
                if (bootverbose) {
                        kprintf("MPTABLE: IOAPIC addr 0x%08x, "
index 3f99a7c..2c8b8aa 100644 (file)
@@ -851,6 +851,20 @@ madt_ioapic_enum_callback(void *xarg, const struct acpi_madt_ent *ent)
                MADT_VPRINTF("IOAPIC addr 0x%08x, apic id %d, gsi base %u\n",
                             ioapic_ent->mio_addr, ioapic_ent->mio_apic_id,
                             ioapic_ent->mio_gsi_base);
+
+               if (!ioapic_use_old) {
+                       uint32_t ver;
+                       void *addr;
+                       int npin;
+
+                       addr = ioapic_map(ioapic_ent->mio_addr);
+
+                       ver = ioapic_read(addr, IOAPIC_VER);
+                       npin = ((ver & IOART_VER_MAXREDIR) >>
+                               MAXREDIRSHIFT) + 1;
+
+                       ioapic_add(addr, ioapic_ent->mio_gsi_base, npin);
+               }
        }
        return 0;
 }