]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/sun4v/sun4v/mp_machdep.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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 static int
245 start_ap_bycpuid(int cpuid, void *func, u_long arg)
246 {
247         static struct {
248                 cell_t  name;
249                 cell_t  nargs;
250                 cell_t  nreturns;
251                 cell_t  cpuid;
252                 cell_t  func;
253                 cell_t  arg;
254                 cell_t  result;
255         } args = {
256                 (cell_t)"SUNW,start-cpu-by-cpuid",
257                 3,
258                 1,
259                 0,
260                 0,
261                 0,
262                 0
263         };
264
265         args.cpuid = cpuid;
266         args.func = (cell_t)func;
267         args.arg = (cell_t)arg;
268         openfirmware(&args);
269         return (int)args.result;
270         
271 }
272
273 /*
274  * Fire up any non-boot processors.
275  */
276 void
277 cpu_mp_start(void)
278 {
279         volatile struct cpu_start_args *csa;
280         struct pcpu *pc;
281         phandle_t child;
282         phandle_t root;
283         vm_offset_t va;
284         char buf[128];
285         u_int clock;
286         int cpuid, bp_skipped;
287         u_long s;
288
289         root = OF_peer(0);
290         csa = &cpu_start_args;
291         clock = cpuid = bp_skipped = 0;
292         for (child = OF_child(root); child != 0; child = OF_peer(child)) {
293                 if (OF_getprop(child, "device_type", buf, sizeof(buf)) <= 0 ||
294                     strcmp(buf, "cpu") != 0)
295                         continue;
296                 /* skip boot processor */
297                 if (!bp_skipped) {
298                         bp_skipped = 1;
299                         continue;
300                 }
301                 cpuid++;
302
303                 if (OF_getprop(child, "clock-frequency", &clock,
304                     sizeof(clock)) <= 0)
305                         panic("cpu_mp_start: can't get clock");
306
307                 csa->csa_state = 0;
308                 start_ap_bycpuid(cpuid, (void *)mp_tramp, (uint64_t)cpuid);
309                 s = intr_disable();
310                 while (csa->csa_state != CPU_INIT)
311                         ;
312                 intr_restore(s);
313                 mp_ncpus = cpuid + 1;
314 #if 0
315                 cpu_identify(0, clock, cpuid);
316 #endif
317                 va = kmem_alloc(kernel_map, PCPU_PAGES * PAGE_SIZE);
318                 pc = (struct pcpu *)(va + (PCPU_PAGES * PAGE_SIZE)) - 1;
319                 pcpu_init(pc, cpuid, sizeof(*pc));
320                 pc->pc_addr = va;
321
322                 all_cpus |= 1 << cpuid;
323
324                 if (mp_ncpus == MAXCPU)
325                         break;
326         }
327         printf("%d cpus: UltraSparc T1 Processor (%d.%02d MHz CPU)\n", mp_ncpus,
328             (clock + 4999) / 1000000, ((clock + 4999) / 10000) % 100);
329
330         PCPU_SET(other_cpus, all_cpus & ~(1 << PCPU_GET(cpuid)));
331         smp_active = 1;
332 }
333
334 void
335 cpu_mp_announce(void)
336 {
337 }
338
339 void
340 cpu_mp_unleash(void *v)
341 {
342         volatile struct cpu_start_args *csa;
343         struct pcpu *pc;
344         u_long s;
345
346         csa = &cpu_start_args;
347         csa->csa_count = mp_ncpus;
348         printf("mp_ncpus=%d\n", mp_ncpus);
349         SLIST_FOREACH(pc, &cpuhead, pc_allcpu) {
350                 if (pc->pc_cpuid == PCPU_GET(cpuid)) 
351                         continue;
352
353                 KASSERT(pc->pc_idlethread != NULL,
354                     ("cpu_mp_unleash: idlethread is NULL"));
355                 pc->pc_curthread = pc->pc_idlethread;   
356                 pc->pc_curpcb = pc->pc_curthread->td_pcb;
357                 pc->pc_curpmap = kernel_pmap;
358                 csa->csa_state = 0;
359                 csa->csa_pcpu = TLB_PHYS_TO_DIRECT(vtophys(pc->pc_addr));
360                 DELAY(300);
361                 /* allow AP to run */
362                 csa->csa_cpuid = pc->pc_cpuid;
363                 membar(Sync);
364                 s = intr_disable();
365                 while (csa->csa_state != CPU_BOOTSTRAP)
366                         ;
367                 intr_restore(s);
368         }
369
370         membar(StoreLoad);
371         csa->csa_count = 0; 
372         smp_started = 1;
373 }
374
375 void
376 cpu_mp_bootstrap(struct pcpu *pc)
377 {
378         volatile struct cpu_start_args *csa;
379
380         csa = &cpu_start_args;
381         cpu_setregs(pc);
382         tsb_set_scratchpad_kernel(&kernel_pmap->pm_tsb);
383         tte_hash_set_scratchpad_kernel(kernel_pmap->pm_hash);
384         trap_init();
385         cpu_intrq_init();
386         tick_start();
387
388 #ifdef TRAP_TRACING
389         mp_trap_trace_init();
390 #endif
391
392         /* 
393          * enable interrupts now that we have our trap table set
394          */
395         intr_restore_all(PSTATE_KERNEL);
396
397         smp_cpus++;
398         KASSERT(curthread != NULL, ("cpu_mp_bootstrap: curthread"));
399         PCPU_SET(other_cpus, all_cpus & ~(1 << curcpu));
400         printf("AP: #%d\n", curcpu);
401         csa->csa_count--;
402         membar(StoreLoad);
403         csa->csa_state = CPU_BOOTSTRAP;
404
405         while (csa->csa_count != 0)
406                 ;
407         /* ok, now enter the scheduler */
408         sched_throw(NULL);
409 }
410
411 void
412 cpu_mp_shutdown(void)
413 {
414         int i;
415
416         critical_enter();
417         shutdown_cpus = PCPU_GET(other_cpus);
418         if (stopped_cpus != PCPU_GET(other_cpus))       /* XXX */
419                 stop_cpus(stopped_cpus ^ PCPU_GET(other_cpus));
420         i = 0;
421         while (shutdown_cpus != 0) {
422                 if (i++ > 100000) {
423                         printf("timeout shutting down CPUs.\n");
424                         break;
425                 }
426         }
427         /* XXX: delay a bit to allow the CPUs to actually enter the PROM. */
428         DELAY(100000);
429         critical_exit();
430 }
431
432 void
433 cpu_ipi_ast(struct trapframe *tf)
434 {
435 }
436
437 void
438 cpu_ipi_stop(struct trapframe *tf)
439 {
440
441         CTR1(KTR_SMP, "cpu_ipi_stop: stopped %d", curcpu);
442         savectx(&stoppcbs[curcpu]);
443         atomic_set_acq_int(&stopped_cpus, PCPU_GET(cpumask));
444         while ((started_cpus & PCPU_GET(cpumask)) == 0) {
445                 if ((shutdown_cpus & PCPU_GET(cpumask)) != 0) {
446                         atomic_clear_int(&shutdown_cpus, PCPU_GET(cpumask));
447                 }
448         }
449         atomic_clear_rel_int(&started_cpus, PCPU_GET(cpumask));
450         atomic_clear_rel_int(&stopped_cpus, PCPU_GET(cpumask));
451         CTR1(KTR_SMP, "cpu_ipi_stop: restarted %d", curcpu);
452 }
453
454 void
455 cpu_ipi_preempt(struct trapframe *tf)
456 {
457         struct thread *running_thread = curthread;
458
459         thread_lock(running_thread);
460         if (running_thread->td_critnest > 1)
461                 running_thread->td_owepreempt = 1;
462         else
463                 mi_switch(SW_INVOL | SW_PREEMPT, NULL);
464         thread_unlock(running_thread);
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 }