]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/sun4v/sun4v/mp_machdep.c
add -n option to suppress clearing the build tree and add -DNO_CLEAN
[FreeBSD/FreeBSD.git] / sys / sun4v / sun4v / mp_machdep.c
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  * Copyright (c) 2006 Kip Macy <kmacy@FreeBSD.org>.
33  * All rights reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  *
44  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
45  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
48  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54  * SUCH DAMAGE.
55  */
56
57 #include <sys/cdefs.h>
58 __FBSDID("$FreeBSD$");
59
60 #include "opt_trap_trace.h"
61
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/lock.h>
65 #include <sys/kdb.h>
66 #include <sys/kernel.h>
67 #include <sys/ktr.h>
68 #include <sys/mutex.h>
69 #include <sys/pcpu.h>
70 #include <sys/proc.h>
71 #include <sys/sched.h>
72 #include <sys/smp.h>
73
74 #include <vm/vm.h>
75 #include <vm/vm_param.h>
76 #include <vm/pmap.h>
77 #include <vm/vm_kern.h>
78 #include <vm/vm_extern.h>
79 #include <vm/vm_map.h>
80
81 #include <dev/ofw/openfirm.h>
82
83 #include <machine/asi.h>
84 #include <machine/atomic.h>
85 #include <machine/bus.h>
86 #include <machine/md_var.h>
87 #include <machine/metadata.h>
88 #include <machine/ofw_machdep.h>
89 #include <machine/pcb.h>
90 #include <machine/smp.h>
91 #include <machine/tick.h>
92 #include <machine/pstate.h>
93 #include <machine/tlb.h>
94 #include <machine/tte.h>
95 #include <machine/tte_hash.h>
96 #include <machine/tsb.h>
97 #include <machine/trap.h>
98 #include <machine/hypervisorvar.h>
99 #include <machine/hv_api.h>
100 #include <machine/asm.h>
101
102 /*
103  * Argument area used to pass data to non-boot processors as they start up.
104  * This must be statically initialized with a known invalid cpuid,
105  * 
106  */
107 struct  cpu_start_args cpu_start_args = { 0, -1, 0, -1 };
108 struct  ipi_cache_args ipi_cache_args;
109 struct  ipi_tlb_args ipi_tlb_args;
110 struct  pcb stoppcbs[MAXCPU];
111
112 struct  mtx ipi_mtx;
113
114 vm_offset_t mp_tramp;
115
116 u_int   mp_boot_mid;
117
118 static volatile u_int   shutdown_cpus;
119
120 void cpu_mp_unleash(void *);
121 SYSINIT(cpu_mp_unleash, SI_SUB_SMP, SI_ORDER_FIRST, cpu_mp_unleash, NULL);
122
123 #ifdef TRAP_TRACING
124 #ifndef TRAP_TRACE_ENTRIES
125 #define TRAP_TRACE_ENTRIES      64
126 #endif
127 extern trap_trace_entry_t trap_trace_entry[MAXCPU][TRAP_TRACE_ENTRIES];
128
129 static void
130 mp_trap_trace_init(void)
131 {
132         uint64_t ret, ret1;
133
134         printf("curcpu %d trap_trace_entry %p TRAP_TRACE_ENTRIES %d\n", curcpu, &trap_trace_entry[curcpu][0], TRAP_TRACE_ENTRIES);
135
136         /* Configure the trap trace buffer for the current CPU. */
137         if ((ret = hv_ttrace_buf_conf((uint64_t) vtophys(&trap_trace_entry[curcpu][0]),
138             (uint64_t) TRAP_TRACE_ENTRIES, &ret1)) != 0)
139                 printf("%s: hv_ttrace_buf_conf error %lu\n", __FUNCTION__, ret);
140
141         /* Enable trap tracing for the current CPU. */
142         else if ((ret = hv_ttrace_enable((uint64_t) -1, &ret1)) != 0)
143                 printf("%s: hv_ttrace_enable error %lu\n", __FUNCTION__, ret);
144 }
145
146 void trap_trace_report(int);
147
148 static int      trace_trap_lock;
149
150 void
151 trap_trace_report(int cpuid)
152 {
153         int i, j;
154
155         while (!atomic_cmpset_acq_int(&trace_trap_lock, 0, 1))
156                 DELAY(10000);
157
158         for (i = 0; i < MAXCPU; i++) {
159                 if (cpuid != -1 && cpuid != i)
160                         continue;
161
162                 for (j = 0; j < TRAP_TRACE_ENTRIES; j++) {
163                         trap_trace_entry_t *p = &trap_trace_entry[i][j];
164
165                         printf("0x%08jx [%02d][%04d] tpc 0x%jx type 0x%x hpstat 0x%x tl %u gl %u tt 0x%hx tag 0x%hx tstate 0x%jx f1 0x%jx f2 0x%jx f3 0x%jx f4 0x%jx\n",
166                             p->tte_tick, i, j, p->tte_tpc,p->tte_type,p->tte_hpstat,
167                             p->tte_tl,p->tte_gl,p->tte_tt,p->tte_tag,p->tte_tstate,
168                             p->tte_f1,p->tte_f2,p->tte_f3,p->tte_f4);
169                 }
170         }
171
172         atomic_store_rel_int(&trace_trap_lock, 0);
173 }
174 #endif
175
176 vm_offset_t
177 mp_tramp_alloc(void)
178 {
179         char *v;
180         int i;
181
182         v = OF_claim(NULL, PAGE_SIZE, PAGE_SIZE);
183         if (v == NULL)
184                 panic("mp_tramp_alloc");
185         bcopy(mp_tramp_code, v, mp_tramp_code_len);
186
187         *(u_long *)(v + mp_tramp_func) = (u_long)mp_startup;
188
189         for (i = 0; i < PAGE_SIZE; i += sizeof(long)*4 /* XXX L1 cacheline size */)
190                 flush(v + i);
191         return (vm_offset_t)v;
192 }
193
194 void
195 mp_set_tsb_desc_ra(vm_paddr_t tsb_desc_ra)
196 {
197         *(u_long *)(mp_tramp + mp_tramp_tsb_desc_ra) = tsb_desc_ra;
198 }
199
200 void
201 mp_add_nucleus_mapping(vm_offset_t va, tte_t tte_data)
202 {
203         static int slot;
204         uint64_t *entry;
205
206         entry = (uint64_t *)(mp_tramp + mp_tramp_code_len + slot*sizeof(*entry)*2);
207         *(entry) = va;
208         *(entry + 1) = tte_data;
209         *(uint64_t *)(mp_tramp + mp_tramp_tte_slots) = slot + 1;
210         slot++;
211 }
212
213 /*
214  * Probe for other cpus.
215  */
216 void
217 cpu_mp_setmaxid(void)
218 {
219         phandle_t child;
220         phandle_t root;
221         char buf[128];
222         int cpus;
223
224         all_cpus = 1 << PCPU_GET(cpuid);
225         mp_ncpus = 1;
226
227         cpus = 0;
228         root = OF_peer(0);
229         for (child = OF_child(root); child != 0; child = OF_peer(child)) {
230                 if (OF_getprop(child, "device_type", buf, sizeof(buf)) > 0 &&
231                     strcmp(buf, "cpu") == 0)
232                         cpus++;
233         }
234         mp_maxid = cpus - 1;
235
236 }
237
238 int
239 cpu_mp_probe(void)
240 {
241         return (mp_maxid > 0);
242 }
243
244 struct cpu_group *
245 cpu_topo(void)
246 {
247
248         return smp_topo_none();
249 }
250
251 static int
252 start_ap_bycpuid(int cpuid, void *func, u_long arg)
253 {
254         static struct {
255                 cell_t  name;
256                 cell_t  nargs;
257                 cell_t  nreturns;
258                 cell_t  cpuid;
259                 cell_t  func;
260                 cell_t  arg;
261                 cell_t  result;
262         } args = {
263                 (cell_t)"SUNW,start-cpu-by-cpuid",
264                 3,
265                 1,
266                 0,
267                 0,
268                 0,
269                 0
270         };
271
272         args.cpuid = cpuid;
273         args.func = (cell_t)func;
274         args.arg = (cell_t)arg;
275         openfirmware(&args);
276         return (int)args.result;
277         
278 }
279
280 /*
281  * Fire up any non-boot processors.
282  */
283 void
284 cpu_mp_start(void)
285 {
286         volatile struct cpu_start_args *csa;
287         struct pcpu *pc;
288         phandle_t child;
289         phandle_t root;
290         vm_offset_t va;
291         char buf[128];
292         u_int clock;
293         int cpuid, bp_skipped;
294         u_long s;
295
296         root = OF_peer(0);
297         csa = &cpu_start_args;
298         clock = cpuid = bp_skipped = 0;
299         for (child = OF_child(root); child != 0; child = OF_peer(child)) {
300                 if (OF_getprop(child, "device_type", buf, sizeof(buf)) <= 0 ||
301                     strcmp(buf, "cpu") != 0)
302                         continue;
303                 /* skip boot processor */
304                 if (!bp_skipped) {
305                         bp_skipped = 1;
306                         continue;
307                 }
308                 cpuid++;
309
310                 if (OF_getprop(child, "clock-frequency", &clock,
311                     sizeof(clock)) <= 0)
312                         panic("cpu_mp_start: can't get clock");
313
314                 csa->csa_state = 0;
315                 start_ap_bycpuid(cpuid, (void *)mp_tramp, (uint64_t)cpuid);
316                 s = intr_disable();
317                 while (csa->csa_state != CPU_INIT)
318                         ;
319                 intr_restore(s);
320                 mp_ncpus = cpuid + 1;
321 #if 0
322                 cpu_identify(0, clock, cpuid);
323 #endif
324                 va = kmem_alloc(kernel_map, PCPU_PAGES * PAGE_SIZE);
325                 pc = (struct pcpu *)(va + (PCPU_PAGES * PAGE_SIZE)) - 1;
326                 pcpu_init(pc, cpuid, sizeof(*pc));
327                 pc->pc_addr = va;
328
329                 all_cpus |= 1 << cpuid;
330
331                 if (mp_ncpus == MAXCPU)
332                         break;
333         }
334         printf("%d cpus: UltraSparc T1 Processor (%d.%02d MHz CPU)\n", mp_ncpus,
335             (clock + 4999) / 1000000, ((clock + 4999) / 10000) % 100);
336
337         PCPU_SET(other_cpus, all_cpus & ~(1 << PCPU_GET(cpuid)));
338         smp_active = 1;
339 }
340
341 void
342 cpu_mp_announce(void)
343 {
344 }
345
346 void
347 cpu_mp_unleash(void *v)
348 {
349         volatile struct cpu_start_args *csa;
350         struct pcpu *pc;
351         u_long s;
352
353         csa = &cpu_start_args;
354         csa->csa_count = mp_ncpus;
355         printf("mp_ncpus=%d\n", mp_ncpus);
356         SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
357                 if (pc->pc_cpuid == PCPU_GET(cpuid)) 
358                         continue;
359
360                 KASSERT(pc->pc_idlethread != NULL,
361                     ("cpu_mp_unleash: idlethread is NULL"));
362                 pc->pc_curthread = pc->pc_idlethread;   
363                 pc->pc_curpcb = pc->pc_curthread->td_pcb;
364                 pc->pc_curpmap = kernel_pmap;
365                 csa->csa_state = 0;
366                 csa->csa_pcpu = TLB_PHYS_TO_DIRECT(vtophys(pc->pc_addr));
367                 DELAY(300);
368                 /* allow AP to run */
369                 csa->csa_cpuid = pc->pc_cpuid;
370                 membar(Sync);
371                 s = intr_disable();
372                 while (csa->csa_state != CPU_BOOTSTRAP)
373                         ;
374                 intr_restore(s);
375         }
376
377         membar(StoreLoad);
378         csa->csa_count = 0; 
379         smp_started = 1;
380 }
381
382 void
383 cpu_mp_bootstrap(struct pcpu *pc)
384 {
385         volatile struct cpu_start_args *csa;
386
387         csa = &cpu_start_args;
388         cpu_setregs(pc);
389         tsb_set_scratchpad_kernel(&kernel_pmap->pm_tsb);
390         tte_hash_set_scratchpad_kernel(kernel_pmap->pm_hash);
391         trap_init();
392         cpu_intrq_init();
393         tick_start();
394
395 #ifdef TRAP_TRACING
396         mp_trap_trace_init();
397 #endif
398
399         /* 
400          * enable interrupts now that we have our trap table set
401          */
402         intr_restore_all(PSTATE_KERNEL);
403
404         smp_cpus++;
405         KASSERT(curthread != NULL, ("cpu_mp_bootstrap: curthread"));
406         PCPU_SET(other_cpus, all_cpus & ~(1 << curcpu));
407         printf("AP: #%d\n", curcpu);
408         csa->csa_count--;
409         membar(StoreLoad);
410         csa->csa_state = CPU_BOOTSTRAP;
411
412         while (csa->csa_count != 0)
413                 ;
414         /* ok, now enter the scheduler */
415         sched_throw(NULL);
416 }
417
418 void
419 cpu_mp_shutdown(void)
420 {
421         int i;
422
423         critical_enter();
424         shutdown_cpus = PCPU_GET(other_cpus);
425         if (stopped_cpus != PCPU_GET(other_cpus))       /* XXX */
426                 stop_cpus(stopped_cpus ^ PCPU_GET(other_cpus));
427         i = 0;
428         while (shutdown_cpus != 0) {
429                 if (i++ > 100000) {
430                         printf("timeout shutting down CPUs.\n");
431                         break;
432                 }
433         }
434         /* XXX: delay a bit to allow the CPUs to actually enter the PROM. */
435         DELAY(100000);
436         critical_exit();
437 }
438
439 void
440 cpu_ipi_ast(struct trapframe *tf)
441 {
442 }
443
444 void
445 cpu_ipi_stop(struct trapframe *tf)
446 {
447
448         CTR1(KTR_SMP, "cpu_ipi_stop: stopped %d", curcpu);
449         savectx(&stoppcbs[curcpu]);
450         atomic_set_acq_int(&stopped_cpus, PCPU_GET(cpumask));
451         while ((started_cpus & PCPU_GET(cpumask)) == 0) {
452                 if ((shutdown_cpus & PCPU_GET(cpumask)) != 0) {
453                         atomic_clear_int(&shutdown_cpus, PCPU_GET(cpumask));
454                 }
455         }
456         atomic_clear_rel_int(&started_cpus, PCPU_GET(cpumask));
457         atomic_clear_rel_int(&stopped_cpus, PCPU_GET(cpumask));
458         CTR1(KTR_SMP, "cpu_ipi_stop: restarted %d", curcpu);
459 }
460
461 void
462 cpu_ipi_preempt(struct trapframe *tf)
463 {
464         sched_preempt(curthread);
465 }
466
467 void
468 cpu_ipi_selected(int cpu_count, uint16_t *cpulist, u_long d0, u_long d1, u_long d2, uint64_t *ackmask)
469 {
470
471         int i, retries;
472
473         init_mondo(d0, d1, d2, (uint64_t)pmap_kextract((vm_offset_t)ackmask));
474
475         retries = 0;
476
477 retry:
478         if (cpu_count) {
479                 int error, new_cpu_count;
480                 vm_paddr_t cpulist_ra;
481
482                 cpulist_ra = TLB_DIRECT_TO_PHYS((vm_offset_t)cpulist);
483                 if ((error = hv_cpu_mondo_send(cpu_count, cpulist_ra)) == H_EWOULDBLOCK) {
484                         new_cpu_count = 0;
485                         for (i = 0; i < cpu_count; i++) {
486                                 if (cpulist[i] != 0xffff)
487                                         cpulist[new_cpu_count++] = cpulist[i];
488                         }      
489                         cpu_count = new_cpu_count;
490                         retries++;
491                         if (cpu_count == 0) {
492                                 printf("no more cpus to send to but mondo_send returned EWOULDBLOCK\n");
493                                 return;
494                         }
495                         if ((retries & 0x1) == 0x1)
496                                 DELAY(10);
497
498                         if (retries < 50000)
499                                 goto retry;
500                         else {
501                                 printf("used up retries - cpus remaining: %d  - cpus: ",
502                                        cpu_count);
503                                 for (i = 0; i < cpu_count; i++)
504                                         printf("#%d ", cpulist[i]);
505                                 printf("\n");
506                         }
507                 }
508                 if (error == H_ENOCPU) {
509                         printf("bad cpuid: ");
510                         for (i = 0; i < cpu_count; i++)
511                                 printf("#%d ", cpulist[i]);
512                         printf("\n");
513                 }               
514                 if (error)
515                         panic("can't handle error %d from cpu_mondo_send\n", error);
516         }
517 }
518
519
520 void
521 ipi_selected(u_int icpus, u_int ipi)
522 {
523         int i, cpu_count;
524         uint16_t *cpulist;
525         cpumask_t cpus;
526         uint64_t ackmask;
527
528         /* 
529          * 
530          * 3) forward_wakeup appears to abuse ASTs
531          * 4) handling 4-way threading vs 2-way threading should happen here
532          *    and not in forward wakeup
533          */
534         
535         cpulist = PCPU_GET(cpulist);
536         cpus = (icpus & ~PCPU_GET(cpumask));
537         
538         for (cpu_count = 0, i = 0; i < 32 && cpus; cpus = cpus >> 1, i++) {
539                 if (!(cpus & 0x1))
540                         continue;
541                 
542                 cpulist[cpu_count] = (uint16_t)i;
543                 cpu_count++;
544         }
545
546         cpu_ipi_selected(cpu_count, cpulist, (u_long)tl_ipi_level, ipi, 0, &ackmask);
547         
548 }
549
550 void
551 ipi_all_but_self(u_int ipi)
552 {
553         ipi_selected(PCPU_GET(other_cpus), ipi);
554 }