[BACK]Return to musycc.c CVS log [TXT][DIR] Up to [local] / sys / dev / pci

Annotation of sys/dev/pci/musycc.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: musycc.c,v 1.15 2006/03/25 22:41:46 djm Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2004,2005  Internet Business Solutions AG, Zurich, Switzerland
        !             5:  * Written by: Claudio Jeker <jeker@accoom.net>
        !             6:  *
        !             7:  * Permission to use, copy, modify, and distribute this software for any
        !             8:  * purpose with or without fee is hereby granted, provided that the above
        !             9:  * copyright notice and this permission notice appear in all copies.
        !            10:  *
        !            11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            17:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            18:  */
        !            19: #include "bpfilter.h"
        !            20:
        !            21: #include <sys/param.h>
        !            22: #include <sys/types.h>
        !            23:
        !            24: #include <sys/device.h>
        !            25: #include <sys/kernel.h>
        !            26: #include <sys/limits.h>
        !            27: #include <sys/malloc.h>
        !            28: #include <sys/mbuf.h>
        !            29: #include <sys/proc.h>
        !            30: #include <sys/socket.h>
        !            31: #include <sys/syslog.h>
        !            32: #include <sys/systm.h>
        !            33:
        !            34: #include <machine/cpu.h>
        !            35: #include <machine/bus.h>
        !            36: #include <machine/intr.h>
        !            37:
        !            38: #include <net/if.h>
        !            39: #include <net/if_media.h>
        !            40: #include <net/if_sppp.h>
        !            41:
        !            42: #if NBPFILTER > 0
        !            43: #include <net/bpf.h>
        !            44: #endif
        !            45:
        !            46: #include <dev/pci/musyccvar.h>
        !            47: #include <dev/pci/musyccreg.h>
        !            48:
        !            49: int    musycc_alloc_groupdesc(struct musycc_softc *);
        !            50: int    musycc_alloc_intqueue(struct musycc_softc *);
        !            51: int    musycc_alloc_group(struct musycc_group *);
        !            52: void   musycc_free_groupdesc(struct musycc_softc *);
        !            53: void   musycc_free_intqueue(struct musycc_softc *);
        !            54: void   musycc_free_dmadesc(struct musycc_group *);
        !            55: void   musycc_free_group(struct musycc_group *);
        !            56: void   musycc_set_group(struct musycc_group *, int, int, int);
        !            57: int    musycc_set_tsmap(struct musycc_group *, struct channel_softc *, char);
        !            58: int    musycc_set_chandesc(struct musycc_group *, int, int, int);
        !            59: void   musycc_activate_channel(struct musycc_group *, int);
        !            60: void   musycc_state_engine(struct musycc_group *, int, enum musycc_event);
        !            61:
        !            62: struct dma_desc                *musycc_dma_get(struct musycc_group *);
        !            63: void   musycc_dma_free(struct musycc_group *, struct dma_desc *);
        !            64: int    musycc_list_tx_init(struct musycc_group *, int, int);
        !            65: int    musycc_list_rx_init(struct musycc_group *, int, int);
        !            66: void   musycc_list_tx_free(struct musycc_group *, int);
        !            67: void   musycc_list_rx_free(struct musycc_group *, int);
        !            68: void   musycc_reinit_dma(struct musycc_group *, int);
        !            69: int    musycc_newbuf(struct musycc_group *, struct dma_desc *, struct mbuf *);
        !            70: int    musycc_encap(struct musycc_group *, struct mbuf *, int);
        !            71:
        !            72: void   musycc_rxeom(struct musycc_group *, int, int);
        !            73: void   musycc_txeom(struct musycc_group *, int, int);
        !            74: void   musycc_kick(struct musycc_group *);
        !            75: void   musycc_sreq(struct musycc_group *, int, u_int32_t, int,
        !            76:            enum musycc_event);
        !            77:
        !            78: #ifndef ACCOOM_DEBUG
        !            79: #define musycc_dump_group(n, x)
        !            80: #define musycc_dump_desc(n, x)
        !            81: #define musycc_dump_dma(n, x, y)
        !            82: #else
        !            83: int    accoom_debug = 0;
        !            84:
        !            85: char   *musycc_intr_print(u_int32_t);
        !            86: void    musycc_dump_group(int, struct musycc_group *);
        !            87: void    musycc_dump_desc(int, struct musycc_group *);
        !            88: void    musycc_dump_dma(int, struct musycc_group *, int);
        !            89: #endif
        !            90:
        !            91: int
        !            92: musycc_attach_common(struct musycc_softc *sc, u_int32_t portmap, u_int32_t mode)
        !            93: {
        !            94:        struct musycc_group     *mg;
        !            95:        int                      i, j;
        !            96:
        !            97:        if (musycc_alloc_groupdesc(sc) == -1) {
        !            98:                printf(": couldn't alloc group descriptors\n");
        !            99:                return (-1);
        !           100:        }
        !           101:
        !           102:        if (musycc_alloc_intqueue(sc) == -1) {
        !           103:                printf(": couldn't alloc interrupt queue\n");
        !           104:                musycc_free_groupdesc(sc);
        !           105:                return (-1);
        !           106:        }
        !           107:
        !           108:        /*
        !           109:         * global configuration: set EBUS to sane defaults:
        !           110:         * intel mode, elapse = 3, blapse = 3, alapse = 3
        !           111:         * XXX XXX disable INTB for now
        !           112:         */
        !           113:        sc->mc_global_conf = (portmap & MUSYCC_CONF_PORTMAP) |
        !           114:            MUSYCC_CONF_MPUSEL | MUSYCC_CONF_ECKEN |
        !           115:            MUSYCC_CONF_ELAPSE_SET(3) | MUSYCC_CONF_ALAPSE_SET(3) |
        !           116:            MUSYCC_CONF_BLAPSE_SET(3) | MUSYCC_CONF_INTB;
        !           117:
        !           118:        /* initialize group descriptors */
        !           119:        sc->mc_groups = (struct musycc_group *)malloc(sc->mc_ngroups *
        !           120:            sizeof(struct musycc_group), M_DEVBUF, M_NOWAIT);
        !           121:        if (sc->mc_groups == NULL) {
        !           122:                printf(": couldn't alloc group descriptors\n");
        !           123:                musycc_free_groupdesc(sc);
        !           124:                musycc_free_intqueue(sc);
        !           125:                return (-1);
        !           126:        }
        !           127:        bzero(sc->mc_groups, sc->mc_ngroups * sizeof(struct musycc_group));
        !           128:
        !           129:        for (i = 0; i < sc->mc_ngroups; i++) {
        !           130:                mg = &sc->mc_groups[i];
        !           131:                mg->mg_hdlc = sc;
        !           132:                mg->mg_gnum = i;
        !           133:                mg->mg_port = i >> (portmap & MUSYCC_CONF_PORTMAP);
        !           134:                mg->mg_dmat = sc->mc_dmat;
        !           135:
        !           136:                if (musycc_alloc_group(mg) == -1) {
        !           137:                        printf(": couldn't alloc group structures\n");
        !           138:                        for (j = 0; j < i; j++)
        !           139:                                musycc_free_group(&sc->mc_groups[j]);
        !           140:                        musycc_free_groupdesc(sc);
        !           141:                        musycc_free_intqueue(sc);
        !           142:                        return (-1);
        !           143:                }
        !           144:
        !           145:                mg->mg_group = (struct musycc_grpdesc *)
        !           146:                    (sc->mc_groupkva + MUSYCC_GROUPBASE(i));
        !           147:                bzero(mg->mg_group, sizeof(struct musycc_grpdesc));
        !           148:                musycc_set_group(mg, MUSYCC_GRCFG_POLL32, MUSYCC_MAXFRM_MAX,
        !           149:                    MUSYCC_MAXFRM_MAX);
        !           150:                musycc_set_port(mg, mode);
        !           151:
        !           152:                bus_dmamap_sync(sc->mc_dmat, sc->mc_cfgmap,
        !           153:                    MUSYCC_GROUPBASE(i), sizeof(struct musycc_grpdesc),
        !           154:                    BUS_DMASYNC_PREWRITE);
        !           155:                bus_space_write_4(sc->mc_st, sc->mc_sh, MUSYCC_GROUPBASE(i),
        !           156:                    sc->mc_cfgmap->dm_segs[0].ds_addr + MUSYCC_GROUPBASE(i));
        !           157:        }
        !           158:
        !           159:        /* Dual Address Cycle Base Pointer */
        !           160:        bus_space_write_4(sc->mc_st, sc->mc_sh, MUSYCC_DACB_PTR, 0);
        !           161:        /* Global Configuration Descriptor */
        !           162:        bus_space_write_4(sc->mc_st, sc->mc_sh, MUSYCC_GLOBALCONF,
        !           163:            sc->mc_global_conf);
        !           164:        /* Interrupt Queue Descriptor */
        !           165:        bus_space_write_4(sc->mc_st, sc->mc_sh, MUSYCC_INTQPTR,
        !           166:            sc->mc_intrqptr);
        !           167:        /*
        !           168:         * Interrupt Queue Length.
        !           169:         * NOTE: a value of 1 indicates a queue length of 2 descriptors!
        !           170:         */
        !           171:        bus_space_write_4(sc->mc_st, sc->mc_sh, MUSYCC_INTQLEN,
        !           172:            MUSYCC_INTLEN - 1);
        !           173:
        !           174:        /* Configure groups, needs to be done only once per group */
        !           175:        for (i = 0; i < sc->mc_ngroups; i++) {
        !           176:                mg = &sc->mc_groups[i];
        !           177:                musycc_sreq(mg, 0, MUSYCC_SREQ_SET(5), MUSYCC_SREQ_BOTH,
        !           178:                    EV_NULL);
        !           179:                mg->mg_loaded = 1;
        !           180:        }
        !           181:
        !           182:        return (0);
        !           183: }
        !           184:
        !           185: int
        !           186: musycc_alloc_groupdesc(struct musycc_softc *sc)
        !           187: {
        !           188:        /*
        !           189:         * Allocate per group/port shared memory.
        !           190:         * One big cunck of nports * 2048 bytes is allocated. This is
        !           191:         * done to ensure that all group structures are 2048 bytes aligned.
        !           192:         */
        !           193:        if (bus_dmamem_alloc(sc->mc_dmat, sc->mc_ngroups * 2048,
        !           194:            2048, 0, sc->mc_cfgseg, 1, &sc->mc_cfgnseg, BUS_DMA_NOWAIT)) {
        !           195:                return (-1);
        !           196:        }
        !           197:        if (bus_dmamem_map(sc->mc_dmat, sc->mc_cfgseg, sc->mc_cfgnseg,
        !           198:            sc->mc_ngroups * 2048, &sc->mc_groupkva, BUS_DMA_NOWAIT)) {
        !           199:                bus_dmamem_free(sc->mc_dmat, sc->mc_cfgseg, sc->mc_cfgnseg);
        !           200:                return (-1);
        !           201:        }
        !           202:        /* create and load bus dma segment, one for all ports */
        !           203:        if (bus_dmamap_create(sc->mc_dmat, sc->mc_ngroups * 2048,
        !           204:            1, sc->mc_ngroups * 2048, 0, BUS_DMA_NOWAIT, &sc->mc_cfgmap)) {
        !           205:                bus_dmamem_unmap(sc->mc_dmat, sc->mc_groupkva,
        !           206:                    sc->mc_ngroups * 2048);
        !           207:                bus_dmamem_free(sc->mc_dmat, sc->mc_cfgseg, sc->mc_cfgnseg);
        !           208:                return (-1);
        !           209:        }
        !           210:        if (bus_dmamap_load(sc->mc_dmat, sc->mc_cfgmap, sc->mc_groupkva,
        !           211:            sc->mc_ngroups * 2048, NULL, BUS_DMA_NOWAIT)) {
        !           212:                musycc_free_groupdesc(sc);
        !           213:                return (-1);
        !           214:        }
        !           215:
        !           216:        return (0);
        !           217: }
        !           218:
        !           219: int
        !           220: musycc_alloc_intqueue(struct musycc_softc *sc)
        !           221: {
        !           222:        /*
        !           223:         * allocate interrupt queue, use one page for the queue
        !           224:         */
        !           225:        if (bus_dmamem_alloc(sc->mc_dmat, sizeof(struct musycc_intdesc), 4, 0,
        !           226:            sc->mc_intrseg, 1, &sc->mc_intrnseg, BUS_DMA_NOWAIT)) {
        !           227:                return (-1);
        !           228:        }
        !           229:        if (bus_dmamem_map(sc->mc_dmat, sc->mc_intrseg, sc->mc_intrnseg,
        !           230:            sizeof(struct musycc_intdesc), (caddr_t *)&sc->mc_intrd,
        !           231:            BUS_DMA_NOWAIT)) {
        !           232:                bus_dmamem_free(sc->mc_dmat, sc->mc_intrseg, sc->mc_intrnseg);
        !           233:                return (-1);
        !           234:        }
        !           235:
        !           236:        /* create and load bus dma segment */
        !           237:        if (bus_dmamap_create(sc->mc_dmat, sizeof(struct musycc_intdesc),
        !           238:            1, sizeof(struct musycc_intdesc), 0, BUS_DMA_NOWAIT,
        !           239:            &sc->mc_intrmap)) {
        !           240:                bus_dmamem_unmap(sc->mc_dmat, (caddr_t)sc->mc_intrd,
        !           241:                    sizeof(struct musycc_intdesc));
        !           242:                bus_dmamem_free(sc->mc_dmat, sc->mc_intrseg, sc->mc_intrnseg);
        !           243:                return (-1);
        !           244:        }
        !           245:        if (bus_dmamap_load(sc->mc_dmat, sc->mc_intrmap, sc->mc_intrd,
        !           246:            sizeof(struct musycc_intdesc), NULL, BUS_DMA_NOWAIT)) {
        !           247:                musycc_free_intqueue(sc);
        !           248:                return (-1);
        !           249:        }
        !           250:
        !           251:        /* initialize the interrupt queue pointer */
        !           252:        sc->mc_intrqptr = sc->mc_intrmap->dm_segs[0].ds_addr +
        !           253:            offsetof(struct musycc_intdesc, md_intrq[0]);
        !           254:
        !           255:        return (0);
        !           256: }
        !           257:
        !           258: int
        !           259: musycc_alloc_group(struct musycc_group *mg)
        !           260: {
        !           261:        struct dma_desc         *dd;
        !           262:        int                      j;
        !           263:
        !           264:        /* Allocate per group dma memory */
        !           265:        if (bus_dmamem_alloc(mg->mg_dmat, MUSYCC_DMA_MAPSIZE,
        !           266:            PAGE_SIZE, 0, mg->mg_listseg, 1, &mg->mg_listnseg,
        !           267:            BUS_DMA_NOWAIT))
        !           268:                return (-1);
        !           269:        if (bus_dmamem_map(mg->mg_dmat, mg->mg_listseg, mg->mg_listnseg,
        !           270:            MUSYCC_DMA_MAPSIZE, &mg->mg_listkva, BUS_DMA_NOWAIT)) {
        !           271:                bus_dmamem_free(mg->mg_dmat, mg->mg_listseg, mg->mg_listnseg);
        !           272:                return (-1);
        !           273:        }
        !           274:
        !           275:        /* create and load bus dma segment */
        !           276:        if (bus_dmamap_create(mg->mg_dmat, MUSYCC_DMA_MAPSIZE, 1,
        !           277:            MUSYCC_DMA_MAPSIZE, 0, BUS_DMA_NOWAIT, &mg->mg_listmap)) {
        !           278:                bus_dmamem_unmap(mg->mg_dmat, mg->mg_listkva,
        !           279:                    MUSYCC_DMA_MAPSIZE);
        !           280:                bus_dmamem_free(mg->mg_dmat, mg->mg_listseg, mg->mg_listnseg);
        !           281:                return (-1);
        !           282:        }
        !           283:        if (bus_dmamap_load(mg->mg_dmat, mg->mg_listmap, mg->mg_listkva,
        !           284:            MUSYCC_DMA_MAPSIZE, NULL, BUS_DMA_NOWAIT)) {
        !           285:                musycc_free_dmadesc(mg);
        !           286:                return (-1);
        !           287:        }
        !           288:
        !           289:        /*
        !           290:         * Create spare maps for musycc_start and musycc_newbuf.
        !           291:         * Limit the dma queue to MUSYCC_DMA_SIZE entries even though there
        !           292:         * is no actual hard limit from the chip.
        !           293:         */
        !           294:        if (bus_dmamap_create(mg->mg_dmat, MCLBYTES, MUSYCC_DMA_SIZE, MCLBYTES,
        !           295:            0, BUS_DMA_NOWAIT, &mg->mg_tx_sparemap) != 0) {
        !           296:                musycc_free_dmadesc(mg);
        !           297:                return (-1);
        !           298:        }
        !           299:        if (bus_dmamap_create(mg->mg_dmat, MCLBYTES, MUSYCC_DMA_SIZE, MCLBYTES,
        !           300:            0, BUS_DMA_NOWAIT, &mg->mg_rx_sparemap) != 0) {
        !           301:                bus_dmamap_destroy(mg->mg_dmat, mg->mg_tx_sparemap);
        !           302:                musycc_free_dmadesc(mg);
        !           303:                return (-1);
        !           304:        }
        !           305:
        !           306:        mg->mg_dma_pool = (struct dma_desc *)mg->mg_listkva;
        !           307:        bzero(mg->mg_dma_pool,
        !           308:            MUSYCC_DMA_CNT * sizeof(struct dma_desc));
        !           309:
        !           310:        /* add all descriptors to the freelist */
        !           311:        for (j = 0; j < MUSYCC_DMA_CNT; j++) {
        !           312:                dd = &mg->mg_dma_pool[j];
        !           313:                /* initalize, same as for spare maps */
        !           314:                if (bus_dmamap_create(mg->mg_dmat, MCLBYTES, MUSYCC_DMA_SIZE,
        !           315:                    MCLBYTES, 0, BUS_DMA_NOWAIT, &dd->map)) {
        !           316:                        musycc_free_group(mg);
        !           317:                        return (-1);
        !           318:                }
        !           319:                /* link */
        !           320:                dd->nextdesc = mg->mg_freelist;
        !           321:                mg->mg_freelist = dd;
        !           322:                mg->mg_freecnt++;
        !           323:        }
        !           324:
        !           325:        return (0);
        !           326: }
        !           327:
        !           328: void
        !           329: musycc_free_groupdesc(struct musycc_softc *sc)
        !           330: {
        !           331:        bus_dmamap_destroy(sc->mc_dmat, sc->mc_cfgmap);
        !           332:        bus_dmamem_unmap(sc->mc_dmat, sc->mc_groupkva,
        !           333:            sc->mc_ngroups * 2048);
        !           334:        bus_dmamem_free(sc->mc_dmat, sc->mc_cfgseg, sc->mc_cfgnseg);
        !           335: }
        !           336:
        !           337: void
        !           338: musycc_free_intqueue(struct musycc_softc *sc)
        !           339: {
        !           340:        bus_dmamap_destroy(sc->mc_dmat, sc->mc_intrmap);
        !           341:        bus_dmamem_unmap(sc->mc_dmat, (caddr_t)sc->mc_intrd,
        !           342:            sizeof(struct musycc_intdesc));
        !           343:        bus_dmamem_free(sc->mc_dmat, sc->mc_intrseg, sc->mc_intrnseg);
        !           344: }
        !           345:
        !           346: void
        !           347: musycc_free_dmadesc(struct musycc_group *mg)
        !           348: {
        !           349:        bus_dmamap_destroy(mg->mg_dmat, mg->mg_listmap);
        !           350:        bus_dmamem_unmap(mg->mg_dmat, mg->mg_listkva,
        !           351:            MUSYCC_DMA_MAPSIZE);
        !           352:        bus_dmamem_free(mg->mg_dmat, mg->mg_listseg, mg->mg_listnseg);
        !           353: }
        !           354:
        !           355: void
        !           356: musycc_free_group(struct musycc_group *mg)
        !           357: {
        !           358:        bus_dmamap_destroy(mg->mg_dmat, mg->mg_tx_sparemap);
        !           359:        bus_dmamap_destroy(mg->mg_dmat, mg->mg_tx_sparemap);
        !           360:        /* XXX dma descriptors ? */
        !           361:        musycc_free_dmadesc(mg);
        !           362:        mg->mg_dma_pool = NULL;
        !           363:        mg->mg_freelist = NULL;
        !           364:        mg->mg_freecnt = 0;
        !           365: }
        !           366:
        !           367: void
        !           368: musycc_set_group(struct musycc_group *mg, int poll, int maxa, int maxb)
        !           369: {
        !           370:        /* set global conf and interrupt descriptor */
        !           371:        mg->mg_group->global_conf = htole32(mg->mg_hdlc->mc_global_conf);
        !           372:        /*
        !           373:         * Interrupt Queue and Length.
        !           374:         * NOTE: a value of 1 indicates the queue length of 2 descriptors!
        !           375:         */
        !           376:        mg->mg_group->int_queuep = htole32(mg->mg_hdlc->mc_intrqptr);
        !           377:        mg->mg_group->int_queuelen = htole32(MUSYCC_INTLEN - 1);
        !           378:
        !           379:        /* group config */
        !           380:        mg->mg_group->group_conf = htole32(MUSYCC_GRCFG_RXENBL |
        !           381:            MUSYCC_GRCFG_TXENBL | MUSYCC_GRCFG_SUBDSBL |
        !           382:            MUSYCC_GRCFG_MSKCOFA | MUSYCC_GRCFG_MSKOOF |
        !           383:            MUSYCC_GRCFG_MCENBL | (poll & MUSYCC_GRCFG_POLL64));
        !           384:
        !           385:        /* memory protection, not supported by device */
        !           386:
        !           387:        /* message length config, preinit with useful data */
        !           388:        /* this is currently not used and the max is limited to 4094 bytes */
        !           389:        mg->mg_group->msglen_conf = htole32(maxa);
        !           390:        mg->mg_group->msglen_conf |= htole32(maxb << MUSYCC_MAXFRM2_SHIFT);
        !           391: }
        !           392:
        !           393: void
        !           394: musycc_set_port(struct musycc_group *mg, int mode)
        !           395: {
        !           396:        /*
        !           397:         * All signals trigger on falling edge only exception is TSYNC
        !           398:         * which triggers on rising edge. For the framer TSYNC is set to
        !           399:         * falling edge too but Musycc needs rising edge or everything gets
        !           400:         * off by one. Don't three-state TX (not needed).
        !           401:         */
        !           402:        mg->mg_group->port_conf = htole32(MUSYCC_PORT_TSYNC_EDGE |
        !           403:            MUSYCC_PORT_TRITX | (mode & MUSYCC_PORT_MODEMASK));
        !           404:
        !           405:        if (mg->mg_loaded)
        !           406:                musycc_sreq(mg, 0, MUSYCC_SREQ_SET(21), MUSYCC_SREQ_RX,
        !           407:                    EV_NULL);
        !           408: }
        !           409:
        !           410: /*
        !           411:  * Channel specifc calls
        !           412:  */
        !           413: int
        !           414: musycc_set_tsmap(struct musycc_group *mg, struct channel_softc *cc, char slot)
        !           415: {
        !           416:        int             i, nslots = 0, off, scale;
        !           417:        u_int32_t       tslots = cc->cc_tslots;
        !           418:
        !           419:        ACCOOM_PRINTF(1, ("%s: musycc_set_tsmap %08x slot %c\n",
        !           420:            cc->cc_ifp->if_xname, tslots, slot));
        !           421:
        !           422:        switch (slot) {
        !           423:        case 'A':               /* single port, non interleaved */
        !           424:                off = 0;
        !           425:                scale = 1;
        !           426:                break;
        !           427:        case 'a':               /* dual port, interleaved */
        !           428:        case 'b':
        !           429:                off = slot - 'a';
        !           430:                scale = 2;
        !           431:                break;
        !           432:        case '1':               /* possible quad port, interleaved */
        !           433:        case '2':
        !           434:        case '3':
        !           435:        case '4':
        !           436:                off = slot - '1';
        !           437:                scale = 4;
        !           438:                break;
        !           439:        default:
        !           440:                /* impossible */
        !           441:                log(LOG_ERR, "%s: accessing unsupported slot %c",
        !           442:                    cc->cc_ifp->if_xname, slot);
        !           443:                return (-1);
        !           444:        }
        !           445:
        !           446:        /*
        !           447:         * setup timeslot map but first make sure no timeslot is already used
        !           448:         * note: 56kbps mode for T1-SF needs to be set in here
        !           449:         * note2: if running with port mapping the other group needs to be
        !           450:         * checked too or we may get funny results. Currenly not possible
        !           451:         * because of the slot offsets (odd, even slots).
        !           452:         */
        !           453:        for (i = 0; i < sizeof(u_int32_t) * 8; i++)
        !           454:                if (tslots & (1 << i))
        !           455:                        if (mg->mg_group->tx_tsmap[i * scale + off] &
        !           456:                            MUSYCC_TSLOT_ENABLED ||
        !           457:                            mg->mg_group->rx_tsmap[i * scale + off] &
        !           458:                            MUSYCC_TSLOT_ENABLED)
        !           459:                                return (0);
        !           460:
        !           461:        for (i = 0; i < sizeof(u_int32_t) * 8; i++)
        !           462:                if (tslots & (1 << i)) {
        !           463:                        nslots++;
        !           464:                        mg->mg_group->tx_tsmap[i * scale + off] =
        !           465:                            MUSYCC_TSLOT_CHAN(cc->cc_channel) |
        !           466:                            MUSYCC_TSLOT_ENABLED;
        !           467:                        mg->mg_group->rx_tsmap[i * scale + off] =
        !           468:                            MUSYCC_TSLOT_CHAN(cc->cc_channel) |
        !           469:                            MUSYCC_TSLOT_ENABLED;
        !           470:                }
        !           471:
        !           472:        return (nslots);
        !           473: }
        !           474:
        !           475: int
        !           476: musycc_set_chandesc(struct musycc_group *mg, int chan, int nslots, int proto)
        !           477: {
        !           478:        u_int64_t       mask = ULLONG_MAX;
        !           479:        int             idx, n;
        !           480:
        !           481:        ACCOOM_PRINTF(1, ("%s: musycc_set_chandesc nslots %d proto %d\n",
        !           482:            mg->mg_channels[chan]->cc_ifp->if_xname, nslots, proto));
        !           483:
        !           484:        if (nslots == 0 || nslots > 32)
        !           485:                return (EINVAL);
        !           486:
        !           487:        n = 64 - 2 * nslots;
        !           488:        mask >>= n;
        !           489:
        !           490:        for (idx = 0; idx <= n; idx += 2)
        !           491:                if (!(mg->mg_fifomask & mask << idx))
        !           492:                        break;
        !           493:
        !           494:        if (idx > n)
        !           495:                return (EBUSY);
        !           496:
        !           497:        mg->mg_fifomask |= mask << idx;
        !           498:
        !           499:        /* setup channel descriptor */
        !           500:        mg->mg_group->tx_cconf[chan] = htole32(MUSYCC_CHAN_BUFIDX_SET(idx) |
        !           501:            MUSYCC_CHAN_BUFLEN_SET(nslots * 2 - 1) |
        !           502:            MUSYCC_CHAN_PROTO_SET(proto));
        !           503:        mg->mg_group->rx_cconf[chan] = htole32(MUSYCC_CHAN_BUFIDX_SET(idx) |
        !           504:            MUSYCC_CHAN_BUFLEN_SET(nslots * 2 - 1) |
        !           505:            MUSYCC_CHAN_MSKIDLE | MUSYCC_CHAN_MSKSUERR | MUSYCC_CHAN_MSKSINC |
        !           506:            MUSYCC_CHAN_MSKSDEC | MUSYCC_CHAN_MSKSFILT |
        !           507:            MUSYCC_CHAN_PROTO_SET(proto));
        !           508:
        !           509:        return (0);
        !           510: }
        !           511:
        !           512: int
        !           513: musycc_init_channel(struct channel_softc *cc, char slot)
        !           514: {
        !           515:        struct musycc_group     *mg;
        !           516:        struct ifnet            *ifp = cc->cc_ifp;
        !           517:        int                      nslots, rv, s;
        !           518:
        !           519:        if (cc->cc_state == CHAN_FLOAT)
        !           520:                return (ENOTTY);
        !           521:        mg = cc->cc_group;
        !           522:
        !           523:        ACCOOM_PRINTF(2, ("%s: musycc_init_channel [state %d] slot %c\n",
        !           524:            cc->cc_ifp->if_xname, cc->cc_state, slot));
        !           525:
        !           526:        if (cc->cc_state != CHAN_IDLE) {
        !           527:                musycc_sreq(mg, cc->cc_channel, MUSYCC_SREQ_SET(9),
        !           528:                    MUSYCC_SREQ_BOTH, EV_STOP);
        !           529:                tsleep(cc, PZERO | PCATCH, "musycc", hz);
        !           530:                if (cc->cc_state != CHAN_IDLE) {
        !           531:                        ACCOOM_PRINTF(0, ("%s: failed to reset channel\n",
        !           532:                            cc->cc_ifp->if_xname));
        !           533:                        return (EIO);
        !           534:                }
        !           535:        }
        !           536:
        !           537:        s = splnet();
        !           538:        /* setup timeslot map */
        !           539:        nslots = musycc_set_tsmap(mg, cc, slot);
        !           540:        if (nslots == -1) {
        !           541:                rv = EINVAL;
        !           542:                goto fail;
        !           543:        } else if (nslots == 0) {
        !           544:                rv = EBUSY;
        !           545:                goto fail;
        !           546:        }
        !           547:
        !           548:        if ((rv = musycc_set_chandesc(mg, cc->cc_channel, nslots,
        !           549:            MUSYCC_PROTO_HDLC16)))
        !           550:                goto fail;
        !           551:
        !           552:        /* setup tx DMA chain */
        !           553:        musycc_list_tx_init(mg, cc->cc_channel, MUSYCC_DMA_SIZE);
        !           554:        /* setup rx DMA chain */
        !           555:        if ((rv = musycc_list_rx_init(mg, cc->cc_channel, MUSYCC_DMA_SIZE))) {
        !           556:                ACCOOM_PRINTF(0, ("%s: initialization failed: "
        !           557:                    "no memory for rx buffers\n", cc->cc_ifp->if_xname));
        !           558:                goto fail;
        !           559:        }
        !           560:
        !           561:        /* IFF_RUNNING set by sppp_ioctl() */
        !           562:        ifp->if_flags &= ~IFF_OACTIVE;
        !           563:
        !           564:        cc->cc_state = CHAN_TRANSIENT;
        !           565:        splx(s);
        !           566:
        !           567:        musycc_dump_group(3, mg);
        !           568:        musycc_activate_channel(mg, cc->cc_channel);
        !           569:        tsleep(cc, PZERO | PCATCH, "musycc", hz);
        !           570:
        !           571:        /*
        !           572:         * XXX we could actually check if the activation of the channels was
        !           573:         * successful but what type of error should we return?
        !           574:         */
        !           575:        return (0);
        !           576:
        !           577: fail:
        !           578:        splx(s);
        !           579:        cc->cc_state = CHAN_IDLE; /* force idle state */
        !           580:        musycc_free_channel(mg, cc->cc_channel);
        !           581:        return (rv);
        !           582: }
        !           583:
        !           584: void
        !           585: musycc_activate_channel(struct musycc_group *mg, int chan)
        !           586: {
        !           587:        ACCOOM_PRINTF(2, ("%s: musycc_activate_channel\n",
        !           588:            mg->mg_channels[chan]->cc_ifp->if_xname));
        !           589:        musycc_sreq(mg, chan, MUSYCC_SREQ_SET(26), MUSYCC_SREQ_BOTH,
        !           590:            EV_NULL);
        !           591:        musycc_sreq(mg, chan, MUSYCC_SREQ_SET(24), MUSYCC_SREQ_BOTH,
        !           592:            EV_NULL);
        !           593:        musycc_sreq(mg, chan, MUSYCC_SREQ_SET(8), MUSYCC_SREQ_BOTH,
        !           594:            EV_ACTIVATE);
        !           595: }
        !           596:
        !           597: void
        !           598: musycc_stop_channel(struct channel_softc *cc)
        !           599: {
        !           600:        struct musycc_group     *mg;
        !           601:
        !           602:        if (cc->cc_state == CHAN_FLOAT) {
        !           603:                /* impossible */
        !           604:                log(LOG_ERR, "%s: unexpected state in musycc_stop_channel",
        !           605:                    cc->cc_ifp->if_xname);
        !           606:                cc->cc_state = CHAN_IDLE; /* reset */
        !           607:                musycc_free_channel(mg, cc->cc_channel);
        !           608:                return;
        !           609:        }
        !           610:
        !           611:        mg = cc->cc_group;
        !           612:        ACCOOM_PRINTF(2, ("%s: musycc_stop_channel\n", cc->cc_ifp->if_xname));
        !           613:        musycc_sreq(mg, cc->cc_channel, MUSYCC_SREQ_SET(9), MUSYCC_SREQ_BOTH,
        !           614:            EV_STOP);
        !           615:        tsleep(cc, PZERO | PCATCH, "musycc", hz);
        !           616: }
        !           617:
        !           618: void
        !           619: musycc_free_channel(struct musycc_group *mg, int chan)
        !           620: {
        !           621:        u_int64_t       mask = ULLONG_MAX;
        !           622:        int             i, idx, s, slots;
        !           623:
        !           624:        ACCOOM_PRINTF(2, ("%s: musycc_free_channel\n",
        !           625:            mg->mg_channels[chan]->cc_ifp->if_xname));
        !           626:
        !           627:        s = splnet();
        !           628:        /* Clear the timeout timer. */
        !           629:        mg->mg_channels[chan]->cc_ifp->if_timer = 0;
        !           630:
        !           631:        /* clear timeslot map */
        !           632:        for (i = 0; i < 128; i++) {
        !           633:                if (mg->mg_group->tx_tsmap[i] & MUSYCC_TSLOT_ENABLED)
        !           634:                        if ((mg->mg_group->tx_tsmap[i] & MUSYCC_TSLOT_MASK) ==
        !           635:                            chan)
        !           636:                                mg->mg_group->tx_tsmap[i] = 0;
        !           637:                if (mg->mg_group->rx_tsmap[i] & MUSYCC_TSLOT_ENABLED)
        !           638:                        if ((mg->mg_group->rx_tsmap[i] & MUSYCC_TSLOT_MASK) ==
        !           639:                            chan)
        !           640:                                mg->mg_group->rx_tsmap[i] = 0;
        !           641:        }
        !           642:
        !           643:        /* clear channel descriptor, especially free FIFO space */
        !           644:        idx = MUSYCC_CHAN_BUFIDX_GET(letoh32(mg->mg_group->tx_cconf[chan]));
        !           645:        slots = MUSYCC_CHAN_BUFLEN_GET(letoh32(mg->mg_group->tx_cconf[chan]));
        !           646:        slots = (slots + 1) / 2;
        !           647:        mask >>= 64 - 2 * slots;
        !           648:        mask <<= idx;
        !           649:        mg->mg_fifomask &= ~mask;
        !           650:        mg->mg_group->tx_cconf[chan] = 0;
        !           651:        mg->mg_group->rx_cconf[chan] = 0;
        !           652:
        !           653:        /* free dma rings */
        !           654:        musycc_list_rx_free(mg, chan);
        !           655:        musycc_list_tx_free(mg, chan);
        !           656:
        !           657:        splx(s);
        !           658:
        !           659:        /* update chip info with sreq */
        !           660:        musycc_sreq(mg, chan, MUSYCC_SREQ_SET(24), MUSYCC_SREQ_BOTH,
        !           661:            EV_NULL);
        !           662:        musycc_sreq(mg, chan, MUSYCC_SREQ_SET(26), MUSYCC_SREQ_BOTH,
        !           663:            EV_IDLE);
        !           664: }
        !           665:
        !           666: void
        !           667: musycc_state_engine(struct musycc_group *mg, int chan, enum musycc_event ev)
        !           668: {
        !           669:        enum musycc_state       state;
        !           670:
        !           671:        if (mg->mg_channels[chan] == NULL)
        !           672:                return;
        !           673:
        !           674:        state = mg->mg_channels[chan]->cc_state;
        !           675:
        !           676:        ACCOOM_PRINTF(2, ("%s: musycc_state_engine state %d event %d\n",
        !           677:            mg->mg_channels[chan]->cc_ifp->if_xname, state, ev));
        !           678:
        !           679:        switch (ev) {
        !           680:        case EV_NULL:
        !           681:                /* no state change */
        !           682:                return;
        !           683:        case EV_ACTIVATE:
        !           684:                state = CHAN_RUNNING;
        !           685:                break;
        !           686:        case EV_STOP:
        !           687:                /* channel disabled now free dma rings et al. */
        !           688:                mg->mg_channels[chan]->cc_state = CHAN_TRANSIENT;
        !           689:                musycc_free_channel(mg, chan);
        !           690:                return;
        !           691:        case EV_IDLE:
        !           692:                state = CHAN_IDLE;
        !           693:                break;
        !           694:        case EV_WATCHDOG:
        !           695:                musycc_reinit_dma(mg, chan);
        !           696:                return;
        !           697:        }
        !           698:
        !           699:        mg->mg_channels[chan]->cc_state = state;
        !           700:        wakeup(mg->mg_channels[chan]);
        !           701: }
        !           702:
        !           703: /*
        !           704:  * DMA handling functions
        !           705:  */
        !           706:
        !           707: struct dma_desc *
        !           708: musycc_dma_get(struct musycc_group *mg)
        !           709: {
        !           710:        struct dma_desc *dd;
        !           711:
        !           712:        splassert(IPL_NET);
        !           713:
        !           714:        if (mg->mg_freecnt == 0)
        !           715:                return (NULL);
        !           716:        mg->mg_freecnt--;
        !           717:        dd = mg->mg_freelist;
        !           718:        mg->mg_freelist = dd->nextdesc;
        !           719:        /* clear some important data */
        !           720:        dd->nextdesc = NULL;
        !           721:        dd->mbuf = NULL;
        !           722:
        !           723:        return (dd);
        !           724: }
        !           725:
        !           726: void
        !           727: musycc_dma_free(struct musycc_group *mg, struct dma_desc *dd)
        !           728: {
        !           729:        splassert(IPL_NET);
        !           730:
        !           731:        dd->nextdesc = mg->mg_freelist;
        !           732:        mg->mg_freelist = dd;
        !           733:        mg->mg_freecnt++;
        !           734: }
        !           735:
        !           736: /*
        !           737:  * Initialize the transmit descriptors. Acctually they are left empty until
        !           738:  * a packet comes in.
        !           739:  */
        !           740: int
        !           741: musycc_list_tx_init(struct musycc_group *mg, int c, int size)
        !           742: {
        !           743:        struct musycc_dma_data  *md;
        !           744:        struct dma_desc         *dd;
        !           745:        bus_addr_t               base;
        !           746:        int                      i;
        !           747:
        !           748:        splassert(IPL_NET);
        !           749:        ACCOOM_PRINTF(2, ("musycc_list_tx_init\n"));
        !           750:        md = &mg->mg_dma_d[c];
        !           751:        md->tx_pend = NULL;
        !           752:        md->tx_cur = NULL;
        !           753:        md->tx_cnt = size;
        !           754:        md->tx_pkts = 0;
        !           755:
        !           756:        base = mg->mg_listmap->dm_segs[0].ds_addr;
        !           757:        for (i = 0; i < md->tx_cnt; i++) {
        !           758:                dd = musycc_dma_get(mg);
        !           759:                if (dd == NULL) {
        !           760:                        ACCOOM_PRINTF(0, ("musycc_list_tx_init: "
        !           761:                            "out of dma_desc\n"));
        !           762:                        musycc_list_tx_free(mg, c);
        !           763:                        return (ENOBUFS);
        !           764:                }
        !           765:                dd->status = 0 /* MUSYCC_STATUS_NOPOLL */;
        !           766:                dd->data = 0;
        !           767:                if (md->tx_cur) {
        !           768:                        md->tx_cur->nextdesc = dd;
        !           769:                        md->tx_cur->next = htole32(base + (caddr_t)dd -
        !           770:                            mg->mg_listkva);
        !           771:                        md->tx_cur = dd;
        !           772:                } else
        !           773:                        md->tx_pend = md->tx_cur = dd;
        !           774:        }
        !           775:
        !           776:        dd->nextdesc = md->tx_pend;
        !           777:        dd->next = htole32(base + (caddr_t)md->tx_pend - mg->mg_listkva);
        !           778:        md->tx_pend = dd;
        !           779:
        !           780:        mg->mg_group->tx_headp[c] = htole32(base + (caddr_t)dd -
        !           781:            mg->mg_listkva);
        !           782:
        !           783:        bus_dmamap_sync(mg->mg_dmat, mg->mg_listmap, 0, MUSYCC_DMA_MAPSIZE,
        !           784:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !           785:
        !           786:        return (0);
        !           787: }
        !           788:
        !           789:
        !           790: /*
        !           791:  * Initialize the RX descriptors and allocate mbufs for them. Note that
        !           792:  * we arrange the descriptors in a closed ring, so that the last descriptor
        !           793:  * points back to the first.
        !           794:  */
        !           795: int
        !           796: musycc_list_rx_init(struct musycc_group *mg, int c, int size)
        !           797: {
        !           798:        struct musycc_dma_data  *md;
        !           799:        struct dma_desc         *dd = NULL, *last;
        !           800:        bus_addr_t               base;
        !           801:        int                      i;
        !           802:
        !           803:        splassert(IPL_NET);
        !           804:        ACCOOM_PRINTF(2, ("musycc_list_rx_init\n"));
        !           805:        md = &mg->mg_dma_d[c];
        !           806:        md->rx_cnt = size;
        !           807:
        !           808:        base = mg->mg_listmap->dm_segs[0].ds_addr;
        !           809:        for (i = 0; i < size; i++) {
        !           810:                dd = musycc_dma_get(mg);
        !           811:                if (dd == NULL) {
        !           812:                        ACCOOM_PRINTF(0, ("musycc_list_rx_init: "
        !           813:                            "out of dma_desc\n"));
        !           814:                        musycc_list_rx_free(mg, c);
        !           815:                        return (ENOBUFS);
        !           816:                }
        !           817:                if (musycc_newbuf(mg, dd, NULL) == ENOBUFS) {
        !           818:                        ACCOOM_PRINTF(0, ("musycc_list_rx_init: "
        !           819:                            "out of mbufs\n"));
        !           820:                        musycc_list_rx_free(mg, c);
        !           821:                        return (ENOBUFS);
        !           822:                }
        !           823:                if (md->rx_prod) {
        !           824:                        md->rx_prod->nextdesc = dd;
        !           825:                        md->rx_prod->next = htole32(base + (caddr_t)dd -
        !           826:                            mg->mg_listkva);
        !           827:                        md->rx_prod = dd;
        !           828:                } else
        !           829:                        last = md->rx_prod = dd;
        !           830:        }
        !           831:
        !           832:        dd->nextdesc = last;
        !           833:        dd->next = htole32(base + (caddr_t)last - mg->mg_listkva);
        !           834:
        !           835:        mg->mg_group->rx_headp[c] = htole32(base + (caddr_t)dd -
        !           836:            mg->mg_listkva);
        !           837:
        !           838:        bus_dmamap_sync(mg->mg_dmat, mg->mg_listmap, 0, MUSYCC_DMA_MAPSIZE,
        !           839:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !           840:
        !           841:        return (0);
        !           842: }
        !           843:
        !           844: void
        !           845: musycc_list_tx_free(struct musycc_group *mg, int c)
        !           846: {
        !           847:        struct musycc_dma_data  *md;
        !           848:        struct dma_desc         *dd, *tmp;
        !           849:
        !           850:        md = &mg->mg_dma_d[c];
        !           851:
        !           852:        splassert(IPL_NET);
        !           853:        ACCOOM_PRINTF(2, ("musycc_list_tx_free\n"));
        !           854:        dd = md->tx_pend;
        !           855:        do {
        !           856:                if (dd == NULL)
        !           857:                        break;
        !           858:                if (dd->map->dm_nsegs != 0) {
        !           859:                        bus_dmamap_t map = dd->map;
        !           860:
        !           861:                        bus_dmamap_unload(mg->mg_dmat, map);
        !           862:                }
        !           863:                if (dd->mbuf != NULL) {
        !           864:                        m_freem(dd->mbuf);
        !           865:                        dd->mbuf = NULL;
        !           866:                }
        !           867:                tmp = dd;
        !           868:                dd = dd->nextdesc;
        !           869:                musycc_dma_free(mg, tmp);
        !           870:        } while (dd != md->tx_pend);
        !           871:        md->tx_pend = md->tx_cur = NULL;
        !           872:        md->tx_cnt = md->tx_use = md->tx_pkts = 0;
        !           873: }
        !           874:
        !           875: void
        !           876: musycc_list_rx_free(struct musycc_group *mg, int c)
        !           877: {
        !           878:        struct musycc_dma_data  *md;
        !           879:        struct dma_desc         *dd, *tmp;
        !           880:
        !           881:        md = &mg->mg_dma_d[c];
        !           882:
        !           883:        splassert(IPL_NET);
        !           884:        ACCOOM_PRINTF(2, ("musycc_list_rx_free\n"));
        !           885:        dd = md->rx_prod;
        !           886:        do {
        !           887:                if (dd == NULL)
        !           888:                        break;
        !           889:                if (dd->map->dm_nsegs != 0) {
        !           890:                        bus_dmamap_t map = dd->map;
        !           891:
        !           892:                        bus_dmamap_unload(mg->mg_dmat, map);
        !           893:                }
        !           894:                if (dd->mbuf != NULL) {
        !           895:                        m_freem(dd->mbuf);
        !           896:                        dd->mbuf = NULL;
        !           897:                }
        !           898:                tmp = dd;
        !           899:                dd = dd->nextdesc;
        !           900:                musycc_dma_free(mg, tmp);
        !           901:        } while (dd != md->rx_prod);
        !           902:        md->rx_prod = NULL;
        !           903:        md->rx_cnt = 0;
        !           904: }
        !           905:
        !           906: /* only used by the watchdog timeout */
        !           907: void
        !           908: musycc_reinit_dma(struct musycc_group *mg, int c)
        !           909: {
        !           910:        int     s;
        !           911:
        !           912:        s = splnet();
        !           913:
        !           914:        musycc_list_tx_free(mg, c);
        !           915:        musycc_list_rx_free(mg, c);
        !           916:
        !           917:        /* setup tx & rx DMA chain */
        !           918:        if (musycc_list_tx_init(mg, c, MUSYCC_DMA_SIZE) ||
        !           919:            musycc_list_rx_init(mg, c, MUSYCC_DMA_SIZE)) {
        !           920:                log(LOG_ERR, "%s: Failed to malloc memory\n",
        !           921:                    mg->mg_channels[c]->cc_ifp->if_xname);
        !           922:                musycc_free_channel(mg, c);
        !           923:        }
        !           924:        splx(s);
        !           925:
        !           926:        musycc_activate_channel(mg, c);
        !           927: }
        !           928:
        !           929: /*
        !           930:  * Initialize an RX descriptor and attach an mbuf cluster.
        !           931:  */
        !           932: int
        !           933: musycc_newbuf(struct musycc_group *mg, struct dma_desc *c, struct mbuf *m)
        !           934: {
        !           935:        struct mbuf     *m_new = NULL;
        !           936:        bus_dmamap_t     map;
        !           937:
        !           938:        if (m == NULL) {
        !           939:                MGETHDR(m_new, M_DONTWAIT, MT_DATA);
        !           940:                if (m_new == NULL)
        !           941:                        return (ENOBUFS);
        !           942:
        !           943:                MCLGET(m_new, M_DONTWAIT);
        !           944:                if (!(m_new->m_flags & M_EXT)) {
        !           945:                        m_freem(m_new);
        !           946:                        return (ENOBUFS);
        !           947:                }
        !           948:                m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
        !           949:        } else {
        !           950:                m_new = m;
        !           951:                m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
        !           952:                m_new->m_data = m_new->m_ext.ext_buf;
        !           953:        }
        !           954:
        !           955:        if (bus_dmamap_load(mg->mg_dmat, mg->mg_rx_sparemap,
        !           956:            mtod(m_new, caddr_t), m_new->m_pkthdr.len, NULL,
        !           957:            BUS_DMA_NOWAIT) != 0) {
        !           958:                ACCOOM_PRINTF(0, ("%s: rx load failed\n",
        !           959:                    mg->mg_hdlc->mc_dev.dv_xname));
        !           960:                m_freem(m_new);
        !           961:                return (ENOBUFS);
        !           962:        }
        !           963:        map = c->map;
        !           964:        c->map = mg->mg_rx_sparemap;
        !           965:        mg->mg_rx_sparemap = map;
        !           966:
        !           967:        bus_dmamap_sync(mg->mg_dmat, c->map, 0, c->map->dm_mapsize,
        !           968:            BUS_DMASYNC_PREREAD);
        !           969:
        !           970:        c->mbuf = m_new;
        !           971:        c->data = htole32(c->map->dm_segs[0].ds_addr);
        !           972:        c->status = htole32(MUSYCC_STATUS_NOPOLL |
        !           973:                    MUSYCC_STATUS_LEN(m_new->m_pkthdr.len));
        !           974:
        !           975:        bus_dmamap_sync(mg->mg_dmat, mg->mg_listmap,
        !           976:            ((caddr_t)c - mg->mg_listkva), sizeof(struct dma_desc),
        !           977:            BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !           978:
        !           979:        return (0);
        !           980: }
        !           981:
        !           982: /*
        !           983:  * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
        !           984:  * pointers to the fragment pointers.
        !           985:  */
        !           986: int
        !           987: musycc_encap(struct musycc_group *mg, struct mbuf *m_head, int c)
        !           988: {
        !           989:        struct dma_desc *cur, *tmp;
        !           990:        bus_dmamap_t     map;
        !           991:        bus_addr_t       base;
        !           992:        u_int32_t        status;
        !           993:        int              i;
        !           994:
        !           995:        splassert(IPL_NET);
        !           996:
        !           997:        map = mg->mg_tx_sparemap;
        !           998:        if (bus_dmamap_load_mbuf(mg->mg_dmat, map, m_head,
        !           999:            BUS_DMA_NOWAIT) != 0) {
        !          1000:                ACCOOM_PRINTF(0, ("%s: musycc_encap: dmamap_load failed\n",
        !          1001:                    mg->mg_channels[c]->cc_ifp->if_xname));
        !          1002:                return (ENOBUFS);
        !          1003:        }
        !          1004:
        !          1005:        cur = mg->mg_dma_d[c].tx_cur;
        !          1006:        base = mg->mg_listmap->dm_segs[0].ds_addr;
        !          1007:
        !          1008:        if (map->dm_nsegs + mg->mg_dma_d[c].tx_use >= mg->mg_dma_d[c].tx_cnt) {
        !          1009:                ACCOOM_PRINTF(1, ("%s: tx out of dma bufs\n",
        !          1010:                    mg->mg_channels[c]->cc_ifp->if_xname));
        !          1011:                return (ENOBUFS);
        !          1012:        }
        !          1013:
        !          1014:        i = 0;
        !          1015:        while (i < map->dm_nsegs) {
        !          1016:                status = /* MUSYCC_STATUS_NOPOLL | */
        !          1017:                    MUSYCC_STATUS_LEN(map->dm_segs[i].ds_len);
        !          1018:                if (cur != mg->mg_dma_d[c].tx_cur)
        !          1019:                        status |= MUSYCC_STATUS_OWNER;
        !          1020:
        !          1021:                cur->status = htole32(status);
        !          1022:                cur->data = htole32(map->dm_segs[i].ds_addr);
        !          1023:
        !          1024:                bus_dmamap_sync(mg->mg_dmat, mg->mg_listmap,
        !          1025:                    ((caddr_t)cur - mg->mg_listkva), sizeof(struct dma_desc),
        !          1026:                    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
        !          1027:
        !          1028:                if (++i >= map->dm_nsegs)
        !          1029:                        break;
        !          1030:                cur = cur->nextdesc;
        !          1031:        }
        !          1032:
        !          1033:        bus_dmamap_sync(mg->mg_dmat, map, 0, map->dm_mapsize,
        !          1034:            BUS_DMASYNC_PREWRITE);
        !          1035:
        !          1036:        cur->mbuf = m_head;
        !          1037:        mg->mg_tx_sparemap = cur->map;
        !          1038:        cur->map = map;
        !          1039:        cur->status |= htole32(MUSYCC_STATUS_EOM);
        !          1040:        tmp = mg->mg_dma_d[c].tx_cur;
        !          1041:        mg->mg_dma_d[c].tx_cur = cur->nextdesc;
        !          1042:        mg->mg_dma_d[c].tx_use += i;
        !          1043:        mg->mg_dma_d[c].tx_pkts++;
        !          1044:
        !          1045:        /*
        !          1046:         * Last but not least, flag the buffer if the buffer is flagged to
        !          1047:         * early, it may happen, that the buffer is already transmitted
        !          1048:         * before we changed all relevant variables.
        !          1049:         */
        !          1050:        tmp->status |= htole32(MUSYCC_STATUS_OWNER);
        !          1051: #if 0
        !          1052:        /* check for transmited packets NO POLLING mode only */
        !          1053:        /*
        !          1054:         * Note: a bug in the HDLC chip seems to make it impossible to use
        !          1055:         * no polling mode.
        !          1056:         */
        !          1057:        musycc_txeom(mg, c);
        !          1058:        if (mg->mg_dma_d[c].tx_pend == tmp) {
        !          1059:                /* and restart as needed */
        !          1060:                printf("%s: tx needs kick\n",
        !          1061:                    mg->mg_channels[c]->cc_ifp->if_xname);
        !          1062:                mg->mg_group->tx_headp[c] = htole32(base +
        !          1063:                    (caddr_t)mg->mg_dma_d[c].tx_pend - mg->mg_listkva);
        !          1064:
        !          1065:                musycc_sreq(mg, c, MUSYCC_SREQ_SET(8), MUSYCC_SREQ_TX);
        !          1066:        }
        !          1067: #endif
        !          1068:
        !          1069:        return (0);
        !          1070: }
        !          1071:
        !          1072:
        !          1073: /*
        !          1074:  * API towards the kernel
        !          1075:  */
        !          1076:
        !          1077: /* start transmit of new network buffer */
        !          1078: void
        !          1079: musycc_start(struct ifnet *ifp)
        !          1080: {
        !          1081:        struct musycc_group     *mg;
        !          1082:        struct channel_softc    *cc;
        !          1083:        struct mbuf             *m = NULL;
        !          1084:        int                     s;
        !          1085:
        !          1086:        cc = ifp->if_softc;
        !          1087:        mg = cc->cc_group;
        !          1088:
        !          1089:        ACCOOM_PRINTF(3, ("musycc_start\n"));
        !          1090:        if (cc->cc_state != CHAN_RUNNING)
        !          1091:                return;
        !          1092:        if (ifp->if_flags & IFF_OACTIVE)
        !          1093:                return;
        !          1094:        if (sppp_isempty(ifp))
        !          1095:                return;
        !          1096:
        !          1097:        s = splnet();
        !          1098:        while ((m = sppp_pick(ifp)) != NULL) {
        !          1099:                if (musycc_encap(mg, m, cc->cc_channel)) {
        !          1100:                        ifp->if_flags |= IFF_OACTIVE;
        !          1101:                        break;
        !          1102:                }
        !          1103:
        !          1104: #if NBPFILTER > 0
        !          1105:                if (ifp->if_bpf)
        !          1106:                        bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
        !          1107: #endif
        !          1108:
        !          1109:                /* now we are committed to transmit the packet */
        !          1110:                sppp_dequeue(ifp);
        !          1111:        }
        !          1112:        splx(s);
        !          1113:
        !          1114:        /*
        !          1115:         * Set a timeout in case the chip goes out to lunch.
        !          1116:         */
        !          1117:        ifp->if_timer = 5;
        !          1118:
        !          1119:        return;
        !          1120: }
        !          1121:
        !          1122:
        !          1123: /*
        !          1124:  * Watchdog/transmission transmit timeout handler. Called when a
        !          1125:  * transmission is started on the interface, but no interrupt is
        !          1126:  * received before the timeout. This usually indicates that the
        !          1127:  * card has wedged for some reason.
        !          1128:  */
        !          1129: void
        !          1130: musycc_watchdog(struct ifnet *ifp)
        !          1131: {
        !          1132:        struct channel_softc    *cc = ifp->if_softc;
        !          1133:
        !          1134:        log(LOG_ERR, "%s: device timeout\n", cc->cc_ifp->if_xname);
        !          1135:        ifp->if_oerrors++;
        !          1136:
        !          1137:        musycc_sreq(cc->cc_group, cc->cc_channel, MUSYCC_SREQ_SET(9),
        !          1138:            MUSYCC_SREQ_BOTH, EV_WATCHDOG);
        !          1139: }
        !          1140:
        !          1141:
        !          1142: /*
        !          1143:  * Interrupt specific functions
        !          1144:  */
        !          1145:
        !          1146: /*
        !          1147:  * A frame has been uploaded: pass the resulting mbuf chain up to
        !          1148:  * the higher level protocols.
        !          1149:  */
        !          1150: void
        !          1151: musycc_rxeom(struct musycc_group *mg, int channel, int forcekick)
        !          1152: {
        !          1153:        struct mbuf     *m;
        !          1154:        struct ifnet    *ifp;
        !          1155:        struct dma_desc *cur_rx, *start_rx;
        !          1156:        int              total_len = 0, consumed = 0;
        !          1157:        u_int32_t        rxstat;
        !          1158:
        !          1159:        ACCOOM_PRINTF(3, ("musycc_rxeom\n"));
        !          1160:
        !          1161:        ifp = mg->mg_channels[channel]->cc_ifp;
        !          1162:
        !          1163:        start_rx = cur_rx = mg->mg_dma_d[channel].rx_prod;
        !          1164:        if (cur_rx == NULL)
        !          1165:                return; /* dma ring got cleared */
        !          1166:        do {
        !          1167:                bus_dmamap_sync(mg->mg_dmat, mg->mg_listmap,
        !          1168:                    ((caddr_t)cur_rx - mg->mg_listkva),
        !          1169:                    sizeof(struct dma_desc),
        !          1170:                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
        !          1171:
        !          1172:                rxstat = letoh32(cur_rx->status);
        !          1173:                if (!(rxstat & MUSYCC_STATUS_OWNER))
        !          1174:                        break;
        !          1175:
        !          1176:                m = cur_rx->mbuf;
        !          1177:                cur_rx->mbuf = NULL;
        !          1178:                total_len = MUSYCC_STATUS_LEN(rxstat);
        !          1179:
        !          1180:
        !          1181:                /*
        !          1182:                 * If an error occurs, update stats, clear the
        !          1183:                 * status word and leave the mbuf cluster in place:
        !          1184:                 * it should simply get re-used next time this descriptor
        !          1185:                 * comes up in the ring.
        !          1186:                 */
        !          1187:                if (rxstat & MUSYCC_STATUS_ERROR) {
        !          1188:                        ifp->if_ierrors++;
        !          1189:                        ACCOOM_PRINTF(1, ("%s: rx error %08x\n",
        !          1190:                            ifp->if_xname, rxstat));
        !          1191:                        musycc_newbuf(mg, cur_rx, m);
        !          1192:                        cur_rx = cur_rx->nextdesc;
        !          1193:                        consumed++;
        !          1194:                        continue;
        !          1195:                }
        !          1196:
        !          1197:                /* No errors; receive the packet. */
        !          1198:                bus_dmamap_sync(mg->mg_dmat, cur_rx->map, 0,
        !          1199:                    cur_rx->map->dm_mapsize, BUS_DMASYNC_POSTREAD);
        !          1200:                if (musycc_newbuf(mg, cur_rx, NULL) != 0) {
        !          1201:                        cur_rx = cur_rx->nextdesc;
        !          1202:                        consumed++;
        !          1203:                        continue;
        !          1204:                }
        !          1205:
        !          1206:                cur_rx = cur_rx->nextdesc;
        !          1207:                consumed++;
        !          1208:
        !          1209:                /* TODO support mbuf chains */
        !          1210:                m->m_pkthdr.rcvif = ifp;
        !          1211:                m->m_pkthdr.len = m->m_len = total_len;
        !          1212:                ifp->if_ipackets++;
        !          1213:
        !          1214: #if NBPFILTER > 0
        !          1215:                if (ifp->if_bpf)
        !          1216:                        bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
        !          1217: #endif
        !          1218:
        !          1219:                /* pass it on. */
        !          1220:                sppp_input(ifp, m);
        !          1221:        } while (cur_rx != start_rx);
        !          1222:
        !          1223:        mg->mg_dma_d[channel].rx_prod = cur_rx;
        !          1224:
        !          1225:        if ((cur_rx == start_rx && consumed) || forcekick) {
        !          1226:                /* send SREQ to signal the new buffers */
        !          1227:                ACCOOM_PRINTF(1, ("%s: rx kick, consumed %d pkts\n",
        !          1228:                    mg->mg_channels[channel]->cc_ifp->if_xname, consumed));
        !          1229:                mg->mg_group->rx_headp[channel] = htole32(
        !          1230:                    mg->mg_listmap->dm_segs[0].ds_addr +
        !          1231:                    (caddr_t)cur_rx - mg->mg_listkva);
        !          1232:                musycc_sreq(mg, channel, MUSYCC_SREQ_SET(8),
        !          1233:                    MUSYCC_SREQ_RX, EV_NULL);
        !          1234:        }
        !          1235: }
        !          1236:
        !          1237: /*
        !          1238:  * A frame was downloaded to the chip. It's safe for us to clean up
        !          1239:  * the list buffers.
        !          1240:  */
        !          1241: void
        !          1242: musycc_txeom(struct musycc_group *mg, int channel, int forcekick)
        !          1243: {
        !          1244:        struct dma_desc         *dd, *dd_pend;
        !          1245:        struct ifnet            *ifp;
        !          1246:
        !          1247:        ACCOOM_PRINTF(3, ("musycc_txeom\n"));
        !          1248:
        !          1249:        ifp = mg->mg_channels[channel]->cc_ifp;
        !          1250:        /* Clear the watchdog timer. */
        !          1251:        ifp->if_timer = 0;
        !          1252:
        !          1253:        /*
        !          1254:         * Go through our tx list and free mbufs for those
        !          1255:         * frames that have been transmitted.
        !          1256:         */
        !          1257:        for (dd = mg->mg_dma_d[channel].tx_pend;
        !          1258:            dd != mg->mg_dma_d[channel].tx_cur;
        !          1259:            dd = dd->nextdesc) {
        !          1260:                bus_dmamap_sync(mg->mg_dmat, mg->mg_listmap,
        !          1261:                    ((caddr_t)dd - mg->mg_listkva), sizeof(struct dma_desc),
        !          1262:                    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
        !          1263:
        !          1264:                if (letoh32(dd->status) & MUSYCC_STATUS_OWNER)
        !          1265:                        /* musycc still owns this descriptor */
        !          1266:                        break;
        !          1267:
        !          1268:                mg->mg_dma_d[channel].tx_use--;
        !          1269:
        !          1270:                dd->status = 0; /* reinit dma status flags */
        !          1271:                /* dd->status |= MUSYCC_STATUS_NOPOLL; *//* disable polling */
        !          1272:
        !          1273:                if (dd->map->dm_nsegs != 0) {
        !          1274:                        bus_dmamap_sync(mg->mg_dmat, dd->map, 0,
        !          1275:                            dd->map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
        !          1276:                        bus_dmamap_unload(mg->mg_dmat, dd->map);
        !          1277:                }
        !          1278:                if (dd->mbuf != NULL) {
        !          1279:                        m_freem(dd->mbuf);
        !          1280:                        dd->mbuf = NULL;
        !          1281:                        mg->mg_dma_d[channel].tx_pkts--;
        !          1282:                        ifp->if_opackets++;
        !          1283:                }
        !          1284:        }
        !          1285:
        !          1286:        dd_pend = mg->mg_dma_d[channel].tx_pend;
        !          1287:        mg->mg_dma_d[channel].tx_pend = dd;
        !          1288:
        !          1289:        if (ifp->if_flags & IFF_OACTIVE && dd_pend != dd) {
        !          1290:                ifp->if_flags &= ~IFF_OACTIVE;
        !          1291:                musycc_start(ifp);
        !          1292:        }
        !          1293:
        !          1294:        if (forcekick) {
        !          1295:                /* restart */
        !          1296:                ACCOOM_PRINTF(1, ("%s: tx kick forced\n",
        !          1297:                    mg->mg_channels[channel]->cc_ifp->if_xname));
        !          1298:                mg->mg_group->tx_headp[channel] =
        !          1299:                    htole32(mg->mg_listmap->dm_segs[0].ds_addr +
        !          1300:                    (caddr_t)mg->mg_dma_d[channel].tx_pend - mg->mg_listkva);
        !          1301:
        !          1302:                musycc_sreq(mg, channel, MUSYCC_SREQ_SET(8), MUSYCC_SREQ_TX,
        !          1303:                    EV_NULL);
        !          1304:        }
        !          1305: }
        !          1306:
        !          1307: int
        !          1308: musycc_intr(void *arg)
        !          1309: {
        !          1310:        struct musycc_softc     *mc = arg;
        !          1311:        struct musycc_group     *mg;
        !          1312:        struct ifnet            *ifp;
        !          1313:        u_int32_t                intstatus, id;
        !          1314:        int                      i, n, chan;
        !          1315:
        !          1316:        intstatus = bus_space_read_4(mc->mc_st, mc->mc_sh, MUSYCC_INTRSTATUS);
        !          1317:
        !          1318:        if (intstatus & MUSYCC_INTCNT_MASK) {
        !          1319:                bus_dmamap_sync(mc->mc_dmat, mc->mc_intrmap,
        !          1320:                    offsetof(struct musycc_intdesc, md_intrq[0]),
        !          1321:                    MUSYCC_INTLEN * sizeof(u_int32_t), BUS_DMASYNC_POSTREAD);
        !          1322:
        !          1323:                ACCOOM_PRINTF(4, ("%s: interrupt status %08x\n",
        !          1324:                    mc->mc_dev.dv_xname, intstatus));
        !          1325:
        !          1326:                n = MUSYCC_NEXTINT_GET(intstatus);
        !          1327:                for (i = 0; i < (intstatus & MUSYCC_INTCNT_MASK); i++) {
        !          1328:                        id = letoh32(mc->mc_intrd->md_intrq[(n + i) %
        !          1329:                            MUSYCC_INTLEN]);
        !          1330:                        chan = MUSYCC_INTD_CHAN(id);
        !          1331:                        mg = &mc->mc_groups[MUSYCC_INTD_GRP(id)];
        !          1332:
        !          1333:                        ACCOOM_PRINTF(4, ("%s: interrupt %s\n",
        !          1334:                            mc->mc_dev.dv_xname, musycc_intr_print(id)));
        !          1335:
        !          1336:                        if (id & MUSYCC_INTD_ILOST)
        !          1337:                                ACCOOM_PRINTF(0, ("%s: interrupt lost\n",
        !          1338:                                    mc->mc_dev.dv_xname));
        !          1339:
        !          1340:                        switch (MUSYCC_INTD_EVENT(id)) {
        !          1341:                        case MUSYCC_INTEV_NONE:
        !          1342:                                break;
        !          1343:                        case MUSYCC_INTEV_SACK:
        !          1344:                                musycc_state_engine(mg, chan,
        !          1345:                                    mg->mg_sreq[mg->mg_sreqpend].event);
        !          1346:                                mg->mg_sreqpend =
        !          1347:                                    (mg->mg_sreqpend + 1) & MUSYCC_SREQMASK;
        !          1348:                                if (mg->mg_sreqpend != mg->mg_sreqprod)
        !          1349:                                        musycc_kick(mg);
        !          1350:                                break;
        !          1351:                        case MUSYCC_INTEV_EOM:
        !          1352:                        case MUSYCC_INTEV_EOB:
        !          1353:                                if (id & MUSYCC_INTD_DIR)
        !          1354:                                        musycc_txeom(mg, chan, 0);
        !          1355:                                else
        !          1356:                                        musycc_rxeom(mg, chan, 0);
        !          1357:                                break;
        !          1358:                        default:
        !          1359:                                ACCOOM_PRINTF(0, ("%s: unhandled event: %s\n",
        !          1360:                                    mc->mc_dev.dv_xname,
        !          1361:                                    musycc_intr_print(id)));
        !          1362:                                break;
        !          1363:                        }
        !          1364:                        switch (MUSYCC_INTD_ERROR(id)) {
        !          1365:                        case MUSYCC_INTERR_NONE:
        !          1366:                                break;
        !          1367:                        case MUSYCC_INTERR_COFA:
        !          1368:                                if ((id & MUSYCC_INTD_DIR) == 0)
        !          1369:                                        /* ignore COFA for RX side */
        !          1370:                                        break;
        !          1371:                                if (mg->mg_channels[chan]->cc_state !=
        !          1372:                                    CHAN_RUNNING) {
        !          1373:                                        /*
        !          1374:                                         * ignore COFA for TX side if card is
        !          1375:                                         * not running
        !          1376:                                         */
        !          1377:                                        break;
        !          1378:                                }
        !          1379:                                ACCOOM_PRINTF(0, ("%s: error: %s\n",
        !          1380:                                    mc->mc_dev.dv_xname,
        !          1381:                                    musycc_intr_print(id)));
        !          1382: #if 0
        !          1383:                                /* digest already transmitted packets */
        !          1384:                                musycc_txeom(mg, chan);
        !          1385:
        !          1386:                                /* adjust head pointer */
        !          1387:                                musycc_dump_dma(mg);
        !          1388:                                mg->mg_group->tx_headp[chan] =
        !          1389:                                    htole32(mg->mg_listmap->dm_segs[0].ds_addr +
        !          1390:                                    (caddr_t)mg->mg_dma_d[chan].tx_pend -
        !          1391:                                    mg->mg_listkva);
        !          1392:                                musycc_dump_dma(mg);
        !          1393:
        !          1394:                                musycc_sreq(mg, chan, MUSYCC_SREQ_SET(8),
        !          1395:                                    MUSYCC_SREQ_TX, CHAN_RUNNING);
        !          1396: #endif
        !          1397:                                break;
        !          1398:                        case MUSYCC_INTERR_BUFF:
        !          1399:                                /*
        !          1400:                                 * log event as this should not happen,
        !          1401:                                 * indicates PCI bus congestion
        !          1402:                                 */
        !          1403:                                log(LOG_ERR, "%s: internal FIFO %s\n",
        !          1404:                                    mg->mg_channels[chan]->cc_ifp->if_xname,
        !          1405:                                    id & MUSYCC_INTD_DIR ? "underflow" :
        !          1406:                                    "overflow");
        !          1407:
        !          1408:                                /* digest queue and restarting dma engine */
        !          1409:                                ifp = mg->mg_channels[chan]->cc_ifp;
        !          1410:                                if (id & MUSYCC_INTD_DIR) {
        !          1411:                                        ifp->if_oerrors++;
        !          1412:                                        musycc_txeom(mg, chan, 1);
        !          1413:                                } else {
        !          1414:                                        ifp->if_ierrors++;
        !          1415:                                        musycc_rxeom(mg, chan, 1);
        !          1416:                                }
        !          1417:                                break;
        !          1418:                        case MUSYCC_INTERR_ONR:
        !          1419:                                ACCOOM_PRINTF(0, ("%s: error: %s\n",
        !          1420:                                    mc->mc_dev.dv_xname,
        !          1421:                                    musycc_intr_print(id)));
        !          1422:
        !          1423:                                /* digest queue and restarting dma engine */
        !          1424:                                ifp = mg->mg_channels[chan]->cc_ifp;
        !          1425:                                if (id & MUSYCC_INTD_DIR) {
        !          1426:                                        ifp->if_oerrors++;
        !          1427:                                        musycc_txeom(mg, chan, 1);
        !          1428:                                } else {
        !          1429:                                        ifp->if_ierrors++;
        !          1430:                                        musycc_rxeom(mg, chan, 1);
        !          1431:                                }
        !          1432:                                break;
        !          1433:                        case MUSYCC_INTERR_OOF:
        !          1434:                                /* ignore */
        !          1435:                                break;
        !          1436:                        default:
        !          1437:                                ACCOOM_PRINTF(0, ("%s: unhandled error: %s\n",
        !          1438:                                    mc->mc_dev.dv_xname,
        !          1439:                                    musycc_intr_print(id)));
        !          1440:                                break;
        !          1441:                        }
        !          1442:                }
        !          1443:                bus_space_write_4(mc->mc_st, mc->mc_sh, MUSYCC_INTRSTATUS,
        !          1444:                    MUSYCC_NEXTINT_SET((n + i) % MUSYCC_INTLEN));
        !          1445:                bus_space_barrier(mc->mc_st, mc->mc_sh, MUSYCC_INTRSTATUS,
        !          1446:                    sizeof(u_int32_t), BUS_SPACE_BARRIER_WRITE);
        !          1447:                return (1);
        !          1448:        } else
        !          1449:                return (0);
        !          1450: }
        !          1451:
        !          1452: void
        !          1453: musycc_kick(struct musycc_group *mg)
        !          1454: {
        !          1455:
        !          1456:        bus_dmamap_sync(mg->mg_dmat, mg->mg_hdlc->mc_cfgmap,
        !          1457:            MUSYCC_GROUPBASE(mg->mg_gnum), sizeof(struct musycc_grpdesc),
        !          1458:            BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
        !          1459:
        !          1460:        ACCOOM_PRINTF(4, ("musycc_kick: group %d sreq[%d] req %08x\n",
        !          1461:            mg->mg_gnum, mg->mg_sreqpend, mg->mg_sreq[mg->mg_sreqpend].sreq));
        !          1462:
        !          1463:        bus_space_write_4(mg->mg_hdlc->mc_st, mg->mg_hdlc->mc_sh,
        !          1464:            MUSYCC_SERREQ(mg->mg_gnum), mg->mg_sreq[mg->mg_sreqpend].sreq);
        !          1465:        bus_space_barrier(mg->mg_hdlc->mc_st, mg->mg_hdlc->mc_sh,
        !          1466:            MUSYCC_SERREQ(mg->mg_gnum), sizeof(u_int32_t),
        !          1467:            BUS_SPACE_BARRIER_WRITE);
        !          1468: }
        !          1469:
        !          1470: void
        !          1471: musycc_sreq(struct musycc_group *mg, int channel, u_int32_t req, int dir,
        !          1472:     enum musycc_event event)
        !          1473: {
        !          1474: #define MUSYCC_SREQINC(x, y)   \
        !          1475:        do {                                                    \
        !          1476:                (x) = ((x) + 1) & MUSYCC_SREQMASK;              \
        !          1477:                if (x == y)                                     \
        !          1478:                        panic("%s: sreq queue overflow",        \
        !          1479:                            mg->mg_hdlc->mc_dev.dv_xname);      \
        !          1480:        } while (0)
        !          1481:
        !          1482:        struct timeval  tv;
        !          1483:        int             needskick;
        !          1484:
        !          1485:        needskick = (mg->mg_sreqpend == mg->mg_sreqprod);
        !          1486:        getmicrouptime(&tv);
        !          1487:
        !          1488:        ACCOOM_PRINTF(4, ("musycc_sreq: g# %d c# %d req %x dir %x\n",
        !          1489:            mg->mg_gnum, channel, req, dir));
        !          1490:
        !          1491:        if (dir & MUSYCC_SREQ_RX) {
        !          1492:                req &= ~MUSYCC_SREQ_TXDIR & ~MUSYCC_SREQ_MASK;
        !          1493:                req |= MUSYCC_SREQ_CHSET(channel);
        !          1494:                mg->mg_sreq[mg->mg_sreqprod].sreq = req;
        !          1495:                mg->mg_sreq[mg->mg_sreqprod].timeout = tv.tv_sec +
        !          1496:                    MUSYCC_SREQTIMEOUT;
        !          1497:                if (dir == MUSYCC_SREQ_RX)
        !          1498:                        mg->mg_sreq[mg->mg_sreqprod].event = event;
        !          1499:                else
        !          1500:                        mg->mg_sreq[mg->mg_sreqprod].event = EV_NULL;
        !          1501:                MUSYCC_SREQINC(mg->mg_sreqprod, mg->mg_sreqpend);
        !          1502:        }
        !          1503:        if (dir & MUSYCC_SREQ_TX) {
        !          1504:                req &= ~MUSYCC_SREQ_MASK;
        !          1505:                req |= MUSYCC_SREQ_TXDIR;
        !          1506:                req |= MUSYCC_SREQ_CHSET(channel);
        !          1507:                mg->mg_sreq[mg->mg_sreqprod].timeout = tv.tv_sec +
        !          1508:                    MUSYCC_SREQTIMEOUT;
        !          1509:                mg->mg_sreq[mg->mg_sreqprod].sreq = req;
        !          1510:                mg->mg_sreq[mg->mg_sreqprod].event = event;
        !          1511:                MUSYCC_SREQINC(mg->mg_sreqprod, mg->mg_sreqpend);
        !          1512:        }
        !          1513:
        !          1514:        if (needskick)
        !          1515:                musycc_kick(mg);
        !          1516:
        !          1517: #undef MUSYCC_SREQINC
        !          1518: }
        !          1519:
        !          1520: void
        !          1521: musycc_tick(struct channel_softc *cc)
        !          1522: {
        !          1523:        struct musycc_group     *mg = cc->cc_group;
        !          1524:        struct timeval           tv;
        !          1525:
        !          1526:        if (mg->mg_sreqpend == mg->mg_sreqprod)
        !          1527:                return;
        !          1528:
        !          1529:        getmicrouptime(&tv);
        !          1530:        if (mg->mg_sreq[mg->mg_sreqpend].timeout < tv.tv_sec) {
        !          1531:                log(LOG_ERR, "%s: service request timeout\n",
        !          1532:                    cc->cc_ifp->if_xname);
        !          1533:                mg->mg_sreqpend++;
        !          1534:                /* digest all timed out SREQ */
        !          1535:                while (mg->mg_sreq[mg->mg_sreqpend].timeout < tv.tv_sec &&
        !          1536:                    mg->mg_sreqpend != mg->mg_sreqprod)
        !          1537:                        mg->mg_sreqpend++;
        !          1538:
        !          1539:                if (mg->mg_sreqpend != mg->mg_sreqprod)
        !          1540:                        musycc_kick(mg);
        !          1541:        }
        !          1542: }
        !          1543:
        !          1544: /*
        !          1545:  * Extension Bus API
        !          1546:  */
        !          1547: int
        !          1548: ebus_intr(void *arg)
        !          1549: {
        !          1550:        struct musycc_softc     *sc = arg;
        !          1551:
        !          1552:        printf("%s: interrupt\n", sc->mc_dev.dv_xname);
        !          1553:        return (1);
        !          1554: }
        !          1555:
        !          1556: int
        !          1557: ebus_attach_device(struct ebus_dev *e, struct musycc_softc *mc,
        !          1558:     bus_size_t offset, bus_size_t size)
        !          1559: {
        !          1560:        struct musycc_softc     *ec = mc->mc_other;
        !          1561:
        !          1562:        e->base = offset << 2;
        !          1563:        e->size = size;
        !          1564:        e->st = ec->mc_st;
        !          1565:        return (bus_space_subregion(ec->mc_st, ec->mc_sh, offset << 2,
        !          1566:            size, &e->sh));
        !          1567: }
        !          1568:
        !          1569: u_int8_t
        !          1570: ebus_read(struct ebus_dev *e, bus_size_t offset)
        !          1571: {
        !          1572:        u_int8_t        value;
        !          1573:
        !          1574:        value = bus_space_read_1(e->st, e->sh, offset << 2);
        !          1575:        bus_space_barrier(e->st, e->sh, 0, e->size,
        !          1576:            BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
        !          1577:        return (value);
        !          1578: }
        !          1579:
        !          1580: void
        !          1581: ebus_write(struct ebus_dev *e, bus_size_t offset, u_int8_t value)
        !          1582: {
        !          1583:        bus_space_write_1(e->st, e->sh, offset << 2, value);
        !          1584:        bus_space_barrier(e->st, e->sh, 0, e->size,
        !          1585:            BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
        !          1586: }
        !          1587:
        !          1588: void
        !          1589: ebus_read_buf(struct ebus_dev *rom, bus_size_t offset, void *buf, size_t size)
        !          1590: {
        !          1591:        u_int8_t        *b = buf;
        !          1592:        size_t           i;
        !          1593:
        !          1594:        for (i = 0; i < size; i++)
        !          1595:                b[i] = ebus_read(rom, offset + i);
        !          1596: }
        !          1597:
        !          1598: void
        !          1599: ebus_set_led(struct channel_softc *cc, int on, u_int8_t value)
        !          1600: {
        !          1601:        struct musycc_softc     *sc = cc->cc_group->mg_hdlc->mc_other;
        !          1602:
        !          1603:        value &= MUSYCC_LED_MASK; /* don't write to other ports led */
        !          1604:        value <<= cc->cc_group->mg_gnum * 2;
        !          1605:
        !          1606:        if (on)
        !          1607:                sc->mc_ledstate |= value;
        !          1608:        else
        !          1609:                sc->mc_ledstate &= ~value;
        !          1610:
        !          1611:        bus_space_write_1(sc->mc_st, sc->mc_sh, sc->mc_ledbase,
        !          1612:            sc->mc_ledstate);
        !          1613:        bus_space_barrier(sc->mc_st, sc->mc_sh, sc->mc_ledbase, 1,
        !          1614:            BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
        !          1615: }
        !          1616:
        !          1617: /*
        !          1618:  * Channel API
        !          1619:  */
        !          1620:
        !          1621: void
        !          1622: musycc_attach_sppp(struct channel_softc *cc,
        !          1623:     int (*if_ioctl)(struct ifnet *, u_long, caddr_t))
        !          1624: {
        !          1625:        struct ifnet            *ifp;
        !          1626:
        !          1627:        ifp = &cc->cc_ppp.pp_if;
        !          1628:        cc->cc_ifp = ifp;
        !          1629:
        !          1630:        IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
        !          1631:        IFQ_SET_READY(&ifp->if_snd);
        !          1632:        ifp->if_mtu = PP_MTU;
        !          1633:        ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST /* | IFF_SIMPLEX */;
        !          1634:        cc->cc_ppp.pp_flags |= PP_CISCO;
        !          1635:        cc->cc_ppp.pp_flags |= PP_KEEPALIVE;
        !          1636:        cc->cc_ppp.pp_framebytes = 3;
        !          1637:
        !          1638:        ifp->if_ioctl = if_ioctl;
        !          1639:        ifp->if_start = musycc_start;
        !          1640:        ifp->if_watchdog = musycc_watchdog;
        !          1641:
        !          1642:        if_attach(ifp);
        !          1643:        if_alloc_sadl(ifp);
        !          1644:        sppp_attach(ifp);
        !          1645: #if NBPFILTER > 0
        !          1646:        bpfattach(&ifp->if_bpf, ifp, DLT_PPP, PPP_HEADER_LEN);
        !          1647: #endif /* NBPFILTER > 0 */
        !          1648:
        !          1649: }
        !          1650:
        !          1651: struct channel_softc *
        !          1652: musycc_channel_create(const char *name, u_int8_t locked)
        !          1653: {
        !          1654:        struct channel_softc    *cc;
        !          1655:
        !          1656:        cc = malloc(sizeof(*cc), M_DEVBUF, M_NOWAIT);
        !          1657:        if (!cc)
        !          1658:                return (NULL);
        !          1659:        bzero(cc, sizeof(*cc));
        !          1660:
        !          1661:        cc->cc_state = CHAN_FLOAT;
        !          1662:        cc->cc_locked = locked;
        !          1663:
        !          1664:        /* set default timeslot map for E1 */
        !          1665:        cc->cc_tslots = 0xfffffffe; /* all but timeslot 0 */
        !          1666:        strlcpy(cc->cc_ppp.pp_if.if_xname, name,
        !          1667:            sizeof(cc->cc_ppp.pp_if.if_xname));
        !          1668:
        !          1669:        cc->cc_ppp.pp_if.if_softc = cc;
        !          1670:
        !          1671:        return (cc);
        !          1672: }
        !          1673:
        !          1674: int
        !          1675: musycc_channel_attach(struct musycc_softc *mc, struct channel_softc *cc,
        !          1676:     struct device *dev, u_int8_t gnum)
        !          1677: {
        !          1678:        struct musycc_group     *mg;
        !          1679:        int                      i;
        !          1680:
        !          1681:        if (cc->cc_state != CHAN_FLOAT)
        !          1682:                return (-1);    /* already attached */
        !          1683:
        !          1684:        if (gnum >= mc->mc_ngroups) {
        !          1685:                ACCOOM_PRINTF(0, ("%s: %s tries to attach to nonexistent group",
        !          1686:                    mc->mc_dev.dv_xname, cc->cc_ifp->if_xname));
        !          1687:                return (-1);
        !          1688:        }
        !          1689:
        !          1690:        mg = &mc->mc_groups[gnum];
        !          1691:        for (i = 0; i < MUSYCC_NUMCHAN; i++)
        !          1692:                if (mg->mg_channels[i] == NULL) {
        !          1693:                        mg->mg_channels[i] = cc;
        !          1694:                        cc->cc_state = CHAN_IDLE;
        !          1695:                        cc->cc_group = mg;
        !          1696:                        cc->cc_channel = i;
        !          1697:                        cc->cc_parent = dev;
        !          1698:                        return (i);
        !          1699:                }
        !          1700:        return (-1);
        !          1701: }
        !          1702:
        !          1703: void
        !          1704: musycc_channel_detach(struct ifnet *ifp)
        !          1705: {
        !          1706:        struct channel_softc *cc = ifp->if_softc;
        !          1707:
        !          1708:        if (cc->cc_state != CHAN_FLOAT) {
        !          1709:                musycc_free_channel(cc->cc_group, cc->cc_channel);
        !          1710:                cc->cc_group->mg_channels[cc->cc_channel] = NULL;
        !          1711:        }
        !          1712:
        !          1713:        if_detach(ifp);
        !          1714: }
        !          1715:
        !          1716: #ifdef ACCOOM_DEBUG
        !          1717: const char     *musycc_events[] = {
        !          1718:        "NONE", "SACK", "EOB", "EOM", "EOP", "CHABT", "CHIC", "FREC",
        !          1719:        "SINC", "SDEC", "SFILT", "RFU", "RFU", "RFU", "RFU", "RFU"
        !          1720: };
        !          1721: const char     *musycc_errors[] = {
        !          1722:        "NONE", "BUFF", "COFA", "ONR", "PROT", "RFU", "RFU", "RFU",
        !          1723:        "OOF", "FCS", "ALIGN", "ABT", "LNG", "SHT", "SUERR", "PERR"
        !          1724: };
        !          1725: const char     *mu_proto[] = {
        !          1726:        "trans", "ss7", "hdlc16", "hdlc32", "rsvd4", "rsvd5", "rsvd6", "rsvd7"
        !          1727: };
        !          1728: const char     *mu_mode[] = {
        !          1729:        "t1", "e1", "2*e1", "4*e1", "n64", "rsvd5", "rsvd6", "rsvd7"
        !          1730: };
        !          1731:
        !          1732: char   musycc_intrbuf[48];
        !          1733:
        !          1734: char *
        !          1735: musycc_intr_print(u_int32_t id)
        !          1736: {
        !          1737:        snprintf(musycc_intrbuf, sizeof(musycc_intrbuf),
        !          1738:            "ev %s er %s grp %d chan %d dir %s",
        !          1739:            musycc_events[MUSYCC_INTD_EVENT(id)],
        !          1740:            musycc_errors[MUSYCC_INTD_ERROR(id)],
        !          1741:            MUSYCC_INTD_GRP(id), MUSYCC_INTD_CHAN(id),
        !          1742:            id & MUSYCC_INTD_DIR ? "T" : "R");
        !          1743:        return (musycc_intrbuf);
        !          1744: }
        !          1745:
        !          1746: void
        !          1747: musycc_dump_group(int level, struct musycc_group *mg)
        !          1748: {
        !          1749:        struct musycc_grpdesc   *md = mg->mg_group;
        !          1750:        u_int32_t                d;
        !          1751:        int                      i;
        !          1752:
        !          1753:        if (level > accoom_debug)
        !          1754:                return;
        !          1755:
        !          1756:        printf("%s: dumping group %d\n",
        !          1757:            mg->mg_hdlc->mc_dev.dv_xname, mg->mg_gnum);
        !          1758:        printf("===========================================================\n");
        !          1759:        printf("global conf: %08x\n", letoh32(md->global_conf));
        !          1760:        d = letoh32(md->group_conf);
        !          1761:        printf("group conf: [%08x] %s %s %s int %s%s inhib BSD %s%s poll %d\n",
        !          1762:            d,
        !          1763:            d & MUSYCC_GRCFG_TXENBL ? "TX" : "",
        !          1764:            d & MUSYCC_GRCFG_RXENBL ? "RX" : "",
        !          1765:            d & MUSYCC_GRCFG_SUBDSBL ? "" : "SUB",
        !          1766:            d & MUSYCC_GRCFG_MSKOOF ? "" : "O",
        !          1767:            d & MUSYCC_GRCFG_MSKCOFA ? "" : "C",
        !          1768:            d & MUSYCC_GRCFG_INHTBSD ? "TX" : "",
        !          1769:            d & MUSYCC_GRCFG_INHRBSD ? "RX" : "",
        !          1770:            (d & MUSYCC_GRCFG_POLL64) == MUSYCC_GRCFG_POLL64 ? 64 :
        !          1771:            d & MUSYCC_GRCFG_POLL32 ? 32 :
        !          1772:            d & MUSYCC_GRCFG_POLL16 ? 16 : 1);
        !          1773:        d = letoh32(md->port_conf);
        !          1774:        printf("port conf: [%08x] %s %s %s %s %s %s %s\n", d,
        !          1775:            mu_mode[d & MUSYCC_PORT_MODEMASK],
        !          1776:            d & MUSYCC_PORT_TDAT_EDGE ? "TXE" : "!TXE",
        !          1777:            d & MUSYCC_PORT_TSYNC_EDGE ? "TXS" : "!TXS",
        !          1778:            d & MUSYCC_PORT_RDAT_EDGE ? "RXE" : "!RXE",
        !          1779:            d & MUSYCC_PORT_RSYNC_EDGE ? "RXS" : "!RXS",
        !          1780:            d & MUSYCC_PORT_ROOF_EDGE ? "ROOF" : "!ROOF",
        !          1781:            d & MUSYCC_PORT_TRITX ? "!tri-state" : "tri-state");
        !          1782:        printf("message len 1: %d 2: %d\n",
        !          1783:            letoh32(md->msglen_conf) & MUSYCC_MAXFRM_MASK,
        !          1784:            (letoh32(md->msglen_conf) >> MUSYCC_MAXFRM2_SHIFT) &
        !          1785:            MUSYCC_MAXFRM_MASK);
        !          1786:        printf("interrupt queue %x len %d\n", letoh32(md->int_queuep),
        !          1787:            letoh32(md->int_queuelen));
        !          1788:        printf("memory protection %x\n", letoh32(md->memprot));
        !          1789:        printf("===========================================================\n");
        !          1790:        printf("Timeslot Map:TX\t\tRX\n");
        !          1791:        for (i = 0; i < 128; i++) {
        !          1792:                if (md->tx_tsmap[i] & MUSYCC_TSLOT_ENABLED)
        !          1793:                        printf("%d: %s%s%s[%02d]\t\t", i,
        !          1794:                            md->tx_tsmap[i] & MUSYCC_TSLOT_ENABLED ? "C" : " ",
        !          1795:                            md->tx_tsmap[i] & MUSYCC_TSLOT_SUB ? "S" : " ",
        !          1796:                            md->tx_tsmap[i] & MUSYCC_TSLOT_56K ? "*" : " ",
        !          1797:                            MUSYCC_TSLOT_CHAN(md->tx_tsmap[i]));
        !          1798:                else if (md->rx_tsmap[i] & MUSYCC_TSLOT_ENABLED)
        !          1799:                        printf("%d: \t\t", i);
        !          1800:                if (md->rx_tsmap[i] & MUSYCC_TSLOT_ENABLED)
        !          1801:                        printf("%s%s%s[%02d]\n",
        !          1802:                            md->rx_tsmap[i] & MUSYCC_TSLOT_ENABLED ? "C" : " ",
        !          1803:                            md->rx_tsmap[i] & MUSYCC_TSLOT_SUB ? "S" : " ",
        !          1804:                            md->rx_tsmap[i] & MUSYCC_TSLOT_56K ? "*" : " ",
        !          1805:                            MUSYCC_TSLOT_CHAN(md->rx_tsmap[i]));
        !          1806:                else
        !          1807:                        printf("\n");
        !          1808:        }
        !          1809:        printf("===========================================================\n");
        !          1810:        printf("Channel config:\nTX\t\t\tRX\n");
        !          1811:        for (i = 0; i < 32; i++)
        !          1812:                if (md->tx_cconf[i] != 0) {
        !          1813:                        d = letoh32(md->tx_cconf[i]);
        !          1814:                        printf("%s%s%s%s%s%s%s %s [%x]\t",
        !          1815:                            d & MUSYCC_CHAN_MSKBUFF ? "B" : " ",
        !          1816:                            d & MUSYCC_CHAN_MSKEOM ? "E" : " ",
        !          1817:                            d & MUSYCC_CHAN_MSKMSG ? "M" : " ",
        !          1818:                            d & MUSYCC_CHAN_MSKIDLE ? "I" : " ",
        !          1819:                            d & MUSYCC_CHAN_FCS ? "F" : "",
        !          1820:                            d & MUSYCC_CHAN_MAXLEN1 ? "1" : "",
        !          1821:                            d & MUSYCC_CHAN_MAXLEN2 ? "2" : "",
        !          1822:                            mu_proto[MUSYCC_CHAN_PROTO_GET(d)],
        !          1823:                            d);
        !          1824:                        d = letoh32(md->rx_cconf[i]);
        !          1825:                        printf("%s%s%s%s%s%s%s %s [%x]\n",
        !          1826:                            d & MUSYCC_CHAN_MSKBUFF ? "B" : " ",
        !          1827:                            d & MUSYCC_CHAN_MSKEOM ? "E" : " ",
        !          1828:                            d & MUSYCC_CHAN_MSKMSG ? "M" : " ",
        !          1829:                            d & MUSYCC_CHAN_MSKIDLE ? "I" : " ",
        !          1830:                            d & MUSYCC_CHAN_FCS ? "F" : "",
        !          1831:                            d & MUSYCC_CHAN_MAXLEN1 ? "1" : "",
        !          1832:                            d & MUSYCC_CHAN_MAXLEN2 ? "2" : "",
        !          1833:                            mu_proto[MUSYCC_CHAN_PROTO_GET(d)],
        !          1834:                            d);
        !          1835:                }
        !          1836:        printf("===========================================================\n");
        !          1837:        musycc_dump_dma(level, mg, 0);
        !          1838: }
        !          1839:
        !          1840: void
        !          1841: musycc_dump_desc(int level, struct musycc_group *mg)
        !          1842: {
        !          1843: #define READ4(x) \
        !          1844:        bus_space_read_4(mg->mg_hdlc->mc_st, mg->mg_hdlc->mc_sh, \
        !          1845:            MUSYCC_GROUPBASE(mg->mg_gnum) + (x))
        !          1846:        u_int32_t       w;
        !          1847:        u_int8_t        c1, c2;
        !          1848:        int             i;
        !          1849:
        !          1850:        if (level > accoom_debug)
        !          1851:                return;
        !          1852:
        !          1853:        printf("%s: dumping descriptor %d at %p kva %08x + %x dma %08x\n",
        !          1854:            mg->mg_hdlc->mc_dev.dv_xname, mg->mg_gnum, mg->mg_group,
        !          1855:            mg->mg_hdlc->mc_cfgmap->dm_segs[0].ds_addr,
        !          1856:            MUSYCC_GROUPBASE(mg->mg_gnum), READ4(0));
        !          1857:        printf("===========================================================\n");
        !          1858:        printf("global conf: %08x\n", READ4(MUSYCC_GLOBALCONF));
        !          1859:        w = READ4(0x060c);
        !          1860:        printf("group conf: [%08x] %s %s %s int %s%s inhib BSD %s%s poll %d\n",
        !          1861:            w, w & MUSYCC_GRCFG_TXENBL ? "TX" : "",
        !          1862:            w & MUSYCC_GRCFG_RXENBL ? "RX" : "",
        !          1863:            w & MUSYCC_GRCFG_SUBDSBL ? "" : "SUB",
        !          1864:            w & MUSYCC_GRCFG_MSKOOF ? "" : "O",
        !          1865:            w & MUSYCC_GRCFG_MSKCOFA ? "" : "C",
        !          1866:            w & MUSYCC_GRCFG_INHTBSD ? "TX" : "",
        !          1867:            w & MUSYCC_GRCFG_INHRBSD ? "RX" : "",
        !          1868:            (w & MUSYCC_GRCFG_POLL64) == MUSYCC_GRCFG_POLL64 ? 64 :
        !          1869:            w & MUSYCC_GRCFG_POLL32 ? 32 :
        !          1870:            w & MUSYCC_GRCFG_POLL16 ? 16 : 1);
        !          1871:        w = READ4(0x0618);
        !          1872:        printf("port conf: [%08x] %s %s %s %s %s %s %s\n", w,
        !          1873:            mu_mode[w & MUSYCC_PORT_MODEMASK],
        !          1874:            w & MUSYCC_PORT_TDAT_EDGE ? "TXE" : "!TXE",
        !          1875:            w & MUSYCC_PORT_TSYNC_EDGE ? "TXS" : "!TXS",
        !          1876:            w & MUSYCC_PORT_RDAT_EDGE ? "RXE" : "!RXE",
        !          1877:            w & MUSYCC_PORT_RSYNC_EDGE ? "RXS" : "!RXS",
        !          1878:            w & MUSYCC_PORT_ROOF_EDGE ? "ROOF" : "!ROOF",
        !          1879:            w & MUSYCC_PORT_TRITX ? "!tri-state" : "tri-state");
        !          1880:        w = READ4(0x0614);
        !          1881:        printf("message len 1: %d 2: %d\n",
        !          1882:            w & MUSYCC_MAXFRM_MASK,
        !          1883:            (w >> MUSYCC_MAXFRM2_SHIFT) & MUSYCC_MAXFRM_MASK);
        !          1884:        printf("interrupt queue %x len %d\n", READ4(0x0604), READ4(0x0608));
        !          1885:        printf("memory protection %x\n", READ4(0x0610));
        !          1886:        printf("===========================================================\n");
        !          1887:        printf("Timeslot Map:TX\t\tRX\n");
        !          1888:        for (i = 0; i < 128; i++) {
        !          1889:                c1 = bus_space_read_1(mg->mg_hdlc->mc_st, mg->mg_hdlc->mc_sh,
        !          1890:                    MUSYCC_GROUPBASE(mg->mg_gnum) + 0x0200 + i);
        !          1891:                c2 = bus_space_read_1(mg->mg_hdlc->mc_st, mg->mg_hdlc->mc_sh,
        !          1892:                    MUSYCC_GROUPBASE(mg->mg_gnum) + 0x0400 + i);
        !          1893:                if (c1 & MUSYCC_TSLOT_ENABLED)
        !          1894:                        printf("%d: %s%s%s[%02d]\t\t", i,
        !          1895:                            c1 & MUSYCC_TSLOT_ENABLED ? "C" : " ",
        !          1896:                            c1 & MUSYCC_TSLOT_SUB ? "S" : " ",
        !          1897:                            c1 & MUSYCC_TSLOT_56K ? "*" : " ",
        !          1898:                            MUSYCC_TSLOT_CHAN(c1));
        !          1899:                else if (c2 & MUSYCC_TSLOT_ENABLED)
        !          1900:                        printf("%d: \t\t", i);
        !          1901:                if (c2 & MUSYCC_TSLOT_ENABLED)
        !          1902:                        printf("%s%s%s[%02d]\n",
        !          1903:                            c2 & MUSYCC_TSLOT_ENABLED ? "C" : " ",
        !          1904:                            c2 & MUSYCC_TSLOT_SUB ? "S" : " ",
        !          1905:                            c2 & MUSYCC_TSLOT_56K ? "*" : " ",
        !          1906:                            MUSYCC_TSLOT_CHAN(c2));
        !          1907:                else
        !          1908:                        printf("\n");
        !          1909:        }
        !          1910:        printf("===========================================================\n");
        !          1911:        printf("Channel config:\nTX\t\t\t\tRX\n");
        !          1912:        for (i = 0; i < 32; i++) {
        !          1913:                w = READ4(0x0380 + i * 4);
        !          1914:                if (w != 0) {
        !          1915:                        printf("%s%s%s%s%s%s%s %s [%08x]\t",
        !          1916:                            w & MUSYCC_CHAN_MSKBUFF ? "B" : " ",
        !          1917:                            w & MUSYCC_CHAN_MSKEOM ? "E" : " ",
        !          1918:                            w & MUSYCC_CHAN_MSKMSG ? "M" : " ",
        !          1919:                            w & MUSYCC_CHAN_MSKIDLE ? "I" : " ",
        !          1920:                            w & MUSYCC_CHAN_FCS ? "F" : "",
        !          1921:                            w & MUSYCC_CHAN_MAXLEN1 ? "1" : "",
        !          1922:                            w & MUSYCC_CHAN_MAXLEN2 ? "2" : "",
        !          1923:                            mu_proto[MUSYCC_CHAN_PROTO_GET(w)],
        !          1924:                            w);
        !          1925:                        w = READ4(0x0580 + i * 4);
        !          1926:                        printf("%s%s%s%s%s%s%s %s [%08x]\n",
        !          1927:                            w & MUSYCC_CHAN_MSKBUFF ? "B" : " ",
        !          1928:                            w & MUSYCC_CHAN_MSKEOM ? "E" : " ",
        !          1929:                            w & MUSYCC_CHAN_MSKMSG ? "M" : " ",
        !          1930:                            w & MUSYCC_CHAN_MSKIDLE ? "I" : " ",
        !          1931:                            w & MUSYCC_CHAN_FCS ? "F" : "",
        !          1932:                            w & MUSYCC_CHAN_MAXLEN1 ? "1" : "",
        !          1933:                            w & MUSYCC_CHAN_MAXLEN2 ? "2" : "",
        !          1934:                            mu_proto[MUSYCC_CHAN_PROTO_GET(w)],
        !          1935:                            w);
        !          1936:                }
        !          1937:        }
        !          1938:        printf("===========================================================\n");
        !          1939:        musycc_dump_dma(level, mg, 0);
        !          1940:
        !          1941: }
        !          1942:
        !          1943: void
        !          1944: musycc_dump_dma(int level, struct musycc_group *mg, int dir)
        !          1945: {
        !          1946:        struct musycc_grpdesc   *md = mg->mg_group;
        !          1947:        struct dma_desc         *dd;
        !          1948:        bus_addr_t               base, addr;
        !          1949:        int                      i;
        !          1950:
        !          1951:        if (level > accoom_debug)
        !          1952:                return;
        !          1953:
        !          1954:        printf("DMA Pointers:\n%8s %8s %8s %8s\n",
        !          1955:            "tx head", "tx msg", "rx head", "rx msg");
        !          1956:        for (i = 0; i < 32; i++) {
        !          1957:                if (md->tx_headp[i] == 0 && md->rx_headp[i] == 0)
        !          1958:                        continue;
        !          1959:                printf("%08x %08x %08x %08x\n",
        !          1960:                    md->tx_headp[i], md->tx_msgp[i],
        !          1961:                    md->rx_headp[i], md->rx_msgp[i]);
        !          1962:        }
        !          1963:
        !          1964:        base = mg->mg_listmap->dm_segs[0].ds_addr;
        !          1965:        for (i = 0; dir & MUSYCC_SREQ_TX && i < 32; i++) {
        !          1966:                if (md->tx_headp[i] == 0)
        !          1967:                        continue;
        !          1968:
        !          1969:                printf("==================================================\n");
        !          1970:                printf("TX DMA Ring for channel %d\n", i);
        !          1971:                printf("pend: %p cur: %p cnt: %d use: %d pkgs: %d\n",
        !          1972:                    mg->mg_dma_d[i].tx_pend, mg->mg_dma_d[i].tx_cur,
        !          1973:                    mg->mg_dma_d[i].tx_cnt, mg->mg_dma_d[i].tx_use,
        !          1974:                    mg->mg_dma_d[i].tx_pkts);
        !          1975:                printf("  %10s %8s %8s %8s %8s %10s\n",
        !          1976:                    "addr", "paddr", "next", "status", "data", "mbuf");
        !          1977:                dd = mg->mg_dma_d[i].tx_pend;
        !          1978:                do {
        !          1979:                        addr = htole32(base + ((caddr_t)dd - mg->mg_listkva));
        !          1980:                        printf("%s %p %08x %08x %08x %08x %p\n",
        !          1981:                            dd == mg->mg_dma_d[i].tx_pend ? ">" :
        !          1982:                            dd == mg->mg_dma_d[i].tx_cur ? "*" : " ",
        !          1983:                            dd, addr, dd->next, dd->status,
        !          1984:                            dd->data, dd->mbuf);
        !          1985:                        dd = dd->nextdesc;
        !          1986:                } while (dd != mg->mg_dma_d[i].tx_pend);
        !          1987:        }
        !          1988:        for (i = 0; dir & MUSYCC_SREQ_RX && i < 32; i++) {
        !          1989:                if (md->rx_headp[i] == 0)
        !          1990:                        continue;
        !          1991:
        !          1992:                printf("==================================================\n");
        !          1993:                printf("RX DMA Ring for channel %d\n", i);
        !          1994:                printf("prod: %p cnt: %d\n",
        !          1995:                    mg->mg_dma_d[i].rx_prod, mg->mg_dma_d[i].rx_cnt);
        !          1996:                printf("  %8s %8s %8s %8s %10s\n",
        !          1997:                    "addr", "paddr", "next", "status", "data", "mbuf");
        !          1998:                dd = mg->mg_dma_d[i].rx_prod;
        !          1999:                do {
        !          2000:                        addr = htole32(base + ((caddr_t)dd - mg->mg_listkva));
        !          2001:                        printf("%p %08x %08x %08x %08x %p\n", dd, addr,
        !          2002:                            dd->next, dd->status, dd->data, dd->mbuf);
        !          2003:                        dd = dd->nextdesc;
        !          2004:                } while (dd != mg->mg_dma_d[i].rx_prod);
        !          2005:        }
        !          2006: }
        !          2007: #endif

CVSweb