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/sparc64/sparc64/mp_machdep.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) 1997 Berkeley Software Design, Inc. 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  * 3. Berkeley Software Design Inc's name may not be used to endorse or
   13  *    promote products derived from this software without specific prior
   14  *    written permission.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN INC ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN INC BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  * from BSDI: locore.s,v 1.36.2.15 1999/08/23 22:34:41 cp Exp
   29  */
   30 /*-
   31  * Copyright (c) 2002 Jake Burkholder.
   32  * All rights reserved.
   33  *
   34  * Redistribution and use in source and binary forms, with or without
   35  * modification, are permitted provided that the following conditions
   36  * are met:
   37  * 1. Redistributions of source code must retain the above copyright
   38  *    notice, this list of conditions and the following disclaimer.
   39  * 2. Redistributions in binary form must reproduce the above copyright
   40  *    notice, this list of conditions and the following disclaimer in the
   41  *    documentation and/or other materials provided with the distribution.
   42  *
   43  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   44  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   45  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   46  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   47  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   48  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   49  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   50  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   51  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   52  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   53  * SUCH DAMAGE.
   54  *
   55  * $FreeBSD: releng/5.2/sys/sparc64/sparc64/mp_machdep.c 123126 2003-12-03 14:57:26Z jhb $
   56  */
   57 
   58 #include "opt_ddb.h"
   59 
   60 #include <sys/param.h>
   61 #include <sys/systm.h>
   62 #include <sys/lock.h>
   63 #include <sys/kernel.h>
   64 #include <sys/ktr.h>
   65 #include <sys/mutex.h>
   66 #include <sys/pcpu.h>
   67 #include <sys/proc.h>
   68 #include <sys/smp.h>
   69 
   70 #include <vm/vm.h>
   71 #include <vm/vm_param.h>
   72 #include <vm/pmap.h>
   73 #include <vm/vm_kern.h>
   74 #include <vm/vm_extern.h>
   75 #include <vm/vm_map.h>
   76 
   77 #include <dev/ofw/openfirm.h>
   78 
   79 #include <ddb/ddb.h>
   80 
   81 #include <machine/asi.h>
   82 #include <machine/atomic.h>
   83 #include <machine/bus.h>
   84 #include <machine/md_var.h>
   85 #include <machine/metadata.h>
   86 #include <machine/ofw_machdep.h>
   87 #include <machine/smp.h>
   88 #include <machine/tick.h>
   89 #include <machine/tlb.h>
   90 #include <machine/tte.h>
   91 
   92 static ih_func_t cpu_ipi_ast;
   93 static ih_func_t cpu_ipi_stop;
   94 
   95 /*
   96  * Argument area used to pass data to non-boot processors as they start up.
   97  * This must be statically initialized with a known invalid upa module id,
   98  * since the other processors will use it before the boot cpu enters the
   99  * kernel.
  100  */
  101 struct  cpu_start_args cpu_start_args = { 0, -1, -1, 0, 0 };
  102 struct  ipi_cache_args ipi_cache_args;
  103 struct  ipi_tlb_args ipi_tlb_args;
  104 
  105 struct  mtx ipi_mtx;
  106 
  107 vm_offset_t mp_tramp;
  108 
  109 u_int   mp_boot_mid;
  110 
  111 static volatile u_int   shutdown_cpus;
  112 
  113 void cpu_mp_unleash(void *);
  114 SYSINIT(cpu_mp_unleash, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL);
  115 
  116 vm_offset_t
  117 mp_tramp_alloc(void)
  118 {
  119         struct tte *tp;
  120         char *v;
  121         int i;
  122 
  123         v = OF_claim(NULL, PAGE_SIZE, PAGE_SIZE);
  124         if (v == NULL)
  125                 panic("mp_tramp_alloc");
  126         bcopy(mp_tramp_code, v, mp_tramp_code_len);
  127         *(u_long *)(v + mp_tramp_tlb_slots) = kernel_tlb_slots;
  128         *(u_long *)(v + mp_tramp_func) = (u_long)mp_startup;
  129         tp = (struct tte *)(v + mp_tramp_code_len);
  130         for (i = 0; i < kernel_tlb_slots; i++) {
  131                 tp[i].tte_vpn = TV_VPN(kernel_tlbs[i].te_va, TS_4M);
  132                 tp[i].tte_data = TD_V | TD_4M | TD_PA(kernel_tlbs[i].te_pa) |
  133                     TD_L | TD_CP | TD_CV | TD_P | TD_W;
  134         }
  135         for (i = 0; i < PAGE_SIZE; i += sizeof(long))
  136                 flush(v + i);
  137         return (vm_offset_t)v;
  138 }
  139 
  140 /*
  141  * Probe for other cpus.
  142  */
  143 void
  144 cpu_mp_setmaxid(void)
  145 {
  146         phandle_t child;
  147         phandle_t root;
  148         char buf[128];
  149         int cpus;
  150 
  151         all_cpus = 1 << PCPU_GET(cpuid);
  152         mp_boot_mid = PCPU_GET(mid);
  153         mp_ncpus = 1;
  154 
  155         cpus = 0;
  156         root = OF_peer(0);
  157         for (child = OF_child(root); child != 0; child = OF_peer(child)) {
  158                 if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 &&
  159                     strcmp(buf, "cpu") == 0)
  160                         cpus++;
  161         }
  162         mp_maxid = cpus - 1;
  163 }
  164 
  165 int
  166 cpu_mp_probe(void)
  167 {
  168 
  169         return (mp_maxid > 0);
  170 }
  171 
  172 static void
  173 sun4u_startcpu(phandle_t cpu, void *func, u_long arg)
  174 {
  175         static struct {
  176                 cell_t  name;
  177                 cell_t  nargs;
  178                 cell_t  nreturns;
  179                 cell_t  cpu;
  180                 cell_t  func;
  181                 cell_t  arg;
  182         } args = {
  183                 (cell_t)"SUNW,start-cpu",
  184                 3,
  185                 0,
  186                 0,
  187                 0,
  188                 0
  189         };
  190 
  191         args.cpu = cpu;
  192         args.func = (cell_t)func;
  193         args.arg = (cell_t)arg;
  194         openfirmware(&args);
  195 }
  196 
  197 /*
  198  * Stop the calling CPU.
  199  */
  200 static void
  201 sun4u_stopself(void)
  202 {
  203         static struct {
  204                 cell_t  name;
  205                 cell_t  nargs;
  206                 cell_t  nreturns;
  207         } args = {
  208                 (cell_t)"SUNW,stop-self",
  209                 0,
  210                 0,
  211         };
  212 
  213         openfirmware_exit(&args);
  214         panic("sun4u_stopself: failed.");
  215 }
  216 
  217 /*
  218  * Fire up any non-boot processors.
  219  */
  220 void
  221 cpu_mp_start(void)
  222 {
  223         volatile struct cpu_start_args *csa;
  224         struct pcpu *pc;
  225         phandle_t child;
  226         phandle_t root;
  227         vm_offset_t va;
  228         char buf[128];
  229         u_int clock;
  230         int cpuid;
  231         u_int mid;
  232         u_long s;
  233 
  234         mtx_init(&ipi_mtx, "ipi", NULL, MTX_SPIN);
  235 
  236         intr_setup(PIL_AST, cpu_ipi_ast, -1, NULL, NULL);
  237         intr_setup(PIL_RENDEZVOUS, (ih_func_t *)smp_rendezvous_action,
  238             -1, NULL, NULL);
  239         intr_setup(PIL_STOP, cpu_ipi_stop, -1, NULL, NULL);
  240 
  241         root = OF_peer(0);
  242         csa = &cpu_start_args;
  243         for (child = OF_child(root); child != 0; child = OF_peer(child)) {
  244                 if (OF_getprop(child, "device_type", buf, sizeof(buf)) <= 0 ||
  245                     strcmp(buf, "cpu") != 0)
  246                         continue;
  247                 if (OF_getprop(child, "upa-portid", &mid, sizeof(mid)) <= 0 &&
  248                     OF_getprop(child, "portid", &mid, sizeof(mid)) <= 0)
  249                         panic("cpu_mp_start: can't get module id");
  250                 if (mid == mp_boot_mid)
  251                         continue;
  252                 if (OF_getprop(child, "clock-frequency", &clock,
  253                     sizeof(clock)) <= 0)
  254                         panic("cpu_mp_start: can't get clock");
  255 
  256                 csa->csa_state = 0;
  257                 sun4u_startcpu(child, (void *)mp_tramp, 0);
  258                 s = intr_disable();
  259                 while (csa->csa_state != CPU_CLKSYNC)
  260                         ;
  261                 membar(StoreLoad);
  262                 csa->csa_tick = rd(tick);
  263                 while (csa->csa_state != CPU_INIT)
  264                         ;
  265                 csa->csa_tick = 0;
  266                 intr_restore(s);
  267 
  268                 cpuid = mp_ncpus++;
  269                 cpu_identify(csa->csa_ver, clock, cpuid);
  270 
  271                 va = kmem_alloc(kernel_map, PCPU_PAGES * PAGE_SIZE);
  272                 pc = (struct pcpu *)(va + (PCPU_PAGES * PAGE_SIZE)) - 1;
  273                 pcpu_init(pc, cpuid, sizeof(*pc));
  274                 pc->pc_addr = va;
  275                 pc->pc_mid = mid;
  276                 pc->pc_node = child;
  277 
  278                 all_cpus |= 1 << cpuid;
  279         }
  280         PCPU_SET(other_cpus, all_cpus & ~(1 << PCPU_GET(cpuid)));
  281         smp_active = 1;
  282 }
  283 
  284 void
  285 cpu_mp_announce(void)
  286 {
  287 }
  288 
  289 void
  290 cpu_mp_unleash(void *v)
  291 {
  292         volatile struct cpu_start_args *csa;
  293         struct pcpu *pc;
  294         vm_offset_t va;
  295         vm_paddr_t pa;
  296         u_int ctx_min;
  297         u_int ctx_inc;
  298         u_long s;
  299         int i;
  300 
  301         ctx_min = TLB_CTX_USER_MIN;
  302         ctx_inc = (TLB_CTX_USER_MAX - 1) / mp_ncpus;
  303         csa = &cpu_start_args;
  304         csa->csa_count = mp_ncpus;
  305         SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
  306                 pc->pc_tlb_ctx = ctx_min;
  307                 pc->pc_tlb_ctx_min = ctx_min;
  308                 pc->pc_tlb_ctx_max = ctx_min + ctx_inc;
  309                 ctx_min += ctx_inc;
  310 
  311                 if (pc->pc_cpuid == PCPU_GET(cpuid))
  312                         continue;
  313                 KASSERT(pc->pc_idlethread != NULL,
  314                     ("cpu_mp_unleash: idlethread"));
  315                 KASSERT(pc->pc_curthread == pc->pc_idlethread,
  316                     ("cpu_mp_unleash: curthread"));
  317         
  318                 pc->pc_curpcb = pc->pc_curthread->td_pcb;
  319                 for (i = 0; i < PCPU_PAGES; i++) {
  320                         va = pc->pc_addr + i * PAGE_SIZE;
  321                         pa = pmap_kextract(va);
  322                         if (pa == 0)
  323                                 panic("cpu_mp_unleash: pmap_kextract\n");
  324                         csa->csa_ttes[i].tte_vpn = TV_VPN(va, TS_8K);
  325                         csa->csa_ttes[i].tte_data = TD_V | TD_8K | TD_PA(pa) |
  326                             TD_L | TD_CP | TD_CV | TD_P | TD_W;
  327                 }
  328                 csa->csa_state = 0;
  329                 csa->csa_pcpu = pc->pc_addr;
  330                 csa->csa_mid = pc->pc_mid;
  331                 s = intr_disable();
  332                 while (csa->csa_state != CPU_BOOTSTRAP)
  333                         ;
  334                 intr_restore(s);
  335         }
  336 
  337         membar(StoreLoad);
  338         csa->csa_count = 0; 
  339         smp_started = 1;
  340 }
  341 
  342 void
  343 cpu_mp_bootstrap(struct pcpu *pc)
  344 {
  345         volatile struct cpu_start_args *csa;
  346 
  347         csa = &cpu_start_args;
  348         pmap_map_tsb();
  349         cpu_setregs(pc);
  350         tick_start_ap();
  351 
  352         smp_cpus++;
  353         PCPU_SET(other_cpus, all_cpus & ~(1 << PCPU_GET(cpuid)));
  354         printf("SMP: AP CPU #%d Launched!\n", PCPU_GET(cpuid));
  355 
  356         csa->csa_count--;
  357         membar(StoreLoad);
  358         csa->csa_state = CPU_BOOTSTRAP;
  359         while (csa->csa_count != 0)
  360                 ;
  361 
  362         binuptime(PCPU_PTR(switchtime));
  363         PCPU_SET(switchticks, ticks);
  364 
  365         /* ok, now grab sched_lock and enter the scheduler */
  366         mtx_lock_spin(&sched_lock);
  367         cpu_throw(NULL, choosethread());        /* doesn't return */
  368 }
  369 
  370 void
  371 cpu_mp_shutdown(void)
  372 {
  373         int i;
  374 
  375         critical_enter();
  376         shutdown_cpus = PCPU_GET(other_cpus);
  377         if (stopped_cpus != PCPU_GET(other_cpus))       /* XXX */
  378                 stop_cpus(stopped_cpus ^ PCPU_GET(other_cpus));
  379         i = 0;
  380         while (shutdown_cpus != 0) {
  381                 if (i++ > 100000) {
  382                         printf("timeout shutting down CPUs.\n");
  383                         break;
  384                 }
  385         }
  386         /* XXX: delay a bit to allow the CPUs to actually enter the PROM. */
  387         DELAY(100000);
  388         critical_exit();
  389 }
  390 
  391 static void
  392 cpu_ipi_ast(struct trapframe *tf)
  393 {
  394 }
  395 
  396 static void
  397 cpu_ipi_stop(struct trapframe *tf)
  398 {
  399 
  400         CTR1(KTR_SMP, "cpu_ipi_stop: stopped %d", PCPU_GET(cpuid));
  401         atomic_set_acq_int(&stopped_cpus, PCPU_GET(cpumask));
  402         while ((started_cpus & PCPU_GET(cpumask)) == 0) {
  403                 if ((shutdown_cpus & PCPU_GET(cpumask)) != 0) {
  404                         atomic_clear_int(&shutdown_cpus, PCPU_GET(cpumask));
  405                         sun4u_stopself();
  406                 }
  407         }
  408         atomic_clear_rel_int(&started_cpus, PCPU_GET(cpumask));
  409         atomic_clear_rel_int(&stopped_cpus, PCPU_GET(cpumask));
  410         CTR1(KTR_SMP, "cpu_ipi_stop: restarted %d", PCPU_GET(cpuid));
  411 }
  412 
  413 void
  414 cpu_ipi_selected(u_int cpus, u_long d0, u_long d1, u_long d2)
  415 {
  416         struct pcpu *pc;
  417         u_int cpu;
  418 
  419         while (cpus) {
  420                 cpu = ffs(cpus) - 1;
  421                 cpus &= ~(1 << cpu);
  422                 pc = pcpu_find(cpu);
  423                 cpu_ipi_send(pc->pc_mid, d0, d1, d2);
  424         }
  425 }
  426 
  427 void
  428 cpu_ipi_send(u_int mid, u_long d0, u_long d1, u_long d2)
  429 {
  430         u_long s;
  431         int i;
  432 
  433         KASSERT((ldxa(0, ASI_INTR_DISPATCH_STATUS) & IDR_BUSY) == 0,
  434             ("ipi_send: outstanding dispatch"));
  435         for (i = 0; i < IPI_RETRIES; i++) {
  436                 s = intr_disable();
  437                 stxa(AA_SDB_INTR_D0, ASI_SDB_INTR_W, d0);
  438                 stxa(AA_SDB_INTR_D1, ASI_SDB_INTR_W, d1);
  439                 stxa(AA_SDB_INTR_D2, ASI_SDB_INTR_W, d2);
  440                 stxa(AA_INTR_SEND | (mid << 14), ASI_SDB_INTR_W, 0);
  441                 membar(Sync);
  442                 while (ldxa(0, ASI_INTR_DISPATCH_STATUS) & IDR_BUSY)
  443                         ;
  444                 intr_restore(s);
  445                 if ((ldxa(0, ASI_INTR_DISPATCH_STATUS) & IDR_NACK) == 0)
  446                         return;
  447         }
  448         if (
  449 #ifdef DDB
  450             db_active ||
  451 #endif
  452             panicstr != NULL)
  453                 printf("ipi_send: couldn't send ipi to module %u\n", mid);
  454         else
  455                 panic("ipi_send: couldn't send ipi");
  456 }
  457 
  458 void
  459 ipi_selected(u_int cpus, u_int ipi)
  460 {
  461         cpu_ipi_selected(cpus, 0, (u_long)tl_ipi_level, ipi);
  462 }
  463 
  464 void
  465 ipi_all(u_int ipi)
  466 {
  467         panic("ipi_all");
  468 }
  469 
  470 void
  471 ipi_all_but_self(u_int ipi)
  472 {
  473         cpu_ipi_selected(PCPU_GET(other_cpus), 0, (u_long)tl_ipi_level, ipi);
  474 }

Cache object: 2b00dadfed94f586557ac83f4886c5cd


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