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