Bug Summary

File:dev/ic/smc91cxx.c
Warning:line 538, column 16
Although the value stored to 'top' is used in the enclosing expression, the value is never actually read from 'top'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name smc91cxx.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model static -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -ffreestanding -mcmodel=kernel -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -target-feature -sse2 -target-feature -sse -target-feature -3dnow -target-feature -mmx -target-feature +save-args -disable-red-zone -no-implicit-float -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -nostdsysteminc -nobuiltininc -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/sys -I /usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -I /usr/src/sys/arch -I /usr/src/sys/dev/pci/drm/include -I /usr/src/sys/dev/pci/drm/include/uapi -I /usr/src/sys/dev/pci/drm/amd/include/asic_reg -I /usr/src/sys/dev/pci/drm/amd/include -I /usr/src/sys/dev/pci/drm/amd/amdgpu -I /usr/src/sys/dev/pci/drm/amd/display -I /usr/src/sys/dev/pci/drm/amd/display/include -I /usr/src/sys/dev/pci/drm/amd/display/dc -I /usr/src/sys/dev/pci/drm/amd/display/amdgpu_dm -I /usr/src/sys/dev/pci/drm/amd/pm/inc -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu11 -I /usr/src/sys/dev/pci/drm/amd/pm/swsmu/smu12 -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/hwmgr -I /usr/src/sys/dev/pci/drm/amd/pm/powerplay/smumgr -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc -I /usr/src/sys/dev/pci/drm/amd/display/dc/inc/hw -I /usr/src/sys/dev/pci/drm/amd/display/dc/clk_mgr -I /usr/src/sys/dev/pci/drm/amd/display/modules/inc -I /usr/src/sys/dev/pci/drm/amd/display/modules/hdcp -I /usr/src/sys/dev/pci/drm/amd/display/dmub/inc -I /usr/src/sys/dev/pci/drm/i915 -D DDB -D DIAGNOSTIC -D KTRACE -D ACCOUNTING -D KMEMSTATS -D PTRACE -D POOL_DEBUG -D CRYPTO -D SYSVMSG -D SYSVSEM -D SYSVSHM -D UVM_SWAP_ENCRYPT -D FFS -D FFS2 -D FFS_SOFTUPDATES -D UFS_DIRHASH -D QUOTA -D EXT2FS -D MFS -D NFSCLIENT -D NFSSERVER -D CD9660 -D UDF -D MSDOSFS -D FIFO -D FUSE -D SOCKET_SPLICE -D TCP_ECN -D TCP_SIGNATURE -D INET6 -D IPSEC -D PPP_BSDCOMP -D PPP_DEFLATE -D PIPEX -D MROUTING -D MPLS -D BOOT_CONFIG -D USER_PCICONF -D APERTURE -D MTRR -D NTFS -D HIBERNATE -D PCIVERBOSE -D USBVERBOSE -D WSDISPLAY_COMPAT_USL -D WSDISPLAY_COMPAT_RAWKBD -D WSDISPLAY_DEFAULTSCREENS=6 -D X86EMU -D ONEWIREVERBOSE -D MULTIPROCESSOR -D MAXUSERS=80 -D _KERNEL -D CONFIG_DRM_AMD_DC_DCN3_0 -O2 -Wno-pointer-sign -Wno-address-of-packed-member -Wno-constant-conversion -Wno-unused-but-set-variable -Wno-gnu-folding-constant -fdebug-compilation-dir=/usr/src/sys/arch/amd64/compile/GENERIC.MP/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -o /usr/obj/sys/arch/amd64/compile/GENERIC.MP/scan-build/2022-01-12-131800-47421-1 -x c /usr/src/sys/dev/ic/smc91cxx.c
1/* $OpenBSD: smc91cxx.c,v 1.51 2022/01/09 05:42:42 jsg 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 derived 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 NBPFILTER1 > 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_2bus_space_write_multi_2 bus_space_write_multi_2
110#define bus_space_write_multi_stream_4bus_space_write_multi_4 bus_space_write_multi_4
111#define bus_space_read_multi_stream_2bus_space_read_multi_2 bus_space_read_multi_2
112#define bus_space_read_multi_stream_4bus_space_read_multi_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
118const char *smc91cxx_idstrs[] = {
119 NULL((void *)0), /* 0 */
120 NULL((void *)0), /* 1 */
121 NULL((void *)0), /* 2 */
122 "SMC91C90/91C92", /* 3 */
123 "SMC91C94/91C96", /* 4 */
124 "SMC91C95", /* 5 */
125 NULL((void *)0), /* 6 */
126 "SMC91C100", /* 7 */
127 "SMC91C100FD", /* 8 */
128 NULL((void *)0), /* 9 */
129 NULL((void *)0), /* 10 */
130 NULL((void *)0), /* 11 */
131 NULL((void *)0), /* 12 */
132 NULL((void *)0), /* 13 */
133 NULL((void *)0), /* 14 */
134 NULL((void *)0), /* 15 */
135};
136
137/* Supported media types. */
138const uint64_t smc91cxx_media[] = {
139 IFM_ETHER0x0000000000000100ULL|IFM_10_T3,
140 IFM_ETHER0x0000000000000100ULL|IFM_10_55,
141};
142#define NSMC91CxxMEDIA(sizeof(smc91cxx_media) / sizeof(smc91cxx_media[0])) (sizeof(smc91cxx_media) / sizeof(smc91cxx_media[0]))
143
144/*
145 * MII bit-bang glue.
146 */
147u_int32_t smc91cxx_mii_bitbang_read(struct device *);
148void smc91cxx_mii_bitbang_write(struct device *, u_int32_t);
149
150const struct mii_bitbang_ops smc91cxx_mii_bitbang_ops = {
151 smc91cxx_mii_bitbang_read,
152 smc91cxx_mii_bitbang_write,
153 {
154 MR_MDO0x01, /* MII_BIT_MDO */
155 MR_MDI0x02, /* MII_BIT_MDI */
156 MR_MCLK0x04, /* MII_BIT_MDC */
157 MR_MDOE0x08, /* MII_BIT_DIR_HOST_PHY */
158 0, /* MII_BIT_DIR_PHY_HOST */
159 }
160};
161
162struct cfdriver sm_cd = {
163 NULL((void *)0), "sm", DV_IFNET
164};
165
166/* MII callbacks */
167int smc91cxx_mii_readreg(struct device *, int, int);
168void smc91cxx_mii_writereg(struct device *, int, int, int);
169void smc91cxx_statchg(struct device *);
170void smc91cxx_tick(void *);
171
172int smc91cxx_mediachange(struct ifnet *);
173void smc91cxx_mediastatus(struct ifnet *, struct ifmediareq *);
174
175int smc91cxx_set_media(struct smc91cxx_softc *, uint64_t);
176
177void smc91cxx_read(struct smc91cxx_softc *);
178void smc91cxx_reset(struct smc91cxx_softc *);
179void smc91cxx_start(struct ifnet *);
180void smc91cxx_resume(struct smc91cxx_softc *);
181void smc91cxx_watchdog(struct ifnet *);
182int smc91cxx_ioctl(struct ifnet *, u_long, caddr_t);
183
184void
185smc91cxx_attach(struct smc91cxx_softc *sc, u_int8_t *myea)
186{
187 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
188 bus_space_tag_t bst = sc->sc_bst;
189 bus_space_handle_t bsh = sc->sc_bsh;
190 struct ifmedia *ifm = &sc->sc_mii.mii_media;
191 u_int32_t miicapabilities;
192 u_int16_t tmp;
193 int i, aui;
194 const char *idstr;
195
196 /* Make sure the chip is stopped. */
197 smc91cxx_stop(sc);
198
199 SMC_SELECT_BANK(sc, 3)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((3
))))
;
200 tmp = bus_space_read_2(bst, bsh, REVISION_REG_W)((bst)->read_2((bsh), (0x0a)));
201 sc->sc_chipid = RR_ID(tmp)(((tmp) >> 4) & 0x0f);
202 /* check magic number */
203 if ((tmp & BSR_DETECT_MASK0xff00) != BSR_DETECT_VALUE0x3300) {
204 idstr = NULL((void *)0);
205 printf("%s: invalid BSR 0x%04x\n", sc->sc_dev.dv_xname, tmp);
206 } else
207 idstr = smc91cxx_idstrs[RR_ID(tmp)(((tmp) >> 4) & 0x0f)];
208#ifdef SMC_DEBUG
209 printf("\n%s: ", sc->sc_dev.dv_xname);
210 if (idstr != NULL((void *)0))
211 printf("%s, ", idstr);
212 else
213 printf("unknown chip id %d, ", sc->sc_chipid);
214 printf("revision %d", RR_REV(tmp)((tmp) & 0x0f));
215#endif
216
217 /* Read the station address from the chip. */
218 SMC_SELECT_BANK(sc, 1)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((1
))))
;
219 if (myea == NULL((void *)0)) {
220 for (i = 0; i < ETHER_ADDR_LEN6; i += 2) {
221 tmp = bus_space_read_2(bst, bsh, IAR_ADDR0_REG_W + i)((bst)->read_2((bsh), (0x04 + i)));
222 sc->sc_arpcom.ac_enaddr[i + 1] = (tmp >>8) & 0xff;
223 sc->sc_arpcom.ac_enaddr[i] = tmp & 0xff;
224 }
225 } else {
226 bcopy(myea, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN6);
227 }
228
229 printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
230
231 /* Initialize the ifnet structure. */
232 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ16);
233 ifp->if_softc = sc;
234 ifp->if_start = smc91cxx_start;
235 ifp->if_ioctl = smc91cxx_ioctl;
236 ifp->if_watchdog = smc91cxx_watchdog;
237 ifp->if_flags =
238 IFF_BROADCAST0x2 | IFF_SIMPLEX0x800 | IFF_MULTICAST0x8000;
239
240 /* Attach the interface. */
241 if_attach(ifp);
242 ether_ifattach(ifp);
243
244 /*
245 * Initialize our media structures and MII info. We will
246 * probe the MII if we are on the SMC91Cxx
247 */
248 sc->sc_mii.mii_ifp = ifp;
249 sc->sc_mii.mii_readreg = smc91cxx_mii_readreg;
250 sc->sc_mii.mii_writereg = smc91cxx_mii_writereg;
251 sc->sc_mii.mii_statchg = smc91cxx_statchg;
252 ifmedia_init(ifm, 0, smc91cxx_mediachange, smc91cxx_mediastatus);
253
254 SMC_SELECT_BANK(sc, 1)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((1
))))
;
255 tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W)((bst)->read_2((bsh), (0x00)));
256
257 miicapabilities = BMSR_MEDIAMASK(0x8000|0x4000|0x2000| 0x1000|0x0800|0x0400|0x0200)|BMSR_ANEG0x0008;
258 switch (sc->sc_chipid) {
259 case CHIP_911007:
260 /*
261 * The 91100 does not have full-duplex capabilities,
262 * even if the PHY does.
263 */
264 miicapabilities &= ~(BMSR_100TXFDX0x4000 | BMSR_10TFDX0x1000);
265 /* FALLTHROUGH */
266 case CHIP_91100FD8:
267 if (tmp & CR_MII_SELECT0x8000) {
268#ifdef SMC_DEBUG
269 printf("%s: default media MII\n",
270 sc->sc_dev.dv_xname);
271#endif
272 mii_attach(&sc->sc_dev, &sc->sc_mii, miicapabilities,
273 MII_PHY_ANY-1, MII_OFFSET_ANY-1, 0);
274 if (LIST_FIRST(&sc->sc_mii.mii_phys)((&sc->sc_mii.mii_phys)->lh_first) == NULL((void *)0)) {
275 ifmedia_add(&sc->sc_mii.mii_media,
276 IFM_ETHER0x0000000000000100ULL|IFM_NONE2ULL, 0, NULL((void *)0));
277 ifmedia_set(&sc->sc_mii.mii_media,
278 IFM_ETHER0x0000000000000100ULL|IFM_NONE2ULL);
279 } else {
280 ifmedia_set(&sc->sc_mii.mii_media,
281 IFM_ETHER0x0000000000000100ULL|IFM_AUTO0ULL);
282 }
283 sc->sc_flags |= SMC_FLAGS_HAS_MII0x0004;
284 break;
285 }
286 /* FALLTHROUGH */
287 default:
288 aui = tmp & CR_AUI_SELECT0x0100;
289#ifdef SMC_DEBUG
290 printf("%s: default media %s\n", sc->sc_dev.dv_xname,
291 aui ? "AUI" : "UTP");
292#endif
293 for (i = 0; i < NSMC91CxxMEDIA(sizeof(smc91cxx_media) / sizeof(smc91cxx_media[0])); i++)
294 ifmedia_add(ifm, smc91cxx_media[i], 0, NULL((void *)0));
295 ifmedia_set(ifm, IFM_ETHER0x0000000000000100ULL | (aui ? IFM_10_55 : IFM_10_T3));
296 break;
297 }
298
299 /* The attach is successful. */
300 sc->sc_flags |= SMC_FLAGS_ATTACHED0x0002;
301}
302
303/*
304 * Change media according to request.
305 */
306int
307smc91cxx_mediachange(struct ifnet *ifp)
308{
309 struct smc91cxx_softc *sc = ifp->if_softc;
310
311 return (smc91cxx_set_media(sc, sc->sc_mii.mii_media.ifm_media));
312}
313
314int
315smc91cxx_set_media(struct smc91cxx_softc *sc, uint64_t media)
316{
317 bus_space_tag_t bst = sc->sc_bst;
318 bus_space_handle_t bsh = sc->sc_bsh;
319 u_int16_t tmp;
320
321 /*
322 * If the interface is not currently powered on, just return.
323 * When it is enabled later, smc91cxx_init() will properly set
324 * up the media for us.
325 */
326 if ((sc->sc_flags & SMC_FLAGS_ENABLED0x0001) == 0)
327 return (0);
328
329 if (IFM_TYPE(media)((media) & 0x000000000000ff00ULL) != IFM_ETHER0x0000000000000100ULL)
330 return (EINVAL22);
331
332 if (sc->sc_flags & SMC_FLAGS_HAS_MII0x0004)
333 return (mii_mediachg(&sc->sc_mii));
334
335 switch (IFM_SUBTYPE(media)((media) & 0x00000000000000ffULL)) {
336 case IFM_10_T3:
337 case IFM_10_55:
338 SMC_SELECT_BANK(sc, 1)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((1
))))
;
339 tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W)((bst)->read_2((bsh), (0x00)));
340 if (IFM_SUBTYPE(media)((media) & 0x00000000000000ffULL) == IFM_10_55)
341 tmp |= CR_AUI_SELECT0x0100;
342 else
343 tmp &= ~CR_AUI_SELECT0x0100;
344 bus_space_write_2(bst, bsh, CONFIG_REG_W, tmp)((bst)->write_2((bsh), (0x00), (tmp)));
345 delay(20000)(*delay_func)(20000); /* XXX is this needed? */
346 break;
347
348 default:
349 return (EINVAL22);
350 }
351
352 return (0);
353}
354
355/*
356 * Notify the world which media we're using.
357 */
358void
359smc91cxx_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
360{
361 struct smc91cxx_softc *sc = ifp->if_softc;
362 bus_space_tag_t bst = sc->sc_bst;
363 bus_space_handle_t bsh = sc->sc_bsh;
364 u_int16_t tmp;
365
366 if ((sc->sc_flags & SMC_FLAGS_ENABLED0x0001) == 0) {
367 ifmr->ifm_active = IFM_ETHER0x0000000000000100ULL | IFM_NONE2ULL;
368 ifmr->ifm_status = 0;
369 return;
370 }
371
372 /*
373 * If we have MII, go ask the PHY what's going on.
374 */
375 if (sc->sc_flags & SMC_FLAGS_HAS_MII0x0004) {
376 mii_pollstat(&sc->sc_mii);
377 ifmr->ifm_active = sc->sc_mii.mii_media_active;
378 ifmr->ifm_status = sc->sc_mii.mii_media_status;
379 return;
380 }
381
382 SMC_SELECT_BANK(sc, 1)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((1
))))
;
383 tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W)((bst)->read_2((bsh), (0x00)));
384 ifmr->ifm_active =
385 IFM_ETHER0x0000000000000100ULL | ((tmp & CR_AUI_SELECT0x0100) ? IFM_10_55 : IFM_10_T3);
386}
387
388/*
389 * Reset and initialize the chip.
390 */
391void
392smc91cxx_init(struct smc91cxx_softc *sc)
393{
394 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
395 bus_space_tag_t bst = sc->sc_bst;
396 bus_space_handle_t bsh = sc->sc_bsh;
397 u_int16_t tmp;
398 int s, i;
399
400 s = splnet()splraise(0x7);
401
402 /*
403 * This resets the registers mostly to defaults, but doesn't
404 * affect the EEPROM. After the reset cycle, we pause briefly
405 * for the chip to recover.
406 *
407 * XXX how long are we really supposed to delay? --thorpej
408 */
409 SMC_SELECT_BANK(sc, 0)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((0
))))
;
410 bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, RCR_SOFTRESET)((bst)->write_2((bsh), (0x04), (0x8000)));
411 delay(100)(*delay_func)(100);
412 bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, 0)((bst)->write_2((bsh), (0x04), (0)));
413 delay(200)(*delay_func)(200);
414
415 bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 0)((bst)->write_2((bsh), (0x00), (0)));
416
417 /* Set the Ethernet address. */
418 SMC_SELECT_BANK(sc, 1)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((1
))))
;
419 for (i = 0; i < ETHER_ADDR_LEN6; i++ )
420 bus_space_write_1(bst, bsh, IAR_ADDR0_REG_W + i,((bst)->write_1((bsh), (0x04 + i), (sc->sc_arpcom.ac_enaddr
[i])))
421 sc->sc_arpcom.ac_enaddr[i])((bst)->write_1((bsh), (0x04 + i), (sc->sc_arpcom.ac_enaddr
[i])))
;
422
423 /*
424 * Set the control register to automatically release successfully
425 * transmitted packets (making the best use of our limited memory)
426 * and enable the EPH interrupt on certain TX errors.
427 */
428 bus_space_write_2(bst, bsh, CONTROL_REG_W, (CTR_AUTO_RELEASE |((bst)->write_2((bsh), (0x0c), ((0x0800 | 0x0020 | 0x0040 |
0x0080))))
429 CTR_TE_ENABLE | CTR_CR_ENABLE | CTR_LE_ENABLE))((bst)->write_2((bsh), (0x0c), ((0x0800 | 0x0020 | 0x0040 |
0x0080))))
;
430
431 /*
432 * Reset the MMU and wait for it to be un-busy.
433 */
434 SMC_SELECT_BANK(sc, 2)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((2
))))
;
435 bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_RESET)((bst)->write_2((bsh), (0x00), (0x0040)));
436 while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W)((bst)->read_2((bsh), (0x00))) & MMUCR_BUSY0x0001)
437 /* XXX bound this loop! */ ;
438
439 /*
440 * Disable all interrupts.
441 */
442 bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0)((bst)->write_1((bsh), (0x0d), (0)));
443
444 /*
445 * Set current media.
446 */
447 smc91cxx_set_media(sc, sc->sc_mii.mii_media.ifm_cur->ifm_media);
448
449 /*
450 * Set the receive filter. We want receive enable and auto
451 * strip of CRC from received packet. If we are in promisc. mode,
452 * then set that bit as well.
453 *
454 * XXX Initialize multicast filter. For now, we just accept
455 * XXX all multicast.
456 */
457 SMC_SELECT_BANK(sc, 0)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((0
))))
;
458
459 tmp = RCR_ENABLE0x0100 | RCR_STRIP_CRC0x0200 | RCR_ALMUL0x0004;
460 if (ifp->if_flags & IFF_PROMISC0x100)
461 tmp |= RCR_PROMISC0x0002;
462
463 bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, tmp)((bst)->write_2((bsh), (0x04), (tmp)));
464
465 /*
466 * Set transmitter control to "enabled".
467 */
468 tmp = TCR_ENABLE0x0001;
469
470#ifndef SMC91CXX_SW_PAD
471 /*
472 * Enable hardware padding of transmitted packets.
473 * XXX doesn't work?
474 */
475 tmp |= TCR_PAD_ENABLE0x0080;
476#endif
477
478 bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, tmp)((bst)->write_2((bsh), (0x00), (tmp)));
479
480 /*
481 * Now, enable interrupts.
482 */
483 SMC_SELECT_BANK(sc, 2)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((2
))))
;
484
485 bus_space_write_1(bst, bsh, INTR_MASK_REG_B,((bst)->write_1((bsh), (0x0d), (0x20 | 0x10 | 0x01 | 0x02)
))
486 IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT | IM_TX_INT)((bst)->write_1((bsh), (0x0d), (0x20 | 0x10 | 0x01 | 0x02)
))
;
487
488 /* Interface is now running, with no output active. */
489 ifp->if_flags |= IFF_RUNNING0x40;
490 ifq_clr_oactive(&ifp->if_snd);
491
492 if (sc->sc_flags & SMC_FLAGS_HAS_MII0x0004) {
493 /* Start the one second clock. */
494 timeout_set(&sc->sc_mii_timeout, smc91cxx_tick, sc);
495 timeout_add_sec(&sc->sc_mii_timeout, 1);
496 }
497
498 /*
499 * Attempt to start any pending transmission.
500 */
501 smc91cxx_start(ifp);
502
503 splx(s)spllower(s);
504}
505
506/*
507 * Start output on an interface.
508 * Must be called at splnet or interrupt level.
509 */
510void
511smc91cxx_start(struct ifnet *ifp)
512{
513 struct smc91cxx_softc *sc = ifp->if_softc;
514 bus_space_tag_t bst = sc->sc_bst;
515 bus_space_handle_t bsh = sc->sc_bsh;
516 u_int len;
517 struct mbuf *m, *top;
518 u_int16_t length, npages;
519 u_int8_t packetno;
520 int timo, pad;
521
522 if (!(ifp->if_flags & IFF_RUNNING0x40) || ifq_is_oactive(&ifp->if_snd))
523 return;
524
525 again:
526 /*
527 * Peek at the next packet.
528 */
529 m = ifq_deq_begin(&ifp->if_snd);
530 if (m == NULL((void *)0))
531 return;
532
533 /*
534 * Compute the frame length and set pad to give an overall even
535 * number of bytes. Below, we assume that the packet length
536 * is even.
537 */
538 for (len = 0, top = m; m != NULL((void *)0); m = m->m_nextm_hdr.mh_next)
Although the value stored to 'top' is used in the enclosing expression, the value is never actually read from 'top'
539 len += m->m_lenm_hdr.mh_len;
540 pad = (len & 1);
541
542 /*
543 * We drop packets that are too large. Perhaps we should
544 * truncate them instead?
545 */
546 if ((len + pad) > (ETHER_MAX_LEN1518 - ETHER_CRC_LEN4)) {
547 printf("%s: large packet discarded\n", sc->sc_dev.dv_xname);
548 ifp->if_oerrorsif_data.ifi_oerrors++;
549 ifq_deq_commit(&ifp->if_snd, m);
550 m_freem(m);
551 goto readcheck;
552 }
553
554#ifdef SMC91CXX_SW_PAD
555 /*
556 * Not using hardware padding; pad to ETHER_MIN_LEN.
557 */
558 if (len < (ETHER_MIN_LEN64 - ETHER_CRC_LEN4))
559 pad = ETHER_MIN_LEN64 - ETHER_CRC_LEN4 - len;
560#endif
561
562 length = pad + len;
563
564 /*
565 * The MMU has a 256 byte page size. The MMU expects us to
566 * ask for "npages - 1". We include space for the status word,
567 * byte count, and control bytes in the allocation request.
568 */
569 npages = (length + 6) >> 8;
570
571 /*
572 * Now allocate the memory.
573 */
574 SMC_SELECT_BANK(sc, 2)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((2
))))
;
575 bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_ALLOC | npages)((bst)->write_2((bsh), (0x00), (0x0020 | npages)));
576
577 timo = MEMORY_WAIT_TIME1000;
578 do {
579 if (bus_space_read_1(bst, bsh, INTR_STAT_REG_B)((bst)->read_1((bsh), (0x0c))) & IM_ALLOC_INT0x08)
580 break;
581 delay(1)(*delay_func)(1);
582 } while (--timo);
583
584 packetno = bus_space_read_1(bst, bsh, ALLOC_RESULT_REG_B)((bst)->read_1((bsh), (0x03)));
585
586 if (packetno & ARR_FAILED0x80 || timo == 0) {
587 /*
588 * No transmit memory is available. Record the number
589 * of requested pages and enable the allocation completion
590 * interrupt. Set up the watchdog timer in case we miss
591 * the interrupt. Mark the interface as active so that
592 * no one else attempts to transmit while we're allocating
593 * memory.
594 */
595 bus_space_write_1(bst, bsh, INTR_MASK_REG_B,((bst)->write_1((bsh), (0x0d), (((bst)->read_1((bsh), (
0x0d))) | 0x08)))
596 bus_space_read_1(bst, bsh, INTR_MASK_REG_B) | IM_ALLOC_INT)((bst)->write_1((bsh), (0x0d), (((bst)->read_1((bsh), (
0x0d))) | 0x08)))
;
597
598 ifp->if_timer = 5;
599 ifq_deq_rollback(&ifp->if_snd, m);
600 ifq_set_oactive(&ifp->if_snd);
601 return;
602 }
603
604 /*
605 * We have a packet number - set the data window.
606 */
607 bus_space_write_1(bst, bsh, PACKET_NUM_REG_B, packetno)((bst)->write_1((bsh), (0x02), (packetno)));
608
609 /*
610 * Point to the beginning of the packet.
611 */
612 bus_space_write_2(bst, bsh, POINTER_REG_W, PTR_AUTOINC /* | 0x0000 */)((bst)->write_2((bsh), (0x06), (0x4000)));
613
614 /*
615 * Send the packet length (+6 for stats, length, and control bytes)
616 * and the status word (set to zeros).
617 */
618 bus_space_write_2(bst, bsh, DATA_REG_W, 0)((bst)->write_2((bsh), (0x08), (0)));
619 bus_space_write_1(bst, bsh, DATA_REG_B, (length + 6) & 0xff)((bst)->write_1((bsh), (0x08), ((length + 6) & 0xff)));
620 bus_space_write_1(bst, bsh, DATA_REG_B, ((length + 6) >> 8) & 0xff)((bst)->write_1((bsh), (0x08), (((length + 6) >> 8) &
0xff)))
;
621
622 /*
623 * Get the packet from the kernel. This will include the Ethernet
624 * frame header, MAC address, etc.
625 */
626 ifq_deq_commit(&ifp->if_snd, m);
627
628 /*
629 * Push the packet out to the card.
630 */
631 for (top = m; m != NULL((void *)0); m = m->m_nextm_hdr.mh_next) {
632 /* Words... */
633 if (m->m_lenm_hdr.mh_len > 1)
634 bus_space_write_multi_stream_2(bst, bsh, DATA_REG_W,((bst)->write_multi_2((bsh), (0x08), (((u_int16_t *)((m)->
m_hdr.mh_data))), (m->m_hdr.mh_len >> 1)))
635 mtod(m, u_int16_t *), m->m_len >> 1)((bst)->write_multi_2((bsh), (0x08), (((u_int16_t *)((m)->
m_hdr.mh_data))), (m->m_hdr.mh_len >> 1)))
;
636
637 /* ...and the remaining byte, if any. */
638 if (m->m_lenm_hdr.mh_len & 1)
639 bus_space_write_1(bst, bsh, DATA_REG_B,((bst)->write_1((bsh), (0x08), (*(u_int8_t *)(((u_int8_t *
)((m)->m_hdr.mh_data)) + (m->m_hdr.mh_len - 1)))))
640 *(u_int8_t *)(mtod(m, u_int8_t *) + (m->m_len - 1)))((bst)->write_1((bsh), (0x08), (*(u_int8_t *)(((u_int8_t *
)((m)->m_hdr.mh_data)) + (m->m_hdr.mh_len - 1)))))
;
641 }
642
643#ifdef SMC91CXX_SW_PAD
644 /*
645 * Push out padding.
646 */
647 while (pad > 1) {
648 bus_space_write_2(bst, bsh, DATA_REG_W, 0)((bst)->write_2((bsh), (0x08), (0)));
649 pad -= 2;
650 }
651 if (pad)
652 bus_space_write_1(bst, bsh, DATA_REG_B, 0)((bst)->write_1((bsh), (0x08), (0)));
653#endif
654
655 /*
656 * Push out control byte and unused packet byte. The control byte
657 * is 0, meaning the packet is even lengthed and no special
658 * CRC handling is necessary.
659 */
660 bus_space_write_2(bst, bsh, DATA_REG_W, 0)((bst)->write_2((bsh), (0x08), (0)));
661
662 /*
663 * Enable transmit interrupts and let the chip go. Set a watchdog
664 * in case we miss the interrupt.
665 */
666 bus_space_write_1(bst, bsh, INTR_MASK_REG_B,((bst)->write_1((bsh), (0x0d), (((bst)->read_1((bsh), (
0x0d))) | 0x02 | 0x04)))
667 bus_space_read_1(bst, bsh, INTR_MASK_REG_B) |((bst)->write_1((bsh), (0x0d), (((bst)->read_1((bsh), (
0x0d))) | 0x02 | 0x04)))
668 IM_TX_INT | IM_TX_EMPTY_INT)((bst)->write_1((bsh), (0x0d), (((bst)->read_1((bsh), (
0x0d))) | 0x02 | 0x04)))
;
669
670 bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_ENQUEUE)((bst)->write_2((bsh), (0x00), (0x00c0)));
671
672 ifp->if_timer = 5;
673
674#if NBPFILTER1 > 0
675 if (ifp->if_bpf)
676 bpf_mtap(ifp->if_bpf, top, BPF_DIRECTION_OUT(1 << 1));
677#endif
678
679 m_freem(top);
680
681 readcheck:
682 /*
683 * Check for incoming packets. We don't want to overflow the small
684 * RX FIFO. If nothing has arrived, attempt to queue another
685 * transmit packet.
686 */
687 if (bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W)((bst)->read_2((bsh), (0x04))) & FIFO_REMPTY0x8000)
688 goto again;
689}
690
691/*
692 * Interrupt service routine.
693 */
694int
695smc91cxx_intr(void *arg)
696{
697 struct smc91cxx_softc *sc = arg;
698 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
699 bus_space_tag_t bst = sc->sc_bst;
700 bus_space_handle_t bsh = sc->sc_bsh;
701 u_int8_t mask, interrupts, status;
702 u_int16_t packetno, tx_status, card_stats;
703
704 if ((sc->sc_flags & SMC_FLAGS_ENABLED0x0001) == 0 ||
705 (sc->sc_dev.dv_flags & DVF_ACTIVE0x0001) == 0)
706 return (0);
707
708 SMC_SELECT_BANK(sc, 2)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((2
))))
;
709
710 /*
711 * Obtain the current interrupt mask.
712 */
713 mask = bus_space_read_1(bst, bsh, INTR_MASK_REG_B)((bst)->read_1((bsh), (0x0d)));
714
715 /*
716 * Get the set of interrupt which occurred and eliminate any
717 * which are not enabled.
718 */
719 interrupts = bus_space_read_1(bst, bsh, INTR_STAT_REG_B)((bst)->read_1((bsh), (0x0c)));
720 status = interrupts & mask;
721
722 /* Ours? */
723 if (status == 0)
724 return (0);
725
726 /*
727 * It's ours; disable all interrupts while we process them.
728 */
729 bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0)((bst)->write_1((bsh), (0x0d), (0)));
730
731 /*
732 * Receive overrun interrupts.
733 */
734 if (status & IM_RX_OVRN_INT0x10) {
735 bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_RX_OVRN_INT)((bst)->write_1((bsh), (0x0c), (0x10)));
736 ifp->if_ierrorsif_data.ifi_ierrors++;
737 }
738
739 /*
740 * Receive interrupts.
741 */
742 if (status & IM_RCV_INT0x01) {
743#if 1 /* DIAGNOSTIC */
744 packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W)((bst)->read_2((bsh), (0x04)));
745 if (packetno & FIFO_REMPTY0x8000) {
746 printf("%s: receive interrupt on empty fifo\n",
747 sc->sc_dev.dv_xname);
748 goto out;
749 } else
750#endif
751 smc91cxx_read(sc);
752 }
753
754 /*
755 * Memory allocation interrupts.
756 */
757 if (status & IM_ALLOC_INT0x08) {
758 /* Disable this interrupt. */
759 mask &= ~IM_ALLOC_INT0x08;
760
761 /*
762 * Release the just-allocated memory. We will reallocate
763 * it through the normal start logic.
764 */
765 while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W)((bst)->read_2((bsh), (0x00))) & MMUCR_BUSY0x0001)
766 /* XXX bound this loop! */ ;
767 bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_FREEPKT)((bst)->write_2((bsh), (0x00), (0x00a0)));
768
769 ifq_clr_oactive(&ifp->if_snd);
770 ifp->if_timer = 0;
771 }
772
773 /*
774 * Transmit complete interrupt. Handle transmission error messages.
775 * This will only be called on error condition because of AUTO RELEASE
776 * mode.
777 */
778 if (status & IM_TX_INT0x02) {
779 bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_TX_INT)((bst)->write_1((bsh), (0x0c), (0x02)));
780
781 packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W)((bst)->read_2((bsh), (0x04))) &
782 FIFO_TX_MASK0x007f;
783
784 /*
785 * Select this as the packet to read from.
786 */
787 bus_space_write_1(bst, bsh, PACKET_NUM_REG_B, packetno)((bst)->write_1((bsh), (0x02), (packetno)));
788
789 /*
790 * Position the pointer to the beginning of the packet.
791 */
792 bus_space_write_2(bst, bsh, POINTER_REG_W,((bst)->write_2((bsh), (0x06), (0x4000 | 0x2000)))
793 PTR_AUTOINC | PTR_READ /* | 0x0000 */)((bst)->write_2((bsh), (0x06), (0x4000 | 0x2000)));
794
795 /*
796 * Fetch the TX status word. This will be a copy of
797 * the EPH_STATUS_REG_W at the time of the transmission
798 * failure.
799 */
800 tx_status = bus_space_read_2(bst, bsh, DATA_REG_W)((bst)->read_2((bsh), (0x08)));
801
802 if (tx_status & EPHSR_TX_SUC0x0001)
803 printf("%s: successful packet caused TX interrupt?!\n",
804 sc->sc_dev.dv_xname);
805 else
806 ifp->if_oerrorsif_data.ifi_oerrors++;
807
808 if (tx_status & EPHSR_LATCOL0x0200)
809 ifp->if_collisionsif_data.ifi_collisions++;
810
811 /*
812 * Some of these errors disable the transmitter; reenable it.
813 */
814 SMC_SELECT_BANK(sc, 0)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((0
))))
;
815#ifdef SMC91CXX_SW_PAD
816 bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, TCR_ENABLE)((bst)->write_2((bsh), (0x00), (0x0001)));
817#else
818 bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W,((bst)->write_2((bsh), (0x00), (0x0001 | 0x0080)))
819 TCR_ENABLE | TCR_PAD_ENABLE)((bst)->write_2((bsh), (0x00), (0x0001 | 0x0080)));
820#endif
821
822 /*
823 * Kill the failed packet and wait for the MMU to unbusy.
824 */
825 SMC_SELECT_BANK(sc, 2)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((2
))))
;
826 while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W)((bst)->read_2((bsh), (0x00))) & MMUCR_BUSY0x0001)
827 /* XXX bound this loop! */ ;
828 bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_FREEPKT)((bst)->write_2((bsh), (0x00), (0x00a0)));
829
830 ifp->if_timer = 0;
831 }
832
833 /*
834 * Transmit underrun interrupts. We use this opportunity to
835 * update transmit statistics from the card.
836 */
837 if (status & IM_TX_EMPTY_INT0x04) {
838 bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_TX_EMPTY_INT)((bst)->write_1((bsh), (0x0c), (0x04)));
839
840 /* Disable this interrupt. */
841 mask &= ~IM_TX_EMPTY_INT0x04;
842
843 SMC_SELECT_BANK(sc, 0)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((0
))))
;
844 card_stats = bus_space_read_2(bst, bsh, COUNTER_REG_W)((bst)->read_2((bsh), (0x06)));
845
846 /* Single collisions. */
847 ifp->if_collisionsif_data.ifi_collisions += card_stats & ECR_COLN_MASK0x000f;
848
849 /* Multiple collisions. */
850 ifp->if_collisionsif_data.ifi_collisions += (card_stats & ECR_MCOLN_MASK0x00f0) >> 4;
851
852 SMC_SELECT_BANK(sc, 2)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((2
))))
;
853
854 ifp->if_timer = 0;
855 }
856
857 /*
858 * Other errors. Reset the interface.
859 */
860 if (status & IM_EPH_INT0x20) {
861 smc91cxx_stop(sc);
862 smc91cxx_init(sc);
863 }
864
865 /*
866 * Attempt to queue more packets for transmission.
867 */
868 smc91cxx_start(ifp);
869
870out:
871 /*
872 * Reenable the interrupts we wish to receive now that processing
873 * is complete.
874 */
875 mask |= bus_space_read_1(bst, bsh, INTR_MASK_REG_B)((bst)->read_1((bsh), (0x0d)));
876 bus_space_write_1(bst, bsh, INTR_MASK_REG_B, mask)((bst)->write_1((bsh), (0x0d), (mask)));
877
878 return (1);
879}
880
881/*
882 * Read a packet from the card and pass it up to the kernel.
883 * NOTE! WE EXPECT TO BE IN REGISTER WINDOW 2!
884 */
885void
886smc91cxx_read(struct smc91cxx_softc *sc)
887{
888 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
889 bus_space_tag_t bst = sc->sc_bst;
890 bus_space_handle_t bsh = sc->sc_bsh;
891 struct mbuf_list ml = MBUF_LIST_INITIALIZER(){ ((void *)0), ((void *)0), 0 };
892 struct mbuf *m;
893 u_int16_t status, packetno, packetlen;
894 u_int8_t *data;
895
896 again:
897 /*
898 * Set data pointer to the beginning of the packet. Since
899 * PTR_RCV is set, the packet number will be found automatically
900 * in FIFO_PORTS_REG_W, FIFO_RX_MASK.
901 */
902 bus_space_write_2(bst, bsh, POINTER_REG_W,((bst)->write_2((bsh), (0x06), (0x2000 | 0x8000 | 0x4000))
)
903 PTR_READ | PTR_RCV | PTR_AUTOINC /* | 0x0000 */)((bst)->write_2((bsh), (0x06), (0x2000 | 0x8000 | 0x4000))
)
;
904
905 /*
906 * First two words are status and packet length.
907 */
908 status = bus_space_read_2(bst, bsh, DATA_REG_W)((bst)->read_2((bsh), (0x08)));
909 packetlen = bus_space_read_2(bst, bsh, DATA_REG_W)((bst)->read_2((bsh), (0x08)));
910
911 /*
912 * The packet length includes 3 extra words: status, length,
913 * and an extra word that includes the control byte.
914 */
915 packetlen -= 6;
916
917 /*
918 * Account for receive errors and discard.
919 */
920 if (status & RS_ERRORS(0x8000 | 0x2000 | 0x0800 | 0x0400)) {
921 ifp->if_ierrorsif_data.ifi_ierrors++;
922 goto out;
923 }
924
925 /*
926 * Adjust for odd-length packet.
927 */
928 if (status & RS_ODDFRAME0x1000)
929 packetlen++;
930
931 /*
932 * Allocate a header mbuf.
933 */
934 MGETHDR(m, M_DONTWAIT, MT_DATA)m = m_gethdr((0x0002), (1));
935 if (m == NULL((void *)0))
936 goto out;
937 m->m_pkthdrM_dat.MH.MH_pkthdr.len = packetlen;
938
939 /*
940 * Always put the packet in a cluster.
941 * XXX should chain small mbufs if less than threshold.
942 */
943 MCLGET(m, M_DONTWAIT)(void) m_clget((m), (0x0002), (1 << 11));
944 if ((m->m_flagsm_hdr.mh_flags & M_EXT0x0001) == 0) {
945 m_freem(m);
946 ifp->if_ierrorsif_data.ifi_ierrors++;
947 printf("%s: can't allocate cluster for incoming packet\n",
948 sc->sc_dev.dv_xname);
949 goto out;
950 }
951
952 /*
953 * Pull the packet off the interface. Make sure the payload
954 * is aligned.
955 */
956 m->m_datam_hdr.mh_data = (caddr_t) ALIGN(mtod(m, caddr_t) +(((unsigned long)(((caddr_t)((m)->m_hdr.mh_data)) + sizeof
(struct ether_header)) + (sizeof(long) - 1)) &~(sizeof(long
) - 1))
957 sizeof(struct ether_header))(((unsigned long)(((caddr_t)((m)->m_hdr.mh_data)) + sizeof
(struct ether_header)) + (sizeof(long) - 1)) &~(sizeof(long
) - 1))
- sizeof(struct ether_header);
958
959 data = mtod(m, u_int8_t *)((u_int8_t *)((m)->m_hdr.mh_data));
960 if (packetlen > 1)
961 bus_space_read_multi_stream_2(bst, bsh, DATA_REG_W,((bst)->read_multi_2((bsh), (0x08), ((u_int16_t *)data), (
packetlen >> 1)))
962 (u_int16_t *)data, packetlen >> 1)((bst)->read_multi_2((bsh), (0x08), ((u_int16_t *)data), (
packetlen >> 1)))
;
963 if (packetlen & 1) {
964 data += packetlen & ~1;
965 *data = bus_space_read_1(bst, bsh, DATA_REG_B)((bst)->read_1((bsh), (0x08)));
966 }
967
968 m->m_pkthdrM_dat.MH.MH_pkthdr.len = m->m_lenm_hdr.mh_len = packetlen;
969 ml_enqueue(&ml, m);
970
971 out:
972 /*
973 * Tell the card to free the memory occupied by this packet.
974 */
975 while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W)((bst)->read_2((bsh), (0x00))) & MMUCR_BUSY0x0001)
976 /* XXX bound this loop! */ ;
977 bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_RELEASE)((bst)->write_2((bsh), (0x00), (0x0080)));
978
979 /*
980 * Check for another packet.
981 */
982 packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W)((bst)->read_2((bsh), (0x04)));
983 if (packetno & FIFO_REMPTY0x8000) {
984 if_input(ifp, &ml);
985 return;
986 }
987 goto again;
988}
989
990/*
991 * Process an ioctl request.
992 */
993int
994smc91cxx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
995{
996 struct smc91cxx_softc *sc = ifp->if_softc;
997 struct ifreq *ifr = (struct ifreq *)data;
998 int s, error = 0;
999
1000 s = splnet()splraise(0x7);
1001
1002 switch (cmd) {
1003 case SIOCSIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((12)))
:
1004 if ((error = smc91cxx_enable(sc)) != 0)
1005 break;
1006 ifp->if_flags |= IFF_UP0x1;
1007 smc91cxx_init(sc);
1008 break;
1009
1010 case SIOCSIFFLAGS((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((16)))
:
1011 if ((ifp->if_flags & IFF_UP0x1) == 0 &&
1012 (ifp->if_flags & IFF_RUNNING0x40) != 0) {
1013 /*
1014 * If interface is marked down and it is running,
1015 * stop it.
1016 */
1017 smc91cxx_stop(sc);
1018 ifp->if_flags &= ~IFF_RUNNING0x40;
1019 smc91cxx_disable(sc);
1020 } else if ((ifp->if_flags & IFF_UP0x1) != 0 &&
1021 (ifp->if_flags & IFF_RUNNING0x40) == 0) {
1022 /*
1023 * If interface is marked up and it is stopped,
1024 * start it.
1025 */
1026 if ((error = smc91cxx_enable(sc)) != 0)
1027 break;
1028 smc91cxx_init(sc);
1029 } else if ((ifp->if_flags & IFF_UP0x1) != 0) {
1030 /*
1031 * Reset the interface to pick up changes in any
1032 * other flags that affect hardware registers.
1033 */
1034 smc91cxx_reset(sc);
1035 }
1036 break;
1037
1038 case SIOCGIFMEDIA(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifmediareq) & 0x1fff) << 16) | ((('i')) <<
8) | ((56)))
:
1039 case SIOCSIFMEDIA(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((55)))
:
1040 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
1041 break;
1042
1043 default:
1044 error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
1045 }
1046
1047 if (error == ENETRESET52) {
1048 if (ifp->if_flags & IFF_RUNNING0x40)
1049 smc91cxx_reset(sc);
1050 error = 0;
1051 }
1052
1053 splx(s)spllower(s);
1054 return (error);
1055}
1056
1057/*
1058 * Reset the interface.
1059 */
1060void
1061smc91cxx_reset(struct smc91cxx_softc *sc)
1062{
1063 int s;
1064
1065 s = splnet()splraise(0x7);
1066 smc91cxx_stop(sc);
1067 smc91cxx_init(sc);
1068 splx(s)spllower(s);
1069}
1070
1071/*
1072 * Watchdog timer.
1073 */
1074void
1075smc91cxx_watchdog(struct ifnet *ifp)
1076{
1077 struct smc91cxx_softc *sc = ifp->if_softc;
1078
1079 log(LOG_ERR3, "%s: device timeout\n", sc->sc_dev.dv_xname);
1080 ++sc->sc_arpcom.ac_if.if_oerrorsif_data.ifi_oerrors;
1081
1082 smc91cxx_reset(sc);
1083}
1084
1085/*
1086 * Stop output on the interface.
1087 */
1088void
1089smc91cxx_stop(struct smc91cxx_softc *sc)
1090{
1091 bus_space_tag_t bst = sc->sc_bst;
1092 bus_space_handle_t bsh = sc->sc_bsh;
1093
1094 /*
1095 * Clear interrupt mask; disable all interrupts.
1096 */
1097 SMC_SELECT_BANK(sc, 2)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((2
))))
;
1098 bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0)((bst)->write_1((bsh), (0x0d), (0)));
1099
1100 /*
1101 * Disable transmitter and receiver.
1102 */
1103 SMC_SELECT_BANK(sc, 0)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((0
))))
;
1104 bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, 0)((bst)->write_2((bsh), (0x04), (0)));
1105 bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 0)((bst)->write_2((bsh), (0x00), (0)));
1106
1107 /*
1108 * Cancel watchdog timer.
1109 */
1110 sc->sc_arpcom.ac_if.if_timer = 0;
1111}
1112
1113/*
1114 * Enable power on the interface.
1115 */
1116int
1117smc91cxx_enable(struct smc91cxx_softc *sc)
1118{
1119 if ((sc->sc_flags & SMC_FLAGS_ENABLED0x0001) == 0 && sc->sc_enable != NULL((void *)0)) {
1120 if ((*sc->sc_enable)(sc) != 0) {
1121 printf("%s: device enable failed\n",
1122 sc->sc_dev.dv_xname);
1123 return (EIO5);
1124 }
1125 }
1126
1127 sc->sc_flags |= SMC_FLAGS_ENABLED0x0001;
1128 return (0);
1129}
1130
1131/*
1132 * Disable power on the interface.
1133 */
1134void
1135smc91cxx_disable(struct smc91cxx_softc *sc)
1136{
1137 if ((sc->sc_flags & SMC_FLAGS_ENABLED0x0001) != 0 && sc->sc_disable != NULL((void *)0)) {
1138 (*sc->sc_disable)(sc);
1139 sc->sc_flags &= ~SMC_FLAGS_ENABLED0x0001;
1140 }
1141}
1142
1143int
1144smc91cxx_activate(struct device *self, int act)
1145{
1146#if 0
1147 struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
1148#endif
1149 int rv = 0, s;
1150
1151 s = splnet()splraise(0x7);
1152 switch (act) {
1153 case DVACT_DEACTIVATE1:
1154#if 0
1155 if_deactivate(&sc->sc_ic.ic_if);
1156#endif
1157 break;
1158 }
1159 splx(s)spllower(s);
1160 return(rv);
1161}
1162
1163int
1164smc91cxx_detach(struct device *self, int flags)
1165{
1166 struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
1167 struct ifnet *ifp = &sc->sc_arpcom.ac_if;
1168
1169 /* Succeed now if there's no work to do. */
1170 if ((sc->sc_flags & SMC_FLAGS_ATTACHED0x0002) == 0)
1171 return(0);
1172
1173 /* smc91cxx_disable() checks SMC_FLAGS_ENABLED */
1174 smc91cxx_disable(sc);
1175
1176 /* smc91cxx_attach() never fails */
1177
1178 /* Delete all media. */
1179 ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY((uint64_t) -1));
1180
1181 ether_ifdetach(ifp);
1182 if_detach(ifp);
1183
1184 return (0);
1185}
1186
1187u_int32_t
1188smc91cxx_mii_bitbang_read(struct device *self)
1189{
1190 struct smc91cxx_softc *sc = (void *) self;
1191
1192 /* We're already in bank 3. */
1193 return (bus_space_read_2(sc->sc_bst, sc->sc_bsh, MGMT_REG_W)((sc->sc_bst)->read_2((sc->sc_bsh), (0x08))));
1194}
1195
1196void
1197smc91cxx_mii_bitbang_write(struct device *self, u_int32_t val)
1198{
1199 struct smc91cxx_softc *sc = (void *) self;
1200
1201 /* We're already in bank 3. */
1202 bus_space_write_2(sc->sc_bst, sc->sc_bsh, MGMT_REG_W, val)((sc->sc_bst)->write_2((sc->sc_bsh), (0x08), (val)));
1203}
1204
1205int
1206smc91cxx_mii_readreg(struct device *self, int phy, int reg)
1207{
1208 struct smc91cxx_softc *sc = (void *) self;
1209 int val;
1210
1211 SMC_SELECT_BANK(sc, 3)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((3
))))
;
1212
1213 val = mii_bitbang_readreg(self, &smc91cxx_mii_bitbang_ops, phy, reg);
1214
1215 SMC_SELECT_BANK(sc, 2)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((2
))))
;
1216
1217 return (val);
1218}
1219
1220void
1221smc91cxx_mii_writereg(struct device *self, int phy, int reg, int val)
1222{
1223 struct smc91cxx_softc *sc = (void *) self;
1224
1225 SMC_SELECT_BANK(sc, 3)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((3
))))
;
1226
1227 mii_bitbang_writereg(self, &smc91cxx_mii_bitbang_ops, phy, reg, val);
1228
1229 SMC_SELECT_BANK(sc, 2)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((2
))))
;
1230}
1231
1232void
1233smc91cxx_statchg(struct device *self)
1234{
1235 struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
1236 bus_space_tag_t bst = sc->sc_bst;
1237 bus_space_handle_t bsh = sc->sc_bsh;
1238 int mctl;
1239
1240 SMC_SELECT_BANK(sc, 0)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((0
))))
;
1241 mctl = bus_space_read_2(bst, bsh, TXMIT_CONTROL_REG_W)((bst)->read_2((bsh), (0x00)));
1242 if (sc->sc_mii.mii_media_active & IFM_FDX0x0000010000000000ULL)
1243 mctl |= TCR_SWFDUP0x8000;
1244 else
1245 mctl &= ~TCR_SWFDUP0x8000;
1246 bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, mctl)((bst)->write_2((bsh), (0x00), (mctl)));
1247 SMC_SELECT_BANK(sc, 2)(((sc)->sc_bst)->write_2(((sc)->sc_bsh), (0x0e), ((2
))))
; /* back to operating window */
1248}
1249
1250/*
1251 * One second timer, used to tick the MII.
1252 */
1253void
1254smc91cxx_tick(void *arg)
1255{
1256 struct smc91cxx_softc *sc = arg;
1257 int s;
1258
1259#ifdef DIAGNOSTIC1
1260 if ((sc->sc_flags & SMC_FLAGS_HAS_MII0x0004) == 0)
1261 panic("smc91cxx_tick");
1262#endif
1263
1264 if ((sc->sc_dev.dv_flags & DVF_ACTIVE0x0001) == 0)
1265 return;
1266
1267 s = splnet()splraise(0x7);
1268 mii_tick(&sc->sc_mii);
1269 splx(s)spllower(s);
1270
1271 timeout_add_sec(&sc->sc_mii_timeout, 1);
1272}