Annotation of sys/arch/aviion/dev/vme.c, Revision 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