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