Index: mpbios.c =================================================================== RCS file: /data/cvs/src/sys/arch/i386/i386/mpbios.c,v retrieving revision 1.3 diff -u -r1.3 mpbios.c --- mpbios.c 23 Jun 2004 17:14:31 -0000 1.3 +++ mpbios.c 2 Jul 2004 18:39:43 -0000 @@ -129,8 +129,10 @@ #include /* for ELCR* def'ns */ +/* set I/O APIC to 2, because 0 and 1 have already been assigned ( APIC ) */ + static struct mpbios_ioapic default_ioapic = { - 2, 0, 1, IOAPICENTRY_FLAG_EN, (caddr_t)IOAPIC_BASE_DEFAULT + MPS_MCT_IOAPIC, 2, 1, IOAPICENTRY_FLAG_EN, (caddr_t)IOAPIC_BASE_DEFAULT }; /* descriptions of MP basetable entries */ @@ -177,6 +179,8 @@ void mpbios_ioapic(const u_int8_t *, struct device *); void mpbios_int(const u_int8_t *, int, struct mp_intr_map *); +int ELCR_trigger(unsigned int); + const void *mpbios_map(paddr_t, int, struct mp_map *); static __inline void mpbios_unmap(struct mp_map *); @@ -484,6 +488,12 @@ 0 }; +int ELCR_trigger(unsigned int irq) +{ + unsigned int elcr_status; + elcr_status = inb(ELCR0) | inb(ELCR1) << 8; + return((elcr_status & (1<dv_xname); @@ -537,30 +548,194 @@ /* check for use of 'default' configuration */ if (mp_fps->mpfb1 != 0) { struct mpbios_proc pe; + struct mpbios_bus bus; + struct mpbios_int mpi; + int i; + int useELCR = 0; printf("\n%s: MP default configuration %d\n", self->dv_xname, mp_fps->mpfb1); - /* use default addresses */ - pe.apic_id = cpu_number(); + + /* + * setup cpu 0 + * cpu_info_primary.ci_signature seems to borken though + * it turns out that the netbsd version of locore.s + * initializes cpu_info_primary, but the openbsd version _does + * not_. Luckily locore.s does initialize cpu_id and + * cpu_feature and that is exactly what we need. We assume + * both cpu's are identical + */ + + pe.apic_id = 0; pe.cpu_flags = PROCENTRY_FLAG_EN|PROCENTRY_FLAG_BP; - pe.cpu_signature = cpu_info_primary.ci_signature; - pe.feature_flags = cpu_info_primary.ci_feature_flags; + pe.cpu_signature = cpu_id; + pe.feature_flags = cpu_feature; mpbios_cpu((u_int8_t *)&pe, self); - pe.apic_id = 1 - cpu_number(); + /* setup cpu 1 */ + + pe.apic_id = 1; pe.cpu_flags = PROCENTRY_FLAG_EN; - mpbios_cpu((u_int8_t *)&pe, self); + /* + * setup ioapic, base adress is known + * the version number should be 0x10 for default + * configurations > 4 + */ + + if (mp_fps->mpfb1 > 4) + { + default_ioapic. apic_version=0x10; + } + mpbios_ioapic((u_int8_t *)&default_ioapic, self); - /* XXX */ - printf("%s: WARNING: interrupts not configured\n", - self->dv_xname); - panic("lazy bum"); - return; + /* + * determine the numbers of busses depending on the + * config type + */ + + if (mp_fps->mpfb1 != 0) + switch(mp_fps->mpfb1) { + case 1: + case 2: + case 3: + case 4: + mp_nbus = 1; + break; + case 5: + case 6: + case 7: + mp_nbus = 2; + break; + default: + panic("Unknown pre-defined MP Table config type %d", + mp_fps->mpfb1); + } + + mp_busses = malloc(sizeof(struct mp_bus) * mp_nbus, + M_DEVBUF, M_NOWAIT); + + /* setup a bus structure for mpbios_bus, first setup bus 0 */ + + bus.type = MPS_MCT_BUS; + bus.bus_id = 0; + + switch (mp_fps->mpfb1) { + case 1: + case 5: + memcpy(bus.bus_type, "ISA ",6); + break; + case 2: + case 6: + case 3: + memcpy(bus.bus_type, "EISA ", 6); + break; + case 4: + case 7: + memcpy(bus.bus_type, "MCA ", 6); + } + mpbios_bus((u_int8_t *)&bus, self); + + /* + * configuration 4 and higher do have a PCI bus, so the + * PCI bus is always second. + */ + + if (mp_fps->mpfb1 > 4) { + bus.bus_id = 1; + memcpy(bus.bus_type, "PCI ", 6); + mpbios_bus((u_int8_t *)&bus, self); + }; + + /* lets setup the interrupts */ + + mp_intrs = malloc(sizeof(struct mp_intr_map) * 15, M_DEVBUF, + M_NOWAIT); + + mpi.type = MPS_MCT_IOINT; + mpi.int_type = MPS_INTTYPE_INT; + + /* + * according the the specs, PCI interrupts have been mapped + * into the (E)ISA interrupts space. All interrupts should + * be wired to bus 0 + */ + + mpi.src_bus_id = 0; + + /* + * There is only one IOAPIC in the default configurations + */ + + mpi.dst_apic_id = default_ioapic.apic_id; + + /* + * do a quick check to see if the ELCR information is correct + * according to freebsd:src/sys/i386/isa/elcr.c almost all + * PCI systems have an ELCR. Linux only uses ELCR for + * Configuration 5, but my Configuration 6 also needs it. + */ + + if (mp_fps->mpfb1 > 4) { + + if ((ELCR_trigger(0) | ELCR_trigger(1) | ELCR_trigger(2) | + ELCR_trigger(8) | ELCR_trigger(13))) { + printf("%s: ELCR is not available\n", self->dv_xname); + } + else + { + useELCR=1; + printf("%s: Using ELCR to identify PCI IRQ's\n" + ,self->dv_xname); + } + } + + /* + * Configuration 2 should not connect IRQ0 and IRQ13 + * the other configurations should not connect to IRQ2 + */ + for ( i = 0; i<16;i++) { + switch (mp_fps->mpfb1) { + case 2: + if (i== 0 || i == 13) + continue; + default: + if (i == 2) + continue; + + mpi.src_bus_irq = i; + mpi.dst_apic_int = i ? i : 2; + + mpi.int_flags = MPS_INTPO_DEF << 2 | MPS_INTTR_DEF; + + /* + * check if it is a level trigger (1) or an edge + * trigger (0) from elcr.c + * (freebsd:src/sys/i386/isa/elcr.c) + * 'Note that the polarity of ISA and EISA IRQs are + * linked to the trigger mode. All edge triggered + * IRQs use active-hi polarity, and all level + * triggered interrupts use active-lo polarity.' + */ + + if (useELCR && ELCR_trigger(i)) + { + mpi.int_flags = 13; + if(mp_verbose) { + printf("%s: Changing irq %d to level triggered 0x%x\n", + self->dv_xname, i, + mpi.int_flags); + } + } + + mpbios_int((u_int8_t *)&mpi , MPS_MCT_IOINT, + &mp_intrs[i]); + } + } } else { /* * should not happen; mp_probe returns 0 in this case, @@ -1106,3 +1281,4 @@ printf(" (type 0x%x flags 0x%x)\n", type, flags); } } +