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/9.0/sys/mips/mips/cpu.c 224115 2011-07-16 20:31:29Z jchandra $");
   29 
   30 #include "opt_cputype.h"
   31 
   32 #include <sys/param.h>
   33 #include <sys/kernel.h>
   34 #include <sys/module.h>
   35 #include <sys/stdint.h>
   36 
   37 #include <sys/bus.h>
   38 #include <sys/rman.h>
   39 #include <sys/sysctl.h>
   40 #include <sys/systm.h>
   41 
   42 #include <vm/vm.h>
   43 #include <vm/vm_page.h>
   44 
   45 #include <machine/cache.h>
   46 #include <machine/cpufunc.h>
   47 #include <machine/cpuinfo.h>
   48 #include <machine/cpuregs.h>
   49 #include <machine/intr_machdep.h>
   50 #include <machine/locore.h>
   51 #include <machine/pte.h>
   52 #include <machine/tlb.h>
   53 #include <machine/hwfunc.h>
   54 
   55 #if defined(CPU_CNMIPS)
   56 #include <contrib/octeon-sdk/cvmx.h>
   57 #include <contrib/octeon-sdk/octeon-model.h>
   58 #endif
   59 
   60 static void cpu_identify(void);
   61 
   62 struct mips_cpuinfo cpuinfo;
   63 
   64 /*
   65  * Attempt to identify the MIPS CPU as much as possible.
   66  *
   67  * XXX: Assumes the CPU is MIPS{32,64}{,r2} compliant.
   68  * XXX: For now, skip config register selections 2 and 3
   69  * as we don't currently use L2/L3 cache or additional
   70  * MIPS32 processor features.
   71  */
   72 static void
   73 mips_get_identity(struct mips_cpuinfo *cpuinfo)
   74 {
   75         u_int32_t prid;
   76         u_int32_t cfg0;
   77         u_int32_t cfg1;
   78 #if defined(CPU_CNMIPS)
   79         u_int32_t cfg4;
   80 #endif
   81         u_int32_t tmp;
   82 
   83         memset(cpuinfo, 0, sizeof(struct mips_cpuinfo));
   84 
   85         /* Read and store the PrID ID for CPU identification. */
   86         prid = mips_rd_prid();
   87         cpuinfo->cpu_vendor = MIPS_PRID_CID(prid);
   88         cpuinfo->cpu_rev = MIPS_PRID_REV(prid);
   89         cpuinfo->cpu_impl = MIPS_PRID_IMPL(prid);
   90 
   91         /* Read config register selection 0 to learn TLB type. */
   92         cfg0 = mips_rd_config();
   93 
   94         cpuinfo->tlb_type = 
   95             ((cfg0 & MIPS_CONFIG0_MT_MASK) >> MIPS_CONFIG0_MT_SHIFT);
   96         cpuinfo->icache_virtual = cfg0 & MIPS_CONFIG0_VI;
   97 
   98         /* If config register selection 1 does not exist, exit. */
   99         if (!(cfg0 & MIPS3_CONFIG_CM))
  100                 return;
  101 
  102         /* Learn TLB size and L1 cache geometry. */
  103         cfg1 = mips_rd_config1();
  104 #ifndef CPU_NLM
  105         cpuinfo->tlb_nentries = 
  106             ((cfg1 & MIPS_CONFIG1_TLBSZ_MASK) >> MIPS_CONFIG1_TLBSZ_SHIFT) + 1;
  107 #else
  108         /* Account for Extended TLB entries in XLP */
  109         tmp = mips_rd_config6();
  110         cpuinfo->tlb_nentries = ((tmp >> 16) & 0xffff) + 1;
  111 #endif
  112 
  113         /* Add extended TLB size information from config4.  */
  114 #if defined(CPU_CNMIPS)
  115         cfg4 = mips_rd_config4();
  116         if ((cfg4 & MIPS_CONFIG4_MMUEXTDEF) == MIPS_CONFIG4_MMUEXTDEF_MMUSIZEEXT)
  117                 cpuinfo->tlb_nentries += (cfg4 & MIPS_CONFIG4_MMUSIZEEXT) * 0x40;
  118 #endif
  119 
  120         /* L1 instruction cache. */
  121         tmp = (cfg1 & MIPS_CONFIG1_IL_MASK) >> MIPS_CONFIG1_IL_SHIFT;
  122         if (tmp != 0) {
  123                 cpuinfo->l1.ic_linesize = 1 << (tmp + 1);
  124                 cpuinfo->l1.ic_nways = (((cfg1 & MIPS_CONFIG1_IA_MASK) >> MIPS_CONFIG1_IA_SHIFT)) + 1;
  125                 cpuinfo->l1.ic_nsets = 
  126                         1 << (((cfg1 & MIPS_CONFIG1_IS_MASK) >> MIPS_CONFIG1_IS_SHIFT) + 6);
  127         }
  128 
  129 #ifndef CPU_CNMIPS
  130         /* L1 data cache. */
  131         tmp = (cfg1 & MIPS_CONFIG1_DL_MASK) >> MIPS_CONFIG1_DL_SHIFT;
  132         if (tmp != 0) {
  133                 cpuinfo->l1.dc_linesize = 1 << (tmp + 1);
  134                 cpuinfo->l1.dc_nways = 
  135                     (((cfg1 & MIPS_CONFIG1_DA_MASK) >> MIPS_CONFIG1_DA_SHIFT)) + 1;
  136                 cpuinfo->l1.dc_nsets = 
  137                     1 << (((cfg1 & MIPS_CONFIG1_DS_MASK) >> MIPS_CONFIG1_DS_SHIFT) + 6);
  138         }
  139 #else
  140         /*
  141          * Some Octeon cache configuration parameters are by model family, not
  142          * config1.
  143          */
  144         if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
  145                 /* Octeon and Octeon XL.  */
  146                 cpuinfo->l1.dc_nsets = 1;
  147                 cpuinfo->l1.dc_nways = 64;
  148         } else if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) {
  149                 /* Octeon Plus.  */
  150                 cpuinfo->l1.dc_nsets = 2;
  151                 cpuinfo->l1.dc_nways = 64;
  152         } else if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) {
  153                 /* Octeon II.  */
  154                 cpuinfo->l1.dc_nsets = 8;
  155                 cpuinfo->l1.dc_nways = 32;
  156 
  157                 cpuinfo->l1.ic_nsets = 8;
  158                 cpuinfo->l1.ic_nways = 37;
  159         } else {
  160                 panic("%s: unsupported Cavium Networks CPU.", __func__);
  161         }
  162 
  163         /* All Octeon models use 128 byte line size.  */
  164         cpuinfo->l1.dc_linesize = 128;
  165 #endif
  166 
  167         cpuinfo->l1.ic_size = cpuinfo->l1.ic_linesize
  168             * cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_nways;
  169         cpuinfo->l1.dc_size = cpuinfo->l1.dc_linesize 
  170             * cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_nways;
  171 }
  172 
  173 void
  174 mips_cpu_init(void)
  175 {
  176         platform_cpu_init();
  177         mips_get_identity(&cpuinfo);
  178         num_tlbentries = cpuinfo.tlb_nentries;
  179         mips_wr_wired(0);
  180         tlb_invalidate_all();
  181         mips_wr_wired(VMWIRED_ENTRIES);
  182         mips_config_cache(&cpuinfo);
  183         mips_vector_init();
  184 
  185         mips_icache_sync_all();
  186         mips_dcache_wbinv_all();
  187         /* Print some info about CPU */
  188         cpu_identify();
  189 }
  190 
  191 static void
  192 cpu_identify(void)
  193 {
  194         uint32_t cfg0, cfg1, cfg2, cfg3;
  195         printf("cpu%d: ", 0);   /* XXX per-cpu */
  196         switch (cpuinfo.cpu_vendor) {
  197         case MIPS_PRID_CID_MTI:
  198                 printf("MIPS Technologies");
  199                 break;
  200         case MIPS_PRID_CID_BROADCOM:
  201         case MIPS_PRID_CID_SIBYTE:
  202                 printf("Broadcom");
  203                 break;
  204         case MIPS_PRID_CID_ALCHEMY:
  205                 printf("AMD");
  206                 break;
  207         case MIPS_PRID_CID_SANDCRAFT:
  208                 printf("Sandcraft");
  209                 break;
  210         case MIPS_PRID_CID_PHILIPS:
  211                 printf("Philips");
  212                 break;
  213         case MIPS_PRID_CID_TOSHIBA:
  214                 printf("Toshiba");
  215                 break;
  216         case MIPS_PRID_CID_LSI:
  217                 printf("LSI");
  218                 break;
  219         case MIPS_PRID_CID_LEXRA:
  220                 printf("Lexra");
  221                 break;
  222         case MIPS_PRID_CID_RMI:
  223                 printf("RMI");
  224                 break;
  225         case MIPS_PRID_CID_CAVIUM:
  226                 printf("Cavium");
  227                 break;
  228         case MIPS_PRID_CID_PREHISTORIC:
  229         default:
  230                 printf("Unknown cid %#x", cpuinfo.cpu_vendor);
  231                 break;
  232         }
  233         printf(" processor v%d.%d\n", cpuinfo.cpu_rev, cpuinfo.cpu_impl);
  234 
  235         printf("  MMU: ");
  236         if (cpuinfo.tlb_type == MIPS_MMU_NONE) {
  237                 printf("none present\n");
  238         } else {
  239                 if (cpuinfo.tlb_type == MIPS_MMU_TLB) {
  240                         printf("Standard TLB");
  241                 } else if (cpuinfo.tlb_type == MIPS_MMU_BAT) {
  242                         printf("Standard BAT");
  243                 } else if (cpuinfo.tlb_type == MIPS_MMU_FIXED) {
  244                         printf("Fixed mapping");
  245                 }
  246                 printf(", %d entries\n", cpuinfo.tlb_nentries);
  247         }
  248 
  249         printf("  L1 i-cache: ");
  250         if (cpuinfo.l1.ic_linesize == 0) {
  251                 printf("disabled");
  252         } else {
  253                 if (cpuinfo.l1.ic_nways == 1) {
  254                         printf("direct-mapped with");
  255                 } else {
  256                         printf ("%d ways of", cpuinfo.l1.ic_nways);
  257                 }
  258                 printf(" %d sets, %d bytes per line\n", 
  259                     cpuinfo.l1.ic_nsets, cpuinfo.l1.ic_linesize);
  260         }
  261 
  262         printf("  L1 d-cache: ");
  263         if (cpuinfo.l1.dc_linesize == 0) {
  264                 printf("disabled");
  265         } else {
  266                 if (cpuinfo.l1.dc_nways == 1) {
  267                         printf("direct-mapped with");
  268                 } else {
  269                         printf ("%d ways of", cpuinfo.l1.dc_nways);
  270                 }
  271                 printf(" %d sets, %d bytes per line\n", 
  272                     cpuinfo.l1.dc_nsets, cpuinfo.l1.dc_linesize);
  273         }
  274 
  275         cfg0 = mips_rd_config();
  276         /* If config register selection 1 does not exist, exit. */
  277         if (!(cfg0 & MIPS3_CONFIG_CM))
  278                 return;
  279 
  280         cfg1 = mips_rd_config1();
  281         printf("  Config1=0x%b\n", cfg1, 
  282             "\2\7COP2\6MDMX\5PerfCount\4WatchRegs\3MIPS16\2EJTAG\1FPU");
  283 
  284         /* If config register selection 2 does not exist, exit. */
  285         if (!(cfg1 & MIPS3_CONFIG_CM))
  286                 return;
  287         cfg2 = mips_rd_config2();
  288         /* 
  289          * Config2 contains no useful information other then Config3 
  290          * existence flag
  291          */
  292 
  293         /* If config register selection 3 does not exist, exit. */
  294         if (!(cfg2 & MIPS3_CONFIG_CM))
  295                 return;
  296         cfg3 = mips_rd_config3();
  297 
  298         /* Print Config3 if it contains any useful info */
  299         if (cfg3 & ~(0x80000000))
  300                 printf("  Config3=0x%b\n", cfg3, "\2\2SmartMIPS\1TraceLogic");
  301 }
  302 
  303 static struct rman cpu_hardirq_rman;
  304 
  305 static devclass_t cpu_devclass;
  306 
  307 /*
  308  * Device methods
  309  */
  310 static int cpu_probe(device_t);
  311 static int cpu_attach(device_t);
  312 static struct resource *cpu_alloc_resource(device_t, device_t, int, int *,
  313                                            u_long, u_long, u_long, u_int);
  314 static int cpu_setup_intr(device_t, device_t, struct resource *, int,
  315                           driver_filter_t *f, driver_intr_t *, void *, 
  316                           void **);
  317 
  318 static device_method_t cpu_methods[] = {
  319         /* Device interface */
  320         DEVMETHOD(device_probe,         cpu_probe),
  321         DEVMETHOD(device_attach,        cpu_attach),
  322         DEVMETHOD(device_detach,        bus_generic_detach),
  323         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  324 
  325         /* Bus interface */
  326         DEVMETHOD(bus_alloc_resource,   cpu_alloc_resource),
  327         DEVMETHOD(bus_setup_intr,       cpu_setup_intr),
  328         DEVMETHOD(bus_teardown_intr,    bus_generic_teardown_intr),
  329 
  330         { 0, 0 }
  331 };
  332 
  333 static driver_t cpu_driver = {
  334         "cpu", cpu_methods, 1
  335 };
  336 
  337 static int
  338 cpu_probe(device_t dev)
  339 {
  340         return (0);
  341 }
  342 
  343 static int
  344 cpu_attach(device_t dev)
  345 {
  346         int error;
  347 #ifdef notyet
  348         device_t clock;
  349 #endif
  350 
  351         cpu_hardirq_rman.rm_start = 0;
  352         cpu_hardirq_rman.rm_end = 5;
  353         cpu_hardirq_rman.rm_type = RMAN_ARRAY;
  354         cpu_hardirq_rman.rm_descr = "CPU Hard Interrupts";
  355 
  356         error = rman_init(&cpu_hardirq_rman);
  357         if (error != 0) {
  358                 device_printf(dev, "failed to initialize irq resources\n");
  359                 return (error);
  360         }
  361         /* XXX rman_manage_all. */
  362         error = rman_manage_region(&cpu_hardirq_rman,
  363                                    cpu_hardirq_rman.rm_start,
  364                                    cpu_hardirq_rman.rm_end);
  365         if (error != 0) {
  366                 device_printf(dev, "failed to manage irq resources\n");
  367                 return (error);
  368         }
  369 
  370         if (device_get_unit(dev) != 0)
  371                 panic("can't attach more cpus");
  372         device_set_desc(dev, "MIPS32 processor");
  373 
  374 #ifdef notyet
  375         clock = device_add_child(dev, "clock", device_get_unit(dev));
  376         if (clock == NULL)
  377                 device_printf(dev, "clock failed to attach");
  378 #endif
  379 
  380         return (bus_generic_attach(dev));
  381 }
  382 
  383 static struct resource *
  384 cpu_alloc_resource(device_t dev, device_t child, int type, int *rid,
  385                    u_long start, u_long end, u_long count, u_int flags)
  386 {
  387         struct resource *res;
  388 
  389         if (type != SYS_RES_IRQ)
  390                 return (NULL);
  391         res = rman_reserve_resource(&cpu_hardirq_rman, start, end, count, 0,
  392                                     child);
  393         return (res);
  394 }
  395 
  396 static int
  397 cpu_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
  398                driver_filter_t *filt, driver_intr_t *handler, void *arg, 
  399                void **cookiep)
  400 {
  401         int error;
  402         int intr;
  403 
  404         error = rman_activate_resource(res);
  405         if (error != 0) {
  406                 device_printf(child, "could not activate irq\n");
  407                 return (error);
  408         }
  409 
  410         intr = rman_get_start(res);
  411 
  412         cpu_establish_hardintr(device_get_nameunit(child), filt, handler, arg, 
  413             intr, flags, cookiep);
  414         device_printf(child, "established CPU interrupt %d\n", intr);
  415         return (0);
  416 }
  417 
  418 DRIVER_MODULE(cpu, root, cpu_driver, cpu_devclass, 0, 0);

Cache object: 8936797c6a0d30e490d41765ce26de9f


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