[BACK]Return to vme.c CVS log [TXT][DIR] Up to [local] / sys / arch / aviion / dev

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