Bug Summary

File:dev/usb/if_axen.c
Warning:line 1285, column 9
Assigned value is garbage or undefined

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 if_axen.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/usb/if_axen.c
1/* $OpenBSD: if_axen.c,v 1.31 2022/01/09 05:43:00 jsg Exp $ */
2
3/*
4 * Copyright (c) 2013 Yojiro UO <yuo@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19/*
20 * ASIX Electronics AX88178a USB 2.0 ethernet and AX88179 USB 3.0 Ethernet
21 * driver.
22 */
23
24#include "bpfilter.h"
25
26#include <sys/param.h>
27#include <sys/systm.h>
28#include <sys/sockio.h>
29#include <sys/rwlock.h>
30#include <sys/mbuf.h>
31#include <sys/kernel.h>
32#include <sys/socket.h>
33
34#include <sys/device.h>
35
36#include <machine/bus.h>
37
38#include <net/if.h>
39#include <net/if_media.h>
40
41#if NBPFILTER1 > 0
42#include <net/bpf.h>
43#endif
44
45#include <netinet/in.h>
46#include <netinet/if_ether.h>
47
48#include <dev/mii/mii.h>
49#include <dev/mii/miivar.h>
50
51#include <dev/usb/usb.h>
52#include <dev/usb/usbdi.h>
53#include <dev/usb/usbdi_util.h>
54#include <dev/usb/usbdivar.h>
55#include <dev/usb/usbdevs.h>
56
57#include <dev/usb/if_axenreg.h>
58
59#ifdef AXEN_DEBUG
60#define DPRINTF(x) do { if (axendebug) printf x; } while (0)
61#define DPRINTFN(n,x) do { if (axendebug >= (n)) printf x; } while (0)
62int axendebug = 0;
63#else
64#define DPRINTF(x)
65#define DPRINTFN(n,x)
66#endif
67
68#define AXEN_TOE /* enable checksum offload function */
69
70/*
71 * Various supported device vendors/products.
72 */
73const struct axen_type axen_devs[] = {
74#if 0 /* not tested */
75 { { USB_VENDOR_ASIX0x0b95, USB_PRODUCT_ASIX_AX88178A}, AX178A0x0001 },
76#endif
77 { { USB_VENDOR_ASIX0x0b95, USB_PRODUCT_ASIX_AX881790x1790}, AX1790x0002 },
78 { { USB_VENDOR_DLINK0x2001, USB_PRODUCT_DLINK_DUB13120x4a00}, AX1790x0002 },
79 { { USB_VENDOR_LENOVO0x17ef, USB_PRODUCT_LENOVO_AX881790x304b}, AX1790x0002 },
80 { { USB_VENDOR_SAMSUNG20x04e8, USB_PRODUCT_SAMSUNG2_AX881790xa100}, AX1790x0002 },
81 { { USB_VENDOR_SITECOMEU0x0df6, USB_PRODUCT_SITECOMEU_LN0320x0072}, AX1790x0002 }
82};
83
84#define axen_lookup(v, p)((struct axen_type *)usbd_match_device((const struct usb_devno
*)(axen_devs), sizeof (axen_devs) / sizeof ((axen_devs)[0]),
sizeof ((axen_devs)[0]), (v), (p)))
((struct axen_type *)usb_lookup(axen_devs, v, p)usbd_match_device((const struct usb_devno *)(axen_devs), sizeof
(axen_devs) / sizeof ((axen_devs)[0]), sizeof ((axen_devs)[0
]), (v), (p))
)
85
86int axen_match(struct device *, void *, void *);
87void axen_attach(struct device *, struct device *, void *);
88int axen_detach(struct device *, int);
89
90struct cfdriver axen_cd = {
91 NULL((void *)0), "axen", DV_IFNET
92};
93
94const struct cfattach axen_ca = {
95 sizeof(struct axen_softc), axen_match, axen_attach, axen_detach
96};
97
98int axen_tx_list_init(struct axen_softc *);
99int axen_rx_list_init(struct axen_softc *);
100struct mbuf *axen_newbuf(void);
101int axen_encap(struct axen_softc *, struct mbuf *, int);
102void axen_rxeof(struct usbd_xfer *, void *, usbd_status);
103void axen_txeof(struct usbd_xfer *, void *, usbd_status);
104void axen_tick(void *);
105void axen_tick_task(void *);
106void axen_start(struct ifnet *);
107int axen_ioctl(struct ifnet *, u_long, caddr_t);
108void axen_init(void *);
109void axen_stop(struct axen_softc *);
110void axen_watchdog(struct ifnet *);
111int axen_miibus_readreg(struct device *, int, int);
112void axen_miibus_writereg(struct device *, int, int, int);
113void axen_miibus_statchg(struct device *);
114int axen_cmd(struct axen_softc *, int, int, int, void *);
115int axen_ifmedia_upd(struct ifnet *);
116void axen_ifmedia_sts(struct ifnet *, struct ifmediareq *);
117void axen_reset(struct axen_softc *sc);
118void axen_iff(struct axen_softc *);
119void axen_lock_mii(struct axen_softc *sc);
120void axen_unlock_mii(struct axen_softc *sc);
121
122void axen_ax88179_init(struct axen_softc *);
123
124/* Get exclusive access to the MII registers */
125void
126axen_lock_mii(struct axen_softc *sc)
127{
128 sc->axen_refcnt++;
129 rw_enter_write(&sc->axen_mii_lock);
130}
131
132void
133axen_unlock_mii(struct axen_softc *sc)
134{
135 rw_exit_write(&sc->axen_mii_lock);
136 if (--sc->axen_refcnt < 0)
137 usb_detach_wakeup(&sc->axen_dev);
138}
139
140int
141axen_cmd(struct axen_softc *sc, int cmd, int index, int val, void *buf)
142{
143 usb_device_request_t req;
144 usbd_status err;
145
146 if (usbd_is_dying(sc->axen_udev))
10
Assuming the condition is true
11
Taking true branch
147 return 0;
148
149 if (AXEN_CMD_DIR(cmd)(((cmd) & 0x0F00) >> 8))
150 req.bmRequestType = UT_WRITE_VENDOR_DEVICE(0x00 | 0x40 | 0x00);
151 else
152 req.bmRequestType = UT_READ_VENDOR_DEVICE(0x80 | 0x40 | 0x00);
153 req.bRequest = AXEN_CMD_CMD(cmd)((cmd) & 0x00FF);
154 USETW(req.wValue, val)(*(u_int16_t *)(req.wValue) = (val));
155 USETW(req.wIndex, index)(*(u_int16_t *)(req.wIndex) = (index));
156 USETW(req.wLength, AXEN_CMD_LEN(cmd))(*(u_int16_t *)(req.wLength) = ((((cmd) & 0xF000) >>
12)))
;
157
158 err = usbd_do_request(sc->axen_udev, &req, buf);
159 DPRINTFN(5, ("axen_cmd: cmd 0x%04x val 0x%04x len %d\n",
160 cmd, val, AXEN_CMD_LEN(cmd)));
161
162 if (err) {
163 DPRINTF(("axen_cmd err: cmd: %d, error: %d\n", cmd, err));
164 return -1;
165 }
166
167 return 0;
168}
169
170int
171axen_miibus_readreg(struct device *dev, int phy, int reg)
172{
173 struct axen_softc *sc = (void *)dev;
174 int err;
175 uWord val;
176 int ival;
177
178 if (usbd_is_dying(sc->axen_udev)) {
179 DPRINTF(("axen: dying\n"));
180 return 0;
181 }
182
183 if (sc->axen_phyno != phy)
184 return 0;
185
186 axen_lock_mii(sc);
187 err = axen_cmd(sc, AXEN_CMD_MII_READ_REG0x2002, reg, phy, &val);
188 axen_unlock_mii(sc);
189
190 if (err) {
191 printf("axen%d: read PHY failed\n", sc->axen_unit);
192 return -1;
193 }
194
195 ival = UGETW(val)(*(u_int16_t *)(val));
196 DPRINTFN(2,("axen_miibus_readreg: phy 0x%x reg 0x%x val 0x%x\n",
197 phy, reg, ival));
198
199 if (reg == MII_BMSR0x01) {
200 ival &= ~BMSR_EXTCAP0x0001;
201 }
202
203 return ival;
204}
205
206void
207axen_miibus_writereg(struct device *dev, int phy, int reg, int val)
208{
209 struct axen_softc *sc = (void *)dev;
210 int err;
211 uWord uval;
212
213 if (usbd_is_dying(sc->axen_udev))
214 return;
215
216 if (sc->axen_phyno != phy)
217 return;
218
219 USETW(uval, val)(*(u_int16_t *)(uval) = (val));
220 axen_lock_mii(sc);
221 err = axen_cmd(sc, AXEN_CMD_MII_WRITE_REG0x2102, reg, phy, &uval);
222 axen_unlock_mii(sc);
223 DPRINTFN(2, ("axen_miibus_writereg: phy 0x%x reg 0x%x val 0x%0x\n",
224 phy, reg, val));
225
226 if (err) {
227 printf("axen%d: write PHY failed\n", sc->axen_unit);
228 return;
229 }
230}
231
232void
233axen_miibus_statchg(struct device *dev)
234{
235 struct axen_softc *sc = (void *)dev;
236 struct mii_data *mii = GET_MII(sc)(&(sc)->axen_mii);
237 struct ifnet *ifp;
238 int err;
239 uint16_t val;
240 uWord wval;
241
242 ifp = GET_IFP(sc)(&(sc)->arpcom.ac_if);
243 if (mii == NULL((void *)0) || ifp == NULL((void *)0) ||
244 (ifp->if_flags & IFF_RUNNING0x40) == 0)
245 return;
246
247 sc->axen_link = 0;
248 if ((mii->mii_media_status & (IFM_ACTIVE0x0000000000000002ULL | IFM_AVALID0x0000000000000001ULL)) ==
249 (IFM_ACTIVE0x0000000000000002ULL | IFM_AVALID0x0000000000000001ULL)) {
250 switch (IFM_SUBTYPE(mii->mii_media_active)((mii->mii_media_active) & 0x00000000000000ffULL)) {
251 case IFM_10_T3:
252 case IFM_100_TX6:
253 sc->axen_link++;
254 break;
255 case IFM_1000_T16:
256 sc->axen_link++;
257 break;
258 default:
259 break;
260 }
261 }
262
263 /* Lost link, do nothing. */
264 if (sc->axen_link == 0)
265 return;
266
267 val = 0;
268 if ((IFM_OPTIONS(mii->mii_media_active)((mii->mii_media_active) & (0x00000000ffff0000ULL|0x00ffff0000000000ULL
))
& IFM_FDX0x0000010000000000ULL) != 0)
269 val |= AXEN_MEDIUM_FDX0x0002;
270
271 val |= (AXEN_MEDIUM_RECV_EN0x0100 | AXEN_MEDIUM_ALWAYS_ONE0x0004);
272 val |= (AXEN_MEDIUM_RXFLOW_CTRL_EN0x0010 | AXEN_MEDIUM_TXFLOW_CTRL_EN0x0020);
273
274 switch (IFM_SUBTYPE(mii->mii_media_active)((mii->mii_media_active) & 0x00000000000000ffULL)) {
275 case IFM_1000_T16:
276 val |= AXEN_MEDIUM_GIGA0x0001 | AXEN_MEDIUM_EN_125MHZ0x0008;
277 break;
278 case IFM_100_TX6:
279 val |= AXEN_MEDIUM_PS0x0200;
280 break;
281 case IFM_10_T3:
282 /* doesn't need to be handled */
283 break;
284 }
285
286 DPRINTF(("axen_miibus_statchg: val=0x%x\n", val));
287 USETW(wval, val)(*(u_int16_t *)(wval) = (val));
288 axen_lock_mii(sc);
289 err = axen_cmd(sc, AXEN_CMD_MAC_WRITE20x2101, 2, AXEN_MEDIUM_STATUS0x22, &wval);
290 axen_unlock_mii(sc);
291 if (err) {
292 printf("%s: media change failed\n", sc->axen_dev.dv_xname);
293 return;
294 }
295}
296
297/*
298 * Set media options.
299 */
300int
301axen_ifmedia_upd(struct ifnet *ifp)
302{
303 struct axen_softc *sc = ifp->if_softc;
304 struct mii_data *mii = GET_MII(sc)(&(sc)->axen_mii);
305 int err;
306
307 sc->axen_link = 0;
308
309 if (mii->mii_instance) {
310 struct mii_softc *miisc;
311 LIST_FOREACH(miisc, &mii->mii_phys, mii_list)for((miisc) = ((&mii->mii_phys)->lh_first); (miisc)
!= ((void *)0); (miisc) = ((miisc)->mii_list.le_next))
312 mii_phy_reset(miisc);
313 }
314
315 err = mii_mediachg(mii);
316 if (err == ENXIO6)
317 return 0;
318 else
319 return err;
320}
321
322/*
323 * Report current media status.
324 */
325void
326axen_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
327{
328 struct axen_softc *sc = ifp->if_softc;
329 struct mii_data *mii = GET_MII(sc)(&(sc)->axen_mii);
330
331 mii_pollstat(mii);
332 ifmr->ifm_active = mii->mii_media_active;
333 ifmr->ifm_status = mii->mii_media_status;
334}
335
336void
337axen_iff(struct axen_softc *sc)
338{
339 struct ifnet *ifp = GET_IFP(sc)(&(sc)->arpcom.ac_if);
340 struct arpcom *ac = &sc->arpcom;
341 struct ether_multi *enm;
342 struct ether_multistep step;
343 u_int32_t h = 0;
344 u_int16_t rxmode;
345 u_int8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
346 uWord wval;
347
348 if (usbd_is_dying(sc->axen_udev))
349 return;
350
351 rxmode = 0;
352
353 /* Enable receiver, set RX mode */
354 axen_lock_mii(sc);
355 axen_cmd(sc, AXEN_CMD_MAC_READ20x2001, 2, AXEN_MAC_RXCTL0x0b, &wval);
356 rxmode = UGETW(wval)(*(u_int16_t *)(wval));
357 rxmode &= ~(AXEN_RXCTL_ACPT_ALL_MCAST0x0002 | AXEN_RXCTL_ACPT_PHY_MCAST0x0020 |
358 AXEN_RXCTL_PROMISC0x0001);
359 ifp->if_flags &= ~IFF_ALLMULTI0x200;
360
361 /*
362 * Always accept broadcast frames.
363 * Always accept frames destined to our station address.
364 */
365 rxmode |= AXEN_RXCTL_ACPT_BCAST0x0010;
366
367 if (ifp->if_flags & IFF_PROMISC0x100 || ac->ac_multirangecnt > 0) {
368 ifp->if_flags |= IFF_ALLMULTI0x200;
369 rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST0x0002 | AXEN_RXCTL_ACPT_PHY_MCAST0x0020;
370 if (ifp->if_flags & IFF_PROMISC0x100)
371 rxmode |= AXEN_RXCTL_PROMISC0x0001;
372 } else {
373 rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST0x0002 | AXEN_RXCTL_ACPT_PHY_MCAST0x0020;
374
375 /* now program new ones */
376 ETHER_FIRST_MULTI(step, ac, enm)do { (step).e_enm = ((&(ac)->ac_multiaddrs)->lh_first
); do { if ((((enm)) = ((step)).e_enm) != ((void *)0)) ((step
)).e_enm = ((((enm)))->enm_list.le_next); } while ( 0); } while
( 0)
;
377 while (enm != NULL((void *)0)) {
378 h = ether_crc32_be(enm->enm_addrlo,
379 ETHER_ADDR_LEN6) >> 26;
380 hashtbl[h / 8] |= 1 << (h % 8);
381 ETHER_NEXT_MULTI(step, enm)do { if (((enm) = (step).e_enm) != ((void *)0)) (step).e_enm =
(((enm))->enm_list.le_next); } while ( 0)
;
382 }
383 }
384
385 axen_cmd(sc, AXEN_CMD_MAC_WRITE_FILTER0x8101, 8, AXEN_FILTER_MULTI0x16,
386 (void *)&hashtbl);
387 USETW(wval, rxmode)(*(u_int16_t *)(wval) = (rxmode));
388 axen_cmd(sc, AXEN_CMD_MAC_WRITE20x2101, 2, AXEN_MAC_RXCTL0x0b, &wval);
389 axen_unlock_mii(sc);
390}
391
392void
393axen_reset(struct axen_softc *sc)
394{
395 if (usbd_is_dying(sc->axen_udev))
396 return;
397
398 axen_ax88179_init(sc);
399
400 /* Wait a little while for the chip to get its brains in order. */
401 DELAY(1000)(*delay_func)(1000);
402 return;
403}
404
405void
406axen_ax88179_init(struct axen_softc *sc)
407{
408 uWord wval;
409 uByte val;
410 u_int16_t ctl, temp;
411 struct axen_qctrl qctrl;
412
413 axen_lock_mii(sc);
414
415 /* XXX: ? */
416 axen_cmd(sc, AXEN_CMD_MAC_READ0x1001, 1, AXEN_UNK_050x05, &val);
417 DPRINTFN(5, ("AXEN_CMD_MAC_READ(0x05): 0x%02x\n", val));
418
419 /* check AX88179 version, UA1 / UA2 */
420 axen_cmd(sc, AXEN_CMD_MAC_READ0x1001, 1, AXEN_GENERAL_STATUS0x03, &val);
421 /* UA1 */
422 if (!(val & AXEN_GENERAL_STATUS_MASK0x4)) {
423 sc->axen_rev = AXEN_REV_UA10;
424 DPRINTF(("AX88179 ver. UA1\n"));
425 } else {
426 sc->axen_rev = AXEN_REV_UA21;
427 DPRINTF(("AX88179 ver. UA2\n"));
428 }
429
430 /* power up ethernet PHY */
431 USETW(wval, 0)(*(u_int16_t *)(wval) = (0));
432 axen_cmd(sc, AXEN_CMD_MAC_WRITE20x2101, 2, AXEN_PHYPWR_RSTCTL0x26, &wval);
433
434 USETW(wval, AXEN_PHYPWR_RSTCTL_IPRL)(*(u_int16_t *)(wval) = (0x0020));
435 axen_cmd(sc, AXEN_CMD_MAC_WRITE20x2101, 2, AXEN_PHYPWR_RSTCTL0x26, &wval);
436 usbd_delay_ms(sc->axen_udev, 200);
437
438 /* set clock mode */
439 val = AXEN_PHYCLK_ACS0x02 | AXEN_PHYCLK_BCS0x01;
440 axen_cmd(sc, AXEN_CMD_MAC_WRITE0x1101, 1, AXEN_PHYCLK0x33, &val);
441 usbd_delay_ms(sc->axen_udev, 100);
442
443 /* set monitor mode (disable) */
444 val = AXEN_MONITOR_NONE0x00;
445 axen_cmd(sc, AXEN_CMD_MAC_WRITE0x1101, 1, AXEN_MONITOR_MODE0x24, &val);
446
447 /* enable auto detach */
448 axen_cmd(sc, AXEN_CMD_EEPROM_READ0x2004, 2, AXEN_EEPROM_STAT0x43, &wval);
449 temp = UGETW(wval)(*(u_int16_t *)(wval));
450 DPRINTFN(2,("EEPROM0x43 = 0x%04x\n", temp));
451 if (!(temp == 0xffff) && !(temp & 0x0100)) {
452 /* Enable auto detach bit */
453 val = 0;
454 axen_cmd(sc, AXEN_CMD_MAC_WRITE0x1101, 1, AXEN_PHYCLK0x33, &val);
455 val = AXEN_PHYCLK_ULR0x08;
456 axen_cmd(sc, AXEN_CMD_MAC_WRITE0x1101, 1, AXEN_PHYCLK0x33, &val);
457 usbd_delay_ms(sc->axen_udev, 100);
458
459 axen_cmd(sc, AXEN_CMD_MAC_READ20x2001, 2, AXEN_PHYPWR_RSTCTL0x26, &wval);
460 ctl = UGETW(wval)(*(u_int16_t *)(wval));
461 ctl |= AXEN_PHYPWR_RSTCTL_AUTODETACH0x1000;
462 USETW(wval, ctl)(*(u_int16_t *)(wval) = (ctl));
463 axen_cmd(sc, AXEN_CMD_MAC_WRITE20x2101, 2, AXEN_PHYPWR_RSTCTL0x26, &wval);
464 usbd_delay_ms(sc->axen_udev, 200);
465 printf("%s: enable auto detach (0x%04x)\n",
466 sc->axen_dev.dv_xname, ctl);
467 }
468
469 /* bulkin queue setting */
470 axen_cmd(sc, AXEN_CMD_MAC_READ0x1001, 1, AXEN_USB_UPLINK0x02, &val);
471 switch (val) {
472 case AXEN_USB_FS0x01:
473 DPRINTF(("uplink: USB1.1\n"));
474 qctrl.ctrl = 0x07;
475 qctrl.timer_low = 0xcc;
476 qctrl.timer_high= 0x4c;
477 qctrl.bufsize = AXEN_BUFSZ_LS8 - 1;
478 qctrl.ifg = 0x08;
479 break;
480 case AXEN_USB_HS0x02:
481 DPRINTF(("uplink: USB2.0\n"));
482 qctrl.ctrl = 0x07;
483 qctrl.timer_low = 0x02;
484 qctrl.timer_high= 0xa0;
485 qctrl.bufsize = AXEN_BUFSZ_HS16 - 1;
486 qctrl.ifg = 0xff;
487 break;
488 case AXEN_USB_SS0x04:
489 DPRINTF(("uplink: USB3.0\n"));
490 qctrl.ctrl = 0x07;
491 qctrl.timer_low = 0x4f;
492 qctrl.timer_high= 0x00;
493 qctrl.bufsize = AXEN_BUFSZ_SS24 - 1;
494 qctrl.ifg = 0xff;
495 break;
496 default:
497 printf("%s: unknown uplink bus:0x%02x\n",
498 sc->axen_dev.dv_xname, val);
499 axen_unlock_mii(sc);
500 return;
501 }
502 axen_cmd(sc, AXEN_CMD_MAC_SET_RXSR0x5101, 5, AXEN_RX_BULKIN_QCTRL0x2e, &qctrl);
503
504 /* Set MAC address. */
505 axen_cmd(sc, AXEN_CMD_MAC_WRITE_ETHER0x6101, ETHER_ADDR_LEN6,
506 AXEN_CMD_MAC_NODE_ID0x10, &sc->arpcom.ac_enaddr);
507
508 /*
509 * set buffer high/low watermark to pause/resume.
510 * write 2byte will set high/log simultaneous with AXEN_PAUSE_HIGH.
511 * XXX: what is the best value? OSX driver uses 0x3c-0x4c as LOW-HIGH
512 * watermark parameters.
513 */
514 val = 0x34;
515 axen_cmd(sc, AXEN_CMD_MAC_WRITE0x1101, 1, AXEN_PAUSE_LOW_WATERMARK0x55, &val);
516 val = 0x52;
517 axen_cmd(sc, AXEN_CMD_MAC_WRITE0x1101, 1, AXEN_PAUSE_HIGH_WATERMARK0x54, &val);
518
519 /* Set RX/TX configuration. */
520 /* Offloading enable */
521#ifdef AXEN_TOE
522 val = AXEN_RXCOE_IPv40x01 | AXEN_RXCOE_TCPv40x02 | AXEN_RXCOE_UDPv40x04 |
523 AXEN_RXCOE_TCPv60x20 | AXEN_RXCOE_UDPv60x40;
524#else
525 val = AXEN_RXCOE_OFF0x00;
526#endif
527 axen_cmd(sc, AXEN_CMD_MAC_WRITE0x1101, 1, AXEN_RX_COE0x34, &val);
528
529#ifdef AXEN_TOE
530 val = AXEN_TXCOE_IPv40x01 | AXEN_TXCOE_TCPv40x02 | AXEN_TXCOE_UDPv40x04 |
531 AXEN_TXCOE_TCPv60x20 | AXEN_TXCOE_UDPv60x40;
532#else
533 val = AXEN_TXCOE_OFF0x00;
534#endif
535 axen_cmd(sc, AXEN_CMD_MAC_WRITE0x1101, 1, AXEN_TX_COE0x35, &val);
536
537 /* Set RX control register */
538 ctl = AXEN_RXCTL_IPE0x0200 | AXEN_RXCTL_DROPCRCERR0x0100 | AXEN_RXCTL_AUTOB0x0008;
539 ctl |= AXEN_RXCTL_ACPT_PHY_MCAST0x0020 | AXEN_RXCTL_ACPT_ALL_MCAST0x0002;
540 ctl |= AXEN_RXCTL_START0x0080;
541 USETW(wval, ctl)(*(u_int16_t *)(wval) = (ctl));
542 axen_cmd(sc, AXEN_CMD_MAC_WRITE20x2101, 2, AXEN_MAC_RXCTL0x0b, &wval);
543
544 /* set monitor mode (enable) */
545 val = AXEN_MONITOR_PMETYPE0x40 | AXEN_MONITOR_PMEPOL0x20 | AXEN_MONITOR_RWMP0x04;
546 axen_cmd(sc, AXEN_CMD_MAC_WRITE0x1101, 1, AXEN_MONITOR_MODE0x24, &val);
547 axen_cmd(sc, AXEN_CMD_MAC_READ0x1001, 1, AXEN_MONITOR_MODE0x24, &val);
548 DPRINTF(("axen: Monitor mode = 0x%02x\n", val));
549
550 /* set medium type */
551 ctl = AXEN_MEDIUM_GIGA0x0001 | AXEN_MEDIUM_FDX0x0002 | AXEN_MEDIUM_ALWAYS_ONE0x0004 |
552 AXEN_MEDIUM_RXFLOW_CTRL_EN0x0010 | AXEN_MEDIUM_TXFLOW_CTRL_EN0x0020;
553 ctl |= AXEN_MEDIUM_RECV_EN0x0100;
554 USETW(wval, ctl)(*(u_int16_t *)(wval) = (ctl));
555 DPRINTF(("axen: set to medium mode: 0x%04x\n", UGETW(wval)));
556 axen_cmd(sc, AXEN_CMD_MAC_WRITE20x2101, 2, AXEN_MEDIUM_STATUS0x22, &wval);
557 usbd_delay_ms(sc->axen_udev, 100);
558
559 axen_cmd(sc, AXEN_CMD_MAC_READ20x2001, 2, AXEN_MEDIUM_STATUS0x22, &wval);
560 DPRINTF(("axen: current medium mode: 0x%04x\n", UGETW(wval)));
561 axen_unlock_mii(sc);
562
563#if 0 /* XXX: TBD.... */
564#define GMII_LED_ACTIVE 0x1a
565#define GMII_PHY_PAGE_SEL 0x1e
566#define GMII_PHY_PAGE_SEL 0x1f
567#define GMII_PAGE_EXT 0x0007
568 axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, GMII_PHY_PAGE_SEL,
569 GMII_PAGE_EXT);
570 axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, GMII_PHY_PAGE,
571 0x002c);
572#endif
573
574#if 1 /* XXX: phy hack ? */
575 axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, 0x1F, 0x0005);
576 axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, 0x0C, 0x0000);
577 val = axen_miibus_readreg(&sc->axen_dev, sc->axen_phyno, 0x0001);
578 axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, 0x01,
579 val | 0x0080);
580 axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, 0x1F, 0x0000);
581#endif
582}
583
584int
585axen_match(struct device *parent, void *match, void *aux)
586{
587 struct usb_attach_arg *uaa = aux;
588
589 if (uaa->iface == NULL((void *)0) || uaa->configno != 1)
590 return (UMATCH_NONE0);
591
592 return (axen_lookup(uaa->vendor, uaa->product)((struct axen_type *)usbd_match_device((const struct usb_devno
*)(axen_devs), sizeof (axen_devs) / sizeof ((axen_devs)[0]),
sizeof ((axen_devs)[0]), (uaa->vendor), (uaa->product)
))
!= NULL((void *)0) ?
593 UMATCH_VENDOR_PRODUCT_CONF_IFACE8 : UMATCH_NONE0);
594}
595
596void
597axen_attach(struct device *parent, struct device *self, void *aux)
598{
599 struct axen_softc *sc = (struct axen_softc *)self;
600 struct usb_attach_arg *uaa = aux;
601 usb_interface_descriptor_t *id;
602 usb_endpoint_descriptor_t *ed;
603 struct mii_data *mii;
604 u_char eaddr[ETHER_ADDR_LEN6];
605 char *devname = sc->axen_dev.dv_xname;
606 struct ifnet *ifp;
607 int i, s;
608
609 sc->axen_unit = self->dv_unit; /*device_get_unit(self);*/
610 sc->axen_udev = uaa->device;
611 sc->axen_iface = uaa->iface;
612 sc->axen_flags = axen_lookup(uaa->vendor, uaa->product)((struct axen_type *)usbd_match_device((const struct usb_devno
*)(axen_devs), sizeof (axen_devs) / sizeof ((axen_devs)[0]),
sizeof ((axen_devs)[0]), (uaa->vendor), (uaa->product)
))
->axen_flags;
613
614 usb_init_task(&sc->axen_tick_task, axen_tick_task, sc,((&sc->axen_tick_task)->fun = (axen_tick_task), (&
sc->axen_tick_task)->arg = (sc), (&sc->axen_tick_task
)->type = (0), (&sc->axen_tick_task)->state = 0x0
)
615 USB_TASK_TYPE_GENERIC)((&sc->axen_tick_task)->fun = (axen_tick_task), (&
sc->axen_tick_task)->arg = (sc), (&sc->axen_tick_task
)->type = (0), (&sc->axen_tick_task)->state = 0x0
)
;
616 rw_init(&sc->axen_mii_lock, "axenmii")_rw_init_flags(&sc->axen_mii_lock, "axenmii", 0, ((void
*)0))
;
617 usb_init_task(&sc->axen_stop_task, (void (*)(void *))axen_stop, sc,((&sc->axen_stop_task)->fun = ((void (*)(void *))axen_stop
), (&sc->axen_stop_task)->arg = (sc), (&sc->
axen_stop_task)->type = (0), (&sc->axen_stop_task)->
state = 0x0)
618 USB_TASK_TYPE_GENERIC)((&sc->axen_stop_task)->fun = ((void (*)(void *))axen_stop
), (&sc->axen_stop_task)->arg = (sc), (&sc->
axen_stop_task)->type = (0), (&sc->axen_stop_task)->
state = 0x0)
;
619
620 sc->axen_product = uaa->product;
621 sc->axen_vendor = uaa->vendor;
622
623 id = usbd_get_interface_descriptor(sc->axen_iface);
624
625 /* decide on what our bufsize will be */
626 switch (sc->axen_udev->speed) {
627 case USB_SPEED_FULL2:
628 sc->axen_bufsz = AXEN_BUFSZ_LS8 * 1024;
629 break;
630 case USB_SPEED_HIGH3:
631 sc->axen_bufsz = AXEN_BUFSZ_HS16 * 1024;
632 break;
633 case USB_SPEED_SUPER4:
634 sc->axen_bufsz = AXEN_BUFSZ_SS24 * 1024;
635 break;
636 default:
637 printf("%s: not supported usb bus type", sc->axen_dev.dv_xname);
638 return;
639 }
640
641 /* Find endpoints. */
642 for (i = 0; i < id->bNumEndpoints; i++) {
643 ed = usbd_interface2endpoint_descriptor(sc->axen_iface, i);
644 if (!ed) {
645 printf("%s: couldn't get ep %d\n",
646 sc->axen_dev.dv_xname, i);
647 return;
648 }
649 if (UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_IN0x80 &&
650 UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) == UE_BULK0x02) {
651 sc->axen_ed[AXEN_ENDPT_RX0x0] = ed->bEndpointAddress;
652 } else if (UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_OUT0x00 &&
653 UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) == UE_BULK0x02) {
654 sc->axen_ed[AXEN_ENDPT_TX0x1] = ed->bEndpointAddress;
655 } else if (UE_GET_DIR(ed->bEndpointAddress)((ed->bEndpointAddress) & 0x80) == UE_DIR_IN0x80 &&
656 UE_GET_XFERTYPE(ed->bmAttributes)((ed->bmAttributes) & 0x03) == UE_INTERRUPT0x03) {
657 sc->axen_ed[AXEN_ENDPT_INTR0x2] = ed->bEndpointAddress;
658 }
659 }
660
661 s = splnet()splraise(0x7);
662
663 sc->axen_phyno = AXEN_PHY_ID0x0003;
664 DPRINTF((" get_phyno %d\n", sc->axen_phyno));
665
666 /*
667 * Get station address.
668 */
669 /* use MAC command */
670 axen_lock_mii(sc);
671 axen_cmd(sc, AXEN_CMD_MAC_READ_ETHER0x6001, ETHER_ADDR_LEN6,
672 AXEN_CMD_MAC_NODE_ID0x10, &eaddr);
673 axen_unlock_mii(sc);
674
675 /*
676 * An ASIX chip was detected. Inform the world.
677 */
678 printf("%s:", sc->axen_dev.dv_xname);
679 if (sc->axen_flags & AX178A0x0001)
680 printf(" AX88178a");
681 else if (sc->axen_flags & AX1790x0002)
682 printf(" AX88179");
683 printf(", address %s\n", ether_sprintf(eaddr));
684
685 bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN6);
686
687 axen_ax88179_init(sc);
688
689 /* Initialize interface info. */
690 ifp = &sc->arpcom.ac_if;
691 ifp->if_softc = sc;
692 strlcpy(ifp->if_xname, devname, IFNAMSIZ16);
693 ifp->if_flags = IFF_BROADCAST0x2 | IFF_SIMPLEX0x800 | IFF_MULTICAST0x8000;
694 ifp->if_ioctl = axen_ioctl;
695 ifp->if_start = axen_start;
696 ifp->if_watchdog = axen_watchdog;
697
698 ifp->if_capabilitiesif_data.ifi_capabilities = IFCAP_VLAN_MTU0x00000010;
699#ifdef AXEN_TOE
700 ifp->if_capabilitiesif_data.ifi_capabilities |= IFCAP_CSUM_IPv40x00000001 | IFCAP_CSUM_TCPv40x00000002 |
701 IFCAP_CSUM_UDPv40x00000004 | IFCAP_CSUM_TCPv60x00000080 | IFCAP_CSUM_UDPv60x00000100;
702#endif
703
704 /* Initialize MII/media info. */
705 mii = &sc->axen_mii;
706 mii->mii_ifp = ifp;
707 mii->mii_readreg = axen_miibus_readreg;
708 mii->mii_writereg = axen_miibus_writereg;
709 mii->mii_statchg = axen_miibus_statchg;
710 mii->mii_flags = MIIF_AUTOTSLEEP0x0010;
711
712 ifmedia_init(&mii->mii_media, 0, axen_ifmedia_upd, axen_ifmedia_sts);
713 mii_attach(self, mii, 0xffffffff, MII_PHY_ANY-1, MII_OFFSET_ANY-1, 0);
714
715 if (LIST_FIRST(&mii->mii_phys)((&mii->mii_phys)->lh_first) == NULL((void *)0)) {
716 ifmedia_add(&mii->mii_media, IFM_ETHER0x0000000000000100ULL | IFM_NONE2ULL, 0, NULL((void *)0));
717 ifmedia_set(&mii->mii_media, IFM_ETHER0x0000000000000100ULL | IFM_NONE2ULL);
718 } else
719 ifmedia_set(&mii->mii_media, IFM_ETHER0x0000000000000100ULL | IFM_AUTO0ULL);
720
721 /* Attach the interface. */
722 if_attach(ifp);
723 ether_ifattach(ifp);
724
725 timeout_set(&sc->axen_stat_ch, axen_tick, sc);
726
727 splx(s)spllower(s);
728}
729
730int
731axen_detach(struct device *self, int flags)
732{
733 struct axen_softc *sc = (struct axen_softc *)self;
734 int s;
735 struct ifnet *ifp = GET_IFP(sc)(&(sc)->arpcom.ac_if);
736
737 DPRINTFN(2,("%s: %s: enter\n", sc->axen_dev.dv_xname, __func__));
738
739 if (timeout_initialized(&sc->axen_stat_ch)((&sc->axen_stat_ch)->to_flags & 0x04))
740 timeout_del(&sc->axen_stat_ch);
741
742 if (sc->axen_ep[AXEN_ENDPT_TX0x1] != NULL((void *)0))
743 usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_TX0x1]);
744 if (sc->axen_ep[AXEN_ENDPT_RX0x0] != NULL((void *)0))
745 usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_RX0x0]);
746 if (sc->axen_ep[AXEN_ENDPT_INTR0x2] != NULL((void *)0))
747 usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_INTR0x2]);
748
749 /*
750 * Remove any pending tasks. They cannot be executing because they run
751 * in the same thread as detach.
752 */
753 usb_rem_task(sc->axen_udev, &sc->axen_tick_task);
754 usb_rem_task(sc->axen_udev, &sc->axen_stop_task);
755
756 s = splusb()splraise(0x5);
757
758 if (--sc->axen_refcnt >= 0) {
759 /* Wait for processes to go away */
760 usb_detach_wait(&sc->axen_dev);
761 }
762
763 if (ifp->if_flags & IFF_RUNNING0x40)
764 axen_stop(sc);
765
766 mii_detach(&sc->axen_mii, MII_PHY_ANY-1, MII_OFFSET_ANY-1);
767 ifmedia_delete_instance(&sc->axen_mii.mii_media, IFM_INST_ANY((uint64_t) -1));
768 if (ifp->if_softc != NULL((void *)0)) {
769 ether_ifdetach(ifp);
770 if_detach(ifp);
771 }
772
773#ifdef DIAGNOSTIC1
774 if (sc->axen_ep[AXEN_ENDPT_TX0x1] != NULL((void *)0) ||
775 sc->axen_ep[AXEN_ENDPT_RX0x0] != NULL((void *)0) ||
776 sc->axen_ep[AXEN_ENDPT_INTR0x2] != NULL((void *)0))
777 printf("%s: detach has active endpoints\n",
778 sc->axen_dev.dv_xname);
779#endif
780
781 splx(s)spllower(s);
782
783 return 0;
784}
785
786struct mbuf *
787axen_newbuf(void)
788{
789 struct mbuf *m;
790
791 MGETHDR(m, M_DONTWAIT, MT_DATA)m = m_gethdr((0x0002), (1));
792 if (m == NULL((void *)0))
793 return NULL((void *)0);
794
795 MCLGET(m, M_DONTWAIT)(void) m_clget((m), (0x0002), (1 << 11));
796 if (!(m->m_flagsm_hdr.mh_flags & M_EXT0x0001)) {
797 m_freem(m);
798 return NULL((void *)0);
799 }
800
801 m->m_lenm_hdr.mh_len = m->m_pkthdrM_dat.MH.MH_pkthdr.len = MCLBYTES(1 << 11);
802 m_adj(m, ETHER_ALIGN2);
803
804 return m;
805}
806
807int
808axen_rx_list_init(struct axen_softc *sc)
809{
810 struct axen_cdata *cd;
811 struct axen_chain *c;
812 int i;
813
814 DPRINTF(("%s: %s: enter\n", sc->axen_dev.dv_xname, __func__));
815
816 cd = &sc->axen_cdata;
817 for (i = 0; i < AXEN_RX_LIST_CNT1; i++) {
818 c = &cd->axen_rx_chain[i];
819 c->axen_sc = sc;
820 c->axen_idx = i;
821 c->axen_mbuf = NULL((void *)0);
822 if (c->axen_xfer == NULL((void *)0)) {
823 c->axen_xfer = usbd_alloc_xfer(sc->axen_udev);
824 if (c->axen_xfer == NULL((void *)0))
825 return ENOBUFS55;
826 c->axen_buf = usbd_alloc_buffer(c->axen_xfer,
827 sc->axen_bufsz);
828 if (c->axen_buf == NULL((void *)0)) {
829 usbd_free_xfer(c->axen_xfer);
830 return ENOBUFS55;
831 }
832 }
833 }
834
835 return 0;
836}
837
838int
839axen_tx_list_init(struct axen_softc *sc)
840{
841 struct axen_cdata *cd;
842 struct axen_chain *c;
843 int i;
844
845 DPRINTF(("%s: %s: enter\n", sc->axen_dev.dv_xname, __func__));
846
847 cd = &sc->axen_cdata;
848 for (i = 0; i < AXEN_TX_LIST_CNT1; i++) {
849 c = &cd->axen_tx_chain[i];
850 c->axen_sc = sc;
851 c->axen_idx = i;
852 c->axen_mbuf = NULL((void *)0);
853 if (c->axen_xfer == NULL((void *)0)) {
854 c->axen_xfer = usbd_alloc_xfer(sc->axen_udev);
855 if (c->axen_xfer == NULL((void *)0))
856 return ENOBUFS55;
857 c->axen_buf = usbd_alloc_buffer(c->axen_xfer,
858 sc->axen_bufsz);
859 if (c->axen_buf == NULL((void *)0)) {
860 usbd_free_xfer(c->axen_xfer);
861 return ENOBUFS55;
862 }
863 }
864 }
865
866 return 0;
867}
868
869/*
870 * A frame has been uploaded: pass the resulting mbuf chain up to
871 * the higher level protocols.
872 */
873void
874axen_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
875{
876 struct axen_chain *c = (struct axen_chain *)priv;
877 struct axen_softc *sc = c->axen_sc;
878 struct ifnet *ifp = GET_IFP(sc)(&(sc)->arpcom.ac_if);
879 u_char *buf = c->axen_buf;
880 struct mbuf_list ml = MBUF_LIST_INITIALIZER(){ ((void *)0), ((void *)0), 0 };
881 struct mbuf *m;
882 u_int32_t total_len;
883 u_int32_t rx_hdr, pkt_hdr;
884 u_int32_t *hdr_p;
885 u_int16_t hdr_offset, pkt_count;
886 size_t pkt_len;
887 size_t temp;
888 int s;
889
890 DPRINTFN(10,("%s: %s: enter\n", sc->axen_dev.dv_xname,__func__));
891
892 if (usbd_is_dying(sc->axen_udev))
893 return;
894
895 if (!(ifp->if_flags & IFF_RUNNING0x40))
896 return;
897
898 if (status != USBD_NORMAL_COMPLETION) {
899 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
900 return;
901 if (usbd_ratecheck(&sc->axen_rx_notice)) {
902 printf("%s: usb errors on rx: %s\n",
903 sc->axen_dev.dv_xname, usbd_errstr(status));
904 }
905 if (status == USBD_STALLED)
906 usbd_clear_endpoint_stall_async(sc->axen_ep[AXEN_ENDPT_RX0x0]);
907 goto done;
908 }
909
910 usbd_get_xfer_status(xfer, NULL((void *)0), NULL((void *)0), &total_len, NULL((void *)0));
911
912 if (total_len < sizeof(pkt_hdr)) {
913 ifp->if_ierrorsif_data.ifi_ierrors++;
914 goto done;
915 }
916
917 /*
918 * buffer map
919 * [packet #0]...[packet #n][pkt hdr#0]..[pkt hdr#n][recv_hdr]
920 * each packet has 0xeeee as pseudo header..
921 */
922 hdr_p = (u_int32_t *)(buf + total_len - sizeof(u_int32_t));
923 rx_hdr = letoh32(*hdr_p)((__uint32_t)(*hdr_p));
924 hdr_offset = (u_int16_t)(rx_hdr >> 16);
925 pkt_count = (u_int16_t)(rx_hdr & 0xffff);
926
927 if (total_len > sc->axen_bufsz) {
928 printf("%s: rxeof: too large transfer\n",
929 sc->axen_dev.dv_xname);
930 goto done;
931 }
932
933 /* sanity check */
934 if (hdr_offset > total_len) {
935 ifp->if_ierrorsif_data.ifi_ierrors++;
936 goto done;
937 }
938
939 /* point first packet header */
940 hdr_p = (u_int32_t*)(buf + hdr_offset);
941
942 /*
943 * ax88179 will pack multiple ip packet to a USB transaction.
944 * process all of packets in the buffer
945 */
946
947#if 1 /* XXX: paranoiac check. need to remove later */
948#define AXEN_MAX_PACKED_PACKET200 200
949 if (pkt_count > AXEN_MAX_PACKED_PACKET200) {
950 DPRINTF(("Too many packets (%d) in a transaction, discard.\n",
951 pkt_count));
952 goto done;
953 }
954#endif
955
956 do {
957 if ((buf[0] != 0xee) || (buf[1] != 0xee)){
958 printf("%s: invalid buffer(pkt#%d), continue\n",
959 sc->axen_dev.dv_xname, pkt_count);
960 ifp->if_ierrorsif_data.ifi_ierrors += pkt_count;
961 goto done;
962 }
963
964 pkt_hdr = letoh32(*hdr_p)((__uint32_t)(*hdr_p));
965 pkt_len = (pkt_hdr >> 16) & 0x1fff;
966
967 DPRINTFN(10,("rxeof: packet#%d, pkt_hdr 0x%08x, pkt_len %zu\n",
968 pkt_count, pkt_hdr, pkt_len));
969
970 if ((pkt_hdr & AXEN_RXHDR_CRC_ERR(1U << 29)) ||
971 (pkt_hdr & AXEN_RXHDR_DROP_ERR(1U << 31))) {
972 ifp->if_ierrorsif_data.ifi_ierrors++;
973 /* move to next pkt header */
974 DPRINTF(("crc err(pkt#%d)\n", pkt_count));
975 goto nextpkt;
976 }
977
978 /* process each packet */
979 /* allocate mbuf */
980 m = axen_newbuf();
981 if (m == NULL((void *)0)) {
982 ifp->if_ierrorsif_data.ifi_ierrors++;
983 goto nextpkt;
984 }
985
986 /* skip pseudo header (2byte) and trailer padding (4Byte) */
987 m->m_pkthdrM_dat.MH.MH_pkthdr.len = m->m_lenm_hdr.mh_len = pkt_len - 6;
988
989#ifdef AXEN_TOE
990 /* checksum err */
991 if ((pkt_hdr & AXEN_RXHDR_L3CSUM_ERR(1U << 1)) ||
992 (pkt_hdr & AXEN_RXHDR_L4CSUM_ERR(1U << 0))) {
993 printf("%s: checksum err (pkt#%d)\n",
994 sc->axen_dev.dv_xname, pkt_count);
995 goto nextpkt;
996 } else {
997 m->m_pkthdrM_dat.MH.MH_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK0x0008;
998 }
999
1000 int l4_type;
1001 l4_type = (pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK0x0000001c) >>
1002 AXEN_RXHDR_L4_TYPE_OFFSET2;
1003
1004 if ((l4_type == AXEN_RXHDR_L4_TYPE_TCP0x4) ||
1005 (l4_type == AXEN_RXHDR_L4_TYPE_UDP0x1))
1006 m->m_pkthdrM_dat.MH.MH_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK0x0020 |
1007 M_UDP_CSUM_IN_OK0x0080;
1008#endif
1009
1010 memcpy(mtod(m, char *), buf + 2, pkt_len - 6)__builtin_memcpy((((char *)((m)->m_hdr.mh_data))), (buf + 2
), (pkt_len - 6))
;
1011
1012 ml_enqueue(&ml, m);
1013
1014nextpkt:
1015 /*
1016 * prepare next packet
1017 * as each packet will be aligned 8byte boundary,
1018 * need to fix up the start point of the buffer.
1019 */
1020 temp = ((pkt_len + 7) & 0xfff8);
1021 buf = buf + temp;
1022 hdr_p++;
1023 pkt_count--;
1024 } while( pkt_count > 0);
1025
1026done:
1027 /* push the packet up */
1028 s = splnet()splraise(0x7);
1029 if_input(ifp, &ml);
1030 splx(s)spllower(s);
1031
1032 /* clear buffer for next transaction */
1033 memset(c->axen_buf, 0, sc->axen_bufsz)__builtin_memset((c->axen_buf), (0), (sc->axen_bufsz));
1034
1035 /* Setup new transfer. */
1036 usbd_setup_xfer(xfer, sc->axen_ep[AXEN_ENDPT_RX0x0],
1037 c, c->axen_buf, sc->axen_bufsz,
1038 USBD_SHORT_XFER_OK0x04 | USBD_NO_COPY0x01,
1039 USBD_NO_TIMEOUT0, axen_rxeof);
1040 usbd_transfer(xfer);
1041
1042 DPRINTFN(10,("%s: %s: start rx\n", sc->axen_dev.dv_xname, __func__));
1043}
1044
1045/*
1046 * A frame was downloaded to the chip. It's safe for us to clean up
1047 * the list buffers.
1048 */
1049void
1050axen_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
1051{
1052 struct axen_softc *sc;
1053 struct axen_chain *c;
1054 struct ifnet *ifp;
1055 int s;
1056
1057 c = priv;
1058 sc = c->axen_sc;
1059 ifp = &sc->arpcom.ac_if;
1060
1061 if (usbd_is_dying(sc->axen_udev))
1062 return;
1063
1064 s = splnet()splraise(0x7);
1065
1066 if (status != USBD_NORMAL_COMPLETION) {
1067 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1068 splx(s)spllower(s);
1069 return;
1070 }
1071 ifp->if_oerrorsif_data.ifi_oerrors++;
1072 printf("axen%d: usb error on tx: %s\n", sc->axen_unit,
1073 usbd_errstr(status));
1074 if (status == USBD_STALLED)
1075 usbd_clear_endpoint_stall_async(sc->axen_ep[AXEN_ENDPT_TX0x1]);
1076 splx(s)spllower(s);
1077 return;
1078 }
1079
1080 ifp->if_timer = 0;
1081 ifq_clr_oactive(&ifp->if_snd);
1082
1083 m_freem(c->axen_mbuf);
1084 c->axen_mbuf = NULL((void *)0);
1085
1086 if (ifq_empty(&ifp->if_snd)(((&ifp->if_snd)->ifq_len) == 0) == 0)
1087 axen_start(ifp);
1088
1089 splx(s)spllower(s);
1090}
1091
1092void
1093axen_tick(void *xsc)
1094{
1095 struct axen_softc *sc = xsc;
1096
1097 if (sc == NULL((void *)0))
1098 return;
1099
1100 DPRINTFN(0xff, ("%s: %s: enter\n", sc->axen_dev.dv_xname,
1101 __func__));
1102
1103 if (usbd_is_dying(sc->axen_udev))
1104 return;
1105
1106 /* Perform periodic stuff in process context */
1107 usb_add_task(sc->axen_udev, &sc->axen_tick_task);
1108}
1109
1110void
1111axen_tick_task(void *xsc)
1112{
1113 int s;
1114 struct axen_softc *sc;
1115 struct mii_data *mii;
1116
1117 sc = xsc;
1118
1119 if (sc == NULL((void *)0))
1120 return;
1121
1122 if (usbd_is_dying(sc->axen_udev))
1123 return;
1124
1125 mii = GET_MII(sc)(&(sc)->axen_mii);
1126 if (mii == NULL((void *)0))
1127 return;
1128
1129 s = splnet()splraise(0x7);
1130
1131 mii_tick(mii);
1132 if (sc->axen_link == 0)
1133 axen_miibus_statchg(&sc->axen_dev);
1134 timeout_add_sec(&sc->axen_stat_ch, 1);
1135
1136 splx(s)spllower(s);
1137}
1138
1139int
1140axen_encap(struct axen_softc *sc, struct mbuf *m, int idx)
1141{
1142 struct axen_chain *c;
1143 usbd_status err;
1144 struct axen_sframe_hdr hdr;
1145 int length, boundary;
1146
1147 c = &sc->axen_cdata.axen_tx_chain[idx];
1148
1149 switch (sc->axen_udev->speed) {
1150 case USB_SPEED_FULL2:
1151 boundary = 64;
1152 break;
1153 case USB_SPEED_HIGH3:
1154 boundary = 512;
1155 break;
1156 case USB_SPEED_SUPER4:
1157 boundary = 4096; /* XXX */
1158 break;
1159 default:
1160 printf("%s: not supported usb bus type", sc->axen_dev.dv_xname);
1161 return EIO5;
1162 }
1163
1164 hdr.plen = htole32(m->m_pkthdr.len)((__uint32_t)(m->M_dat.MH.MH_pkthdr.len));
1165 hdr.gso = 0; /* disable segmentation offloading */
1166
1167 memcpy(c->axen_buf, &hdr, sizeof(hdr))__builtin_memcpy((c->axen_buf), (&hdr), (sizeof(hdr)));
1168 length = sizeof(hdr);
1169
1170 m_copydata(m, 0, m->m_pkthdrM_dat.MH.MH_pkthdr.len, c->axen_buf + length);
1171 length += m->m_pkthdrM_dat.MH.MH_pkthdr.len;
1172
1173 if ((length % boundary) == 0) {
1174 hdr.plen = 0x0;
1175 hdr.gso |= 0x80008000; /* enable padding */
1176 memcpy(c->axen_buf + length, &hdr, sizeof(hdr))__builtin_memcpy((c->axen_buf + length), (&hdr), (sizeof
(hdr)))
;
1177 length += sizeof(hdr);
1178 }
1179
1180 c->axen_mbuf = m;
1181
1182 usbd_setup_xfer(c->axen_xfer, sc->axen_ep[AXEN_ENDPT_TX0x1],
1183 c, c->axen_buf, length, USBD_FORCE_SHORT_XFER0x08 | USBD_NO_COPY0x01,
1184 10000, axen_txeof);
1185
1186 /* Transmit */
1187 err = usbd_transfer(c->axen_xfer);
1188 if (err != USBD_IN_PROGRESS) {
1189 c->axen_mbuf = NULL((void *)0);
1190 axen_stop(sc);
1191 return EIO5;
1192 }
1193
1194 sc->axen_cdata.axen_tx_cnt++;
1195
1196 return 0;
1197}
1198
1199void
1200axen_start(struct ifnet *ifp)
1201{
1202 struct axen_softc *sc;
1203 struct mbuf *m_head = NULL((void *)0);
1204
1205 sc = ifp->if_softc;
1206
1207 if (!sc->axen_link)
1208 return;
1209
1210 if (ifq_is_oactive(&ifp->if_snd))
1211 return;
1212
1213 m_head = ifq_dequeue(&ifp->if_snd);
1214 if (m_head == NULL((void *)0))
1215 return;
1216
1217 if (axen_encap(sc, m_head, 0)) {
1218 m_freem(m_head);
1219 ifq_set_oactive(&ifp->if_snd);
1220 return;
1221 }
1222
1223 /*
1224 * If there's a BPF listener, bounce a copy of this frame
1225 * to him.
1226 */
1227#if NBPFILTER1 > 0
1228 if (ifp->if_bpf)
1229 bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT(1 << 1));
1230#endif
1231
1232 ifq_set_oactive(&ifp->if_snd);
1233
1234 /*
1235 * Set a timeout in case the chip goes out to lunch.
1236 */
1237 ifp->if_timer = 5;
1238}
1239
1240void
1241axen_init(void *xsc)
1242{
1243 struct axen_softc *sc = xsc;
1244 struct ifnet *ifp = &sc->arpcom.ac_if;
1245 struct axen_chain *c;
1246 usbd_status err;
1247 int i, s;
1248 uByte bval;
1249 uWord wval;
1250 uint16_t rxmode;
1251
1252 s = splnet()splraise(0x7);
1253
1254 /*
1255 * Cancel pending I/O and free all RX/TX buffers.
1256 */
1257 axen_reset(sc);
1258
1259 /* XXX: ? */
1260 bval = 0x01;
1261 axen_lock_mii(sc);
1262 axen_cmd(sc, AXEN_CMD_MAC_WRITE0x1101, 1, AXEN_UNK_280x28, &bval);
1263 axen_unlock_mii(sc);
1264
1265 /* Init RX ring. */
1266 if (axen_rx_list_init(sc) == ENOBUFS55) {
7
Taking false branch
1267 printf("axen%d: rx list init failed\n", sc->axen_unit);
1268 splx(s)spllower(s);
1269 return;
1270 }
1271
1272 /* Init TX ring. */
1273 if (axen_tx_list_init(sc) == ENOBUFS55) {
8
Taking false branch
1274 printf("axen%d: tx list init failed\n", sc->axen_unit);
1275 splx(s)spllower(s);
1276 return;
1277 }
1278
1279 /* Program promiscuous mode and multicast filters. */
1280 axen_iff(sc);
1281
1282 /* Enable receiver, set RX mode */
1283 axen_lock_mii(sc);
1284 axen_cmd(sc, AXEN_CMD_MAC_READ20x2001, 2, AXEN_MAC_RXCTL0x0b, &wval);
9
Calling 'axen_cmd'
12
Returning from 'axen_cmd'
1285 rxmode = UGETW(wval)(*(u_int16_t *)(wval));
13
Assigned value is garbage or undefined
1286 rxmode |= AXEN_RXCTL_START0x0080;
1287 USETW(wval, rxmode)(*(u_int16_t *)(wval) = (rxmode));
1288 axen_cmd(sc, AXEN_CMD_MAC_WRITE20x2101, 2, AXEN_MAC_RXCTL0x0b, &wval);
1289 axen_unlock_mii(sc);
1290
1291 /* Open RX and TX pipes. */
1292 err = usbd_open_pipe(sc->axen_iface, sc->axen_ed[AXEN_ENDPT_RX0x0],
1293 USBD_EXCLUSIVE_USE0x01, &sc->axen_ep[AXEN_ENDPT_RX0x0]);
1294 if (err) {
1295 printf("axen%d: open rx pipe failed: %s\n",
1296 sc->axen_unit, usbd_errstr(err));
1297 splx(s)spllower(s);
1298 return;
1299 }
1300
1301 err = usbd_open_pipe(sc->axen_iface, sc->axen_ed[AXEN_ENDPT_TX0x1],
1302 USBD_EXCLUSIVE_USE0x01, &sc->axen_ep[AXEN_ENDPT_TX0x1]);
1303 if (err) {
1304 printf("axen%d: open tx pipe failed: %s\n",
1305 sc->axen_unit, usbd_errstr(err));
1306 splx(s)spllower(s);
1307 return;
1308 }
1309
1310 /* Start up the receive pipe. */
1311 for (i = 0; i < AXEN_RX_LIST_CNT1; i++) {
1312 c = &sc->axen_cdata.axen_rx_chain[i];
1313 usbd_setup_xfer(c->axen_xfer, sc->axen_ep[AXEN_ENDPT_RX0x0],
1314 c, c->axen_buf, sc->axen_bufsz,
1315 USBD_SHORT_XFER_OK0x04 | USBD_NO_COPY0x01,
1316 USBD_NO_TIMEOUT0, axen_rxeof);
1317 usbd_transfer(c->axen_xfer);
1318 }
1319
1320 sc->axen_link = 0;
1321 ifp->if_flags |= IFF_RUNNING0x40;
1322 ifq_clr_oactive(&ifp->if_snd);
1323
1324 splx(s)spllower(s);
1325
1326 timeout_add_sec(&sc->axen_stat_ch, 1);
1327 return;
1328}
1329
1330int
1331axen_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1332{
1333 struct axen_softc *sc = ifp->if_softc;
1334 struct ifreq *ifr = (struct ifreq *)data;
1335 int s;
1336 int error = 0;
1337
1338 s = splnet()splraise(0x7);
1339
1340 switch(cmd) {
1
Control jumps to 'case 2149607696:' at line 1347
1341 case SIOCSIFADDR((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((12)))
:
1342 ifp->if_flags |= IFF_UP0x1;
1343 if (!(ifp->if_flags & IFF_RUNNING0x40))
1344 axen_init(sc);
1345 break;
1346
1347 case SIOCSIFFLAGS((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('i')) << 8) | ((16)))
:
1348 if (ifp->if_flags & IFF_UP0x1) {
2
Assuming the condition is true
3
Taking true branch
1349 if (ifp->if_flags & IFF_RUNNING0x40)
4
Assuming the condition is false
5
Taking false branch
1350 error = ENETRESET52;
1351 else
1352 axen_init(sc);
6
Calling 'axen_init'
1353 } else {
1354 if (ifp->if_flags & IFF_RUNNING0x40)
1355 axen_stop(sc);
1356 }
1357 break;
1358
1359 case SIOCGIFMEDIA(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifmediareq) & 0x1fff) << 16) | ((('i')) <<
8) | ((56)))
:
1360 case SIOCSIFMEDIA(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct ifreq) & 0x1fff) << 16) | ((('i')) <<
8) | ((55)))
:
1361 error = ifmedia_ioctl(ifp, ifr, &sc->axen_mii.mii_media, cmd);
1362 break;
1363
1364#if 0
1365 case SCIOCSIFMTU:
1366 /* XXX need to set AX_MEDIUM_JUMBO_EN here? */
1367 /* fall through */
1368#endif
1369 default:
1370 error = ether_ioctl(ifp, &sc->arpcom, cmd, data);
1371 }
1372
1373 if (error == ENETRESET52) {
1374 if (ifp->if_flags & IFF_RUNNING0x40)
1375 axen_iff(sc);
1376 error = 0;
1377 }
1378
1379 splx(s)spllower(s);
1380
1381 return error;
1382}
1383
1384void
1385axen_watchdog(struct ifnet *ifp)
1386{
1387 struct axen_softc *sc;
1388 struct axen_chain *c;
1389 usbd_status stat;
1390 int s;
1391
1392 sc = ifp->if_softc;
1393
1394 ifp->if_oerrorsif_data.ifi_oerrors++;
1395 printf("axen%d: watchdog timeout\n", sc->axen_unit);
1396
1397 s = splusb()splraise(0x5);
1398 c = &sc->axen_cdata.axen_tx_chain[0];
1399 usbd_get_xfer_status(c->axen_xfer, NULL((void *)0), NULL((void *)0), NULL((void *)0), &stat);
1400 axen_txeof(c->axen_xfer, c, stat);
1401
1402 if (!ifq_empty(&ifp->if_snd)(((&ifp->if_snd)->ifq_len) == 0))
1403 axen_start(ifp);
1404 splx(s)spllower(s);
1405}
1406
1407/*
1408 * Stop the adapter and free any mbufs allocated to the
1409 * RX and TX lists.
1410 */
1411void
1412axen_stop(struct axen_softc *sc)
1413{
1414 usbd_status err;
1415 struct ifnet *ifp;
1416 int i;
1417
1418 axen_reset(sc);
1419
1420 ifp = &sc->arpcom.ac_if;
1421 ifp->if_timer = 0;
1422 ifp->if_flags &= ~IFF_RUNNING0x40;
1423 ifq_clr_oactive(&ifp->if_snd);
1424
1425 timeout_del(&sc->axen_stat_ch);
1426
1427 /* Stop transfers. */
1428 if (sc->axen_ep[AXEN_ENDPT_RX0x0] != NULL((void *)0)) {
1429 err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_RX0x0]);
1430 if (err) {
1431 printf("axen%d: close rx pipe failed: %s\n",
1432 sc->axen_unit, usbd_errstr(err));
1433 }
1434 sc->axen_ep[AXEN_ENDPT_RX0x0] = NULL((void *)0);
1435 }
1436
1437 if (sc->axen_ep[AXEN_ENDPT_TX0x1] != NULL((void *)0)) {
1438 err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_TX0x1]);
1439 if (err) {
1440 printf("axen%d: close tx pipe failed: %s\n",
1441 sc->axen_unit, usbd_errstr(err));
1442 }
1443 sc->axen_ep[AXEN_ENDPT_TX0x1] = NULL((void *)0);
1444 }
1445
1446 if (sc->axen_ep[AXEN_ENDPT_INTR0x2] != NULL((void *)0)) {
1447 err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_INTR0x2]);
1448 if (err) {
1449 printf("axen%d: close intr pipe failed: %s\n",
1450 sc->axen_unit, usbd_errstr(err));
1451 }
1452 sc->axen_ep[AXEN_ENDPT_INTR0x2] = NULL((void *)0);
1453 }
1454
1455 /* Free RX resources. */
1456 for (i = 0; i < AXEN_RX_LIST_CNT1; i++) {
1457 if (sc->axen_cdata.axen_rx_chain[i].axen_mbuf != NULL((void *)0)) {
1458 m_freem(sc->axen_cdata.axen_rx_chain[i].axen_mbuf);
1459 sc->axen_cdata.axen_rx_chain[i].axen_mbuf = NULL((void *)0);
1460 }
1461 if (sc->axen_cdata.axen_rx_chain[i].axen_xfer != NULL((void *)0)) {
1462 usbd_free_xfer(sc->axen_cdata.axen_rx_chain[i].axen_xfer);
1463 sc->axen_cdata.axen_rx_chain[i].axen_xfer = NULL((void *)0);
1464 }
1465 }
1466
1467 /* Free TX resources. */
1468 for (i = 0; i < AXEN_TX_LIST_CNT1; i++) {
1469
1470 if (sc->axen_cdata.axen_tx_chain[i].axen_mbuf != NULL((void *)0)) {
1471 m_freem(sc->axen_cdata.axen_tx_chain[i].axen_mbuf);
1472 sc->axen_cdata.axen_tx_chain[i].axen_mbuf = NULL((void *)0);
1473 }
1474 if (sc->axen_cdata.axen_tx_chain[i].axen_xfer != NULL((void *)0)) {
1475 usbd_free_xfer(sc->axen_cdata.axen_tx_chain[i].axen_xfer);
1476 sc->axen_cdata.axen_tx_chain[i].axen_xfer = NULL((void *)0);
1477 }
1478 }
1479
1480 sc->axen_link = 0;
1481}