[BACK]Return to cpu_subr.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / mips / mips

Annotation of src/sys/arch/mips/mips/cpu_subr.c, Revision 1.27

1.27    ! matt        1: /*     $NetBSD: cpu_subr.c,v 1.26 2015/06/11 15:50:17 matt Exp $       */
1.3       rmind       2:
1.2       matt        3: /*-
                      4:  * Copyright (c) 2010 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Matt Thomas of 3am Software Foundry.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: #include <sys/cdefs.h>
1.27    ! matt       33: __KERNEL_RCSID(0, "$NetBSD: cpu_subr.c,v 1.26 2015/06/11 15:50:17 matt Exp $");
1.2       matt       34:
1.27    ! matt       35: #include "opt_ddb.h"
1.21      matt       36: #include "opt_cputype.h"
1.27    ! matt       37: #include "opt_modular.h"
1.2       matt       38: #include "opt_multiprocessor.h"
                     39:
                     40: #include <sys/param.h>
                     41: #include <sys/cpu.h>
                     42: #include <sys/intr.h>
                     43: #include <sys/atomic.h>
                     44: #include <sys/device.h>
                     45: #include <sys/lwp.h>
                     46: #include <sys/proc.h>
                     47: #include <sys/ras.h>
1.27    ! matt       48: #include <sys/module.h>
1.2       matt       49: #include <sys/bitops.h>
                     50: #include <sys/idle.h>
                     51: #include <sys/xcall.h>
1.24      matt       52: #include <sys/kernel.h>
1.17      rmind      53: #include <sys/ipi.h>
1.2       matt       54:
                     55: #include <uvm/uvm.h>
                     56:
                     57: #include <mips/locore.h>
                     58: #include <mips/regnum.h>
                     59: #include <mips/pcb.h>
                     60: #include <mips/cache.h>
                     61: #include <mips/frame.h>
                     62: #include <mips/userret.h>
                     63: #include <mips/pte.h>
                     64:
                     65: #if defined(DDB) || defined(KGDB)
                     66: #ifdef DDB
                     67: #include <mips/db_machdep.h>
                     68: #include <ddb/db_command.h>
                     69: #include <ddb/db_output.h>
                     70: #endif
                     71: #endif
                     72:
1.20      matt       73: #ifdef MIPS64_OCTEON
                     74: extern struct cpu_softc octeon_cpu0_softc;
                     75: #endif
                     76:
1.2       matt       77: struct cpu_info cpu_info_store
1.20      matt       78: #if defined(MULTIPROCESSOR) && !defined(MIPS64_OCTEON)
1.2       matt       79:        __section(".data1")
                     80:        __aligned(1LU << ilog2((2*sizeof(struct cpu_info)-1)))
                     81: #endif
                     82:     = {
                     83:        .ci_curlwp = &lwp0,
                     84:        .ci_tlb_info = &pmap_tlb0_info,
1.27    ! matt       85:        .ci_pmap_kern_segtab = &pmap_kern_segtab,
        !            86:        .ci_pmap_user_segtab = NULL,
1.2       matt       87: #ifdef _LP64
1.27    ! matt       88:        .ci_pmap_user_seg0tab = NULL,
1.2       matt       89: #endif
                     90:        .ci_cpl = IPL_HIGH,
                     91:        .ci_tlb_slot = -1,
                     92: #ifdef MULTIPROCESSOR
                     93:        .ci_flags = CPUF_PRIMARY|CPUF_PRESENT|CPUF_RUNNING,
                     94: #endif
1.20      matt       95: #ifdef MIPS64_OCTEON
                     96:        .ci_softc = &octeon_cpu0_softc,
                     97: #endif
1.2       matt       98: };
                     99:
1.14      matt      100: const pcu_ops_t * const pcu_ops_md_defs[PCU_UNIT_COUNT] = {
                    101:        [PCU_FPU] = &mips_fpu_ops,
                    102: #if (MIPS32R2 + MIPS64R2) > 0
                    103:        [PCU_DSP] = &mips_dsp_ops,
                    104: #endif
                    105: };
                    106:
1.2       matt      107: #ifdef MULTIPROCESSOR
1.20      matt      108: struct cpu_info * cpuid_infos[MAXCPUS] = {
                    109:        [0] = &cpu_info_store,
                    110: };
1.2       matt      111:
1.24      matt      112: kcpuset_t *cpus_halted;
                    113: kcpuset_t *cpus_hatched;
                    114: kcpuset_t *cpus_paused;
                    115: kcpuset_t *cpus_resumed;
                    116: kcpuset_t *cpus_running;
1.2       matt      117:
1.24      matt      118: static void cpu_ipi_wait(const char *, const kcpuset_t *, const kcpuset_t *);
1.2       matt      119:
                    120: struct cpu_info *
1.6       matt      121: cpu_info_alloc(struct pmap_tlb_info *ti, cpuid_t cpu_id, cpuid_t cpu_package_id,
1.2       matt      122:        cpuid_t cpu_core_id, cpuid_t cpu_smt_id)
                    123: {
1.20      matt      124:        KASSERT(cpu_id < MAXCPUS);
                    125:
1.21      matt      126: #ifdef MIPS64_OCTEON
1.20      matt      127:        vaddr_t exc_page = MIPS_UTLB_MISS_EXC_VEC + 0x1000*cpu_id;
1.23      matt      128:        __CTASSERT(sizeof(struct cpu_info) + sizeof(struct pmap_tlb_info) <= 0x1000 - 0x280);
1.20      matt      129:
1.23      matt      130:        struct cpu_info * const ci = ((struct cpu_info *)(exc_page + 0x1000)) - 1;
1.21      matt      131:        memset((void *)exc_page, 0, PAGE_SIZE);
1.20      matt      132:
                    133:        if (ti == NULL) {
                    134:                ti = ((struct pmap_tlb_info *)ci) - 1;
                    135:                pmap_tlb_info_init(ti);
                    136:        }
                    137: #else
                    138:        const vaddr_t cpu_info_offset = (vaddr_t)&cpu_info_store & PAGE_MASK;
1.21      matt      139:        struct pglist pglist;
                    140:        int error;
1.20      matt      141:
1.2       matt      142:        /*
                    143:        * Grab a page from the first 512MB (mappable by KSEG0) to use to store
                    144:        * exception vectors and cpu_info for this cpu.
                    145:        */
                    146:        error = uvm_pglistalloc(PAGE_SIZE,
                    147:            0, MIPS_KSEG1_START - MIPS_KSEG0_START,
                    148:            PAGE_SIZE, PAGE_SIZE, &pglist, 1, false);
                    149:        if (error)
                    150:                return NULL;
                    151:
                    152:        const paddr_t pa = VM_PAGE_TO_PHYS(TAILQ_FIRST(&pglist));
                    153:        const vaddr_t va = MIPS_PHYS_TO_KSEG0(pa);
                    154:        struct cpu_info * const ci = (void *) (va + cpu_info_offset);
                    155:        memset((void *)va, 0, PAGE_SIZE);
                    156:
                    157:        /*
                    158:         * If we weren't passed a pmap_tlb_info to use, the caller wants us
                    159:         * to take care of that for him.  Since we have room left over in the
                    160:         * page we just allocated, just use a piece of that for it.
                    161:         */
                    162:        if (ti == NULL) {
                    163:                if (cpu_info_offset >= sizeof(*ti)) {
                    164:                        ti = (void *) va;
                    165:                } else {
                    166:                        KASSERT(PAGE_SIZE - cpu_info_offset + sizeof(*ci) >= sizeof(*ti));
                    167:                        ti = (struct pmap_tlb_info *)(va + PAGE_SIZE) - 1;
                    168:                }
                    169:                pmap_tlb_info_init(ti);
                    170:        }
                    171:
1.20      matt      172:        /*
                    173:         * Attach its TLB info (which must be direct-mapped)
                    174:         */
                    175: #ifdef _LP64
                    176:        KASSERT(MIPS_KSEG0_P(ti) || MIPS_XKPHYS_P(ti));
                    177: #else
                    178:        KASSERT(MIPS_KSEG0_P(ti));
                    179: #endif
                    180: #endif /* MIPS64_OCTEON */
                    181:
1.21      matt      182:        KASSERT(cpu_id != 0);
1.2       matt      183:        ci->ci_cpuid = cpu_id;
1.6       matt      184:        ci->ci_data.cpu_package_id = cpu_package_id;
1.2       matt      185:        ci->ci_data.cpu_core_id = cpu_core_id;
                    186:        ci->ci_data.cpu_smt_id = cpu_smt_id;
                    187:        ci->ci_cpu_freq = cpu_info_store.ci_cpu_freq;
                    188:        ci->ci_cctr_freq = cpu_info_store.ci_cctr_freq;
                    189:         ci->ci_cycles_per_hz = cpu_info_store.ci_cycles_per_hz;
                    190:         ci->ci_divisor_delay = cpu_info_store.ci_divisor_delay;
                    191:         ci->ci_divisor_recip = cpu_info_store.ci_divisor_recip;
1.11      matt      192:        ci->ci_cpuwatch_count = cpu_info_store.ci_cpuwatch_count;
1.2       matt      193:
1.27    ! matt      194:        pmap_md_alloc_ephemeral_address_space(ci);
1.2       matt      195:
                    196:        mi_cpu_attach(ci);
                    197:
                    198:        pmap_tlb_info_attach(ti, ci);
                    199:
                    200:        return ci;
                    201: }
                    202: #endif /* MULTIPROCESSOR */
                    203:
1.5       matt      204: static void
                    205: cpu_hwrena_setup(void)
                    206: {
                    207: #if (MIPS32R2 + MIPS64R2) > 0
                    208:        const int cp0flags = mips_options.mips_cpu->cpu_cp0flags;
                    209:        if ((cp0flags & MIPS_CP0FL_USE) == 0)
                    210:                return;
                    211:
                    212:        if (cp0flags & MIPS_CP0FL_HWRENA) {
                    213:                mipsNN_cp0_hwrena_write(
                    214:                    MIPS_HWRENA_UL
                    215:                    |MIPS_HWRENA_CCRES
                    216:                    |MIPS_HWRENA_CC
                    217:                    |MIPS_HWRENA_SYNCI_STEP
                    218:                    |MIPS_HWRENA_CPUNUM);
                    219:                if (cp0flags & MIPS_CP0FL_USERLOCAL) {
                    220:                        mipsNN_cp0_userlocal_write(curlwp->l_private);
                    221:                }
                    222:        }
                    223: #endif
                    224: }
                    225:
1.2       matt      226: void
                    227: cpu_attach_common(device_t self, struct cpu_info *ci)
                    228: {
1.6       matt      229:        const char * const xname = device_xname(self);
                    230:
1.2       matt      231:        /*
                    232:         * Cross link cpu_info and its device together
                    233:         */
                    234:        ci->ci_dev = self;
                    235:        self->dv_private = ci;
                    236:        KASSERT(ci->ci_idepth == 0);
                    237:
                    238:        evcnt_attach_dynamic(&ci->ci_ev_count_compare,
1.6       matt      239:                EVCNT_TYPE_INTR, NULL, xname,
1.2       matt      240:                "int 5 (clock)");
                    241:        evcnt_attach_dynamic(&ci->ci_ev_count_compare_missed,
1.6       matt      242:                EVCNT_TYPE_INTR, NULL, xname,
1.2       matt      243:                "int 5 (clock) missed");
                    244:        evcnt_attach_dynamic(&ci->ci_ev_fpu_loads,
1.6       matt      245:                EVCNT_TYPE_MISC, NULL, xname,
1.2       matt      246:                "fpu loads");
                    247:        evcnt_attach_dynamic(&ci->ci_ev_fpu_saves,
1.6       matt      248:                EVCNT_TYPE_MISC, NULL, xname,
1.2       matt      249:                "fpu saves");
1.14      matt      250:        evcnt_attach_dynamic(&ci->ci_ev_dsp_loads,
                    251:                EVCNT_TYPE_MISC, NULL, xname,
                    252:                "dsp loads");
                    253:        evcnt_attach_dynamic(&ci->ci_ev_dsp_saves,
                    254:                EVCNT_TYPE_MISC, NULL, xname,
                    255:                "dsp saves");
1.2       matt      256:        evcnt_attach_dynamic(&ci->ci_ev_tlbmisses,
1.6       matt      257:                EVCNT_TYPE_TRAP, NULL, xname,
1.2       matt      258:                "tlb misses");
                    259:
                    260: #ifdef MULTIPROCESSOR
                    261:        if (ci != &cpu_info_store) {
                    262:                /*
                    263:                 * Tail insert this onto the list of cpu_info's.
                    264:                 */
1.20      matt      265:                KASSERT(cpuid_infos[ci->ci_cpuid] == NULL);
                    266:                cpuid_infos[ci->ci_cpuid] = ci;
                    267:                membar_producer();
1.2       matt      268:        }
1.21      matt      269:        KASSERT(cpuid_infos[ci->ci_cpuid] != NULL);
1.2       matt      270:        evcnt_attach_dynamic(&ci->ci_evcnt_synci_activate_rqst,
1.6       matt      271:            EVCNT_TYPE_MISC, NULL, xname,
1.2       matt      272:            "syncicache activate request");
                    273:        evcnt_attach_dynamic(&ci->ci_evcnt_synci_deferred_rqst,
1.6       matt      274:            EVCNT_TYPE_MISC, NULL, xname,
1.2       matt      275:            "syncicache deferred request");
                    276:        evcnt_attach_dynamic(&ci->ci_evcnt_synci_ipi_rqst,
1.6       matt      277:            EVCNT_TYPE_MISC, NULL, xname,
1.2       matt      278:            "syncicache ipi request");
                    279:        evcnt_attach_dynamic(&ci->ci_evcnt_synci_onproc_rqst,
1.6       matt      280:            EVCNT_TYPE_MISC, NULL, xname,
1.2       matt      281:            "syncicache onproc request");
                    282:
                    283:        /*
                    284:         * Initialize IPI framework for this cpu instance
                    285:         */
                    286:        ipi_init(ci);
                    287: #endif
                    288: }
                    289:
                    290: void
                    291: cpu_startup_common(void)
                    292: {
                    293:        vaddr_t minaddr, maxaddr;
                    294:        char pbuf[9];   /* "99999 MB" */
                    295:
                    296:        pmap_tlb_info_evcnt_attach(&pmap_tlb0_info);
                    297:
1.24      matt      298: #ifdef MULTIPROCESSOR
                    299:        kcpuset_create(&cpus_halted, true);
                    300:                KASSERT(cpus_halted != NULL);
                    301:        kcpuset_create(&cpus_hatched, true);
                    302:                KASSERT(cpus_hatched != NULL);
                    303:        kcpuset_create(&cpus_paused, true);
                    304:                KASSERT(cpus_paused != NULL);
                    305:        kcpuset_create(&cpus_resumed, true);
                    306:                KASSERT(cpus_resumed != NULL);
                    307:        kcpuset_create(&cpus_running, true);
                    308:                KASSERT(cpus_running != NULL);
                    309:        kcpuset_set(cpus_hatched, cpu_number());
                    310:        kcpuset_set(cpus_running, cpu_number());
                    311: #endif
                    312:
1.5       matt      313:        cpu_hwrena_setup();
                    314:
1.2       matt      315:        /*
                    316:         * Good {morning,afternoon,evening,night}.
                    317:         */
                    318:        printf("%s%s", copyright, version);
1.18      matt      319:        printf("%s\n", cpu_getmodel());
1.2       matt      320:        format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
                    321:        printf("total memory = %s\n", pbuf);
                    322:
                    323:        minaddr = 0;
                    324:        /*
                    325:         * Allocate a submap for physio.
                    326:         */
                    327:        phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
                    328:                                    VM_PHYS_SIZE, 0, FALSE, NULL);
                    329:
                    330:        /*
                    331:         * (No need to allocate an mbuf cluster submap.  Mbuf clusters
                    332:         * are allocated via the pool allocator, and we use KSEG/XKPHYS to
                    333:         * map those pages.)
                    334:         */
                    335:
                    336:        format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free));
                    337:        printf("avail memory = %s\n", pbuf);
1.27    ! matt      338:
        !           339: #if defined(__mips_n32)
        !           340:        module_machine = "mips-n32";
        !           341: #endif
1.2       matt      342: }
                    343:
                    344: void
                    345: cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
                    346: {
                    347:        const struct trapframe *tf = l->l_md.md_utf;
                    348:        __greg_t *gr = mcp->__gregs;
                    349:        __greg_t ras_pc;
                    350:
                    351:        /* Save register context. Dont copy R0 - it is always 0 */
                    352:        memcpy(&gr[_REG_AT], &tf->tf_regs[_R_AST], sizeof(mips_reg_t) * 31);
                    353:
                    354:        gr[_REG_MDLO]  = tf->tf_regs[_R_MULLO];
                    355:        gr[_REG_MDHI]  = tf->tf_regs[_R_MULHI];
                    356:        gr[_REG_CAUSE] = tf->tf_regs[_R_CAUSE];
                    357:        gr[_REG_EPC]   = tf->tf_regs[_R_PC];
                    358:        gr[_REG_SR]    = tf->tf_regs[_R_SR];
1.6       matt      359:        mcp->_mc_tlsbase = (intptr_t)l->l_private;
1.2       matt      360:
                    361:        if ((ras_pc = (intptr_t)ras_lookup(l->l_proc,
                    362:            (void *) (intptr_t)gr[_REG_EPC])) != -1)
                    363:                gr[_REG_EPC] = ras_pc;
                    364:
1.6       matt      365:        *flags |= _UC_CPU | _UC_TLSBASE;
1.4       joerg     366:
1.2       matt      367:        /* Save floating point register context, if any. */
1.13      rmind     368:        KASSERT(l == curlwp);
                    369:        if (fpu_used_p()) {
1.2       matt      370:                size_t fplen;
                    371:                /*
                    372:                 * If this process is the current FP owner, dump its
                    373:                 * context to the PCB first.
                    374:                 */
                    375:                fpu_save();
                    376:
                    377:                /*
                    378:                 * The PCB FP regs struct includes the FP CSR, so use the
                    379:                 * size of __fpregs.__fp_r when copying.
                    380:                 */
                    381: #if !defined(__mips_o32)
                    382:                if (_MIPS_SIM_NEWABI_P(l->l_proc->p_md.md_abi)) {
                    383: #endif
                    384:                        fplen = sizeof(struct fpreg);
                    385: #if !defined(__mips_o32)
                    386:                } else {
                    387:                        fplen = sizeof(struct fpreg_oabi);
                    388:                }
                    389: #endif
                    390:                struct pcb * const pcb = lwp_getpcb(l);
                    391:                memcpy(&mcp->__fpregs, &pcb->pcb_fpregs, fplen);
                    392:                *flags |= _UC_FPU;
                    393:        }
                    394: }
                    395:
                    396: int
1.16      martin    397: cpu_mcontext_validate(struct lwp *l, const mcontext_t *mcp)
                    398: {
                    399:        /* XXX:  Do we validate the addresses?? */
                    400:        return 0;
                    401: }
                    402:
                    403: int
1.2       matt      404: cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
                    405: {
                    406:        struct trapframe *tf = l->l_md.md_utf;
                    407:        struct proc *p = l->l_proc;
                    408:        const __greg_t *gr = mcp->__gregs;
1.16      martin    409:        int error;
1.2       matt      410:
                    411:        /* Restore register context, if any. */
                    412:        if (flags & _UC_CPU) {
1.16      martin    413:                error = cpu_mcontext_validate(l, mcp);
                    414:                if (error)
                    415:                        return error;
                    416:
1.2       matt      417:                /* Save register context. */
1.16      martin    418:
1.2       matt      419: #ifdef __mips_n32
                    420:                CTASSERT(_R_AST == _REG_AT);
                    421:                if (__predict_false(p->p_md.md_abi == _MIPS_BSD_API_O32)) {
                    422:                        const mcontext_o32_t *mcp32 = (const mcontext_o32_t *)mcp;
                    423:                        const __greg32_t *gr32 = mcp32->__gregs;
                    424:                        for (size_t i = _R_AST; i < 32; i++) {
                    425:                                tf->tf_regs[i] = gr32[i];
                    426:                        }
                    427:                } else
                    428: #endif
                    429:                memcpy(&tf->tf_regs[_R_AST], &gr[_REG_AT],
                    430:                       sizeof(mips_reg_t) * 31);
                    431:
                    432:                tf->tf_regs[_R_MULLO] = gr[_REG_MDLO];
                    433:                tf->tf_regs[_R_MULHI] = gr[_REG_MDHI];
                    434:                tf->tf_regs[_R_CAUSE] = gr[_REG_CAUSE];
                    435:                tf->tf_regs[_R_PC]    = gr[_REG_EPC];
                    436:                /* Do not restore SR. */
                    437:        }
                    438:
1.6       matt      439:        /* Restore the private thread context */
                    440:        if (flags & _UC_TLSBASE) {
                    441:                lwp_setprivate(l, (void *)(intptr_t)mcp->_mc_tlsbase);
                    442:        }
                    443:
1.2       matt      444:        /* Restore floating point register context, if any. */
                    445:        if (flags & _UC_FPU) {
                    446:                size_t fplen;
                    447:
                    448:                /* Disable the FPU contents. */
                    449:                fpu_discard();
                    450:
                    451: #if !defined(__mips_o32)
                    452:                if (_MIPS_SIM_NEWABI_P(l->l_proc->p_md.md_abi)) {
                    453: #endif
                    454:                        fplen = sizeof(struct fpreg);
                    455: #if !defined(__mips_o32)
                    456:                } else {
                    457:                        fplen = sizeof(struct fpreg_oabi);
                    458:                }
                    459: #endif
                    460:                /*
                    461:                 * The PCB FP regs struct includes the FP CSR, so use the
                    462:                 * proper size of fpreg when copying.
                    463:                 */
                    464:                struct pcb * const pcb = lwp_getpcb(l);
                    465:                memcpy(&pcb->pcb_fpregs, &mcp->__fpregs, fplen);
                    466:        }
                    467:
                    468:        mutex_enter(p->p_lock);
                    469:        if (flags & _UC_SETSTACK)
                    470:                l->l_sigstk.ss_flags |= SS_ONSTACK;
                    471:        if (flags & _UC_CLRSTACK)
                    472:                l->l_sigstk.ss_flags &= ~SS_ONSTACK;
                    473:        mutex_exit(p->p_lock);
                    474:
                    475:        return (0);
                    476: }
                    477:
                    478: void
                    479: cpu_need_resched(struct cpu_info *ci, int flags)
                    480: {
                    481:        struct lwp * const l = ci->ci_data.cpu_onproc;
                    482: #ifdef MULTIPROCESSOR
                    483:        struct cpu_info * const cur_ci = curcpu();
                    484: #endif
                    485:
                    486:        KASSERT(kpreempt_disabled());
                    487:
                    488:        ci->ci_want_resched |= flags;
                    489:
                    490:        if (__predict_false((l->l_pflag & LP_INTR) != 0)) {
                    491:                /*
                    492:                 * No point doing anything, it will switch soon.
                    493:                 * Also here to prevent an assertion failure in
                    494:                 * kpreempt() due to preemption being set on a
                    495:                 * soft interrupt LWP.
                    496:                 */
                    497:                return;
                    498:        }
                    499:
                    500:        if (__predict_false(l == ci->ci_data.cpu_idlelwp)) {
                    501: #ifdef MULTIPROCESSOR
                    502:                /*
                    503:                 * If the other CPU is idling, it must be waiting for an
                    504:                 * interrupt.  So give it one.
                    505:                 */
                    506:                if (__predict_false(ci != cur_ci))
                    507:                        cpu_send_ipi(ci, IPI_NOP);
                    508: #endif
                    509:                return;
                    510:        }
                    511:
                    512: #ifdef MULTIPROCESSOR
                    513:        atomic_or_uint(&ci->ci_want_resched, flags);
                    514: #else
                    515:        ci->ci_want_resched |= flags;
                    516: #endif
                    517:
                    518:        if (flags & RESCHED_KPREEMPT) {
                    519: #ifdef __HAVE_PREEMPTION
                    520:                atomic_or_uint(&l->l_dopreempt, DOPREEMPT_ACTIVE);
                    521:                if (ci == cur_ci) {
                    522:                        softint_trigger(SOFTINT_KPREEMPT);
                    523:                 } else {
                    524:                         cpu_send_ipi(ci, IPI_KPREEMPT);
                    525:                 }
                    526: #endif
                    527:                return;
                    528:        }
                    529:        l->l_md.md_astpending = 1;              /* force call to ast() */
                    530: #ifdef MULTIPROCESSOR
                    531:        if (ci != cur_ci && (flags & RESCHED_IMMED)) {
                    532:                cpu_send_ipi(ci, IPI_AST);
                    533:        }
                    534: #endif
                    535: }
                    536:
1.27    ! matt      537: uint32_t
        !           538: cpu_clkf_usermode_mask(void)
        !           539: {
        !           540:        return CPUISMIPS3 ? MIPS_SR_KSU_USER : MIPS_SR_KU_PREV;
        !           541: }
        !           542:
1.2       matt      543: void
                    544: cpu_signotify(struct lwp *l)
                    545: {
                    546:        KASSERT(kpreempt_disabled());
                    547: #ifdef __HAVE_FAST_SOFTINTS
                    548:        KASSERT(lwp_locked(l, NULL));
                    549: #endif
                    550:        KASSERT(l->l_stat == LSONPROC || l->l_stat == LSRUN || l->l_stat == LSSTOP);
                    551:
                    552:        l->l_md.md_astpending = 1;              /* force call to ast() */
                    553: }
                    554:
                    555: void
                    556: cpu_need_proftick(struct lwp *l)
                    557: {
                    558:        KASSERT(kpreempt_disabled());
                    559:        KASSERT(l->l_cpu == curcpu());
                    560:
                    561:        l->l_pflag |= LP_OWEUPC;
                    562:        l->l_md.md_astpending = 1;              /* force call to ast() */
                    563: }
                    564:
                    565: void
                    566: cpu_set_curpri(int pri)
                    567: {
                    568:        kpreempt_disable();
                    569:        curcpu()->ci_schedstate.spc_curpriority = pri;
                    570:        kpreempt_enable();
                    571: }
                    572:
                    573:
                    574: #ifdef __HAVE_PREEMPTION
                    575: bool
                    576: cpu_kpreempt_enter(uintptr_t where, int s)
                    577: {
                    578:         KASSERT(kpreempt_disabled());
                    579:
                    580: #if 0
                    581:        if (where == (intptr_t)-2) {
                    582:                KASSERT(curcpu()->ci_mtx_count == 0);
                    583:                /*
                    584:                 * We must be called via kern_intr (which already checks for
                    585:                 * IPL_NONE so of course we call be preempted).
                    586:                 */
                    587:                return true;
                    588:        }
                    589:        /*
                    590:         * We are called from KPREEMPT_ENABLE().  If we are at IPL_NONE,
                    591:         * of course we can be preempted.  If we aren't, ask for a
                    592:         * softint so that kern_intr can call kpreempt.
                    593:         */
                    594:        if (s == IPL_NONE) {
                    595:                KASSERT(curcpu()->ci_mtx_count == 0);
                    596:                return true;
                    597:        }
                    598:        softint_trigger(SOFTINT_KPREEMPT);
                    599: #endif
                    600:        return false;
                    601: }
                    602:
                    603: void
                    604: cpu_kpreempt_exit(uintptr_t where)
                    605: {
                    606:
                    607:        /* do nothing */
                    608: }
                    609:
                    610: /*
                    611:  * Return true if preemption is disabled for MD reasons.  Must be called
                    612:  * with preemption disabled, and thus is only for diagnostic checks.
                    613:  */
                    614: bool
                    615: cpu_kpreempt_disabled(void)
                    616: {
                    617:        /*
                    618:         * Any elevated IPL disables preemption.
                    619:         */
                    620:        return curcpu()->ci_cpl > IPL_NONE;
                    621: }
                    622: #endif /* __HAVE_PREEMPTION */
                    623:
                    624: void
                    625: cpu_idle(void)
                    626: {
                    627:        void (*const mach_idle)(void) = mips_locoresw.lsw_cpu_idle;
                    628:        struct cpu_info * const ci = curcpu();
                    629:
                    630:        while (!ci->ci_want_resched) {
                    631: #ifdef __HAVE_FAST_SOFTINTS
                    632:                KASSERT(ci->ci_data.cpu_softints == 0);
                    633: #endif
                    634:                (*mach_idle)();
                    635:        }
                    636: }
                    637:
                    638: bool
                    639: cpu_intr_p(void)
                    640: {
                    641:        bool rv;
                    642:        kpreempt_disable();
                    643:        rv = (curcpu()->ci_idepth != 0);
                    644:        kpreempt_enable();
                    645:        return rv;
                    646: }
                    647:
                    648: #ifdef MULTIPROCESSOR
                    649:
                    650: void
                    651: cpu_broadcast_ipi(int tag)
                    652: {
1.24      matt      653:        // No reason to remove ourselves since multicast_ipi will do that for us
                    654:        cpu_multicast_ipi(cpus_running, tag);
1.2       matt      655: }
                    656:
                    657: void
1.24      matt      658: cpu_multicast_ipi(const kcpuset_t *kcp, int tag)
1.2       matt      659: {
1.24      matt      660:        struct cpu_info * const ci = curcpu();
                    661:        kcpuset_t *kcp2;
1.2       matt      662:
1.24      matt      663:        if (kcpuset_match(cpus_running, ci->ci_data.cpu_kcpuset))
1.2       matt      664:                return;
                    665:
1.24      matt      666:        kcpuset_clone(&kcp2, kcp);
                    667:        kcpuset_remove(kcp2, ci->ci_data.cpu_kcpuset);
                    668:        for (cpuid_t cii; (cii = kcpuset_ffs(kcp2)) != 0; ) {
                    669:                kcpuset_clear(kcp2, --cii);
                    670:                (void)cpu_send_ipi(cpu_lookup(cii), tag);
1.2       matt      671:        }
1.24      matt      672:        kcpuset_destroy(kcp2);
1.2       matt      673: }
                    674:
                    675: int
                    676: cpu_send_ipi(struct cpu_info *ci, int tag)
                    677: {
                    678:
                    679:        return (*mips_locoresw.lsw_send_ipi)(ci, tag);
                    680: }
                    681:
                    682: static void
1.24      matt      683: cpu_ipi_wait(const char *s, const kcpuset_t *watchset, const kcpuset_t *wanted)
1.2       matt      684: {
1.24      matt      685:        bool done = false;
                    686:        kcpuset_t *kcp;
                    687:        kcpuset_create(&kcp, false);
                    688:
                    689:        /* some finite amount of time */
                    690:
                    691:        for (u_long limit = curcpu()->ci_cpu_freq/10; !done && limit--; ) {
                    692:                kcpuset_copy(kcp, watchset);
                    693:                kcpuset_intersect(kcp, wanted);
                    694:                done = kcpuset_match(kcp, wanted);
                    695:        }
                    696:
                    697:        if (!done) {
                    698:                cpuid_t cii;
                    699:                kcpuset_copy(kcp, wanted);
                    700:                kcpuset_remove(kcp, watchset);
                    701:                if ((cii = kcpuset_ffs(kcp)) != 0) {
                    702:                        printf("Failed to %s:", s);
                    703:                        do {
                    704:                                kcpuset_clear(kcp, --cii);
                    705:                                printf(" cpu%lu", cii);
                    706:                        } while ((cii = kcpuset_ffs(kcp)) != 0);
                    707:                        printf("\n");
                    708:                }
1.2       matt      709:        }
                    710:
1.24      matt      711:        kcpuset_destroy(kcp);
1.2       matt      712: }
                    713:
                    714: /*
                    715:  * Halt this cpu
                    716:  */
                    717: void
                    718: cpu_halt(void)
                    719: {
1.24      matt      720:        cpuid_t cii = cpu_index(curcpu());
1.2       matt      721:
1.24      matt      722:        printf("cpu%lu: shutting down\n", cii);
                    723:        kcpuset_atomic_set(cpus_halted, cii);
1.2       matt      724:        spl0();         /* allow interrupts e.g. further ipi ? */
                    725:        for (;;) ;      /* spin */
                    726:
                    727:        /* NOTREACHED */
                    728: }
                    729:
                    730: /*
                    731:  * Halt all running cpus, excluding current cpu.
                    732:  */
                    733: void
                    734: cpu_halt_others(void)
                    735: {
1.24      matt      736:        kcpuset_t *kcp;
1.2       matt      737:
1.24      matt      738:        // If we are the only CPU running, there's nothing to do.
                    739:        if (kcpuset_match(cpus_running, curcpu()->ci_data.cpu_kcpuset))
1.2       matt      740:                return;
                    741:
1.24      matt      742:        // Get all running CPUs
                    743:        kcpuset_clone(&kcp, cpus_running);
                    744:        // Remove ourself
                    745:        kcpuset_remove(kcp, curcpu()->ci_data.cpu_kcpuset);
                    746:        // Remove any halted CPUs
                    747:        kcpuset_remove(kcp, cpus_halted);
                    748:        // If there are CPUs left, send the IPIs
                    749:        if (!kcpuset_iszero(kcp)) {
                    750:                cpu_multicast_ipi(kcp, IPI_HALT);
                    751:                cpu_ipi_wait("halt", cpus_halted, kcp);
                    752:        }
                    753:        kcpuset_destroy(kcp);
1.2       matt      754:
                    755:        /*
                    756:         * TBD
                    757:         * Depending on available firmware methods, other cpus will
1.24      matt      758:         * either shut down themselves, or spin and wait for us to
1.2       matt      759:         * stop them.
                    760:         */
                    761: }
                    762:
                    763: /*
                    764:  * Pause this cpu
                    765:  */
                    766: void
                    767: cpu_pause(struct reg *regsp)
                    768: {
                    769:        int s = splhigh();
1.24      matt      770:        cpuid_t cii = cpu_index(curcpu());
1.2       matt      771:
1.24      matt      772:        if (__predict_false(cold))
                    773:                return;
                    774:
                    775:        do {
                    776:                kcpuset_atomic_set(cpus_paused, cii);
1.2       matt      777:                do {
                    778:                        ;
1.24      matt      779:                } while (kcpuset_isset(cpus_paused, cii));
                    780:                kcpuset_atomic_set(cpus_resumed, cii);
1.2       matt      781: #if defined(DDB)
1.6       matt      782:                if (ddb_running_on_this_cpu_p())
1.2       matt      783:                        cpu_Debugger();
1.6       matt      784:                if (ddb_running_on_any_cpu_p())
1.2       matt      785:                        continue;
                    786: #endif
1.24      matt      787:        } while (false);
1.2       matt      788:
                    789:        splx(s);
                    790: }
                    791:
                    792: /*
                    793:  * Pause all running cpus, excluding current cpu.
                    794:  */
                    795: void
                    796: cpu_pause_others(void)
                    797: {
1.24      matt      798:        struct cpu_info * const ci = curcpu();
                    799:        kcpuset_t *kcp;
1.2       matt      800:
1.24      matt      801:        if (cold || kcpuset_match(cpus_running, ci->ci_data.cpu_kcpuset))
                    802:                return;
                    803:
                    804:        kcpuset_clone(&kcp, cpus_running);
                    805:        kcpuset_remove(kcp, ci->ci_data.cpu_kcpuset);
                    806:        kcpuset_remove(kcp, cpus_paused);
1.2       matt      807:
1.24      matt      808:        cpu_broadcast_ipi(IPI_SUSPEND);
                    809:        cpu_ipi_wait("pause", cpus_paused, kcp);
1.2       matt      810:
1.24      matt      811:        kcpuset_destroy(kcp);
1.2       matt      812: }
                    813:
                    814: /*
                    815:  * Resume a single cpu
                    816:  */
                    817: void
1.24      matt      818: cpu_resume(cpuid_t cii)
1.2       matt      819: {
1.24      matt      820:        kcpuset_t *kcp;
                    821:
                    822:        if (__predict_false(cold))
                    823:                return;
                    824:
                    825:        kcpuset_create(&kcp, true);
                    826:        kcpuset_set(kcp, cii);
                    827:        kcpuset_atomicly_remove(cpus_resumed, cpus_resumed);
                    828:        kcpuset_atomic_clear(cpus_paused, cii);
                    829:
                    830:        cpu_ipi_wait("resume", cpus_resumed, kcp);
1.2       matt      831:
1.24      matt      832:        kcpuset_destroy(kcp);
1.2       matt      833: }
                    834:
                    835: /*
                    836:  * Resume all paused cpus.
                    837:  */
                    838: void
                    839: cpu_resume_others(void)
                    840: {
1.24      matt      841:        kcpuset_t *kcp;
                    842:
                    843:        if (__predict_false(cold))
                    844:                return;
1.2       matt      845:
1.24      matt      846:        kcpuset_atomicly_remove(cpus_resumed, cpus_resumed);
                    847:        kcpuset_clone(&kcp, cpus_paused);
                    848:        kcpuset_atomicly_remove(cpus_paused, cpus_paused);
1.2       matt      849:
                    850:        /* CPUs awake on cpus_paused clear */
1.24      matt      851:        cpu_ipi_wait("resume", cpus_resumed, kcp);
                    852:
                    853:        kcpuset_destroy(kcp);
1.2       matt      854: }
                    855:
1.24      matt      856: bool
                    857: cpu_is_paused(cpuid_t cii)
1.2       matt      858: {
                    859:
1.24      matt      860:        return !cold && kcpuset_isset(cpus_paused, cii);
1.2       matt      861: }
                    862:
1.7       cliff     863: #ifdef DDB
1.2       matt      864: void
                    865: cpu_debug_dump(void)
                    866: {
                    867:        CPU_INFO_ITERATOR cii;
                    868:        struct cpu_info *ci;
                    869:        char running, hatched, paused, resumed, halted;
                    870:
                    871:        db_printf("CPU CPUID STATE CPUINFO            CPL INT MTX IPIS\n");
                    872:        for (CPU_INFO_FOREACH(cii, ci)) {
1.24      matt      873:                hatched = (kcpuset_isset(cpus_hatched, cpu_index(ci)) ? 'H' : '-');
                    874:                running = (kcpuset_isset(cpus_running, cpu_index(ci)) ? 'R' : '-');
                    875:                paused  = (kcpuset_isset(cpus_paused,  cpu_index(ci)) ? 'P' : '-');
                    876:                resumed = (kcpuset_isset(cpus_resumed, cpu_index(ci)) ? 'r' : '-');
                    877:                halted  = (kcpuset_isset(cpus_halted,  cpu_index(ci)) ? 'h' : '-');
1.2       matt      878:                db_printf("%3d 0x%03lx %c%c%c%c%c %p "
                    879:                        "%3d %3d %3d "
                    880:                        "0x%02" PRIx64 "/0x%02" PRIx64 "\n",
                    881:                        cpu_index(ci), ci->ci_cpuid,
                    882:                        running, hatched, paused, resumed, halted,
                    883:                        ci, ci->ci_cpl, ci->ci_idepth, ci->ci_mtx_count,
                    884:                        ci->ci_active_ipis, ci->ci_request_ipis);
                    885:        }
                    886: }
1.7       cliff     887: #endif
1.2       matt      888:
                    889: void
                    890: cpu_hatch(struct cpu_info *ci)
                    891: {
                    892:        struct pmap_tlb_info * const ti = ci->ci_tlb_info;
                    893:
                    894:        /*
                    895:         * Invalidate all the TLB enties (even wired ones) and then reserve
                    896:         * space for the wired TLB entries.
                    897:         */
                    898:        mips3_cp0_wired_write(0);
                    899:        tlb_invalidate_all();
                    900:        mips3_cp0_wired_write(ti->ti_wired);
                    901:
                    902:        /*
1.5       matt      903:         * Setup HWRENA and USERLOCAL COP0 registers (MIPSxxR2).
                    904:         */
                    905:        cpu_hwrena_setup();
                    906:
                    907:        /*
1.2       matt      908:         * If we are using register zero relative addressing to access cpu_info
                    909:         * in the exception vectors, enter that mapping into TLB now.
                    910:         */
                    911:        if (ci->ci_tlb_slot >= 0) {
                    912:                const uint32_t tlb_lo = MIPS3_PG_G|MIPS3_PG_V
                    913:                    | mips3_paddr_to_tlbpfn((vaddr_t)ci);
1.27    ! matt      914:                const struct tlbmask tlbmask = {
        !           915:                        .tlb_hi = -PAGE_SIZE | KERNEL_PID,
        !           916: #if (PGSHIFT & 1)
        !           917:                        .tlb_lo0 = tlb_lo,
        !           918:                        .tlb_lo1 = tlb_lo + MIPS3_PG_NEXT,
        !           919: #else
        !           920:                        .tlb_lo0 = 0,
        !           921:                        .tlb_lo1 = tlb_lo,
        !           922: #endif
        !           923:                        .tlb_mask = -1,
        !           924:                };
1.2       matt      925:
1.27    ! matt      926:                tlb_invalidate_addr(tlbmask.tlb_hi, KERNEL_PID);
        !           927:                tlb_write_entry(ci->ci_tlb_slot, &tlbmask);
1.2       matt      928:        }
                    929:
                    930:        /*
                    931:         * Flush the icache just be sure.
                    932:         */
                    933:        mips_icache_sync_all();
                    934:
                    935:        /*
                    936:         * Let this CPU do its own initialization (for things that have to be
                    937:         * done on the local CPU).
                    938:         */
                    939:        (*mips_locoresw.lsw_cpu_init)(ci);
                    940:
1.21      matt      941:        // Show this CPU as present.
                    942:        atomic_or_ulong(&ci->ci_flags, CPUF_PRESENT);
                    943:
1.2       matt      944:        /*
                    945:         * Announce we are hatched
                    946:         */
1.24      matt      947:        kcpuset_atomic_set(cpus_hatched, cpu_index(ci));
1.2       matt      948:
                    949:        /*
                    950:         * Now wait to be set free!
                    951:         */
1.24      matt      952:        while (! kcpuset_isset(cpus_running, cpu_index(ci))) {
1.2       matt      953:                /* spin, spin, spin */
                    954:        }
                    955:
                    956:        /*
                    957:         * initialize the MIPS count/compare clock
                    958:         */
                    959:        mips3_cp0_count_write(ci->ci_data.cpu_cc_skew);
                    960:        KASSERT(ci->ci_cycles_per_hz != 0);
                    961:        ci->ci_next_cp0_clk_intr = ci->ci_data.cpu_cc_skew + ci->ci_cycles_per_hz;
                    962:        mips3_cp0_compare_write(ci->ci_next_cp0_clk_intr);
                    963:        ci->ci_data.cpu_cc_skew = 0;
                    964:
                    965:        /*
1.7       cliff     966:         * Let this CPU do its own post-running initialization
                    967:         * (for things that have to be done on the local CPU).
                    968:         */
1.8       cliff     969:        (*mips_locoresw.lsw_cpu_run)(ci);
1.7       cliff     970:
                    971:        /*
1.23      matt      972:         * Now turn on interrupts (and verify they are on).
1.2       matt      973:         */
                    974:        spl0();
1.23      matt      975:        KASSERTMSG(ci->ci_cpl == IPL_NONE, "cpl %d", ci->ci_cpl);
                    976:        KASSERT(mips_cp0_status_read() & MIPS_SR_INT_IE);
1.2       matt      977:
1.24      matt      978:        kcpuset_atomic_set(pmap_kernel()->pm_onproc, cpu_index(ci));
                    979:        kcpuset_atomic_set(pmap_kernel()->pm_active, cpu_index(ci));
                    980:
1.2       matt      981:        /*
                    982:         * And do a tail call to idle_loop
                    983:         */
                    984:        idle_loop(NULL);
                    985: }
                    986:
                    987: void
                    988: cpu_boot_secondary_processors(void)
                    989: {
1.20      matt      990:        CPU_INFO_ITERATOR cii;
                    991:        struct cpu_info *ci;
                    992:        for (CPU_INFO_FOREACH(cii, ci)) {
                    993:                if (CPU_IS_PRIMARY(ci))
                    994:                        continue;
1.2       matt      995:                KASSERT(ci->ci_data.cpu_idlelwp);
                    996:
                    997:                /*
                    998:                 * Skip this CPU if it didn't sucessfully hatch.
                    999:                 */
1.24      matt     1000:                if (!kcpuset_isset(cpus_hatched, cpu_index(ci)))
1.2       matt     1001:                        continue;
                   1002:
                   1003:                ci->ci_data.cpu_cc_skew = mips3_cp0_count_read();
                   1004:                atomic_or_ulong(&ci->ci_flags, CPUF_RUNNING);
1.24      matt     1005:                kcpuset_set(cpus_running, cpu_index(ci));
1.23      matt     1006:                // Spin until the cpu calls idle_loop
                   1007:                for (u_int i = 0; i < 100; i++) {
1.24      matt     1008:                        if (kcpuset_isset(cpus_running, cpu_index(ci)))
1.23      matt     1009:                                break;
                   1010:                        delay(1000);
                   1011:                }
1.2       matt     1012:        }
                   1013: }
                   1014:
                   1015: void
                   1016: xc_send_ipi(struct cpu_info *ci)
                   1017: {
                   1018:
1.12      matt     1019:        (*mips_locoresw.lsw_send_ipi)(ci, IPI_XCALL);
1.2       matt     1020: }
1.17      rmind    1021:
                   1022: void
                   1023: cpu_ipi(struct cpu_info *ci)
                   1024: {
                   1025:        (*mips_locoresw.lsw_send_ipi)(ci, IPI_GENERIC);
                   1026: }
                   1027:
1.2       matt     1028: #endif /* MULTIPROCESSOR */
                   1029:
                   1030: void
                   1031: cpu_offline_md(void)
                   1032: {
                   1033:
                   1034:        (*mips_locoresw.lsw_cpu_offline_md)();
                   1035: }
                   1036:
                   1037: #ifdef _LP64
                   1038: void
                   1039: cpu_vmspace_exec(lwp_t *l, vaddr_t start, vaddr_t end)
                   1040: {
                   1041:        /*
                   1042:         * We need to turn on/off UX so that copyout/copyin will work
                   1043:         * well before setreg gets called.
                   1044:         */
                   1045:        uint32_t sr = mips_cp0_status_read();
                   1046:        if (end != (uint32_t) end) {
                   1047:                mips_cp0_status_write(sr | MIPS3_SR_UX);
                   1048:        } else {
                   1049:                mips_cp0_status_write(sr & ~MIPS3_SR_UX);
                   1050:        }
                   1051: }
                   1052: #endif
1.5       matt     1053:
                   1054: int
                   1055: cpu_lwp_setprivate(lwp_t *l, void *v)
                   1056: {
                   1057: #if (MIPS32R2 + MIPS64R2) > 0
1.10      matt     1058:        if (l == curlwp
                   1059:            && (mips_options.mips_cpu->cpu_cp0flags & MIPS_CP0FL_USERLOCAL)) {
1.5       matt     1060:                mipsNN_cp0_userlocal_write(v);
                   1061:        }
                   1062: #endif
                   1063:        return 0;
                   1064: }
1.7       cliff    1065:
                   1066:
1.9       cliff    1067: #if (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0
                   1068:
1.7       cliff    1069: #if (CPUWATCH_MAX != 8)
                   1070: # error CPUWATCH_MAX
                   1071: #endif
                   1072:
                   1073: /*
                   1074:  * cpuwatch_discover - determine how many COP0 watchpoints this CPU supports
                   1075:  */
                   1076: u_int
                   1077: cpuwatch_discover(void)
                   1078: {
                   1079:        int i;
                   1080:
                   1081:        for (i=0; i < CPUWATCH_MAX; i++) {
                   1082:                uint32_t watchhi = mipsNN_cp0_watchhi_read(i);
                   1083:                if ((watchhi & __BIT(31)) == 0) /* test 'M' bit */
                   1084:                        break;
                   1085:        }
                   1086:        return i + 1;
                   1087: }
                   1088:
                   1089: void
                   1090: cpuwatch_free(cpu_watchpoint_t *cwp)
                   1091: {
                   1092: #ifdef DIAGNOSTIC
                   1093:        struct cpu_info * const ci = curcpu();
                   1094:        KASSERT(cwp >= &ci->ci_cpuwatch_tab[0] &&
                   1095:                cwp <= &ci->ci_cpuwatch_tab[ci->ci_cpuwatch_count-1]);
                   1096: #endif
                   1097:        cwp->cw_mode = 0;
                   1098:        cwp->cw_asid = 0;
                   1099:        cwp->cw_addr = 0;
                   1100:        cpuwatch_clr(cwp);
                   1101: }
                   1102:
                   1103: /*
                   1104:  * cpuwatch_alloc
                   1105:  *     find an empty slot
                   1106:  *     no locking for the table since it is CPU private
                   1107:  */
                   1108: cpu_watchpoint_t *
                   1109: cpuwatch_alloc(void)
                   1110: {
                   1111:        struct cpu_info * const ci = curcpu();
                   1112:        cpu_watchpoint_t *cwp;
                   1113:
                   1114:        for (int i=0; i < ci->ci_cpuwatch_count; i++) {
                   1115:                cwp = &ci->ci_cpuwatch_tab[i];
                   1116:                if ((cwp->cw_mode & CPUWATCH_RWX) == 0)
                   1117:                        return cwp;
                   1118:        }
                   1119:        return NULL;
                   1120: }
                   1121:
                   1122:
                   1123: void
                   1124: cpuwatch_set_all(void)
                   1125: {
                   1126:        struct cpu_info * const ci = curcpu();
                   1127:        cpu_watchpoint_t *cwp;
                   1128:        int i;
                   1129:
                   1130:        for (i=0; i < ci->ci_cpuwatch_count; i++) {
                   1131:                cwp = &ci->ci_cpuwatch_tab[i];
                   1132:                if ((cwp->cw_mode & CPUWATCH_RWX) != 0)
                   1133:                        cpuwatch_set(cwp);
                   1134:        }
                   1135: }
                   1136:
                   1137: void
                   1138: cpuwatch_clr_all(void)
                   1139: {
                   1140:        struct cpu_info * const ci = curcpu();
                   1141:        cpu_watchpoint_t *cwp;
                   1142:        int i;
                   1143:
                   1144:        for (i=0; i < ci->ci_cpuwatch_count; i++) {
                   1145:                cwp = &ci->ci_cpuwatch_tab[i];
                   1146:                if ((cwp->cw_mode & CPUWATCH_RWX) != 0)
                   1147:                        cpuwatch_clr(cwp);
                   1148:        }
                   1149: }
                   1150:
                   1151: /*
                   1152:  * cpuwatch_set - establish a MIPS COP0 watchpoint
                   1153:  */
                   1154: void
                   1155: cpuwatch_set(cpu_watchpoint_t *cwp)
                   1156: {
                   1157:        struct cpu_info * const ci = curcpu();
                   1158:        uint32_t watchhi;
                   1159:        register_t watchlo;
                   1160:        int cwnum = cwp - &ci->ci_cpuwatch_tab[0];
                   1161:
                   1162:        KASSERT(cwp >= &ci->ci_cpuwatch_tab[0] &&
                   1163:                cwp <= &ci->ci_cpuwatch_tab[ci->ci_cpuwatch_count-1]);
                   1164:
                   1165:        watchlo = cwp->cw_addr;
                   1166:        if (cwp->cw_mode & CPUWATCH_WRITE)
                   1167:                watchlo |= __BIT(0);
                   1168:        if (cwp->cw_mode & CPUWATCH_READ)
                   1169:                watchlo |= __BIT(1);
                   1170:        if (cwp->cw_mode & CPUWATCH_EXEC)
                   1171:                watchlo |= __BIT(2);
                   1172:
                   1173:        if (cwp->cw_mode & CPUWATCH_ASID)
                   1174:                watchhi = cwp->cw_asid << 16;   /* addr qualified by asid */
                   1175:        else
                   1176:                watchhi = __BIT(30);            /* addr not qual. by asid (Global) */
                   1177:        if (cwp->cw_mode & CPUWATCH_MASK)
                   1178:                watchhi |= cwp->cw_mask;        /* set "dont care" addr match bits */
                   1179:
                   1180:        mipsNN_cp0_watchhi_write(cwnum, watchhi);
                   1181:        mipsNN_cp0_watchlo_write(cwnum, watchlo);
                   1182: }
                   1183:
                   1184: /*
                   1185:  * cpuwatch_clr - disestablish a MIPS COP0 watchpoint
                   1186:  */
                   1187: void
                   1188: cpuwatch_clr(cpu_watchpoint_t *cwp)
                   1189: {
                   1190:        struct cpu_info * const ci = curcpu();
                   1191:        int cwnum = cwp - &ci->ci_cpuwatch_tab[0];
                   1192:
                   1193:        KASSERT(cwp >= &ci->ci_cpuwatch_tab[0] &&
                   1194:                cwp <= &ci->ci_cpuwatch_tab[ci->ci_cpuwatch_count-1]);
                   1195:
                   1196:        mipsNN_cp0_watchhi_write(cwnum, 0);
                   1197:        mipsNN_cp0_watchlo_write(cwnum, 0);
                   1198: }
                   1199:
1.9       cliff    1200: #endif /* (MIPS32 + MIPS32R2 + MIPS64 + MIPS64R2) > 0 */

CVSweb <webmaster@jp.NetBSD.org>