Annotation of sys/dev/sbus/be.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: be.c,v 1.19 2006/06/02 20:00:56 miod Exp $ */
2: /* $NetBSD: be.c,v 1.26 2001/03/20 15:39:20 pk Exp $ */
3:
4: /*-
5: * Copyright (c) 1999 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Paul Kranenburg.
10: *
11: * Redistribution and use in source and binary forms, with or without
12: * modification, are permitted provided that the following conditions
13: * are met:
14: * 1. Redistributions of source code must retain the above copyright
15: * notice, this list of conditions and the following disclaimer.
16: * 2. Redistributions in binary form must reproduce the above copyright
17: * notice, this list of conditions and the following disclaimer in the
18: * documentation and/or other materials provided with the distribution.
19: * 3. All advertising materials mentioning features or use of this software
20: * must display the following acknowledgement:
21: * This product includes software developed by the NetBSD
22: * Foundation, Inc. and its contributors.
23: * 4. Neither the name of The NetBSD Foundation nor the names of its
24: * contributors may be used to endorse or promote products derived
25: * from this software without specific prior written permission.
26: *
27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37: * POSSIBILITY OF SUCH DAMAGE.
38: */
39:
40: /*
41: * Copyright (c) 1998 Theo de Raadt and Jason L. Wright.
42: * All rights reserved.
43: *
44: * Redistribution and use in source and binary forms, with or without
45: * modification, are permitted provided that the following conditions
46: * are met:
47: * 1. Redistributions of source code must retain the above copyright
48: * notice, this list of conditions and the following disclaimer.
49: * 2. Redistributions in binary form must reproduce the above copyright
50: * notice, this list of conditions and the following disclaimer in the
51: * documentation and/or other materials provided with the distribution.
52: *
53: * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
54: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
55: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
56: * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
57: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
58: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
59: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
60: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
61: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
62: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63: */
64:
65: #include "bpfilter.h"
66:
67: #include <sys/param.h>
68: #include <sys/systm.h>
69: #include <sys/timeout.h>
70: #include <sys/kernel.h>
71: #include <sys/errno.h>
72: #include <sys/ioctl.h>
73: #include <sys/mbuf.h>
74: #include <sys/socket.h>
75: #include <sys/syslog.h>
76: #include <sys/device.h>
77: #include <sys/malloc.h>
78:
79: #include <net/if.h>
80: #include <net/if_dl.h>
81: #include <net/if_types.h>
82: #include <net/netisr.h>
83: #include <net/if_media.h>
84:
85: #ifdef INET
86: #include <netinet/in.h>
87: #include <netinet/in_systm.h>
88: #include <netinet/in_var.h>
89: #include <netinet/ip.h>
90: #include <netinet/if_ether.h>
91: #endif
92:
93: #if NBPFILTER > 0
94: #include <net/bpf.h>
95: #endif
96:
97: #include <machine/bus.h>
98: #include <machine/intr.h>
99: #include <machine/autoconf.h>
100:
101: #include <dev/sbus/sbusvar.h>
102:
103: #include <dev/mii/mii.h>
104: #include <dev/mii/miivar.h>
105:
106: #include <dev/sbus/qecreg.h>
107: #include <dev/sbus/qecvar.h>
108: #include <dev/sbus/bereg.h>
109:
110: struct be_softc {
111: struct device sc_dev;
112: bus_space_tag_t sc_bustag; /* bus & dma tags */
113: bus_dma_tag_t sc_dmatag;
114: bus_dmamap_t sc_dmamap;
115: struct arpcom sc_arpcom;
116: /*struct ifmedia sc_ifmedia; -* interface media */
117: struct mii_data sc_mii; /* MII media control */
118: #define sc_media sc_mii.mii_media/* shorthand */
119: int sc_phys[2]; /* MII instance -> phy */
120:
121: struct timeout sc_tick_ch;
122:
123: /*
124: * Some `mii_softc' items we need to emulate MII operation
125: * for our internal transceiver.
126: */
127: int sc_mii_inst; /* instance of internal phy */
128: int sc_mii_active; /* currently active medium */
129: int sc_mii_ticks; /* tick counter */
130: int sc_mii_flags; /* phy status flags */
131: #define MIIF_HAVELINK 0x04000000
132: int sc_intphy_curspeed; /* Established link speed */
133:
134: struct qec_softc *sc_qec; /* QEC parent */
135:
136: bus_space_handle_t sc_qr; /* QEC registers */
137: bus_space_handle_t sc_br; /* BE registers */
138: bus_space_handle_t sc_cr; /* channel registers */
139: bus_space_handle_t sc_tr; /* transceiver registers */
140:
141: u_int sc_rev;
142:
143: int sc_channel; /* channel number */
144: int sc_burst;
145:
146: struct qec_ring sc_rb; /* Packet Ring Buffer */
147: };
148:
149: int bematch(struct device *, void *, void *);
150: void beattach(struct device *, struct device *, void *);
151:
152: void beinit(struct be_softc *);
153: void bestart(struct ifnet *);
154: void bestop(struct be_softc *);
155: void bewatchdog(struct ifnet *);
156: int beioctl(struct ifnet *, u_long, caddr_t);
157: void bereset(struct be_softc *);
158:
159: int beintr(void *);
160: int berint(struct be_softc *);
161: int betint(struct be_softc *);
162: int beqint(struct be_softc *, u_int32_t);
163: int beeint(struct be_softc *, u_int32_t);
164:
165: static void be_read(struct be_softc *, int, int);
166: static int be_put(struct be_softc *, int, struct mbuf *);
167: static struct mbuf *be_get(struct be_softc *, int, int);
168:
169: void be_pal_gate(struct be_softc *, int);
170:
171: /* ifmedia callbacks */
172: void be_ifmedia_sts(struct ifnet *, struct ifmediareq *);
173: int be_ifmedia_upd(struct ifnet *);
174:
175: void be_mcreset(struct be_softc *);
176:
177: /* MII methods & callbacks */
178: static int be_mii_readreg(struct device *, int, int);
179: static void be_mii_writereg(struct device *, int, int, int);
180: static void be_mii_statchg(struct device *);
181:
182: /* MII helpers */
183: static void be_mii_sync(struct be_softc *);
184: static void be_mii_sendbits(struct be_softc *, int, u_int32_t, int);
185: static int be_mii_reset(struct be_softc *, int);
186: static int be_tcvr_read_bit(struct be_softc *, int);
187: static void be_tcvr_write_bit(struct be_softc *, int, int);
188:
189: void be_tick(void *);
190: void be_intphy_auto(struct be_softc *);
191: void be_intphy_status(struct be_softc *);
192: int be_intphy_service(struct be_softc *, struct mii_data *, int);
193:
194:
195: struct cfattach be_ca = {
196: sizeof(struct be_softc), bematch, beattach
197: };
198:
199: struct cfdriver be_cd = {
200: NULL, "be", DV_IFNET
201: };
202:
203: int
204: bematch(struct device *parent, void *vcf, void *aux)
205: {
206: struct cfdata *cf = vcf;
207: struct sbus_attach_args *sa = aux;
208:
209: return (strcmp(cf->cf_driver->cd_name, sa->sa_name) == 0);
210: }
211:
212: void
213: beattach(struct device *parent, struct device *self, void *aux)
214: {
215: struct sbus_attach_args *sa = aux;
216: struct qec_softc *qec = (struct qec_softc *)parent;
217: struct be_softc *sc = (struct be_softc *)self;
218: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
219: struct mii_data *mii = &sc->sc_mii;
220: struct mii_softc *child;
221: int node = sa->sa_node;
222: bus_dma_tag_t dmatag = sa->sa_dmatag;
223: bus_dma_segment_t seg;
224: bus_size_t size;
225: int instance;
226: int rseg, error;
227: u_int32_t v;
228: extern void myetheraddr(u_char *);
229:
230: /* Pass on the bus tags */
231: sc->sc_bustag = sa->sa_bustag;
232: sc->sc_dmatag = sa->sa_dmatag;
233:
234: if (sa->sa_nreg < 3) {
235: printf("%s: only %d register sets\n",
236: self->dv_xname, sa->sa_nreg);
237: return;
238: }
239:
240: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[0].sbr_slot,
241: (bus_addr_t)sa->sa_reg[0].sbr_offset,
242: (bus_size_t)sa->sa_reg[0].sbr_size, 0, 0, &sc->sc_cr) != 0) {
243: printf("beattach: cannot map registers\n");
244: return;
245: }
246:
247: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[1].sbr_slot,
248: (bus_addr_t)sa->sa_reg[1].sbr_offset,
249: (bus_size_t)sa->sa_reg[1].sbr_size, 0, 0, &sc->sc_br) != 0) {
250: printf("beattach: cannot map registers\n");
251: return;
252: }
253:
254: if (sbus_bus_map(sa->sa_bustag, sa->sa_reg[2].sbr_slot,
255: (bus_addr_t)sa->sa_reg[2].sbr_offset,
256: (bus_size_t)sa->sa_reg[2].sbr_size, 0, 0, &sc->sc_tr) != 0) {
257: printf("beattach: cannot map registers\n");
258: return;
259: }
260:
261: sc->sc_qec = qec;
262: sc->sc_qr = qec->sc_regs;
263:
264: sc->sc_rev = getpropint(node, "board-version", -1);
265: printf(" rev %x", sc->sc_rev);
266:
267: bestop(sc);
268:
269: sc->sc_channel = getpropint(node, "channel#", -1);
270: if (sc->sc_channel == -1)
271: sc->sc_channel = 0;
272:
273: sc->sc_burst = getpropint(node, "burst-sizes", -1);
274: if (sc->sc_burst == -1)
275: sc->sc_burst = qec->sc_burst;
276:
277: /* Clamp at parent's burst sizes */
278: sc->sc_burst &= qec->sc_burst;
279:
280: /* Establish interrupt handler */
281: if (sa->sa_nintr == 0 || bus_intr_establish(sa->sa_bustag, sa->sa_pri,
282: IPL_NET, 0, beintr, sc, self->dv_xname) == NULL) {
283: printf(": no interrupt established\n");
284: return;
285: }
286:
287: myetheraddr(sc->sc_arpcom.ac_enaddr);
288: printf(" address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
289:
290: /*
291: * Allocate descriptor ring and buffers.
292: */
293:
294: /* for now, allocate as many bufs as there are ring descriptors */
295: sc->sc_rb.rb_ntbuf = QEC_XD_RING_MAXSIZE;
296: sc->sc_rb.rb_nrbuf = QEC_XD_RING_MAXSIZE;
297:
298: size = QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd) +
299: QEC_XD_RING_MAXSIZE * sizeof(struct qec_xd) +
300: sc->sc_rb.rb_ntbuf * BE_PKT_BUF_SZ +
301: sc->sc_rb.rb_nrbuf * BE_PKT_BUF_SZ;
302:
303: /* Get a DMA handle */
304: if ((error = bus_dmamap_create(dmatag, size, 1, size, 0,
305: BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
306: printf("%s: DMA map create error %d\n", self->dv_xname, error);
307: return;
308: }
309:
310: /* Allocate DMA buffer */
311: if ((error = bus_dmamem_alloc(sa->sa_dmatag, size, 0, 0,
312: &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
313: printf("%s: DMA buffer alloc error %d\n",
314: self->dv_xname, error);
315: return;
316: }
317:
318: /* Map DMA memory in CPU addressable space */
319: if ((error = bus_dmamem_map(sa->sa_dmatag, &seg, rseg, size,
320: &sc->sc_rb.rb_membase, BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
321: printf("%s: DMA buffer map error %d\n",
322: self->dv_xname, error);
323: bus_dmamem_free(sa->sa_dmatag, &seg, rseg);
324: return;
325: }
326:
327: /* Load the buffer */
328: if ((error = bus_dmamap_load(dmatag, sc->sc_dmamap,
329: sc->sc_rb.rb_membase, size, NULL, BUS_DMA_NOWAIT)) != 0) {
330: printf("%s: DMA buffer map load error %d\n",
331: self->dv_xname, error);
332: bus_dmamem_unmap(dmatag, sc->sc_rb.rb_membase, size);
333: bus_dmamem_free(dmatag, &seg, rseg);
334: return;
335: }
336: sc->sc_rb.rb_dmabase = sc->sc_dmamap->dm_segs[0].ds_addr;
337:
338: /*
339: * Initialize our media structures and MII info.
340: */
341: mii->mii_ifp = ifp;
342: mii->mii_readreg = be_mii_readreg;
343: mii->mii_writereg = be_mii_writereg;
344: mii->mii_statchg = be_mii_statchg;
345:
346: ifmedia_init(&mii->mii_media, 0, be_ifmedia_upd, be_ifmedia_sts);
347:
348: timeout_set(&sc->sc_tick_ch, be_tick, sc);
349:
350: /*
351: * Initialize transceiver and determine which PHY connection to use.
352: */
353: be_mii_sync(sc);
354: v = bus_space_read_4(sc->sc_bustag, sc->sc_tr, BE_TRI_MGMTPAL);
355:
356: instance = 0;
357:
358: if ((v & MGMT_PAL_EXT_MDIO) != 0) {
359:
360: mii_attach(&sc->sc_dev, mii, 0xffffffff, BE_PHY_EXTERNAL,
361: MII_OFFSET_ANY, 0);
362:
363: child = LIST_FIRST(&mii->mii_phys);
364: if (child == NULL) {
365: /* No PHY attached */
366: ifmedia_add(&sc->sc_media,
367: IFM_MAKEWORD(IFM_ETHER,IFM_NONE,0,instance),
368: 0, NULL);
369: ifmedia_set(&sc->sc_media,
370: IFM_MAKEWORD(IFM_ETHER,IFM_NONE,0,instance));
371: } else {
372: /*
373: * Note: we support just one PHY on the external
374: * MII connector.
375: */
376: #ifdef DIAGNOSTIC
377: if (LIST_NEXT(child, mii_list) != NULL) {
378: printf("%s: spurious MII device %s attached\n",
379: sc->sc_dev.dv_xname,
380: child->mii_dev.dv_xname);
381: }
382: #endif
383: if (child->mii_phy != BE_PHY_EXTERNAL ||
384: child->mii_inst > 0) {
385: printf("%s: cannot accommodate MII device %s"
386: " at phy %d, instance %d\n",
387: sc->sc_dev.dv_xname,
388: child->mii_dev.dv_xname,
389: child->mii_phy, child->mii_inst);
390: } else {
391: sc->sc_phys[instance] = child->mii_phy;
392: }
393:
394: /*
395: * XXX - we can really do the following ONLY if the
396: * phy indeed has the auto negotiation capability!!
397: */
398: ifmedia_set(&sc->sc_media,
399: IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance));
400:
401: /* Mark our current media setting */
402: be_pal_gate(sc, BE_PHY_EXTERNAL);
403: instance++;
404: }
405:
406: }
407:
408: if ((v & MGMT_PAL_INT_MDIO) != 0) {
409: /*
410: * The be internal phy looks vaguely like MII hardware,
411: * but not enough to be able to use the MII device
412: * layer. Hence, we have to take care of media selection
413: * ourselves.
414: */
415:
416: sc->sc_mii_inst = instance;
417: sc->sc_phys[instance] = BE_PHY_INTERNAL;
418:
419: /* Use `ifm_data' to store BMCR bits */
420: ifmedia_add(&sc->sc_media,
421: IFM_MAKEWORD(IFM_ETHER,IFM_10_T,0,instance), 0, NULL);
422: ifmedia_add(&sc->sc_media,
423: IFM_MAKEWORD(IFM_ETHER,IFM_100_TX,0,instance),
424: BMCR_S100, NULL);
425: ifmedia_add(&sc->sc_media,
426: IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance), 0, NULL);
427:
428: printf("on-board transceiver at %s: 10baseT, 100baseTX, auto\n",
429: self->dv_xname);
430:
431: be_mii_reset(sc, BE_PHY_INTERNAL);
432: /* Only set default medium here if there's no external PHY */
433: if (instance == 0) {
434: be_pal_gate(sc, BE_PHY_INTERNAL);
435: ifmedia_set(&sc->sc_media,
436: IFM_MAKEWORD(IFM_ETHER,IFM_AUTO,0,instance));
437: } else
438: be_mii_writereg((void *)sc,
439: BE_PHY_INTERNAL, MII_BMCR, BMCR_ISO);
440: }
441:
442: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
443: ifp->if_softc = sc;
444: ifp->if_start = bestart;
445: ifp->if_ioctl = beioctl;
446: ifp->if_watchdog = bewatchdog;
447: ifp->if_flags =
448: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
449: IFQ_SET_READY(&ifp->if_snd);
450:
451: /* Attach the interface. */
452: if_attach(ifp);
453: ether_ifattach(ifp);
454: }
455:
456:
457: /*
458: * Routine to copy from mbuf chain to transmit buffer in
459: * network buffer memory.
460: */
461: static __inline__ int
462: be_put(struct be_softc *sc, int idx, struct mbuf *m)
463: {
464: struct mbuf *n;
465: int len, tlen = 0, boff = 0;
466: caddr_t bp;
467:
468: bp = sc->sc_rb.rb_txbuf + (idx % sc->sc_rb.rb_ntbuf) * BE_PKT_BUF_SZ;
469:
470: for (; m; m = n) {
471: len = m->m_len;
472: if (len == 0) {
473: MFREE(m, n);
474: continue;
475: }
476: bcopy(mtod(m, caddr_t), bp+boff, len);
477: boff += len;
478: tlen += len;
479: MFREE(m, n);
480: }
481: return (tlen);
482: }
483:
484: /*
485: * Pull data off an interface.
486: * Len is the length of data, with local net header stripped.
487: * We copy the data into mbufs. When full cluster sized units are present,
488: * we copy into clusters.
489: */
490: static __inline__ struct mbuf *
491: be_get(struct be_softc *sc, int idx, int totlen)
492: {
493: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
494: struct mbuf *m;
495: struct mbuf *top, **mp;
496: int len, pad, boff = 0;
497: caddr_t bp;
498:
499: bp = sc->sc_rb.rb_rxbuf + (idx % sc->sc_rb.rb_nrbuf) * BE_PKT_BUF_SZ;
500:
501: MGETHDR(m, M_DONTWAIT, MT_DATA);
502: if (m == NULL)
503: return (NULL);
504: m->m_pkthdr.rcvif = ifp;
505: m->m_pkthdr.len = totlen;
506:
507: pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
508: m->m_data += pad;
509: len = MHLEN - pad;
510: top = NULL;
511: mp = ⊤
512:
513: while (totlen > 0) {
514: if (top) {
515: MGET(m, M_DONTWAIT, MT_DATA);
516: if (m == NULL) {
517: m_freem(top);
518: return (NULL);
519: }
520: len = MLEN;
521: }
522: if (top && totlen >= MINCLSIZE) {
523: MCLGET(m, M_DONTWAIT);
524: if (m->m_flags & M_EXT)
525: len = MCLBYTES;
526: }
527: m->m_len = len = min(totlen, len);
528: bcopy(bp + boff, mtod(m, caddr_t), len);
529: boff += len;
530: totlen -= len;
531: *mp = m;
532: mp = &m->m_next;
533: }
534:
535: return (top);
536: }
537:
538: /*
539: * Pass a packet to the higher levels.
540: */
541: static __inline__ void
542: be_read(struct be_softc *sc, int idx, int len)
543: {
544: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
545: struct mbuf *m;
546:
547: if (len <= sizeof(struct ether_header) ||
548: len > ETHERMTU + sizeof(struct ether_header)) {
549:
550: printf("%s: invalid packet size %d; dropping\n",
551: ifp->if_xname, len);
552:
553: ifp->if_ierrors++;
554: return;
555: }
556:
557: /*
558: * Pull packet off interface.
559: */
560: m = be_get(sc, idx, len);
561: if (m == NULL) {
562: ifp->if_ierrors++;
563: return;
564: }
565: ifp->if_ipackets++;
566:
567: #if NBPFILTER > 0
568: /*
569: * Check if there's a BPF listener on this interface.
570: * If so, hand off the raw packet to BPF.
571: */
572: if (ifp->if_bpf)
573: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
574: #endif
575: /* Pass the packet up. */
576: ether_input_mbuf(ifp, m);
577: }
578:
579: /*
580: * Start output on interface.
581: * We make two assumptions here:
582: * 1) that the current priority is set to splnet _before_ this code
583: * is called *and* is returned to the appropriate priority after
584: * return
585: * 2) that the IFF_OACTIVE flag is checked before this code is called
586: * (i.e. that the output part of the interface is idle)
587: */
588: void
589: bestart(struct ifnet *ifp)
590: {
591: struct be_softc *sc = (struct be_softc *)ifp->if_softc;
592: struct qec_xd *txd = sc->sc_rb.rb_txd;
593: struct mbuf *m;
594: unsigned int bix, len;
595: unsigned int ntbuf = sc->sc_rb.rb_ntbuf;
596:
597: if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
598: return;
599:
600: bix = sc->sc_rb.rb_tdhead;
601:
602: for (;;) {
603: IFQ_DEQUEUE(&ifp->if_snd, m);
604: if (m == 0)
605: break;
606:
607: #if NBPFILTER > 0
608: /*
609: * If BPF is listening on this interface, let it see the
610: * packet before we commit it to the wire.
611: */
612: if (ifp->if_bpf)
613: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
614: #endif
615:
616: /*
617: * Copy the mbuf chain into the transmit buffer.
618: */
619: len = be_put(sc, bix, m);
620:
621: /*
622: * Initialize transmit registers and start transmission
623: */
624: txd[bix].xd_flags = QEC_XD_OWN | QEC_XD_SOP | QEC_XD_EOP |
625: (len & QEC_XD_LENGTH);
626: bus_space_write_4(sc->sc_bustag, sc->sc_cr, BE_CRI_CTRL,
627: BE_CR_CTRL_TWAKEUP);
628:
629: if (++bix == QEC_XD_RING_MAXSIZE)
630: bix = 0;
631:
632: if (++sc->sc_rb.rb_td_nbusy == ntbuf) {
633: ifp->if_flags |= IFF_OACTIVE;
634: break;
635: }
636: }
637:
638: sc->sc_rb.rb_tdhead = bix;
639: }
640:
641: void
642: bestop(struct be_softc *sc)
643: {
644: int n;
645: bus_space_tag_t t = sc->sc_bustag;
646: bus_space_handle_t br = sc->sc_br;
647:
648: timeout_del(&sc->sc_tick_ch);
649:
650: /* Down the MII. */
651: mii_down(&sc->sc_mii);
652: (void)be_intphy_service(sc, &sc->sc_mii, MII_DOWN);
653:
654: /* Stop the transmitter */
655: bus_space_write_4(t, br, BE_BRI_TXCFG, 0);
656: for (n = 32; n > 0; n--) {
657: if (bus_space_read_4(t, br, BE_BRI_TXCFG) == 0)
658: break;
659: DELAY(20);
660: }
661:
662: /* Stop the receiver */
663: bus_space_write_4(t, br, BE_BRI_RXCFG, 0);
664: for (n = 32; n > 0; n--) {
665: if (bus_space_read_4(t, br, BE_BRI_RXCFG) == 0)
666: break;
667: DELAY(20);
668: }
669: }
670:
671: /*
672: * Reset interface.
673: */
674: void
675: bereset(struct be_softc *sc)
676: {
677: int s;
678:
679: s = splnet();
680: bestop(sc);
681: if ((sc->sc_arpcom.ac_if.if_flags & IFF_UP) != 0)
682: beinit(sc);
683: splx(s);
684: }
685:
686: void
687: bewatchdog(struct ifnet *ifp)
688: {
689: struct be_softc *sc = ifp->if_softc;
690:
691: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
692: ++sc->sc_arpcom.ac_if.if_oerrors;
693: bereset(sc);
694: }
695:
696: int
697: beintr(void *v)
698: {
699: struct be_softc *sc = (struct be_softc *)v;
700: bus_space_tag_t t = sc->sc_bustag;
701: u_int32_t whyq, whyb, whyc;
702: int r = 0;
703:
704: /* Read QEC status, channel status and BE status */
705: whyq = bus_space_read_4(t, sc->sc_qr, QEC_QRI_STAT);
706: whyc = bus_space_read_4(t, sc->sc_cr, BE_CRI_STAT);
707: whyb = bus_space_read_4(t, sc->sc_br, BE_BRI_STAT);
708:
709: if (whyq & QEC_STAT_BM)
710: r |= beeint(sc, whyb);
711:
712: if (whyq & QEC_STAT_ER)
713: r |= beqint(sc, whyc);
714:
715: if (whyq & QEC_STAT_TX && whyc & BE_CR_STAT_TXIRQ)
716: r |= betint(sc);
717:
718: if (whyq & QEC_STAT_RX && whyc & BE_CR_STAT_RXIRQ)
719: r |= berint(sc);
720:
721: return (r);
722: }
723:
724: /*
725: * QEC Interrupt.
726: */
727: int
728: beqint(struct be_softc *sc, u_int32_t why)
729: {
730: int r = 0, rst = 0;
731:
732: if (why & BE_CR_STAT_TXIRQ)
733: r |= 1;
734: if (why & BE_CR_STAT_RXIRQ)
735: r |= 1;
736:
737: if (why & BE_CR_STAT_BERROR) {
738: r |= 1;
739: rst = 1;
740: printf("%s: bigmac error\n", sc->sc_dev.dv_xname);
741: }
742:
743: if (why & BE_CR_STAT_TXDERR) {
744: r |= 1;
745: rst = 1;
746: printf("%s: bogus tx descriptor\n", sc->sc_dev.dv_xname);
747: }
748:
749: if (why & (BE_CR_STAT_TXLERR | BE_CR_STAT_TXPERR | BE_CR_STAT_TXSERR)) {
750: r |= 1;
751: rst = 1;
752: printf("%s: tx dma error ( ", sc->sc_dev.dv_xname);
753: if (why & BE_CR_STAT_TXLERR)
754: printf("Late ");
755: if (why & BE_CR_STAT_TXPERR)
756: printf("Parity ");
757: if (why & BE_CR_STAT_TXSERR)
758: printf("Generic ");
759: printf(")\n");
760: }
761:
762: if (why & BE_CR_STAT_RXDROP) {
763: r |= 1;
764: rst = 1;
765: printf("%s: out of rx descriptors\n", sc->sc_dev.dv_xname);
766: }
767:
768: if (why & BE_CR_STAT_RXSMALL) {
769: r |= 1;
770: rst = 1;
771: printf("%s: rx descriptor too small\n", sc->sc_dev.dv_xname);
772: }
773:
774: if (why & (BE_CR_STAT_RXLERR | BE_CR_STAT_RXPERR | BE_CR_STAT_RXSERR)) {
775: r |= 1;
776: rst = 1;
777: printf("%s: rx dma error ( ", sc->sc_dev.dv_xname);
778: if (why & BE_CR_STAT_RXLERR)
779: printf("Late ");
780: if (why & BE_CR_STAT_RXPERR)
781: printf("Parity ");
782: if (why & BE_CR_STAT_RXSERR)
783: printf("Generic ");
784: printf(")\n");
785: }
786:
787: if (!r) {
788: rst = 1;
789: printf("%s: unexpected error interrupt %08x\n",
790: sc->sc_dev.dv_xname, why);
791: }
792:
793: if (rst) {
794: printf("%s: resetting\n", sc->sc_dev.dv_xname);
795: bereset(sc);
796: }
797:
798: return (r);
799: }
800:
801: /*
802: * Error interrupt.
803: */
804: int
805: beeint(struct be_softc *sc, u_int32_t why)
806: {
807: int r = 0, rst = 0;
808:
809: if (why & BE_BR_STAT_RFIFOVF) {
810: r |= 1;
811: rst = 1;
812: printf("%s: receive fifo overrun\n", sc->sc_dev.dv_xname);
813: }
814: if (why & BE_BR_STAT_TFIFO_UND) {
815: r |= 1;
816: rst = 1;
817: printf("%s: transmit fifo underrun\n", sc->sc_dev.dv_xname);
818: }
819: if (why & BE_BR_STAT_MAXPKTERR) {
820: r |= 1;
821: rst = 1;
822: printf("%s: max packet size error\n", sc->sc_dev.dv_xname);
823: }
824:
825: if (!r) {
826: rst = 1;
827: printf("%s: unexpected error interrupt %08x\n",
828: sc->sc_dev.dv_xname, why);
829: }
830:
831: if (rst) {
832: printf("%s: resetting\n", sc->sc_dev.dv_xname);
833: bereset(sc);
834: }
835:
836: return (r);
837: }
838:
839: /*
840: * Transmit interrupt.
841: */
842: int
843: betint(struct be_softc *sc)
844: {
845: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
846: bus_space_tag_t t = sc->sc_bustag;
847: bus_space_handle_t br = sc->sc_br;
848: unsigned int bix, txflags;
849:
850: /*
851: * Unload collision counters
852: */
853: ifp->if_collisions +=
854: bus_space_read_4(t, br, BE_BRI_NCCNT) +
855: bus_space_read_4(t, br, BE_BRI_FCCNT) +
856: bus_space_read_4(t, br, BE_BRI_EXCNT) +
857: bus_space_read_4(t, br, BE_BRI_LTCNT);
858:
859: /*
860: * the clear the hardware counters
861: */
862: bus_space_write_4(t, br, BE_BRI_NCCNT, 0);
863: bus_space_write_4(t, br, BE_BRI_FCCNT, 0);
864: bus_space_write_4(t, br, BE_BRI_EXCNT, 0);
865: bus_space_write_4(t, br, BE_BRI_LTCNT, 0);
866:
867: bix = sc->sc_rb.rb_tdtail;
868:
869: for (;;) {
870: if (sc->sc_rb.rb_td_nbusy <= 0)
871: break;
872:
873: txflags = sc->sc_rb.rb_txd[bix].xd_flags;
874:
875: if (txflags & QEC_XD_OWN)
876: break;
877:
878: ifp->if_flags &= ~IFF_OACTIVE;
879: ifp->if_opackets++;
880:
881: if (++bix == QEC_XD_RING_MAXSIZE)
882: bix = 0;
883:
884: --sc->sc_rb.rb_td_nbusy;
885: }
886:
887: sc->sc_rb.rb_tdtail = bix;
888:
889: bestart(ifp);
890:
891: if (sc->sc_rb.rb_td_nbusy == 0)
892: ifp->if_timer = 0;
893:
894: return (1);
895: }
896:
897: /*
898: * Receive interrupt.
899: */
900: int
901: berint(struct be_softc *sc)
902: {
903: struct qec_xd *xd = sc->sc_rb.rb_rxd;
904: unsigned int bix, len;
905: unsigned int nrbuf = sc->sc_rb.rb_nrbuf;
906:
907: bix = sc->sc_rb.rb_rdtail;
908:
909: /*
910: * Process all buffers with valid data.
911: */
912: for (;;) {
913: len = xd[bix].xd_flags;
914: if (len & QEC_XD_OWN)
915: break;
916:
917: len &= QEC_XD_LENGTH;
918: be_read(sc, bix, len);
919:
920: /* ... */
921: xd[(bix+nrbuf) % QEC_XD_RING_MAXSIZE].xd_flags =
922: QEC_XD_OWN | (BE_PKT_BUF_SZ & QEC_XD_LENGTH);
923:
924: if (++bix == QEC_XD_RING_MAXSIZE)
925: bix = 0;
926: }
927:
928: sc->sc_rb.rb_rdtail = bix;
929:
930: return (1);
931: }
932:
933: int
934: beioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
935: {
936: struct be_softc *sc = ifp->if_softc;
937: struct ifaddr *ifa = (struct ifaddr *)data;
938: struct ifreq *ifr = (struct ifreq *)data;
939: int s, error = 0;
940:
941: s = splnet();
942:
943: if ((error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data)) > 0) {
944: splx(s);
945: return (error);
946: }
947:
948: switch (cmd) {
949: case SIOCSIFADDR:
950: ifp->if_flags |= IFF_UP;
951: switch (ifa->ifa_addr->sa_family) {
952: #ifdef INET
953: case AF_INET:
954: beinit(sc);
955: arp_ifinit(&sc->sc_arpcom, ifa);
956: break;
957: #endif /* INET */
958: default:
959: beinit(sc);
960: break;
961: }
962: break;
963:
964: case SIOCSIFFLAGS:
965: if ((ifp->if_flags & IFF_UP) == 0 &&
966: (ifp->if_flags & IFF_RUNNING) != 0) {
967: /*
968: * If interface is marked down and it is running, then
969: * stop it.
970: */
971: bestop(sc);
972: ifp->if_flags &= ~IFF_RUNNING;
973: } else if ((ifp->if_flags & IFF_UP) != 0 &&
974: (ifp->if_flags & IFF_RUNNING) == 0) {
975: /*
976: * If interface is marked up and it is stopped, then
977: * start it.
978: */
979: beinit(sc);
980: } else {
981: /*
982: * Reset the interface to pick up changes in any other
983: * flags that affect hardware registers.
984: */
985: bestop(sc);
986: beinit(sc);
987: }
988: #ifdef BEDEBUG
989: if (ifp->if_flags & IFF_DEBUG)
990: sc->sc_debug = 1;
991: else
992: sc->sc_debug = 0;
993: #endif
994: break;
995:
996: case SIOCADDMULTI:
997: case SIOCDELMULTI:
998: error = (cmd == SIOCADDMULTI) ?
999: ether_addmulti(ifr, &sc->sc_arpcom):
1000: ether_delmulti(ifr, &sc->sc_arpcom);
1001:
1002: if (error == ENETRESET) {
1003: /*
1004: * Multicast list has changed; set the hardware filter
1005: * accordingly.
1006: */
1007: if (ifp->if_flags & IFF_RUNNING)
1008: be_mcreset(sc);
1009: error = 0;
1010: }
1011: break;
1012: case SIOCGIFMEDIA:
1013: case SIOCSIFMEDIA:
1014: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
1015: break;
1016: default:
1017: error = EINVAL;
1018: break;
1019: }
1020: splx(s);
1021: return (error);
1022: }
1023:
1024:
1025: void
1026: beinit(struct be_softc *sc)
1027: {
1028: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
1029: bus_space_tag_t t = sc->sc_bustag;
1030: bus_space_handle_t br = sc->sc_br;
1031: bus_space_handle_t cr = sc->sc_cr;
1032: struct qec_softc *qec = sc->sc_qec;
1033: u_int32_t v;
1034: u_int32_t qecaddr;
1035: u_int8_t *ea;
1036: int s;
1037:
1038: s = splnet();
1039:
1040: qec_meminit(&sc->sc_rb, BE_PKT_BUF_SZ);
1041:
1042: bestop(sc);
1043:
1044: ea = sc->sc_arpcom.ac_enaddr;
1045: bus_space_write_4(t, br, BE_BRI_MACADDR0, (ea[0] << 8) | ea[1]);
1046: bus_space_write_4(t, br, BE_BRI_MACADDR1, (ea[2] << 8) | ea[3]);
1047: bus_space_write_4(t, br, BE_BRI_MACADDR2, (ea[4] << 8) | ea[5]);
1048:
1049: /* Clear hash table */
1050: bus_space_write_4(t, br, BE_BRI_HASHTAB0, 0);
1051: bus_space_write_4(t, br, BE_BRI_HASHTAB1, 0);
1052: bus_space_write_4(t, br, BE_BRI_HASHTAB2, 0);
1053: bus_space_write_4(t, br, BE_BRI_HASHTAB3, 0);
1054:
1055: /* Re-initialize RX configuration */
1056: v = BE_BR_RXCFG_FIFO;
1057: bus_space_write_4(t, br, BE_BRI_RXCFG, v);
1058:
1059: be_mcreset(sc);
1060:
1061: bus_space_write_4(t, br, BE_BRI_RANDSEED, 0xbd);
1062:
1063: bus_space_write_4(t, br, BE_BRI_XIFCFG,
1064: BE_BR_XCFG_ODENABLE | BE_BR_XCFG_RESV);
1065:
1066: bus_space_write_4(t, br, BE_BRI_JSIZE, 4);
1067:
1068: /*
1069: * Turn off counter expiration interrupts as well as
1070: * 'gotframe' and 'sentframe'
1071: */
1072: bus_space_write_4(t, br, BE_BRI_IMASK,
1073: BE_BR_IMASK_GOTFRAME |
1074: BE_BR_IMASK_RCNTEXP |
1075: BE_BR_IMASK_ACNTEXP |
1076: BE_BR_IMASK_CCNTEXP |
1077: BE_BR_IMASK_LCNTEXP |
1078: BE_BR_IMASK_CVCNTEXP |
1079: BE_BR_IMASK_SENTFRAME |
1080: BE_BR_IMASK_NCNTEXP |
1081: BE_BR_IMASK_ECNTEXP |
1082: BE_BR_IMASK_LCCNTEXP |
1083: BE_BR_IMASK_FCNTEXP |
1084: BE_BR_IMASK_DTIMEXP);
1085:
1086: /* Channel registers: */
1087: bus_space_write_4(t, cr, BE_CRI_RXDS, (u_int32_t)sc->sc_rb.rb_rxddma);
1088: bus_space_write_4(t, cr, BE_CRI_TXDS, (u_int32_t)sc->sc_rb.rb_txddma);
1089:
1090: qecaddr = sc->sc_channel * qec->sc_msize;
1091: bus_space_write_4(t, cr, BE_CRI_RXWBUF, qecaddr);
1092: bus_space_write_4(t, cr, BE_CRI_RXRBUF, qecaddr);
1093: bus_space_write_4(t, cr, BE_CRI_TXWBUF, qecaddr + qec->sc_rsize);
1094: bus_space_write_4(t, cr, BE_CRI_TXRBUF, qecaddr + qec->sc_rsize);
1095:
1096: bus_space_write_4(t, cr, BE_CRI_RIMASK, 0);
1097: bus_space_write_4(t, cr, BE_CRI_TIMASK, 0);
1098: bus_space_write_4(t, cr, BE_CRI_QMASK, 0);
1099: bus_space_write_4(t, cr, BE_CRI_BMASK, 0);
1100: bus_space_write_4(t, cr, BE_CRI_CCNT, 0);
1101:
1102: /* Enable transmitter */
1103: bus_space_write_4(t, br, BE_BRI_TXCFG,
1104: BE_BR_TXCFG_FIFO | BE_BR_TXCFG_ENABLE);
1105:
1106: /* Enable receiver */
1107: v = bus_space_read_4(t, br, BE_BRI_RXCFG);
1108: v |= BE_BR_RXCFG_FIFO | BE_BR_RXCFG_ENABLE;
1109: bus_space_write_4(t, br, BE_BRI_RXCFG, v);
1110:
1111: ifp->if_flags |= IFF_RUNNING;
1112: ifp->if_flags &= ~IFF_OACTIVE;
1113:
1114: be_ifmedia_upd(ifp);
1115: timeout_add(&sc->sc_tick_ch, hz);
1116: splx(s);
1117: }
1118:
1119: void
1120: be_mcreset(struct be_softc *sc)
1121: {
1122: struct arpcom *ac = &sc->sc_arpcom;
1123: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
1124: bus_space_tag_t t = sc->sc_bustag;
1125: bus_space_handle_t br = sc->sc_br;
1126: u_int32_t crc;
1127: u_int16_t hash[4];
1128: u_int8_t octet;
1129: u_int32_t v;
1130: int i, j;
1131: struct ether_multi *enm;
1132: struct ether_multistep step;
1133:
1134: if (ifp->if_flags & IFF_PROMISC) {
1135: v = bus_space_read_4(t, br, BE_BRI_RXCFG);
1136: v |= BE_BR_RXCFG_PMISC;
1137: bus_space_write_4(t, br, BE_BRI_RXCFG, v);
1138: return;
1139: }
1140:
1141: if (ifp->if_flags & IFF_ALLMULTI) {
1142: hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
1143: goto chipit;
1144: }
1145:
1146: hash[3] = hash[2] = hash[1] = hash[0] = 0;
1147:
1148: ETHER_FIRST_MULTI(step, ac, enm);
1149: while (enm != NULL) {
1150: if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
1151: /*
1152: * We must listen to a range of multicast
1153: * addresses. For now, just accept all
1154: * multicasts, rather than trying to set only
1155: * those filter bits needed to match the range.
1156: * (At this time, the only use of address
1157: * ranges is for IP multicast routing, for
1158: * which the range is big enough to require
1159: * all bits set.)
1160: */
1161: hash[3] = hash[2] = hash[1] = hash[0] = 0xffff;
1162: ifp->if_flags |= IFF_ALLMULTI;
1163: goto chipit;
1164: }
1165:
1166: crc = 0xffffffff;
1167:
1168: for (i = 0; i < ETHER_ADDR_LEN; i++) {
1169: octet = enm->enm_addrlo[i];
1170:
1171: for (j = 0; j < 8; j++) {
1172: if ((crc & 1) ^ (octet & 1)) {
1173: crc >>= 1;
1174: crc ^= MC_POLY_LE;
1175: }
1176: else
1177: crc >>= 1;
1178: octet >>= 1;
1179: }
1180: }
1181:
1182: crc >>= 26;
1183: hash[crc >> 4] |= 1 << (crc & 0xf);
1184: ETHER_NEXT_MULTI(step, enm);
1185: }
1186:
1187: ifp->if_flags &= ~IFF_ALLMULTI;
1188:
1189: chipit:
1190: /* Enable the hash filter */
1191: bus_space_write_4(t, br, BE_BRI_HASHTAB0, hash[0]);
1192: bus_space_write_4(t, br, BE_BRI_HASHTAB1, hash[1]);
1193: bus_space_write_4(t, br, BE_BRI_HASHTAB2, hash[2]);
1194: bus_space_write_4(t, br, BE_BRI_HASHTAB3, hash[3]);
1195:
1196: v = bus_space_read_4(t, br, BE_BRI_RXCFG);
1197: v &= ~BE_BR_RXCFG_PMISC;
1198: v |= BE_BR_RXCFG_HENABLE;
1199: bus_space_write_4(t, br, BE_BRI_RXCFG, v);
1200: }
1201:
1202: /*
1203: * Set the tcvr to an idle state
1204: */
1205: void
1206: be_mii_sync(struct be_softc *sc)
1207: {
1208: bus_space_tag_t t = sc->sc_bustag;
1209: bus_space_handle_t tr = sc->sc_tr;
1210: int n = 32;
1211:
1212: while (n--) {
1213: bus_space_write_4(t, tr, BE_TRI_MGMTPAL,
1214: MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO | MGMT_PAL_OENAB);
1215: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
1216: bus_space_write_4(t, tr, BE_TRI_MGMTPAL,
1217: MGMT_PAL_INT_MDIO | MGMT_PAL_EXT_MDIO |
1218: MGMT_PAL_OENAB | MGMT_PAL_DCLOCK);
1219: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
1220: }
1221: }
1222:
1223: void
1224: be_pal_gate(struct be_softc *sc, int phy)
1225: {
1226: bus_space_tag_t t = sc->sc_bustag;
1227: bus_space_handle_t tr = sc->sc_tr;
1228: u_int32_t v;
1229:
1230: be_mii_sync(sc);
1231:
1232: v = ~(TCVR_PAL_EXTLBACK | TCVR_PAL_MSENSE | TCVR_PAL_LTENABLE);
1233: if (phy == BE_PHY_INTERNAL)
1234: v &= ~TCVR_PAL_SERIAL;
1235:
1236: bus_space_write_4(t, tr, BE_TRI_TCVRPAL, v);
1237: (void)bus_space_read_4(t, tr, BE_TRI_TCVRPAL);
1238: }
1239:
1240: static int
1241: be_tcvr_read_bit(struct be_softc *sc, int phy)
1242: {
1243: bus_space_tag_t t = sc->sc_bustag;
1244: bus_space_handle_t tr = sc->sc_tr;
1245: int ret;
1246:
1247: if (phy == BE_PHY_INTERNAL) {
1248: bus_space_write_4(t, tr, BE_TRI_MGMTPAL, MGMT_PAL_EXT_MDIO);
1249: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
1250: bus_space_write_4(t, tr, BE_TRI_MGMTPAL,
1251: MGMT_PAL_EXT_MDIO | MGMT_PAL_DCLOCK);
1252: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
1253: ret = (bus_space_read_4(t, tr, BE_TRI_MGMTPAL) &
1254: MGMT_PAL_INT_MDIO) >> MGMT_PAL_INT_MDIO_SHIFT;
1255: } else {
1256: bus_space_write_4(t, tr, BE_TRI_MGMTPAL, MGMT_PAL_INT_MDIO);
1257: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
1258: ret = (bus_space_read_4(t, tr, BE_TRI_MGMTPAL) &
1259: MGMT_PAL_EXT_MDIO) >> MGMT_PAL_EXT_MDIO_SHIFT;
1260: bus_space_write_4(t, tr, BE_TRI_MGMTPAL,
1261: MGMT_PAL_INT_MDIO | MGMT_PAL_DCLOCK);
1262: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
1263: }
1264:
1265: return (ret);
1266: }
1267:
1268: static void
1269: be_tcvr_write_bit(struct be_softc *sc, int phy, int bit)
1270: {
1271: bus_space_tag_t t = sc->sc_bustag;
1272: bus_space_handle_t tr = sc->sc_tr;
1273: u_int32_t v;
1274:
1275: if (phy == BE_PHY_INTERNAL) {
1276: v = ((bit & 1) << MGMT_PAL_INT_MDIO_SHIFT) |
1277: MGMT_PAL_OENAB | MGMT_PAL_EXT_MDIO;
1278: } else {
1279: v = ((bit & 1) << MGMT_PAL_EXT_MDIO_SHIFT)
1280: | MGMT_PAL_OENAB | MGMT_PAL_INT_MDIO;
1281: }
1282: bus_space_write_4(t, tr, BE_TRI_MGMTPAL, v);
1283: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
1284: bus_space_write_4(t, tr, BE_TRI_MGMTPAL, v | MGMT_PAL_DCLOCK);
1285: (void)bus_space_read_4(t, tr, BE_TRI_MGMTPAL);
1286: }
1287:
1288: static void
1289: be_mii_sendbits(struct be_softc *sc, int phy, u_int32_t data, int nbits)
1290: {
1291: int i;
1292:
1293: for (i = 1 << (nbits - 1); i != 0; i >>= 1)
1294: be_tcvr_write_bit(sc, phy, (data & i) != 0);
1295: }
1296:
1297: static int
1298: be_mii_readreg(struct device *self, int phy, int reg)
1299: {
1300: struct be_softc *sc = (struct be_softc *)self;
1301: int val = 0, i;
1302:
1303: /*
1304: * Read the PHY register by manually driving the MII control lines.
1305: */
1306: be_mii_sync(sc);
1307: be_mii_sendbits(sc, phy, MII_COMMAND_START, 2);
1308: be_mii_sendbits(sc, phy, MII_COMMAND_READ, 2);
1309: be_mii_sendbits(sc, phy, phy, 5);
1310: be_mii_sendbits(sc, phy, reg, 5);
1311:
1312: (void) be_tcvr_read_bit(sc, phy);
1313: (void) be_tcvr_read_bit(sc, phy);
1314:
1315: for (i = 15; i >= 0; i--)
1316: val |= (be_tcvr_read_bit(sc, phy) << i);
1317:
1318: (void) be_tcvr_read_bit(sc, phy);
1319: (void) be_tcvr_read_bit(sc, phy);
1320: (void) be_tcvr_read_bit(sc, phy);
1321:
1322: return (val);
1323: }
1324:
1325: void
1326: be_mii_writereg(struct device *self, int phy, int reg, int val)
1327: {
1328: struct be_softc *sc = (struct be_softc *)self;
1329: int i;
1330:
1331: /*
1332: * Write the PHY register by manually driving the MII control lines.
1333: */
1334: be_mii_sync(sc);
1335: be_mii_sendbits(sc, phy, MII_COMMAND_START, 2);
1336: be_mii_sendbits(sc, phy, MII_COMMAND_WRITE, 2);
1337: be_mii_sendbits(sc, phy, phy, 5);
1338: be_mii_sendbits(sc, phy, reg, 5);
1339:
1340: be_tcvr_write_bit(sc, phy, 1);
1341: be_tcvr_write_bit(sc, phy, 0);
1342:
1343: for (i = 15; i >= 0; i--)
1344: be_tcvr_write_bit(sc, phy, (val >> i) & 1);
1345: }
1346:
1347: int
1348: be_mii_reset(struct be_softc *sc, int phy)
1349: {
1350: int n;
1351:
1352: be_mii_writereg((struct device *)sc, phy, MII_BMCR,
1353: BMCR_LOOP | BMCR_PDOWN | BMCR_ISO);
1354: be_mii_writereg((struct device *)sc, phy, MII_BMCR, BMCR_RESET);
1355:
1356: for (n = 16; n >= 0; n--) {
1357: int bmcr = be_mii_readreg((struct device *)sc, phy, MII_BMCR);
1358: if ((bmcr & BMCR_RESET) == 0)
1359: break;
1360: DELAY(20);
1361: }
1362: if (n == 0) {
1363: printf("%s: bmcr reset failed\n", sc->sc_dev.dv_xname);
1364: return (EIO);
1365: }
1366:
1367: return (0);
1368: }
1369:
1370: void
1371: be_tick(void *arg)
1372: {
1373: struct be_softc *sc = arg;
1374: int s = splnet();
1375:
1376: mii_tick(&sc->sc_mii);
1377: (void)be_intphy_service(sc, &sc->sc_mii, MII_TICK);
1378:
1379: timeout_add(&sc->sc_tick_ch, hz);
1380: splx(s);
1381: }
1382:
1383: void
1384: be_mii_statchg(struct device *self)
1385: {
1386: struct be_softc *sc = (struct be_softc *)self;
1387: bus_space_tag_t t = sc->sc_bustag;
1388: bus_space_handle_t br = sc->sc_br;
1389: u_int instance;
1390: u_int32_t v;
1391:
1392: instance = IFM_INST(sc->sc_mii.mii_media.ifm_cur->ifm_media);
1393: #ifdef DIAGNOSTIC
1394: if (instance > 1)
1395: panic("be_mii_statchg: instance %d out of range", instance);
1396: #endif
1397:
1398: /* Update duplex mode in TX configuration */
1399: v = bus_space_read_4(t, br, BE_BRI_TXCFG);
1400: if ((IFM_OPTIONS(sc->sc_mii.mii_media_active) & IFM_FDX) != 0)
1401: v |= BE_BR_TXCFG_FULLDPLX;
1402: else
1403: v &= ~BE_BR_TXCFG_FULLDPLX;
1404: bus_space_write_4(t, br, BE_BRI_TXCFG, v);
1405:
1406: /* Change to appropriate gate in transceiver PAL */
1407: be_pal_gate(sc, sc->sc_phys[instance]);
1408: }
1409:
1410: /*
1411: * Get current media settings.
1412: */
1413: void
1414: be_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
1415: {
1416: struct be_softc *sc = ifp->if_softc;
1417:
1418: mii_pollstat(&sc->sc_mii);
1419: (void)be_intphy_service(sc, &sc->sc_mii, MII_POLLSTAT);
1420:
1421: ifmr->ifm_status = sc->sc_mii.mii_media_status;
1422: ifmr->ifm_active = sc->sc_mii.mii_media_active;
1423: return;
1424: }
1425:
1426: /*
1427: * Set media options.
1428: */
1429: int
1430: be_ifmedia_upd(struct ifnet *ifp)
1431: {
1432: struct be_softc *sc = ifp->if_softc;
1433: int error;
1434:
1435: if ((error = mii_mediachg(&sc->sc_mii)) != 0)
1436: return (error);
1437:
1438: return (be_intphy_service(sc, &sc->sc_mii, MII_MEDIACHG));
1439: }
1440:
1441: /*
1442: * Service routine for our pseudo-MII internal transceiver.
1443: */
1444: int
1445: be_intphy_service(struct be_softc *sc, struct mii_data *mii, int cmd)
1446: {
1447: struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
1448: int bmcr, bmsr;
1449: int error;
1450:
1451: switch (cmd) {
1452: case MII_POLLSTAT:
1453: /*
1454: * If we're not polling our PHY instance, just return.
1455: */
1456: if (IFM_INST(ife->ifm_media) != sc->sc_mii_inst)
1457: return (0);
1458:
1459: break;
1460:
1461: case MII_MEDIACHG:
1462:
1463: /*
1464: * If the media indicates a different PHY instance,
1465: * isolate ourselves.
1466: */
1467: if (IFM_INST(ife->ifm_media) != sc->sc_mii_inst) {
1468: bmcr = be_mii_readreg((void *)sc,
1469: BE_PHY_INTERNAL, MII_BMCR);
1470: be_mii_writereg((void *)sc,
1471: BE_PHY_INTERNAL, MII_BMCR, bmcr | BMCR_ISO);
1472: sc->sc_mii_flags &= ~MIIF_HAVELINK;
1473: sc->sc_intphy_curspeed = 0;
1474: return (0);
1475: }
1476:
1477:
1478: if ((error = be_mii_reset(sc, BE_PHY_INTERNAL)) != 0)
1479: return (error);
1480:
1481: bmcr = be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMCR);
1482:
1483: /*
1484: * Select the new mode and take out of isolation
1485: */
1486: if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_TX)
1487: bmcr |= BMCR_S100;
1488: else if (IFM_SUBTYPE(ife->ifm_media) == IFM_10_T)
1489: bmcr &= ~BMCR_S100;
1490: else if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
1491: if ((sc->sc_mii_flags & MIIF_HAVELINK) != 0) {
1492: bmcr &= ~BMCR_S100;
1493: bmcr |= sc->sc_intphy_curspeed;
1494: } else {
1495: /* Keep isolated until link is up */
1496: bmcr |= BMCR_ISO;
1497: sc->sc_mii_flags |= MIIF_DOINGAUTO;
1498: }
1499: }
1500:
1501: if ((IFM_OPTIONS(ife->ifm_media) & IFM_FDX) != 0)
1502: bmcr |= BMCR_FDX;
1503: else
1504: bmcr &= ~BMCR_FDX;
1505:
1506: be_mii_writereg((void *)sc, BE_PHY_INTERNAL, MII_BMCR, bmcr);
1507: break;
1508:
1509: case MII_TICK:
1510: /*
1511: * If we're not currently selected, just return.
1512: */
1513: if (IFM_INST(ife->ifm_media) != sc->sc_mii_inst)
1514: return (0);
1515:
1516: /* Only used for automatic media selection */
1517: if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
1518: return (0);
1519:
1520: /* Is the interface even up? */
1521: if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
1522: return (0);
1523:
1524: /*
1525: * Check link status; if we don't have a link, try another
1526: * speed. We can't detect duplex mode, so half-duplex is
1527: * what we have to settle for.
1528: */
1529:
1530: /* Read twice in case the register is latched */
1531: bmsr = be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMSR) |
1532: be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMSR);
1533:
1534: if ((bmsr & BMSR_LINK) != 0) {
1535: /* We have a carrier */
1536: bmcr = be_mii_readreg((void *)sc,
1537: BE_PHY_INTERNAL, MII_BMCR);
1538:
1539: if ((sc->sc_mii_flags & MIIF_DOINGAUTO) != 0) {
1540: bmcr = be_mii_readreg((void *)sc,
1541: BE_PHY_INTERNAL, MII_BMCR);
1542:
1543: sc->sc_mii_flags |= MIIF_HAVELINK;
1544: sc->sc_intphy_curspeed = (bmcr & BMCR_S100);
1545: sc->sc_mii_flags &= ~MIIF_DOINGAUTO;
1546:
1547: bmcr &= ~BMCR_ISO;
1548: be_mii_writereg((void *)sc,
1549: BE_PHY_INTERNAL, MII_BMCR, bmcr);
1550:
1551: printf("%s: link up at %s Mbps\n",
1552: sc->sc_dev.dv_xname,
1553: (bmcr & BMCR_S100) ? "100" : "10");
1554: }
1555: return (0);
1556: }
1557:
1558: if ((sc->sc_mii_flags & MIIF_DOINGAUTO) == 0) {
1559: sc->sc_mii_flags |= MIIF_DOINGAUTO;
1560: sc->sc_mii_flags &= ~MIIF_HAVELINK;
1561: sc->sc_intphy_curspeed = 0;
1562: printf("%s: link down\n", sc->sc_dev.dv_xname);
1563: }
1564:
1565: /* Only retry autonegotiation every 5 seconds. */
1566: if (++sc->sc_mii_ticks < 5)
1567: return(0);
1568:
1569: sc->sc_mii_ticks = 0;
1570: bmcr = be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMCR);
1571: /* Just flip the fast speed bit */
1572: bmcr ^= BMCR_S100;
1573: be_mii_writereg((void *)sc, BE_PHY_INTERNAL, MII_BMCR, bmcr);
1574:
1575: break;
1576:
1577: case MII_DOWN:
1578: /* Isolate this phy */
1579: bmcr = be_mii_readreg((void *)sc, BE_PHY_INTERNAL, MII_BMCR);
1580: be_mii_writereg((void *)sc,
1581: BE_PHY_INTERNAL, MII_BMCR, bmcr | BMCR_ISO);
1582: return (0);
1583: }
1584:
1585: /* Update the media status. */
1586: be_intphy_status(sc);
1587:
1588: /* Callback if something changed. */
1589: if (sc->sc_mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
1590: (*mii->mii_statchg)((struct device *)sc);
1591: sc->sc_mii_active = mii->mii_media_active;
1592: }
1593: return (0);
1594: }
1595:
1596: /*
1597: * Determine status of internal transceiver
1598: */
1599: void
1600: be_intphy_status(struct be_softc *sc)
1601: {
1602: struct mii_data *mii = &sc->sc_mii;
1603: int media_active, media_status;
1604: int bmcr, bmsr;
1605:
1606: media_status = IFM_AVALID;
1607: media_active = 0;
1608:
1609: /*
1610: * Internal transceiver; do the work here.
1611: */
1612: bmcr = be_mii_readreg((struct device *)sc, BE_PHY_INTERNAL, MII_BMCR);
1613:
1614: switch (bmcr & (BMCR_S100 | BMCR_FDX)) {
1615: case (BMCR_S100 | BMCR_FDX):
1616: media_active = IFM_ETHER | IFM_100_TX | IFM_FDX;
1617: break;
1618: case BMCR_S100:
1619: media_active = IFM_ETHER | IFM_100_TX | IFM_HDX;
1620: break;
1621: case BMCR_FDX:
1622: media_active = IFM_ETHER | IFM_10_T | IFM_FDX;
1623: break;
1624: case 0:
1625: media_active = IFM_ETHER | IFM_10_T | IFM_HDX;
1626: break;
1627: }
1628:
1629: /* Read twice in case the register is latched */
1630: bmsr = be_mii_readreg((struct device *)sc, BE_PHY_INTERNAL, MII_BMSR)|
1631: be_mii_readreg((struct device *)sc, BE_PHY_INTERNAL, MII_BMSR);
1632: if (bmsr & BMSR_LINK)
1633: media_status |= IFM_ACTIVE;
1634:
1635: mii->mii_media_status = media_status;
1636: mii->mii_media_active = media_active;
1637: }
CVSweb