Annotation of sys/arch/hppa/hppa/mainbus.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: mainbus.c,v 1.66 2007/07/15 20:11:12 kettenis Exp $ */
2:
3: /*
4: * Copyright (c) 1998-2004 Michael Shalayeff
5: * All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: *
16: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19: * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22: * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25: * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26: * THE POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29: #include "lcd.h"
30: #include "power.h"
31:
32: #undef BTLBDEBUG
33:
34: #include <sys/param.h>
35: #include <sys/systm.h>
36: #include <sys/device.h>
37: #include <sys/reboot.h>
38: #include <sys/extent.h>
39: #include <sys/mbuf.h>
40:
41: #include <uvm/uvm.h>
42: #include <uvm/uvm_page.h>
43:
44: #include <machine/bus.h>
45: #include <machine/pdc.h>
46: #include <machine/iomod.h>
47: #include <machine/autoconf.h>
48:
49: #include <hppa/dev/cpudevs.h>
50:
51: struct mainbus_softc {
52: struct device sc_dv;
53:
54: hppa_hpa_t sc_hpa;
55: };
56:
57: int mbmatch(struct device *, void *, void *);
58: void mbattach(struct device *, struct device *, void *);
59:
60: struct cfattach mainbus_ca = {
61: sizeof(struct mainbus_softc), mbmatch, mbattach
62: };
63:
64: struct cfdriver mainbus_cd = {
65: NULL, "mainbus", DV_DULL
66: };
67:
68: struct pdc_hpa pdc_hpa PDC_ALIGNMENT;
69: struct pdc_power_info pdc_power_info PDC_ALIGNMENT;
70: struct pdc_chassis_info pdc_chassis_info PDC_ALIGNMENT;
71: struct pdc_chassis_lcd pdc_chassis_lcd PDC_ALIGNMENT;
72:
73: /* from machdep.c */
74: extern struct extent *hppa_ex;
75: extern struct pdc_btlb pdc_btlb;
76:
77: int
78: mbus_add_mapping(bus_addr_t bpa, bus_size_t size, int flags,
79: bus_space_handle_t *bshp)
80: {
81: static u_int32_t bmm[0x4000/32];
82: int bank, off, flex = HPPA_FLEX(bpa);
83: u_int64_t spa, epa;
84:
85: #ifdef BTLBDEBUG
86: printf("bus_mem_add_mapping(%x,%x,%scachable,%p)\n",
87: bpa, size, flags? "" : "non", bshp);
88: #endif
89:
90: if ((bank = vm_physseg_find(atop(bpa), &off)) >= 0)
91: panic("mbus_add_mapping: mapping real memory @0x%lx", bpa);
92:
93: /*
94: * determine if we are mapping IO space, or beyond the physmem
95: * region. use block mapping then
96: *
97: * we map the whole bus module (there are 1024 of those max)
98: * so, check here if it's mapped already, map if needed.
99: * all mappings are equal mappings.
100: */
101: #ifdef DEBUG
102: if (flags & BUS_SPACE_MAP_CACHEABLE) {
103: printf("WARNING: mapping I/O space cachable\n");
104: flags &= ~BUS_SPACE_MAP_CACHEABLE;
105: }
106: #endif
107:
108: /* need a new mapping */
109: if (!(bmm[flex / 32] & (1 << (flex % 32)))) {
110: spa = bpa & HPPA_FLEX_MASK;
111: epa = ((u_long)((u_int64_t)bpa + size +
112: ~HPPA_FLEX_MASK - 1) & HPPA_FLEX_MASK) - 1;
113: #ifdef BTLBDEBUG
114: printf("bus_mem_add_mapping: adding flex=%x "
115: "%qx-%qx, ", flex, spa, epa);
116: #endif
117: while (spa < epa) {
118: vsize_t len = epa - spa;
119: u_int64_t pa;
120: if (len > pdc_btlb.max_size << PGSHIFT)
121: len = pdc_btlb.max_size << PGSHIFT;
122: if (btlb_insert(HPPA_SID_KERNEL, spa, spa, &len,
123: pmap_sid2pid(HPPA_SID_KERNEL) |
124: pmap_prot(pmap_kernel(), UVM_PROT_RW)) >= 0) {
125: pa = spa + len - 1;
126: #ifdef BTLBDEBUG
127: printf("--- %x/%x, %qx, %qx-%qx",
128: flex, HPPA_FLEX(pa), pa, spa, epa);
129: #endif
130: /* do the mask */
131: for (; flex <= HPPA_FLEX(pa); flex++) {
132: #ifdef BTLBDEBUG
133: printf("mask %x ", flex);
134: #endif
135: bmm[flex / 32] |= (1 << (flex % 32));
136: }
137: spa = pa;
138: } else {
139: spa = trunc_page(bpa);
140: epa = round_page(bpa + size);
141:
142: if (epa - 1 > ~0U)
143: epa = (u_int64_t)~0U + 1;
144:
145: #ifdef BTLBDEBUG
146: printf("kenter 0x%qx-0x%qx", spa, epa);
147: #endif
148: for (; spa < epa; spa += PAGE_SIZE)
149: pmap_kenter_pa(spa, spa, UVM_PROT_RW);
150: }
151: #ifdef BTLBDEBUG
152: printf("\n");
153: #endif
154: }
155: }
156: #ifdef BTLBDEBUG
157: else {
158: printf("+++ already b-mapped flex=%x, mask=%x",
159: flex, bmm[flex / 8]);
160: }
161: #endif
162:
163: *bshp = bpa;
164: return (0);
165: }
166:
167: int
168: mbus_map(void *v, bus_addr_t bpa, bus_size_t size,
169: int flags, bus_space_handle_t *bshp)
170: {
171: int error;
172:
173: if (!(flags & BUS_SPACE_MAP_NOEXTENT) &&
174: (error = extent_alloc_region(hppa_ex, bpa, size, EX_NOWAIT)))
175: return (error);
176:
177: if ((error = mbus_add_mapping(bpa, size, flags, bshp))) {
178: if (extent_free(hppa_ex, bpa, size, EX_NOWAIT)) {
179: printf("bus_space_map: pa 0x%lx, size 0x%lx\n",
180: bpa, size);
181: printf("bus_space_map: can't free region\n");
182: }
183: }
184:
185: return error;
186: }
187:
188: void
189: mbus_unmap(void *v, bus_space_handle_t bsh, bus_size_t size)
190: {
191: u_long sva, eva;
192:
193: sva = trunc_page(bsh);
194: eva = round_page(bsh + size);
195:
196: #ifdef DIAGNOSTIC
197: if (eva <= sva)
198: panic("bus_space_unmap: overflow");
199: #endif
200:
201: if (pmap_extract(pmap_kernel(), bsh, NULL))
202: pmap_kremove(sva, eva - sva);
203: else
204: ; /* XXX assuming equ b-mapping been done */
205:
206: if (extent_free(hppa_ex, bsh, size, EX_NOWAIT)) {
207: printf("bus_space_unmap: ps 0x%lx, size 0x%lx\n",
208: bsh, size);
209: printf("bus_space_unmap: can't free region\n");
210: }
211: }
212:
213: int
214: mbus_alloc(void *v, bus_addr_t rstart, bus_addr_t rend, bus_size_t size,
215: bus_size_t align, bus_size_t boundary, int flags,
216: bus_addr_t *addrp, bus_space_handle_t *bshp)
217: {
218: u_long bpa;
219: int error;
220:
221: if (rstart < hppa_ex->ex_start || rend > hppa_ex->ex_end)
222: panic("bus_space_alloc: bad region start/end");
223:
224: if ((error = extent_alloc_subregion(hppa_ex, rstart, rend, size,
225: align, 0, boundary, EX_NOWAIT, &bpa)))
226: return (error);
227:
228: if ((error = mbus_add_mapping(bpa, size, flags, bshp))) {
229: if (extent_free(hppa_ex, bpa, size, EX_NOWAIT)) {
230: printf("bus_space_alloc: pa 0x%lx, size 0x%lx\n",
231: bpa, size);
232: printf("bus_space_alloc: can't free region\n");
233: }
234: }
235:
236: *addrp = bpa;
237: return (error);
238: }
239:
240: void
241: mbus_free(void *v, bus_space_handle_t h, bus_size_t size)
242: {
243: /* bus_space_unmap() does all that we need to do. */
244: mbus_unmap(v, h, size);
245: }
246:
247: int
248: mbus_subregion(void *v, bus_space_handle_t bsh, bus_size_t offset,
249: bus_size_t size, bus_space_handle_t *nbshp)
250: {
251: *nbshp = bsh + offset;
252: return (0);
253: }
254:
255: void
256: mbus_barrier(void *v, bus_space_handle_t h, bus_size_t o, bus_size_t l, int op)
257: {
258: sync_caches();
259: }
260:
261: void *
262: mbus_vaddr(void *v, bus_space_handle_t h)
263: {
264: return ((void *)h);
265: }
266:
267: u_int8_t
268: mbus_r1(void *v, bus_space_handle_t h, bus_size_t o)
269: {
270: return *((volatile u_int8_t *)(h + o));
271: }
272:
273: u_int16_t
274: mbus_r2(void *v, bus_space_handle_t h, bus_size_t o)
275: {
276: return *((volatile u_int16_t *)(h + o));
277: }
278:
279: u_int32_t
280: mbus_r4(void *v, bus_space_handle_t h, bus_size_t o)
281: {
282: return *((volatile u_int32_t *)(h + o));
283: }
284:
285: u_int64_t
286: mbus_r8(void *v, bus_space_handle_t h, bus_size_t o)
287: {
288: return *((volatile u_int64_t *)(h + o));
289: }
290:
291: void
292: mbus_w1(void *v, bus_space_handle_t h, bus_size_t o, u_int8_t vv)
293: {
294: *((volatile u_int8_t *)(h + o)) = vv;
295: }
296:
297: void
298: mbus_w2(void *v, bus_space_handle_t h, bus_size_t o, u_int16_t vv)
299: {
300: *((volatile u_int16_t *)(h + o)) = vv;
301: }
302:
303: void
304: mbus_w4(void *v, bus_space_handle_t h, bus_size_t o, u_int32_t vv)
305: {
306: *((volatile u_int32_t *)(h + o)) = vv;
307: }
308:
309: void
310: mbus_w8(void *v, bus_space_handle_t h, bus_size_t o, u_int64_t vv)
311: {
312: *((volatile u_int64_t *)(h + o)) = vv;
313: }
314:
315:
316: void
317: mbus_rm_1(void *v, bus_space_handle_t h, bus_size_t o, u_int8_t *a, bus_size_t c)
318: {
319: h += o;
320: while (c--)
321: *(a++) = *(volatile u_int8_t *)h;
322: }
323:
324: void
325: mbus_rm_2(void *v, bus_space_handle_t h, bus_size_t o, u_int16_t *a, bus_size_t c)
326: {
327: h += o;
328: while (c--)
329: *(a++) = *(volatile u_int16_t *)h;
330: }
331:
332: void
333: mbus_rm_4(void *v, bus_space_handle_t h, bus_size_t o, u_int32_t *a, bus_size_t c)
334: {
335: h += o;
336: while (c--)
337: *(a++) = *(volatile u_int32_t *)h;
338: }
339:
340: void
341: mbus_rm_8(void *v, bus_space_handle_t h, bus_size_t o, u_int64_t *a, bus_size_t c)
342: {
343: h += o;
344: while (c--)
345: *(a++) = *(volatile u_int64_t *)h;
346: }
347:
348: void
349: mbus_wm_1(void *v, bus_space_handle_t h, bus_size_t o, const u_int8_t *a, bus_size_t c)
350: {
351: h += o;
352: while (c--)
353: *(volatile u_int8_t *)h = *(a++);
354: }
355:
356: void
357: mbus_wm_2(void *v, bus_space_handle_t h, bus_size_t o, const u_int16_t *a, bus_size_t c)
358: {
359: h += o;
360: while (c--)
361: *(volatile u_int16_t *)h = *(a++);
362: }
363:
364: void
365: mbus_wm_4(void *v, bus_space_handle_t h, bus_size_t o, const u_int32_t *a, bus_size_t c)
366: {
367: h += o;
368: while (c--)
369: *(volatile u_int32_t *)h = *(a++);
370: }
371:
372: void
373: mbus_wm_8(void *v, bus_space_handle_t h, bus_size_t o, const u_int64_t *a, bus_size_t c)
374: {
375: h += o;
376: while (c--)
377: *(volatile u_int64_t *)h = *(a++);
378: }
379:
380: void
381: mbus_sm_1(void *v, bus_space_handle_t h, bus_size_t o, u_int8_t vv, bus_size_t c)
382: {
383: h += o;
384: while (c--)
385: *(volatile u_int8_t *)h = vv;
386: }
387:
388: void
389: mbus_sm_2(void *v, bus_space_handle_t h, bus_size_t o, u_int16_t vv, bus_size_t c)
390: {
391: h += o;
392: while (c--)
393: *(volatile u_int16_t *)h = vv;
394: }
395:
396: void
397: mbus_sm_4(void *v, bus_space_handle_t h, bus_size_t o, u_int32_t vv, bus_size_t c)
398: {
399: h += o;
400: while (c--)
401: *(volatile u_int32_t *)h = vv;
402: }
403:
404: void
405: mbus_sm_8(void *v, bus_space_handle_t h, bus_size_t o, u_int64_t vv, bus_size_t c)
406: {
407: h += o;
408: while (c--)
409: *(volatile u_int64_t *)h = vv;
410: }
411:
412: void mbus_rrm_2(void *v, bus_space_handle_t h,
413: bus_size_t o, u_int16_t*a, bus_size_t c);
414: void mbus_rrm_4(void *v, bus_space_handle_t h,
415: bus_size_t o, u_int32_t*a, bus_size_t c);
416: void mbus_rrm_8(void *v, bus_space_handle_t h,
417: bus_size_t o, u_int64_t*a, bus_size_t c);
418:
419: void mbus_wrm_2(void *v, bus_space_handle_t h,
420: bus_size_t o, const u_int16_t *a, bus_size_t c);
421: void mbus_wrm_4(void *v, bus_space_handle_t h,
422: bus_size_t o, const u_int32_t *a, bus_size_t c);
423: void mbus_wrm_8(void *v, bus_space_handle_t h,
424: bus_size_t o, const u_int64_t *a, bus_size_t c);
425:
426: void
427: mbus_rr_1(void *v, bus_space_handle_t h, bus_size_t o, u_int8_t *a, bus_size_t c)
428: {
429: h += o;
430: while (c--)
431: *(a++) = *((volatile u_int8_t *)h)++;
432: }
433:
434: void
435: mbus_rr_2(void *v, bus_space_handle_t h, bus_size_t o, u_int16_t *a, bus_size_t c)
436: {
437: h += o;
438: while (c--)
439: *(a++) = *((volatile u_int16_t *)h)++;
440: }
441:
442: void
443: mbus_rr_4(void *v, bus_space_handle_t h, bus_size_t o, u_int32_t *a, bus_size_t c)
444: {
445: h += o;
446: while (c--)
447: *(a++) = *((volatile u_int32_t *)h)++;
448: }
449:
450: void
451: mbus_rr_8(void *v, bus_space_handle_t h, bus_size_t o, u_int64_t *a, bus_size_t c)
452: {
453: h += o;
454: while (c--)
455: *(a++) = *((volatile u_int64_t *)h)++;
456: }
457:
458: void
459: mbus_wr_1(void *v, bus_space_handle_t h, bus_size_t o, const u_int8_t *a, bus_size_t c)
460: {
461: h += o;
462: while (c--)
463: *((volatile u_int8_t *)h)++ = *(a++);
464: }
465:
466: void
467: mbus_wr_2(void *v, bus_space_handle_t h, bus_size_t o, const u_int16_t *a, bus_size_t c)
468: {
469: h += o;
470: while (c--)
471: *((volatile u_int16_t *)h)++ = *(a++);
472: }
473:
474: void
475: mbus_wr_4(void *v, bus_space_handle_t h, bus_size_t o, const u_int32_t *a, bus_size_t c)
476: {
477: h += o;
478: while (c--)
479: *((volatile u_int32_t *)h)++ = *(a++);
480: }
481:
482: void
483: mbus_wr_8(void *v, bus_space_handle_t h, bus_size_t o, const u_int64_t *a, bus_size_t c)
484: {
485: h += o;
486: while (c--)
487: *((volatile u_int64_t *)h)++ = *(a++);
488: }
489:
490: void mbus_rrr_2(void *v, bus_space_handle_t h,
491: bus_size_t o, u_int16_t *a, bus_size_t c);
492: void mbus_rrr_4(void *v, bus_space_handle_t h,
493: bus_size_t o, u_int32_t *a, bus_size_t c);
494: void mbus_rrr_8(void *v, bus_space_handle_t h,
495: bus_size_t o, u_int64_t *a, bus_size_t c);
496:
497: void mbus_wrr_2(void *v, bus_space_handle_t h,
498: bus_size_t o, const u_int16_t *a, bus_size_t c);
499: void mbus_wrr_4(void *v, bus_space_handle_t h,
500: bus_size_t o, const u_int32_t *a, bus_size_t c);
501: void mbus_wrr_8(void *v, bus_space_handle_t h,
502: bus_size_t o, const u_int64_t *a, bus_size_t c);
503:
504: void
505: mbus_sr_1(void *v, bus_space_handle_t h, bus_size_t o, u_int8_t vv, bus_size_t c)
506: {
507: h += o;
508: while (c--)
509: *((volatile u_int8_t *)h)++ = vv;
510: }
511:
512: void
513: mbus_sr_2(void *v, bus_space_handle_t h, bus_size_t o, u_int16_t vv, bus_size_t c)
514: {
515: h += o;
516: while (c--)
517: *((volatile u_int16_t *)h)++ = vv;
518: }
519:
520: void
521: mbus_sr_4(void *v, bus_space_handle_t h, bus_size_t o, u_int32_t vv, bus_size_t c)
522: {
523: h += o;
524: while (c--)
525: *((volatile u_int32_t *)h)++ = vv;
526: }
527:
528: void
529: mbus_sr_8(void *v, bus_space_handle_t h, bus_size_t o, u_int64_t vv, bus_size_t c)
530: {
531: h += o;
532: while (c--)
533: *((volatile u_int64_t *)h)++ = vv;
534: }
535:
536: void
537: mbus_cp_1(void *v, bus_space_handle_t h1, bus_size_t o1,
538: bus_space_handle_t h2, bus_size_t o2, bus_size_t c)
539: {
540: h1 += o1;
541: h2 += o2;
542: while (c--)
543: *((volatile u_int8_t *)h1)++ =
544: *((volatile u_int8_t *)h2)++;
545: }
546:
547: void
548: mbus_cp_2(void *v, bus_space_handle_t h1, bus_size_t o1,
549: bus_space_handle_t h2, bus_size_t o2, bus_size_t c)
550: {
551: h1 += o1;
552: h2 += o2;
553: while (c--)
554: *((volatile u_int16_t *)h1)++ =
555: *((volatile u_int16_t *)h2)++;
556: }
557:
558: void
559: mbus_cp_4(void *v, bus_space_handle_t h1, bus_size_t o1,
560: bus_space_handle_t h2, bus_size_t o2, bus_size_t c)
561: {
562: h1 += o1;
563: h2 += o2;
564: while (c--)
565: *((volatile u_int32_t *)h1)++ =
566: *((volatile u_int32_t *)h2)++;
567: }
568:
569: void
570: mbus_cp_8(void *v, bus_space_handle_t h1, bus_size_t o1,
571: bus_space_handle_t h2, bus_size_t o2, bus_size_t c)
572: {
573: h1 += o1;
574: h2 += o2;
575: while (c--)
576: *((volatile u_int64_t *)h1)++ =
577: *((volatile u_int64_t *)h2)++;
578: }
579:
580:
581: /* ugly typecast macro */
582: #define crr(n) ((void (*)(void *, bus_space_handle_t, bus_size_t, u_int8_t *, bus_size_t))(n))
583: #define cwr(n) ((void (*)(void *, bus_space_handle_t, bus_size_t, const u_int8_t *, bus_size_t))(n))
584:
585: const struct hppa_bus_space_tag hppa_bustag = {
586: NULL,
587:
588: mbus_map, mbus_unmap, mbus_subregion, mbus_alloc, mbus_free,
589: mbus_barrier, mbus_vaddr,
590: mbus_r1, mbus_r2, mbus_r4, mbus_r8,
591: mbus_w1, mbus_w2, mbus_w4, mbus_w8,
592: mbus_rm_1, mbus_rm_2, mbus_rm_4, mbus_rm_8,
593: mbus_wm_1, mbus_wm_2, mbus_wm_4, mbus_wm_8,
594: mbus_sm_1, mbus_sm_2, mbus_sm_4, mbus_sm_8,
595: /* *_raw_* are the same as non-raw for native busses */
596: crr(mbus_rm_1), crr(mbus_rm_1), crr(mbus_rm_1),
597: cwr(mbus_wm_1), cwr(mbus_wm_1), cwr(mbus_wm_1),
598: mbus_rr_1, mbus_rr_2, mbus_rr_4, mbus_rr_8,
599: mbus_wr_1, mbus_wr_2, mbus_wr_4, mbus_wr_8,
600: /* *_raw_* are the same as non-raw for native busses */
601: crr(mbus_rr_1), crr(mbus_rr_1), crr(mbus_rr_1),
602: cwr(mbus_wr_1), cwr(mbus_wr_1), cwr(mbus_wr_1),
603: mbus_sr_1, mbus_sr_2, mbus_sr_4, mbus_sr_8,
604: mbus_cp_1, mbus_cp_2, mbus_cp_4, mbus_cp_8
605: };
606:
607: int
608: mbus_dmamap_create(void *v, bus_size_t size, int nsegments,
609: bus_size_t maxsegsz, bus_size_t boundary, int flags,
610: bus_dmamap_t *dmamp)
611: {
612: struct hppa_bus_dmamap *map;
613: size_t mapsize;
614:
615: mapsize = sizeof(struct hppa_bus_dmamap) +
616: (sizeof(bus_dma_segment_t) * (nsegments - 1));
617: map = malloc(mapsize, M_DEVBUF,
618: (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK);
619: if (!map)
620: return (ENOMEM);
621:
622: bzero(map, mapsize);
623: map->_dm_size = size;
624: map->_dm_segcnt = nsegments;
625: map->_dm_maxsegsz = maxsegsz;
626: map->_dm_boundary = boundary;
627: map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT);
628: map->dm_mapsize = 0;
629: map->dm_nsegs = 0;
630:
631: *dmamp = map;
632: return (0);
633: }
634:
635: void
636: mbus_dmamap_unload(void *v, bus_dmamap_t map)
637: {
638: map->dm_mapsize = 0;
639: map->dm_nsegs = 0;
640: }
641:
642: void
643: mbus_dmamap_destroy(void *v, bus_dmamap_t map)
644: {
645: if (map->dm_mapsize != 0)
646: mbus_dmamap_unload(v, map);
647:
648: free(map, M_DEVBUF);
649: }
650:
651: /*
652: * Utility function to load a linear buffer. lastaddrp holds state
653: * between invocations (for multiple-buffer loads). segp contains
654: * the starting segment on entrance, and the ending segment on exit.
655: * first indicates if this is the first invocation of this function.
656: */
657: int
658: _bus_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
659: bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp,
660: int *segp, int first)
661: {
662: bus_size_t sgsize;
663: bus_addr_t curaddr, lastaddr, baddr, bmask;
664: vaddr_t vaddr = (vaddr_t)buf;
665: int seg;
666: pmap_t pmap;
667:
668: pmap = p? p->p_vmspace->vm_map.pmap : pmap_kernel();
669: lastaddr = *lastaddrp;
670: bmask = ~(map->_dm_boundary - 1);
671:
672: for (seg = *segp; buflen > 0 ; ) {
673: /*
674: * Get the physical address for this segment.
675: */
676: pmap_extract(pmap, vaddr, (paddr_t *)&curaddr);
677:
678: /*
679: * Compute the segment size, and adjust counts.
680: */
681: sgsize = PAGE_SIZE - ((u_long)vaddr & PGOFSET);
682: if (buflen < sgsize)
683: sgsize = buflen;
684:
685: /*
686: * Make sure we don't cross any boundaries.
687: */
688: if (map->_dm_boundary > 0) {
689: baddr = (curaddr + map->_dm_boundary) & bmask;
690: if (sgsize > (baddr - curaddr))
691: sgsize = (baddr - curaddr);
692: }
693:
694: /*
695: * Insert chunk into a segment, coalescing with
696: * previous segment if possible.
697: */
698: if (first) {
699: map->dm_segs[seg].ds_addr = curaddr;
700: map->dm_segs[seg].ds_len = sgsize;
701: map->dm_segs[seg]._ds_va = vaddr;
702: first = 0;
703: } else {
704: if (curaddr == lastaddr &&
705: (map->dm_segs[seg].ds_len + sgsize) <=
706: map->_dm_maxsegsz &&
707: (map->_dm_boundary == 0 ||
708: (map->dm_segs[seg].ds_addr & bmask) ==
709: (curaddr & bmask)))
710: map->dm_segs[seg].ds_len += sgsize;
711: else {
712: if (++seg >= map->_dm_segcnt)
713: break;
714: map->dm_segs[seg].ds_addr = curaddr;
715: map->dm_segs[seg].ds_len = sgsize;
716: map->dm_segs[seg]._ds_va = vaddr;
717: }
718: }
719:
720: lastaddr = curaddr + sgsize;
721: vaddr += sgsize;
722: buflen -= sgsize;
723: }
724:
725: *segp = seg;
726: *lastaddrp = lastaddr;
727:
728: /*
729: * Did we fit?
730: */
731: if (buflen != 0)
732: return (EFBIG); /* XXX better return value here? */
733: return (0);
734: }
735:
736: int
737: mbus_dmamap_load(void *v, bus_dmamap_t map, void *addr, bus_size_t size,
738: struct proc *p, int flags)
739: {
740: paddr_t lastaddr;
741: int seg, error;
742:
743: /*
744: * Make sure that on error condition we return "no valid mappings".
745: */
746: map->dm_nsegs = 0;
747: map->dm_mapsize = 0;
748:
749: if (size > map->_dm_size)
750: return (EINVAL);
751:
752: seg = 0;
753: lastaddr = 0;
754: error = _bus_dmamap_load_buffer(NULL, map, addr, size, p, flags,
755: &lastaddr, &seg, 1);
756: if (error == 0) {
757: map->dm_mapsize = size;
758: map->dm_nsegs = seg + 1;
759: }
760:
761: return (0);
762: }
763:
764: int
765: mbus_dmamap_load_mbuf(void *v, bus_dmamap_t map, struct mbuf *m0, int flags)
766: {
767: paddr_t lastaddr;
768: int seg, error, first;
769: struct mbuf *m;
770:
771: map->dm_mapsize = 0;
772: map->dm_nsegs = 0;
773:
774: #ifdef DIAGNOSTIC
775: if ((m0->m_flags & M_PKTHDR) == 0)
776: panic("_bus_dmamap_load_mbuf: no packet header");
777: #endif
778:
779: if (m0->m_pkthdr.len > map->_dm_size)
780: return (EINVAL);
781:
782: first = 1;
783: seg = 0;
784: error = 0;
785: lastaddr = 0;
786: for (m = m0; m != NULL && error == 0; m = m->m_next) {
787: if (m->m_len == 0)
788: continue;
789: error = _bus_dmamap_load_buffer(NULL, map, m->m_data, m->m_len,
790: NULL, flags, &lastaddr, &seg, first);
791: first = 0;
792: }
793: if (error == 0) {
794: map->dm_mapsize = m0->m_pkthdr.len;
795: map->dm_nsegs = seg + 1;
796: }
797:
798: return (error);
799: }
800:
801: int
802: mbus_dmamap_load_uio(void *v, bus_dmamap_t map, struct uio *uio, int flags)
803: {
804: paddr_t lastaddr;
805: int seg, i, error, first;
806: bus_size_t minlen, resid;
807: struct proc *p = NULL;
808: struct iovec *iov;
809: caddr_t addr;
810:
811: /*
812: * Make sure that on error condition we return "no valid mappings".
813: */
814: map->dm_mapsize = 0;
815: map->dm_nsegs = 0;
816:
817: resid = uio->uio_resid;
818: iov = uio->uio_iov;
819:
820: if (resid > map->_dm_size)
821: return (EINVAL);
822:
823: if (uio->uio_segflg == UIO_USERSPACE) {
824: p = uio->uio_procp;
825: #ifdef DIAGNOSTIC
826: if (p == NULL)
827: panic("_bus_dmamap_load_uio: USERSPACE but no proc");
828: #endif
829: }
830:
831: first = 1;
832: seg = 0;
833: error = 0;
834: lastaddr = 0;
835: for (i = 0; i < uio->uio_iovcnt && resid != 0 && error == 0; i++) {
836: /*
837: * Now at the first iovec to load. Load each iovec
838: * until we have exhausted the residual count.
839: */
840: minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
841: addr = (caddr_t)iov[i].iov_base;
842:
843: error = _bus_dmamap_load_buffer(NULL, map, addr, minlen,
844: p, flags, &lastaddr, &seg, first);
845: first = 0;
846:
847: resid -= minlen;
848: }
849: if (error == 0) {
850: map->dm_mapsize = uio->uio_resid;
851: map->dm_nsegs = seg + 1;
852: }
853: return (error);
854: }
855:
856: int
857: mbus_dmamap_load_raw(void *v, bus_dmamap_t map, bus_dma_segment_t *segs,
858: int nsegs, bus_size_t size, int flags)
859: {
860: if (nsegs > map->_dm_segcnt || size > map->_dm_size)
861: return (EINVAL);
862:
863: /*
864: * Make sure we don't cross any boundaries.
865: */
866: if (map->_dm_boundary) {
867: bus_addr_t bmask = ~(map->_dm_boundary - 1);
868: int i;
869:
870: for (i = 0; i < nsegs; i++) {
871: if (segs[i].ds_len > map->_dm_maxsegsz)
872: return (EINVAL);
873: if ((segs[i].ds_addr & bmask) !=
874: ((segs[i].ds_addr + segs[i].ds_len - 1) & bmask))
875: return (EINVAL);
876: }
877: }
878:
879: bcopy(segs, map->dm_segs, nsegs * sizeof(*segs));
880: map->dm_nsegs = nsegs;
881: map->dm_mapsize = size;
882: return (0);
883: }
884:
885: void
886: mbus_dmamap_sync(void *v, bus_dmamap_t map, bus_addr_t off, bus_size_t len,
887: int ops)
888: {
889: bus_dma_segment_t *ps = map->dm_segs,
890: *es = &map->dm_segs[map->dm_nsegs];
891:
892: if (off >= map->_dm_size)
893: return;
894:
895: if ((off + len) > map->_dm_size)
896: len = map->_dm_size - off;
897:
898: for (; len && ps < es; ps++)
899: if (off > ps->ds_len)
900: off -= ps->ds_len;
901: else {
902: bus_size_t l = ps->ds_len - off;
903: if (l > len)
904: l = len;
905: fdcache(HPPA_SID_KERNEL, ps->_ds_va + off, l);
906: len -= l;
907: off = 0;
908: }
909:
910: /* for either operation sync the shit away */
911: __asm __volatile ("sync\n\tsyncdma\n\tsync\n\t"
912: "nop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop\n\tnop");
913: }
914:
915: int
916: mbus_dmamem_alloc(void *v, bus_size_t size, bus_size_t alignment,
917: bus_size_t boundary, bus_dma_segment_t *segs, int nsegs,
918: int *rsegs, int flags)
919: {
920: extern paddr_t avail_end;
921: struct pglist pglist;
922: struct vm_page *pg;
923:
924: size = round_page(size);
925:
926: TAILQ_INIT(&pglist);
927: if (uvm_pglistalloc(size, 0, avail_end, alignment, boundary,
928: &pglist, 1, flags & BUS_DMA_NOWAIT))
929: return (ENOMEM);
930:
931: pg = TAILQ_FIRST(&pglist);
932: segs[0]._ds_va = segs[0].ds_addr = VM_PAGE_TO_PHYS(pg);
933: segs[0].ds_len = size;
934: *rsegs = 1;
935:
936: for(; pg; pg = TAILQ_NEXT(pg, pageq))
937: /* XXX for now */
938: pmap_changebit(pg, PTE_PROT(TLB_UNCACHABLE), 0);
939: pmap_update(pmap_kernel());
940:
941: return (0);
942: }
943:
944: void
945: mbus_dmamem_free(void *v, bus_dma_segment_t *segs, int nsegs)
946: {
947: struct pglist pglist;
948: paddr_t pa, epa;
949:
950: TAILQ_INIT(&pglist);
951: for(; nsegs--; segs++)
952: for (pa = segs->ds_addr, epa = pa + segs->ds_len;
953: pa < epa; pa += PAGE_SIZE) {
954: struct vm_page *pg = PHYS_TO_VM_PAGE(pa);
955: if (!pg)
956: panic("mbus_dmamem_free: no page for pa");
957: TAILQ_INSERT_TAIL(&pglist, pg, pageq);
958: }
959: uvm_pglistfree(&pglist);
960: }
961:
962: int
963: mbus_dmamem_map(void *v, bus_dma_segment_t *segs, int nsegs, size_t size,
964: caddr_t *kvap, int flags)
965: {
966: *kvap = (caddr_t)segs[0].ds_addr;
967: return 0;
968: }
969:
970: void
971: mbus_dmamem_unmap(void *v, caddr_t kva, size_t size)
972: {
973: }
974:
975: paddr_t
976: mbus_dmamem_mmap(void *v, bus_dma_segment_t *segs, int nsegs, off_t off,
977: int prot, int flags)
978: {
979: panic("_dmamem_mmap: not implemented");
980: }
981:
982: const struct hppa_bus_dma_tag hppa_dmatag = {
983: NULL,
984: mbus_dmamap_create, mbus_dmamap_destroy,
985: mbus_dmamap_load, mbus_dmamap_load_mbuf,
986: mbus_dmamap_load_uio, mbus_dmamap_load_raw,
987: mbus_dmamap_unload, mbus_dmamap_sync,
988:
989: mbus_dmamem_alloc, mbus_dmamem_free, mbus_dmamem_map,
990: mbus_dmamem_unmap, mbus_dmamem_mmap
991: };
992:
993: int
994: mbmatch(parent, cfdata, aux)
995: struct device *parent;
996: void *cfdata;
997: void *aux;
998: {
999: struct cfdata *cf = cfdata;
1000:
1001: /* there will be only one */
1002: if (cf->cf_unit)
1003: return 0;
1004:
1005: return 1;
1006: }
1007:
1008: void
1009: mbattach(parent, self, aux)
1010: struct device *parent;
1011: struct device *self;
1012: void *aux;
1013: {
1014: struct mainbus_softc *sc = (struct mainbus_softc *)self;
1015: struct confargs nca;
1016: bus_space_handle_t ioh;
1017:
1018: /* fetch the "default" cpu hpa */
1019: if (pdc_call((iodcio_t)pdc, 0, PDC_HPA, PDC_HPA_DFLT, &pdc_hpa) < 0)
1020: panic("mbattach: PDC_HPA failed");
1021:
1022: printf(" [flex %lx]\n", pdc_hpa.hpa & HPPA_FLEX_MASK);
1023:
1024: /* map all the way till the end of the memory */
1025: if (bus_space_map(&hppa_bustag, pdc_hpa.hpa,
1026: (~0LU - pdc_hpa.hpa + 1), 0, &ioh))
1027: panic("mbattach: cannot map mainbus IO space");
1028:
1029: /*
1030: * Local-Broadcast the HPA to all modules on this bus
1031: */
1032: ((struct iomod *)HPPA_LBCAST)->io_flex =
1033: (pdc_hpa.hpa & HPPA_FLEX_MASK) | DMA_ENABLE;
1034:
1035: sc->sc_hpa = pdc_hpa.hpa;
1036:
1037: /* PDC first */
1038: bzero(&nca, sizeof(nca));
1039: nca.ca_name = "pdc";
1040: nca.ca_iot = &hppa_bustag;
1041: nca.ca_dmatag = &hppa_dmatag;
1042: config_found(self, &nca, mbprint);
1043:
1044: #if NPOWER > 0
1045: /* get some power */
1046: bzero(&nca, sizeof(nca));
1047: nca.ca_name = "power";
1048: nca.ca_irq = -1;
1049: if (!pdc_call((iodcio_t)pdc, 0, PDC_SOFT_POWER,
1050: PDC_SOFT_POWER_INFO, &pdc_power_info, 0)) {
1051: nca.ca_iot = &hppa_bustag;
1052: nca.ca_hpa = pdc_power_info.addr;
1053: nca.ca_hpamask = HPPA_IOBEGIN;
1054: }
1055: config_found(self, &nca, mbprint);
1056: #endif
1057:
1058: #if NLCD > 0
1059: if (!pdc_call((iodcio_t)pdc, 0, PDC_CHASSIS, PDC_CHASSIS_INFO,
1060: &pdc_chassis_info, &pdc_chassis_lcd, sizeof(pdc_chassis_lcd)) &&
1061: pdc_chassis_lcd.enabled) {
1062: bzero(&nca, sizeof(nca));
1063: nca.ca_name = "lcd";
1064: nca.ca_irq = -1;
1065: nca.ca_iot = &hppa_bustag;
1066: nca.ca_hpa = pdc_chassis_lcd.cmd_addr;
1067: nca.ca_hpamask = HPPA_IOBEGIN;
1068: nca.ca_pdc_iodc_read = (void *)&pdc_chassis_lcd;
1069:
1070: config_found(self, &nca, mbprint);
1071: }
1072: #endif
1073:
1074: bzero(&nca, sizeof(nca));
1075: nca.ca_hpa = 0;
1076: nca.ca_irq = -1;
1077: nca.ca_hpamask = HPPA_IOBEGIN;
1078: nca.ca_iot = &hppa_bustag;
1079: nca.ca_dmatag = &hppa_dmatag;
1080: nca.ca_dp.dp_bc[0] = nca.ca_dp.dp_bc[1] = nca.ca_dp.dp_bc[2] =
1081: nca.ca_dp.dp_bc[3] = nca.ca_dp.dp_bc[4] = nca.ca_dp.dp_bc[5] = -1;
1082: nca.ca_dp.dp_mod = -1;
1083: switch (cpu_hvers) {
1084: #if 0
1085: case HPPA_BOARD_HP809:
1086: case HPPA_BOARD_HP819:
1087: case HPPA_BOARD_HP839:
1088: case HPPA_BOARD_HP859:
1089: case HPPA_BOARD_HP770_J200:
1090: case HPPA_BOARD_HP770_J210:
1091: case HPPA_BOARD_HP770_J210XC:
1092: case HPPA_BOARD_HP780_J282:
1093: case HPPA_BOARD_HP782_J2240:
1094: #endif
1095: case HPPA_BOARD_HP780_C160:
1096: case HPPA_BOARD_HP780_C180P:
1097: case HPPA_BOARD_HP780_C180XP:
1098: case HPPA_BOARD_HP780_C200:
1099: case HPPA_BOARD_HP780_C230:
1100: case HPPA_BOARD_HP780_C240:
1101: case HPPA_BOARD_HP785_C360:
1102: pdc_scanbus(self, &nca, MAXMODBUS, HPPA_FPA);
1103: break;
1104: default:
1105: pdc_scanbus(self, &nca, MAXMODBUS, 0);
1106: break;
1107: }
1108: }
1109:
1110: /*
1111: * retrive CPU #N HPA value
1112: */
1113: hppa_hpa_t
1114: cpu_gethpa(n)
1115: int n;
1116: {
1117: struct mainbus_softc *sc;
1118:
1119: sc = mainbus_cd.cd_devs[0];
1120:
1121: return sc->sc_hpa;
1122: }
1123:
1124: int
1125: mbprint(aux, pnp)
1126: void *aux;
1127: const char *pnp;
1128: {
1129: struct confargs *ca = aux;
1130:
1131: if (pnp)
1132: printf("\"%s\" at %s (type %x sv %x mod %x hv %x)",
1133: ca->ca_name, pnp,
1134: ca->ca_type.iodc_type, ca->ca_type.iodc_sv_model,
1135: ca->ca_type.iodc_model, ca->ca_type.iodc_revision);
1136: if (ca->ca_hpa) {
1137: if (~ca->ca_hpamask)
1138: printf(" offset %lx", ca->ca_hpa & ~ca->ca_hpamask);
1139: if (!pnp && ca->ca_irq >= 0)
1140: printf(" irq %d", ca->ca_irq);
1141: }
1142:
1143: return (UNCONF);
1144: }
1145:
1146: int
1147: mbsubmatch(parent, match, aux)
1148: struct device *parent;
1149: void *match, *aux;
1150: {
1151: struct cfdata *cf = match;
1152: struct confargs *ca = aux;
1153: int ret;
1154:
1155: if (autoconf_verbose)
1156: printf(">> hpa %lx off %lx cf_off %x\n",
1157: ca->ca_hpa, ca->ca_hpa & ~ca->ca_hpamask, cf->hppacf_off);
1158:
1159: if (ca->ca_hpa && ~ca->ca_hpamask && cf->hppacf_off != -1 &&
1160: ((ca->ca_hpa & ~ca->ca_hpamask) != cf->hppacf_off))
1161: return (0);
1162:
1163: if ((ret = (*cf->cf_attach->ca_match)(parent, match, aux)))
1164: ca->ca_irq = cf->hppacf_irq;
1165:
1166: return ret;
1167: }
1168:
CVSweb