Annotation of sys/dev/tc/if_le_ioasic.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_le_ioasic.c,v 1.13 2007/06/18 21:24:43 jasper Exp $ */
! 2: /* $NetBSD: if_le_ioasic.c,v 1.18 2001/11/13 06:26:10 lukem Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1996 Carnegie-Mellon University.
! 6: * All rights reserved.
! 7: *
! 8: * Author: Chris G. Demetriou
! 9: *
! 10: * Permission to use, copy, modify and distribute this software and
! 11: * its documentation is hereby granted, provided that both the copyright
! 12: * notice and this permission notice appear in all copies of the
! 13: * software, derivative works or modified versions, and any portions
! 14: * thereof, and that both notices appear in supporting documentation.
! 15: *
! 16: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
! 17: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
! 18: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
! 19: *
! 20: * Carnegie Mellon requests users of this software to return to
! 21: *
! 22: * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
! 23: * School of Computer Science
! 24: * Carnegie Mellon University
! 25: * Pittsburgh PA 15213-3890
! 26: *
! 27: * any improvements or extensions that they make and grant Carnegie the
! 28: * rights to redistribute these changes.
! 29: */
! 30:
! 31: /*
! 32: * LANCE on DEC IOCTL ASIC.
! 33: */
! 34:
! 35: #include <sys/param.h>
! 36: #include <sys/systm.h>
! 37: #include <sys/mbuf.h>
! 38: #include <sys/syslog.h>
! 39: #include <sys/socket.h>
! 40: #include <sys/device.h>
! 41:
! 42: #include <net/if.h>
! 43: #include <net/if_media.h>
! 44:
! 45: #ifdef INET
! 46: #include <netinet/in.h>
! 47: #include <netinet/if_ether.h>
! 48: #endif
! 49:
! 50: #include <dev/ic/am7990reg.h>
! 51: #include <dev/ic/am7990var.h>
! 52:
! 53: #include <dev/tc/if_levar.h>
! 54: #include <dev/tc/tcvar.h>
! 55: #include <dev/tc/ioasicreg.h>
! 56: #include <dev/tc/ioasicvar.h>
! 57:
! 58: struct le_ioasic_softc {
! 59: struct am7990_softc sc_am7990; /* glue to MI code */
! 60: struct lereg1 *sc_r1; /* LANCE registers */
! 61: /* XXX must match with le_softc of if_levar.h XXX */
! 62:
! 63: bus_dma_tag_t sc_dmat; /* bus dma tag */
! 64: bus_dmamap_t sc_dmamap; /* bus dmamap */
! 65: };
! 66:
! 67: int le_ioasic_match(struct device *, void *, void *);
! 68: void le_ioasic_attach(struct device *, struct device *, void *);
! 69:
! 70: struct cfattach le_ioasic_ca = {
! 71: sizeof(struct le_softc), le_ioasic_match, le_ioasic_attach
! 72: };
! 73:
! 74: void le_ioasic_copytobuf_gap2(struct am7990_softc *, void *,
! 75: int, int);
! 76: void le_ioasic_copyfrombuf_gap2(struct am7990_softc *, void *,
! 77: int, int);
! 78: void le_ioasic_copytobuf_gap16(struct am7990_softc *, void *,
! 79: int, int);
! 80: void le_ioasic_copyfrombuf_gap16(struct am7990_softc *, void *,
! 81: int, int);
! 82: void le_ioasic_zerobuf_gap16(struct am7990_softc *, int, int);
! 83:
! 84: int
! 85: le_ioasic_match(struct device *parent, void *match, void *aux)
! 86: {
! 87: struct ioasicdev_attach_args *d = aux;
! 88:
! 89: if (strncmp("PMAD-BA ", d->iada_modname, TC_ROM_LLEN) != 0)
! 90: return 0;
! 91:
! 92: return 1;
! 93: }
! 94:
! 95: /* IOASIC LANCE DMA needs 128KB boundary aligned 128KB chunk */
! 96: #define LE_IOASIC_MEMSIZE (128*1024)
! 97: #define LE_IOASIC_MEMALIGN (128*1024)
! 98:
! 99: void
! 100: le_ioasic_attach(struct device *parent, struct device *self, void *aux)
! 101: {
! 102: struct le_ioasic_softc *sc = (void *)self;
! 103: struct ioasicdev_attach_args *d = aux;
! 104: struct am7990_softc *le = &sc->sc_am7990;
! 105: bus_space_tag_t ioasic_bst;
! 106: bus_space_handle_t ioasic_bsh;
! 107: bus_dma_tag_t dmat;
! 108: bus_dma_segment_t seg;
! 109: tc_addr_t tca;
! 110: u_int32_t ssr;
! 111: int rseg;
! 112: caddr_t le_iomem;
! 113:
! 114: ioasic_bst = ((struct ioasic_softc *)parent)->sc_bst;
! 115: ioasic_bsh = ((struct ioasic_softc *)parent)->sc_bsh;
! 116: dmat = sc->sc_dmat = ((struct ioasic_softc *)parent)->sc_dmat;
! 117: /*
! 118: * Allocate a DMA area for the chip.
! 119: */
! 120: if (bus_dmamem_alloc(dmat, LE_IOASIC_MEMSIZE, LE_IOASIC_MEMALIGN,
! 121: 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
! 122: printf("can't allocate DMA area for LANCE\n");
! 123: return;
! 124: }
! 125: if (bus_dmamem_map(dmat, &seg, rseg, LE_IOASIC_MEMSIZE,
! 126: &le_iomem, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) {
! 127: printf("can't map DMA area for LANCE\n");
! 128: bus_dmamem_free(dmat, &seg, rseg);
! 129: return;
! 130: }
! 131: /*
! 132: * Create and load the DMA map for the DMA area.
! 133: */
! 134: if (bus_dmamap_create(dmat, LE_IOASIC_MEMSIZE, 1,
! 135: LE_IOASIC_MEMSIZE, 0, BUS_DMA_NOWAIT, &sc->sc_dmamap)) {
! 136: printf("can't create DMA map\n");
! 137: goto bad;
! 138: }
! 139: if (bus_dmamap_load(dmat, sc->sc_dmamap,
! 140: le_iomem, LE_IOASIC_MEMSIZE, NULL, BUS_DMA_NOWAIT)) {
! 141: printf("can't load DMA map\n");
! 142: goto bad;
! 143: }
! 144: /*
! 145: * Bind 128KB buffer with IOASIC DMA.
! 146: */
! 147: tca = IOASIC_DMA_ADDR(sc->sc_dmamap->dm_segs[0].ds_addr);
! 148: bus_space_write_4(ioasic_bst, ioasic_bsh, IOASIC_LANCE_DMAPTR, tca);
! 149: ssr = bus_space_read_4(ioasic_bst, ioasic_bsh, IOASIC_CSR);
! 150: ssr |= IOASIC_CSR_DMAEN_LANCE;
! 151: bus_space_write_4(ioasic_bst, ioasic_bsh, IOASIC_CSR, ssr);
! 152:
! 153: sc->sc_r1 = (struct lereg1 *)
! 154: TC_DENSE_TO_SPARSE(TC_PHYS_TO_UNCACHED(d->iada_addr));
! 155: le->sc_mem = (void *)TC_PHYS_TO_UNCACHED(le_iomem);
! 156: le->sc_copytodesc = le_ioasic_copytobuf_gap2;
! 157: le->sc_copyfromdesc = le_ioasic_copyfrombuf_gap2;
! 158: le->sc_copytobuf = le_ioasic_copytobuf_gap16;
! 159: le->sc_copyfrombuf = le_ioasic_copyfrombuf_gap16;
! 160: le->sc_zerobuf = le_ioasic_zerobuf_gap16;
! 161:
! 162: dec_le_common_attach(&sc->sc_am7990,
! 163: (u_char *)((struct ioasic_softc *)parent)->sc_base
! 164: + IOASIC_SLOT_2_START);
! 165:
! 166: ioasic_intr_establish(parent, d->iada_cookie, TC_IPL_NET,
! 167: am7990_intr, sc);
! 168: return;
! 169:
! 170: bad:
! 171: bus_dmamem_unmap(dmat, le_iomem, LE_IOASIC_MEMSIZE);
! 172: bus_dmamem_free(dmat, &seg, rseg);
! 173: }
! 174:
! 175: /*
! 176: * Special memory access functions needed by ioasic-attached LANCE
! 177: * chips.
! 178: */
! 179:
! 180: /*
! 181: * gap2: two bytes of data followed by two bytes of pad.
! 182: *
! 183: * Buffers must be 4-byte aligned. The code doesn't worry about
! 184: * doing an extra byte.
! 185: */
! 186:
! 187: void
! 188: le_ioasic_copytobuf_gap2(struct am7990_softc *sc, void *fromv,
! 189: int boff, int len)
! 190: {
! 191: volatile caddr_t buf = sc->sc_mem;
! 192: caddr_t from = fromv;
! 193: volatile u_int16_t *bptr;
! 194:
! 195: if (boff & 0x1) {
! 196: /* handle unaligned first byte */
! 197: bptr = ((volatile u_int16_t *)buf) + (boff - 1);
! 198: *bptr = (*from++ << 8) | (*bptr & 0xff);
! 199: bptr += 2;
! 200: len--;
! 201: } else
! 202: bptr = ((volatile u_int16_t *)buf) + boff;
! 203: while (len > 1) {
! 204: *bptr = (from[1] << 8) | (from[0] & 0xff);
! 205: bptr += 2;
! 206: from += 2;
! 207: len -= 2;
! 208: }
! 209: if (len == 1)
! 210: *bptr = (u_int16_t)*from;
! 211: }
! 212:
! 213: void
! 214: le_ioasic_copyfrombuf_gap2(struct am7990_softc *sc, void *tov,
! 215: int boff, int len)
! 216: {
! 217: volatile caddr_t buf = sc->sc_mem;
! 218: caddr_t to = tov;
! 219: volatile u_int16_t *bptr;
! 220: u_int16_t tmp;
! 221:
! 222: if (boff & 0x1) {
! 223: /* handle unaligned first byte */
! 224: bptr = ((volatile u_int16_t *)buf) + (boff - 1);
! 225: *to++ = (*bptr >> 8) & 0xff;
! 226: bptr += 2;
! 227: len--;
! 228: } else
! 229: bptr = ((volatile u_int16_t *)buf) + boff;
! 230: while (len > 1) {
! 231: tmp = *bptr;
! 232: *to++ = tmp & 0xff;
! 233: *to++ = (tmp >> 8) & 0xff;
! 234: bptr += 2;
! 235: len -= 2;
! 236: }
! 237: if (len == 1)
! 238: *to = *bptr & 0xff;
! 239: }
! 240:
! 241: /*
! 242: * gap16: 16 bytes of data followed by 16 bytes of pad.
! 243: *
! 244: * Buffers must be 32-byte aligned.
! 245: */
! 246:
! 247: void
! 248: le_ioasic_copytobuf_gap16(struct am7990_softc *sc, void *fromv,
! 249: int boff, int len)
! 250: {
! 251: volatile caddr_t buf = sc->sc_mem;
! 252: caddr_t from = fromv;
! 253: caddr_t bptr;
! 254:
! 255: bptr = buf + ((boff << 1) & ~0x1f);
! 256: boff &= 0xf;
! 257:
! 258: /*
! 259: * Dispose of boff so destination of subsequent copies is
! 260: * 16-byte aligned.
! 261: */
! 262: if (boff) {
! 263: int xfer;
! 264: xfer = min(len, 16 - boff);
! 265: bcopy(from, bptr + boff, xfer);
! 266: from += xfer;
! 267: bptr += 32;
! 268: len -= xfer;
! 269: }
! 270:
! 271: /* Destination of copies is now 16-byte aligned. */
! 272: if (len >= 16)
! 273: switch ((u_long)from & (sizeof(u_int32_t) -1)) {
! 274: case 2:
! 275: /* Ethernet headers make this the dominant case. */
! 276: do {
! 277: u_int32_t *dst = (u_int32_t*)bptr;
! 278: u_int16_t t0;
! 279: u_int32_t t1, t2, t3, t4;
! 280:
! 281: /* read from odd-16-bit-aligned, cached src */
! 282: t0 = *(u_int16_t*)from;
! 283: t1 = *(u_int32_t*)(from+2);
! 284: t2 = *(u_int32_t*)(from+6);
! 285: t3 = *(u_int32_t*)(from+10);
! 286: t4 = *(u_int16_t*)(from+14);
! 287:
! 288: /* DMA buffer is uncached on mips */
! 289: dst[0] = t0 | (t1 << 16);
! 290: dst[1] = (t1 >> 16) | (t2 << 16);
! 291: dst[2] = (t2 >> 16) | (t3 << 16);
! 292: dst[3] = (t3 >> 16) | (t4 << 16);
! 293:
! 294: from += 16;
! 295: bptr += 32;
! 296: len -= 16;
! 297: } while (len >= 16);
! 298: break;
! 299:
! 300: case 0:
! 301: do {
! 302: u_int32_t *src = (u_int32_t*)from;
! 303: u_int32_t *dst = (u_int32_t*)bptr;
! 304: u_int32_t t0, t1, t2, t3;
! 305:
! 306: t0 = src[0]; t1 = src[1]; t2 = src[2]; t3 = src[3];
! 307: dst[0] = t0; dst[1] = t1; dst[2] = t2; dst[3] = t3;
! 308:
! 309: from += 16;
! 310: bptr += 32;
! 311: len -= 16;
! 312: } while (len >= 16);
! 313: break;
! 314:
! 315: default:
! 316: /* Does odd-aligned case ever happen? */
! 317: do {
! 318: bcopy(from, bptr, 16);
! 319: from += 16;
! 320: bptr += 32;
! 321: len -= 16;
! 322: } while (len >= 16);
! 323: break;
! 324: }
! 325: if (len)
! 326: bcopy(from, bptr, len);
! 327: }
! 328:
! 329: void
! 330: le_ioasic_copyfrombuf_gap16(struct am7990_softc *sc, void *tov,
! 331: int boff, int len)
! 332: {
! 333: volatile caddr_t buf = sc->sc_mem;
! 334: caddr_t to = tov;
! 335: caddr_t bptr;
! 336:
! 337: bptr = buf + ((boff << 1) & ~0x1f);
! 338: boff &= 0xf;
! 339:
! 340: /* Dispose of boff. source of copy is subsequently 16-byte aligned. */
! 341: if (boff) {
! 342: int xfer;
! 343: xfer = min(len, 16 - boff);
! 344: bcopy(bptr+boff, to, xfer);
! 345: to += xfer;
! 346: bptr += 32;
! 347: len -= xfer;
! 348: }
! 349: if (len >= 16)
! 350: switch ((u_long)to & (sizeof(u_int32_t) -1)) {
! 351: case 2:
! 352: /*
! 353: * to is aligned to an odd 16-bit boundary. Ethernet headers
! 354: * make this the dominant case (98% or more).
! 355: */
! 356: do {
! 357: u_int32_t *src = (u_int32_t*)bptr;
! 358: u_int32_t t0, t1, t2, t3;
! 359:
! 360: /* read from uncached aligned DMA buf */
! 361: t0 = src[0]; t1 = src[1]; t2 = src[2]; t3 = src[3];
! 362:
! 363: /* write to odd-16-bit-word aligned dst */
! 364: *(u_int16_t *) (to+0) = (u_short) t0;
! 365: *(u_int32_t *) (to+2) = (t0 >> 16) | (t1 << 16);
! 366: *(u_int32_t *) (to+6) = (t1 >> 16) | (t2 << 16);
! 367: *(u_int32_t *) (to+10) = (t2 >> 16) | (t3 << 16);
! 368: *(u_int16_t *) (to+14) = (t3 >> 16);
! 369: bptr += 32;
! 370: to += 16;
! 371: len -= 16;
! 372: } while (len > 16);
! 373: break;
! 374: case 0:
! 375: /* 32-bit aligned aligned copy. Rare. */
! 376: do {
! 377: u_int32_t *src = (u_int32_t*)bptr;
! 378: u_int32_t *dst = (u_int32_t*)to;
! 379: u_int32_t t0, t1, t2, t3;
! 380:
! 381: t0 = src[0]; t1 = src[1]; t2 = src[2]; t3 = src[3];
! 382: dst[0] = t0; dst[1] = t1; dst[2] = t2; dst[3] = t3;
! 383: to += 16;
! 384: bptr += 32;
! 385: len -= 16;
! 386: } while (len > 16);
! 387: break;
! 388:
! 389: /* XXX Does odd-byte-aligned case ever happen? */
! 390: default:
! 391: do {
! 392: bcopy(bptr, to, 16);
! 393: to += 16;
! 394: bptr += 32;
! 395: len -= 16;
! 396: } while (len > 16);
! 397: break;
! 398: }
! 399: if (len)
! 400: bcopy(bptr, to, len);
! 401: }
! 402:
! 403: void
! 404: le_ioasic_zerobuf_gap16(struct am7990_softc *sc, int boff, int len)
! 405: {
! 406: volatile caddr_t buf = sc->sc_mem;
! 407: caddr_t bptr;
! 408: int xfer;
! 409:
! 410: bptr = buf + ((boff << 1) & ~0x1f);
! 411: boff &= 0xf;
! 412: xfer = min(len, 16 - boff);
! 413: while (len > 0) {
! 414: bzero(bptr + boff, xfer);
! 415: bptr += 32;
! 416: boff = 0;
! 417: len -= xfer;
! 418: xfer = min(len, 16);
! 419: }
! 420: }
CVSweb