[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

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