Annotation of sys/arch/sparc/dev/if_le.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: if_le.c,v 1.29 2007/05/29 09:54:09 sobrado Exp $ */
2: /* $NetBSD: if_le.c,v 1.50 1997/09/09 20:54:48 pk Exp $ */
3:
4: /*-
5: * Copyright (c) 1997 Jason R. Thorpe. All rights reserved.
6: * Copyright (c) 1996
7: * The President and Fellows of Harvard College. All rights reserved.
8: * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
9: * Copyright (c) 1992, 1993
10: * The Regents of the University of California. All rights reserved.
11: *
12: * This code is derived from software contributed to Berkeley by
13: * Ralph Campbell and Rick Macklem.
14: *
15: * Redistribution and use in source and binary forms, with or without
16: * modification, are permitted provided that the following conditions
17: * are met:
18: * 1. Redistributions of source code must retain the above copyright
19: * notice, this list of conditions and the following disclaimer.
20: * 2. Redistributions in binary form must reproduce the above copyright
21: * notice, this list of conditions and the following disclaimer in the
22: * documentation and/or other materials provided with the distribution.
23: * 3. All advertising materials mentioning features or use of this software
24: * must display the following acknowledgement:
25: * This product includes software developed by Aaron Brown and
26: * Harvard University.
27: * This product includes software developed for the NetBSD Project
28: * by Jason R. Thorpe.
29: * 4. Neither the name of the University nor the names of its contributors
30: * may be used to endorse or promote products derived from this software
31: * without specific prior written permission.
32: *
33: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
34: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
37: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43: * SUCH DAMAGE.
44: *
45: * @(#)if_le.c 8.2 (Berkeley) 11/16/93
46: */
47:
48: #include "bpfilter.h"
49:
50: #include <sys/param.h>
51: #include <sys/systm.h>
52: #include <sys/mbuf.h>
53: #include <sys/syslog.h>
54: #include <sys/socket.h>
55: #include <sys/device.h>
56: #include <sys/malloc.h>
57:
58: #include <net/if.h>
59: #include <net/if_media.h>
60:
61: #ifdef INET
62: #include <netinet/in.h>
63: #include <netinet/if_ether.h>
64: #endif
65:
66: #include <machine/autoconf.h>
67: #include <machine/cpu.h>
68:
69: #include <sparc/dev/sbusvar.h>
70: #include <sparc/dev/dmareg.h>
71: #include <sparc/dev/dmavar.h>
72: #include <sparc/dev/lebuffervar.h>
73:
74: #include <dev/ic/am7990reg.h>
75: #include <dev/ic/am7990var.h>
76:
77: #include <sparc/dev/if_lereg.h>
78: #include <sparc/dev/if_levar.h>
79:
80: #ifdef solbourne
81: #include <sparc/sparc/asm.h>
82: #include <machine/idt.h>
83: #include <machine/kap.h>
84: #endif
85:
86: int lematch(struct device *, void *, void *);
87: void leattach(struct device *, struct device *, void *);
88:
89: /*
90: * ifmedia interfaces
91: */
92: int lemediachange(struct ifnet *);
93: void lemediastatus(struct ifnet *, struct ifmediareq *);
94:
95: #if defined(SUN4M)
96: /*
97: * media change methods (only for sun4m)
98: */
99: void lesetutp(struct am7990_softc *);
100: void lesetaui(struct am7990_softc *);
101: #endif /* SUN4M */
102:
103: #if defined(SUN4M) /* XXX */
104: int myleintr(void *);
105: int ledmaintr(struct dma_softc *);
106:
107: int
108: myleintr(arg)
109: void *arg;
110: {
111: register struct le_softc *lesc = arg;
112: static int dodrain=0;
113:
114: if (lesc->sc_dma->sc_regs->csr & D_ERR_PEND) {
115: dodrain = 1;
116: return ledmaintr(lesc->sc_dma);
117: }
118:
119: if (dodrain) { /* XXX - is this necessary with D_DSBL_WRINVAL on? */
120: int i = 10;
121: while (i-- > 0 && (lesc->sc_dma->sc_regs->csr & D_DRAINING))
122: delay(1);
123: }
124:
125: return (am7990_intr(arg));
126: }
127: #endif
128:
129: struct cfattach le_ca = {
130: sizeof(struct le_softc), lematch, leattach
131: };
132:
133: hide void lewrcsr(struct am7990_softc *, u_int16_t, u_int16_t);
134: hide u_int16_t lerdcsr(struct am7990_softc *, u_int16_t);
135: hide void lehwreset(struct am7990_softc *);
136: hide void lehwinit(struct am7990_softc *);
137: #if defined(SUN4M)
138: hide void lenocarrier(struct am7990_softc *);
139: #endif
140: #if defined(solbourne)
141: hide void kap_copytobuf(struct am7990_softc *, void *, int, int);
142: hide void kap_copyfrombuf(struct am7990_softc *, void *, int, int);
143: #endif
144:
145: hide void
146: lewrcsr(sc, port, val)
147: struct am7990_softc *sc;
148: u_int16_t port, val;
149: {
150: register struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
151: #if defined(SUN4M)
152: volatile u_int16_t discard;
153: #endif
154:
155: ler1->ler1_rap = port;
156: ler1->ler1_rdp = val;
157: #if defined(SUN4M)
158: /*
159: * We need to flush the SBus->MBus write buffers. This can most
160: * easily be accomplished by reading back the register that we
161: * just wrote (thanks to Chris Torek for this solution).
162: */
163: if (CPU_ISSUN4M)
164: discard = ler1->ler1_rdp;
165: #endif
166: }
167:
168: hide u_int16_t
169: lerdcsr(sc, port)
170: struct am7990_softc *sc;
171: u_int16_t port;
172: {
173: register struct lereg1 *ler1 = ((struct le_softc *)sc)->sc_r1;
174: u_int16_t val;
175:
176: ler1->ler1_rap = port;
177: val = ler1->ler1_rdp;
178: return (val);
179: }
180:
181: #if defined(SUN4M)
182: void
183: lesetutp(sc)
184: struct am7990_softc *sc;
185: {
186: struct le_softc *lesc = (struct le_softc *)sc;
187: u_int32_t csr;
188: int tries = 5;
189:
190: while (--tries) {
191: csr = lesc->sc_dma->sc_regs->csr;
192: csr |= E_TP_AUI;
193: lesc->sc_dma->sc_regs->csr = csr;
194: delay(20000); /* must not touch le for 20ms */
195: if (lesc->sc_dma->sc_regs->csr & E_TP_AUI)
196: return;
197: }
198: }
199:
200: void
201: lesetaui(sc)
202: struct am7990_softc *sc;
203: {
204: struct le_softc *lesc = (struct le_softc *)sc;
205: u_int32_t csr;
206: int tries = 5;
207:
208: while (--tries) {
209: csr = lesc->sc_dma->sc_regs->csr;
210: csr &= ~E_TP_AUI;
211: lesc->sc_dma->sc_regs->csr = csr;
212: delay(20000); /* must not touch le for 20ms */
213: if ((lesc->sc_dma->sc_regs->csr & E_TP_AUI) == 0)
214: return;
215: }
216: }
217: #endif
218:
219: int
220: lemediachange(ifp)
221: struct ifnet *ifp;
222: {
223: struct am7990_softc *sc = ifp->if_softc;
224: struct ifmedia *ifm = &sc->sc_ifmedia;
225: #if defined(SUN4M)
226: struct le_softc *lesc = (struct le_softc *)sc;
227: #endif
228:
229: if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
230: return (EINVAL);
231:
232: /*
233: * Switch to the selected media. If autoselect is
234: * set, we don't really have to do anything. We'll
235: * switch to the other media when we detect loss of
236: * carrier.
237: */
238: switch (IFM_SUBTYPE(ifm->ifm_media)) {
239: #if defined(SUN4M)
240: case IFM_10_T:
241: if (CPU_ISSUN4M && lesc->sc_dma)
242: lesetutp(sc);
243: else
244: return (EOPNOTSUPP);
245: break;
246:
247: case IFM_AUTO:
248: if (CPU_ISSUN4M && lesc->sc_dma)
249: return (0);
250: else
251: return (EOPNOTSUPP);
252: break;
253: #endif
254:
255: case IFM_10_5:
256: #if defined(SUN4M)
257: if (CPU_ISSUN4M && lesc->sc_dma)
258: lesetaui(sc);
259: #else
260: return (0);
261: #endif
262: break;
263:
264:
265: default:
266: return (EINVAL);
267: }
268:
269: return (0);
270: }
271:
272: void
273: lemediastatus(ifp, ifmr)
274: struct ifnet *ifp;
275: struct ifmediareq *ifmr;
276: {
277: #if defined(SUN4M)
278: struct am7990_softc *sc = ifp->if_softc;
279: struct le_softc *lesc = (struct le_softc *)sc;
280:
281: if (lesc->sc_dma == NULL) {
282: if (lesc->sc_lebufchild)
283: ifmr->ifm_active = IFM_ETHER | IFM_10_T;
284: else
285: ifmr->ifm_active = IFM_ETHER | IFM_10_5;
286: return;
287: }
288:
289: if (CPU_ISSUN4M) {
290: /*
291: * Notify the world which media we're currently using.
292: */
293: if (lesc->sc_dma->sc_regs->csr & E_TP_AUI)
294: ifmr->ifm_active = IFM_ETHER | IFM_10_T;
295: else
296: ifmr->ifm_active = IFM_ETHER | IFM_10_5;
297: }
298: else
299: ifmr->ifm_active = IFM_ETHER | IFM_10_5;
300: #else
301: ifmr->ifm_active = IFM_ETHER | IFM_10_5;
302: #endif
303: }
304:
305: hide void
306: lehwreset(sc)
307: struct am7990_softc *sc;
308: {
309: #if defined(SUN4M)
310: struct le_softc *lesc = (struct le_softc *)sc;
311:
312: /*
313: * Reset DMA channel.
314: */
315: if (CPU_ISSUN4M && lesc->sc_dma) {
316: u_int32_t aui;
317:
318: aui = lesc->sc_dma->sc_regs->csr & E_TP_AUI;
319: DMA_RESET(lesc->sc_dma);
320: lesc->sc_dma->sc_regs->en_bar = lesc->sc_laddr & 0xff000000;
321: DMA_ENINTR(lesc->sc_dma);
322: #define D_DSBL_WRINVAL D_DSBL_SCSI_DRN /* XXX: fix dmareg.h */
323: /* Disable E-cache invalidates on chip writes */
324: lesc->sc_dma->sc_regs->csr |= D_DSBL_WRINVAL | aui;
325: delay(20000); /* must not touch le for 20ms */
326: }
327: #endif
328: }
329:
330: hide void
331: lehwinit(sc)
332: struct am7990_softc *sc;
333: {
334: #if defined(SUN4M)
335: struct le_softc *lesc = (struct le_softc *)sc;
336:
337: if (CPU_ISSUN4M && lesc->sc_dma) {
338: switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_cur->ifm_media)) {
339: case IFM_10_T:
340: lesetutp(sc);
341: break;
342:
343: case IFM_10_5:
344: lesetaui(sc);
345: break;
346:
347: case IFM_AUTO:
348: lesetutp(sc);
349: break;
350:
351: default: /* XXX shouldn't happen */
352: lesetutp(sc);
353: break;
354: }
355: }
356: #endif
357: }
358:
359: #if defined(SUN4M)
360: hide void
361: lenocarrier(sc)
362: struct am7990_softc *sc;
363: {
364: struct le_softc *lesc = (struct le_softc *)sc;
365:
366: if (lesc->sc_dma) {
367: /*
368: * Check if the user has requested a certain cable type, and
369: * if so, honor that request.
370: */
371: if (lesc->sc_dma->sc_regs->csr & E_TP_AUI) {
372: switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
373: case IFM_10_5:
374: case IFM_AUTO:
375: printf("%s: lost carrier on UTP port"
376: ", switching to AUI port\n",
377: sc->sc_dev.dv_xname);
378: lesetaui(sc);
379: }
380: } else {
381: switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
382: case IFM_10_T:
383: case IFM_AUTO:
384: printf("%s: lost carrier on AUI port"
385: ", switching to UTP port\n",
386: sc->sc_dev.dv_xname);
387: lesetutp(sc);
388: }
389: }
390: }
391: }
392: #endif
393:
394: int
395: lematch(parent, vcf, aux)
396: struct device *parent;
397: void *vcf, *aux;
398: {
399: struct cfdata *cf = vcf;
400: struct confargs *ca = aux;
401: register struct romaux *ra = &ca->ca_ra;
402:
403: if (strcmp(cf->cf_driver->cd_name, ra->ra_name))
404: return (0);
405: #if defined(solbourne)
406: if (CPU_ISKAP) {
407: return (ca->ca_bustype == BUS_OBIO);
408: }
409: #endif
410: #if defined(SUN4C) || defined(SUN4M)
411: if (ca->ca_bustype == BUS_SBUS) {
412: if (!sbus_testdma((struct sbus_softc *)parent, ca))
413: return (0);
414: return (1);
415: }
416: #endif
417:
418: return (probeget(ra->ra_vaddr, 2) != -1);
419: }
420:
421: void
422: leattach(parent, self, aux)
423: struct device *parent, *self;
424: void *aux;
425: {
426: struct le_softc *lesc = (struct le_softc *)self;
427: struct am7990_softc *sc = &lesc->sc_am7990;
428: struct confargs *ca = aux;
429: int pri;
430: struct bootpath *bp;
431: #if defined(SUN4C) || defined(SUN4M)
432: int sbuschild = strncmp(parent->dv_xname, "sbus", 4) == 0;
433: int lebufchild = strncmp(parent->dv_xname, "lebuffer", 8) == 0;
434: int dmachild = strncmp(parent->dv_xname, "ledma", 5) == 0;
435: struct lebuf_softc *lebuf;
436: #endif
437:
438: /* XXX the following declarations should be elsewhere */
439: extern void myetheraddr(u_char *);
440:
441: if (ca->ca_ra.ra_nintr != 1) {
442: printf(": expected 1 interrupt, got %d\n", ca->ca_ra.ra_nintr);
443: return;
444: }
445: pri = ca->ca_ra.ra_intr[0].int_pri;
446: printf(" pri %d", pri);
447:
448: sc->sc_hasifmedia = 1;
449: #if defined(SUN4C) || defined(SUN4M)
450: lesc->sc_lebufchild = lebufchild;
451: #endif
452:
453: lesc->sc_r1 = (struct lereg1 *)
454: mapiodev(ca->ca_ra.ra_reg, 0, sizeof(struct lereg1));
455:
456: #if defined(SUN4C) || defined(SUN4M)
457: lebuf = NULL;
458: if (lebufchild) {
459: lebuf = (struct lebuf_softc *)parent;
460: } else if (sbuschild) {
461: extern struct cfdriver lebuffer_cd;
462: struct lebuf_softc *lebufsc;
463: int i;
464:
465: for (i = 0; i < lebuffer_cd.cd_ndevs; i++) {
466: lebufsc = (struct lebuf_softc *)lebuffer_cd.cd_devs[i];
467: if (lebufsc == NULL || lebufsc->attached != 0)
468: continue;
469:
470: lebuf = lebufsc;
471: break;
472: }
473: }
474: if (lebuf != NULL) {
475: sc->sc_mem = lebuf->sc_buffer;
476: sc->sc_memsize = lebuf->sc_bufsiz;
477: sc->sc_addr = 0; /* Lance view is offset by buffer location */
478: lebuf->attached = 1;
479:
480: /* That old black magic... */
481: sc->sc_conf3 = getpropint(ca->ca_ra.ra_node,
482: "busmaster-regval",
483: LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON);
484: } else
485: #endif
486: {
487: u_long laddr;
488:
489: #if defined(solbourne)
490: if (CPU_ISKAP && ca->ca_bustype == BUS_OBIO) {
491: /*
492: * Use the fixed buffer allocated in pmap_bootstrap().
493: * for now, until I get the iCU translation to work...
494: */
495: extern vaddr_t lance_va;
496:
497: laddr = PTW1_TO_PHYS(lance_va);
498: sc->sc_mem = (void *)PHYS_TO_PTW2(laddr);
499:
500: /* disable ICU translations for ethernet */
501: sta(ICU_TER, ASI_PHYS_IO,
502: lda(ICU_TER, ASI_PHYS_IO) & ~TER_ETHERNET);
503:
504: /* stash the high 15 bits of the physical address */
505: sta(SE_BASE + 0x18, ASI_PHYS_IO,
506: laddr & 0xfffe0000);
507: } /* else */
508: #endif /* solbourne */
509: #if defined(SUN4) || defined(SUN4C) || defined(SUN4M)
510: #if defined(SUN4C) || defined(SUN4M)
511: if (sbuschild && CPU_ISSUN4M)
512: laddr = (u_long)dvma_malloc_space(MEMSIZE,
513: &sc->sc_mem, M_NOWAIT, M_SPACE_D24);
514: else
515: #endif
516: laddr = (u_long)dvma_malloc(MEMSIZE,
517: &sc->sc_mem, M_NOWAIT);
518: #endif /* SUN4 || SUN4C || SUN4M */
519: #if defined (SUN4M)
520: if ((laddr & 0xffffff) >= (laddr & 0xffffff) + MEMSIZE)
521: panic("if_le: Lance buffer crosses 16MB boundary");
522: #endif
523: #if defined(solbourne)
524: if (CPU_ISKAP && ca->ca_bustype == BUS_OBIO)
525: sc->sc_addr = laddr & 0x01ffff;
526: else
527: #endif
528: sc->sc_addr = laddr & 0xffffff;
529: sc->sc_memsize = MEMSIZE;
530: #if defined(solbourne)
531: if (CPU_ISKAP && ca->ca_bustype == BUS_OBIO)
532: sc->sc_conf3 = LE_C3_BSWP;
533: else
534: #endif
535: sc->sc_conf3 = LE_C3_BSWP | LE_C3_ACON | LE_C3_BCON;
536: #if defined(SUN4C) || defined(SUN4M)
537: if (dmachild) {
538: lesc->sc_dma = (struct dma_softc *)parent;
539: lesc->sc_dma->sc_le = lesc;
540: lesc->sc_laddr = laddr;
541: }
542: #endif
543: }
544:
545: bp = ca->ca_ra.ra_bp;
546: switch (ca->ca_bustype) {
547: #if defined(SUN4C) || defined(SUN4M)
548: #define SAME_LANCE(bp, ca) \
549: ((bp->val[0] == ca->ca_slot && bp->val[1] == ca->ca_offset) || \
550: (bp->val[0] == -1 && bp->val[1] == sc->sc_dev.dv_unit))
551:
552: case BUS_SBUS:
553: if (bp != NULL && strcmp(bp->name, le_cd.cd_name) == 0 &&
554: SAME_LANCE(bp, ca))
555: bp->dev = &sc->sc_dev;
556: break;
557: #endif /* SUN4C || SUN4M */
558:
559: default:
560: if (bp != NULL && strcmp(bp->name, le_cd.cd_name) == 0 &&
561: sc->sc_dev.dv_unit == bp->val[1])
562: bp->dev = &sc->sc_dev;
563: break;
564: }
565:
566: myetheraddr(sc->sc_arpcom.ac_enaddr);
567:
568: sc->sc_copytodesc = am7990_copytobuf_contig;
569: sc->sc_copyfromdesc = am7990_copyfrombuf_contig;
570: sc->sc_copytobuf = am7990_copytobuf_contig;
571: sc->sc_copyfrombuf = am7990_copyfrombuf_contig;
572: sc->sc_zerobuf = am7990_zerobuf_contig;
573:
574: sc->sc_rdcsr = lerdcsr;
575: sc->sc_wrcsr = lewrcsr;
576: sc->sc_hwinit = lehwinit;
577: #if defined(SUN4M)
578: if (CPU_ISSUN4M)
579: sc->sc_nocarrier = lenocarrier;
580: #endif
581: sc->sc_hwreset = lehwreset;
582:
583: ifmedia_init(&sc->sc_ifmedia, 0, lemediachange, lemediastatus);
584: #if defined(SUN4C) || defined(SUN4M)
585: if (lebufchild) {
586: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
587: ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T);
588: } else
589: #endif
590: #if defined(SUN4M)
591: if (CPU_ISSUN4M && lesc->sc_dma) {
592: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
593: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, NULL);
594: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
595: ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO);
596: } else
597: #endif
598: {
599: ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, NULL);
600: ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5);
601: }
602:
603: am7990_config(sc);
604:
605: #if defined(solbourne)
606: if (CPU_ISKAP && ca->ca_bustype == BUS_OBIO) {
607: sc->sc_copytodesc = kap_copytobuf;
608: sc->sc_copyfromdesc = kap_copyfrombuf;
609:
610: sc->sc_initaddr = 1 << 23 | (sc->sc_initaddr & 0x01ffff);
611: sc->sc_rmdaddr = 1 << 23 | (sc->sc_rmdaddr & 0x01ffff);
612: sc->sc_tmdaddr = 1 << 23 | (sc->sc_tmdaddr & 0x01ffff);
613: }
614: #endif
615:
616: lesc->sc_ih.ih_fun = am7990_intr;
617: #if defined(SUN4M) /*XXX*/
618: if (CPU_ISSUN4M && lesc->sc_dma)
619: lesc->sc_ih.ih_fun = myleintr;
620: #endif
621: lesc->sc_ih.ih_arg = sc;
622: intr_establish(pri, &lesc->sc_ih, IPL_NET, self->dv_xname);
623:
624: /* now initialize DMA */
625: lehwreset(sc);
626: }
627:
628: #if defined(solbourne)
629: hide void
630: kap_copytobuf(struct am7990_softc *sc, void *to, int boff, int len)
631: {
632: return (am7990_copytobuf_contig(sc, to, boff & ~(1 << 23), len));
633: }
634: hide void
635: kap_copyfrombuf(struct am7990_softc *sc, void *from, int boff, int len)
636: {
637: return (am7990_copyfrombuf_contig(sc, from, boff & ~(1 << 23), len));
638: }
639: #endif
CVSweb