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/mips/mips/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  * Copyright (c) 2004 Juli Mallett.  All rights reserved.
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  *
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD: releng/11.0/sys/mips/mips/cpu.c 294883 2016-01-27 02:23:54Z jhibbits $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/kernel.h>
   32 #include <sys/module.h>
   33 #include <sys/stdint.h>
   34 
   35 #include <sys/bus.h>
   36 #include <sys/rman.h>
   37 #include <sys/sysctl.h>
   38 #include <sys/systm.h>
   39 
   40 #include <vm/vm.h>
   41 #include <vm/vm_page.h>
   42 
   43 #include <machine/cache.h>
   44 #include <machine/cpufunc.h>
   45 #include <machine/cpuinfo.h>
   46 #include <machine/cpuregs.h>
   47 #include <machine/intr_machdep.h>
   48 #include <machine/locore.h>
   49 #include <machine/pte.h>
   50 #include <machine/tlb.h>
   51 #include <machine/hwfunc.h>
   52 
   53 #if defined(CPU_CNMIPS)
   54 #include <contrib/octeon-sdk/cvmx.h>
   55 #include <contrib/octeon-sdk/octeon-model.h>
   56 #endif
   57 
   58 static void cpu_identify(void);
   59 
   60 struct mips_cpuinfo cpuinfo;
   61 
   62 /*
   63  * Attempt to identify the MIPS CPU as much as possible.
   64  *
   65  * XXX: Assumes the CPU is MIPS{32,64}{,r2} compliant.
   66  * XXX: For now, skip config register selections 2 and 3
   67  * as we don't currently use L2/L3 cache or additional
   68  * MIPS32 processor features.
   69  */
   70 static void
   71 mips_get_identity(struct mips_cpuinfo *cpuinfo)
   72 {
   73         u_int32_t prid;
   74         u_int32_t cfg0;
   75         u_int32_t cfg1;
   76 #ifndef CPU_CNMIPS
   77         u_int32_t cfg2;
   78 #endif
   79 #if defined(CPU_CNMIPS)
   80         u_int32_t cfg4;
   81 #endif
   82         u_int32_t tmp;
   83 
   84         memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
   85 
   86         /* Read and store the PrID ID for CPU identification. */
   87         prid = mips_rd_prid();
   88         cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
   89         cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
   90         cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
   91 
   92         /* Read config register selection 0 to learn TLB type. */
   93         cfg0 = mips_rd_config();
   94 
   95         cpuinfo->tlb_type = 
   96             ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
   97         cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
   98 
   99         /* If config register selection 1 does not exist, exit. */
  100         if (!(cfg0 & MIPS_CONFIG_CM))
  101                 return;
  102 
  103         /* Learn TLB size and L1 cache geometry. */
  104         cfg1 = mips_rd_config1();
  105 
  106 #if defined(CPU_NLM)
  107         /* Account for Extended TLB entries in XLP */
  108         tmp = mips_rd_config6();
  109         cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1;
  110 #elif defined(BERI_LARGE_TLB)
  111         /* Check if we support extended TLB entries and if so activate. */
  112         tmp = mips_rd_config5();
  113 #define BERI_CP5_LTLB_SUPPORTED 0x1
  114         if (tmp & BERI_CP5_LTLB_SUPPORTED) {
  115                 /* See how many extra TLB entries we have. */
  116                 tmp = mips_rd_config6();
  117                 cpuinfo->tlb_nentries = (tmp >> 16) + 1;
  118                 /* Activate the extended entries. */
  119                 mips_wr_config6(tmp|0x4);
  120         } else
  121 #endif
  122 #if !defined(CPU_NLM)
  123         cpuinfo->tlb_nentries = 
  124             ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
  125 #endif
  126 #if defined(CPU_CNMIPS)
  127         /* Add extended TLB size information from config4.  */
  128         cfg4 = mips_rd_config4();
  129         if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT)
  130                 cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40;
  131 #endif
  132 
  133         /* L1 instruction cache. */
  134 #ifdef MIPS_DISABLE_L1_CACHE
  135         cpuinfo->l1.ic_linesize = 0;
  136 #else
  137         tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
  138         if (tmp != 0) {
  139                 cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
  140                 cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
  141                 cpuinfo->l1.ic_nsets = 
  142                         1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
  143         }
  144 #endif
  145 
  146         /* L1 data cache. */
  147 #ifdef MIPS_DISABLE_L1_CACHE
  148         cpuinfo->l1.dc_linesize = 0;
  149 #else
  150 #ifndef CPU_CNMIPS
  151         tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
  152         if (tmp != 0) {
  153                 cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
  154                 cpuinfo->l1.dc_nways = 
  155                     (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
  156                 cpuinfo->l1.dc_nsets = 
  157                     1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
  158         }
  159 #else
  160         /*
  161          * Some Octeon cache configuration parameters are by model family, not
  162          * config1.
  163          */
  164         if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
  165                 /* Octeon and Octeon XL.  */
  166                 cpuinfo->l1.dc_nsets = 1;
  167                 cpuinfo->l1.dc_nways = 64;
  168         } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
  169                 /* Octeon Plus.  */
  170                 cpuinfo->l1.dc_nsets = 2;
  171                 cpuinfo->l1.dc_nways = 64;
  172         } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
  173                 /* Octeon II.  */
  174                 cpuinfo->l1.dc_nsets = 8;
  175                 cpuinfo->l1.dc_nways = 32;
  176 
  177                 cpuinfo->l1.ic_nsets = 8;
  178                 cpuinfo->l1.ic_nways = 37;
  179         } else {
  180                 panic("%s: unsupported Cavium Networks CPU.", __func__);
  181         }
  182 
  183         /* All Octeon models use 128 byte line size.  */
  184         cpuinfo->l1.dc_linesize = 128;
  185 #endif
  186 #endif
  187 
  188         cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize
  189             * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways;
  190         cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize 
  191             * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways;
  192 
  193         /*
  194          * Probe PageMask register to see what sizes of pages are supported
  195          * by writing all one's and then reading it back.
  196          */
  197         mips_wr_pagemask(~0);
  198         cpuinfo->tlb_pgmask = mips_rd_pagemask();
  199         mips_wr_pagemask(MIPS3_PGMASK_4K);
  200 
  201 #ifndef CPU_CNMIPS
  202         /* L2 cache */
  203         if (!(cfg1 & MIPS_CONFIG_CM)) {
  204                 /* We don't have valid cfg2 register */
  205                 return;
  206         }
  207 
  208         cfg2 = mips_rd_config2();
  209 
  210         tmp = (cfg2 >> MIPS_CONFIG2_SL_SHIFT) & MIPS_CONFIG2_SL_MASK;
  211         if (0 < tmp && tmp <= 7)
  212                 cpuinfo->l2.dc_linesize = 2 << tmp;
  213 
  214         tmp = (cfg2 >> MIPS_CONFIG2_SS_SHIFT) & MIPS_CONFIG2_SS_MASK;
  215         if (0 <= tmp && tmp <= 7)
  216                 cpuinfo->l2.dc_nsets = 64 << tmp;
  217 
  218         tmp = (cfg2 >> MIPS_CONFIG2_SA_SHIFT) & MIPS_CONFIG2_SA_MASK;
  219         if (0 <= tmp && tmp <= 7)
  220                 cpuinfo->l2.dc_nways = tmp + 1;
  221 
  222         cpuinfo->l2.dc_size = cpuinfo->l2.dc_linesize
  223             * cpuinfo->l2.dc_nsets * cpuinfo->l2.dc_nways;
  224 #endif
  225 }
  226 
  227 void
  228 mips_cpu_init(void)
  229 {
  230         platform_cpu_init();
  231         mips_get_identity(&cpuinfo);
  232         num_tlbentries = cpuinfo.tlb_nentries;
  233         mips_wr_wired(0);
  234         tlb_invalidate_all();
  235         mips_wr_wired(VMWIRED_ENTRIES);
  236         mips_config_cache(&cpuinfo);
  237         mips_vector_init();
  238 
  239         mips_icache_sync_all();
  240         mips_dcache_wbinv_all();
  241         /* Print some info about CPU */
  242         cpu_identify();
  243 }
  244 
  245 static void
  246 cpu_identify(void)
  247 {
  248         uint32_t cfg0, cfg1, cfg2, cfg3;
  249         printf("cpu%d: ", 0);   /* XXX per-cpu */
  250         switch (cpuinfo.cpu_vendor) {
  251         case MIPS_PRID_CID_MTI:
  252                 printf("MIPS Technologies");
  253                 break;
  254         case MIPS_PRID_CID_BROADCOM:
  255         case MIPS_PRID_CID_SIBYTE:
  256                 printf("Broadcom");
  257                 break;
  258         case MIPS_PRID_CID_ALCHEMY:
  259                 printf("AMD");
  260                 break;
  261         case MIPS_PRID_CID_SANDCRAFT:
  262                 printf("Sandcraft");
  263                 break;
  264         case MIPS_PRID_CID_PHILIPS:
  265                 printf("Philips");
  266                 break;
  267         case MIPS_PRID_CID_TOSHIBA:
  268                 printf("Toshiba");
  269                 break;
  270         case MIPS_PRID_CID_LSI:
  271                 printf("LSI");
  272                 break;
  273         case MIPS_PRID_CID_LEXRA:
  274                 printf("Lexra");
  275                 break;
  276         case MIPS_PRID_CID_RMI:
  277                 printf("RMI");
  278                 break;
  279         case MIPS_PRID_CID_CAVIUM:
  280                 printf("Cavium");
  281                 break;
  282         case MIPS_PRID_CID_PREHISTORIC:
  283         default:
  284                 printf("Unknown cid %#x", cpuinfo.cpu_vendor);
  285                 break;
  286         }
  287         printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
  288 
  289         printf("  MMU: ");
  290         if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
  291                 printf("none present\n");
  292         } else {
  293                 if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
  294                         printf("Standard TLB");
  295                 } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
  296                         printf("Standard BAT");
  297                 } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
  298                         printf("Fixed mapping");
  299                 }
  300                 printf(", %d entries ", cpuinfo.tlb_nentries);
  301         }
  302 
  303         if (cpuinfo.tlb_pgmask) {
  304                 printf("(");
  305                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_MASKX)
  306                         printf("1K ");
  307                 printf("4K ");
  308                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16K)
  309                         printf("16K ");
  310                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64K)
  311                         printf("64K ");
  312                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256K)
  313                         printf("256K ");
  314                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_1M)
  315                         printf("1M ");
  316                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_16M)
  317                         printf("16M ");
  318                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_64M)
  319                         printf("64M ");
  320                 if (cpuinfo.tlb_pgmask & MIPS3_PGMASK_256M)
  321                         printf("256M ");
  322                 printf("pg sizes)");
  323         }
  324         printf("\n");
  325 
  326         printf("  L1 i-cache: ");
  327         if (cpuinfo.l1.ic_linesize == 0) {
  328                 printf("disabled");
  329         } else {
  330                 if (cpuinfo.l1.ic_nways == 1) {
  331                         printf("direct-mapped with");
  332                 } else {
  333                         printf ("%d ways of", cpuinfo.l1.ic_nways);
  334                 }
  335                 printf(" %d sets, %d bytes per line\n", 
  336                     cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
  337         }
  338 
  339         printf("  L1 d-cache: ");
  340         if (cpuinfo.l1.dc_linesize == 0) {
  341                 printf("disabled");
  342         } else {
  343                 if (cpuinfo.l1.dc_nways == 1) {
  344                         printf("direct-mapped with");
  345                 } else {
  346                         printf ("%d ways of", cpuinfo.l1.dc_nways);
  347                 }
  348                 printf(" %d sets, %d bytes per line\n", 
  349                     cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
  350         }
  351 
  352         printf("  L2 cache: ");
  353         if (cpuinfo.l2.dc_linesize == 0) {
  354                 printf("disabled\n");
  355         } else {
  356                 printf("%d ways of %d sets, %d bytes per line, "
  357                     "%d KiB total size\n",
  358                     cpuinfo.l2.dc_nways,
  359                     cpuinfo.l2.dc_nsets,
  360                     cpuinfo.l2.dc_linesize,
  361                     cpuinfo.l2.dc_size / 1024);
  362         }
  363 
  364         cfg0 = mips_rd_config();
  365         /* If config register selection 1 does not exist, exit. */
  366         if (!(cfg0 & MIPS_CONFIG_CM))
  367                 return;
  368 
  369         cfg1 = mips_rd_config1();
  370         printf("  Config1=0x%b\n", cfg1, 
  371             "\2\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
  372 
  373         /* If config register selection 2 does not exist, exit. */
  374         if (!(cfg1 & MIPS_CONFIG_CM))
  375                 return;
  376         cfg2 = mips_rd_config2();
  377         /* 
  378          * Config2 contains no useful information other then Config3 
  379          * existence flag
  380          */
  381         printf("  Config2=0x%08x\n", cfg2);
  382 
  383         /* If config register selection 3 does not exist, exit. */
  384         if (!(cfg2 & MIPS_CONFIG_CM))
  385                 return;
  386         cfg3 = mips_rd_config3();
  387 
  388         /* Print Config3 if it contains any useful info */
  389         if (cfg3 & ~(0x80000000))
  390                 printf("  Config3=0x%b\n", cfg3, "\2\2SmartMIPS\1TraceLogic");
  391 }
  392 
  393 static struct rman cpu_hardirq_rman;
  394 
  395 static devclass_t cpu_devclass;
  396 
  397 /*
  398  * Device methods
  399  */
  400 static int cpu_probe(device_t);
  401 static int cpu_attach(device_t);
  402 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
  403                                            rman_res_t, rman_res_t, rman_res_t,
  404                                            u_int);
  405 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
  406                           driver_filter_t *f, driver_intr_t *, void *, 
  407                           void **);
  408 
  409 static device_method_t cpu_methods[] = {
  410         /* Device interface */
  411         DEVMETHOD(device_probe,         cpu_probe),
  412         DEVMETHOD(device_attach,        cpu_attach),
  413         DEVMETHOD(device_detach,        bus_generic_detach),
  414         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  415 
  416         /* Bus interface */
  417         DEVMETHOD(bus_alloc_resource,   cpu_alloc_resource),
  418         DEVMETHOD(bus_setup_intr,       cpu_setup_intr),
  419         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
  420 
  421         { 0, 0 }
  422 };
  423 
  424 static driver_t cpu_driver = {
  425         "cpu", cpu_methods, 1
  426 };
  427 
  428 static int
  429 cpu_probe(device_t dev)
  430 {
  431 
  432         return (0);
  433 }
  434 
  435 static int
  436 cpu_attach(device_t dev)
  437 {
  438         int error;
  439 #ifdef notyet
  440         device_t clock;
  441 #endif
  442 
  443         cpu_hardirq_rman.rm_start = 0;
  444         cpu_hardirq_rman.rm_end = 5;
  445         cpu_hardirq_rman.rm_type = RMAN_ARRAY;
  446         cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
  447 
  448         error = rman_init(&cpu_hardirq_rman);
  449         if (error != 0) {
  450                 device_printf(dev, "failed to initialize irq resources\n");
  451                 return (error);
  452         }
  453         /* XXX rman_manage_all. */
  454         error = rman_manage_region(&cpu_hardirq_rman,
  455                                    cpu_hardirq_rman.rm_start,
  456                                    cpu_hardirq_rman.rm_end);
  457         if (error != 0) {
  458                 device_printf(dev, "failed to manage irq resources\n");
  459                 return (error);
  460         }
  461 
  462         if (device_get_unit(dev) != 0)
  463                 panic("can't attach more cpus");
  464         device_set_desc(dev, "MIPS32 processor");
  465 
  466 #ifdef notyet
  467         clock = device_add_child(dev, "clock", device_get_unit(dev));
  468         if (clock == NULL)
  469                 device_printf(dev, "clock failed to attach");
  470 #endif
  471 
  472         return (bus_generic_attach(dev));
  473 }
  474 
  475 static struct resource *
  476 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
  477                    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
  478 {
  479         struct resource *res;
  480 
  481         if (type != SYS_RES_IRQ)
  482                 return (NULL);
  483         res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
  484                                     child);
  485         return (res);
  486 }
  487 
  488 static int
  489 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
  490                driver_filter_t *filt, driver_intr_t *handler, void *arg, 
  491                void **cookiep)
  492 {
  493         int error;
  494         int intr;
  495 
  496         error = rman_activate_resource(res);
  497         if (error != 0) {
  498                 device_printf(child, "could not activate irq\n");
  499                 return (error);
  500         }
  501 
  502         intr = rman_get_start(res);
  503 
  504         cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg, 
  505             intr, flags, cookiep);
  506         device_printf(child, "established CPU interrupt %d\n", intr);
  507         return (0);
  508 }
  509 
  510 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);

Cache object: 7d06a951a47706c531988890d8a6bf00


[ 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.