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

Cache object: dda36ecf7c0ee0291b27241f3b92bf54


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