Annotation of sys/dev/ic/smc91cxx.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: smc91cxx.c,v 1.26 2006/06/23 06:27:11 miod Exp $ */
2: /* $NetBSD: smc91cxx.c,v 1.11 1998/08/08 23:51:41 mycroft Exp $ */
3:
4: /*-
5: * Copyright (c) 1997 The NetBSD Foundation, Inc.
6: * All rights reserved.
7: *
8: * This code is derived from software contributed to The NetBSD Foundation
9: * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10: * NASA Ames Research Center.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: * 3. All advertising materials mentioning features or use of this software
21: * must display the following acknowledgement:
22: * This product includes software developed by the NetBSD
23: * Foundation, Inc. and its contributors.
24: * 4. Neither the name of The NetBSD Foundation nor the names of its
25: * contributors may be used to endorse or promote products derived
26: * from this software without specific prior written permission.
27: *
28: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38: * POSSIBILITY OF SUCH DAMAGE.
39: */
40:
41: /*
42: * Copyright (c) 1996 Gardner Buchanan <gbuchanan@shl.com>
43: * All rights reserved.
44: *
45: * Redistribution and use in source and binary forms, with or without
46: * modification, are permitted provided that the following conditions
47: * are met:
48: * 1. Redistributions of source code must retain the above copyright
49: * notice, this list of conditions and the following disclaimer.
50: * 2. Redistributions in binary form must reproduce the above copyright
51: * notice, this list of conditions and the following disclaimer in the
52: * documentation and/or other materials provided with the distribution.
53: * 3. All advertising materials mentioning features or use of this software
54: * must display the following acknowledgement:
55: * This product includes software developed by Gardner Buchanan.
56: * 4. The name of Gardner Buchanan may not be used to endorse or promote
57: * products derived from this software without specific prior written
58: * permission.
59: *
60: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
61: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
62: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
63: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
64: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
65: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
66: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
67: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
68: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
69: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70: *
71: * from FreeBSD Id: if_sn.c,v 1.4 1996/03/18 15:47:16 gardner Exp
72: */
73:
74: /*
75: * Core driver for the SMC 91Cxx family of Ethernet chips.
76: *
77: * Memory allocation interrupt logic is drived from an SMC 91C90 driver
78: * written for NetBSD/amiga by Michael Hitch.
79: */
80:
81: #include "bpfilter.h"
82:
83: #include <sys/param.h>
84: #include <sys/systm.h>
85: #include <sys/mbuf.h>
86: #include <sys/syslog.h>
87: #include <sys/socket.h>
88: #include <sys/device.h>
89: #include <sys/timeout.h>
90: #include <sys/kernel.h>
91: #include <sys/malloc.h>
92: #include <sys/ioctl.h>
93: #include <sys/errno.h>
94:
95: #include <machine/bus.h>
96: #include <machine/intr.h>
97:
98: #include <net/if.h>
99: #include <net/if_dl.h>
100: #include <net/if_media.h>
101:
102: #ifdef INET
103: #include <netinet/in.h>
104: #include <netinet/if_ether.h>
105: #include <netinet/in_systm.h>
106: #include <netinet/in_var.h>
107: #include <netinet/ip.h>
108: #endif
109:
110: #if NBPFILTER > 0
111: #include <net/bpf.h>
112: #endif
113:
114: #include <dev/mii/mii.h>
115: #include <dev/mii/miivar.h>
116: #include <dev/mii/mii_bitbang.h>
117:
118: #include <dev/ic/smc91cxxreg.h>
119: #include <dev/ic/smc91cxxvar.h>
120:
121: #ifndef __BUS_SPACE_HAS_STREAM_METHODS
122: #define bus_space_write_multi_stream_2 bus_space_write_multi_2
123: #define bus_space_write_multi_stream_4 bus_space_write_multi_4
124: #define bus_space_read_multi_stream_2 bus_space_read_multi_2
125: #define bus_space_read_multi_stream_4 bus_space_read_multi_4
126: #endif /* __BUS_SPACE_HAS_STREAM_METHODS */
127:
128: /* XXX Hardware padding doesn't work yet(?) */
129: #define SMC91CXX_SW_PAD
130:
131: const char *smc91cxx_idstrs[] = {
132: NULL, /* 0 */
133: NULL, /* 1 */
134: NULL, /* 2 */
135: "SMC91C90/91C92", /* 3 */
136: "SMC91C94/91C96", /* 4 */
137: "SMC91C95", /* 5 */
138: NULL, /* 6 */
139: "SMC91C100", /* 7 */
140: "SMC91C100FD", /* 8 */
141: NULL, /* 9 */
142: NULL, /* 10 */
143: NULL, /* 11 */
144: NULL, /* 12 */
145: NULL, /* 13 */
146: NULL, /* 14 */
147: NULL, /* 15 */
148: };
149:
150: /* Supported media types. */
151: const int smc91cxx_media[] = {
152: IFM_ETHER|IFM_10_T,
153: IFM_ETHER|IFM_10_5,
154: };
155: #define NSMC91CxxMEDIA (sizeof(smc91cxx_media) / sizeof(smc91cxx_media[0]))
156:
157: /*
158: * MII bit-bang glue.
159: */
160: u_int32_t smc91cxx_mii_bitbang_read(struct device *);
161: void smc91cxx_mii_bitbang_write(struct device *, u_int32_t);
162:
163: const struct mii_bitbang_ops smc91cxx_mii_bitbang_ops = {
164: smc91cxx_mii_bitbang_read,
165: smc91cxx_mii_bitbang_write,
166: {
167: MR_MDO, /* MII_BIT_MDO */
168: MR_MDI, /* MII_BIT_MDI */
169: MR_MCLK, /* MII_BIT_MDC */
170: MR_MDOE, /* MII_BIT_DIR_HOST_PHY */
171: 0, /* MII_BIT_DIR_PHY_HOST */
172: }
173: };
174:
175: struct cfdriver sm_cd = {
176: NULL, "sm", DV_IFNET
177: };
178:
179: /* MII callbacks */
180: int smc91cxx_mii_readreg(struct device *, int, int);
181: void smc91cxx_mii_writereg(struct device *, int, int, int);
182: void smc91cxx_statchg(struct device *);
183: void smc91cxx_tick(void *);
184:
185: int smc91cxx_mediachange(struct ifnet *);
186: void smc91cxx_mediastatus(struct ifnet *, struct ifmediareq *);
187:
188: int smc91cxx_set_media(struct smc91cxx_softc *, int);
189:
190: void smc91cxx_read(struct smc91cxx_softc *);
191: void smc91cxx_reset(struct smc91cxx_softc *);
192: void smc91cxx_start(struct ifnet *);
193: void smc91cxx_resume(struct smc91cxx_softc *);
194: void smc91cxx_watchdog(struct ifnet *);
195: int smc91cxx_ioctl(struct ifnet *, u_long, caddr_t);
196:
197: static __inline int ether_cmp(void *, void *);
198: static __inline int
199: ether_cmp(va, vb)
200: void *va, *vb;
201: {
202: u_int8_t *a = va;
203: u_int8_t *b = vb;
204:
205: return ((a[5] != b[5]) || (a[4] != b[4]) || (a[3] != b[3]) ||
206: (a[2] != b[2]) || (a[1] != b[1]) || (a[0] != b[0]));
207: }
208:
209: void
210: smc91cxx_attach(sc, myea)
211: struct smc91cxx_softc *sc;
212: u_int8_t *myea;
213: {
214: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
215: bus_space_tag_t bst = sc->sc_bst;
216: bus_space_handle_t bsh = sc->sc_bsh;
217: struct ifmedia *ifm = &sc->sc_mii.mii_media;
218: u_int32_t miicapabilities;
219: u_int16_t tmp;
220: int i, aui;
221: const char *idstr;
222:
223: /* Make sure the chip is stopped. */
224: smc91cxx_stop(sc);
225:
226: SMC_SELECT_BANK(sc, 3);
227: tmp = bus_space_read_2(bst, bsh, REVISION_REG_W);
228: sc->sc_chipid = RR_ID(tmp);
229: /* check magic number */
230: if ((tmp & BSR_DETECT_MASK) != BSR_DETECT_VALUE) {
231: idstr = NULL;
232: printf("%s: invalid BSR 0x%04x\n", sc->sc_dev.dv_xname, tmp);
233: } else
234: idstr = smc91cxx_idstrs[RR_ID(tmp)];
235: #ifdef SMC_DEBUG
236: printf("\n%s: ", sc->sc_dev.dv_xname);
237: if (idstr != NULL)
238: printf("%s, ", idstr);
239: else
240: printf("unknown chip id %d, ", sc->sc_chipid);
241: printf("revision %d", RR_REV(tmp));
242: #endif
243:
244: /* Read the station address from the chip. */
245: SMC_SELECT_BANK(sc, 1);
246: if (myea == NULL) {
247: for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
248: tmp = bus_space_read_2(bst, bsh, IAR_ADDR0_REG_W + i);
249: sc->sc_arpcom.ac_enaddr[i + 1] = (tmp >>8) & 0xff;
250: sc->sc_arpcom.ac_enaddr[i] = tmp & 0xff;
251: }
252: } else {
253: bcopy(myea, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
254: }
255:
256: printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
257:
258: /* Initialize the ifnet structure. */
259: bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
260: ifp->if_softc = sc;
261: ifp->if_start = smc91cxx_start;
262: ifp->if_ioctl = smc91cxx_ioctl;
263: ifp->if_watchdog = smc91cxx_watchdog;
264: ifp->if_flags =
265: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
266: IFQ_SET_READY(&ifp->if_snd);
267:
268: /* Attach the interface. */
269: if_attach(ifp);
270: ether_ifattach(ifp);
271:
272: /*
273: * Initialize our media structures and MII info. We will
274: * probe the MII if we are on the SMC91Cxx
275: */
276: sc->sc_mii.mii_ifp = ifp;
277: sc->sc_mii.mii_readreg = smc91cxx_mii_readreg;
278: sc->sc_mii.mii_writereg = smc91cxx_mii_writereg;
279: sc->sc_mii.mii_statchg = smc91cxx_statchg;
280: ifmedia_init(ifm, 0, smc91cxx_mediachange, smc91cxx_mediastatus);
281:
282: SMC_SELECT_BANK(sc, 1);
283: tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W);
284:
285: miicapabilities = BMSR_MEDIAMASK|BMSR_ANEG;
286: switch (sc->sc_chipid) {
287: case CHIP_91100:
288: /*
289: * The 91100 does not have full-duplex capabilities,
290: * even if the PHY does.
291: */
292: miicapabilities &= ~(BMSR_100TXFDX | BMSR_10TFDX);
293: case CHIP_91100FD:
294: if (tmp & CR_MII_SELECT) {
295: #ifdef SMC_DEBUG
296: printf("%s: default media MII\n",
297: sc->sc_dev.dv_xname);
298: #endif
299: mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff,
300: MII_PHY_ANY, MII_OFFSET_ANY, 0);
301: if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
302: ifmedia_add(&sc->sc_mii.mii_media,
303: IFM_ETHER|IFM_NONE, 0, NULL);
304: ifmedia_set(&sc->sc_mii.mii_media,
305: IFM_ETHER|IFM_NONE);
306: } else {
307: ifmedia_set(&sc->sc_mii.mii_media,
308: IFM_ETHER|IFM_AUTO);
309: }
310: sc->sc_flags |= SMC_FLAGS_HAS_MII;
311: break;
312: }
313: /*FALLTHROUGH*/
314: default:
315: aui = tmp & CR_AUI_SELECT;
316: #ifdef SMC_DEBUG
317: printf("%s: default media %s\n", sc->sc_dev.dv_xname,
318: aui ? "AUI" : "UTP");
319: #endif
320: for (i = 0; i < NSMC91CxxMEDIA; i++)
321: ifmedia_add(ifm, smc91cxx_media[i], 0, NULL);
322: ifmedia_set(ifm, IFM_ETHER | (aui ? IFM_10_5 : IFM_10_T));
323: break;
324: }
325:
326: /* The attach is successful. */
327: sc->sc_flags |= SMC_FLAGS_ATTACHED;
328: }
329:
330: /*
331: * Change media according to request.
332: */
333: int
334: smc91cxx_mediachange(ifp)
335: struct ifnet *ifp;
336: {
337: struct smc91cxx_softc *sc = ifp->if_softc;
338:
339: return (smc91cxx_set_media(sc, sc->sc_mii.mii_media.ifm_media));
340: }
341:
342: int
343: smc91cxx_set_media(sc, media)
344: struct smc91cxx_softc *sc;
345: int media;
346: {
347: bus_space_tag_t bst = sc->sc_bst;
348: bus_space_handle_t bsh = sc->sc_bsh;
349: u_int16_t tmp;
350:
351: /*
352: * If the interface is not currently powered on, just return.
353: * When it is enabled later, smc91cxx_init() will properly set
354: * up the media for us.
355: */
356: if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0)
357: return (0);
358:
359: if (IFM_TYPE(media) != IFM_ETHER)
360: return (EINVAL);
361:
362: if (sc->sc_flags & SMC_FLAGS_HAS_MII)
363: return (mii_mediachg(&sc->sc_mii));
364:
365: switch (IFM_SUBTYPE(media)) {
366: case IFM_10_T:
367: case IFM_10_5:
368: SMC_SELECT_BANK(sc, 1);
369: tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W);
370: if (IFM_SUBTYPE(media) == IFM_10_5)
371: tmp |= CR_AUI_SELECT;
372: else
373: tmp &= ~CR_AUI_SELECT;
374: bus_space_write_2(bst, bsh, CONFIG_REG_W, tmp);
375: delay(20000); /* XXX is this needed? */
376: break;
377:
378: default:
379: return (EINVAL);
380: }
381:
382: return (0);
383: }
384:
385: /*
386: * Notify the world which media we're using.
387: */
388: void
389: smc91cxx_mediastatus(ifp, ifmr)
390: struct ifnet *ifp;
391: struct ifmediareq *ifmr;
392: {
393: struct smc91cxx_softc *sc = ifp->if_softc;
394: bus_space_tag_t bst = sc->sc_bst;
395: bus_space_handle_t bsh = sc->sc_bsh;
396: u_int16_t tmp;
397:
398: if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0) {
399: ifmr->ifm_active = IFM_ETHER | IFM_NONE;
400: ifmr->ifm_status = 0;
401: return;
402: }
403:
404: /*
405: * If we have MII, go ask the PHY what's going on.
406: */
407: if (sc->sc_flags & SMC_FLAGS_HAS_MII) {
408: mii_pollstat(&sc->sc_mii);
409: ifmr->ifm_active = sc->sc_mii.mii_media_active;
410: ifmr->ifm_status = sc->sc_mii.mii_media_status;
411: return;
412: }
413:
414: SMC_SELECT_BANK(sc, 1);
415: tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W);
416: ifmr->ifm_active =
417: IFM_ETHER | ((tmp & CR_AUI_SELECT) ? IFM_10_5 : IFM_10_T);
418: }
419:
420: /*
421: * Reset and initialize the chip.
422: */
423: void
424: smc91cxx_init(sc)
425: struct smc91cxx_softc *sc;
426: {
427: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
428: bus_space_tag_t bst = sc->sc_bst;
429: bus_space_handle_t bsh = sc->sc_bsh;
430: u_int16_t tmp;
431: int s, i;
432:
433: s = splnet();
434:
435: /*
436: * This resets the registers mostly to defaults, but doesn't
437: * affect the EEPROM. After the reset cycle, we pause briefly
438: * for the chip to recover.
439: *
440: * XXX how long are we really supposed to delay? --thorpej
441: */
442: SMC_SELECT_BANK(sc, 0);
443: bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, RCR_SOFTRESET);
444: delay(100);
445: bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, 0);
446: delay(200);
447:
448: bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 0);
449:
450: /* Set the Ethernet address. */
451: SMC_SELECT_BANK(sc, 1);
452: for (i = 0; i < ETHER_ADDR_LEN; i++ )
453: bus_space_write_1(bst, bsh, IAR_ADDR0_REG_W + i,
454: sc->sc_arpcom.ac_enaddr[i]);
455:
456: /*
457: * Set the control register to automatically release successfully
458: * transmitted packets (making the best use of our limited memory)
459: * and enable the EPH interrupt on certain TX errors.
460: */
461: bus_space_write_2(bst, bsh, CONTROL_REG_W, (CTR_AUTO_RELEASE |
462: CTR_TE_ENABLE | CTR_CR_ENABLE | CTR_LE_ENABLE));
463:
464: /*
465: * Reset the MMU and wait for it to be un-busy.
466: */
467: SMC_SELECT_BANK(sc, 2);
468: bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_RESET);
469: while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
470: /* XXX bound this loop! */ ;
471:
472: /*
473: * Disable all interrupts.
474: */
475: bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0);
476:
477: /*
478: * Set current media.
479: */
480: smc91cxx_set_media(sc, sc->sc_mii.mii_media.ifm_cur->ifm_media);
481:
482: /*
483: * Set the receive filter. We want receive enable and auto
484: * strip of CRC from received packet. If we are in promisc. mode,
485: * then set that bit as well.
486: *
487: * XXX Initialize multicast filter. For now, we just accept
488: * XXX all multicast.
489: */
490: SMC_SELECT_BANK(sc, 0);
491:
492: tmp = RCR_ENABLE | RCR_STRIP_CRC | RCR_ALMUL;
493: if (ifp->if_flags & IFF_PROMISC)
494: tmp |= RCR_PROMISC;
495:
496: bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, tmp);
497:
498: /*
499: * Set transmitter control to "enabled".
500: */
501: tmp = TCR_ENABLE;
502:
503: #ifndef SMC91CXX_SW_PAD
504: /*
505: * Enable hardware padding of transmitted packets.
506: * XXX doesn't work?
507: */
508: tmp |= TCR_PAD_ENABLE;
509: #endif
510:
511: bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, tmp);
512:
513: /*
514: * Now, enable interrupts.
515: */
516: SMC_SELECT_BANK(sc, 2);
517:
518: bus_space_write_1(bst, bsh, INTR_MASK_REG_B,
519: IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT | IM_TX_INT);
520:
521: /* Interface is now running, with no output active. */
522: ifp->if_flags |= IFF_RUNNING;
523: ifp->if_flags &= ~IFF_OACTIVE;
524:
525: if (sc->sc_flags & SMC_FLAGS_HAS_MII) {
526: /* Start the one second clock. */
527: timeout_set(&sc->sc_mii_timeout, smc91cxx_tick, sc);
528: timeout_add(&sc->sc_mii_timeout, hz);
529: }
530:
531: /*
532: * Attempt to start any pending transmission.
533: */
534: smc91cxx_start(ifp);
535:
536: splx(s);
537: }
538:
539: /*
540: * Start output on an interface.
541: * Must be called at splnet or interrupt level.
542: */
543: void
544: smc91cxx_start(ifp)
545: struct ifnet *ifp;
546: {
547: struct smc91cxx_softc *sc = ifp->if_softc;
548: bus_space_tag_t bst = sc->sc_bst;
549: bus_space_handle_t bsh = sc->sc_bsh;
550: u_int len;
551: struct mbuf *m, *top;
552: u_int16_t length, npages;
553: u_int8_t packetno;
554: int timo, pad;
555:
556: if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING)
557: return;
558:
559: again:
560: /*
561: * Peek at the next packet.
562: */
563: IFQ_POLL(&ifp->if_snd, m);
564: if (m == NULL)
565: return;
566:
567: /*
568: * Compute the frame length and set pad to give an overall even
569: * number of bytes. Below, we assume that the packet length
570: * is even.
571: */
572: for (len = 0, top = m; m != NULL; m = m->m_next)
573: len += m->m_len;
574: pad = (len & 1);
575:
576: /*
577: * We drop packets that are too large. Perhaps we should
578: * truncate them instead?
579: */
580: if ((len + pad) > (ETHER_MAX_LEN - ETHER_CRC_LEN)) {
581: printf("%s: large packet discarded\n", sc->sc_dev.dv_xname);
582: ifp->if_oerrors++;
583: IFQ_DEQUEUE(&ifp->if_snd, m);
584: m_freem(m);
585: goto readcheck;
586: }
587:
588: #ifdef SMC91CXX_SW_PAD
589: /*
590: * Not using hardware padding; pad to ETHER_MIN_LEN.
591: */
592: if (len < (ETHER_MIN_LEN - ETHER_CRC_LEN))
593: pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;
594: #endif
595:
596: length = pad + len;
597:
598: /*
599: * The MMU has a 256 byte page size. The MMU expects us to
600: * ask for "npages - 1". We include space for the status word,
601: * byte count, and control bytes in the allocation request.
602: */
603: npages = (length + 6) >> 8;
604:
605: /*
606: * Now allocate the memory.
607: */
608: SMC_SELECT_BANK(sc, 2);
609: bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_ALLOC | npages);
610:
611: timo = MEMORY_WAIT_TIME;
612: do {
613: if (bus_space_read_1(bst, bsh, INTR_STAT_REG_B) & IM_ALLOC_INT)
614: break;
615: delay(1);
616: } while (--timo);
617:
618: packetno = bus_space_read_1(bst, bsh, ALLOC_RESULT_REG_B);
619:
620: if (packetno & ARR_FAILED || timo == 0) {
621: /*
622: * No transmit memory is available. Record the number
623: * of requestd pages and enable the allocation completion
624: * interrupt. Set up the watchdog timer in case we miss
625: * the interrupt. Mark the interface as active so that
626: * no one else attempts to transmit while we're allocating
627: * memory.
628: */
629: bus_space_write_1(bst, bsh, INTR_MASK_REG_B,
630: bus_space_read_1(bst, bsh, INTR_MASK_REG_B) | IM_ALLOC_INT);
631:
632: ifp->if_timer = 5;
633: ifp->if_flags |= IFF_OACTIVE;
634:
635: return;
636: }
637:
638: /*
639: * We have a packet number - set the data window.
640: */
641: bus_space_write_1(bst, bsh, PACKET_NUM_REG_B, packetno);
642:
643: /*
644: * Point to the beginning of the packet.
645: */
646: bus_space_write_2(bst, bsh, POINTER_REG_W, PTR_AUTOINC /* | 0x0000 */);
647:
648: /*
649: * Send the packet length (+6 for stats, length, and control bytes)
650: * and the status word (set to zeros).
651: */
652: bus_space_write_2(bst, bsh, DATA_REG_W, 0);
653: bus_space_write_1(bst, bsh, DATA_REG_B, (length + 6) & 0xff);
654: bus_space_write_1(bst, bsh, DATA_REG_B, ((length + 6) >> 8) & 0xff);
655:
656: /*
657: * Get the packet from the kernel. This will include the Ethernet
658: * frame header, MAC address, etc.
659: */
660: IFQ_DEQUEUE(&ifp->if_snd, m);
661:
662: /*
663: * Push the packet out to the card.
664: */
665: for (top = m; m != NULL; m = m->m_next) {
666: /* Words... */
667: if (m->m_len > 1)
668: bus_space_write_multi_stream_2(bst, bsh, DATA_REG_W,
669: mtod(m, u_int16_t *), m->m_len >> 1);
670:
671: /* ...and the remaining byte, if any. */
672: if (m->m_len & 1)
673: bus_space_write_1(bst, bsh, DATA_REG_B,
674: *(u_int8_t *)(mtod(m, u_int8_t *) + (m->m_len - 1)));
675: }
676:
677: #ifdef SMC91CXX_SW_PAD
678: /*
679: * Push out padding.
680: */
681: while (pad > 1) {
682: bus_space_write_2(bst, bsh, DATA_REG_W, 0);
683: pad -= 2;
684: }
685: if (pad)
686: bus_space_write_1(bst, bsh, DATA_REG_B, 0);
687: #endif
688:
689: /*
690: * Push out control byte and unused packet byte. The control byte
691: * is 0, meaning the packet is even lengthed and no special
692: * CRC handling is necessary.
693: */
694: bus_space_write_2(bst, bsh, DATA_REG_W, 0);
695:
696: /*
697: * Enable transmit interrupts and let the chip go. Set a watchdog
698: * in case we miss the interrupt.
699: */
700: bus_space_write_1(bst, bsh, INTR_MASK_REG_B,
701: bus_space_read_1(bst, bsh, INTR_MASK_REG_B) |
702: IM_TX_INT | IM_TX_EMPTY_INT);
703:
704: bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_ENQUEUE);
705:
706: ifp->if_timer = 5;
707:
708: #if NBPFILTER > 0
709: /* Hand off a copy to the bpf. */
710: if (ifp->if_bpf)
711: bpf_mtap(ifp->if_bpf, top, BPF_DIRECTION_OUT);
712: #endif
713:
714: ifp->if_opackets++;
715: m_freem(top);
716:
717: readcheck:
718: /*
719: * Check for incoming pcakets. We don't want to overflow the small
720: * RX FIFO. If nothing has arrived, attempt to queue another
721: * transmit packet.
722: */
723: if (bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W) & FIFO_REMPTY)
724: goto again;
725: }
726:
727: /*
728: * Interrupt service routine.
729: */
730: int
731: smc91cxx_intr(arg)
732: void *arg;
733: {
734: struct smc91cxx_softc *sc = arg;
735: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
736: bus_space_tag_t bst = sc->sc_bst;
737: bus_space_handle_t bsh = sc->sc_bsh;
738: u_int8_t mask, interrupts, status;
739: u_int16_t packetno, tx_status, card_stats;
740:
741: if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0 ||
742: (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
743: return (0);
744:
745: SMC_SELECT_BANK(sc, 2);
746:
747: /*
748: * Obtain the current interrupt mask.
749: */
750: mask = bus_space_read_1(bst, bsh, INTR_MASK_REG_B);
751:
752: /*
753: * Get the set of interrupt which occurred and eliminate any
754: * which are not enabled.
755: */
756: interrupts = bus_space_read_1(bst, bsh, INTR_STAT_REG_B);
757: status = interrupts & mask;
758:
759: /* Ours? */
760: if (status == 0)
761: return (0);
762:
763: /*
764: * It's ours; disable all interrupts while we process them.
765: */
766: bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0);
767:
768: /*
769: * Receive overrun interrupts.
770: */
771: if (status & IM_RX_OVRN_INT) {
772: bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_RX_OVRN_INT);
773: ifp->if_ierrors++;
774: }
775:
776: /*
777: * Receive interrupts.
778: */
779: if (status & IM_RCV_INT) {
780: #if 1 /* DIAGNOSTIC */
781: packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W);
782: if (packetno & FIFO_REMPTY) {
783: printf("%s: receive interrupt on empty fifo\n",
784: sc->sc_dev.dv_xname);
785: goto out;
786: } else
787: #endif
788: smc91cxx_read(sc);
789: }
790:
791: /*
792: * Memory allocation interrupts.
793: */
794: if (status & IM_ALLOC_INT) {
795: /* Disable this interrupt. */
796: mask &= ~IM_ALLOC_INT;
797:
798: /*
799: * Release the just-allocated memory. We will reallocate
800: * it through the normal start logic.
801: */
802: while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
803: /* XXX bound this loop! */ ;
804: bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_FREEPKT);
805:
806: ifp->if_flags &= ~IFF_OACTIVE;
807: ifp->if_timer = 0;
808: }
809:
810: /*
811: * Transmit complete interrupt. Handle transmission error messages.
812: * This will only be called on error condition because of AUTO RELEASE
813: * mode.
814: */
815: if (status & IM_TX_INT) {
816: bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_TX_INT);
817:
818: packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W) &
819: FIFO_TX_MASK;
820:
821: /*
822: * Select this as the packet to read from.
823: */
824: bus_space_write_1(bst, bsh, PACKET_NUM_REG_B, packetno);
825:
826: /*
827: * Position the pointer to the beginning of the packet.
828: */
829: bus_space_write_2(bst, bsh, POINTER_REG_W,
830: PTR_AUTOINC | PTR_READ /* | 0x0000 */);
831:
832: /*
833: * Fetch the TX status word. This will be a copy of
834: * the EPH_STATUS_REG_W at the time of the transmission
835: * failure.
836: */
837: tx_status = bus_space_read_2(bst, bsh, DATA_REG_W);
838:
839: if (tx_status & EPHSR_TX_SUC)
840: printf("%s: successful packet caused TX interrupt?!\n",
841: sc->sc_dev.dv_xname);
842: else
843: ifp->if_oerrors++;
844:
845: if (tx_status & EPHSR_LATCOL)
846: ifp->if_collisions++;
847:
848: /*
849: * Some of these errors disable the transmitter; reenable it.
850: */
851: SMC_SELECT_BANK(sc, 0);
852: #ifdef SMC91CXX_SW_PAD
853: bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, TCR_ENABLE);
854: #else
855: bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W,
856: TCR_ENABLE | TCR_PAD_ENABLE);
857: #endif
858:
859: /*
860: * Kill the failed packet and wait for the MMU to unbusy.
861: */
862: SMC_SELECT_BANK(sc, 2);
863: while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
864: /* XXX bound this loop! */ ;
865: bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_FREEPKT);
866:
867: ifp->if_timer = 0;
868: }
869:
870: /*
871: * Transmit underrun interrupts. We use this opportunity to
872: * update transmit statistics from the card.
873: */
874: if (status & IM_TX_EMPTY_INT) {
875: bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_TX_EMPTY_INT);
876:
877: /* Disable this interrupt. */
878: mask &= ~IM_TX_EMPTY_INT;
879:
880: SMC_SELECT_BANK(sc, 0);
881: card_stats = bus_space_read_2(bst, bsh, COUNTER_REG_W);
882:
883: /* Single collisions. */
884: ifp->if_collisions += card_stats & ECR_COLN_MASK;
885:
886: /* Multiple collisions. */
887: ifp->if_collisions += (card_stats & ECR_MCOLN_MASK) >> 4;
888:
889: SMC_SELECT_BANK(sc, 2);
890:
891: ifp->if_timer = 0;
892: }
893:
894: /*
895: * Other errors. Reset the interface.
896: */
897: if (status & IM_EPH_INT) {
898: smc91cxx_stop(sc);
899: smc91cxx_init(sc);
900: }
901:
902: /*
903: * Attempt to queue more packets for transmission.
904: */
905: smc91cxx_start(ifp);
906:
907: out:
908: /*
909: * Reenable the interrupts we wish to receive now that processing
910: * is complete.
911: */
912: mask |= bus_space_read_1(bst, bsh, INTR_MASK_REG_B);
913: bus_space_write_1(bst, bsh, INTR_MASK_REG_B, mask);
914:
915: return (1);
916: }
917:
918: /*
919: * Read a packet from the card and pass it up to the kernel.
920: * NOTE! WE EXPECT TO BE IN REGISTER WINDOW 2!
921: */
922: void
923: smc91cxx_read(sc)
924: struct smc91cxx_softc *sc;
925: {
926: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
927: bus_space_tag_t bst = sc->sc_bst;
928: bus_space_handle_t bsh = sc->sc_bsh;
929: struct mbuf *m;
930: u_int16_t status, packetno, packetlen;
931: u_int8_t *data;
932:
933: again:
934: /*
935: * Set data pointer to the beginning of the packet. Since
936: * PTR_RCV is set, the packet number will be found automatically
937: * in FIFO_PORTS_REG_W, FIFO_RX_MASK.
938: */
939: bus_space_write_2(bst, bsh, POINTER_REG_W,
940: PTR_READ | PTR_RCV | PTR_AUTOINC /* | 0x0000 */);
941:
942: /*
943: * First two words are status and packet length.
944: */
945: status = bus_space_read_2(bst, bsh, DATA_REG_W);
946: packetlen = bus_space_read_2(bst, bsh, DATA_REG_W);
947:
948: /*
949: * The packet length includes 3 extra words: status, length,
950: * and an extra word that includes the control byte.
951: */
952: packetlen -= 6;
953:
954: /*
955: * Account for receive errors and discard.
956: */
957: if (status & RS_ERRORS) {
958: ifp->if_ierrors++;
959: goto out;
960: }
961:
962: /*
963: * Adjust for odd-length packet.
964: */
965: if (status & RS_ODDFRAME)
966: packetlen++;
967:
968: /*
969: * Allocate a header mbuf.
970: */
971: MGETHDR(m, M_DONTWAIT, MT_DATA);
972: if (m == NULL)
973: goto out;
974: m->m_pkthdr.rcvif = ifp;
975: m->m_pkthdr.len = packetlen;
976:
977: /*
978: * Always put the packet in a cluster.
979: * XXX should chain small mbufs if less than threshold.
980: */
981: MCLGET(m, M_DONTWAIT);
982: if ((m->m_flags & M_EXT) == 0) {
983: m_freem(m);
984: ifp->if_ierrors++;
985: printf("%s: can't allocate cluster for incoming packet\n",
986: sc->sc_dev.dv_xname);
987: goto out;
988: }
989:
990: /*
991: * Pull the packet off the interface. Make sure the payload
992: * is aligned.
993: */
994: m->m_data = (caddr_t) ALIGN(mtod(m, caddr_t) +
995: sizeof(struct ether_header)) - sizeof(struct ether_header);
996:
997: data = mtod(m, u_int8_t *);
998: if (packetlen > 1)
999: bus_space_read_multi_stream_2(bst, bsh, DATA_REG_W,
1000: (u_int16_t *)data, packetlen >> 1);
1001: if (packetlen & 1) {
1002: data += packetlen & ~1;
1003: *data = bus_space_read_1(bst, bsh, DATA_REG_B);
1004: }
1005:
1006: ifp->if_ipackets++;
1007:
1008: #if NBPFILTER > 0
1009: /*
1010: * Hand the packet off to bpf listeners. If there's a bpf listener,
1011: * we need to check if the packet is ours.
1012: */
1013: if (ifp->if_bpf)
1014: bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
1015: #endif
1016:
1017: m->m_pkthdr.len = m->m_len = packetlen;
1018: ether_input_mbuf(ifp, m);
1019:
1020: out:
1021: /*
1022: * Tell the card to free the memory occupied by this packet.
1023: */
1024: while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
1025: /* XXX bound this loop! */ ;
1026: bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_RELEASE);
1027:
1028: /*
1029: * Check for another packet.
1030: */
1031: packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W);
1032: if (packetno & FIFO_REMPTY)
1033: return;
1034: goto again;
1035: }
1036:
1037: /*
1038: * Process an ioctl request.
1039: */
1040: int
1041: smc91cxx_ioctl(ifp, cmd, data)
1042: struct ifnet *ifp;
1043: u_long cmd;
1044: caddr_t data;
1045: {
1046: struct smc91cxx_softc *sc = ifp->if_softc;
1047: struct ifaddr *ifa = (struct ifaddr *)data;
1048: struct ifreq *ifr = (struct ifreq *)data;
1049: int s, error = 0;
1050:
1051: s = splnet();
1052:
1053: switch (cmd) {
1054: case SIOCSIFADDR:
1055: if ((error = smc91cxx_enable(sc)) != 0)
1056: break;
1057: ifp->if_flags |= IFF_UP;
1058: switch (ifa->ifa_addr->sa_family) {
1059: #ifdef INET
1060: case AF_INET:
1061: smc91cxx_init(sc);
1062: arp_ifinit(&sc->sc_arpcom, ifa);
1063: break;
1064: #endif
1065: default:
1066: smc91cxx_init(sc);
1067: break;
1068: }
1069: break;
1070:
1071: case SIOCSIFFLAGS:
1072: if ((ifp->if_flags & IFF_UP) == 0 &&
1073: (ifp->if_flags & IFF_RUNNING) != 0) {
1074: /*
1075: * If interface is marked down and it is running,
1076: * stop it.
1077: */
1078: smc91cxx_stop(sc);
1079: ifp->if_flags &= ~IFF_RUNNING;
1080: smc91cxx_disable(sc);
1081: } else if ((ifp->if_flags & IFF_UP) != 0 &&
1082: (ifp->if_flags & IFF_RUNNING) == 0) {
1083: /*
1084: * If interface is marked up and it is stopped,
1085: * start it.
1086: */
1087: if ((error = smc91cxx_enable(sc)) != 0)
1088: break;
1089: smc91cxx_init(sc);
1090: } else if ((ifp->if_flags & IFF_UP) != 0) {
1091: /*
1092: * Reset the interface to pick up changes in any
1093: * other flags that affect hardware registers.
1094: */
1095: smc91cxx_reset(sc);
1096: }
1097: break;
1098:
1099: case SIOCADDMULTI:
1100: case SIOCDELMULTI:
1101: if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0) {
1102: error = EIO;
1103: break;
1104: }
1105:
1106: error = (cmd == SIOCADDMULTI) ?
1107: ether_addmulti(ifr, &sc->sc_arpcom) :
1108: ether_delmulti(ifr, &sc->sc_arpcom);
1109: if (error == ENETRESET) {
1110: /*
1111: * Multicast list has changed; set the hardware
1112: * filter accordingly.
1113: */
1114: if (ifp->if_flags & IFF_RUNNING)
1115: smc91cxx_reset(sc);
1116: error = 0;
1117: }
1118: break;
1119:
1120: case SIOCGIFMEDIA:
1121: case SIOCSIFMEDIA:
1122: error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
1123: break;
1124:
1125: default:
1126: error = EINVAL;
1127: break;
1128: }
1129:
1130: splx(s);
1131: return (error);
1132: }
1133:
1134: /*
1135: * Reset the interface.
1136: */
1137: void
1138: smc91cxx_reset(sc)
1139: struct smc91cxx_softc *sc;
1140: {
1141: int s;
1142:
1143: s = splnet();
1144: smc91cxx_stop(sc);
1145: smc91cxx_init(sc);
1146: splx(s);
1147: }
1148:
1149: /*
1150: * Watchdog timer.
1151: */
1152: void
1153: smc91cxx_watchdog(ifp)
1154: struct ifnet *ifp;
1155: {
1156: struct smc91cxx_softc *sc = ifp->if_softc;
1157:
1158: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
1159: ++sc->sc_arpcom.ac_if.if_oerrors;
1160:
1161: smc91cxx_reset(sc);
1162: }
1163:
1164: /*
1165: * Stop output on the interface.
1166: */
1167: void
1168: smc91cxx_stop(sc)
1169: struct smc91cxx_softc *sc;
1170: {
1171: bus_space_tag_t bst = sc->sc_bst;
1172: bus_space_handle_t bsh = sc->sc_bsh;
1173:
1174: /*
1175: * Clear interrupt mask; disable all interrupts.
1176: */
1177: SMC_SELECT_BANK(sc, 2);
1178: bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0);
1179:
1180: /*
1181: * Disable transmitter and receiver.
1182: */
1183: SMC_SELECT_BANK(sc, 0);
1184: bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, 0);
1185: bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 0);
1186:
1187: /*
1188: * Cancel watchdog timer.
1189: */
1190: sc->sc_arpcom.ac_if.if_timer = 0;
1191: }
1192:
1193: /*
1194: * Enable power on the interface.
1195: */
1196: int
1197: smc91cxx_enable(sc)
1198: struct smc91cxx_softc *sc;
1199: {
1200: if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0 && sc->sc_enable != NULL) {
1201: if ((*sc->sc_enable)(sc) != 0) {
1202: printf("%s: device enable failed\n",
1203: sc->sc_dev.dv_xname);
1204: return (EIO);
1205: }
1206: }
1207:
1208: sc->sc_flags |= SMC_FLAGS_ENABLED;
1209: return (0);
1210: }
1211:
1212: /*
1213: * Disable power on the interface.
1214: */
1215: void
1216: smc91cxx_disable(sc)
1217: struct smc91cxx_softc *sc;
1218: {
1219: if ((sc->sc_flags & SMC_FLAGS_ENABLED) != 0 && sc->sc_disable != NULL) {
1220: (*sc->sc_disable)(sc);
1221: sc->sc_flags &= ~SMC_FLAGS_ENABLED;
1222: }
1223: }
1224:
1225: int
1226: smc91cxx_activate(self, act)
1227: struct device *self;
1228: enum devact act;
1229: {
1230: #if 0
1231: struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
1232: #endif
1233: int rv = 0, s;
1234:
1235: s = splnet();
1236: switch (act) {
1237: case DVACT_ACTIVATE:
1238: break;
1239:
1240: case DVACT_DEACTIVATE:
1241: #if 0
1242: if_deactivate(&sc->sc_ic.ic_if);
1243: #endif
1244: break;
1245: }
1246: splx(s);
1247: return(rv);
1248: }
1249:
1250: int
1251: smc91cxx_detach(self, flags)
1252: struct device *self;
1253: int flags;
1254: {
1255: struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
1256: struct ifnet *ifp = &sc->sc_arpcom.ac_if;
1257:
1258: /* Succeed now if there's no work to do. */
1259: if ((sc->sc_flags & SMC_FLAGS_ATTACHED) == 0)
1260: return(0);
1261:
1262: /* smc91cxx_disable() checks SMC_FLAGS_ENABLED */
1263: smc91cxx_disable(sc);
1264:
1265: /* smc91cxx_attach() never fails */
1266:
1267: /* Delete all media. */
1268: ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
1269:
1270: #if NBPFILTER > 0
1271: bpfdetach(ifp);
1272: #endif
1273: ether_ifdetach(ifp);
1274: if_detach(ifp);
1275:
1276: return (0);
1277: }
1278:
1279: u_int32_t
1280: smc91cxx_mii_bitbang_read(self)
1281: struct device *self;
1282: {
1283: struct smc91cxx_softc *sc = (void *) self;
1284:
1285: /* We're already in bank 3. */
1286: return (bus_space_read_2(sc->sc_bst, sc->sc_bsh, MGMT_REG_W));
1287: }
1288:
1289: void
1290: smc91cxx_mii_bitbang_write(self, val)
1291: struct device *self;
1292: u_int32_t val;
1293: {
1294: struct smc91cxx_softc *sc = (void *) self;
1295:
1296: /* We're already in bank 3. */
1297: bus_space_write_2(sc->sc_bst, sc->sc_bsh, MGMT_REG_W, val);
1298: }
1299:
1300: int
1301: smc91cxx_mii_readreg(self, phy, reg)
1302: struct device *self;
1303: int phy, reg;
1304: {
1305: struct smc91cxx_softc *sc = (void *) self;
1306: int val;
1307:
1308: SMC_SELECT_BANK(sc, 3);
1309:
1310: val = mii_bitbang_readreg(self, &smc91cxx_mii_bitbang_ops, phy, reg);
1311:
1312: SMC_SELECT_BANK(sc, 2);
1313:
1314: return (val);
1315: }
1316:
1317: void
1318: smc91cxx_mii_writereg(self, phy, reg, val)
1319: struct device *self;
1320: int phy, reg, val;
1321: {
1322: struct smc91cxx_softc *sc = (void *) self;
1323:
1324: SMC_SELECT_BANK(sc, 3);
1325:
1326: mii_bitbang_writereg(self, &smc91cxx_mii_bitbang_ops, phy, reg, val);
1327:
1328: SMC_SELECT_BANK(sc, 2);
1329: }
1330:
1331: void
1332: smc91cxx_statchg(self)
1333: struct device *self;
1334: {
1335: struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
1336: bus_space_tag_t bst = sc->sc_bst;
1337: bus_space_handle_t bsh = sc->sc_bsh;
1338: int mctl;
1339:
1340: SMC_SELECT_BANK(sc, 0);
1341: mctl = bus_space_read_2(bst, bsh, TXMIT_CONTROL_REG_W);
1342: if (sc->sc_mii.mii_media_active & IFM_FDX)
1343: mctl |= TCR_SWFDUP;
1344: else
1345: mctl &= ~TCR_SWFDUP;
1346: bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, mctl);
1347: SMC_SELECT_BANK(sc, 2); /* back to operating window */
1348: }
1349:
1350: /*
1351: * One second timer, used to tick the MII.
1352: */
1353: void
1354: smc91cxx_tick(arg)
1355: void *arg;
1356: {
1357: struct smc91cxx_softc *sc = arg;
1358: int s;
1359:
1360: #ifdef DIAGNOSTIC
1361: if ((sc->sc_flags & SMC_FLAGS_HAS_MII) == 0)
1362: panic("smc91cxx_tick");
1363: #endif
1364:
1365: if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
1366: return;
1367:
1368: s = splnet();
1369: mii_tick(&sc->sc_mii);
1370: splx(s);
1371:
1372: timeout_add(&sc->sc_mii_timeout, hz);
1373: }
CVSweb