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 
   56 #include <sys/cdefs.h>
   57 __FBSDID("$FreeBSD: releng/6.0/sys/sparc64/sparc64/mp_machdep.c 145150 2005-04-16 14:57:38Z marius $");
   58 
   59 #include <sys/param.h>
   60 #include <sys/systm.h>
   61 #include <sys/lock.h>
   62 #include <sys/kdb.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 <machine/asi.h>
   80 #include <machine/atomic.h>
   81 #include <machine/bus.h>
   82 #include <machine/md_var.h>
   83 #include <machine/metadata.h>
   84 #include <machine/ofw_machdep.h>
   85 #include <machine/smp.h>
   86 #include <machine/tick.h>
   87 #include <machine/tlb.h>
   88 #include <machine/tte.h>
   89 
   90 static ih_func_t cpu_ipi_ast;
   91 static ih_func_t cpu_ipi_stop;
   92 
   93 /*
   94  * Argument area used to pass data to non-boot processors as they start up.
   95  * This must be statically initialized with a known invalid upa module id,
   96  * since the other processors will use it before the boot cpu enters the
   97  * kernel.
   98  */
   99 struct  cpu_start_args cpu_start_args = { 0, -1, -1, 0, 0 };
  100 struct  ipi_cache_args ipi_cache_args;
  101 struct  ipi_tlb_args ipi_tlb_args;
  102 
  103 struct  mtx ipi_mtx;
  104 
  105 vm_offset_t mp_tramp;
  106 
  107 u_int   mp_boot_mid;
  108 
  109 static volatile u_int   shutdown_cpus;
  110 
  111 void cpu_mp_unleash(void *);
  112 SYSINIT(cpu_mp_unleash, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL);
  113 
  114 vm_offset_t
  115 mp_tramp_alloc(void)
  116 {
  117         struct tte *tp;
  118         char *v;
  119         int i;
  120 
  121         v = OF_claim(NULL, PAGE_SIZE, PAGE_SIZE);
  122         if (v == NULL)
  123                 panic("mp_tramp_alloc");
  124         bcopy(mp_tramp_code, v, mp_tramp_code_len);
  125         *(u_long *)(v + mp_tramp_tlb_slots) = kernel_tlb_slots;
  126         *(u_long *)(v + mp_tramp_func) = (u_long)mp_startup;
  127         tp = (struct tte *)(v + mp_tramp_code_len);
  128         for (i = 0; i < kernel_tlb_slots; i++) {
  129                 tp[i].tte_vpn = TV_VPN(kernel_tlbs[i].te_va, TS_4M);
  130                 tp[i].tte_data = TD_V | TD_4M | TD_PA(kernel_tlbs[i].te_pa) |
  131                     TD_L | TD_CP | TD_CV | TD_P | TD_W;
  132         }
  133         for (i = 0; i < PAGE_SIZE; i += sizeof(long))
  134                 flush(v + i);
  135         return (vm_offset_t)v;
  136 }
  137 
  138 /*
  139  * Probe for other cpus.
  140  */
  141 void
  142 cpu_mp_setmaxid(void)
  143 {
  144         phandle_t child;
  145         phandle_t root;
  146         char buf[128];
  147         int cpus;
  148 
  149         all_cpus = 1 << PCPU_GET(cpuid);
  150         mp_boot_mid = PCPU_GET(mid);
  151         mp_ncpus = 1;
  152 
  153         cpus = 0;
  154         root = OF_peer(0);
  155         for (child = OF_child(root); child != 0; child = OF_peer(child)) {
  156                 if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 &&
  157                     strcmp(buf, "cpu") == 0)
  158                         cpus++;
  159         }
  160         mp_maxid = cpus - 1;
  161 }
  162 
  163 int
  164 cpu_mp_probe(void)
  165 {
  166 
  167         return (mp_maxid > 0);
  168 }
  169 
  170 static void
  171 sun4u_startcpu(phandle_t cpu, void *func, u_long arg)
  172 {
  173         static struct {
  174                 cell_t  name;
  175                 cell_t  nargs;
  176                 cell_t  nreturns;
  177                 cell_t  cpu;
  178                 cell_t  func;
  179                 cell_t  arg;
  180         } args = {
  181                 (cell_t)"SUNW,start-cpu",
  182                 3,
  183                 0,
  184                 0,
  185                 0,
  186                 0
  187         };
  188 
  189         args.cpu = cpu;
  190         args.func = (cell_t)func;
  191         args.arg = (cell_t)arg;
  192         openfirmware(&args);
  193 }
  194 
  195 /*
  196  * Stop the calling CPU.
  197  */
  198 static void
  199 sun4u_stopself(void)
  200 {
  201         static struct {
  202                 cell_t  name;
  203                 cell_t  nargs;
  204                 cell_t  nreturns;
  205         } args = {
  206                 (cell_t)"SUNW,stop-self",
  207                 0,
  208                 0,
  209         };
  210 
  211         openfirmware_exit(&args);
  212         panic("sun4u_stopself: failed.");
  213 }
  214 
  215 /*
  216  * Fire up any non-boot processors.
  217  */
  218 void
  219 cpu_mp_start(void)
  220 {
  221         volatile struct cpu_start_args *csa;
  222         struct pcpu *pc;
  223         phandle_t child;
  224         phandle_t root;
  225         vm_offset_t va;
  226         char buf[128];
  227         u_int clock;
  228         int cpuid;
  229         u_int mid;
  230         u_long s;
  231 
  232         mtx_init(&ipi_mtx, "ipi", NULL, MTX_SPIN);
  233 
  234         intr_setup(PIL_AST, cpu_ipi_ast, -1, NULL, NULL);
  235         intr_setup(PIL_RENDEZVOUS, (ih_func_t *)smp_rendezvous_action,
  236             -1, NULL, NULL);
  237         intr_setup(PIL_STOP, cpu_ipi_stop, -1, NULL, NULL);
  238 
  239         root = OF_peer(0);
  240         csa = &cpu_start_args;
  241         for (child = OF_child(root); child != 0; child = OF_peer(child)) {
  242                 if (OF_getprop(child, "device_type", buf, sizeof(buf)) <= 0 ||
  243                     strcmp(buf, "cpu") != 0)
  244                         continue;
  245                 if (OF_getprop(child, "upa-portid", &mid, sizeof(mid)) <= 0 &&
  246                     OF_getprop(child, "portid", &mid, sizeof(mid)) <= 0)
  247                         panic("cpu_mp_start: can't get module id");
  248                 if (mid == mp_boot_mid)
  249                         continue;
  250                 if (OF_getprop(child, "clock-frequency", &clock,
  251                     sizeof(clock)) <= 0)
  252                         panic("cpu_mp_start: can't get clock");
  253 
  254                 csa->csa_state = 0;
  255                 sun4u_startcpu(child, (void *)mp_tramp, 0);
  256                 s = intr_disable();
  257                 while (csa->csa_state != CPU_CLKSYNC)
  258                         ;
  259                 membar(StoreLoad);
  260                 csa->csa_tick = rd(tick);
  261                 while (csa->csa_state != CPU_INIT)
  262                         ;
  263                 csa->csa_tick = 0;
  264                 intr_restore(s);
  265 
  266                 cpuid = mp_ncpus++;
  267                 cpu_identify(csa->csa_ver, clock, cpuid);
  268 
  269                 va = kmem_alloc(kernel_map, PCPU_PAGES * PAGE_SIZE);
  270                 pc = (struct pcpu *)(va + (PCPU_PAGES * PAGE_SIZE)) - 1;
  271                 pcpu_init(pc, cpuid, sizeof(*pc));
  272                 pc->pc_addr = va;
  273                 pc->pc_mid = mid;
  274                 pc->pc_node = child;
  275 
  276                 all_cpus |= 1 << cpuid;
  277         }
  278         PCPU_SET(other_cpus, all_cpus & ~(1 << PCPU_GET(cpuid)));
  279         smp_active = 1;
  280 }
  281 
  282 void
  283 cpu_mp_announce(void)
  284 {
  285 }
  286 
  287 void
  288 cpu_mp_unleash(void *v)
  289 {
  290         volatile struct cpu_start_args *csa;
  291         struct pcpu *pc;
  292         vm_offset_t va;
  293         vm_paddr_t pa;
  294         u_int ctx_min;
  295         u_int ctx_inc;
  296         u_long s;
  297         int i;
  298 
  299         ctx_min = TLB_CTX_USER_MIN;
  300         ctx_inc = (TLB_CTX_USER_MAX - 1) / mp_ncpus;
  301         csa = &cpu_start_args;
  302         csa->csa_count = mp_ncpus;
  303         SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
  304                 pc->pc_tlb_ctx = ctx_min;
  305                 pc->pc_tlb_ctx_min = ctx_min;
  306                 pc->pc_tlb_ctx_max = ctx_min + ctx_inc;
  307                 ctx_min += ctx_inc;
  308 
  309                 if (pc->pc_cpuid == PCPU_GET(cpuid))
  310                         continue;
  311                 KASSERT(pc->pc_idlethread != NULL,
  312                     ("cpu_mp_unleash: idlethread"));
  313                 pc->pc_curthread = pc->pc_idlethread;   
  314                 pc->pc_curpcb = pc->pc_curthread->td_pcb;
  315                 for (i = 0; i < PCPU_PAGES; i++) {
  316                         va = pc->pc_addr + i * PAGE_SIZE;
  317                         pa = pmap_kextract(va);
  318                         if (pa == 0)
  319                                 panic("cpu_mp_unleash: pmap_kextract\n");
  320                         csa->csa_ttes[i].tte_vpn = TV_VPN(va, TS_8K);
  321                         csa->csa_ttes[i].tte_data = TD_V | TD_8K | TD_PA(pa) |
  322                             TD_L | TD_CP | TD_CV | TD_P | TD_W;
  323                 }
  324                 csa->csa_state = 0;
  325                 csa->csa_pcpu = pc->pc_addr;
  326                 csa->csa_mid = pc->pc_mid;
  327                 s = intr_disable();
  328                 while (csa->csa_state != CPU_BOOTSTRAP)
  329                         ;
  330                 intr_restore(s);
  331         }
  332 
  333         membar(StoreLoad);
  334         csa->csa_count = 0; 
  335         smp_started = 1;
  336 }
  337 
  338 void
  339 cpu_mp_bootstrap(struct pcpu *pc)
  340 {
  341         volatile struct cpu_start_args *csa;
  342 
  343         csa = &cpu_start_args;
  344         pmap_map_tsb();
  345         cpu_setregs(pc);
  346         tick_start();
  347 
  348         smp_cpus++;
  349         KASSERT(curthread != NULL, ("cpu_mp_bootstrap: curthread"));
  350         PCPU_SET(other_cpus, all_cpus & ~(1 << PCPU_GET(cpuid)));
  351         printf("SMP: AP CPU #%d Launched!\n", PCPU_GET(cpuid));
  352 
  353         csa->csa_count--;
  354         membar(StoreLoad);
  355         csa->csa_state = CPU_BOOTSTRAP;
  356         while (csa->csa_count != 0)
  357                 ;
  358 
  359         /* ok, now grab sched_lock and enter the scheduler */
  360         mtx_lock_spin(&sched_lock);
  361         spinlock_exit();
  362         binuptime(PCPU_PTR(switchtime));
  363         PCPU_SET(switchticks, ticks);
  364         cpu_throw(NULL, choosethread());        /* doesn't return */
  365 }
  366 
  367 void
  368 cpu_mp_shutdown(void)
  369 {
  370         int i;
  371 
  372         critical_enter();
  373         shutdown_cpus = PCPU_GET(other_cpus);
  374         if (stopped_cpus != PCPU_GET(other_cpus))       /* XXX */
  375                 stop_cpus(stopped_cpus ^ PCPU_GET(other_cpus));
  376         i = 0;
  377         while (shutdown_cpus != 0) {
  378                 if (i++ > 100000) {
  379                         printf("timeout shutting down CPUs.\n");
  380                         break;
  381                 }
  382         }
  383         /* XXX: delay a bit to allow the CPUs to actually enter the PROM. */
  384         DELAY(100000);
  385         critical_exit();
  386 }
  387 
  388 static void
  389 cpu_ipi_ast(struct trapframe *tf)
  390 {
  391 }
  392 
  393 static void
  394 cpu_ipi_stop(struct trapframe *tf)
  395 {
  396 
  397         CTR1(KTR_SMP, "cpu_ipi_stop: stopped %d", PCPU_GET(cpuid));
  398         atomic_set_acq_int(&stopped_cpus, PCPU_GET(cpumask));
  399         while ((started_cpus & PCPU_GET(cpumask)) == 0) {
  400                 if ((shutdown_cpus & PCPU_GET(cpumask)) != 0) {
  401                         atomic_clear_int(&shutdown_cpus, PCPU_GET(cpumask));
  402                         sun4u_stopself();
  403                 }
  404         }
  405         atomic_clear_rel_int(&started_cpus, PCPU_GET(cpumask));
  406         atomic_clear_rel_int(&stopped_cpus, PCPU_GET(cpumask));
  407         CTR1(KTR_SMP, "cpu_ipi_stop: restarted %d", PCPU_GET(cpuid));
  408 }
  409 
  410 void
  411 cpu_ipi_selected(u_int cpus, u_long d0, u_long d1, u_long d2)
  412 {
  413         struct pcpu *pc;
  414         u_int cpu;
  415 
  416         while (cpus) {
  417                 cpu = ffs(cpus) - 1;
  418                 cpus &= ~(1 << cpu);
  419                 pc = pcpu_find(cpu);
  420                 cpu_ipi_send(pc->pc_mid, d0, d1, d2);
  421         }
  422 }
  423 
  424 void
  425 cpu_ipi_send(u_int mid, u_long d0, u_long d1, u_long d2)
  426 {
  427         u_long s;
  428         int i;
  429 
  430         KASSERT((ldxa(0, ASI_INTR_DISPATCH_STATUS) & IDR_BUSY) == 0,
  431             ("cpu_ipi_send: outstanding dispatch"));
  432         for (i = 0; i < IPI_RETRIES; i++) {
  433                 s = intr_disable();
  434                 stxa(AA_SDB_INTR_D0, ASI_SDB_INTR_W, d0);
  435                 stxa(AA_SDB_INTR_D1, ASI_SDB_INTR_W, d1);
  436                 stxa(AA_SDB_INTR_D2, ASI_SDB_INTR_W, d2);
  437                 stxa(AA_INTR_SEND | (mid << 14), ASI_SDB_INTR_W, 0);
  438                 membar(Sync);
  439                 while (ldxa(0, ASI_INTR_DISPATCH_STATUS) & IDR_BUSY)
  440                         ;
  441                 intr_restore(s);
  442                 if ((ldxa(0, ASI_INTR_DISPATCH_STATUS) & IDR_NACK) == 0)
  443                         return;
  444         }
  445         if (
  446 #ifdef KDB
  447             kdb_active ||
  448 #endif
  449             panicstr != NULL)
  450                 printf("cpu_ipi_send: couldn't send ipi to module %u\n", mid);
  451         else
  452                 panic("cpu_ipi_send: couldn't send ipi");
  453 }
  454 
  455 void
  456 ipi_selected(u_int cpus, u_int ipi)
  457 {
  458         cpu_ipi_selected(cpus, 0, (u_long)tl_ipi_level, ipi);
  459 }
  460 
  461 void
  462 ipi_all(u_int ipi)
  463 {
  464         panic("ipi_all");
  465 }
  466 
  467 void
  468 ipi_all_but_self(u_int ipi)
  469 {
  470         cpu_ipi_selected(PCPU_GET(other_cpus), 0, (u_long)tl_ipi_level, ipi);
  471 }

Cache object: 9ce2fa5ab8d24b6d89aa21c599b30574


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