[BACK]Return to cpu_fdt.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / arm / fdt

Annotation of src/sys/arch/arm/fdt/cpu_fdt.c, Revision 1.30.2.1

1.30.2.1! ad          1: /* $NetBSD: cpu_fdt.c,v 1.31 2020/01/12 09:29:18 mrg Exp $ */
1.1       jmcneill    2:
                      3: /*-
                      4:  * Copyright (c) 2017 Jared McNeill <jmcneill@invisible.ca>
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     18:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     19:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     20:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
                     21:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     22:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
                     23:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
                     24:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     26:  * SUCH DAMAGE.
                     27:  */
                     28:
1.12      ryo        29: #include "opt_multiprocessor.h"
                     30: #include "psci_fdt.h"
                     31:
1.1       jmcneill   32: #include <sys/cdefs.h>
1.30.2.1! ad         33: __KERNEL_RCSID(0, "$NetBSD: cpu_fdt.c,v 1.31 2020/01/12 09:29:18 mrg Exp $");
1.1       jmcneill   34:
                     35: #include <sys/param.h>
1.12      ryo        36: #include <sys/atomic.h>
1.1       jmcneill   37: #include <sys/bus.h>
                     38: #include <sys/device.h>
1.4       skrll      39: #include <sys/lwp.h>
1.1       jmcneill   40: #include <sys/systm.h>
                     41: #include <sys/kernel.h>
                     42:
                     43: #include <dev/fdt/fdtvar.h>
                     44:
1.5       ryo        45: #include <arm/armreg.h>
1.1       jmcneill   46: #include <arm/cpu.h>
1.5       ryo        47: #include <arm/cpufunc.h>
1.12      ryo        48: #include <arm/locore.h>
                     49:
                     50: #include <arm/arm/psci.h>
                     51: #include <arm/fdt/arm_fdtvar.h>
                     52: #include <arm/fdt/psci_fdtvar.h>
                     53:
                     54: #include <uvm/uvm_extern.h>
1.1       jmcneill   55:
                     56: static int     cpu_fdt_match(device_t, cfdata_t, void *);
                     57: static void    cpu_fdt_attach(device_t, device_t, void *);
                     58:
1.3       jmcneill   59: enum cpu_fdt_type {
                     60:        ARM_CPU_UP = 1,
                     61:        ARM_CPU_ARMV7,
                     62:        ARM_CPU_ARMV8,
                     63: };
                     64:
1.1       jmcneill   65: struct cpu_fdt_softc {
                     66:        device_t                sc_dev;
                     67:        int                     sc_phandle;
                     68: };
                     69:
1.3       jmcneill   70: static const struct of_compat_data compat_data[] = {
                     71:        { "arm,arm1176jzf-s",           ARM_CPU_UP },
                     72:
1.6       jakllsch   73:        { "arm,arm-v7",                 ARM_CPU_ARMV7 },
1.3       jmcneill   74:        { "arm,cortex-a5",              ARM_CPU_ARMV7 },
                     75:        { "arm,cortex-a7",              ARM_CPU_ARMV7 },
                     76:        { "arm,cortex-a8",              ARM_CPU_ARMV7 },
                     77:        { "arm,cortex-a9",              ARM_CPU_ARMV7 },
                     78:        { "arm,cortex-a12",             ARM_CPU_ARMV7 },
                     79:        { "arm,cortex-a15",             ARM_CPU_ARMV7 },
                     80:        { "arm,cortex-a17",             ARM_CPU_ARMV7 },
                     81:
1.11      jmcneill   82:        { "arm,armv8",                  ARM_CPU_ARMV8 },
1.3       jmcneill   83:        { "arm,cortex-a53",             ARM_CPU_ARMV8 },
                     84:        { "arm,cortex-a57",             ARM_CPU_ARMV8 },
                     85:        { "arm,cortex-a72",             ARM_CPU_ARMV8 },
                     86:        { "arm,cortex-a73",             ARM_CPU_ARMV8 },
1.7       jmcneill   87:
1.3       jmcneill   88:        { NULL }
                     89: };
                     90:
1.1       jmcneill   91: CFATTACH_DECL_NEW(cpu_fdt, sizeof(struct cpu_fdt_softc),
                     92:        cpu_fdt_match, cpu_fdt_attach, NULL, NULL);
                     93:
                     94: static int
                     95: cpu_fdt_match(device_t parent, cfdata_t cf, void *aux)
                     96: {
                     97:        struct fdt_attach_args * const faa = aux;
1.3       jmcneill   98:        const int phandle = faa->faa_phandle;
                     99:        enum cpu_fdt_type type;
1.2       jmcneill  100:        int is_compatible;
                    101:        bus_addr_t mpidr;
                    102:
1.3       jmcneill  103:        is_compatible = of_match_compat_data(phandle, compat_data);
1.2       jmcneill  104:        if (!is_compatible)
                    105:                return 0;
                    106:
1.3       jmcneill  107:        type = of_search_compatible(phandle, compat_data)->data;
                    108:        switch (type) {
                    109:        case ARM_CPU_ARMV7:
                    110:        case ARM_CPU_ARMV8:
                    111:                if (fdtbus_get_reg(phandle, 0, &mpidr, NULL) != 0)
                    112:                        return 0;
                    113:        default:
                    114:                break;
                    115:        }
1.1       jmcneill  116:
1.2       jmcneill  117:        return is_compatible;
1.1       jmcneill  118: }
                    119:
                    120: static void
                    121: cpu_fdt_attach(device_t parent, device_t self, void *aux)
                    122: {
                    123:        struct cpu_fdt_softc * const sc = device_private(self);
                    124:        struct fdt_attach_args * const faa = aux;
1.3       jmcneill  125:        const int phandle = faa->faa_phandle;
                    126:        enum cpu_fdt_type type;
1.1       jmcneill  127:        bus_addr_t mpidr;
1.3       jmcneill  128:        cpuid_t cpuid;
1.30.2.1! ad        129:        const uint32_t *cap_ptr;
        !           130:        int len;
1.1       jmcneill  131:
                    132:        sc->sc_dev = self;
1.3       jmcneill  133:        sc->sc_phandle = phandle;
                    134:
1.30.2.1! ad        135:        cap_ptr = fdtbus_get_prop(phandle, "capacity-dmips-mhz", &len);
        !           136:        if (cap_ptr && len == 4) {
        !           137:                prop_dictionary_t dict = device_properties(self);
        !           138:                uint32_t capacity_dmips_mhz = be32toh(*cap_ptr);
        !           139:
        !           140:                prop_dictionary_set_uint32(dict, "capacity_dmips_mhz",
        !           141:                    capacity_dmips_mhz);
        !           142:        }
        !           143:
1.3       jmcneill  144:        type = of_search_compatible(phandle, compat_data)->data;
1.1       jmcneill  145:
1.3       jmcneill  146:        switch (type) {
                    147:        case ARM_CPU_ARMV7:
                    148:        case ARM_CPU_ARMV8:
                    149:                if (fdtbus_get_reg(phandle, 0, &mpidr, NULL) != 0) {
                    150:                        aprint_error(": missing 'reg' property\n");
                    151:                        return;
                    152:                }
1.9       ryo       153:                cpuid = mpidr;
1.3       jmcneill  154:                break;
                    155:        default:
                    156:                cpuid = 0;
                    157:                break;
1.1       jmcneill  158:        }
                    159:
1.2       jmcneill  160:        /* Attach the CPU */
1.3       jmcneill  161:        cpu_attach(self, cpuid);
1.8       jmcneill  162:
                    163:        /* Attach CPU frequency scaling provider */
                    164:        config_found(self, faa, NULL);
1.1       jmcneill  165: }
1.12      ryo       166:
1.24      jmcneill  167: #if defined(MULTIPROCESSOR) && (NPSCI_FDT > 0 || defined(__aarch64__))
1.12      ryo       168: static register_t
                    169: cpu_fdt_mpstart_pa(void)
                    170: {
1.16      skrll     171:        bool ok __diagused;
                    172:        paddr_t pa;
                    173:
                    174:        ok = pmap_extract(pmap_kernel(), (vaddr_t)cpu_mpstart, &pa);
                    175:        KASSERT(ok);
                    176:
                    177:        return pa;
1.12      ryo       178: }
1.24      jmcneill  179: #endif
1.12      ryo       180:
1.24      jmcneill  181: #ifdef MULTIPROCESSOR
1.13      jmcneill  182: static bool
                    183: arm_fdt_cpu_okay(const int child)
                    184: {
                    185:        const char *s;
                    186:
                    187:        s = fdtbus_get_string(child, "device_type");
                    188:        if (!s || strcmp(s, "cpu") != 0)
                    189:                return false;
                    190:
                    191:        s = fdtbus_get_string(child, "status");
                    192:        if (s) {
                    193:                if (strcmp(s, "okay") == 0)
                    194:                        return false;
                    195:                if (strcmp(s, "disabled") == 0)
                    196:                        return of_hasprop(child, "enable-method");
                    197:                return false;
                    198:        } else {
                    199:                return true;
                    200:        }
                    201: }
1.14      jmcneill  202: #endif /* MULTIPROCESSOR */
1.12      ryo       203:
                    204: void
                    205: arm_fdt_cpu_bootstrap(void)
                    206: {
                    207: #ifdef MULTIPROCESSOR
                    208:        uint64_t mpidr, bp_mpidr;
                    209:        u_int cpuindex;
1.16      skrll     210:        int child;
                    211:
                    212:        const int cpus = OF_finddevice("/cpus");
                    213:        if (cpus == -1) {
                    214:                aprint_error("%s: no /cpus node found\n", __func__);
                    215:                arm_cpu_max = 1;
                    216:                return;
                    217:        }
                    218:
                    219:        /* Count CPUs */
                    220:        arm_cpu_max = 0;
                    221:
                    222:        /* MPIDR affinity levels of boot processor. */
                    223:        bp_mpidr = cpu_mpidr_aff_read();
                    224:
                    225:        /* Boot APs */
                    226:        cpuindex = 1;
                    227:        for (child = OF_child(cpus); child; child = OF_peer(child)) {
                    228:                if (!arm_fdt_cpu_okay(child))
                    229:                        continue;
                    230:
                    231:                arm_cpu_max++;
                    232:                if (fdtbus_get_reg64(child, 0, &mpidr, NULL) != 0)
                    233:                        continue;
                    234:                if (mpidr == bp_mpidr)
                    235:                        continue;       /* BP already started */
                    236:
                    237:                KASSERT(cpuindex < MAXCPUS);
                    238:                cpu_mpidr[cpuindex] = mpidr;
                    239:                cpu_dcache_wb_range((vaddr_t)&cpu_mpidr[cpuindex],
                    240:                    sizeof(cpu_mpidr[cpuindex]));
                    241:
                    242:                cpuindex++;
                    243:        }
                    244: #endif
                    245: }
                    246:
1.19      jmcneill  247: #ifdef MULTIPROCESSOR
1.25      jmcneill  248: static struct arm_cpu_method *
                    249: arm_fdt_cpu_enable_method(int phandle)
1.19      jmcneill  250: {
1.25      jmcneill  251:        const char *method;
                    252:
                    253:        method = fdtbus_get_string(phandle, "enable-method");
                    254:        if (method == NULL)
                    255:                return NULL;
                    256:
1.19      jmcneill  257:        __link_set_decl(arm_cpu_methods, struct arm_cpu_method);
1.25      jmcneill  258:        struct arm_cpu_method * const *acmp;
                    259:        __link_set_foreach(acmp, arm_cpu_methods) {
                    260:                if (strcmp(method, (*acmp)->acm_compat) == 0)
                    261:                        return *acmp;
1.19      jmcneill  262:        }
1.25      jmcneill  263:
                    264:        return NULL;
                    265: }
                    266:
                    267: static int
                    268: arm_fdt_cpu_enable(int phandle, struct arm_cpu_method *acm)
                    269: {
                    270:        return acm->acm_enable(phandle);
1.19      jmcneill  271: }
                    272: #endif
                    273:
1.22      skrll     274: int
1.16      skrll     275: arm_fdt_cpu_mpstart(void)
                    276: {
1.22      skrll     277:        int ret = 0;
1.16      skrll     278: #ifdef MULTIPROCESSOR
                    279:        uint64_t mpidr, bp_mpidr;
1.19      jmcneill  280:        u_int cpuindex, i;
                    281:        int child, error;
1.25      jmcneill  282:        struct arm_cpu_method *acm;
1.12      ryo       283:
                    284:        const int cpus = OF_finddevice("/cpus");
                    285:        if (cpus == -1) {
                    286:                aprint_error("%s: no /cpus node found\n", __func__);
1.22      skrll     287:                return 0;
1.12      ryo       288:        }
                    289:
                    290:        /* MPIDR affinity levels of boot processor. */
                    291:        bp_mpidr = cpu_mpidr_aff_read();
                    292:
                    293:        /* Boot APs */
                    294:        cpuindex = 1;
                    295:        for (child = OF_child(cpus); child; child = OF_peer(child)) {
1.13      jmcneill  296:                if (!arm_fdt_cpu_okay(child))
1.12      ryo       297:                        continue;
1.16      skrll     298:
1.12      ryo       299:                if (fdtbus_get_reg64(child, 0, &mpidr, NULL) != 0)
                    300:                        continue;
1.18      skrll     301:
1.12      ryo       302:                if (mpidr == bp_mpidr)
                    303:                        continue;       /* BP already started */
                    304:
1.25      jmcneill  305:                acm = arm_fdt_cpu_enable_method(child);
                    306:                if (acm == NULL)
                    307:                        acm = arm_fdt_cpu_enable_method(cpus);
                    308:                if (acm == NULL)
1.12      ryo       309:                        continue;
                    310:
1.25      jmcneill  311:                error = arm_fdt_cpu_enable(child, acm);
1.19      jmcneill  312:                if (error != 0) {
1.25      jmcneill  313:                        aprint_error("%s: failed to enable CPU %#" PRIx64 "\n", __func__, mpidr);
1.12      ryo       314:                        continue;
                    315:                }
                    316:
1.19      jmcneill  317:                /* Wake up AP in case firmware has placed it in WFE state */
                    318:                __asm __volatile("sev" ::: "memory");
                    319:
                    320:                /* Wait for AP to start */
1.21      jmcneill  321:                for (i = 0x10000000; i > 0; i--) {
1.28      jmcneill  322:                        if (cpu_hatched_p(cpuindex))
1.19      jmcneill  323:                                break;
                    324:                }
1.22      skrll     325:
                    326:                if (i == 0) {
                    327:                        ret++;
1.19      jmcneill  328:                        aprint_error("cpu%d: WARNING: AP failed to start\n", cpuindex);
1.22      skrll     329:                }
1.19      jmcneill  330:
1.12      ryo       331:                cpuindex++;
                    332:        }
1.19      jmcneill  333: #endif /* MULTIPROCESSOR */
1.22      skrll     334:        return ret;
1.19      jmcneill  335: }
1.12      ryo       336:
1.19      jmcneill  337: static int
                    338: cpu_enable_nullop(int phandle)
                    339: {
                    340:        return ENXIO;
                    341: }
                    342: ARM_CPU_METHOD(default, "", cpu_enable_nullop);
1.12      ryo       343:
1.19      jmcneill  344: #if defined(MULTIPROCESSOR) && NPSCI_FDT > 0
                    345: static int
                    346: cpu_enable_psci(int phandle)
                    347: {
                    348:        static bool psci_probed, psci_p;
                    349:        uint64_t mpidr;
                    350:        int ret;
                    351:
                    352:        if (!psci_probed) {
                    353:                psci_probed = true;
                    354:                psci_p = psci_fdt_preinit() == 0;
1.12      ryo       355:        }
1.19      jmcneill  356:        if (!psci_p)
                    357:                return ENXIO;
                    358:
                    359:        fdtbus_get_reg64(phandle, 0, &mpidr, NULL);
                    360:
1.29      bad       361: #if !defined(AARCH64)
                    362:        /*
1.30      bad       363:         * not necessary on AARCH64. beside there it hangs the system
1.29      bad       364:         * because cache ops are only functional after cpu_attach()
                    365:         * was called.
                    366:         */
                    367:        cpu_dcache_wbinv_all();
                    368: #endif
1.19      jmcneill  369:        ret = psci_cpu_on(mpidr, cpu_fdt_mpstart_pa(), 0);
                    370:        if (ret != PSCI_SUCCESS)
                    371:                return EIO;
                    372:
                    373:        return 0;
                    374: }
                    375: ARM_CPU_METHOD(psci, "psci", cpu_enable_psci);
                    376: #endif
                    377:
1.23      jmcneill  378: #if defined(MULTIPROCESSOR) && defined(__aarch64__)
                    379: static int
                    380: spintable_cpu_on(u_int cpuindex, paddr_t entry_point_address, paddr_t cpu_release_addr)
                    381: {
                    382:        /*
                    383:         * we need devmap for cpu-release-addr in advance.
                    384:         * __HAVE_MM_MD_DIRECT_MAPPED_PHYS nor pmap didn't work at this point.
                    385:         */
                    386:        if (pmap_devmap_find_pa(cpu_release_addr, sizeof(paddr_t)) == NULL) {
                    387:                aprint_error("%s: devmap for cpu-release-addr"
                    388:                    " 0x%08"PRIxPADDR" required\n", __func__, cpu_release_addr);
                    389:                return -1;
                    390:        } else {
                    391:                extern struct bus_space arm_generic_bs_tag;
                    392:                bus_space_handle_t ioh;
                    393:
                    394:                bus_space_map(&arm_generic_bs_tag, cpu_release_addr,
                    395:                    sizeof(paddr_t), 0, &ioh);
                    396:                bus_space_write_4(&arm_generic_bs_tag, ioh, 0,
                    397:                    entry_point_address);
                    398:                bus_space_unmap(&arm_generic_bs_tag, ioh, sizeof(paddr_t));
                    399:        }
                    400:
                    401:        return 0;
                    402: }
                    403:
1.19      jmcneill  404: static int
                    405: cpu_enable_spin_table(int phandle)
                    406: {
1.20      jmcneill  407:        uint64_t mpidr, addr;
1.19      jmcneill  408:        int ret;
                    409:
                    410:        fdtbus_get_reg64(phandle, 0, &mpidr, NULL);
                    411:
1.20      jmcneill  412:        if (of_getprop_uint64(phandle, "cpu-release-addr", &addr) != 0)
1.19      jmcneill  413:                return ENXIO;
                    414:
1.20      jmcneill  415:        ret = spintable_cpu_on(mpidr, cpu_fdt_mpstart_pa(), (paddr_t)addr);
1.19      jmcneill  416:        if (ret != 0)
                    417:                return EIO;
                    418:
                    419:        return 0;
1.12      ryo       420: }
1.19      jmcneill  421: ARM_CPU_METHOD(spin_table, "spin-table", cpu_enable_spin_table);
                    422: #endif

CVSweb <webmaster@jp.NetBSD.org>