From 7da2706b8bf5236909eb4983d7415fe8976fbc5f Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Tue, 22 Feb 2011 18:59:14 +0800 Subject: [PATCH] mptable: Implement stub I/O APIC enumerator --- sys/platform/pc32/i386/mp_machdep.c | 227 ++++++++++++++++++++++++++ sys/platform/pc64/x86_64/mp_machdep.c | 227 ++++++++++++++++++++++++++ 2 files changed, 454 insertions(+) diff --git a/sys/platform/pc32/i386/mp_machdep.c b/sys/platform/pc32/i386/mp_machdep.c index 0989a85caa..483b930944 100644 --- a/sys/platform/pc32/i386/mp_machdep.c +++ b/sys/platform/pc32/i386/mp_machdep.c @@ -346,6 +346,9 @@ static int mptable_lapic_probe(struct lapic_enumerator *); static void mptable_lapic_enumerate(struct lapic_enumerator *); static void mptable_lapic_default(void); +static int mptable_ioapic_probe(struct ioapic_enumerator *); +static void mptable_ioapic_enumerate(struct ioapic_enumerator *); + #ifdef SMP /* APIC-IO */ static void setup_apic_irq_mapping(void); static int apic_int_is_bus_type(int intr, int bus_type); @@ -3348,3 +3351,227 @@ done: } SYSINIT(mptable_pci, SI_BOOT2_PRESMP, SI_ORDER_ANY, mptable_pci_int_register, 0); + +struct mptable_ioapic_probe_cbarg { + const struct mptable_bus_info *bus_info; + int ioapic_cnt; +}; + +static int +mptable_ioapic_probe_callback(void *xarg, const void *pos, int type) +{ + struct mptable_ioapic_probe_cbarg *arg = xarg; + + if (type == 3) { + const struct INTENTRY *ent = pos; + const struct mptable_bus *bus; + + if (ent->int_type != 0) + return 0; + + TAILQ_FOREACH(bus, &arg->bus_info->mbi_list, mb_link) { + if (bus->mb_type == MPTABLE_BUS_ISA && + bus->mb_id == ent->src_bus_id) + break; + } + if (bus == NULL) + return 0; + + /* XXX magic number */ + if (ent->src_bus_irq >= 16) { + kprintf("mptable_ioapic_probe: invalid ISA irq " + "(%d)\n", ent->src_bus_irq); + return EINVAL; + } + } else if (type == 2) { + const struct IOAPICENTRY *ent = pos; + + if ((ent->apic_flags & IOAPICENTRY_FLAG_EN) == 0) + return 0; + + if (ent->apic_address == 0) { + kprintf("mptable_ioapic_probe: zero IOAPIC address\n"); + return EINVAL; + } + arg->ioapic_cnt++; + } + return 0; +} + +static int +mptable_ioapic_probe(struct ioapic_enumerator *e) +{ + struct mptable_ioapic_probe_cbarg arg; + struct mptable_bus_info bus_info; + struct mptable_pos mpt; + mpcth_t cth; + int error; + + if (mptable_fps_phyaddr == 0) + return ENXIO; + + if (mptable_use_default) + return 0; + + error = mptable_map(&mpt); + if (error) + panic("mptable_ioapic_probe: mptable_map failed\n"); + KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt)); + + cth = mpt.mp_cth; + + mptable_bus_info_alloc(cth, &bus_info); + + bzero(&arg, sizeof(arg)); + arg.bus_info = &bus_info; + + error = mptable_iterate_entries(cth, + mptable_ioapic_probe_callback, &arg); + if (!error) { + if (arg.ioapic_cnt == 0) { + kprintf("mptable_ioapic_probe: no IOAPIC\n"); + error = ENXIO; + } + } + + mptable_bus_info_free(&bus_info); + mptable_unmap(&mpt); + + return error; +} + +static int +mptable_ioapic_enum_callback(void *xarg, const void *pos, int type) +{ + const struct IOAPICENTRY *ent; + + if (type != 2) + return 0; + + ent = pos; + + if ((ent->apic_flags & IOAPICENTRY_FLAG_EN) == 0) + return 0; + + if (bootverbose) { + kprintf("MPTABLE: IOAPIC addr 0x%08x, apic id %d\n", + (unsigned int)ent->apic_address, ent->apic_id); + } + return 0; +} + +struct mptable_ioapic_int_cbarg { + const struct mptable_bus_info *bus_info; + int ioapic_nint; +}; + +static int +mptable_ioapic_int_callback(void *xarg, const void *pos, int type) +{ + struct mptable_ioapic_int_cbarg *arg = xarg; + const struct mptable_bus *bus; + const struct INTENTRY *ent; + + if (type != 3) + return 0; + + arg->ioapic_nint++; + + ent = pos; + if (ent->int_type != 0) + return 0; + + TAILQ_FOREACH(bus, &arg->bus_info->mbi_list, mb_link) { + if (bus->mb_type == MPTABLE_BUS_ISA && + bus->mb_id == ent->src_bus_id) + break; + } + if (bus == NULL) + return 0; + + /* XXX rough estimation */ + if (ent->src_bus_irq != ent->dst_apic_int) { + if (bootverbose) { + kprintf("MPTABLE: INTSRC irq %d -> GSI %d\n", + ent->src_bus_irq, ent->dst_apic_int); + } + } + return 0; +} + +static void +mptable_ioapic_enumerate(struct ioapic_enumerator *e) +{ + struct mptable_bus_info bus_info; + struct mptable_pos mpt; + mpcth_t cth; + int error; + + KKASSERT(mptable_fps_phyaddr != 0); + + if (mptable_use_default) { + if (bootverbose) { + kprintf("MPTABLE: IOAPIC address 0xfec00000 " + "(default)\n"); + kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 (default)\n"); + } + /* TODO default ioapic and intsrc */ + return; + } + + error = mptable_map(&mpt); + if (error) + panic("mptable_ioapic_probe: mptable_map failed\n"); + KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt)); + + cth = mpt.mp_cth; + + error = mptable_iterate_entries(cth, + mptable_ioapic_enum_callback, NULL); + if (error) + panic("mptable_ioapic_enum failed\n"); + + mptable_bus_info_alloc(cth, &bus_info); + + if (TAILQ_EMPTY(&bus_info.mbi_list)) { + if (bootverbose) + kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 (no bus)\n"); + /* TODO default intsrc */ + } else { + struct mptable_ioapic_int_cbarg arg; + + bzero(&arg, sizeof(arg)); + arg.bus_info = &bus_info; + + error = mptable_iterate_entries(cth, + mptable_ioapic_int_callback, &arg); + if (error) + panic("mptable_ioapic_int failed\n"); + + if (arg.ioapic_nint == 0) { + if (bootverbose) { + kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 " + "(no int)\n"); + } + /* TODO default intsrc */ + } + } + + mptable_bus_info_free(&bus_info); + + mptable_unmap(&mpt); +} + +static struct ioapic_enumerator mptable_ioapic_enumerator = { + .ioapic_prio = IOAPIC_ENUM_PRIO_MPTABLE, + .ioapic_probe = mptable_ioapic_probe, + .ioapic_enumerate = mptable_ioapic_enumerate +}; + +static void +mptable_ioapic_enum_register(void) +{ + ioapic_enumerator_register(&mptable_ioapic_enumerator); +} +SYSINIT(mptable_ioapic, SI_BOOT2_PRESMP, SI_ORDER_ANY, + mptable_ioapic_enum_register, 0); diff --git a/sys/platform/pc64/x86_64/mp_machdep.c b/sys/platform/pc64/x86_64/mp_machdep.c index f283339bd5..197a86036d 100644 --- a/sys/platform/pc64/x86_64/mp_machdep.c +++ b/sys/platform/pc64/x86_64/mp_machdep.c @@ -332,6 +332,9 @@ static int mptable_lapic_probe(struct lapic_enumerator *); static void mptable_lapic_enumerate(struct lapic_enumerator *); static void mptable_lapic_default(void); +static int mptable_ioapic_probe(struct ioapic_enumerator *); +static void mptable_ioapic_enumerate(struct ioapic_enumerator *); + #ifdef SMP /* APIC-IO */ static void setup_apic_irq_mapping(void); static int apic_int_is_bus_type(int intr, int bus_type); @@ -3343,3 +3346,227 @@ done: } SYSINIT(mptable_pci, SI_BOOT2_PRESMP, SI_ORDER_ANY, mptable_pci_int_register, 0); + +struct mptable_ioapic_probe_cbarg { + const struct mptable_bus_info *bus_info; + int ioapic_cnt; +}; + +static int +mptable_ioapic_probe_callback(void *xarg, const void *pos, int type) +{ + struct mptable_ioapic_probe_cbarg *arg = xarg; + + if (type == 3) { + const struct INTENTRY *ent = pos; + const struct mptable_bus *bus; + + if (ent->int_type != 0) + return 0; + + TAILQ_FOREACH(bus, &arg->bus_info->mbi_list, mb_link) { + if (bus->mb_type == MPTABLE_BUS_ISA && + bus->mb_id == ent->src_bus_id) + break; + } + if (bus == NULL) + return 0; + + /* XXX magic number */ + if (ent->src_bus_irq >= 16) { + kprintf("mptable_ioapic_probe: invalid ISA irq " + "(%d)\n", ent->src_bus_irq); + return EINVAL; + } + } else if (type == 2) { + const struct IOAPICENTRY *ent = pos; + + if ((ent->apic_flags & IOAPICENTRY_FLAG_EN) == 0) + return 0; + + if (ent->apic_address == 0) { + kprintf("mptable_ioapic_probe: zero IOAPIC address\n"); + return EINVAL; + } + arg->ioapic_cnt++; + } + return 0; +} + +static int +mptable_ioapic_probe(struct ioapic_enumerator *e) +{ + struct mptable_ioapic_probe_cbarg arg; + struct mptable_bus_info bus_info; + struct mptable_pos mpt; + mpcth_t cth; + int error; + + if (mptable_fps_phyaddr == 0) + return ENXIO; + + if (mptable_use_default) + return 0; + + error = mptable_map(&mpt); + if (error) + panic("mptable_ioapic_probe: mptable_map failed\n"); + KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt)); + + cth = mpt.mp_cth; + + mptable_bus_info_alloc(cth, &bus_info); + + bzero(&arg, sizeof(arg)); + arg.bus_info = &bus_info; + + error = mptable_iterate_entries(cth, + mptable_ioapic_probe_callback, &arg); + if (!error) { + if (arg.ioapic_cnt == 0) { + kprintf("mptable_ioapic_probe: no IOAPIC\n"); + error = ENXIO; + } + } + + mptable_bus_info_free(&bus_info); + mptable_unmap(&mpt); + + return error; +} + +static int +mptable_ioapic_enum_callback(void *xarg, const void *pos, int type) +{ + const struct IOAPICENTRY *ent; + + if (type != 2) + return 0; + + ent = pos; + + if ((ent->apic_flags & IOAPICENTRY_FLAG_EN) == 0) + return 0; + + if (bootverbose) { + kprintf("MPTABLE: IOAPIC addr 0x%08x, apic id %d\n", + ent->apic_address, ent->apic_id); + } + return 0; +} + +struct mptable_ioapic_int_cbarg { + const struct mptable_bus_info *bus_info; + int ioapic_nint; +}; + +static int +mptable_ioapic_int_callback(void *xarg, const void *pos, int type) +{ + struct mptable_ioapic_int_cbarg *arg = xarg; + const struct mptable_bus *bus; + const struct INTENTRY *ent; + + if (type != 3) + return 0; + + arg->ioapic_nint++; + + ent = pos; + if (ent->int_type != 0) + return 0; + + TAILQ_FOREACH(bus, &arg->bus_info->mbi_list, mb_link) { + if (bus->mb_type == MPTABLE_BUS_ISA && + bus->mb_id == ent->src_bus_id) + break; + } + if (bus == NULL) + return 0; + + /* XXX rough estimation */ + if (ent->src_bus_irq != ent->dst_apic_int) { + if (bootverbose) { + kprintf("MPTABLE: INTSRC irq %d -> GSI %d\n", + ent->src_bus_irq, ent->dst_apic_int); + } + } + return 0; +} + +static void +mptable_ioapic_enumerate(struct ioapic_enumerator *e) +{ + struct mptable_bus_info bus_info; + struct mptable_pos mpt; + mpcth_t cth; + int error; + + KKASSERT(mptable_fps_phyaddr != 0); + + if (mptable_use_default) { + if (bootverbose) { + kprintf("MPTABLE: IOAPIC address 0xfec00000 " + "(default)\n"); + kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 (default)\n"); + } + /* TODO default ioapic and intsrc */ + return; + } + + error = mptable_map(&mpt); + if (error) + panic("mptable_ioapic_probe: mptable_map failed\n"); + KKASSERT(!MPTABLE_POS_USE_DEFAULT(&mpt)); + + cth = mpt.mp_cth; + + error = mptable_iterate_entries(cth, + mptable_ioapic_enum_callback, NULL); + if (error) + panic("mptable_ioapic_enum failed\n"); + + mptable_bus_info_alloc(cth, &bus_info); + + if (TAILQ_EMPTY(&bus_info.mbi_list)) { + if (bootverbose) + kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 (no bus)\n"); + /* TODO default intsrc */ + } else { + struct mptable_ioapic_int_cbarg arg; + + bzero(&arg, sizeof(arg)); + arg.bus_info = &bus_info; + + error = mptable_iterate_entries(cth, + mptable_ioapic_int_callback, &arg); + if (error) + panic("mptable_ioapic_int failed\n"); + + if (arg.ioapic_nint == 0) { + if (bootverbose) { + kprintf("MPTABLE: INTSRC irq 0 -> GSI 2 " + "(no int)\n"); + } + /* TODO default intsrc */ + } + } + + mptable_bus_info_free(&bus_info); + + mptable_unmap(&mpt); +} + +static struct ioapic_enumerator mptable_ioapic_enumerator = { + .ioapic_prio = IOAPIC_ENUM_PRIO_MPTABLE, + .ioapic_probe = mptable_ioapic_probe, + .ioapic_enumerate = mptable_ioapic_enumerate +}; + +static void +mptable_ioapic_enum_register(void) +{ + ioapic_enumerator_register(&mptable_ioapic_enumerator); +} +SYSINIT(mptable_ioapic, SI_BOOT2_PRESMP, SI_ORDER_ANY, + mptable_ioapic_enum_register, 0); -- 2.41.0