Annotation of src/sys/dev/isa/if_ix.c, Revision 1.20
1.20 ! perry 1: /* $NetBSD: if_ix.c,v 1.19 2004/09/14 20:20:47 drochner Exp $ */
1.1 pk 2:
3: /*-
4: * Copyright (c) 1998 The NetBSD Foundation, Inc.
5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
8: * by Rafal K. Boni.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. All advertising materials mentioning features or use of this software
19: * must display the following acknowledgement:
20: * This product includes software developed by the NetBSD
21: * Foundation, Inc. and its contributors.
22: * 4. Neither the name of The NetBSD Foundation nor the names of its
23: * contributors may be used to endorse or promote products derived
24: * from this software without specific prior written permission.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36: * POSSIBILITY OF SUCH DAMAGE.
37: */
1.10 lukem 38:
39: #include <sys/cdefs.h>
1.20 ! perry 40: __KERNEL_RCSID(0, "$NetBSD: if_ix.c,v 1.19 2004/09/14 20:20:47 drochner Exp $");
1.1 pk 41:
42: #include <sys/param.h>
43: #include <sys/systm.h>
44: #include <sys/mbuf.h>
45: #include <sys/errno.h>
46: #include <sys/device.h>
47: #include <sys/protosw.h>
48: #include <sys/socket.h>
49:
50: #include <net/if.h>
51: #include <net/if_dl.h>
52: #include <net/if_types.h>
53: #include <net/if_media.h>
54: #include <net/if_ether.h>
55:
56: #include <machine/cpu.h>
57: #include <machine/bus.h>
58: #include <machine/intr.h>
59:
60: #include <dev/isa/isareg.h>
61: #include <dev/isa/isavar.h>
62:
63: #include <dev/ic/i82586reg.h>
64: #include <dev/ic/i82586var.h>
65: #include <dev/isa/if_ixreg.h>
66:
67: #ifdef IX_DEBUG
68: #define DPRINTF(x) printf x
69: #else
1.2 pk 70: #define DPRINTF(x)
1.1 pk 71: #endif
72:
1.2 pk 73: int ix_media[] = {
1.1 pk 74: IFM_ETHER | IFM_10_5,
75: IFM_ETHER | IFM_10_2,
76: IFM_ETHER | IFM_10_T,
77: };
78: #define NIX_MEDIA (sizeof(ix_media) / sizeof(ix_media[0]))
79:
80: struct ix_softc {
1.2 pk 81: struct ie_softc sc_ie;
1.1 pk 82:
1.2 pk 83: bus_space_tag_t sc_regt; /* space tag for registers */
84: bus_space_handle_t sc_regh; /* space handle for registers */
1.1 pk 85:
1.8 bjh21 86: u_int8_t use_pio; /* use PIO rather than shared mem */
1.2 pk 87: u_int16_t irq_encoded; /* encoded IRQ */
88: void *sc_ih; /* interrupt handle */
1.1 pk 89: };
90:
1.20 ! perry 91: static void ix_reset(struct ie_softc *, int);
! 92: static void ix_atten(struct ie_softc *, int);
! 93: static int ix_intrhook(struct ie_softc *, int);
1.1 pk 94:
1.20 ! perry 95: static void ix_copyin(struct ie_softc *, void *, int, size_t);
! 96: static void ix_copyout(struct ie_softc *, const void *, int, size_t);
1.2 pk 97:
1.20 ! perry 98: static void ix_bus_barrier(struct ie_softc *, int, int, int);
1.8 bjh21 99:
1.20 ! perry 100: static u_int16_t ix_read_16(struct ie_softc *, int);
! 101: static void ix_write_16(struct ie_softc *, int, u_int16_t);
! 102: static void ix_write_24(struct ie_softc *, int, int);
! 103: static void ix_zeromem (struct ie_softc *, int, int);
1.2 pk 104:
1.20 ! perry 105: static void ix_mediastatus(struct ie_softc *, struct ifmediareq *);
1.1 pk 106:
1.20 ! perry 107: static u_int16_t ix_read_eeprom(bus_space_tag_t, bus_space_handle_t, int);
! 108: static void ix_eeprom_outbits(bus_space_tag_t, bus_space_handle_t, int, int);
! 109: static int ix_eeprom_inbits (bus_space_tag_t, bus_space_handle_t);
! 110: static void ix_eeprom_clock (bus_space_tag_t, bus_space_handle_t, int);
1.1 pk 111:
1.20 ! perry 112: int ix_match(struct device *, struct cfdata *, void *);
! 113: void ix_attach(struct device *, struct device *, void *);
1.1 pk 114:
115: /*
116: * EtherExpress/16 support routines
117: */
118: static void
119: ix_reset(sc, why)
1.2 pk 120: struct ie_softc *sc;
121: int why;
1.1 pk 122: {
1.2 pk 123: struct ix_softc* isc = (struct ix_softc *) sc;
1.1 pk 124:
1.2 pk 125: switch (why) {
126: case CHIP_PROBE:
127: bus_space_write_1(isc->sc_regt, isc->sc_regh, IX_ECTRL,
128: IX_RESET_586);
129: delay(100);
130: bus_space_write_1(isc->sc_regt, isc->sc_regh, IX_ECTRL, 0);
131: delay(100);
132: break;
1.1 pk 133:
1.2 pk 134: case CARD_RESET:
135: break;
1.1 pk 136: }
137: }
138:
139: static void
1.9 jdolecek 140: ix_atten(sc, why)
1.2 pk 141: struct ie_softc *sc;
1.9 jdolecek 142: int why;
1.1 pk 143: {
1.2 pk 144: struct ix_softc* isc = (struct ix_softc *) sc;
145: bus_space_write_1(isc->sc_regt, isc->sc_regh, IX_ATTN, 0);
1.1 pk 146: }
147:
148: static u_int16_t
1.3 pk 149: ix_read_eeprom(iot, ioh, location)
150: bus_space_tag_t iot;
151: bus_space_handle_t ioh;
1.2 pk 152: int location;
1.1 pk 153: {
1.2 pk 154: int ectrl, edata;
1.1 pk 155:
1.3 pk 156: ectrl = bus_space_read_1(iot, ioh, IX_ECTRL);
1.2 pk 157: ectrl &= IX_ECTRL_MASK;
158: ectrl |= IX_ECTRL_EECS;
1.3 pk 159: bus_space_write_1(iot, ioh, IX_ECTRL, ectrl);
1.2 pk 160:
1.3 pk 161: ix_eeprom_outbits(iot, ioh, IX_EEPROM_READ, IX_EEPROM_OPSIZE1);
162: ix_eeprom_outbits(iot, ioh, location, IX_EEPROM_ADDR_SIZE);
163: edata = ix_eeprom_inbits(iot, ioh);
164: ectrl = bus_space_read_1(iot, ioh, IX_ECTRL);
1.2 pk 165: ectrl &= ~(IX_RESET_ASIC | IX_ECTRL_EEDI | IX_ECTRL_EECS);
1.3 pk 166: bus_space_write_1(iot, ioh, IX_ECTRL, ectrl);
167: ix_eeprom_clock(iot, ioh, 1);
168: ix_eeprom_clock(iot, ioh, 0);
1.2 pk 169: return (edata);
1.1 pk 170: }
171:
172: static void
1.3 pk 173: ix_eeprom_outbits(iot, ioh, edata, count)
174: bus_space_tag_t iot;
175: bus_space_handle_t ioh;
1.2 pk 176: int edata, count;
1.1 pk 177: {
1.2 pk 178: int ectrl, i;
1.1 pk 179:
1.3 pk 180: ectrl = bus_space_read_1(iot, ioh, IX_ECTRL);
1.2 pk 181: ectrl &= ~IX_RESET_ASIC;
182: for (i = count - 1; i >= 0; i--) {
183: ectrl &= ~IX_ECTRL_EEDI;
184: if (edata & (1 << i)) {
185: ectrl |= IX_ECTRL_EEDI;
186: }
1.3 pk 187: bus_space_write_1(iot, ioh, IX_ECTRL, ectrl);
1.2 pk 188: delay(1); /* eeprom data must be setup for 0.4 uSec */
1.3 pk 189: ix_eeprom_clock(iot, ioh, 1);
190: ix_eeprom_clock(iot, ioh, 0);
1.2 pk 191: }
192: ectrl &= ~IX_ECTRL_EEDI;
1.3 pk 193: bus_space_write_1(iot, ioh, IX_ECTRL, ectrl);
1.2 pk 194: delay(1); /* eeprom data must be held for 0.4 uSec */
1.1 pk 195: }
196:
197: static int
1.3 pk 198: ix_eeprom_inbits(iot, ioh)
199: bus_space_tag_t iot;
200: bus_space_handle_t ioh;
1.1 pk 201: {
1.2 pk 202: int ectrl, edata, i;
1.1 pk 203:
1.3 pk 204: ectrl = bus_space_read_1(iot, ioh, IX_ECTRL);
1.2 pk 205: ectrl &= ~IX_RESET_ASIC;
206: for (edata = 0, i = 0; i < 16; i++) {
207: edata = edata << 1;
1.3 pk 208: ix_eeprom_clock(iot, ioh, 1);
209: ectrl = bus_space_read_1(iot, ioh, IX_ECTRL);
1.2 pk 210: if (ectrl & IX_ECTRL_EEDO) {
211: edata |= 1;
212: }
1.3 pk 213: ix_eeprom_clock(iot, ioh, 0);
1.2 pk 214: }
215: return (edata);
1.1 pk 216: }
217:
218: static void
1.3 pk 219: ix_eeprom_clock(iot, ioh, state)
220: bus_space_tag_t iot;
221: bus_space_handle_t ioh;
1.2 pk 222: int state;
1.1 pk 223: {
1.2 pk 224: int ectrl;
1.1 pk 225:
1.3 pk 226: ectrl = bus_space_read_1(iot, ioh, IX_ECTRL);
1.2 pk 227: ectrl &= ~(IX_RESET_ASIC | IX_ECTRL_EESK);
228: if (state) {
229: ectrl |= IX_ECTRL_EESK;
230: }
1.3 pk 231: bus_space_write_1(iot, ioh, IX_ECTRL, ectrl);
1.2 pk 232: delay(9); /* EESK must be stable for 8.38 uSec */
1.1 pk 233: }
234:
235: static int
236: ix_intrhook(sc, where)
237: struct ie_softc *sc;
238: int where;
239: {
1.2 pk 240: struct ix_softc* isc = (struct ix_softc *) sc;
1.1 pk 241:
1.2 pk 242: switch (where) {
243: case INTR_ENTER:
244: /* entering ISR: disable card interrupts */
245: bus_space_write_1(isc->sc_regt, isc->sc_regh,
246: IX_IRQ, isc->irq_encoded);
247: break;
248:
249: case INTR_EXIT:
250: /* exiting ISR: re-enable card interrupts */
251: bus_space_write_1(isc->sc_regt, isc->sc_regh, IX_IRQ,
252: isc->irq_encoded | IX_IRQ_ENABLE);
1.1 pk 253: break;
254: }
255:
256: return 1;
257: }
258:
259:
260: static void
261: ix_copyin (sc, dst, offset, size)
262: struct ie_softc *sc;
263: void *dst;
264: int offset;
265: size_t size;
266: {
1.8 bjh21 267: int i, dribble;
1.2 pk 268: u_int8_t* bptr = dst;
1.8 bjh21 269: u_int16_t* wptr = dst;
270: struct ix_softc* isc = (struct ix_softc *) sc;
1.1 pk 271:
1.8 bjh21 272: if (isc->use_pio) {
273: /* Reset read pointer to the specified offset */
274: bus_space_barrier(sc->bt, sc->bh, IX_DATAPORT, 2,
275: BUS_SPACE_BARRIER_READ);
276: bus_space_write_2(sc->bt, sc->bh, IX_READPTR, offset);
277: bus_space_barrier(sc->bt, sc->bh, IX_READPTR, 2,
278: BUS_SPACE_BARRIER_WRITE);
279: } else {
1.2 pk 280: bus_space_barrier(sc->bt, sc->bh, offset, size,
281: BUS_SPACE_BARRIER_READ);
1.8 bjh21 282: }
1.1 pk 283:
1.2 pk 284: if (offset % 2) {
1.8 bjh21 285: if (isc->use_pio)
286: *bptr = bus_space_read_1(sc->bt, sc->bh, IX_DATAPORT);
287: else
1.2 pk 288: *bptr = bus_space_read_1(sc->bt, sc->bh, offset);
289: offset++; bptr++; size--;
290: }
291:
292: dribble = size % 2;
1.8 bjh21 293: wptr = (u_int16_t*) bptr;
294:
295: if (isc->use_pio) {
296: for(i = 0; i < size / 2; i++) {
297: *wptr = bus_space_read_2(sc->bt, sc->bh, IX_DATAPORT);
298: wptr++;
299: }
300: } else {
301: bus_space_read_region_2(sc->bt, sc->bh, offset,
302: (u_int16_t *) bptr, size / 2);
303: }
1.2 pk 304:
305: if (dribble) {
306: bptr += size - 1;
307: offset += size - 1;
1.8 bjh21 308:
309: if (isc->use_pio)
310: *bptr = bus_space_read_1(sc->bt, sc->bh, IX_DATAPORT);
311: else
1.2 pk 312: *bptr = bus_space_read_1(sc->bt, sc->bh, offset);
313: }
1.1 pk 314: }
315:
316: static void
1.2 pk 317: ix_copyout (sc, src, offset, size)
1.1 pk 318: struct ie_softc *sc;
319: const void *src;
320: int offset;
321: size_t size;
322: {
1.8 bjh21 323: int i, dribble;
1.2 pk 324: int osize = size;
325: int ooffset = offset;
326: const u_int8_t* bptr = src;
1.8 bjh21 327: const u_int16_t* wptr = src;
328: struct ix_softc* isc = (struct ix_softc *) sc;
329:
330: if (isc->use_pio) {
331: /* Reset write pointer to the specified offset */
332: bus_space_write_2(sc->bt, sc->bh, IX_WRITEPTR, offset);
333: bus_space_barrier(sc->bt, sc->bh, IX_WRITEPTR, 2,
334: BUS_SPACE_BARRIER_WRITE);
335: }
1.2 pk 336:
337: if (offset % 2) {
1.8 bjh21 338: if (isc->use_pio)
339: bus_space_write_1(sc->bt, sc->bh, IX_DATAPORT, *bptr);
340: else
1.2 pk 341: bus_space_write_1(sc->bt, sc->bh, offset, *bptr);
342: offset++; bptr++; size--;
343: }
344:
345: dribble = size % 2;
1.8 bjh21 346: wptr = (u_int16_t*) bptr;
347:
348: if (isc->use_pio) {
349: for(i = 0; i < size / 2; i++) {
350: bus_space_write_2(sc->bt, sc->bh, IX_DATAPORT, *wptr);
351: wptr++;
352: }
353: } else {
354: bus_space_write_region_2(sc->bt, sc->bh, offset,
355: (u_int16_t *)bptr, size / 2);
356: }
357:
1.2 pk 358: if (dribble) {
359: bptr += size - 1;
360: offset += size - 1;
1.8 bjh21 361:
362: if (isc->use_pio)
363: bus_space_write_1(sc->bt, sc->bh, IX_DATAPORT, *bptr);
364: else
1.2 pk 365: bus_space_write_1(sc->bt, sc->bh, offset, *bptr);
366: }
1.1 pk 367:
1.8 bjh21 368: if (isc->use_pio)
369: bus_space_barrier(sc->bt, sc->bh, IX_DATAPORT, 2,
370: BUS_SPACE_BARRIER_WRITE);
371: else
1.2 pk 372: bus_space_barrier(sc->bt, sc->bh, ooffset, osize,
373: BUS_SPACE_BARRIER_WRITE);
1.1 pk 374: }
375:
1.8 bjh21 376: static void
377: ix_bus_barrier(sc, offset, length, flags)
378: struct ie_softc *sc;
379: int offset, length, flags;
380: {
381: struct ix_softc* isc = (struct ix_softc *) sc;
382:
383: if (isc->use_pio)
384: bus_space_barrier(sc->bt, sc->bh, IX_DATAPORT, 2, flags);
385: else
386: bus_space_barrier(sc->bt, sc->bh, offset, length, flags);
387: }
388:
1.1 pk 389: static u_int16_t
390: ix_read_16 (sc, offset)
391: struct ie_softc *sc;
392: int offset;
393: {
1.8 bjh21 394: struct ix_softc* isc = (struct ix_softc *) sc;
395:
396: if (isc->use_pio) {
397: bus_space_barrier(sc->bt, sc->bh, IX_DATAPORT, 2,
398: BUS_SPACE_BARRIER_READ);
399:
400: /* Reset read pointer to the specified offset */
401: bus_space_write_2(sc->bt, sc->bh, IX_READPTR, offset);
402: bus_space_barrier(sc->bt, sc->bh, IX_READPTR, 2,
403: BUS_SPACE_BARRIER_WRITE);
404:
405: return bus_space_read_2(sc->bt, sc->bh, IX_DATAPORT);
406: } else {
407: bus_space_barrier(sc->bt, sc->bh, offset, 2,
408: BUS_SPACE_BARRIER_READ);
1.1 pk 409: return bus_space_read_2(sc->bt, sc->bh, offset);
1.8 bjh21 410: }
1.1 pk 411: }
412:
413: static void
1.2 pk 414: ix_write_16 (sc, offset, value)
1.1 pk 415: struct ie_softc *sc;
416: int offset;
417: u_int16_t value;
418: {
1.8 bjh21 419: struct ix_softc* isc = (struct ix_softc *) sc;
420:
421: if (isc->use_pio) {
422: /* Reset write pointer to the specified offset */
423: bus_space_write_2(sc->bt, sc->bh, IX_WRITEPTR, offset);
424: bus_space_barrier(sc->bt, sc->bh, IX_WRITEPTR, 2,
425: BUS_SPACE_BARRIER_WRITE);
426:
427: bus_space_write_2(sc->bt, sc->bh, IX_DATAPORT, value);
428: bus_space_barrier(sc->bt, sc->bh, IX_DATAPORT, 2,
429: BUS_SPACE_BARRIER_WRITE);
430: } else {
1.1 pk 431: bus_space_write_2(sc->bt, sc->bh, offset, value);
1.8 bjh21 432: bus_space_barrier(sc->bt, sc->bh, offset, 2,
433: BUS_SPACE_BARRIER_WRITE);
434: }
1.1 pk 435: }
436:
437: static void
438: ix_write_24 (sc, offset, addr)
439: struct ie_softc *sc;
440: int offset, addr;
441: {
1.8 bjh21 442: char* ptr;
443: struct ix_softc* isc = (struct ix_softc *) sc;
444: int val = addr + (u_long) sc->sc_maddr - (u_long) sc->sc_iobase;
445:
446: if (isc->use_pio) {
447: /* Reset write pointer to the specified offset */
448: bus_space_write_2(sc->bt, sc->bh, IX_WRITEPTR, offset);
449: bus_space_barrier(sc->bt, sc->bh, IX_WRITEPTR, 2,
450: BUS_SPACE_BARRIER_WRITE);
451:
452: ptr = (char*) &val;
453: bus_space_write_2(sc->bt, sc->bh, IX_DATAPORT,
454: *((u_int16_t *)ptr));
455: bus_space_write_2(sc->bt, sc->bh, IX_DATAPORT,
456: *((u_int16_t *)(ptr + 2)));
457: bus_space_barrier(sc->bt, sc->bh, IX_DATAPORT, 2,
458: BUS_SPACE_BARRIER_WRITE);
459: } else {
460: bus_space_write_4(sc->bt, sc->bh, offset, val);
461: bus_space_barrier(sc->bt, sc->bh, offset, 4,
462: BUS_SPACE_BARRIER_WRITE);
463: }
464: }
465:
466: static void
467: ix_zeromem(sc, offset, count)
468: struct ie_softc *sc;
469: int offset, count;
470: {
471: int i;
472: int dribble;
473: struct ix_softc* isc = (struct ix_softc *) sc;
474:
475: if (isc->use_pio) {
476: /* Reset write pointer to the specified offset */
477: bus_space_write_2(sc->bt, sc->bh, IX_WRITEPTR, offset);
478: bus_space_barrier(sc->bt, sc->bh, IX_WRITEPTR, 2,
479: BUS_SPACE_BARRIER_WRITE);
480:
481: if (offset % 2) {
482: bus_space_write_1(sc->bt, sc->bh, IX_DATAPORT, 0);
483: count--;
484: }
485:
486: dribble = count % 2;
487: for(i = 0; i < count / 2; i++)
488: bus_space_write_2(sc->bt, sc->bh, IX_DATAPORT, 0);
489:
490: if (dribble)
491: bus_space_write_1(sc->bt, sc->bh, IX_DATAPORT, 0);
492:
493: bus_space_barrier(sc->bt, sc->bh, IX_DATAPORT, 2,
494: BUS_SPACE_BARRIER_WRITE);
495: } else {
496: bus_space_set_region_1(sc->bt, sc->bh, offset, 0, count);
497: bus_space_barrier(sc->bt, sc->bh, offset, count,
498: BUS_SPACE_BARRIER_WRITE);
499: }
1.1 pk 500: }
501:
502: static void
503: ix_mediastatus(sc, ifmr)
1.2 pk 504: struct ie_softc *sc;
505: struct ifmediareq *ifmr;
1.1 pk 506: {
507: struct ifmedia *ifm = &sc->sc_media;
508:
509: /*
1.2 pk 510: * The currently selected media is always the active media.
1.1 pk 511: */
512: ifmr->ifm_active = ifm->ifm_cur->ifm_media;
513: }
514:
515: int
516: ix_match(parent, cf, aux)
1.2 pk 517: struct device *parent;
518: struct cfdata *cf;
519: void *aux;
1.1 pk 520: {
1.2 pk 521: int i;
522: int rv = 0;
523: bus_addr_t maddr;
524: bus_size_t msize;
525: u_short checksum = 0;
526: bus_space_handle_t ioh;
1.3 pk 527: bus_space_tag_t iot;
1.2 pk 528: u_int8_t val, bart_config;
529: u_short pg, adjust, decode, edecode;
1.3 pk 530: u_short board_id, id_var1, id_var2, irq, irq_encoded;
1.2 pk 531: struct isa_attach_args * const ia = aux;
532: short irq_translate[] = {0, 0x09, 0x03, 0x04, 0x05, 0x0a, 0x0b, 0};
533:
1.13 thorpej 534: if (ia->ia_nio < 1)
535: return (0);
536: if (ia->ia_niomem < 1)
537: return (0);
538: if (ia->ia_nirq < 1)
539: return (0);
540:
541: if (ISA_DIRECT_CONFIG(ia))
542: return (0);
543:
1.3 pk 544: iot = ia->ia_iot;
545:
1.19 drochner 546: if (ia->ia_io[0].ir_addr == ISA_UNKNOWN_PORT)
1.13 thorpej 547: return (0);
548:
549: if (bus_space_map(iot, ia->ia_io[0].ir_addr,
1.2 pk 550: IX_IOSIZE, 0, &ioh) != 0) {
551: DPRINTF(("Can't map io space at 0x%x\n", ia->ia_iobase));
552: return (0);
553: }
554:
555: /* XXX: reset any ee16 at the current iobase */
1.3 pk 556: bus_space_write_1(iot, ioh, IX_ECTRL, IX_RESET_ASIC);
557: bus_space_write_1(iot, ioh, IX_ECTRL, 0);
1.2 pk 558: delay(240);
559:
560: /* now look for ee16. */
561: board_id = id_var1 = id_var2 = 0;
562: for (i = 0; i < 4 ; i++) {
1.3 pk 563: id_var1 = bus_space_read_1(iot, ioh, IX_ID_PORT);
1.2 pk 564: id_var2 = ((id_var1 & 0x03) << 2);
565: board_id |= (( id_var1 >> 4) << id_var2);
566: }
567:
568: if (board_id != IX_ID) {
569: DPRINTF(("BART ID mismatch (got 0x%04x, expected 0x%04x)\n",
570: board_id, IX_ID));
571: goto out;
572: }
573:
574: /*
575: * The shared RAM size and location of the EE16 is encoded into
576: * EEPROM location 6. The location of the first set bit tells us
577: * the memory address (0xc0000 + (0x4000 * FSB)), where FSB is the
578: * number of the first set bit. The zeroes are then shifted out,
579: * and the results is the memory size (1 = 16k, 3 = 32k, 7 = 48k,
580: * 0x0f = 64k).
581: *
582: * Examples:
583: * 0x3c -> 64k@0xc8000, 0x70 -> 48k@0xd0000, 0xc0 -> 32k@0xd8000
584: * 0x80 -> 16k@0xdc000.
585: *
586: * Side note: this comes from reading the old driver rather than
587: * from a more definitive source, so it could be out-of-whack
588: * with what the card can do...
589: */
590:
1.3 pk 591: val = ix_read_eeprom(iot, ioh, 6) & 0xff;
1.18 mycroft 592: for (pg = 0; pg < 8; pg++) {
1.2 pk 593: if (val & 1)
594: break;
1.18 mycroft 595: val >>= 1;
1.2 pk 596: }
597:
1.8 bjh21 598: maddr = 0xc0000 + (pg * 0x4000);
1.2 pk 599:
600: switch (val) {
1.8 bjh21 601: case 0x00:
1.18 mycroft 602: maddr = 0;
1.8 bjh21 603: msize = 0;
604: break;
605:
1.2 pk 606: case 0x01:
607: msize = 16 * 1024;
608: break;
609:
610: case 0x03:
611: msize = 32 * 1024;
612: break;
613:
614: case 0x07:
615: msize = 48 * 1024;
616: break;
617:
618: case 0x0f:
619: msize = 64 * 1024;
620: break;
621:
622: default:
623: DPRINTF(("invalid memory size %02x\n", val));
624: goto out;
625: }
626:
1.19 drochner 627: if (ia->ia_iomem[0].ir_addr != ISA_UNKNOWN_IOMEM &&
1.13 thorpej 628: ia->ia_iomem[0].ir_addr != maddr) {
1.2 pk 629: DPRINTF((
630: "ix_match: memaddr of board @ 0x%x doesn't match config\n",
631: ia->ia_iobase));
632: goto out;
633: }
634:
1.19 drochner 635: if (ia->ia_iomem[0].ir_size != ISA_UNKNOWN_IOSIZ &&
1.13 thorpej 636: ia->ia_iomem[0].ir_size != msize) {
1.2 pk 637: DPRINTF((
638: "ix_match: memsize of board @ 0x%x doesn't match config\n",
639: ia->ia_iobase));
640: goto out;
641: }
642:
643: /* need to put the 586 in RESET, and leave it */
1.3 pk 644: bus_space_write_1(iot, ioh, IX_ECTRL, IX_RESET_586);
1.2 pk 645:
646: /* read the eeprom and checksum it, should == IX_ID */
647: for(i = 0; i < 0x40; i++)
1.3 pk 648: checksum += ix_read_eeprom(iot, ioh, i);
1.2 pk 649:
650: if (checksum != IX_ID) {
651: DPRINTF(("checksum mismatch (got 0x%04x, expected 0x%04x\n",
652: checksum, IX_ID));
653: goto out;
654: }
655:
656: /*
1.8 bjh21 657: * Only do the following bit if using memory-mapped access. For
658: * boards with no mapped memory, we use PIO. We also use PIO for
659: * boards with 16K of mapped memory, as those setups don't seem
660: * to work otherwise.
1.2 pk 661: */
1.8 bjh21 662: if (msize != 0 && msize != 16384) {
663: /* Set board up with memory-mapping info */
1.2 pk 664: adjust = IX_MCTRL_FMCS16 | (pg & 0x3) << 2;
1.13 thorpej 665: decode = ((1 << (ia->ia_iomem[0].ir_size / 16384)) - 1) << pg;
1.2 pk 666: edecode = ((~decode >> 4) & 0xF0) | (decode >> 8);
667:
1.3 pk 668: bus_space_write_1(iot, ioh, IX_MEMDEC, decode & 0xFF);
669: bus_space_write_1(iot, ioh, IX_MCTRL, adjust);
670: bus_space_write_1(iot, ioh, IX_MPCTRL, (~decode & 0xFF));
1.2 pk 671:
1.8 bjh21 672: /* XXX disable Exxx */
673: bus_space_write_1(iot, ioh, IX_MECTRL, edecode);
674: }
1.2 pk 675:
676: /*
677: * Get the encoded interrupt number from the EEPROM, check it
678: * against the passed in IRQ. Issue a warning if they do not
1.19 drochner 679: * match, and fail the probe. If irq is 'ISA_UNKNOWN_IRQ' then we
1.2 pk 680: * use the EEPROM irq, and continue.
681: */
1.3 pk 682: irq_encoded = ix_read_eeprom(iot, ioh, IX_EEPROM_CONFIG1);
683: irq_encoded = (irq_encoded & IX_EEPROM_IRQ) >> IX_EEPROM_IRQ_SHIFT;
684: irq = irq_translate[irq_encoded];
1.19 drochner 685: if (ia->ia_irq[0].ir_irq != ISA_UNKNOWN_IRQ &&
1.13 thorpej 686: irq != ia->ia_irq[0].ir_irq) {
1.2 pk 687: DPRINTF(("board IRQ %d does not match config\n", irq));
688: goto out;
689: }
690:
691: /* disable the board interrupts */
1.3 pk 692: bus_space_write_1(iot, ioh, IX_IRQ, irq_encoded);
1.2 pk 693:
1.3 pk 694: bart_config = bus_space_read_1(iot, ioh, IX_CONFIG);
1.2 pk 695: bart_config |= IX_BART_LOOPBACK;
696: bart_config |= IX_BART_MCS16_TEST; /* inb doesn't get bit! */
1.3 pk 697: bus_space_write_1(iot, ioh, IX_CONFIG, bart_config);
698: bart_config = bus_space_read_1(iot, ioh, IX_CONFIG);
1.2 pk 699:
1.3 pk 700: bus_space_write_1(iot, ioh, IX_ECTRL, 0);
1.2 pk 701: delay(100);
702:
703: rv = 1;
1.13 thorpej 704:
705: ia->ia_nio = 1;
706: ia->ia_io[0].ir_size = IX_IOSIZE;
707:
708: ia->ia_niomem = 1;
709: ia->ia_iomem[0].ir_addr = maddr;
710: ia->ia_iomem[0].ir_size = msize;
711:
712: ia->ia_nirq = 1;
713: ia->ia_irq[0].ir_irq = irq;
714:
1.2 pk 715: DPRINTF(("ix_match: found board @ 0x%x\n", ia->ia_iobase));
1.1 pk 716:
717: out:
1.3 pk 718: bus_space_unmap(iot, ioh, IX_IOSIZE);
1.2 pk 719: return (rv);
1.1 pk 720: }
721:
722: void
723: ix_attach(parent, self, aux)
1.2 pk 724: struct device *parent;
725: struct device *self;
726: void *aux;
727: {
728: struct ix_softc *isc = (void *)self;
729: struct ie_softc *sc = &isc->sc_ie;
730: struct isa_attach_args *ia = aux;
731:
732: int media;
1.8 bjh21 733: int i, memsize;
1.2 pk 734: u_int8_t bart_config;
1.3 pk 735: bus_space_tag_t iot;
1.8 bjh21 736: u_int8_t bpat, bval;
737: u_int16_t wpat, wval;
1.2 pk 738: bus_space_handle_t ioh, memh;
1.3 pk 739: u_short irq_encoded;
1.2 pk 740: u_int8_t ethaddr[ETHER_ADDR_LEN];
741:
1.3 pk 742: iot = ia->ia_iot;
743:
1.8 bjh21 744: /*
745: * Shared memory access seems to fail on 16K mapped boards, so
746: * disable shared memory access if the board is in 16K mode. If
747: * no memory is mapped, we have no choice but to use PIO
748: */
1.13 thorpej 749: isc->use_pio = (ia->ia_iomem[0].ir_size <= (16 * 1024));
1.8 bjh21 750:
1.13 thorpej 751: if (bus_space_map(iot, ia->ia_io[0].ir_addr,
752: ia->ia_io[0].ir_size, 0, &ioh) != 0) {
1.2 pk 753:
754: DPRINTF(("\n%s: can't map i/o space 0x%x-0x%x\n",
1.13 thorpej 755: sc->sc_dev.dv_xname, ia->ia_[0].ir_addr,
756: ia->ia_io[0].ir_addr + ia->ia_io[0].ir_size - 1));
1.2 pk 757: return;
758: }
759:
1.8 bjh21 760: /* We map memory even if using PIO so something else doesn't grab it */
1.13 thorpej 761: if (ia->ia_iomem[0].ir_size) {
762: if (bus_space_map(ia->ia_memt, ia->ia_iomem[0].ir_addr,
763: ia->ia_iomem[0].ir_size, 0, &memh) != 0) {
1.2 pk 764: DPRINTF(("\n%s: can't map iomem space 0x%x-0x%x\n",
1.13 thorpej 765: sc->sc_dev.dv_xname, ia->ia_iomem[0].ir_addr,
766: ia->ia_iomem[0].ir_addr + ia->ia_iomem[0].ir_size - 1));
767: bus_space_unmap(iot, ioh, ia->ia_io[0].ir_size);
1.2 pk 768: return;
769: }
1.8 bjh21 770: }
1.2 pk 771:
1.3 pk 772: isc->sc_regt = iot;
1.2 pk 773: isc->sc_regh = ioh;
774:
775: /*
776: * Get the hardware ethernet address from the EEPROM and
777: * save it in the softc for use by the 586 setup code.
778: */
1.8 bjh21 779: wval = ix_read_eeprom(iot, ioh, IX_EEPROM_ENET_HIGH);
780: ethaddr[1] = wval & 0xFF;
781: ethaddr[0] = wval >> 8;
782: wval = ix_read_eeprom(iot, ioh, IX_EEPROM_ENET_MID);
783: ethaddr[3] = wval & 0xFF;
784: ethaddr[2] = wval >> 8;
785: wval = ix_read_eeprom(iot, ioh, IX_EEPROM_ENET_LOW);
786: ethaddr[5] = wval & 0xFF;
787: ethaddr[4] = wval >> 8;
1.2 pk 788:
789: sc->hwinit = NULL;
790: sc->hwreset = ix_reset;
791: sc->chan_attn = ix_atten;
792: sc->intrhook = ix_intrhook;
793:
794: sc->memcopyin = ix_copyin;
795: sc->memcopyout = ix_copyout;
1.8 bjh21 796:
797: /* If using PIO, make sure to setup single-byte read/write functions */
798: if (isc->use_pio) {
799: sc->ie_bus_barrier = ix_bus_barrier;
800: } else {
801: sc->ie_bus_barrier = NULL;
802: }
803:
1.2 pk 804: sc->ie_bus_read16 = ix_read_16;
805: sc->ie_bus_write16 = ix_write_16;
806: sc->ie_bus_write24 = ix_write_24;
807:
808: sc->do_xmitnopchain = 0;
809:
810: sc->sc_mediachange = NULL;
811: sc->sc_mediastatus = ix_mediastatus;
812:
1.8 bjh21 813: if (isc->use_pio) {
814: sc->bt = iot;
815: sc->bh = ioh;
816:
817: /*
818: * If using PIO, the memory size is bounded by on-card memory,
819: * not by how much is mapped into the memory-mapped region, so
820: * determine how much total memory we have to play with here.
821: */
822: for(memsize = 64 * 1024; memsize; memsize -= 16 * 1024) {
823: /* warm up shared memory, the zero it all out */
824: ix_zeromem(sc, 0, 32);
825: ix_zeromem(sc, 0, memsize);
826:
827: /* Reset write pointer to the start of RAM */
828: bus_space_write_2(iot, ioh, IX_WRITEPTR, 0);
829: bus_space_barrier(iot, ioh, IX_WRITEPTR, 2,
830: BUS_SPACE_BARRIER_WRITE);
831:
832: /* write test pattern */
1.12 rafal 833: for(i = 0, wpat = 1; i < memsize; i += 2) {
1.8 bjh21 834: bus_space_write_2(iot, ioh, IX_DATAPORT, wpat);
835: wpat += 3;
836: }
837:
838: /* Flush all reads & writes to data port */
839: bus_space_barrier(iot, ioh, IX_DATAPORT, 2,
840: BUS_SPACE_BARRIER_READ |
841: BUS_SPACE_BARRIER_WRITE);
842:
843: /* Reset read pointer to beginning of card RAM */
844: bus_space_write_2(iot, ioh, IX_READPTR, 0);
845: bus_space_barrier(iot, ioh, IX_READPTR, 2,
846: BUS_SPACE_BARRIER_WRITE);
847:
848: /* read and verify test pattern */
849: for(i = 0, wpat = 1; i < memsize; i += 2) {
850: wval = bus_space_read_2(iot, ioh, IX_DATAPORT);
851:
852: if (wval != wpat)
853: break;
854:
855: wpat += 3;
856: }
857:
858: /* If we failed, try next size down */
859: if (i != memsize)
860: continue;
861:
862: /* Now try it all with byte reads/writes */
863: ix_zeromem(sc, 0, 32);
864: ix_zeromem(sc, 0, memsize);
865:
866: /* Reset write pointer to start of card RAM */
867: bus_space_write_2(iot, ioh, IX_WRITEPTR, 0);
868: bus_space_barrier(iot, ioh, IX_WRITEPTR, 2,
869: BUS_SPACE_BARRIER_WRITE);
870:
871: /* write out test pattern */
872: for(i = 0, bpat = 1; i < memsize; i++) {
873: bus_space_write_1(iot, ioh, IX_DATAPORT, bpat);
874: bpat += 3;
875: }
876:
877: /* Flush all reads & writes to data port */
878: bus_space_barrier(iot, ioh, IX_DATAPORT, 2,
879: BUS_SPACE_BARRIER_READ |
880: BUS_SPACE_BARRIER_WRITE);
881:
882: /* Reset read pointer to beginning of card RAM */
883: bus_space_write_2(iot, ioh, IX_READPTR, 0);
884: bus_space_barrier(iot, ioh, IX_READPTR, 2,
885: BUS_SPACE_BARRIER_WRITE);
886:
887: /* read and verify test pattern */
888: for(i = 0, bpat = 1; i < memsize; i++) {
889: bval = bus_space_read_1(iot, ioh, IX_DATAPORT);
890:
891: if (bval != bpat)
892: bpat += 3;
893: }
894:
895: /* If we got through all of memory, we're done! */
896: if (i == memsize)
897: break;
898: }
899:
900: /* Memory tests failed, punt... */
901: if (memsize == 0) {
902: DPRINTF(("\n%s: can't determine size of on-card RAM\n",
903: sc->sc_dev.dv_xname));
1.13 thorpej 904: bus_space_unmap(iot, ioh, ia->ia_io[0].ir_size);
1.8 bjh21 905: return;
906: }
907:
908: sc->bt = iot;
909: sc->bh = ioh;
910:
911: sc->sc_msize = memsize;
912: sc->sc_maddr = (void*) 0;
913: } else {
1.2 pk 914: sc->bt = ia->ia_memt;
915: sc->bh = memh;
916:
1.13 thorpej 917: sc->sc_msize = ia->ia_iomem[0].ir_size;
1.6 augustss 918: sc->sc_maddr = (void *)memh;
1.8 bjh21 919: }
920:
921: /* Map i/o space. */
1.6 augustss 922: sc->sc_iobase = (char *)sc->sc_maddr + sc->sc_msize - (1 << 24);
1.2 pk 923:
924: /* set up pointers to important on-card control structures */
925: sc->iscp = 0;
926: sc->scb = IE_ISCP_SZ;
927: sc->scp = sc->sc_msize + IE_SCP_ADDR - (1 << 24);
928:
929: sc->buf_area = sc->scb + IE_SCB_SZ;
930: sc->buf_area_sz = sc->sc_msize - IE_ISCP_SZ - IE_SCB_SZ - IE_SCP_SZ;
931:
932: /* zero card memory */
1.8 bjh21 933: ix_zeromem(sc, 0, 32);
934: ix_zeromem(sc, 0, sc->sc_msize);
1.2 pk 935:
936: /* set card to 16-bit bus mode */
1.8 bjh21 937: if (isc->use_pio) {
938: bus_space_write_2(sc->bt, sc->bh, IX_WRITEPTR,
939: IE_SCP_BUS_USE((u_long)sc->scp));
940: bus_space_barrier(sc->bt, sc->bh, IX_WRITEPTR, 2,
941: BUS_SPACE_BARRIER_WRITE);
942:
1.11 fredette 943: bus_space_write_1(sc->bt, sc->bh, IX_DATAPORT,
944: IE_SYSBUS_16BIT);
1.8 bjh21 945: } else {
946: bus_space_write_1(sc->bt, sc->bh,
1.11 fredette 947: IE_SCP_BUS_USE((u_long)sc->scp),
948: IE_SYSBUS_16BIT);
1.8 bjh21 949: }
1.2 pk 950:
951: /* set up pointers to key structures */
952: ix_write_24(sc, IE_SCP_ISCP((u_long)sc->scp), (u_long) sc->iscp);
953: ix_write_16(sc, IE_ISCP_SCB((u_long)sc->iscp), (u_long) sc->scb);
954: ix_write_24(sc, IE_ISCP_BASE((u_long)sc->iscp), (u_long) sc->iscp);
955:
956: /* flush setup of pointers, check if chip answers */
1.8 bjh21 957: if (isc->use_pio) {
958: bus_space_barrier(sc->bt, sc->bh, 0, IX_IOSIZE,
959: BUS_SPACE_BARRIER_WRITE);
960: } else {
1.2 pk 961: bus_space_barrier(sc->bt, sc->bh, 0, sc->sc_msize,
962: BUS_SPACE_BARRIER_WRITE);
1.8 bjh21 963: }
964:
1.2 pk 965: if (!i82586_proberam(sc)) {
966: DPRINTF(("\n%s: Can't talk to i82586!\n",
967: sc->sc_dev.dv_xname));
1.13 thorpej 968: bus_space_unmap(iot, ioh, ia->ia_io[0].ir_size);
1.8 bjh21 969:
1.13 thorpej 970: if (ia->ia_iomem[0].ir_size)
971: bus_space_unmap(ia->ia_memt, memh, ia->ia_iomem[0].ir_size);
1.2 pk 972: return;
973: }
974:
975: /* Figure out which media is being used... */
1.3 pk 976: if (ix_read_eeprom(iot, ioh, IX_EEPROM_CONFIG1) &
977: IX_EEPROM_MEDIA_EXT) {
978: if (ix_read_eeprom(iot, ioh, IX_EEPROM_MEDIA) &
979: IX_EEPROM_MEDIA_TP)
1.2 pk 980: media = IFM_ETHER | IFM_10_T;
981: else
982: media = IFM_ETHER | IFM_10_2;
983: } else
984: media = IFM_ETHER | IFM_10_5;
985:
986: /* Take the card out of lookback */
1.3 pk 987: bart_config = bus_space_read_1(iot, ioh, IX_CONFIG);
1.2 pk 988: bart_config &= ~IX_BART_LOOPBACK;
989: bart_config |= IX_BART_MCS16_TEST; /* inb doesn't get bit! */
1.3 pk 990: bus_space_write_1(iot, ioh, IX_CONFIG, bart_config);
991: bart_config = bus_space_read_1(iot, ioh, IX_CONFIG);
992:
993: irq_encoded = ix_read_eeprom(iot, ioh,
994: IX_EEPROM_CONFIG1);
995: irq_encoded = (irq_encoded & IX_EEPROM_IRQ) >> IX_EEPROM_IRQ_SHIFT;
1.2 pk 996:
997: /* Enable interrupts */
1.3 pk 998: bus_space_write_1(iot, ioh, IX_IRQ,
999: irq_encoded | IX_IRQ_ENABLE);
1000:
1.8 bjh21 1001: /* Flush all writes to registers */
1.13 thorpej 1002: bus_space_barrier(iot, ioh, 0, ia->ia_io[0].ir_size,
1003: BUS_SPACE_BARRIER_WRITE);
1.8 bjh21 1004:
1.3 pk 1005: isc->irq_encoded = irq_encoded;
1.2 pk 1006:
1007: i82586_attach(sc, "EtherExpress/16", ethaddr,
1008: ix_media, NIX_MEDIA, media);
1.8 bjh21 1009:
1010: if (isc->use_pio)
1011: printf("%s: unsupported memory config, using PIO to access %d bytes of memory\n", sc->sc_dev.dv_xname, sc->sc_msize);
1.2 pk 1012:
1.13 thorpej 1013: isc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq[0].ir_irq,
1014: IST_EDGE, IPL_NET, i82586_intr, sc);
1.2 pk 1015: if (isc->sc_ih == NULL)
1016: DPRINTF(("\n%s: can't establish interrupt\n",
1017: sc->sc_dev.dv_xname));
1.1 pk 1018: }
1019:
1.16 thorpej 1020: CFATTACH_DECL(ix, sizeof(struct ix_softc),
1.17 thorpej 1021: ix_match, ix_attach, NULL, NULL);
CVSweb <webmaster@jp.NetBSD.org>