]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/sun4v/sun4v/mp_machdep.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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         ofw_entry(&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                 dpcpu_init((void *)kmem_alloc(kernel_map, DPCPU_SIZE),
328                     cpuid);
329                 pc->pc_addr = va;
330
331                 all_cpus |= 1 << cpuid;
332
333                 if (mp_ncpus == MAXCPU)
334                         break;
335         }
336         printf("%d cpus: UltraSparc T1 Processor (%d.%02d MHz CPU)\n", mp_ncpus,
337             (clock + 4999) / 1000000, ((clock + 4999) / 10000) % 100);
338
339         PCPU_SET(other_cpus, all_cpus & ~(1 << PCPU_GET(cpuid)));
340         smp_active = 1;
341 }
342
343 void
344 cpu_mp_announce(void)
345 {
346 }
347
348 void
349 cpu_mp_unleash(void *v)
350 {
351         volatile struct cpu_start_args *csa;
352         struct pcpu *pc;
353         u_long s;
354
355         csa = &cpu_start_args;
356         csa->csa_count = mp_ncpus;
357         printf("mp_ncpus=%d\n", mp_ncpus);
358         SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
359                 if (pc->pc_cpuid == PCPU_GET(cpuid)) 
360                         continue;
361
362                 KASSERT(pc->pc_idlethread != NULL,
363                     ("cpu_mp_unleash: idlethread is NULL"));
364                 pc->pc_curthread = pc->pc_idlethread;   
365                 pc->pc_curpcb = pc->pc_curthread->td_pcb;
366                 pc->pc_curpmap = kernel_pmap;
367                 csa->csa_state = 0;
368                 csa->csa_pcpu = TLB_PHYS_TO_DIRECT(vtophys(pc->pc_addr));
369                 DELAY(300);
370                 /* allow AP to run */
371                 csa->csa_cpuid = pc->pc_cpuid;
372                 membar(Sync);
373                 s = intr_disable();
374                 while (csa->csa_state != CPU_BOOTSTRAP)
375                         ;
376                 intr_restore(s);
377         }
378
379         membar(StoreLoad);
380         csa->csa_count = 0; 
381         smp_started = 1;
382 }
383
384 void
385 cpu_mp_bootstrap(struct pcpu *pc)
386 {
387         volatile struct cpu_start_args *csa;
388
389         csa = &cpu_start_args;
390         cpu_setregs(pc);
391         tsb_set_scratchpad_kernel(&kernel_pmap->pm_tsb);
392         tte_hash_set_scratchpad_kernel(kernel_pmap->pm_hash);
393         trap_init();
394         cpu_intrq_init();
395         tick_start();
396
397 #ifdef TRAP_TRACING
398         mp_trap_trace_init();
399 #endif
400
401         /* 
402          * enable interrupts now that we have our trap table set
403          */
404         intr_restore_all(PSTATE_KERNEL);
405
406         smp_cpus++;
407         KASSERT(curthread != NULL, ("cpu_mp_bootstrap: curthread"));
408         PCPU_SET(other_cpus, all_cpus & ~(1 << curcpu));
409         printf("AP: #%d\n", curcpu);
410         csa->csa_count--;
411         membar(StoreLoad);
412         csa->csa_state = CPU_BOOTSTRAP;
413
414         while (csa->csa_count != 0)
415                 ;
416         /* ok, now enter the scheduler */
417         sched_throw(NULL);
418 }
419
420 void
421 cpu_mp_shutdown(void)
422 {
423         int i;
424
425         critical_enter();
426         shutdown_cpus = PCPU_GET(other_cpus);
427         if (stopped_cpus != PCPU_GET(other_cpus))       /* XXX */
428                 stop_cpus(stopped_cpus ^ PCPU_GET(other_cpus));
429         i = 0;
430         while (shutdown_cpus != 0) {
431                 if (i++ > 100000) {
432                         printf("timeout shutting down CPUs.\n");
433                         break;
434                 }
435         }
436         /* XXX: delay a bit to allow the CPUs to actually enter the PROM. */
437         DELAY(100000);
438         critical_exit();
439 }
440
441 void
442 cpu_ipi_ast(struct trapframe *tf)
443 {
444 }
445
446 void
447 cpu_ipi_stop(struct trapframe *tf)
448 {
449
450         CTR1(KTR_SMP, "cpu_ipi_stop: stopped %d", curcpu);
451         savectx(&stoppcbs[curcpu]);
452         atomic_set_acq_int(&stopped_cpus, PCPU_GET(cpumask));
453         while ((started_cpus & PCPU_GET(cpumask)) == 0) {
454                 if ((shutdown_cpus & PCPU_GET(cpumask)) != 0) {
455                         atomic_clear_int(&shutdown_cpus, PCPU_GET(cpumask));
456                 }
457         }
458         atomic_clear_rel_int(&started_cpus, PCPU_GET(cpumask));
459         atomic_clear_rel_int(&stopped_cpus, PCPU_GET(cpumask));
460         CTR1(KTR_SMP, "cpu_ipi_stop: restarted %d", curcpu);
461 }
462
463 void
464 cpu_ipi_preempt(struct trapframe *tf)
465 {
466         sched_preempt(curthread);
467 }
468
469 void
470 cpu_ipi_selected(int cpu_count, uint16_t *cpulist, u_long d0, u_long d1, u_long d2, uint64_t *ackmask)
471 {
472
473         int i, retries;
474
475         init_mondo(d0, d1, d2, (uint64_t)pmap_kextract((vm_offset_t)ackmask));
476
477         retries = 0;
478
479 retry:
480         if (cpu_count) {
481                 int error, new_cpu_count;
482                 vm_paddr_t cpulist_ra;
483
484                 cpulist_ra = TLB_DIRECT_TO_PHYS((vm_offset_t)cpulist);
485                 if ((error = hv_cpu_mondo_send(cpu_count, cpulist_ra)) == H_EWOULDBLOCK) {
486                         new_cpu_count = 0;
487                         for (i = 0; i < cpu_count; i++) {
488                                 if (cpulist[i] != 0xffff)
489                                         cpulist[new_cpu_count++] = cpulist[i];
490                         }      
491                         cpu_count = new_cpu_count;
492                         retries++;
493                         if (cpu_count == 0) {
494                                 printf("no more cpus to send to but mondo_send returned EWOULDBLOCK\n");
495                                 return;
496                         }
497                         if ((retries & 0x1) == 0x1)
498                                 DELAY(10);
499
500                         if (retries < 50000)
501                                 goto retry;
502                         else {
503                                 printf("used up retries - cpus remaining: %d  - cpus: ",
504                                        cpu_count);
505                                 for (i = 0; i < cpu_count; i++)
506                                         printf("#%d ", cpulist[i]);
507                                 printf("\n");
508                         }
509                 }
510                 if (error == H_ENOCPU) {
511                         printf("bad cpuid: ");
512                         for (i = 0; i < cpu_count; i++)
513                                 printf("#%d ", cpulist[i]);
514                         printf("\n");
515                 }               
516                 if (error)
517                         panic("can't handle error %d from cpu_mondo_send\n", error);
518         }
519 }
520
521
522 void
523 ipi_selected(u_int icpus, u_int ipi)
524 {
525         int i, cpu_count;
526         uint16_t *cpulist;
527         cpumask_t cpus;
528         uint64_t ackmask;
529
530         /* 
531          * 
532          * 3) forward_wakeup appears to abuse ASTs
533          * 4) handling 4-way threading vs 2-way threading should happen here
534          *    and not in forward wakeup
535          */
536         
537         cpulist = PCPU_GET(cpulist);
538         cpus = (icpus & ~PCPU_GET(cpumask));
539         
540         for (cpu_count = 0, i = 0; i < 32 && cpus; cpus = cpus >> 1, i++) {
541                 if (!(cpus & 0x1))
542                         continue;
543                 
544                 cpulist[cpu_count] = (uint16_t)i;
545                 cpu_count++;
546         }
547
548         cpu_ipi_selected(cpu_count, cpulist, (u_long)tl_ipi_level, ipi, 0, &ackmask);
549         
550 }
551
552 void
553 ipi_all_but_self(u_int ipi)
554 {
555         ipi_selected(PCPU_GET(other_cpus), ipi);
556 }