The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/powerpc/powerpc/cpu.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-4-Clause AND BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2001 Matt Thomas.
    5  * Copyright (c) 2001 Tsubai Masanari.
    6  * Copyright (c) 1998, 1999, 2001 Internet Research Institute, Inc.
    7  * All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed by
   20  *      Internet Research Institute, Inc.
   21  * 4. The name of the author may not be used to endorse or promote products
   22  *    derived from this software without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   33  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   34  */
   35 /*-
   36  * Copyright (C) 2003 Benno Rice.
   37  * All rights reserved.
   38  *
   39  * Redistribution and use in source and binary forms, with or without
   40  * modification, are permitted provided that the following conditions
   41  * are met:
   42  * 1. Redistributions of source code must retain the above copyright
   43  *    notice, this list of conditions and the following disclaimer.
   44  * 2. Redistributions in binary form must reproduce the above copyright
   45  *    notice, this list of conditions and the following disclaimer in the
   46  *    documentation and/or other materials provided with the distribution.
   47  *
   48  * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR
   49  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   50  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   51  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   52  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   53  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   54  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   55  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   56  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   57  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   58  *
   59  * from $NetBSD: cpu_subr.c,v 1.1 2003/02/03 17:10:09 matt Exp $
   60  * $FreeBSD: releng/12.0/sys/powerpc/powerpc/cpu.c 334260 2018-05-27 20:36:43Z jhibbits $
   61  */
   62 
   63 #include <sys/param.h>
   64 #include <sys/systm.h>
   65 #include <sys/bus.h>
   66 #include <sys/conf.h>
   67 #include <sys/cpu.h>
   68 #include <sys/kernel.h>
   69 #include <sys/proc.h>
   70 #include <sys/sysctl.h>
   71 #include <sys/sched.h>
   72 #include <sys/smp.h>
   73 
   74 #include <machine/bus.h>
   75 #include <machine/cpu.h>
   76 #include <machine/hid.h>
   77 #include <machine/md_var.h>
   78 #include <machine/smp.h>
   79 #include <machine/spr.h>
   80 
   81 #include <dev/ofw/openfirm.h>
   82 
   83 static void     cpu_6xx_setup(int cpuid, uint16_t vers);
   84 static void     cpu_970_setup(int cpuid, uint16_t vers);
   85 static void     cpu_booke_setup(int cpuid, uint16_t vers);
   86 static void     cpu_powerx_setup(int cpuid, uint16_t vers);
   87 
   88 int powerpc_pow_enabled;
   89 void (*cpu_idle_hook)(sbintime_t) = NULL;
   90 static void     cpu_idle_60x(sbintime_t);
   91 static void     cpu_idle_booke(sbintime_t);
   92 #if defined(__powerpc64__) && defined(AIM)
   93 static void     cpu_idle_powerx(sbintime_t);
   94 static void     cpu_idle_power9(sbintime_t);
   95 #endif
   96 
   97 struct cputab {
   98         const char      *name;
   99         uint16_t        version;
  100         uint16_t        revfmt;
  101         int             features;       /* Do not include PPC_FEATURE_32 or
  102                                          * PPC_FEATURE_HAS_MMU */
  103         int             features2;
  104         void            (*cpu_setup)(int cpuid, uint16_t vers);
  105 };
  106 #define REVFMT_MAJMIN   1       /* %u.%u */
  107 #define REVFMT_HEX      2       /* 0x%04x */
  108 #define REVFMT_DEC      3       /* %u */
  109 static const struct cputab models[] = {
  110         { "Motorola PowerPC 601",       MPC601,         REVFMT_DEC,
  111            PPC_FEATURE_HAS_FPU | PPC_FEATURE_UNIFIED_CACHE, 0, cpu_6xx_setup },
  112         { "Motorola PowerPC 602",       MPC602,         REVFMT_DEC,
  113            PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  114         { "Motorola PowerPC 603",       MPC603,         REVFMT_MAJMIN,
  115            PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  116         { "Motorola PowerPC 603e",      MPC603e,        REVFMT_MAJMIN,
  117            PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  118         { "Motorola PowerPC 603ev",     MPC603ev,       REVFMT_MAJMIN,
  119            PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  120         { "Motorola PowerPC 604",       MPC604,         REVFMT_MAJMIN,
  121            PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  122         { "Motorola PowerPC 604ev",     MPC604ev,       REVFMT_MAJMIN,
  123            PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  124         { "Motorola PowerPC 620",       MPC620,         REVFMT_HEX,
  125            PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU, 0, NULL },
  126         { "Motorola PowerPC 750",       MPC750,         REVFMT_MAJMIN,
  127            PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  128         { "IBM PowerPC 750FX",          IBM750FX,       REVFMT_MAJMIN,
  129            PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  130         { "IBM PowerPC 970",            IBM970,         REVFMT_MAJMIN,
  131            PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
  132            0, cpu_970_setup },
  133         { "IBM PowerPC 970FX",          IBM970FX,       REVFMT_MAJMIN,
  134            PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
  135            0, cpu_970_setup },
  136         { "IBM PowerPC 970GX",          IBM970GX,       REVFMT_MAJMIN,
  137            PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
  138            0, cpu_970_setup },
  139         { "IBM PowerPC 970MP",          IBM970MP,       REVFMT_MAJMIN,
  140            PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU,
  141            0, cpu_970_setup },
  142         { "IBM POWER4",         IBMPOWER4,      REVFMT_MAJMIN,
  143            PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_POWER4, 0, NULL },
  144         { "IBM POWER4+",        IBMPOWER4PLUS,  REVFMT_MAJMIN,
  145            PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_POWER4, 0, NULL },
  146         { "IBM POWER5",         IBMPOWER5,      REVFMT_MAJMIN,
  147            PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_POWER4 |
  148            PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP, 0, NULL },
  149         { "IBM POWER5+",        IBMPOWER5PLUS,  REVFMT_MAJMIN,
  150            PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_POWER5_PLUS |
  151            PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP, 0, NULL },
  152         { "IBM POWER6",         IBMPOWER6,      REVFMT_MAJMIN,
  153            PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
  154            PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 |
  155            PPC_FEATURE_TRUE_LE, 0, NULL },
  156         { "IBM POWER7",         IBMPOWER7,      REVFMT_MAJMIN,
  157            PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
  158            PPC_FEATURE_SMT | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06 |
  159            PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE, PPC_FEATURE2_DSCR, NULL },
  160         { "IBM POWER7+",        IBMPOWER7PLUS,  REVFMT_MAJMIN,
  161            PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
  162            PPC_FEATURE_SMT | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06 |
  163            PPC_FEATURE_HAS_VSX, PPC_FEATURE2_DSCR, NULL },
  164         { "IBM POWER8E",        IBMPOWER8E,     REVFMT_MAJMIN,
  165            PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
  166            PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 |
  167            PPC_FEATURE_ARCH_2_06 | PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE,
  168            PPC_FEATURE2_ARCH_2_07 | PPC_FEATURE2_HTM | PPC_FEATURE2_DSCR | 
  169            PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR | PPC_FEATURE2_HAS_VEC_CRYPTO |
  170            PPC_FEATURE2_HTM_NOSC, cpu_powerx_setup },
  171         { "IBM POWER8",         IBMPOWER8,      REVFMT_MAJMIN,
  172            PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
  173            PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 |
  174            PPC_FEATURE_ARCH_2_06 | PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE,
  175            PPC_FEATURE2_ARCH_2_07 | PPC_FEATURE2_HTM | PPC_FEATURE2_DSCR | 
  176            PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR | PPC_FEATURE2_HAS_VEC_CRYPTO |
  177            PPC_FEATURE2_HTM_NOSC, cpu_powerx_setup },
  178         { "IBM POWER9",         IBMPOWER9,      REVFMT_MAJMIN,
  179            PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
  180            PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | PPC_FEATURE_ARCH_2_05 |
  181            PPC_FEATURE_ARCH_2_06 | PPC_FEATURE_HAS_VSX | PPC_FEATURE_TRUE_LE,
  182            PPC_FEATURE2_ARCH_2_07 | PPC_FEATURE2_HTM | PPC_FEATURE2_DSCR |
  183            PPC_FEATURE2_ISEL | PPC_FEATURE2_TAR | PPC_FEATURE2_HAS_VEC_CRYPTO |
  184            PPC_FEATURE2_ARCH_3_00 | PPC_FEATURE2_HAS_IEEE128 |
  185            PPC_FEATURE2_DARN, cpu_powerx_setup },
  186         { "Motorola PowerPC 7400",      MPC7400,        REVFMT_MAJMIN,
  187            PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  188         { "Motorola PowerPC 7410",      MPC7410,        REVFMT_MAJMIN,
  189            PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  190         { "Motorola PowerPC 7450",      MPC7450,        REVFMT_MAJMIN,
  191            PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  192         { "Motorola PowerPC 7455",      MPC7455,        REVFMT_MAJMIN,
  193            PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  194         { "Motorola PowerPC 7457",      MPC7457,        REVFMT_MAJMIN,
  195            PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  196         { "Motorola PowerPC 7447A",     MPC7447A,       REVFMT_MAJMIN,
  197            PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  198         { "Motorola PowerPC 7448",      MPC7448,        REVFMT_MAJMIN,
  199            PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  200         { "Motorola PowerPC 8240",      MPC8240,        REVFMT_MAJMIN,
  201            PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  202         { "Motorola PowerPC 8245",      MPC8245,        REVFMT_MAJMIN,
  203            PPC_FEATURE_HAS_FPU, 0, cpu_6xx_setup },
  204         { "Freescale e500v1 core",      FSL_E500v1,     REVFMT_MAJMIN,
  205            PPC_FEATURE_HAS_SPE | PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_BOOKE,
  206            PPC_FEATURE2_ISEL, cpu_booke_setup },
  207         { "Freescale e500v2 core",      FSL_E500v2,     REVFMT_MAJMIN,
  208            PPC_FEATURE_HAS_SPE | PPC_FEATURE_BOOKE |
  209            PPC_FEATURE_HAS_EFP_SINGLE | PPC_FEATURE_HAS_EFP_DOUBLE,
  210            PPC_FEATURE2_ISEL, cpu_booke_setup },
  211         { "Freescale e500mc core",      FSL_E500mc,     REVFMT_MAJMIN,
  212            PPC_FEATURE_HAS_FPU | PPC_FEATURE_BOOKE | PPC_FEATURE_ARCH_2_05 |
  213            PPC_FEATURE_ARCH_2_06, PPC_FEATURE2_ISEL,
  214            cpu_booke_setup },
  215         { "Freescale e5500 core",       FSL_E5500,      REVFMT_MAJMIN,
  216            PPC_FEATURE_64 | PPC_FEATURE_HAS_FPU | PPC_FEATURE_BOOKE |
  217            PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06,
  218            PPC_FEATURE2_ISEL, cpu_booke_setup },
  219         { "Freescale e6500 core",       FSL_E6500,      REVFMT_MAJMIN,
  220            PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
  221            PPC_FEATURE_BOOKE | PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_ARCH_2_06,
  222            PPC_FEATURE2_ISEL, cpu_booke_setup },
  223         { "IBM Cell Broadband Engine",  IBMCELLBE,      REVFMT_MAJMIN,
  224            PPC_FEATURE_64 | PPC_FEATURE_HAS_ALTIVEC | PPC_FEATURE_HAS_FPU |
  225            PPC_FEATURE_CELL | PPC_FEATURE_SMT, 0, NULL},
  226         { "Unknown PowerPC CPU",        0,              REVFMT_HEX, 0, 0, NULL },
  227 };
  228 
  229 static void     cpu_6xx_print_cacheinfo(u_int, uint16_t);
  230 static int      cpu_feature_bit(SYSCTL_HANDLER_ARGS);
  231 
  232 static char model[64];
  233 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, model, 0, "");
  234 
  235 static const struct cputab      *cput;
  236 
  237 u_long cpu_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU;
  238 u_long cpu_features2 = 0;
  239 SYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features, CTLFLAG_RD,
  240     &cpu_features, sizeof(cpu_features), "LX", "PowerPC CPU features");
  241 SYSCTL_OPAQUE(_hw, OID_AUTO, cpu_features2, CTLFLAG_RD,
  242     &cpu_features2, sizeof(cpu_features2), "LX", "PowerPC CPU features 2");
  243 
  244 #ifdef __powerpc64__
  245 register_t      lpcr = LPCR_LPES;
  246 #endif
  247 
  248 /* Provide some user-friendly aliases for bits in cpu_features */
  249 SYSCTL_PROC(_hw, OID_AUTO, floatingpoint, CTLTYPE_INT | CTLFLAG_RD,
  250     0, PPC_FEATURE_HAS_FPU, cpu_feature_bit, "I",
  251     "Floating point instructions executed in hardware");
  252 SYSCTL_PROC(_hw, OID_AUTO, altivec, CTLTYPE_INT | CTLFLAG_RD,
  253     0, PPC_FEATURE_HAS_ALTIVEC, cpu_feature_bit, "I", "CPU supports Altivec");
  254 
  255 /*
  256  * Phase 1 (early) CPU setup.  Setup the cpu_features/cpu_features2 variables,
  257  * so they can be used during platform and MMU bringup.
  258  */
  259 void
  260 cpu_feature_setup()
  261 {
  262         u_int           pvr;
  263         uint16_t        vers;
  264         const struct    cputab *cp;
  265 
  266         pvr = mfpvr();
  267         vers = pvr >> 16;
  268         for (cp = models; cp->version != 0; cp++) {
  269                 if (cp->version == vers)
  270                         break;
  271         }
  272 
  273         cput = cp;
  274         cpu_features |= cp->features;
  275         cpu_features2 |= cp->features2;
  276 }
  277 
  278 
  279 void
  280 cpu_setup(u_int cpuid)
  281 {
  282         uint64_t        cps;
  283         const char      *name;
  284         u_int           maj, min, pvr;
  285         uint16_t        rev, revfmt, vers;
  286 
  287         pvr = mfpvr();
  288         vers = pvr >> 16;
  289         rev = pvr;
  290         switch (vers) {
  291                 case MPC7410:
  292                         min = (pvr >> 0) & 0xff;
  293                         maj = min <= 4 ? 1 : 2;
  294                         break;
  295                 case FSL_E500v1:
  296                 case FSL_E500v2:
  297                 case FSL_E500mc:
  298                 case FSL_E5500:
  299                         maj = (pvr >>  4) & 0xf;
  300                         min = (pvr >>  0) & 0xf;
  301                         break;
  302                 default:
  303                         maj = (pvr >>  8) & 0xf;
  304                         min = (pvr >>  0) & 0xf;
  305         }
  306 
  307         revfmt = cput->revfmt;
  308         name = cput->name;
  309         if (rev == MPC750 && pvr == 15) {
  310                 name = "Motorola MPC755";
  311                 revfmt = REVFMT_HEX;
  312         }
  313         strncpy(model, name, sizeof(model) - 1);
  314 
  315         printf("cpu%d: %s revision ", cpuid, name);
  316 
  317         switch (revfmt) {
  318                 case REVFMT_MAJMIN:
  319                         printf("%u.%u", maj, min);
  320                         break;
  321                 case REVFMT_HEX:
  322                         printf("0x%04x", rev);
  323                         break;
  324                 case REVFMT_DEC:
  325                         printf("%u", rev);
  326                         break;
  327         }
  328 
  329         if (cpu_est_clockrate(0, &cps) == 0)
  330                 printf(", %jd.%02jd MHz", cps / 1000000, (cps / 10000) % 100);
  331         printf("\n");
  332 
  333         printf("cpu%d: Features %b\n", cpuid, (int)cpu_features,
  334             PPC_FEATURE_BITMASK);
  335         if (cpu_features2 != 0)
  336                 printf("cpu%d: Features2 %b\n", cpuid, (int)cpu_features2,
  337                     PPC_FEATURE2_BITMASK);
  338 
  339         /*
  340          * Configure CPU
  341          */
  342         if (cput->cpu_setup != NULL)
  343                 cput->cpu_setup(cpuid, vers);
  344 }
  345 
  346 /* Get current clock frequency for the given cpu id. */
  347 int
  348 cpu_est_clockrate(int cpu_id, uint64_t *cps)
  349 {
  350         uint16_t        vers;
  351         register_t      msr;
  352         phandle_t       cpu, dev, root;
  353         int             res  = 0;
  354         char            buf[8];
  355 
  356         vers = mfpvr() >> 16;
  357         msr = mfmsr();
  358         mtmsr(msr & ~PSL_EE);
  359 
  360         switch (vers) {
  361                 case MPC7450:
  362                 case MPC7455:
  363                 case MPC7457:
  364                 case MPC750:
  365                 case IBM750FX:
  366                 case MPC7400:
  367                 case MPC7410:
  368                 case MPC7447A:
  369                 case MPC7448:
  370                         mtspr(SPR_MMCR0, SPR_MMCR0_FC);
  371                         mtspr(SPR_PMC1, 0);
  372                         mtspr(SPR_MMCR0, SPR_MMCR0_PMC1SEL(PMCN_CYCLES));
  373                         DELAY(1000);
  374                         *cps = (mfspr(SPR_PMC1) * 1000) + 4999;
  375                         mtspr(SPR_MMCR0, SPR_MMCR0_FC);
  376 
  377                         mtmsr(msr);
  378                         return (0);
  379                 case IBM970:
  380                 case IBM970FX:
  381                 case IBM970MP:
  382                         isync();
  383                         mtspr(SPR_970MMCR0, SPR_MMCR0_FC);
  384                         isync();
  385                         mtspr(SPR_970MMCR1, 0);
  386                         mtspr(SPR_970MMCRA, 0);
  387                         mtspr(SPR_970PMC1, 0);
  388                         mtspr(SPR_970MMCR0,
  389                             SPR_970MMCR0_PMC1SEL(PMC970N_CYCLES));
  390                         isync();
  391                         DELAY(1000);
  392                         powerpc_sync();
  393                         mtspr(SPR_970MMCR0, SPR_MMCR0_FC);
  394                         *cps = (mfspr(SPR_970PMC1) * 1000) + 4999;
  395 
  396                         mtmsr(msr);
  397                         return (0);
  398 
  399                 default:
  400                         root = OF_peer(0);
  401                         if (root == 0)
  402                                 return (ENXIO);
  403 
  404                         dev = OF_child(root);
  405                         while (dev != 0) {
  406                                 res = OF_getprop(dev, "name", buf, sizeof(buf));
  407                                 if (res > 0 && strcmp(buf, "cpus") == 0)
  408                                         break;
  409                                 dev = OF_peer(dev);
  410                         }
  411                         cpu = OF_child(dev);
  412                         while (cpu != 0) {
  413                                 res = OF_getprop(cpu, "device_type", buf,
  414                                                 sizeof(buf));
  415                                 if (res > 0 && strcmp(buf, "cpu") == 0)
  416                                         break;
  417                                 cpu = OF_peer(cpu);
  418                         }
  419                         if (cpu == 0)
  420                                 return (ENOENT);
  421                         if (OF_getprop(cpu, "ibm,extended-clock-frequency",
  422                             cps, sizeof(*cps)) >= 0) {
  423                                 return (0);
  424                         } else if (OF_getprop(cpu, "clock-frequency", cps, 
  425                             sizeof(cell_t)) >= 0) {
  426                                 *cps >>= 32;
  427                                 return (0);
  428                         } else {
  429                                 return (ENOENT);
  430                         }
  431         }
  432 }
  433 
  434 void
  435 cpu_6xx_setup(int cpuid, uint16_t vers)
  436 {
  437         register_t hid0, pvr;
  438         const char *bitmask;
  439 
  440         hid0 = mfspr(SPR_HID0);
  441         pvr = mfpvr();
  442 
  443         /*
  444          * Configure power-saving mode.
  445          */
  446         switch (vers) {
  447                 case MPC603:
  448                 case MPC603e:
  449                 case MPC603ev:
  450                 case MPC604ev:
  451                 case MPC750:
  452                 case IBM750FX:
  453                 case MPC7400:
  454                 case MPC7410:
  455                 case MPC8240:
  456                 case MPC8245:
  457                         /* Select DOZE mode. */
  458                         hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
  459                         hid0 |= HID0_DOZE | HID0_DPM;
  460                         powerpc_pow_enabled = 1;
  461                         break;
  462 
  463                 case MPC7448:
  464                 case MPC7447A:
  465                 case MPC7457:
  466                 case MPC7455:
  467                 case MPC7450:
  468                         /* Enable the 7450 branch caches */
  469                         hid0 |= HID0_SGE | HID0_BTIC;
  470                         hid0 |= HID0_LRSTK | HID0_FOLD | HID0_BHT;
  471                         /* Disable BTIC on 7450 Rev 2.0 or earlier and on 7457 */
  472                         if (((pvr >> 16) == MPC7450 && (pvr & 0xFFFF) <= 0x0200)
  473                                         || (pvr >> 16) == MPC7457)
  474                                 hid0 &= ~HID0_BTIC;
  475                         /* Select NAP mode. */
  476                         hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
  477                         hid0 |= HID0_NAP | HID0_DPM;
  478                         powerpc_pow_enabled = 1;
  479                         break;
  480 
  481                 default:
  482                         /* No power-saving mode is available. */ ;
  483         }
  484 
  485         switch (vers) {
  486                 case IBM750FX:
  487                 case MPC750:
  488                         hid0 &= ~HID0_DBP;              /* XXX correct? */
  489                         hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT;
  490                         break;
  491 
  492                 case MPC7400:
  493                 case MPC7410:
  494                         hid0 &= ~HID0_SPD;
  495                         hid0 |= HID0_EMCP | HID0_BTIC | HID0_SGE | HID0_BHT;
  496                         hid0 |= HID0_EIEC;
  497                         break;
  498 
  499         }
  500 
  501         mtspr(SPR_HID0, hid0);
  502 
  503         if (bootverbose)
  504                 cpu_6xx_print_cacheinfo(cpuid, vers);
  505 
  506         switch (vers) {
  507                 case MPC7447A:
  508                 case MPC7448:
  509                 case MPC7450:
  510                 case MPC7455:
  511                 case MPC7457:
  512                         bitmask = HID0_7450_BITMASK;
  513                         break;
  514                 default:
  515                         bitmask = HID0_BITMASK;
  516                         break;
  517         }
  518 
  519         printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask);
  520 
  521         if (cpu_idle_hook == NULL)
  522                 cpu_idle_hook = cpu_idle_60x;
  523 }
  524 
  525 
  526 static void
  527 cpu_6xx_print_cacheinfo(u_int cpuid, uint16_t vers)
  528 {
  529         register_t hid;
  530 
  531         hid = mfspr(SPR_HID0);
  532         printf("cpu%u: ", cpuid);
  533         printf("L1 I-cache %sabled, ", (hid & HID0_ICE) ? "en" : "dis");
  534         printf("L1 D-cache %sabled\n", (hid & HID0_DCE) ? "en" : "dis");
  535 
  536         printf("cpu%u: ", cpuid);
  537         if (mfspr(SPR_L2CR) & L2CR_L2E) {
  538                 switch (vers) {
  539                 case MPC7450:
  540                 case MPC7455:
  541                 case MPC7457:
  542                         printf("256KB L2 cache, ");
  543                         if (mfspr(SPR_L3CR) & L3CR_L3E)
  544                                 printf("%cMB L3 backside cache",
  545                                     mfspr(SPR_L3CR) & L3CR_L3SIZ ? '2' : '1');
  546                         else
  547                                 printf("L3 cache disabled");
  548                         printf("\n");
  549                         break;
  550                 case IBM750FX:
  551                         printf("512KB L2 cache\n");
  552                         break; 
  553                 default:
  554                         switch (mfspr(SPR_L2CR) & L2CR_L2SIZ) {
  555                         case L2SIZ_256K:
  556                                 printf("256KB ");
  557                                 break;
  558                         case L2SIZ_512K:
  559                                 printf("512KB ");
  560                                 break;
  561                         case L2SIZ_1M:
  562                                 printf("1MB ");
  563                                 break;
  564                         }
  565                         printf("write-%s", (mfspr(SPR_L2CR) & L2CR_L2WT)
  566                             ? "through" : "back");
  567                         if (mfspr(SPR_L2CR) & L2CR_L2PE)
  568                                 printf(", with parity");
  569                         printf(" backside cache\n");
  570                         break;
  571                 }
  572         } else
  573                 printf("L2 cache disabled\n");
  574 }
  575 
  576 static void
  577 cpu_booke_setup(int cpuid, uint16_t vers)
  578 {
  579 #ifdef BOOKE_E500
  580         register_t hid0;
  581         const char *bitmask;
  582 
  583         hid0 = mfspr(SPR_HID0);
  584 
  585         switch (vers) {
  586         case FSL_E500mc:
  587                 bitmask = HID0_E500MC_BITMASK;
  588                 break;
  589         case FSL_E5500:
  590         case FSL_E6500:
  591                 bitmask = HID0_E5500_BITMASK;
  592                 break;
  593         case FSL_E500v1:
  594         case FSL_E500v2:
  595                 /* Only e500v1/v2 support HID0 power management setup. */
  596 
  597                 /* Program power-management mode. */
  598                 hid0 &= ~(HID0_DOZE | HID0_NAP | HID0_SLEEP);
  599                 hid0 |= HID0_DOZE;
  600 
  601                 mtspr(SPR_HID0, hid0);
  602         default:
  603                 bitmask = HID0_E500_BITMASK;
  604                 break;
  605         }
  606         printf("cpu%d: HID0 %b\n", cpuid, (int)hid0, bitmask);
  607 #endif
  608 
  609         if (cpu_idle_hook == NULL)
  610                 cpu_idle_hook = cpu_idle_booke;
  611 }
  612 
  613 static void
  614 cpu_970_setup(int cpuid, uint16_t vers)
  615 {
  616 #ifdef AIM
  617         uint32_t hid0_hi, hid0_lo;
  618 
  619         __asm __volatile ("mfspr %0,%2; clrldi %1,%0,32; srdi %0,%0,32;"
  620             : "=r" (hid0_hi), "=r" (hid0_lo) : "K" (SPR_HID0));
  621 
  622         /* Configure power-saving mode */
  623         switch (vers) {
  624         case IBM970MP:
  625                 hid0_hi |= (HID0_DEEPNAP | HID0_NAP | HID0_DPM);
  626                 hid0_hi &= ~HID0_DOZE;
  627                 break;
  628         default:
  629                 hid0_hi |= (HID0_NAP | HID0_DPM);
  630                 hid0_hi &= ~(HID0_DOZE | HID0_DEEPNAP);
  631                 break;
  632         }
  633         powerpc_pow_enabled = 1;
  634 
  635         __asm __volatile (" \
  636                 sync; isync;                                    \
  637                 sldi    %0,%0,32; or %0,%0,%1;                  \
  638                 mtspr   %2, %0;                                 \
  639                 mfspr   %0, %2; mfspr   %0, %2; mfspr   %0, %2; \
  640                 mfspr   %0, %2; mfspr   %0, %2; mfspr   %0, %2; \
  641                 sync; isync"
  642             :: "r" (hid0_hi), "r"(hid0_lo), "K" (SPR_HID0));
  643 
  644         __asm __volatile ("mfspr %0,%1; srdi %0,%0,32;"
  645             : "=r" (hid0_hi) : "K" (SPR_HID0));
  646         printf("cpu%d: HID0 %b\n", cpuid, (int)(hid0_hi), HID0_970_BITMASK);
  647 #endif
  648 
  649         cpu_idle_hook = cpu_idle_60x;
  650 }
  651 
  652 static void
  653 cpu_powerx_setup(int cpuid, uint16_t vers)
  654 {
  655 
  656 #if defined(__powerpc64__) && defined(AIM)
  657         if ((mfmsr() & PSL_HV) == 0)
  658                 return;
  659 
  660         /* Configure power-saving */
  661         switch (vers) {
  662         case IBMPOWER8:
  663         case IBMPOWER8E:
  664                 cpu_idle_hook = cpu_idle_powerx;
  665                 mtspr(SPR_LPCR, mfspr(SPR_LPCR) | LPCR_PECE_WAKESET);
  666                 isync();
  667                 break;
  668         case IBMPOWER9:
  669                 cpu_idle_hook = cpu_idle_power9;
  670                 mtspr(SPR_LPCR, mfspr(SPR_LPCR) | LPCR_PECE_WAKESET);
  671                 isync();
  672                 break;
  673         default:
  674                 return;
  675         }
  676 
  677 #endif
  678 }
  679 
  680 static int
  681 cpu_feature_bit(SYSCTL_HANDLER_ARGS)
  682 {
  683         int result;
  684 
  685         result = (cpu_features & arg2) ? 1 : 0;
  686 
  687         return (sysctl_handle_int(oidp, &result, 0, req));
  688 }
  689 
  690 void
  691 cpu_idle(int busy)
  692 {
  693         sbintime_t sbt = -1;
  694 
  695 #ifdef INVARIANTS
  696         if ((mfmsr() & PSL_EE) != PSL_EE) {
  697                 struct thread *td = curthread;
  698                 printf("td msr %#lx\n", (u_long)td->td_md.md_saved_msr);
  699                 panic("ints disabled in idleproc!");
  700         }
  701 #endif
  702 
  703         CTR2(KTR_SPARE2, "cpu_idle(%d) at %d",
  704             busy, curcpu);
  705 
  706         if (cpu_idle_hook != NULL) {
  707                 if (!busy) {
  708                         critical_enter();
  709                         sbt = cpu_idleclock();
  710                 }
  711                 cpu_idle_hook(sbt);
  712                 if (!busy) {
  713                         cpu_activeclock();
  714                         critical_exit();
  715                 }
  716         }
  717 
  718         CTR2(KTR_SPARE2, "cpu_idle(%d) at %d done",
  719             busy, curcpu);
  720 }
  721 
  722 static void
  723 cpu_idle_60x(sbintime_t sbt)
  724 {
  725         register_t msr;
  726         uint16_t vers;
  727 
  728         if (!powerpc_pow_enabled)
  729                 return;
  730 
  731         msr = mfmsr();
  732         vers = mfpvr() >> 16;
  733 
  734 #ifdef AIM
  735         switch (vers) {
  736         case IBM970:
  737         case IBM970FX:
  738         case IBM970MP:
  739         case MPC7447A:
  740         case MPC7448:
  741         case MPC7450:
  742         case MPC7455:
  743         case MPC7457:
  744                 __asm __volatile("\
  745                             dssall; sync; mtmsr %0; isync"
  746                             :: "r"(msr | PSL_POW));
  747                 break;
  748         default:
  749                 powerpc_sync();
  750                 mtmsr(msr | PSL_POW);
  751                 break;
  752         }
  753 #endif
  754 }
  755 
  756 static void
  757 cpu_idle_booke(sbintime_t sbt)
  758 {
  759         register_t msr;
  760         uint16_t vers;
  761 
  762         msr = mfmsr();
  763         vers = mfpvr() >> 16;
  764 
  765 #ifdef BOOKE
  766         switch (vers) {
  767         case FSL_E500mc:
  768         case FSL_E5500:
  769         case FSL_E6500:
  770                 /*
  771                  * Base binutils doesn't know what the 'wait' instruction is, so
  772                  * use the opcode encoding here.
  773                  */
  774                 __asm __volatile(".long 0x7c00007c");
  775                 break;
  776         default:
  777                 powerpc_sync();
  778                 mtmsr(msr | PSL_WE);
  779                 break;
  780         }
  781 #endif
  782 }
  783 
  784 #if defined(__powerpc64__) && defined(AIM)
  785 static void
  786 cpu_idle_powerx(sbintime_t sbt)
  787 {
  788 
  789         /* Sleeping when running on one cpu gives no advantages - avoid it */
  790         if (smp_started == 0)
  791                 return;
  792 
  793         spinlock_enter();
  794         if (sched_runnable()) {
  795                 spinlock_exit();
  796                 return;
  797         }
  798 
  799         if (can_wakeup == 0)
  800                 can_wakeup = 1;
  801         mb();
  802 
  803         enter_idle_powerx();
  804         spinlock_exit();
  805 }
  806 
  807 static void
  808 cpu_idle_power9(sbintime_t sbt)
  809 {
  810         register_t msr;
  811 
  812         msr = mfmsr();
  813 
  814         /* Suspend external interrupts until stop instruction completes. */
  815         mtmsr(msr &  ~PSL_EE);
  816         /* Set the stop state to lowest latency, wake up to next instruction */
  817         mtspr(SPR_PSSCR, 0);
  818         /* "stop" instruction (PowerISA 3.0) */
  819         __asm __volatile (".long 0x4c0002e4");
  820         /*
  821          * Re-enable external interrupts to capture the interrupt that caused
  822          * the wake up.
  823          */
  824         mtmsr(msr);
  825         
  826 }
  827 #endif
  828 
  829 int
  830 cpu_idle_wakeup(int cpu)
  831 {
  832 
  833         return (0);
  834 }

Cache object: e5b7a59cfcdb55c04695e1e804b4bc79


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.