root/sys/arch/mips/rmi/rmixl_cpucore.c
/*      $NetBSD: rmixl_cpucore.c,v 1.7 2021/08/07 16:18:59 thorpej Exp $        */

/*
 * Copyright 2002 Wasabi Systems, Inc.
 * All rights reserved.
 *
 * Written by Simon Burge for Wasabi Systems, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *      This product includes software developed for the NetBSD Project by
 *      Wasabi Systems, Inc.
 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
 *    or promote products derived from this software without specific prior
 *    written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include "locators.h"

#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: rmixl_cpucore.c,v 1.7 2021/08/07 16:18:59 thorpej Exp $");

#include "opt_multiprocessor.h"

#include <sys/param.h>
#include <sys/device.h>
#include <sys/systm.h>
#include <sys/cpu.h>

#include <uvm/uvm_extern.h>

#include <mips/rmi/rmixlvar.h>
#include <mips/rmi/rmixl_cpunodevar.h>
#include <mips/rmi/rmixl_cpucorevar.h>
#include <mips/rmi/rmixl_fmnvar.h>

static int      cpucore_rmixl_match(device_t, cfdata_t, void *);
static void     cpucore_rmixl_attach(device_t, device_t, void *);
static int      cpucore_rmixl_print(void *, const char *);

CFATTACH_DECL_NEW(cpucore_rmixl, sizeof(struct cpucore_softc),
        cpucore_rmixl_match, cpucore_rmixl_attach, NULL, NULL);

static int
cpucore_rmixl_match(device_t parent, cfdata_t cf, void *aux)
{
        struct cpunode_attach_args *na = aux;
        int core = cf->cf_loc[CPUNODECF_CORE];

        if (!cpu_rmixl(mips_options.mips_cpu))
                return 0;

        if (strncmp(na->na_name, cf->cf_name, strlen(cf->cf_name)) == 0
#ifndef MULTIPROCESSOR
            && na->na_core == 0
#endif
            && (core == CPUNODECF_CORE_DEFAULT || core == na->na_core))
                return 1;

        return 0;
}

static void
cpucore_rmixl_attach(device_t parent, device_t self, void *aux)
{
        struct cpucore_softc * const sc = device_private(self);
        struct cpunode_attach_args *na = aux;
        struct cpucore_attach_args ca;
        u_int nthreads;
        struct rmixl_config *rcp = &rmixl_configuration;

        sc->sc_dev = self;
        sc->sc_core = na->na_core;
        KASSERT(sc->sc_hatched == false);

#if 0
#ifdef MULTIPROCESSOR
        /*
         * Create the TLB structure needed - one per core and core0 uses the
         * default one for the system.
         */
        if (sc->sc_core == 0) {
                sc->sc_tlbinfo = &pmap_tlb0_info;
        } else {
                const vaddr_t va = (vaddr_t)&sc->sc_tlbinfo0;
                paddr_t pa;

                if (! pmap_extract(pmap_kernel(), va, &pa))
                        panic("%s: pmap_extract fail, va %#"PRIxVADDR, __func__, va);
#ifdef _LP64
                sc->sc_tlbinfo = (struct pmap_tlb_info *)
                        MIPS_PHYS_TO_XKPHYS_CACHED(pa);
#else
                sc->sc_tlbinfo = (struct pmap_tlb_info *)
                        MIPS_PHYS_TO_KSEG0(pa);
#endif
                pmap_tlb_info_init(sc->sc_tlbinfo);
        }
#endif
#endif

        aprint_normal("\n");
        aprint_normal_dev(self, "%lu.%02luMHz (hz cycles = %lu, "
            "delay divisor = %lu)\n",
            curcpu()->ci_cpu_freq / 1000000,
            (curcpu()->ci_cpu_freq % 1000000) / 10000,
            curcpu()->ci_cycles_per_hz, curcpu()->ci_divisor_delay);

        aprint_normal("%s: ", device_xname(self));
        cpu_identify(self);

        nthreads = MIPS_CIDFL_RMI_NTHREADS(mips_options.mips_cpu->cpu_cidflags);
        aprint_normal_dev(self, "%d %s on core\n", nthreads,
                nthreads == 1 ? "thread" : "threads");

        /*
         * Attach CPU (RMI thread contexts) devices
         * according to userapp_cpu_map bitmask.
         */
        u_int thread_mask = (1 << nthreads) - 1;
        u_int core_shft = sc->sc_core * nthreads;
        u_int threads_enb =
                (u_int)(rcp->rc_psb_info.userapp_cpu_map >> core_shft) & thread_mask;
        u_int threads_dis = (~threads_enb) & thread_mask;

        sc->sc_threads_dis = threads_dis;
        if (threads_dis != 0) {
                aprint_normal_dev(self, "threads");
                u_int d = threads_dis;
                while (d != 0) {
                        const u_int t = ffs(d) - 1;
                        d ^= (1 << t);
                        aprint_normal(" %d%s", t, (d==0) ? "" : ",");
                }
                aprint_normal(" offline (disabled by firmware)\n");
        }

        u_int threads_try_attach = threads_enb;
        while (threads_try_attach != 0) {
                const u_int t = ffs(threads_try_attach) - 1;
                const u_int bit = 1 << t;
                threads_try_attach ^= bit;
                ca.ca_name = "cpu";
                ca.ca_thread = t;
                ca.ca_core = sc->sc_core;
                if (config_found(self, &ca, cpucore_rmixl_print,
                                 CFARGS_NONE) == NULL) {
                        /*
                         * thread did not attach, e.g. not configured
                         * arrange to have it disabled in THREADEN PCR
                         */
                        threads_enb ^= bit;
                        threads_dis |= bit;
                }
        }

        sc->sc_threads_enb = threads_enb;
        sc->sc_threads_dis = threads_dis;

        /*
         * when attaching the core of the primary cpu,
         * do the post-running initialization here
         */
        if (sc->sc_core == RMIXL_CPU_CORE((curcpu()->ci_cpuid)))
                cpucore_rmixl_run(self);
}

static int
cpucore_rmixl_print(void *aux, const char *pnp)
{
        struct cpucore_attach_args *ca = aux;

        if (pnp != NULL)
                aprint_normal("%s:", pnp);
        aprint_normal(" thread %d", ca->ca_thread);

        return (UNCONF);
}

/*
 * cpucore_rmixl_run
 *      called from cpucore_rmixl_attach for primary core
 *      and called from cpu_rmixl_run for each hatched cpu
 *      the first call for each cpucore causes init of per-core features:
 *      - disable unused threads
 *      - set Fine-grained (Round Robin) thread scheduling mode
 */
void
cpucore_rmixl_run(device_t self)
{
        struct cpucore_softc * const sc = device_private(self);

        if (sc->sc_running == false) {
                sc->sc_running = true;
                rmixl_mtcr(RMIXL_PCR_THREADEN, sc->sc_threads_enb);
                rmixl_mtcr(RMIXL_PCR_SCHEDULING, 0);
        }
}

#ifdef MULTIPROCESSOR
/*
 * cpucore_rmixl_hatch
 *      called from cpu_rmixl_hatch for each cpu
 *      the first call for each cpucore causes init of per-core features
 */
void
cpucore_rmixl_hatch(device_t self)
{
        struct cpucore_softc * const sc = device_private(self);

        if (sc->sc_hatched == false) {
                /* PCRs for core#0 are set up in mach_init() */
                if (sc->sc_core != 0)
                        rmixl_pcr_init_core();
                rmixl_fmn_init_core();
                sc->sc_hatched = true;
        }
}
#endif  /* MULTIPROCESSOR */