[BACK]Return to lapic.c CVS log [TXT][DIR] Up to [local] / sys / arch / amd64 / amd64

Annotation of sys/arch/amd64/amd64/lapic.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: lapic.c,v 1.10 2007/05/25 16:22:11 art Exp $  */
        !             2: /* $NetBSD: lapic.c,v 1.2 2003/05/08 01:04:35 fvdl Exp $ */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 2000 The NetBSD Foundation, Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * This code is derived from software contributed to The NetBSD Foundation
        !             9:  * by RedBack Networks Inc.
        !            10:  *
        !            11:  * Author: Bill Sommerfeld
        !            12:  *
        !            13:  * Redistribution and use in source and binary forms, with or without
        !            14:  * modification, are permitted provided that the following conditions
        !            15:  * are met:
        !            16:  * 1. Redistributions of source code must retain the above copyright
        !            17:  *    notice, this list of conditions and the following disclaimer.
        !            18:  * 2. Redistributions in binary form must reproduce the above copyright
        !            19:  *    notice, this list of conditions and the following disclaimer in the
        !            20:  *    documentation and/or other materials provided with the distribution.
        !            21:  * 3. All advertising materials mentioning features or use of this software
        !            22:  *    must display the following acknowledgement:
        !            23:  *        This product includes software developed by the NetBSD
        !            24:  *        Foundation, Inc. and its contributors.
        !            25:  * 4. Neither the name of The NetBSD Foundation nor the names of its
        !            26:  *    contributors may be used to endorse or promote products derived
        !            27:  *    from this software without specific prior written permission.
        !            28:  *
        !            29:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
        !            30:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            31:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            32:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
        !            33:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
        !            34:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
        !            35:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
        !            36:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
        !            37:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            38:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            39:  * POSSIBILITY OF SUCH DAMAGE.
        !            40:  */
        !            41:
        !            42: #include <sys/param.h>
        !            43: #include <sys/proc.h>
        !            44: #include <sys/user.h>
        !            45: #include <sys/systm.h>
        !            46: #include <sys/device.h>
        !            47:
        !            48: #include <uvm/uvm_extern.h>
        !            49:
        !            50: #include <dev/ic/i8253reg.h>
        !            51:
        !            52: #include <machine/cpu.h>
        !            53: #include <machine/cpufunc.h>
        !            54: #include <machine/cpuvar.h>
        !            55: #include <machine/pmap.h>
        !            56: #include <machine/vmparam.h>
        !            57: #include <machine/mpbiosvar.h>
        !            58: #include <machine/pcb.h>
        !            59: #include <machine/specialreg.h>
        !            60: #include <machine/segments.h>
        !            61:
        !            62: #include <machine/apicvar.h>
        !            63: #include <machine/i82489reg.h>
        !            64: #include <machine/i82489var.h>
        !            65:
        !            66: #include "ioapic.h"
        !            67:
        !            68: #if NIOAPIC > 0
        !            69: #include <machine/i82093var.h>
        !            70: #endif
        !            71:
        !            72: struct evcount clk_count;
        !            73: struct evcount ipi_count;
        !            74:
        !            75: void           lapic_delay(int);
        !            76: void           lapic_microtime(struct timeval *);
        !            77: static u_int32_t lapic_gettick(void);
        !            78: void           lapic_clockintr(void *, struct intrframe);
        !            79: void           lapic_map(paddr_t);
        !            80:
        !            81: void lapic_hwmask(struct pic *, int);
        !            82: void lapic_hwunmask(struct pic *, int);
        !            83: void lapic_setup(struct pic *, struct cpu_info *, int, int, int);
        !            84:
        !            85: extern char idt_allocmap[];
        !            86:
        !            87: struct pic local_pic = {
        !            88:        {0, {NULL}, NULL, 0, "lapic", NULL, 0, 0},
        !            89:        PIC_LAPIC,
        !            90: #ifdef MULTIPROCESSOR
        !            91:        {},
        !            92: #endif
        !            93:        lapic_hwmask,
        !            94:        lapic_hwunmask,
        !            95:        lapic_setup,
        !            96:        lapic_setup,
        !            97: };
        !            98:
        !            99: void
        !           100: lapic_map(paddr_t lapic_base)
        !           101: {
        !           102:        int s;
        !           103:        pt_entry_t *pte;
        !           104:        vaddr_t va = (vaddr_t)&local_apic;
        !           105:
        !           106:        disable_intr();
        !           107:        s = lapic_tpr;
        !           108:
        !           109:        /*
        !           110:         * Map local apic.  If we have a local apic, it's safe to assume
        !           111:         * we're on a 486 or better and can use invlpg and non-cacheable PTE's
        !           112:         *
        !           113:         * Whap the PTE "by hand" rather than calling pmap_kenter_pa because
        !           114:         * the latter will attempt to invoke TLB shootdown code just as we
        !           115:         * might have changed the value of cpu_number()..
        !           116:         */
        !           117:
        !           118:        pte = kvtopte(va);
        !           119:        *pte = lapic_base | PG_RW | PG_V | PG_N | pmap_pg_g;
        !           120:        invlpg(va);
        !           121:
        !           122: #ifdef MULTIPROCESSOR
        !           123:        cpu_init_first();       /* catch up to changed cpu_number() */
        !           124: #endif
        !           125:
        !           126:        lapic_tpr = s;
        !           127:        enable_intr();
        !           128: }
        !           129:
        !           130: /*
        !           131:  * enable local apic
        !           132:  */
        !           133: void
        !           134: lapic_enable(void)
        !           135: {
        !           136:        i82489_writereg(LAPIC_SVR, LAPIC_SVR_ENABLE | LAPIC_SPURIOUS_VECTOR);
        !           137: }
        !           138:
        !           139: void
        !           140: lapic_set_lvt(void)
        !           141: {
        !           142:        struct cpu_info *ci = curcpu();
        !           143:        int i;
        !           144:        struct mp_intr_map *mpi;
        !           145:        uint32_t lint0;
        !           146:
        !           147: #ifdef MULTIPROCESSOR
        !           148:        if (mp_verbose) {
        !           149:                apic_format_redir (ci->ci_dev->dv_xname, "prelint", 0, 0,
        !           150:                    i82489_readreg(LAPIC_LVINT0));
        !           151:                apic_format_redir (ci->ci_dev->dv_xname, "prelint", 1, 0,
        !           152:                    i82489_readreg(LAPIC_LVINT1));
        !           153:        }
        !           154: #endif
        !           155:
        !           156: #if NIOAPIC > 0
        !           157:        /*
        !           158:         * Disable ExtINT by default when using I/O APICs.
        !           159:         */
        !           160:        if (nioapics > 0) {
        !           161:                lint0 = i82489_readreg(LAPIC_LVINT0);
        !           162:                lint0 |= LAPIC_LVT_MASKED;
        !           163:                i82489_writereg(LAPIC_LVINT0, lint0);
        !           164:        }
        !           165: #endif
        !           166:
        !           167:        for (i = 0; i < mp_nintr; i++) {
        !           168:                mpi = &mp_intrs[i];
        !           169:                if (mpi->ioapic == NULL && (mpi->cpu_id == MPS_ALL_APICS
        !           170:                                            || mpi->cpu_id == ci->ci_apicid)) {
        !           171: #ifdef DIAGNOSTIC
        !           172:                        if (mpi->ioapic_pin > 1)
        !           173:                                panic("lapic_set_lvt: bad pin value %d",
        !           174:                                    mpi->ioapic_pin);
        !           175: #endif
        !           176:                        if (mpi->ioapic_pin == 0)
        !           177:                                i82489_writereg(LAPIC_LVINT0, mpi->redir);
        !           178:                        else
        !           179:                                i82489_writereg(LAPIC_LVINT1, mpi->redir);
        !           180:                }
        !           181:        }
        !           182:
        !           183: #ifdef MULTIPROCESSOR
        !           184:        if (mp_verbose) {
        !           185:                apic_format_redir (ci->ci_dev->dv_xname, "timer", 0, 0,
        !           186:                    i82489_readreg(LAPIC_LVTT));
        !           187:                apic_format_redir (ci->ci_dev->dv_xname, "pcint", 0, 0,
        !           188:                    i82489_readreg(LAPIC_PCINT));
        !           189:                apic_format_redir (ci->ci_dev->dv_xname, "lint", 0, 0,
        !           190:                    i82489_readreg(LAPIC_LVINT0));
        !           191:                apic_format_redir (ci->ci_dev->dv_xname, "lint", 1, 0,
        !           192:                    i82489_readreg(LAPIC_LVINT1));
        !           193:                apic_format_redir (ci->ci_dev->dv_xname, "err", 0, 0,
        !           194:                    i82489_readreg(LAPIC_LVERR));
        !           195:        }
        !           196: #endif
        !           197: }
        !           198:
        !           199: /*
        !           200:  * Initialize fixed idt vectors for use by local apic.
        !           201:  */
        !           202: void
        !           203: lapic_boot_init(paddr_t lapic_base)
        !           204: {
        !           205:        static u_int64_t clk_irq = 0;
        !           206:        static u_int64_t ipi_irq = 0;
        !           207:
        !           208:        lapic_map(lapic_base);
        !           209:
        !           210: #ifdef MULTIPROCESSOR
        !           211:        idt_allocmap[LAPIC_IPI_VECTOR] = 1;
        !           212:        idt_vec_set(LAPIC_IPI_VECTOR, Xintr_lapic_ipi);
        !           213:        idt_allocmap[LAPIC_IPI_INVLTLB] = 1;
        !           214:        idt_vec_set(LAPIC_IPI_INVLTLB, Xipi_invltlb);
        !           215:        idt_allocmap[LAPIC_IPI_INVLPG] = 1;
        !           216:        idt_vec_set(LAPIC_IPI_INVLPG, Xipi_invlpg);
        !           217:        idt_allocmap[LAPIC_IPI_INVLRANGE] = 1;
        !           218:        idt_vec_set(LAPIC_IPI_INVLRANGE, Xipi_invlrange);
        !           219: #endif
        !           220:        idt_allocmap[LAPIC_SPURIOUS_VECTOR] = 1;
        !           221:        idt_vec_set(LAPIC_SPURIOUS_VECTOR, Xintrspurious);
        !           222:
        !           223:        idt_allocmap[LAPIC_TIMER_VECTOR] = 1;
        !           224:        idt_vec_set(LAPIC_TIMER_VECTOR, Xintr_lapic_ltimer);
        !           225:
        !           226:        evcount_attach(&clk_count, "clock", (void *)&clk_irq, &evcount_intr);
        !           227:        evcount_attach(&ipi_count, "ipi", (void *)&ipi_irq, &evcount_intr);
        !           228: }
        !           229:
        !           230: static inline u_int32_t
        !           231: lapic_gettick(void)
        !           232: {
        !           233:        return i82489_readreg(LAPIC_CCR_TIMER);
        !           234: }
        !           235:
        !           236: #include <sys/kernel.h>                /* for hz */
        !           237:
        !           238: u_int32_t lapic_tval;
        !           239:
        !           240: /*
        !           241:  * this gets us up to a 4GHz busclock....
        !           242:  */
        !           243: u_int32_t lapic_per_second;
        !           244: u_int32_t lapic_frac_usec_per_cycle;
        !           245: u_int64_t lapic_frac_cycle_per_usec;
        !           246: u_int32_t lapic_delaytab[26];
        !           247:
        !           248: void
        !           249: lapic_clockintr(void *arg, struct intrframe frame)
        !           250: {
        !           251:
        !           252:        hardclock((struct clockframe *)&frame);
        !           253:
        !           254:        clk_count.ec_count++;
        !           255: }
        !           256:
        !           257: void
        !           258: lapic_initclocks(void)
        !           259: {
        !           260:        /*
        !           261:         * Start local apic countdown timer running, in repeated mode.
        !           262:         *
        !           263:         * Mask the clock interrupt and set mode,
        !           264:         * then set divisor,
        !           265:         * then unmask and set the vector.
        !           266:         */
        !           267:        i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_LVTT_M);
        !           268:        i82489_writereg (LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
        !           269:        i82489_writereg (LAPIC_ICR_TIMER, lapic_tval);
        !           270:        i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_TIMER_VECTOR);
        !           271: }
        !           272:
        !           273: extern int gettick(void);      /* XXX put in header file */
        !           274: extern u_long rtclock_tval; /* XXX put in header file */
        !           275: extern void (*initclock_func)(void); /* XXX put in header file */
        !           276:
        !           277: /*
        !           278:  * Calibrate the local apic count-down timer (which is running at
        !           279:  * bus-clock speed) vs. the i8254 counter/timer (which is running at
        !           280:  * a fixed rate).
        !           281:  *
        !           282:  * The Intel MP spec says: "An MP operating system may use the IRQ8
        !           283:  * real-time clock as a reference to determine the actual APIC timer clock
        !           284:  * speed."
        !           285:  *
        !           286:  * We're actually using the IRQ0 timer.  Hmm.
        !           287:  */
        !           288: void
        !           289: lapic_calibrate_timer(struct cpu_info *ci)
        !           290: {
        !           291:        unsigned int starttick, tick1, tick2, endtick;
        !           292:        unsigned int startapic, apic1, apic2, endapic;
        !           293:        u_int64_t dtick, dapic, tmp;
        !           294:        int i;
        !           295:
        !           296:        if (mp_verbose)
        !           297:                printf("%s: calibrating local timer\n", ci->ci_dev->dv_xname);
        !           298:
        !           299:        /*
        !           300:         * Configure timer to one-shot, interrupt masked,
        !           301:         * large positive number.
        !           302:         */
        !           303:        i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_M);
        !           304:        i82489_writereg (LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
        !           305:        i82489_writereg (LAPIC_ICR_TIMER, 0x80000000);
        !           306:
        !           307:        starttick = gettick();
        !           308:        startapic = lapic_gettick();
        !           309:
        !           310:        for (i=0; i<hz; i++) {
        !           311:                DELAY(2);
        !           312:                do {
        !           313:                        tick1 = gettick();
        !           314:                        apic1 = lapic_gettick();
        !           315:                } while (tick1 < starttick);
        !           316:                DELAY(2);
        !           317:                do {
        !           318:                        tick2 = gettick();
        !           319:                        apic2 = lapic_gettick();
        !           320:                } while (tick2 > starttick);
        !           321:        }
        !           322:
        !           323:        endtick = gettick();
        !           324:        endapic = lapic_gettick();
        !           325:
        !           326:        dtick = hz * rtclock_tval + (starttick-endtick);
        !           327:        dapic = startapic-endapic;
        !           328:
        !           329:        /*
        !           330:         * there are TIMER_FREQ ticks per second.
        !           331:         * in dtick ticks, there are dapic bus clocks.
        !           332:         */
        !           333:        tmp = (TIMER_FREQ * dapic) / dtick;
        !           334:
        !           335:        lapic_per_second = tmp;
        !           336:
        !           337:        printf("%s: apic clock running at %lldMHz\n",
        !           338:            ci->ci_dev->dv_xname, tmp / (1000 * 1000));
        !           339:
        !           340:        if (lapic_per_second != 0) {
        !           341:                /*
        !           342:                 * reprogram the apic timer to run in periodic mode.
        !           343:                 * XXX need to program timer on other cpu's, too.
        !           344:                 */
        !           345:                lapic_tval = (lapic_per_second * 2) / hz;
        !           346:                lapic_tval = (lapic_tval / 2) + (lapic_tval & 0x1);
        !           347:
        !           348:                i82489_writereg (LAPIC_LVTT, LAPIC_LVTT_TM|LAPIC_LVTT_M
        !           349:                    |LAPIC_TIMER_VECTOR);
        !           350:                i82489_writereg (LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
        !           351:                i82489_writereg (LAPIC_ICR_TIMER, lapic_tval);
        !           352:
        !           353:                /*
        !           354:                 * Compute fixed-point ratios between cycles and
        !           355:                 * microseconds to avoid having to do any division
        !           356:                 * in lapic_delay and lapic_microtime.
        !           357:                 */
        !           358:
        !           359:                tmp = (1000000 * (u_int64_t)1<<32) / lapic_per_second;
        !           360:                lapic_frac_usec_per_cycle = tmp;
        !           361:
        !           362:                tmp = (lapic_per_second * (u_int64_t)1<<32) / 1000000;
        !           363:
        !           364:                lapic_frac_cycle_per_usec = tmp;
        !           365:
        !           366:                /*
        !           367:                 * Compute delay in cycles for likely short delays in usec.
        !           368:                 */
        !           369:                for (i=0; i<26; i++)
        !           370:                        lapic_delaytab[i] = (lapic_frac_cycle_per_usec * i) >>
        !           371:                            32;
        !           372:
        !           373:                /*
        !           374:                 * Now that the timer's calibrated, use the apic timer routines
        !           375:                 * for all our timing needs..
        !           376:                 */
        !           377:                delay_func = lapic_delay;
        !           378:                initclock_func = lapic_initclocks;
        !           379:        }
        !           380: }
        !           381:
        !           382: /*
        !           383:  * delay for N usec.
        !           384:  */
        !           385:
        !           386: void
        !           387: lapic_delay(int usec)
        !           388: {
        !           389:        int32_t tick, otick;
        !           390:        int64_t deltat;         /* XXX may want to be 64bit */
        !           391:
        !           392:        otick = lapic_gettick();
        !           393:
        !           394:        if (usec <= 0)
        !           395:                return;
        !           396:        if (usec <= 25)
        !           397:                deltat = lapic_delaytab[usec];
        !           398:        else
        !           399:                deltat = (lapic_frac_cycle_per_usec * usec) >> 32;
        !           400:
        !           401:        while (deltat > 0) {
        !           402:                tick = lapic_gettick();
        !           403:                if (tick > otick)
        !           404:                        deltat -= lapic_tval - (tick - otick);
        !           405:                else
        !           406:                        deltat -= otick - tick;
        !           407:                otick = tick;
        !           408:
        !           409:                x86_pause();
        !           410:        }
        !           411: }
        !           412:
        !           413: /*
        !           414:  * XXX the following belong mostly or partly elsewhere..
        !           415:  */
        !           416:
        !           417: static __inline void i82489_icr_wait(void);
        !           418:
        !           419: static __inline void
        !           420: i82489_icr_wait(void)
        !           421: {
        !           422: #ifdef DIAGNOSTIC
        !           423:        unsigned j = 100000;
        !           424: #endif /* DIAGNOSTIC */
        !           425:
        !           426:        while ((i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) != 0) {
        !           427:                x86_pause();
        !           428: #ifdef DIAGNOSTIC
        !           429:                j--;
        !           430:                if (j == 0)
        !           431:                        panic("i82489_icr_wait: busy");
        !           432: #endif /* DIAGNOSTIC */
        !           433:        }
        !           434: }
        !           435:
        !           436: int
        !           437: x86_ipi_init(int target)
        !           438: {
        !           439:
        !           440:        if ((target&LAPIC_DEST_MASK)==0) {
        !           441:                i82489_writereg(LAPIC_ICRHI, target<<LAPIC_ID_SHIFT);
        !           442:        }
        !           443:
        !           444:        i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) |
        !           445:            LAPIC_DLMODE_INIT | LAPIC_LVL_ASSERT );
        !           446:
        !           447:        i82489_icr_wait();
        !           448:
        !           449:        delay(10000);
        !           450:
        !           451:        i82489_writereg(LAPIC_ICRLO, (target & LAPIC_DEST_MASK) |
        !           452:             LAPIC_DLMODE_INIT | LAPIC_LVL_TRIG | LAPIC_LVL_DEASSERT);
        !           453:
        !           454:        i82489_icr_wait();
        !           455:
        !           456:        return (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY)?EBUSY:0;
        !           457: }
        !           458:
        !           459: int
        !           460: x86_ipi(int vec, int target, int dl)
        !           461: {
        !           462:        int result, s;
        !           463:
        !           464:        s = splclock();
        !           465:
        !           466:        i82489_icr_wait();
        !           467:
        !           468:        if ((target & LAPIC_DEST_MASK) == 0)
        !           469:                i82489_writereg(LAPIC_ICRHI, target << LAPIC_ID_SHIFT);
        !           470:
        !           471:        i82489_writereg(LAPIC_ICRLO,
        !           472:            (target & LAPIC_DEST_MASK) | vec | dl | LAPIC_LVL_ASSERT);
        !           473:
        !           474:        i82489_icr_wait();
        !           475:
        !           476:        result = (i82489_readreg(LAPIC_ICRLO) & LAPIC_DLSTAT_BUSY) ? EBUSY : 0;
        !           477:
        !           478:        splx(s);
        !           479:
        !           480:        return result;
        !           481: }
        !           482:
        !           483:
        !           484: /*
        !           485:  * Using 'pin numbers' as:
        !           486:  * 0 - timer
        !           487:  * 1 - unused
        !           488:  * 2 - PCINT
        !           489:  * 3 - LVINT0
        !           490:  * 4 - LVINT1
        !           491:  * 5 - LVERR
        !           492:  */
        !           493:
        !           494: void
        !           495: lapic_hwmask(struct pic *pic, int pin)
        !           496: {
        !           497:        int reg;
        !           498:        u_int32_t val;
        !           499:
        !           500:        reg = LAPIC_LVTT + (pin << 4);
        !           501:        val = i82489_readreg(reg);
        !           502:        val |= LAPIC_LVT_MASKED;
        !           503:        i82489_writereg(reg, val);
        !           504: }
        !           505:
        !           506: void
        !           507: lapic_hwunmask(struct pic *pic, int pin)
        !           508: {
        !           509:        int reg;
        !           510:        u_int32_t val;
        !           511:
        !           512:        reg = LAPIC_LVTT + (pin << 4);
        !           513:        val = i82489_readreg(reg);
        !           514:        val &= ~LAPIC_LVT_MASKED;
        !           515:        i82489_writereg(reg, val);
        !           516: }
        !           517:
        !           518: void
        !           519: lapic_setup(struct pic *pic, struct cpu_info *ci, int pin, int idtvec, int type)
        !           520: {
        !           521: }

CVSweb