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

Cache object: 35c54fe2a637ede257e538476c07def2


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