Annotation of sys/dev/isa/if_ec.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: if_ec.c,v 1.10 2006/10/20 17:02:24 brad Exp $ */
! 2: /* $NetBSD: if_ec.c,v 1.9 1998/07/05 06:49:12 jonathan Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
! 10: * NASA Ames Research Center.
! 11: *
! 12: * Redistribution and use in source and binary forms, with or without
! 13: * modification, are permitted provided that the following conditions
! 14: * are met:
! 15: * 1. Redistributions of source code must retain the above copyright
! 16: * notice, this list of conditions and the following disclaimer.
! 17: * 2. Redistributions in binary form must reproduce the above copyright
! 18: * notice, this list of conditions and the following disclaimer in the
! 19: * documentation and/or other materials provided with the distribution.
! 20: * 3. All advertising materials mentioning features or use of this software
! 21: * must display the following acknowledgement:
! 22: * This product includes software developed by the NetBSD
! 23: * Foundation, Inc. and its contributors.
! 24: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 25: * contributors may be used to endorse or promote products derived
! 26: * from this software without specific prior written permission.
! 27: *
! 28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 38: * POSSIBILITY OF SUCH DAMAGE.
! 39: */
! 40:
! 41: /*
! 42: * Device driver for National Semiconductor DS8390/WD83C690 based ethernet
! 43: * adapters.
! 44: *
! 45: * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved.
! 46: *
! 47: * Copyright (C) 1993, David Greenman. This software may be used, modified,
! 48: * copied, distributed, and sold, in both source and binary form provided that
! 49: * the above copyright and these terms are retained. Under no circumstances is
! 50: * the author responsible for the proper functioning of this software, nor does
! 51: * the author assume any responsibility for damages incurred with its use.
! 52: */
! 53:
! 54: /*
! 55: * Device driver for the 3Com Etherlink II (3c503).
! 56: */
! 57:
! 58: #include "bpfilter.h"
! 59:
! 60: #include <sys/param.h>
! 61: #include <sys/systm.h>
! 62: #include <sys/device.h>
! 63: #include <sys/socket.h>
! 64: #include <sys/mbuf.h>
! 65: #include <sys/syslog.h>
! 66:
! 67: #include <net/if.h>
! 68: #include <net/if_dl.h>
! 69: #include <net/if_types.h>
! 70: #include <net/if_media.h>
! 71:
! 72: #ifdef INET
! 73: #include <netinet/in.h>
! 74: #include <netinet/in_systm.h>
! 75: #include <netinet/in_var.h>
! 76: #include <netinet/ip.h>
! 77: #include <netinet/if_ether.h>
! 78: #endif
! 79:
! 80: #if NBPFILTER > 0
! 81: #include <net/bpf.h>
! 82: #endif
! 83:
! 84: #include <machine/bus.h>
! 85: #include <machine/intr.h>
! 86:
! 87: #include <dev/isa/isareg.h>
! 88: #include <dev/isa/isavar.h>
! 89:
! 90: #include <dev/ic/dp8390reg.h>
! 91: #include <dev/ic/dp8390var.h>
! 92:
! 93: #include <dev/isa/if_ecreg.h>
! 94:
! 95: struct ec_softc {
! 96: struct dp8390_softc sc_dp8390;
! 97:
! 98: bus_space_tag_t sc_asict; /* space tag for ASIC */
! 99: bus_space_handle_t sc_asich; /* space handle for ASIC */
! 100:
! 101: int sc_16bitp; /* are we 16 bit? */
! 102:
! 103: void *sc_ih; /* interrupt handle */
! 104: };
! 105:
! 106: int ec_probe(struct device *, void *, void *);
! 107: void ec_attach(struct device *, struct device *, void *);
! 108:
! 109: struct cfattach ec_ca = {
! 110: sizeof(struct ec_softc), ec_probe, ec_attach
! 111: };
! 112:
! 113: int ec_set_media(struct ec_softc *, int);
! 114:
! 115: void ec_media_init(struct dp8390_softc *);
! 116:
! 117: int ec_mediachange(struct dp8390_softc *);
! 118: void ec_mediastatus(struct dp8390_softc *, struct ifmediareq *);
! 119:
! 120: void ec_init_card(struct dp8390_softc *);
! 121: int ec_write_mbuf(struct dp8390_softc *, struct mbuf *, int);
! 122: int ec_ring_copy(struct dp8390_softc *, int, caddr_t, u_short);
! 123: void ec_read_hdr(struct dp8390_softc *, int, struct dp8390_ring *);
! 124: int ec_fake_test_mem(struct dp8390_softc *);
! 125: int ec_test_mem(struct dp8390_softc *);
! 126:
! 127: __inline void ec_readmem(struct ec_softc *, int, u_int8_t *, int);
! 128:
! 129: static const int ec_iobase[] = {
! 130: 0x2e0, 0x2a0, 0x280, 0x250, 0x350, 0x330, 0x310, 0x300,
! 131: };
! 132: #define NEC_IOBASE (sizeof(ec_iobase) / sizeof(ec_iobase[0]))
! 133:
! 134: static const int ec_membase[] = {
! 135: MADDRUNK, MADDRUNK, MADDRUNK, MADDRUNK, 0xc8000, 0xcc000,
! 136: 0xd8000, 0xdc000,
! 137: };
! 138: #define NEC_MEMBASE (sizeof(ec_membase) / sizeof(ec_membase[0]))
! 139:
! 140: struct cfdriver ec_cd = {
! 141: NULL, "ec", DV_IFNET
! 142: };
! 143:
! 144: int
! 145: ec_probe(struct device *parent, void *match, void *aux)
! 146: {
! 147: struct isa_attach_args *ia = aux;
! 148: bus_space_tag_t nict, asict, memt;
! 149: bus_space_handle_t nich, asich, memh;
! 150: bus_size_t memsize;
! 151: int nich_valid, asich_valid, memh_valid;
! 152: int i, rv = 0;
! 153: u_int8_t x;
! 154:
! 155: nict = asict = ia->ia_iot;
! 156: memt = ia->ia_memt;
! 157:
! 158: nich_valid = asich_valid = memh_valid = 0;
! 159:
! 160: /*
! 161: * Hmm, a 16-bit card has 16k of memory, but only an 8k window
! 162: * to it.
! 163: */
! 164: memsize = 8192;
! 165:
! 166: /* Disallow wildcarded i/o addresses. */
! 167: if (ia->ia_iobase == -1 /* ISACF_PORT_DEFAULT */)
! 168: return (0);
! 169:
! 170: /* Disallow wildcarded mem address. */
! 171: if (ia->ia_maddr == -1 /* ISACF_IOMEM_DEFAULT */)
! 172: return (0);
! 173:
! 174: /* Validate the i/o base. */
! 175: for (i = 0; i < NEC_IOBASE; i++)
! 176: if (ia->ia_iobase == ec_iobase[i])
! 177: break;
! 178: if (i == NEC_IOBASE)
! 179: return (0);
! 180:
! 181: /* Validate the mem base. */
! 182: for (i = 0; i < NEC_MEMBASE; i++) {
! 183: if (ec_membase[i] == MADDRUNK)
! 184: continue;
! 185: if (ia->ia_maddr == ec_membase[i])
! 186: break;
! 187: }
! 188: if (i == NEC_MEMBASE)
! 189: return (0);
! 190:
! 191: /* Attempt to map the NIC space. */
! 192: if (bus_space_map(nict, ia->ia_iobase + ELINK2_NIC_OFFSET,
! 193: ELINK2_NIC_PORTS, 0, &nich))
! 194: goto out;
! 195: nich_valid = 1;
! 196:
! 197: /* Attempt to map the ASIC space. */
! 198: if (bus_space_map(asict, ia->ia_iobase + ELINK2_ASIC_OFFSET,
! 199: ELINK2_ASIC_PORTS, 0, &asich))
! 200: goto out;
! 201: asich_valid = 1;
! 202:
! 203: /* Attempt to map the memory space. */
! 204: if (bus_space_map(memt, ia->ia_maddr, memsize, 0, &memh))
! 205: goto out;
! 206: memh_valid = 1;
! 207:
! 208: /*
! 209: * Verify that the kernel configured I/O address matches the
! 210: * board configured I/O address.
! 211: *
! 212: * This is really only useful to see if something that looks like
! 213: * the board is there; after all, we're already talking to it at
! 214: * this point.
! 215: */
! 216: x = bus_space_read_1(asict, asich, ELINK2_BCFR);
! 217: if (x == 0 || (x & (x - 1)) != 0)
! 218: goto out;
! 219: i = ffs(x) - 1;
! 220: if (ia->ia_iobase != ec_iobase[i])
! 221: goto out;
! 222:
! 223: /*
! 224: * ...and for the memory address. Note we do not support
! 225: * cards configured with shared memory disabled.
! 226: */
! 227: x = bus_space_read_1(asict, asich, ELINK2_PCFR);
! 228: if (x == 0 || (x & (x - 1)) != 0)
! 229: goto out;
! 230: i = ffs(x) - 1;
! 231: if (ia->ia_maddr != ec_membase[i])
! 232: goto out;
! 233:
! 234: /* So, we say we've found it! */
! 235: ia->ia_iosize = ELINK2_NIC_PORTS;
! 236: ia->ia_msize = memsize;
! 237: rv = 1;
! 238:
! 239: out:
! 240: if (nich_valid)
! 241: bus_space_unmap(nict, nich, ELINK2_NIC_PORTS);
! 242: if (asich_valid)
! 243: bus_space_unmap(asict, asich, ELINK2_ASIC_PORTS);
! 244: if (memh_valid)
! 245: bus_space_unmap(memt, memh, memsize);
! 246: return (rv);
! 247: }
! 248:
! 249: void
! 250: ec_attach(struct device *parent, struct device *self, void *aux)
! 251: {
! 252: struct ec_softc *esc = (struct ec_softc *)self;
! 253: struct dp8390_softc *sc = &esc->sc_dp8390;
! 254: struct isa_attach_args *ia = aux;
! 255: bus_space_tag_t nict, asict, memt;
! 256: bus_space_handle_t nich, asich, memh;
! 257: bus_size_t memsize;
! 258: u_int8_t tmp;
! 259: int i;
! 260:
! 261: printf("\n");
! 262:
! 263: nict = asict = ia->ia_iot;
! 264: memt = ia->ia_memt;
! 265:
! 266: /*
! 267: * Hmm, a 16-bit card has 16k of memory, but only an 8k window
! 268: * to it.
! 269: */
! 270: memsize = 8192;
! 271:
! 272: /* Map the NIC space. */
! 273: if (bus_space_map(nict, ia->ia_iobase + ELINK2_NIC_OFFSET,
! 274: ELINK2_NIC_PORTS, 0, &nich)) {
! 275: printf("%s: can't map nic i/o space\n",
! 276: sc->sc_dev.dv_xname);
! 277: return;
! 278: }
! 279:
! 280: /* Map the ASIC space. */
! 281: if (bus_space_map(asict, ia->ia_iobase + ELINK2_ASIC_OFFSET,
! 282: ELINK2_ASIC_PORTS, 0, &asich)) {
! 283: printf("%s: can't map asic i/o space\n",
! 284: sc->sc_dev.dv_xname);
! 285: return;
! 286: }
! 287:
! 288: /* Map the memory space. */
! 289: if (bus_space_map(memt, ia->ia_maddr, memsize, 0, &memh)) {
! 290: printf("%s: can't map shared memory\n",
! 291: sc->sc_dev.dv_xname);
! 292: return;
! 293: }
! 294:
! 295: esc->sc_asict = asict;
! 296: esc->sc_asich = asich;
! 297:
! 298: sc->sc_regt = nict;
! 299: sc->sc_regh = nich;
! 300:
! 301: sc->sc_buft = memt;
! 302: sc->sc_bufh = memh;
! 303:
! 304: /* Interface is always enabled. */
! 305: sc->sc_enabled = 1;
! 306:
! 307: /* Registers are linear. */
! 308: for (i = 0; i < 16; i++)
! 309: sc->sc_reg_map[i] = i;
! 310:
! 311: /* Now we can use the NIC_{GET,PUT}() macros. */
! 312:
! 313: /*
! 314: * Reset NIC and ASIC. Enable on-board transeiver throughout
! 315: * reset sequence since it will lock up if the cable isn't
! 316: * connected if we don't.
! 317: */
! 318: bus_space_write_1(asict, asich, ELINK2_CR,
! 319: ELINK2_CR_RST | ELINK2_CR_XSEL);
! 320:
! 321: /* Wait for a while, then un-reset it. */
! 322: delay(50);
! 323:
! 324: /*
! 325: * The 3Com ASIC defaults to rather strange settings for the CR
! 326: * after a reset. It's important to set it again after the
! 327: * following write (this is done when we map the PROM below).
! 328: */
! 329: bus_space_write_1(asict, asich, ELINK2_CR, ELINK2_CR_XSEL);
! 330:
! 331: /* Wait a bit for the NIC to recover from the reset. */
! 332: delay(5000);
! 333:
! 334: /*
! 335: * Get the station address from on-board ROM.
! 336: *
! 337: * First, map Ethernet address PROM over the top of where the NIC
! 338: * registers normally appear.
! 339: */
! 340: bus_space_write_1(asict, asich, ELINK2_CR,
! 341: ELINK2_CR_XSEL | ELINK2_CR_EALO);
! 342:
! 343: for (i = 0; i < ETHER_ADDR_LEN; i++)
! 344: sc->sc_arpcom.ac_enaddr[i] = NIC_GET(nict, nich, i);
! 345:
! 346: /*
! 347: * Unmap PROM - select NIC registers. The proper setting of the
! 348: * transciever is set in later in ec_init_card() via dp8390_init().
! 349: */
! 350: bus_space_write_1(asict, asich, ELINK2_CR, ELINK2_CR_XSEL);
! 351:
! 352: /* Determine if this is an 8-bit or 16-bit board. */
! 353:
! 354: /* Select page 0 registers. */
! 355: NIC_PUT(nict, nich, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP);
! 356:
! 357: /*
! 358: * Attempt to clear WTS. If it doesn't clear, then this is a
! 359: * 16-bit board.
! 360: */
! 361: NIC_PUT(nict, nich, ED_P0_DCR, 0);
! 362:
! 363: /* Select page 2 registers. */
! 364: NIC_PUT(nict, nich, ED_P0_CR, ED_CR_RD2 | ED_CR_PAGE_2 | ED_CR_STP);
! 365:
! 366: /* The 3c503 forces the WTS bit to a one if this is a 16-bit board. */
! 367: if (NIC_GET(nict, nich, ED_P2_DCR) & ED_DCR_WTS)
! 368: esc->sc_16bitp = 1;
! 369: else
! 370: esc->sc_16bitp = 0;
! 371:
! 372: printf("%s: 3Com 3c503 Ethernet (%s-bit)",
! 373: sc->sc_dev.dv_xname, esc->sc_16bitp ? "16" : "8");
! 374:
! 375: /* Select page 0 registers. */
! 376: NIC_PUT(nict, nich, ED_P2_CR, ED_CR_RD2 | ED_CR_PAGE_0 | ED_CR_STP);
! 377:
! 378: sc->cr_proto = ED_CR_RD2;
! 379:
! 380: /*
! 381: * DCR gets:
! 382: *
! 383: * FIFO threshold to 8, No auto-init Remote DMA,
! 384: * byte order=80x86.
! 385: *
! 386: * 16-bit cards also get word-wide DMA transfers.
! 387: */
! 388: sc->dcr_reg = ED_DCR_FT1 | ED_DCR_LS |
! 389: (esc->sc_16bitp ? ED_DCR_WTS : 0);
! 390:
! 391: sc->test_mem = ec_fake_test_mem;
! 392: sc->ring_copy = ec_ring_copy;
! 393: sc->write_mbuf = ec_write_mbuf;
! 394: sc->read_hdr = ec_read_hdr;
! 395:
! 396: sc->sc_media_init = ec_media_init;
! 397:
! 398: sc->sc_mediachange = ec_mediachange;
! 399: sc->sc_mediastatus = ec_mediastatus;
! 400:
! 401: sc->mem_start = 0;
! 402: sc->mem_size = memsize;
! 403:
! 404: /* Do generic parts of attach. */
! 405: if (dp8390_config(sc)) {
! 406: printf(": configuration failed\n");
! 407: return;
! 408: }
! 409:
! 410: /*
! 411: * We need to override the way dp8390_config() set up our
! 412: * shared memory.
! 413: *
! 414: * We have an entire 8k window to put the transmit buffers on the
! 415: * 16-bit boards. But since the 16bit 3c503's shared memory is only
! 416: * fast enough to overlap the loading of one full-size packet, trying
! 417: * to load more than 2 buffers can actually leave the transmitter idle
! 418: * during the load. So 2 seems the best value. (Although a mix of
! 419: * variable-sized packets might change this assumption. Nonetheless,
! 420: * we optimize for linear transfers of same-size packets.)
! 421: */
! 422: if (esc->sc_16bitp) {
! 423: if (sc->sc_dev.dv_cfdata->cf_flags & DP8390_NO_MULTI_BUFFERING)
! 424: sc->txb_cnt = 1;
! 425: else
! 426: sc->txb_cnt = 2;
! 427:
! 428: sc->tx_page_start = ELINK2_TX_PAGE_OFFSET_16BIT;
! 429: sc->rec_page_start = ELINK2_RX_PAGE_OFFSET_16BIT;
! 430: sc->rec_page_stop = (memsize >> ED_PAGE_SHIFT) +
! 431: sc->rec_page_start;
! 432: sc->mem_ring = sc->mem_start;
! 433: } else {
! 434: sc->txb_cnt = 1;
! 435: sc->tx_page_start = ELINK2_TX_PAGE_OFFSET_8BIT;
! 436: sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE;
! 437: sc->rec_page_stop = (memsize >> ED_PAGE_SHIFT) +
! 438: sc->tx_page_start;
! 439: sc->mem_ring = sc->mem_start +
! 440: (ED_TXBUF_SIZE << ED_PAGE_SHIFT);
! 441: }
! 442:
! 443: /*
! 444: * Initialize CA page start/stop registers. Probably only needed
! 445: * if doing DMA, but what the Hell.
! 446: */
! 447: bus_space_write_1(asict, asich, ELINK2_PSTR, sc->rec_page_start);
! 448: bus_space_write_1(asict, asich, ELINK2_PSPR, sc->rec_page_stop);
! 449:
! 450: /*
! 451: * Program the IRQ.
! 452: */
! 453: switch (ia->ia_irq) {
! 454: case 9: tmp = ELINK2_IDCFR_IRQ2; break;
! 455: case 3: tmp = ELINK2_IDCFR_IRQ3; break;
! 456: case 4: tmp = ELINK2_IDCFR_IRQ4; break;
! 457: case 5: tmp = ELINK2_IDCFR_IRQ5; break;
! 458: break;
! 459:
! 460: case IRQUNK:
! 461: printf("%s: wildcarded IRQ is not allowed\n",
! 462: sc->sc_dev.dv_xname);
! 463: return;
! 464:
! 465: default:
! 466: printf("%s: invalid IRQ %d, must be 3, 4, 5, or 9\n",
! 467: sc->sc_dev.dv_xname, ia->ia_irq);
! 468: return;
! 469: }
! 470:
! 471: bus_space_write_1(asict, asich, ELINK2_IDCFR, tmp);
! 472:
! 473: /*
! 474: * Initialize the GA configuration register. Set bank and enable
! 475: * shared memory.
! 476: */
! 477: bus_space_write_1(asict, asich, ELINK2_GACFR,
! 478: ELINK2_GACFR_RSEL | ELINK2_GACFR_MBS0);
! 479:
! 480: /*
! 481: * Intialize "Vector Pointer" registers. These gawd-awful things
! 482: * are compared to 20 bits of the address on the ISA, and if they
! 483: * match, the shared memory is disabled. We se them to 0xffff0...
! 484: * allegedly the reset vector.
! 485: */
! 486: bus_space_write_1(asict, asich, ELINK2_VPTR2, 0xff);
! 487: bus_space_write_1(asict, asich, ELINK2_VPTR1, 0xff);
! 488: bus_space_write_1(asict, asich, ELINK2_VPTR0, 0x00);
! 489:
! 490: /*
! 491: * Now run the real memory test.
! 492: */
! 493: if (ec_test_mem(sc)) {
! 494: printf("%s: memory test failed\n", sc->sc_dev.dv_xname);
! 495: return;
! 496: }
! 497:
! 498: /* Establish interrupt handler. */
! 499: esc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
! 500: IPL_NET, dp8390_intr, sc, sc->sc_dev.dv_xname);
! 501: if (esc->sc_ih == NULL)
! 502: printf("%s: can't establish interrupt\n", sc->sc_dev.dv_xname);
! 503: }
! 504:
! 505: int
! 506: ec_fake_test_mem(struct dp8390_softc *sc)
! 507: {
! 508: /*
! 509: * We have to do this after we initialize the GA, but we
! 510: * have to do that after calling dp8390_config(), which
! 511: * wants to test memory. Put this noop here, and then
! 512: * actually test memory later.
! 513: */
! 514: return (0);
! 515: }
! 516:
! 517: int
! 518: ec_test_mem(struct dp8390_softc *sc)
! 519: {
! 520: struct ec_softc *esc = (struct ec_softc *)sc;
! 521: bus_space_tag_t memt = sc->sc_buft;
! 522: bus_space_handle_t memh = sc->sc_bufh;
! 523: bus_size_t memsize = sc->mem_size;
! 524: int i;
! 525:
! 526: if (esc->sc_16bitp)
! 527: bus_space_set_region_2(memt, memh, 0, 0, memsize >> 1);
! 528: else
! 529: bus_space_set_region_1(memt, memh, 0, 0, memsize);
! 530:
! 531: if (esc->sc_16bitp) {
! 532: for (i = 0; i < memsize; i += 2) {
! 533: if (bus_space_read_2(memt, memh, i) != 0)
! 534: goto fail;
! 535: }
! 536: } else {
! 537: for (i = 0; i < memsize; i++) {
! 538: if (bus_space_read_1(memt, memh, i) != 0)
! 539: goto fail;
! 540: }
! 541: }
! 542:
! 543: return (0);
! 544:
! 545: fail:
! 546: printf("%s: failed to clear shared memory at offset 0x%x\n",
! 547: sc->sc_dev.dv_xname, i);
! 548: return (1);
! 549: }
! 550:
! 551: /*
! 552: * Given a NIC memory source address and a host memory destination address,
! 553: * copy 'len' from NIC to host using shared memory. The 'len' is rounded
! 554: * up to a word - ok as long as mbufs are word-sized.
! 555: */
! 556: __inline void
! 557: ec_readmem(struct ec_softc *esc, int from, u_int8_t *to, int len)
! 558: {
! 559: bus_space_tag_t memt = esc->sc_dp8390.sc_buft;
! 560: bus_space_handle_t memh = esc->sc_dp8390.sc_bufh;
! 561:
! 562: if (len & 1)
! 563: ++len;
! 564:
! 565: if (esc->sc_16bitp)
! 566: bus_space_read_region_2(memt, memh, from, (u_int16_t *)to,
! 567: len >> 1);
! 568: else
! 569: bus_space_read_region_1(memt, memh, from, to, len);
! 570: }
! 571:
! 572: int
! 573: ec_write_mbuf(struct dp8390_softc *sc, struct mbuf *m, int buf)
! 574: {
! 575: struct ec_softc *esc = (struct ec_softc *)sc;
! 576: bus_space_tag_t asict = esc->sc_asict;
! 577: bus_space_handle_t asich = esc->sc_asich;
! 578: bus_space_tag_t memt = esc->sc_dp8390.sc_buft;
! 579: bus_space_handle_t memh = esc->sc_dp8390.sc_bufh;
! 580: u_int8_t *data, savebyte[2];
! 581: int savelen, len, leftover;
! 582: #ifdef DIAGNOSTIC
! 583: u_int8_t *lim;
! 584: #endif
! 585:
! 586: savelen = m->m_pkthdr.len;
! 587:
! 588: /*
! 589: * 8-bit boards are simple: we're already in the correct
! 590: * page, and no alignment tricks are necessary.
! 591: */
! 592: if (esc->sc_16bitp == 0) {
! 593: for (; m != NULL; buf += m->m_len, m = m->m_next)
! 594: bus_space_write_region_1(memt, memh, buf,
! 595: mtod(m, u_int8_t *), m->m_len);
! 596: return (savelen);
! 597: }
! 598:
! 599: /*
! 600: * If it's a 16-bit board, we have transmit buffers
! 601: * in a different page; switch to it.
! 602: */
! 603: if (esc->sc_16bitp)
! 604: bus_space_write_1(asict, asich, ELINK2_GACFR,
! 605: ELINK2_GACFR_RSEL);
! 606:
! 607: /* Start out with no leftover data. */
! 608: leftover = 0;
! 609: savebyte[0] = savebyte[1] = 0;
! 610:
! 611: for (; m != NULL; m = m->m_next) {
! 612: len = m->m_len;
! 613: if (len == 0)
! 614: continue;
! 615: data = mtod(m, u_int8_t *);
! 616: #ifdef DIAGNOSTIC
! 617: lim = data + len;
! 618: #endif
! 619: while (len > 0) {
! 620: if (leftover) {
! 621: /*
! 622: * Data left over (from mbuf or realignment).
! 623: * Buffer the next byte, and write it and
! 624: * the leftover data out.
! 625: */
! 626: savebyte[1] = *data++;
! 627: len--;
! 628: bus_space_write_2(memt, memh, buf,
! 629: *(u_int16_t *)savebyte);
! 630: buf += 2;
! 631: leftover = 0;
! 632: } else if (ALIGNED_POINTER(data, u_int16_t) == 0) {
! 633: /*
! 634: * Unaligned data; buffer the next byte.
! 635: */
! 636: savebyte[0] = *data++;
! 637: len--;
! 638: leftover = 1;
! 639: } else {
! 640: /*
! 641: * Aligned data; output contiguous words as
! 642: * much as we can, then buffer the remaining
! 643: * byte, if any.
! 644: */
! 645: leftover = len & 1;
! 646: len &= ~1;
! 647: bus_space_write_region_2(memt, memh, buf,
! 648: (u_int16_t *)data, len >> 1);
! 649: data += len;
! 650: buf += len;
! 651: if (leftover)
! 652: savebyte[0] = *data++;
! 653: len = 0;
! 654: }
! 655: }
! 656: if (len < 0)
! 657: panic("ec_write_mbuf: negative len");
! 658: #ifdef DIAGNOSTIC
! 659: if (data != lim)
! 660: panic("ec_write_mbuf: data != lim");
! 661: #endif
! 662: }
! 663: if (leftover) {
! 664: savebyte[1] = 0;
! 665: bus_space_write_2(memt, memh, buf, *(u_int16_t *)savebyte);
! 666: }
! 667:
! 668: /*
! 669: * Switch back to receive page.
! 670: */
! 671: if (esc->sc_16bitp)
! 672: bus_space_write_1(asict, asich, ELINK2_GACFR,
! 673: ELINK2_GACFR_RSEL | ELINK2_GACFR_MBS0);
! 674:
! 675: return (savelen);
! 676: }
! 677:
! 678: int
! 679: ec_ring_copy(struct dp8390_softc *sc, int src, caddr_t dst,
! 680: u_short amount)
! 681: {
! 682: struct ec_softc *esc = (struct ec_softc *)sc;
! 683: u_short tmp_amount;
! 684:
! 685: /* Does copy wrap to lower addr in ring buffer? */
! 686: if (src + amount > sc->mem_end) {
! 687: tmp_amount = sc->mem_end - src;
! 688:
! 689: /* Copy amount up to end of NIC memory. */
! 690: ec_readmem(esc, src, dst, tmp_amount);
! 691:
! 692: amount -= tmp_amount;
! 693: src = sc->mem_ring;
! 694: dst += tmp_amount;
! 695: }
! 696:
! 697: ec_readmem(esc, src, dst, amount);
! 698:
! 699: return (src + amount);
! 700: }
! 701:
! 702: void
! 703: ec_read_hdr(struct dp8390_softc *sc, int packet_ptr,
! 704: struct dp8390_ring *packet_hdrp)
! 705: {
! 706: struct ec_softc *esc = (struct ec_softc *)sc;
! 707:
! 708: ec_readmem(esc, packet_ptr, (u_int8_t *)packet_hdrp,
! 709: sizeof(struct dp8390_ring));
! 710: #if BYTE_ORDER == BIG_ENDIAN
! 711: packet_hdrp->count = swap16(packet_hdrp->count);
! 712: #endif
! 713: }
! 714:
! 715: void
! 716: ec_media_init(struct dp8390_softc *sc)
! 717: {
! 718: ifmedia_init(&sc->sc_media, 0, dp8390_mediachange, dp8390_mediastatus);
! 719: ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10_2, 0, NULL);
! 720: ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_10_5, 0, NULL);
! 721: ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_10_2);
! 722: }
! 723:
! 724: int
! 725: ec_mediachange(struct dp8390_softc *sc)
! 726: {
! 727: struct ec_softc *esc = (struct ec_softc *)sc;
! 728: struct ifmedia *ifm = &sc->sc_media;
! 729:
! 730: return (ec_set_media(esc, ifm->ifm_media));
! 731: }
! 732:
! 733: void
! 734: ec_mediastatus(struct dp8390_softc *sc, struct ifmediareq *ifmr)
! 735: {
! 736: struct ifmedia *ifm = &sc->sc_media;
! 737:
! 738: /*
! 739: * The currently selected media is always the active media.
! 740: */
! 741: ifmr->ifm_active = ifm->ifm_cur->ifm_media;
! 742: }
! 743:
! 744: void
! 745: ec_init_card(struct dp8390_softc *sc)
! 746: {
! 747: struct ec_softc *esc = (struct ec_softc *)sc;
! 748: struct ifmedia *ifm = &sc->sc_media;
! 749:
! 750: (void) ec_set_media(esc, ifm->ifm_cur->ifm_media);
! 751: }
! 752:
! 753: int
! 754: ec_set_media(struct ec_softc *esc, int media)
! 755: {
! 756: u_int8_t new;
! 757:
! 758: if (IFM_TYPE(media) != IFM_ETHER)
! 759: return (EINVAL);
! 760:
! 761: switch (IFM_SUBTYPE(media)) {
! 762: case IFM_10_2:
! 763: new = ELINK2_CR_XSEL;
! 764: break;
! 765:
! 766: case IFM_10_5:
! 767: new = 0;
! 768: break;
! 769:
! 770: default:
! 771: return (EINVAL);
! 772: }
! 773:
! 774: bus_space_write_1(esc->sc_asict, esc->sc_asich, ELINK2_CR, new);
! 775: return (0);
! 776: }
CVSweb