Annotation of sys/arch/aviion/dev/vme.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: vme.c,v 1.3 2006/05/21 12:22:02 miod Exp $ */
2: /*
3: * Copyright (c) 2006, Miodrag Vallat.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
18: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24: * POSSIBILITY OF SUCH DAMAGE.
25: */
26:
27: /*
28: * XXX TODO: Finish /dev/vme{a16,a24,a32}{d8,d16,d32} interface.
29: */
30:
31: #include <sys/param.h>
32: #include <sys/systm.h>
33: #include <sys/kernel.h>
34: #include <sys/device.h>
35: #include <sys/extent.h>
36: #include <sys/malloc.h>
37: #include <sys/proc.h>
38: #include <sys/uio.h>
39:
40: #include <machine/bus.h>
41: #include <machine/conf.h>
42:
43: #include <uvm/uvm_extern.h>
44:
45: #include <aviion/dev/vmevar.h>
46:
47: #include <machine/avcommon.h>
48: #include <machine/av400.h>
49: #include <aviion/dev/sysconreg.h>
50:
51: struct vmesoftc {
52: struct device sc_dev;
53:
54: struct extent *sc_ext_a16;
55: struct extent *sc_ext_a24;
56: struct extent *sc_ext_a32;
57: };
58:
59: int vmematch(struct device *, void *, void *);
60: void vmeattach(struct device *, struct device *, void *);
61:
62: struct cfattach vme_ca = {
63: sizeof(struct vmesoftc), vmematch, vmeattach
64: };
65:
66: struct cfdriver vme_cd = {
67: NULL, "vme", DV_DULL
68: };
69:
70: int vme16_map(bus_addr_t, bus_size_t, int, bus_space_handle_t *);
71: void vme16_unmap(bus_space_handle_t, bus_size_t);
72: int vme24_map(bus_addr_t, bus_size_t, int, bus_space_handle_t *);
73: void vme24_unmap(bus_space_handle_t, bus_size_t);
74: int vme32_map(bus_addr_t, bus_size_t, int, bus_space_handle_t *);
75: void vme32_unmap(bus_space_handle_t, bus_size_t);
76: int vme_subregion(bus_space_handle_t, bus_size_t, bus_size_t,
77: bus_space_handle_t *);
78: void * vme_vaddr(bus_space_handle_t);
79:
80: int vme_map(struct extent *, paddr_t, bus_addr_t, bus_size_t, int,
81: bus_space_handle_t *);
82: void vme_unmap(struct extent *, vme_addr_t, vaddr_t, bus_size_t);
83: int vmeprint(void *, const char *);
84: int vmescan(struct device *, void *, void *);
85:
86: u_int vmevecbase;
87:
88: int
89: vmematch(struct device *parent, void *vcf, void *aux)
90: {
91: /* XXX no VME on AV100/AV200/AV300, though */
92: return (1);
93: }
94:
95: void
96: vmeattach(struct device *parent, struct device *self, void *aux)
97: {
98: struct vmesoftc *sc = (struct vmesoftc *)self;
99: u_int32_t ucsr;
100:
101: printf("\n");
102:
103: /*
104: * Initialize extents
105: */
106: sc->sc_ext_a16 = extent_create("vme a16", 0, 1 << (16 - PAGE_SHIFT),
107: M_DEVBUF, NULL, 0, EX_NOWAIT);
108: sc->sc_ext_a24 = extent_create("vme a24", 0, 1 << (24 - PAGE_SHIFT),
109: M_DEVBUF, NULL, 0, EX_NOWAIT);
110: sc->sc_ext_a32 = extent_create("vme a32", 0, 1 << (32 - PAGE_SHIFT),
111: M_DEVBUF, NULL, 0, EX_NOWAIT);
112:
113: vmevecbase = 0x80; /* Hard coded */
114:
115: /*
116: * Force a reasonable timeout for VME data transfers.
117: * We can not disable this, this would cause autoconf to hang
118: * on the first missing device we'll probe.
119: */
120: ucsr = *(volatile u_int32_t*)AV_UCSR;
121: ucsr = (ucsr & ~VTOSELBITS) | VTO128US;
122: *(volatile u_int32_t *)AV_UCSR = ucsr;
123:
124: /*
125: * Clear EXTAD to allow VME A24 devices to access the first 16MB
126: * of memory.
127: */
128: *(volatile u_int32_t *)AV_EXTAD = 0x00000000;
129:
130: /*
131: * Use supervisor data address modifiers for VME accesses.
132: */
133: *(volatile u_int32_t *)AV_EXTAM = 0x0d;
134:
135: /*
136: * Display VME ranges.
137: */
138: printf("%s: A32 %08x-%08x\n", self->dv_xname,
139: AV400_VME32_START1, AV400_VME32_END1);
140: printf("%s: A32 %08x-%08x\n", self->dv_xname,
141: AV400_VME32_START2, AV400_VME32_END2);
142: printf("%s: A24 %08x-%08x\n", self->dv_xname,
143: AV400_VME24_START, AV400_VME24_END);
144: printf("%s: A16 %08x-%08x\n", self->dv_xname,
145: AV400_VME16_START, AV400_VME16_END);
146:
147: /* scan for child devices */
148: config_search(vmescan, self, aux);
149: }
150:
151: int
152: vmescan(struct device *parent, void *vcf, void *aux)
153: {
154: struct cfdata *cf = vcf;
155: struct vme_attach_args vaa;
156:
157: bzero(&vaa, sizeof vaa);
158: vaa.vaa_addr_a16 = (vme_addr_t)cf->cf_loc[0];
159: vaa.vaa_addr_a24 = (vme_addr_t)cf->cf_loc[1];
160: vaa.vaa_addr_a32 = (vme_addr_t)cf->cf_loc[2];
161: vaa.vaa_ipl = (u_int)cf->cf_loc[3];
162:
163: if ((*cf->cf_attach->ca_match)(parent, cf, &vaa) == 0)
164: return (0);
165:
166: config_attach(parent, cf, &vaa, vmeprint);
167: return (1);
168: }
169:
170: int
171: vmeprint(void *aux, const char *pnp)
172: {
173: struct vme_attach_args *vaa = aux;
174:
175: if (vaa->vaa_addr_a16 != (vme_addr_t)-1)
176: printf(" a16 0x%04x", vaa->vaa_addr_a16);
177: if (vaa->vaa_addr_a24 != (vme_addr_t)-1)
178: printf(" a24 0x%06x", vaa->vaa_addr_a24);
179: if (vaa->vaa_addr_a32 != (vme_addr_t)-1)
180: printf(" a32 0x%08x", vaa->vaa_addr_a32);
181: if (vaa->vaa_ipl != (u_int)-1)
182: printf(" ipl %u", vaa->vaa_ipl);
183:
184: return (UNCONF);
185: }
186:
187: /*
188: * Interrupt related code
189: */
190:
191: /* allocate interrupt vectors */
192: int
193: vmeintr_allocate(u_int count, int flags, u_int *array)
194: {
195: u_int vec, v;
196:
197: if ((flags & VMEINTR_CONTIGUOUS) == 0) {
198: for (vec = vmevecbase; vec <= NVMEINTR - count; vec++) {
199: if (SLIST_EMPTY(&intr_handlers[vec])) {
200: *array++ = vec;
201: if (--count == 0)
202: return (0);
203: }
204: }
205: } else {
206: for (vec = vmevecbase; vec <= NVMEINTR - count; vec++) {
207: /* do we have count contiguous unassigned vectors? */
208: for (v = count; v != 0; v--)
209: if (!SLIST_EMPTY(&intr_handlers[vec + v - 1]))
210: break;
211:
212: if (v == 0) {
213: *array = vec;
214: return (0);
215: }
216: }
217: }
218:
219: return (EPERM);
220: }
221:
222: /* enable and establish interrupt */
223: int
224: vmeintr_establish(u_int vec, struct intrhand *ih, const char *name)
225: {
226: /*
227: * No need to enable the VME interrupt source in the interrupt
228: * controller, as they are enabled by default.
229: */
230: return intr_establish(vec, ih, name);
231: }
232:
233: /*
234: * bus_space specific functions
235: */
236:
237: int
238: vme16_map(bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t *ret)
239: {
240: struct vmesoftc *sc = (void *)vme_cd.cd_devs[0];
241:
242: if (AV400_ISVMEA16(addr) && AV400_ISVMEA16(addr + size - 1))
243: return (vme_map(sc->sc_ext_a16, addr + AV400_VME16_BASE, addr,
244: size, flags, ret));
245: else
246: return (EINVAL);
247: }
248:
249: int
250: vme24_map(bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t *ret)
251: {
252: struct vmesoftc *sc = (void *)vme_cd.cd_devs[0];
253:
254: if (AV400_ISVMEA24(addr) && AV400_ISVMEA24(addr + size - 1))
255: return (vme_map(sc->sc_ext_a24, addr + AV400_VME24_BASE, addr,
256: size, flags, ret));
257: else
258: return (EINVAL);
259: }
260:
261: int
262: vme32_map(bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t *ret)
263: {
264: struct vmesoftc *sc = (void *)vme_cd.cd_devs[0];
265:
266: if (AV400_ISVMEA32(addr) && AV400_ISVMEA32(addr + size - 1))
267: return (vme_map(sc->sc_ext_a32, addr + AV400_VME32_BASE, addr,
268: size, flags, ret));
269: else
270: return (EINVAL);
271: }
272:
273: int
274: vme_map(struct extent *ext, paddr_t paddr, bus_addr_t addr, bus_size_t size,
275: int flags, bus_space_handle_t *ret)
276: {
277: int rc;
278: paddr_t pa;
279: psize_t len;
280: vaddr_t ova, va;
281: u_int pg;
282: extern vaddr_t pmap_map(vaddr_t, paddr_t, paddr_t, vm_prot_t, u_int);
283:
284: pa = trunc_page(paddr);
285: len = round_page(paddr + size) - pa;
286:
287: if (ext != NULL) {
288: rc = extent_alloc_region(ext, atop(addr), atop(len),
289: EX_NOWAIT | EX_MALLOCOK);
290: if (rc != 0)
291: return (rc);
292: }
293:
294: ova = va = uvm_km_valloc(kernel_map, len);
295: if (va == NULL) {
296: rc = ENOMEM;
297: goto fail;
298: }
299:
300: *ret = (bus_space_handle_t)va;
301:
302: for (pg = atop(len); pg !=0; pg--) {
303: pmap_kenter_pa(va, pa, UVM_PROT_RW);
304: va += PAGE_SIZE;
305: pa += PAGE_SIZE;
306: }
307: if (flags & BUS_SPACE_MAP_CACHEABLE)
308: pmap_cache_ctrl(pmap_kernel(), ova, ova + len, CACHE_GLOBAL);
309: pmap_update(pmap_kernel());
310:
311: return (0);
312:
313: fail:
314: if (ext != NULL)
315: extent_free(ext, atop(addr), atop(len), EX_NOWAIT | EX_MALLOCOK);
316: return (rc);
317: }
318:
319: void
320: vme16_unmap(bus_space_handle_t handle, bus_size_t size)
321: {
322: struct vmesoftc *sc = (void *)vme_cd.cd_devs[0];
323: paddr_t pa;
324:
325: if (pmap_extract(pmap_kernel(), (vaddr_t)handle, &pa) == FALSE)
326: return;
327:
328: pa -= AV400_VME16_BASE;
329: return (vme_unmap(sc->sc_ext_a16, pa, (vaddr_t)handle, size));
330: }
331:
332: void
333: vme24_unmap(bus_space_handle_t handle, bus_size_t size)
334: {
335: struct vmesoftc *sc = (void *)vme_cd.cd_devs[0];
336: paddr_t pa;
337:
338: if (pmap_extract(pmap_kernel(), (vaddr_t)handle, &pa) == FALSE)
339: return;
340:
341: pa -= AV400_VME24_BASE;
342: return (vme_unmap(sc->sc_ext_a24, pa, (vaddr_t)handle, size));
343: }
344:
345: void
346: vme32_unmap(bus_space_handle_t handle, bus_size_t size)
347: {
348: struct vmesoftc *sc = (void *)vme_cd.cd_devs[0];
349: paddr_t pa;
350:
351: if (pmap_extract(pmap_kernel(), (vaddr_t)handle, &pa) == FALSE)
352: return;
353:
354: pa -= AV400_VME32_BASE;
355: return (vme_unmap(sc->sc_ext_a32, pa, (vaddr_t)handle, size));
356: }
357:
358: void
359: vme_unmap(struct extent *ext, vme_addr_t addr, vaddr_t vaddr, bus_size_t size)
360: {
361: vaddr_t va;
362: vsize_t len;
363:
364: va = trunc_page(vaddr);
365: len = round_page(vaddr + size) - va;
366:
367: pmap_kremove(va, len);
368: pmap_update(pmap_kernel());
369: uvm_km_free(kernel_map, va, len);
370:
371: if (ext != NULL)
372: extent_free(ext, atop(addr), atop(len),
373: EX_NOWAIT | EX_MALLOCOK);
374: }
375:
376: int
377: vme_subregion(bus_space_handle_t handle, bus_addr_t offset, bus_size_t size,
378: bus_space_handle_t *ret)
379: {
380: /* since vme_map produces linear mappings, this is safe */
381: *ret = handle + offset;
382: return (0);
383: }
384:
385: void *
386: vme_vaddr(bus_space_handle_t handle)
387: {
388: return ((void *)handle);
389: }
390:
391: /*
392: * Get a bus_space_tag for the requested address and data access modes.
393: *
394: * On aviion, we do not honour the dspace yet.
395: */
396: int
397: vmebus_get_bst(struct device *vsc, u_int aspace, u_int dspace,
398: bus_space_tag_t *bst)
399: {
400: struct aviion_bus_space_tag *tag;
401:
402: switch (dspace) {
403: case VME_D32:
404: case VME_D16:
405: case VME_D8:
406: break;
407: default:
408: return (EINVAL);
409: }
410:
411: switch (aspace) {
412: case VME_A32:
413: case VME_A24:
414: case VME_A16:
415: break;
416: default:
417: return (EINVAL);
418: }
419:
420: tag = (struct aviion_bus_space_tag *)malloc(sizeof *tag, M_DEVBUF,
421: M_NOWAIT);
422: if (tag == NULL)
423: return (ENOMEM);
424:
425: switch (aspace) {
426: default:
427: case VME_A32:
428: tag->bs_map = vme32_map;
429: tag->bs_unmap = vme32_unmap;
430: tag->bs_subregion = vme_subregion;
431: tag->bs_vaddr = vme_vaddr;
432: break;
433: case VME_A24:
434: tag->bs_map = vme24_map;
435: tag->bs_unmap = vme24_unmap;
436: tag->bs_subregion = vme_subregion;
437: tag->bs_vaddr = vme_vaddr;
438: break;
439: case VME_A16:
440: tag->bs_map = vme16_map;
441: tag->bs_unmap = vme16_unmap;
442: tag->bs_subregion = vme_subregion;
443: tag->bs_vaddr = vme_vaddr;
444: break;
445: }
446:
447: *bst = tag;
448: return (0);
449: }
450:
451: void
452: vmebus_release_bst(struct device *vsc, bus_space_tag_t b)
453: {
454: free((void *)b, M_DEVBUF);
455: }
456:
457: /*
458: * /dev/vme* access routines
459: */
460:
461: /* minor device number encoding */
462: #define AWIDTH_FIELD(minor) (minor & 0x0f)
463: #define AWIDTH(w) ((w) << 3)
464: #define DWIDTH_FIELD(minor) ((minor & 0xf0) >> 4)
465: #define DWIDTH(w) ((w) << 3)
466:
467: int
468: vmeopen(dev_t dev, int flags, int type, struct proc *p)
469: {
470: if (vme_cd.cd_ndevs == 0 || vme_cd.cd_devs[0] == NULL)
471: return (ENODEV);
472:
473: switch (AWIDTH_FIELD(minor(dev))) {
474: case VME_A32:
475: case VME_A24:
476: case VME_A16:
477: break;
478: default:
479: return (ENODEV);
480: }
481:
482: switch (DWIDTH_FIELD(minor(dev))) {
483: case VME_D32:
484: case VME_D16:
485: case VME_D8:
486: break;
487: default:
488: return (ENODEV);
489: }
490:
491: return (0);
492: }
493:
494: int
495: vmeclose(dev_t dev, int flags, int type, struct proc *p)
496: {
497: return (0);
498: }
499:
500: int
501: vmeread(dev_t dev, struct uio *uio, int flags)
502: {
503: return (EIO);
504: }
505:
506: int
507: vmewrite(dev_t dev, struct uio *uio, int flags)
508: {
509: return (EIO);
510: }
511:
512: int
513: vmeioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
514: {
515: switch (cmd) {
516: default:
517: return (ENOTTY);
518: }
519: }
520:
521: paddr_t
522: vmemmap(dev_t dev, off_t off, int prot)
523: {
524: int awidth;
525: paddr_t pa;
526:
527: if ((off & PAGE_MASK) != 0)
528: return (-1);
529:
530: awidth = AWIDTH_FIELD(minor(dev));
531:
532: /* check offset range */
533: if (off < 0 || off >= (1ULL << AWIDTH(awidth)))
534: return (-1);
535:
536: pa = (paddr_t)off;
537:
538: switch (awidth) {
539: case VME_A32:
540: if (!AV400_ISVMEA32(pa))
541: return (-1);
542: pa += AV400_VME32_BASE;
543: break;
544: case VME_A24:
545: if (!AV400_ISVMEA24(pa))
546: return (-1);
547: pa += AV400_VME24_BASE;
548: break;
549: case VME_A16:
550: if (!AV400_ISVMEA16(pa))
551: return (-1);
552: pa += AV400_VME16_BASE;
553: break;
554: }
555:
556: return (atop(pa));
557: }
CVSweb