booke_machdep.c revision 1.4 1 /*-
2 * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Raytheon BBN Technologies Corp and Defense Advanced Research Projects
7 * Agency and which was developed by Matt Thomas of 3am Software Foundry.
8 *
9 * This material is based upon work supported by the Defense Advanced Research
10 * Projects Agency and Space and Naval Warfare Systems Center, Pacific, under
11 * Contract No. N66001-09-C-2073.
12 * Approved for Public Release, Distribution Unlimited
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #define __INTR_PRIVATE
37 #define _POWERPC_BUS_DMA_PRIVATE
38
39 #include <sys/cdefs.h>
40
41 #include <sys/param.h>
42 #include <sys/cpu.h>
43 #include <sys/device.h>
44 #include <sys/intr.h>
45 #include <sys/mount.h>
46 #include <sys/msgbuf.h>
47 #include <sys/kernel.h>
48 #include <sys/reboot.h>
49 #include <sys/bus.h>
50
51 #include <uvm/uvm_extern.h>
52
53 #include <powerpc/spr.h>
54 #include <powerpc/booke/spr.h>
55 #include <powerpc/booke/cpuvar.h>
56
57 /*
58 * Global variables used here and there
59 */
60 paddr_t msgbuf_paddr;
61 psize_t pmemsize;
62 struct vm_map *phys_map;
63
64 static bus_addr_t booke_dma_phys_to_bus_mem(bus_dma_tag_t, bus_addr_t);
65 static bus_addr_t booke_dma_bus_mem_to_phys(bus_dma_tag_t, bus_addr_t);
66
67
68 struct powerpc_bus_dma_tag booke_bus_dma_tag = {
69 ._dmamap_create = _bus_dmamap_create,
70 ._dmamap_destroy = _bus_dmamap_destroy,
71 ._dmamap_load = _bus_dmamap_load,
72 ._dmamap_load_mbuf = _bus_dmamap_load_mbuf,
73 ._dmamap_load_uio = _bus_dmamap_load_uio,
74 ._dmamap_load_raw = _bus_dmamap_load_raw,
75 ._dmamap_unload = _bus_dmamap_unload,
76 ._dmamap_sync = _bus_dmamap_sync,
77 ._dmamem_alloc = _bus_dmamem_alloc,
78 ._dmamem_free = _bus_dmamem_free,
79 ._dmamem_map = _bus_dmamem_map,
80 ._dmamem_unmap = _bus_dmamem_unmap,
81 ._dmamem_mmap = _bus_dmamem_mmap,
82 ._dma_phys_to_bus_mem = booke_dma_phys_to_bus_mem,
83 ._dma_bus_mem_to_phys = booke_dma_bus_mem_to_phys,
84 };
85
86 static bus_addr_t
87 booke_dma_phys_to_bus_mem(bus_dma_tag_t t, bus_addr_t a)
88 {
89 return a;
90 }
91
92 static bus_addr_t
93 booke_dma_bus_mem_to_phys(bus_dma_tag_t t, bus_addr_t a)
94 {
95 return a;
96 }
97
98 static int
99 null_splraise(int ipl)
100 {
101 int cpl = curcpu()->ci_cpl;
102 curcpu()->ci_cpl = ipl;
103 return cpl;
104 }
105
106 static void
107 null_splx(int ipl)
108 {
109 curcpu()->ci_cpl = ipl;
110 }
111
112 static const struct intrsw null_intrsw = {
113 .intrsw_splraise = null_splraise,
114 .intrsw_splx = null_splx,
115 };
116
117 const struct intrsw *powerpc_intrsw = &null_intrsw;
118 struct cpu_md_ops cpu_md_ops;
119 extern struct cpu_info cpu_info[1];
120
121 #if 0
122 pt_entry_t ptp0[NPTEPG] = {
123 [(0x20000 & SEGOFSET) >> PGSHIFT] = 0x00020000|PTE_xR|PTE_xX|PTE_M,
124 };
125
126 struct pmap_segtab pmap_kern_segtab = {
127 .seg_tab[0x20000 >> SEGSHIFT] = ptp0,
128 };
129 #endif
130
131 struct cpu_softc cpu_softc[1] = {
132 [0] = {
133 .cpu_ci = cpu_info,
134 },
135 };
136 struct cpu_info cpu_info[1] = {
137 [0] = {
138 .ci_curlwp = &lwp0,
139 .ci_tlb_info = &pmap_tlb0_info,
140 .ci_softc = cpu_softc,
141 .ci_cpl = IPL_HIGH,
142 .ci_fpulwp = &lwp0,
143 .ci_veclwp = &lwp0,
144 #if 0
145 .ci_pmap_kern_segtab = &pmap_kern_segtab,
146 #endif
147 },
148 };
149
150 /*
151 * This should probably be in autoconf! XXX
152 */
153 char cpu_model[80];
154 char machine[] = MACHINE; /* from <machine/param.h> */
155 char machine_arch[] = MACHINE_ARCH; /* from <machine/param.h> */
156
157 char bootpath[256];
158
159 #if NKSYMS || defined(DDB) || defined(MODULAR)
160 void *startsym, *endsym;
161 #endif
162
163 int fake_mapiodev = 1;
164
165 void lcsplx(int);
166
167 void
168 booke_cpu_startup(const char *model)
169 {
170 vaddr_t minaddr, maxaddr;
171 char pbuf[9];
172
173 strlcpy(cpu_model, model, sizeof(cpu_model));
174
175 printf("%s%s", copyright, version);
176
177 format_bytes(pbuf, sizeof(pbuf), ctob(physmem));
178 printf("total memory = %s\n", pbuf);
179
180 minaddr = 0;
181 /*
182 * Allocate a submap for physio
183 */
184 phys_map = uvm_km_suballoc(kernel_map, &minaddr, &maxaddr,
185 VM_PHYS_SIZE, 0, false, NULL);
186
187 /*
188 * No need to allocate an mbuf cluster submap. Mbuf clusters
189 * are allocated via the pool allocator, and we use direct-mapped
190 * pool pages.
191 */
192
193 format_bytes(pbuf, sizeof(pbuf), ptoa(uvmexp.free));
194 printf("avail memory = %s\n", pbuf);
195
196 /*
197 * Set up the board properties database.
198 */
199 board_info_init();
200
201 /*
202 * Now that we have VM, malloc()s are OK in bus_space.
203 */
204 bus_space_mallocok();
205 fake_mapiodev = 0;
206 }
207
208 static void
209 dumpsys(void)
210 {
211
212 printf("dumpsys: TBD\n");
213 }
214
215 /*
216 * Halt or reboot the machine after syncing/dumping according to howto.
217 */
218 void
219 cpu_reboot(int howto, char *what)
220 {
221 static int syncing;
222 static char str[256];
223 char *ap = str, *ap1 = ap;
224
225 boothowto = howto;
226 if (!cold && !(howto & RB_NOSYNC) && !syncing) {
227 syncing = 1;
228 vfs_shutdown(); /* sync */
229 resettodr(); /* set wall clock */
230 }
231
232 splhigh();
233
234 if (!cold && (howto & RB_DUMP))
235 dumpsys();
236
237 doshutdownhooks();
238
239 pmf_system_shutdown(boothowto);
240
241 if ((howto & RB_POWERDOWN) == RB_POWERDOWN) {
242 /* Power off here if we know how...*/
243 }
244
245 if (howto & RB_HALT) {
246 printf("halted\n\n");
247
248 goto reboot; /* XXX for now... */
249
250 #ifdef DDB
251 printf("dropping to debugger\n");
252 while(1)
253 Debugger();
254 #endif
255 }
256
257 printf("rebooting\n\n");
258 if (what && *what) {
259 if (strlen(what) > sizeof str - 5)
260 printf("boot string too large, ignored\n");
261 else {
262 strcpy(str, what);
263 ap1 = ap = str + strlen(str);
264 *ap++ = ' ';
265 }
266 }
267 *ap++ = '-';
268 if (howto & RB_SINGLE)
269 *ap++ = 's';
270 if (howto & RB_KDB)
271 *ap++ = 'd';
272 *ap++ = 0;
273 if (ap[-2] == '-')
274 *ap1 = 0;
275
276 /* flush cache for msgbuf */
277 dcache_wb(msgbuf_paddr, round_page(MSGBUFSIZE));
278
279 reboot:
280 __asm volatile("msync; isync");
281 (*cpu_md_ops.md_cpu_reset)();
282
283 printf("%s: md_cpu_reset() failed!\n", __func__);
284 #ifdef DDB
285 for (;;)
286 Debugger();
287 #else
288 for (;;)
289 /* nothing */;
290 #endif
291 }
292 void
293 lcsplx(int spl)
294 {
295 splx(spl);
296 }
297
298 /*
299 * mapiodev:
300 *
301 * Allocate vm space and mapin the I/O address. Use reserved TLB
302 * mapping if one is found.
303 */
304 void *
305 mapiodev(paddr_t pa, psize_t len)
306 {
307 const vsize_t off = pa & PAGE_MASK;
308
309 /*
310 * See if we have reserved TLB entry for the pa. This needs to be
311 * true for console as we can't use uvm during early bootstrap.
312 */
313 void * const p = tlb_mapiodev(pa, len);
314 if (p != NULL)
315 return p;
316
317 if (fake_mapiodev)
318 panic("mapiodev: no TLB entry reserved for %llx+%llx",
319 (long long)pa, (long long)len);
320
321 pa = trunc_page(pa);
322 len = round_page(off + len);
323 vaddr_t va = uvm_km_alloc(kernel_map, len, 0, UVM_KMF_VAONLY);
324
325 if (va == 0)
326 return NULL;
327
328 for (va += len, pa += len; len > 0; len -= PAGE_SIZE) {
329 va -= PAGE_SIZE;
330 pa -= PAGE_SIZE;
331 pmap_kenter_pa(va, pa, VM_PROT_READ|VM_PROT_WRITE,
332 PMAP_NOCACHE);
333 }
334 pmap_update(pmap_kernel());
335 return (void *)(va + off);
336 }
337
338 void
339 unmapiodev(vaddr_t va, vsize_t len)
340 {
341 /* Nothing to do for reserved (ie. not uvm_km_alloc'd) mappings. */
342 if (va < VM_MIN_KERNEL_ADDRESS || va > VM_MAX_KERNEL_ADDRESS) {
343 tlb_unmapiodev(va, len);
344 return;
345 }
346
347 len = round_page((va & PAGE_MASK) + len);
348 va = trunc_page(va);
349
350 pmap_kremove(va, len);
351 uvm_km_free(kernel_map, va, len, UVM_KMF_VAONLY);
352 }
353
354 void
355 cpu_evcnt_attach(struct cpu_info *ci)
356 {
357 struct cpu_softc * const cpu = ci->ci_softc;
358 const char * const xname = device_xname(ci->ci_dev);
359
360 evcnt_attach_dynamic_nozero(&ci->ci_ev_clock, EVCNT_TYPE_INTR,
361 NULL, xname, "clock");
362 evcnt_attach_dynamic_nozero(&cpu->cpu_ev_late_clock, EVCNT_TYPE_INTR,
363 NULL, xname, "late clock");
364 evcnt_attach_dynamic_nozero(&cpu->cpu_ev_exec_trap_sync, EVCNT_TYPE_TRAP,
365 NULL, xname, "exec pages synced (trap)");
366 #ifndef __HAVE_FAST_SOFTINTS
367 evcnt_attach_dynamic_nozero(&ci->ci_ev_softclock, EVCNT_TYPE_INTR,
368 NULL, xname, "soft clock");
369 evcnt_attach_dynamic_nozero(&ci->ci_ev_softnet, EVCNT_TYPE_INTR,
370 NULL, xname, "soft net");
371 evcnt_attach_dynamic_nozero(&ci->ci_ev_softserial, EVCNT_TYPE_INTR,
372 NULL, xname, "soft serial");
373 #endif
374 evcnt_attach_dynamic_nozero(&ci->ci_ev_traps, EVCNT_TYPE_TRAP,
375 NULL, xname, "traps");
376 evcnt_attach_dynamic_nozero(&ci->ci_ev_kdsi, EVCNT_TYPE_TRAP,
377 &ci->ci_ev_traps, xname, "kernel DSI traps");
378 evcnt_attach_dynamic_nozero(&ci->ci_ev_udsi, EVCNT_TYPE_TRAP,
379 &ci->ci_ev_traps, xname, "user DSI traps");
380 evcnt_attach_dynamic_nozero(&ci->ci_ev_udsi_fatal, EVCNT_TYPE_TRAP,
381 &ci->ci_ev_udsi, xname, "user DSI failures");
382 evcnt_attach_dynamic_nozero(&ci->ci_ev_kisi, EVCNT_TYPE_TRAP,
383 &ci->ci_ev_traps, xname, "kernel ISI traps");
384 evcnt_attach_dynamic_nozero(&ci->ci_ev_isi, EVCNT_TYPE_TRAP,
385 &ci->ci_ev_traps, xname, "user ISI traps");
386 evcnt_attach_dynamic_nozero(&ci->ci_ev_isi_fatal, EVCNT_TYPE_TRAP,
387 &ci->ci_ev_isi, xname, "user ISI failures");
388 evcnt_attach_dynamic_nozero(&ci->ci_ev_scalls, EVCNT_TYPE_TRAP,
389 &ci->ci_ev_traps, xname, "system call traps");
390 evcnt_attach_dynamic_nozero(&ci->ci_ev_pgm, EVCNT_TYPE_TRAP,
391 &ci->ci_ev_traps, xname, "PGM traps");
392 evcnt_attach_dynamic_nozero(&ci->ci_ev_debug, EVCNT_TYPE_TRAP,
393 &ci->ci_ev_traps, xname, "debug traps");
394 evcnt_attach_dynamic_nozero(&ci->ci_ev_fpu, EVCNT_TYPE_TRAP,
395 &ci->ci_ev_traps, xname, "FPU unavailable traps");
396 evcnt_attach_dynamic_nozero(&ci->ci_ev_fpusw, EVCNT_TYPE_MISC,
397 &ci->ci_ev_fpu, xname, "FPU context switches");
398 evcnt_attach_dynamic_nozero(&ci->ci_ev_ali, EVCNT_TYPE_TRAP,
399 &ci->ci_ev_traps, xname, "user alignment traps");
400 evcnt_attach_dynamic_nozero(&ci->ci_ev_ali_fatal, EVCNT_TYPE_TRAP,
401 &ci->ci_ev_ali, xname, "user alignment traps");
402 evcnt_attach_dynamic_nozero(&ci->ci_ev_umchk, EVCNT_TYPE_TRAP,
403 &ci->ci_ev_umchk, xname, "user MCHK failures");
404 evcnt_attach_dynamic_nozero(&ci->ci_ev_vec, EVCNT_TYPE_TRAP,
405 &ci->ci_ev_traps, xname, "SPE unavailable");
406 evcnt_attach_dynamic_nozero(&ci->ci_ev_vecsw, EVCNT_TYPE_MISC,
407 &ci->ci_ev_vec, xname, "SPE context switches");
408 evcnt_attach_dynamic_nozero(&ci->ci_ev_ipi, EVCNT_TYPE_INTR,
409 NULL, xname, "IPIs");
410 evcnt_attach_dynamic_nozero(&ci->ci_ev_tlbmiss_soft, EVCNT_TYPE_TRAP,
411 &ci->ci_ev_traps, xname, "soft tlb misses");
412 evcnt_attach_dynamic_nozero(&ci->ci_ev_dtlbmiss_hard, EVCNT_TYPE_TRAP,
413 &ci->ci_ev_traps, xname, "data tlb misses");
414 evcnt_attach_dynamic_nozero(&ci->ci_ev_itlbmiss_hard, EVCNT_TYPE_TRAP,
415 &ci->ci_ev_traps, xname, "inst tlb misses");
416 }
417
418 uint32_t
419 cpu_read_4(bus_addr_t a)
420 {
421 struct cpu_softc * const cpu = curcpu()->ci_softc;
422 // printf(" %s(%p, %x, %x)", __func__, cpu->cpu_bst, cpu->cpu_bsh, a);
423 return bus_space_read_4(cpu->cpu_bst, cpu->cpu_bsh, a);
424 }
425
426 uint8_t
427 cpu_read_1(bus_addr_t a)
428 {
429 struct cpu_softc * const cpu = curcpu()->ci_softc;
430 // printf(" %s(%p, %x, %x)", __func__, cpu->cpu_bst, cpu->cpu_bsh, a);
431 return bus_space_read_1(cpu->cpu_bst, cpu->cpu_bsh, a);
432 }
433
434 void
435 cpu_write_4(bus_addr_t a, uint32_t v)
436 {
437 struct cpu_softc * const cpu = curcpu()->ci_softc;
438 bus_space_write_4(cpu->cpu_bst, cpu->cpu_bsh, a, v);
439 }
440
441 void
442 cpu_write_1(bus_addr_t a, uint8_t v)
443 {
444 struct cpu_softc * const cpu = curcpu()->ci_softc;
445 bus_space_write_1(cpu->cpu_bst, cpu->cpu_bsh, a, v);
446 }
447
448 void
449 booke_sstep(struct trapframe *tf)
450 {
451 KASSERT(tf->tf_srr1 & PSL_DE);
452 const uint32_t insn = ufetch_32((const void *)tf->tf_srr0);
453 register_t dbcr0 = DBCR0_IAC1 | DBCR0_IDM;
454 register_t dbcr1 = DBCR1_IAC1US_USER | DBCR1_IAC1ER_DS1;
455 if ((insn >> 28) == 4) {
456 uint32_t iac2 = 0;
457 if ((insn >> 26) == 0x12) {
458 const int32_t off = (((int32_t)insn << 6) >> 6) & ~3;
459 iac2 = ((insn & 2) ? 0 : tf->tf_srr0) + off;
460 dbcr0 |= DBCR0_IAC2;
461 } else if ((insn >> 26) == 0x10) {
462 const int16_t off = insn & ~3;
463 iac2 = ((insn & 2) ? 0 : tf->tf_srr0) + off;
464 dbcr0 |= DBCR0_IAC2;
465 } else if ((insn & 0xfc00ffde) == 0x4c000420) {
466 iac2 = tf->tf_ctr;
467 dbcr0 |= DBCR0_IAC2;
468 } else if ((insn & 0xfc00ffde) == 0x4c000020) {
469 iac2 = tf->tf_lr;
470 dbcr0 |= DBCR0_IAC2;
471 }
472 if (dbcr0 & DBCR0_IAC2) {
473 dbcr1 |= DBCR1_IAC2US_USER | DBCR1_IAC2ER_DS1;
474 mtspr(SPR_IAC2, iac2);
475 }
476 }
477 mtspr(SPR_IAC1, tf->tf_srr0 + 4);
478 mtspr(SPR_DBCR1, dbcr1);
479 mtspr(SPR_DBCR0, dbcr0);
480 }
481