Line data Source code
1 : /* $OpenBSD: if_axe.c,v 1.138 2017/01/22 10:17:39 dlg Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2005, 2006, 2007 Jonathan Gray <jsg@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 : * Copyright (c) 1997, 1998, 1999, 2000-2003
21 : * Bill Paul <wpaul@windriver.com>. All rights reserved.
22 : *
23 : * Redistribution and use in source and binary forms, with or without
24 : * modification, are permitted provided that the following conditions
25 : * are met:
26 : * 1. Redistributions of source code must retain the above copyright
27 : * notice, this list of conditions and the following disclaimer.
28 : * 2. Redistributions in binary form must reproduce the above copyright
29 : * notice, this list of conditions and the following disclaimer in the
30 : * documentation and/or other materials provided with the distribution.
31 : * 3. All advertising materials mentioning features or use of this software
32 : * must display the following acknowledgement:
33 : * This product includes software developed by Bill Paul.
34 : * 4. Neither the name of the author nor the names of any co-contributors
35 : * may be used to endorse or promote products derived from this software
36 : * without specific prior written permission.
37 : *
38 : * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
39 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 : * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
42 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
43 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
44 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
45 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
46 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
48 : * THE POSSIBILITY OF SUCH DAMAGE.
49 : */
50 :
51 : /*
52 : * ASIX Electronics AX88172 USB 2.0 ethernet driver. Used in the
53 : * LinkSys USB200M and various other adapters.
54 : *
55 : * Manuals available from:
56 : * http://www.asix.com.tw/datasheet/mac/Ax88172.PDF
57 : * Note: you need the manual for the AX88170 chip (USB 1.x ethernet
58 : * controller) to find the definitions for the RX control register.
59 : * http://www.asix.com.tw/datasheet/mac/Ax88170.PDF
60 : *
61 : * Written by Bill Paul <wpaul@windriver.com>
62 : * Senior Engineer
63 : * Wind River Systems
64 : */
65 :
66 : /*
67 : * The AX88172 provides USB ethernet supports at 10 and 100Mbps.
68 : * It uses an external PHY (reference designs use a Realtek chip),
69 : * and has a 64-bit multicast hash filter. There is some information
70 : * missing from the manual which one needs to know in order to make
71 : * the chip function:
72 : *
73 : * - You must set bit 7 in the RX control register, otherwise the
74 : * chip won't receive any packets.
75 : * - You must initialize all 3 IPG registers, or you won't be able
76 : * to send any packets.
77 : *
78 : * Note that this device appears to only support loading the station
79 : * address via autoload from the EEPROM (i.e. there's no way to manually
80 : * set it).
81 : *
82 : * (Adam Weinberger wanted me to name this driver if_gir.c.)
83 : */
84 :
85 : /*
86 : * Ported to OpenBSD 3/28/2004 by Greg Taleck <taleck@oz.net>
87 : * with bits and pieces from the aue and url drivers.
88 : */
89 :
90 : #include "bpfilter.h"
91 :
92 : #include <sys/param.h>
93 : #include <sys/systm.h>
94 : #include <sys/sockio.h>
95 : #include <sys/rwlock.h>
96 : #include <sys/mbuf.h>
97 : #include <sys/kernel.h>
98 : #include <sys/socket.h>
99 :
100 : #include <sys/device.h>
101 :
102 : #include <machine/bus.h>
103 :
104 : #include <net/if.h>
105 : #include <net/if_media.h>
106 :
107 : #if NBPFILTER > 0
108 : #include <net/bpf.h>
109 : #endif
110 :
111 : #include <netinet/in.h>
112 : #include <netinet/if_ether.h>
113 :
114 : #include <dev/mii/mii.h>
115 : #include <dev/mii/miivar.h>
116 :
117 : #include <dev/usb/usb.h>
118 : #include <dev/usb/usbdi.h>
119 : #include <dev/usb/usbdi_util.h>
120 : #include <dev/usb/usbdivar.h>
121 : #include <dev/usb/usbdevs.h>
122 :
123 : #include <dev/usb/if_axereg.h>
124 :
125 : #ifdef AXE_DEBUG
126 : #define DPRINTF(x) do { if (axedebug) printf x; } while (0)
127 : #define DPRINTFN(n,x) do { if (axedebug >= (n)) printf x; } while (0)
128 : int axedebug = 0;
129 : #else
130 : #define DPRINTF(x)
131 : #define DPRINTFN(n,x)
132 : #endif
133 :
134 : /*
135 : * Various supported device vendors/products.
136 : */
137 : const struct axe_type axe_devs[] = {
138 : { { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_UF200}, 0 },
139 : { { USB_VENDOR_ACERCM, USB_PRODUCT_ACERCM_EP1427X2}, 0 },
140 : { { USB_VENDOR_APPLE, USB_PRODUCT_APPLE_ETHERNET }, AX772 },
141 : { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88172}, 0 },
142 : { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772}, AX772 },
143 : { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772A}, AX772 },
144 : { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B}, AX772 | AX772B },
145 : { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88772B_1}, AX772 | AX772B },
146 : { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178}, AX178 },
147 : { { USB_VENDOR_ATEN, USB_PRODUCT_ATEN_UC210T}, 0 },
148 : { { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D5055 }, AX178 },
149 : { { USB_VENDOR_BILLIONTON, USB_PRODUCT_BILLIONTON_USB2AR}, 0},
150 : { { USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB200MV2}, AX772 },
151 : { { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_FETHER_USB2_TX }, 0},
152 : { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100}, 0 },
153 : { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100B1 }, AX772 },
154 : { { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DUBE100C1 }, AX772 | AX772B },
155 : { { USB_VENDOR_GOODWAY, USB_PRODUCT_GOODWAY_GWUSB2E}, 0 },
156 : { { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_ETGUS2 }, AX178 },
157 : { { USB_VENDOR_JVC, USB_PRODUCT_JVC_MP_PRX1}, 0 },
158 : { { USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_ETHERNET }, AX772 | AX772B },
159 : { { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_HG20F9}, AX772 | AX772B },
160 : { { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_USB200M}, 0 },
161 : { { USB_VENDOR_LINKSYS4, USB_PRODUCT_LINKSYS4_USB1000 }, AX178 },
162 : { { USB_VENDOR_LOGITEC, USB_PRODUCT_LOGITEC_LAN_GTJU2}, AX178 },
163 : { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2GT}, AX178 },
164 : { { USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAU2KTX}, 0 },
165 : { { USB_VENDOR_MSI, USB_PRODUCT_MSI_AX88772A}, AX772 },
166 : { { USB_VENDOR_NETGEAR, USB_PRODUCT_NETGEAR_FA120}, 0 },
167 : { { USB_VENDOR_OQO, USB_PRODUCT_OQO_ETHER01PLUS }, AX772 },
168 : { { USB_VENDOR_PLANEX3, USB_PRODUCT_PLANEX3_GU1000T }, AX178 },
169 : { { USB_VENDOR_SYSTEMTALKS, USB_PRODUCT_SYSTEMTALKS_SGCX2UL}, 0 },
170 : { { USB_VENDOR_SITECOM, USB_PRODUCT_SITECOM_LN029}, 0 },
171 : { { USB_VENDOR_SITECOMEU, USB_PRODUCT_SITECOMEU_LN028 }, AX178 }
172 : };
173 :
174 : #define axe_lookup(v, p) ((struct axe_type *)usb_lookup(axe_devs, v, p))
175 :
176 : int axe_match(struct device *, void *, void *);
177 : void axe_attach(struct device *, struct device *, void *);
178 : int axe_detach(struct device *, int);
179 :
180 : struct cfdriver axe_cd = {
181 : NULL, "axe", DV_IFNET
182 : };
183 :
184 : const struct cfattach axe_ca = {
185 : sizeof(struct axe_softc), axe_match, axe_attach, axe_detach
186 : };
187 :
188 : int axe_tx_list_init(struct axe_softc *);
189 : int axe_rx_list_init(struct axe_softc *);
190 : struct mbuf *axe_newbuf(void);
191 : int axe_encap(struct axe_softc *, struct mbuf *, int);
192 : void axe_rxeof(struct usbd_xfer *, void *, usbd_status);
193 : void axe_txeof(struct usbd_xfer *, void *, usbd_status);
194 : void axe_tick(void *);
195 : void axe_tick_task(void *);
196 : void axe_start(struct ifnet *);
197 : int axe_ioctl(struct ifnet *, u_long, caddr_t);
198 : void axe_init(void *);
199 : void axe_stop(struct axe_softc *);
200 : void axe_watchdog(struct ifnet *);
201 : int axe_miibus_readreg(struct device *, int, int);
202 : void axe_miibus_writereg(struct device *, int, int, int);
203 : void axe_miibus_statchg(struct device *);
204 : int axe_cmd(struct axe_softc *, int, int, int, void *);
205 : int axe_ifmedia_upd(struct ifnet *);
206 : void axe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
207 : void axe_reset(struct axe_softc *sc);
208 :
209 : void axe_iff(struct axe_softc *);
210 : void axe_lock_mii(struct axe_softc *sc);
211 : void axe_unlock_mii(struct axe_softc *sc);
212 :
213 : void axe_ax88178_init(struct axe_softc *);
214 : void axe_ax88772_init(struct axe_softc *);
215 :
216 : /* Get exclusive access to the MII registers */
217 : void
218 0 : axe_lock_mii(struct axe_softc *sc)
219 : {
220 0 : sc->axe_refcnt++;
221 0 : rw_enter_write(&sc->axe_mii_lock);
222 0 : }
223 :
224 : void
225 0 : axe_unlock_mii(struct axe_softc *sc)
226 : {
227 0 : rw_exit_write(&sc->axe_mii_lock);
228 0 : if (--sc->axe_refcnt < 0)
229 0 : usb_detach_wakeup(&sc->axe_dev);
230 0 : }
231 :
232 : int
233 0 : axe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf)
234 : {
235 0 : usb_device_request_t req;
236 : usbd_status err;
237 :
238 0 : if (usbd_is_dying(sc->axe_udev))
239 0 : return(0);
240 :
241 0 : if (AXE_CMD_DIR(cmd))
242 0 : req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
243 : else
244 0 : req.bmRequestType = UT_READ_VENDOR_DEVICE;
245 0 : req.bRequest = AXE_CMD_CMD(cmd);
246 0 : USETW(req.wValue, val);
247 0 : USETW(req.wIndex, index);
248 0 : USETW(req.wLength, AXE_CMD_LEN(cmd));
249 :
250 0 : err = usbd_do_request(sc->axe_udev, &req, buf);
251 :
252 0 : if (err) {
253 : DPRINTF(("axe_cmd err: cmd: %d\n", cmd));
254 0 : return(-1);
255 : }
256 :
257 0 : return(0);
258 0 : }
259 :
260 : int
261 0 : axe_miibus_readreg(struct device *dev, int phy, int reg)
262 : {
263 0 : struct axe_softc *sc = (void *)dev;
264 : usbd_status err;
265 0 : uWord val;
266 : int ival;
267 :
268 0 : if (usbd_is_dying(sc->axe_udev)) {
269 : DPRINTF(("axe: dying\n"));
270 0 : return(0);
271 : }
272 :
273 : #ifdef notdef
274 : /*
275 : * The chip tells us the MII address of any supported
276 : * PHYs attached to the chip, so only read from those.
277 : */
278 :
279 : DPRINTF(("axe_miibus_readreg: phy 0x%x reg 0x%x\n", phy, reg));
280 :
281 : if (sc->axe_phyaddrs[0] != AXE_NOPHY && phy != sc->axe_phyaddrs[0])
282 : return (0);
283 :
284 : if (sc->axe_phyaddrs[1] != AXE_NOPHY && phy != sc->axe_phyaddrs[1])
285 : return (0);
286 : #endif
287 0 : if (sc->axe_phyno != phy)
288 0 : return (0);
289 :
290 0 : USETW(val, 0);
291 :
292 0 : axe_lock_mii(sc);
293 0 : axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
294 0 : err = axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, val);
295 0 : axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
296 0 : axe_unlock_mii(sc);
297 :
298 0 : if (err) {
299 0 : printf("axe%d: read PHY failed\n", sc->axe_unit);
300 0 : return(-1);
301 : }
302 : DPRINTF(("axe_miibus_readreg: phy 0x%x reg 0x%x val 0x%x\n",
303 : phy, reg, UGETW(val)));
304 :
305 0 : ival = UGETW(val);
306 0 : if ((sc->axe_flags & AX772) != 0 && reg == MII_BMSR) {
307 : /*
308 : * BMSR of AX88772 indicates that it supports extended
309 : * capability but the extended status register is
310 : * revered for embedded ethernet PHY. So clear the
311 : * extended capability bit of BMSR.
312 : */
313 0 : ival &= ~BMSR_EXTCAP;
314 0 : }
315 :
316 0 : return (ival);
317 0 : }
318 :
319 : void
320 0 : axe_miibus_writereg(struct device *dev, int phy, int reg, int val)
321 : {
322 0 : struct axe_softc *sc = (void *)dev;
323 : usbd_status err;
324 0 : uWord uval;
325 :
326 0 : if (usbd_is_dying(sc->axe_udev))
327 0 : return;
328 0 : if (sc->axe_phyno != phy)
329 0 : return;
330 :
331 0 : USETW(uval, val);
332 :
333 0 : axe_lock_mii(sc);
334 0 : axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
335 0 : err = axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, uval);
336 0 : axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
337 0 : axe_unlock_mii(sc);
338 :
339 0 : if (err) {
340 0 : printf("axe%d: write PHY failed\n", sc->axe_unit);
341 0 : return;
342 : }
343 0 : }
344 :
345 : void
346 0 : axe_miibus_statchg(struct device *dev)
347 : {
348 0 : struct axe_softc *sc = (void *)dev;
349 0 : struct mii_data *mii = GET_MII(sc);
350 : struct ifnet *ifp;
351 : int val, err;
352 :
353 0 : ifp = GET_IFP(sc);
354 0 : if (mii == NULL || ifp == NULL ||
355 0 : (ifp->if_flags & IFF_RUNNING) == 0)
356 0 : return;
357 :
358 0 : sc->axe_link = 0;
359 0 : if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
360 : (IFM_ACTIVE | IFM_AVALID)) {
361 0 : switch (IFM_SUBTYPE(mii->mii_media_active)) {
362 : case IFM_10_T:
363 : case IFM_100_TX:
364 0 : sc->axe_link++;
365 0 : break;
366 : case IFM_1000_T:
367 0 : if ((sc->axe_flags & AX178) == 0)
368 : break;
369 0 : sc->axe_link++;
370 0 : break;
371 : default:
372 : break;
373 : }
374 : }
375 :
376 : /* Lost link, do nothing. */
377 0 : if (sc->axe_link == 0)
378 0 : return;
379 :
380 : val = 0;
381 0 : if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
382 0 : val |= AXE_MEDIA_FULL_DUPLEX;
383 :
384 0 : if (sc->axe_flags & AX178 || sc->axe_flags & AX772) {
385 0 : val |= (AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC);
386 0 : if (sc->axe_flags & AX178)
387 0 : val |= AXE_178_MEDIA_ENCK;
388 :
389 0 : switch (IFM_SUBTYPE(mii->mii_media_active)) {
390 : case IFM_1000_T:
391 0 : val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK;
392 0 : break;
393 : case IFM_100_TX:
394 0 : val |= AXE_178_MEDIA_100TX;
395 0 : break;
396 : case IFM_10_T:
397 : /* doesn't need to be handled */
398 : break;
399 : }
400 : }
401 :
402 : DPRINTF(("axe_miibus_statchg: val=0x%x\n", val));
403 0 : err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL);
404 0 : if (err) {
405 0 : printf("%s: media change failed\n", sc->axe_dev.dv_xname);
406 0 : return;
407 : }
408 0 : }
409 :
410 : /*
411 : * Set media options.
412 : */
413 : int
414 0 : axe_ifmedia_upd(struct ifnet *ifp)
415 : {
416 0 : struct axe_softc *sc = ifp->if_softc;
417 0 : struct mii_data *mii = GET_MII(sc);
418 :
419 0 : if (mii->mii_instance) {
420 : struct mii_softc *miisc;
421 0 : LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
422 0 : mii_phy_reset(miisc);
423 0 : }
424 0 : mii_mediachg(mii);
425 :
426 0 : return (0);
427 : }
428 :
429 : /*
430 : * Report current media status.
431 : */
432 : void
433 0 : axe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
434 : {
435 0 : struct axe_softc *sc = ifp->if_softc;
436 0 : struct mii_data *mii = GET_MII(sc);
437 :
438 0 : mii_pollstat(mii);
439 0 : ifmr->ifm_active = mii->mii_media_active;
440 0 : ifmr->ifm_status = mii->mii_media_status;
441 0 : }
442 :
443 : void
444 0 : axe_iff(struct axe_softc *sc)
445 : {
446 0 : struct ifnet *ifp = GET_IFP(sc);
447 : struct arpcom *ac = &sc->arpcom;
448 : struct ether_multi *enm;
449 : struct ether_multistep step;
450 : u_int32_t h = 0;
451 0 : uWord urxmode;
452 : u_int16_t rxmode;
453 0 : u_int8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
454 :
455 0 : if (usbd_is_dying(sc->axe_udev))
456 0 : return;
457 :
458 0 : axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, urxmode);
459 0 : rxmode = UGETW(urxmode);
460 0 : rxmode &= ~(AXE_RXCMD_ALLMULTI | AXE_RXCMD_MULTICAST |
461 : AXE_RXCMD_PROMISC);
462 0 : ifp->if_flags &= ~IFF_ALLMULTI;
463 :
464 : /*
465 : * Always accept broadcast frames.
466 : * Always accept frames destined to our station address.
467 : */
468 0 : rxmode |= AXE_RXCMD_BROADCAST;
469 0 : if ((sc->axe_flags & (AX178 | AX772)) == 0)
470 0 : rxmode |= AXE_172_RXCMD_UNICAST;
471 :
472 0 : if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0) {
473 0 : ifp->if_flags |= IFF_ALLMULTI;
474 0 : rxmode |= AXE_RXCMD_ALLMULTI;
475 0 : if (ifp->if_flags & IFF_PROMISC)
476 0 : rxmode |= AXE_RXCMD_PROMISC;
477 : } else {
478 0 : rxmode |= AXE_RXCMD_MULTICAST;
479 :
480 : /* now program new ones */
481 0 : ETHER_FIRST_MULTI(step, ac, enm);
482 0 : while (enm != NULL) {
483 0 : h = ether_crc32_be(enm->enm_addrlo,
484 0 : ETHER_ADDR_LEN) >> 26;
485 :
486 0 : hashtbl[h / 8] |= 1 << (h % 8);
487 :
488 0 : ETHER_NEXT_MULTI(step, enm);
489 : }
490 : }
491 :
492 0 : axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl);
493 0 : axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
494 0 : }
495 :
496 : void
497 0 : axe_reset(struct axe_softc *sc)
498 : {
499 0 : if (usbd_is_dying(sc->axe_udev))
500 : return;
501 : /* XXX What to reset? */
502 :
503 : /* Wait a little while for the chip to get its brains in order. */
504 0 : DELAY(1000);
505 0 : return;
506 0 : }
507 :
508 : #define AXE_GPIO_WRITE(x,y) do { \
509 : axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL); \
510 : usbd_delay_ms(sc->axe_udev, (y)); \
511 : } while (0)
512 :
513 : void
514 0 : axe_ax88178_init(struct axe_softc *sc)
515 : {
516 : int gpio0 = 0, phymode = 0, ledmode;
517 0 : u_int16_t eeprom, val;
518 :
519 0 : axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL);
520 : /* XXX magic */
521 0 : axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom);
522 0 : axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL);
523 :
524 0 : eeprom = letoh16(eeprom);
525 :
526 : DPRINTF((" EEPROM is 0x%x\n", eeprom));
527 :
528 : /* if EEPROM is invalid we have to use to GPIO0 */
529 0 : if (eeprom == 0xffff) {
530 : phymode = AXE_PHY_MODE_MARVELL;
531 : gpio0 = 1;
532 : ledmode = 0;
533 0 : } else {
534 0 : phymode = eeprom & 0x7f;
535 0 : gpio0 = (eeprom & 0x80) ? 0 : 1;
536 0 : ledmode = eeprom >> 8;
537 : }
538 :
539 : DPRINTF(("use gpio0: %d, phymode 0x%02x, eeprom 0x%04x\n",
540 : gpio0, phymode, eeprom));
541 :
542 : /* power up external phy */
543 0 : AXE_GPIO_WRITE(AXE_GPIO1|AXE_GPIO1_EN | AXE_GPIO_RELOAD_EEPROM, 40);
544 0 : if (ledmode == 1) {
545 0 : AXE_GPIO_WRITE(AXE_GPIO1_EN, 30);
546 0 : AXE_GPIO_WRITE(AXE_GPIO1_EN | AXE_GPIO1, 30);
547 0 : } else {
548 0 : val = gpio0 == 1 ? AXE_GPIO0 | AXE_GPIO0_EN :
549 : AXE_GPIO1 | AXE_GPIO1_EN;
550 0 : AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, 30);
551 0 : AXE_GPIO_WRITE(val | AXE_GPIO2_EN, 300);
552 0 : AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, 30);
553 : }
554 :
555 : /* initialize phy */
556 0 : if (phymode == AXE_PHY_MODE_REALTEK_8211CL) {
557 0 : axe_miibus_writereg(&sc->axe_dev, sc->axe_phyno, 0x1f, 0x0005);
558 0 : axe_miibus_writereg(&sc->axe_dev, sc->axe_phyno, 0x0c, 0x0000);
559 0 : val = axe_miibus_readreg(&sc->axe_dev, sc->axe_phyno, 0x0001);
560 0 : axe_miibus_writereg(&sc->axe_dev, sc->axe_phyno, 0x01,
561 0 : val | 0x0080);
562 0 : axe_miibus_writereg(&sc->axe_dev, sc->axe_phyno, 0x1f, 0x0000);
563 0 : }
564 :
565 : /* soft reset */
566 0 : axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL);
567 0 : usbd_delay_ms(sc->axe_udev, 150);
568 0 : axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
569 : AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL);
570 0 : usbd_delay_ms(sc->axe_udev, 150);
571 : /* Enable MII/GMII/RGMII for external PHY */
572 0 : axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL);
573 0 : usbd_delay_ms(sc->axe_udev, 10);
574 0 : axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
575 0 : }
576 :
577 : /* Read Ethernet Address from EEPROM if it is zero */
578 : void
579 0 : axe_ax88772b_nodeid(struct axe_softc *sc, u_char *eaddr)
580 : {
581 : int i;
582 0 : uint16_t val;
583 :
584 0 : for (i = 0; i < ETHER_ADDR_LEN; i++) {
585 0 : if (eaddr[i] != 0)
586 : break;
587 : }
588 :
589 : /* We already have an ethernet address */
590 0 : if (i != ETHER_ADDR_LEN)
591 0 : return;
592 :
593 : /* read from EEPROM */
594 0 : for (i = 0; i < ETHER_ADDR_LEN/2; i++) {
595 0 : axe_cmd(sc, AXE_CMD_SROM_READ, 0, AXE_EEPROM_772B_NODEID + i, &val);
596 0 : val = ntohs(val);
597 0 : *eaddr++ = (u_char)((val >> 8) & 0xff);
598 0 : *eaddr++ = (u_char)(val & 0xff);
599 : }
600 0 : }
601 :
602 : void
603 0 : axe_ax88772_init(struct axe_softc *sc)
604 : {
605 0 : axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL);
606 0 : usbd_delay_ms(sc->axe_udev, 40);
607 :
608 0 : if (sc->axe_phyno == AXE_PHY_NO_AX772_EPHY) {
609 : /* ask for the embedded PHY */
610 0 : axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL);
611 0 : usbd_delay_ms(sc->axe_udev, 10);
612 :
613 : /* power down and reset state, pin reset state */
614 0 : axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL);
615 0 : usbd_delay_ms(sc->axe_udev, 60);
616 :
617 : /* power down/reset state, pin operating state */
618 0 : axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
619 : AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
620 0 : usbd_delay_ms(sc->axe_udev, 150);
621 :
622 : /* power up, reset */
623 0 : axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL);
624 :
625 : /* power up, operating */
626 0 : axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
627 : AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL);
628 0 : } else {
629 : /* ask for external PHY */
630 0 : axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x00, NULL);
631 0 : usbd_delay_ms(sc->axe_udev, 10);
632 :
633 : /* power down internal PHY */
634 0 : axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
635 : AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
636 : }
637 :
638 0 : usbd_delay_ms(sc->axe_udev, 150);
639 0 : axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
640 0 : }
641 :
642 : static int
643 0 : axe_get_phyno(struct axe_softc *sc, int sel)
644 : {
645 : int phyno = -1;
646 :
647 0 : switch (AXE_PHY_TYPE(sc->axe_phyaddrs[sel])) {
648 : case PHY_TYPE_100_HOME:
649 : case PHY_TYPE_GIG:
650 0 : phyno = AXE_PHY_NO(sc->axe_phyaddrs[sel]);
651 0 : break;
652 : case PHY_TYPE_SPECIAL:
653 : /* FALLTHROUGH */
654 : case PHY_TYPE_RSVD:
655 : /* FALLTHROUGH */
656 : case PHY_TYPE_NON_SUP:
657 : /* FALLTHROUGH */
658 : default:
659 : break;
660 : }
661 :
662 0 : return (phyno);
663 : }
664 :
665 : /*
666 : * Probe for a AX88172 chip.
667 : */
668 : int
669 0 : axe_match(struct device *parent, void *match, void *aux)
670 : {
671 0 : struct usb_attach_arg *uaa = aux;
672 :
673 0 : if (uaa->iface == NULL || uaa->configno != 1)
674 0 : return (UMATCH_NONE);
675 :
676 0 : return (axe_lookup(uaa->vendor, uaa->product) != NULL ?
677 : UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
678 0 : }
679 :
680 : /*
681 : * Attach the interface. Allocate softc structures, do ifmedia
682 : * setup and ethernet/BPF attach.
683 : */
684 : void
685 0 : axe_attach(struct device *parent, struct device *self, void *aux)
686 : {
687 0 : struct axe_softc *sc = (struct axe_softc *)self;
688 0 : struct usb_attach_arg *uaa = aux;
689 : usb_interface_descriptor_t *id;
690 : usb_endpoint_descriptor_t *ed;
691 : struct mii_data *mii;
692 0 : u_char eaddr[ETHER_ADDR_LEN];
693 0 : char *devname = sc->axe_dev.dv_xname;
694 : struct ifnet *ifp;
695 : int i, s;
696 :
697 0 : sc->axe_unit = self->dv_unit; /*device_get_unit(self);*/
698 0 : sc->axe_udev = uaa->device;
699 0 : sc->axe_iface = uaa->iface;
700 0 : sc->axe_flags = axe_lookup(uaa->vendor, uaa->product)->axe_flags;
701 :
702 0 : usb_init_task(&sc->axe_tick_task, axe_tick_task, sc,
703 : USB_TASK_TYPE_GENERIC);
704 0 : rw_init(&sc->axe_mii_lock, "axemii");
705 0 : usb_init_task(&sc->axe_stop_task, (void (*)(void *))axe_stop, sc,
706 : USB_TASK_TYPE_GENERIC);
707 :
708 0 : sc->axe_product = uaa->product;
709 0 : sc->axe_vendor = uaa->vendor;
710 :
711 0 : id = usbd_get_interface_descriptor(sc->axe_iface);
712 :
713 : /* decide on what our bufsize will be */
714 0 : if (sc->axe_flags & (AX178 | AX772))
715 0 : sc->axe_bufsz = (sc->axe_udev->speed == USB_SPEED_HIGH) ?
716 : AXE_178_MAX_BUFSZ : AXE_178_MIN_BUFSZ;
717 : else
718 0 : sc->axe_bufsz = AXE_172_BUFSZ;
719 :
720 : /* Find endpoints. */
721 0 : for (i = 0; i < id->bNumEndpoints; i++) {
722 0 : ed = usbd_interface2endpoint_descriptor(sc->axe_iface, i);
723 0 : if (!ed) {
724 0 : printf("%s: couldn't get ep %d\n",
725 : sc->axe_dev.dv_xname, i);
726 0 : return;
727 : }
728 0 : if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
729 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
730 0 : sc->axe_ed[AXE_ENDPT_RX] = ed->bEndpointAddress;
731 0 : } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
732 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
733 0 : sc->axe_ed[AXE_ENDPT_TX] = ed->bEndpointAddress;
734 0 : } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
735 0 : UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
736 0 : sc->axe_ed[AXE_ENDPT_INTR] = ed->bEndpointAddress;
737 0 : }
738 : }
739 :
740 0 : s = splnet();
741 :
742 : /* We need the PHYID for init dance in some cases */
743 0 : axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, (void *)&sc->axe_phyaddrs);
744 :
745 : DPRINTF((" phyaddrs[0]: %x phyaddrs[1]: %x\n",
746 : sc->axe_phyaddrs[0], sc->axe_phyaddrs[1]));
747 :
748 0 : sc->axe_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI);
749 0 : if (sc->axe_phyno == -1)
750 0 : sc->axe_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC);
751 0 : if (sc->axe_phyno == -1) {
752 0 : printf("%s:", sc->axe_dev.dv_xname);
753 0 : printf(" no valid PHY address found, assuming PHY address 0\n");
754 0 : sc->axe_phyno = 0;
755 0 : }
756 :
757 : DPRINTF((" get_phyno %d\n", sc->axe_phyno));
758 :
759 0 : if (sc->axe_flags & AX178)
760 0 : axe_ax88178_init(sc);
761 0 : else if (sc->axe_flags & AX772)
762 0 : axe_ax88772_init(sc);
763 :
764 : /*
765 : * Get station address.
766 : */
767 0 : if (sc->axe_flags & (AX178 | AX772))
768 0 : axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, &eaddr);
769 : else
770 0 : axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, &eaddr);
771 :
772 0 : if (sc->axe_flags & AX772B)
773 0 : axe_ax88772b_nodeid(sc, eaddr);
774 :
775 : /*
776 : * Load IPG values
777 : */
778 0 : axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, (void *)&sc->axe_ipgs);
779 :
780 : /*
781 : * An ASIX chip was detected. Inform the world.
782 : */
783 0 : printf("%s:", sc->axe_dev.dv_xname);
784 0 : if (sc->axe_flags & AX178)
785 0 : printf(" AX88178");
786 0 : else if (sc->axe_flags & AX772B)
787 0 : printf(" AX88772B");
788 0 : else if (sc->axe_flags & AX772)
789 0 : printf(" AX88772");
790 : else
791 0 : printf(" AX88172");
792 0 : printf(", address %s\n", ether_sprintf(eaddr));
793 :
794 0 : bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
795 :
796 : /* Initialize interface info.*/
797 0 : ifp = &sc->arpcom.ac_if;
798 0 : ifp->if_softc = sc;
799 0 : strlcpy(ifp->if_xname, devname, IFNAMSIZ);
800 0 : ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
801 0 : ifp->if_ioctl = axe_ioctl;
802 0 : ifp->if_start = axe_start;
803 0 : ifp->if_watchdog = axe_watchdog;
804 :
805 0 : ifp->if_capabilities = IFCAP_VLAN_MTU;
806 :
807 : /* Initialize MII/media info. */
808 0 : mii = &sc->axe_mii;
809 0 : mii->mii_ifp = ifp;
810 0 : mii->mii_readreg = axe_miibus_readreg;
811 0 : mii->mii_writereg = axe_miibus_writereg;
812 0 : mii->mii_statchg = axe_miibus_statchg;
813 0 : mii->mii_flags = MIIF_AUTOTSLEEP;
814 :
815 0 : ifmedia_init(&mii->mii_media, 0, axe_ifmedia_upd, axe_ifmedia_sts);
816 0 : mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
817 :
818 0 : if (LIST_FIRST(&mii->mii_phys) == NULL) {
819 0 : ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
820 0 : ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
821 0 : } else
822 0 : ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
823 :
824 : /* Attach the interface. */
825 0 : if_attach(ifp);
826 0 : ether_ifattach(ifp);
827 :
828 0 : timeout_set(&sc->axe_stat_ch, axe_tick, sc);
829 :
830 0 : splx(s);
831 0 : }
832 :
833 : int
834 0 : axe_detach(struct device *self, int flags)
835 : {
836 0 : struct axe_softc *sc = (struct axe_softc *)self;
837 : int s;
838 0 : struct ifnet *ifp = GET_IFP(sc);
839 :
840 : DPRINTFN(2,("%s: %s: enter\n", sc->axe_dev.dv_xname, __func__));
841 :
842 0 : if (timeout_initialized(&sc->axe_stat_ch))
843 0 : timeout_del(&sc->axe_stat_ch);
844 :
845 0 : if (sc->axe_ep[AXE_ENDPT_TX] != NULL)
846 0 : usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_TX]);
847 0 : if (sc->axe_ep[AXE_ENDPT_RX] != NULL)
848 0 : usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_RX]);
849 0 : if (sc->axe_ep[AXE_ENDPT_INTR] != NULL)
850 0 : usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
851 :
852 : /*
853 : * Remove any pending tasks. They cannot be executing because they run
854 : * in the same thread as detach.
855 : */
856 0 : usb_rem_task(sc->axe_udev, &sc->axe_tick_task);
857 0 : usb_rem_task(sc->axe_udev, &sc->axe_stop_task);
858 :
859 0 : s = splusb();
860 :
861 0 : if (--sc->axe_refcnt >= 0) {
862 : /* Wait for processes to go away */
863 0 : usb_detach_wait(&sc->axe_dev);
864 0 : }
865 :
866 0 : if (ifp->if_flags & IFF_RUNNING)
867 0 : axe_stop(sc);
868 :
869 0 : mii_detach(&sc->axe_mii, MII_PHY_ANY, MII_OFFSET_ANY);
870 0 : ifmedia_delete_instance(&sc->axe_mii.mii_media, IFM_INST_ANY);
871 0 : if (ifp->if_softc != NULL) {
872 0 : ether_ifdetach(ifp);
873 0 : if_detach(ifp);
874 0 : }
875 :
876 : #ifdef DIAGNOSTIC
877 0 : if (sc->axe_ep[AXE_ENDPT_TX] != NULL ||
878 0 : sc->axe_ep[AXE_ENDPT_RX] != NULL ||
879 0 : sc->axe_ep[AXE_ENDPT_INTR] != NULL)
880 0 : printf("%s: detach has active endpoints\n",
881 0 : sc->axe_dev.dv_xname);
882 : #endif
883 :
884 0 : if (--sc->axe_refcnt >= 0) {
885 : /* Wait for processes to go away. */
886 0 : usb_detach_wait(&sc->axe_dev);
887 0 : }
888 0 : splx(s);
889 :
890 0 : return (0);
891 : }
892 :
893 : struct mbuf *
894 0 : axe_newbuf(void)
895 : {
896 : struct mbuf *m;
897 :
898 0 : MGETHDR(m, M_DONTWAIT, MT_DATA);
899 0 : if (m == NULL)
900 0 : return (NULL);
901 :
902 0 : MCLGET(m, M_DONTWAIT);
903 0 : if (!(m->m_flags & M_EXT)) {
904 0 : m_freem(m);
905 0 : return (NULL);
906 : }
907 :
908 0 : m->m_len = m->m_pkthdr.len = MCLBYTES;
909 0 : m_adj(m, ETHER_ALIGN);
910 :
911 0 : return (m);
912 0 : }
913 :
914 : int
915 0 : axe_rx_list_init(struct axe_softc *sc)
916 : {
917 : struct axe_cdata *cd;
918 : struct axe_chain *c;
919 : int i;
920 :
921 : DPRINTF(("%s: %s: enter\n", sc->axe_dev.dv_xname, __func__));
922 :
923 0 : cd = &sc->axe_cdata;
924 0 : for (i = 0; i < AXE_RX_LIST_CNT; i++) {
925 0 : c = &cd->axe_rx_chain[i];
926 0 : c->axe_sc = sc;
927 0 : c->axe_idx = i;
928 0 : c->axe_mbuf = NULL;
929 0 : if (c->axe_xfer == NULL) {
930 0 : c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
931 0 : if (c->axe_xfer == NULL)
932 0 : return (ENOBUFS);
933 0 : c->axe_buf = usbd_alloc_buffer(c->axe_xfer,
934 0 : sc->axe_bufsz);
935 0 : if (c->axe_buf == NULL) {
936 0 : usbd_free_xfer(c->axe_xfer);
937 0 : return (ENOBUFS);
938 : }
939 : }
940 : }
941 :
942 0 : return (0);
943 0 : }
944 :
945 : int
946 0 : axe_tx_list_init(struct axe_softc *sc)
947 : {
948 : struct axe_cdata *cd;
949 : struct axe_chain *c;
950 : int i;
951 :
952 : DPRINTF(("%s: %s: enter\n", sc->axe_dev.dv_xname, __func__));
953 :
954 0 : cd = &sc->axe_cdata;
955 0 : for (i = 0; i < AXE_TX_LIST_CNT; i++) {
956 0 : c = &cd->axe_tx_chain[i];
957 0 : c->axe_sc = sc;
958 0 : c->axe_idx = i;
959 0 : c->axe_mbuf = NULL;
960 0 : if (c->axe_xfer == NULL) {
961 0 : c->axe_xfer = usbd_alloc_xfer(sc->axe_udev);
962 0 : if (c->axe_xfer == NULL)
963 0 : return (ENOBUFS);
964 0 : c->axe_buf = usbd_alloc_buffer(c->axe_xfer,
965 0 : sc->axe_bufsz);
966 0 : if (c->axe_buf == NULL) {
967 0 : usbd_free_xfer(c->axe_xfer);
968 0 : return (ENOBUFS);
969 : }
970 : }
971 : }
972 :
973 0 : return (0);
974 0 : }
975 :
976 : /*
977 : * A frame has been uploaded: pass the resulting mbuf chain up to
978 : * the higher level protocols.
979 : */
980 : void
981 0 : axe_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
982 : {
983 0 : struct axe_chain *c = (struct axe_chain *)priv;
984 0 : struct axe_softc *sc = c->axe_sc;
985 0 : struct ifnet *ifp = GET_IFP(sc);
986 0 : struct mbuf_list ml = MBUF_LIST_INITIALIZER();
987 0 : u_char *buf = c->axe_buf;
988 0 : u_int32_t total_len;
989 : u_int16_t pktlen = 0;
990 : struct mbuf *m;
991 : struct axe_sframe_hdr hdr;
992 : int s;
993 :
994 : DPRINTFN(10,("%s: %s: enter\n", sc->axe_dev.dv_xname,__func__));
995 :
996 0 : if (usbd_is_dying(sc->axe_udev))
997 0 : return;
998 :
999 0 : if (!(ifp->if_flags & IFF_RUNNING))
1000 0 : return;
1001 :
1002 0 : if (status != USBD_NORMAL_COMPLETION) {
1003 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
1004 0 : return;
1005 0 : if (usbd_ratecheck(&sc->axe_rx_notice)) {
1006 0 : printf("%s: usb errors on rx: %s\n",
1007 0 : sc->axe_dev.dv_xname, usbd_errstr(status));
1008 0 : }
1009 0 : if (status == USBD_STALLED)
1010 0 : usbd_clear_endpoint_stall_async(sc->axe_ep[AXE_ENDPT_RX]);
1011 : goto done;
1012 : }
1013 :
1014 0 : usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
1015 :
1016 0 : do {
1017 0 : if (sc->axe_flags & (AX178 | AX772)) {
1018 0 : if (total_len < sizeof(hdr)) {
1019 0 : ifp->if_ierrors++;
1020 0 : goto done;
1021 : }
1022 :
1023 0 : buf += pktlen;
1024 :
1025 0 : memcpy(&hdr, buf, sizeof(hdr));
1026 0 : total_len -= sizeof(hdr);
1027 :
1028 0 : if (((letoh16(hdr.len) & AXE_RH1M_RXLEN_MASK) ^
1029 0 : (letoh16(hdr.ilen) & AXE_RH1M_RXLEN_MASK)) !=
1030 : AXE_RH1M_RXLEN_MASK) {
1031 0 : ifp->if_ierrors++;
1032 0 : goto done;
1033 : }
1034 0 : pktlen = letoh16(hdr.len) & AXE_RH1M_RXLEN_MASK;
1035 0 : if (pktlen > total_len) {
1036 0 : ifp->if_ierrors++;
1037 0 : goto done;
1038 : }
1039 :
1040 0 : buf += sizeof(hdr);
1041 :
1042 0 : if ((pktlen % 2) != 0)
1043 0 : pktlen++;
1044 :
1045 0 : if (total_len < pktlen)
1046 0 : total_len = 0;
1047 : else
1048 0 : total_len -= pktlen;
1049 : } else {
1050 0 : pktlen = total_len; /* crc on the end? */
1051 0 : total_len = 0;
1052 : }
1053 :
1054 0 : m = axe_newbuf();
1055 0 : if (m == NULL) {
1056 0 : ifp->if_ierrors++;
1057 0 : goto done;
1058 : }
1059 :
1060 0 : m->m_pkthdr.len = m->m_len = pktlen;
1061 :
1062 0 : memcpy(mtod(m, char *), buf, pktlen);
1063 :
1064 0 : ml_enqueue(&ml, m);
1065 :
1066 0 : } while (total_len > 0);
1067 :
1068 : done:
1069 : /* push the packet up */
1070 0 : s = splnet();
1071 0 : if_input(ifp, &ml);
1072 0 : splx(s);
1073 :
1074 0 : memset(c->axe_buf, 0, sc->axe_bufsz);
1075 :
1076 : /* Setup new transfer. */
1077 0 : usbd_setup_xfer(xfer, sc->axe_ep[AXE_ENDPT_RX],
1078 0 : c, c->axe_buf, sc->axe_bufsz,
1079 : USBD_SHORT_XFER_OK | USBD_NO_COPY,
1080 : USBD_NO_TIMEOUT, axe_rxeof);
1081 0 : usbd_transfer(xfer);
1082 :
1083 : DPRINTFN(10,("%s: %s: start rx\n", sc->axe_dev.dv_xname, __func__));
1084 :
1085 0 : return;
1086 0 : }
1087 :
1088 : /*
1089 : * A frame was downloaded to the chip. It's safe for us to clean up
1090 : * the list buffers.
1091 : */
1092 :
1093 : void
1094 0 : axe_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
1095 : {
1096 : struct axe_softc *sc;
1097 : struct axe_chain *c;
1098 : struct ifnet *ifp;
1099 : int s;
1100 :
1101 0 : c = priv;
1102 0 : sc = c->axe_sc;
1103 0 : ifp = &sc->arpcom.ac_if;
1104 :
1105 0 : if (usbd_is_dying(sc->axe_udev))
1106 0 : return;
1107 :
1108 0 : s = splnet();
1109 :
1110 0 : if (status != USBD_NORMAL_COMPLETION) {
1111 0 : if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1112 0 : splx(s);
1113 0 : return;
1114 : }
1115 0 : ifp->if_oerrors++;
1116 0 : printf("axe%d: usb error on tx: %s\n", sc->axe_unit,
1117 0 : usbd_errstr(status));
1118 0 : if (status == USBD_STALLED)
1119 0 : usbd_clear_endpoint_stall_async(sc->axe_ep[AXE_ENDPT_TX]);
1120 0 : splx(s);
1121 0 : return;
1122 : }
1123 :
1124 0 : ifp->if_timer = 0;
1125 0 : ifq_clr_oactive(&ifp->if_snd);
1126 :
1127 0 : m_freem(c->axe_mbuf);
1128 0 : c->axe_mbuf = NULL;
1129 :
1130 0 : if (IFQ_IS_EMPTY(&ifp->if_snd) == 0)
1131 0 : axe_start(ifp);
1132 :
1133 0 : splx(s);
1134 0 : return;
1135 0 : }
1136 :
1137 : void
1138 0 : axe_tick(void *xsc)
1139 : {
1140 0 : struct axe_softc *sc = xsc;
1141 :
1142 0 : if (sc == NULL)
1143 0 : return;
1144 :
1145 : DPRINTFN(0xff, ("%s: %s: enter\n", sc->axe_dev.dv_xname,
1146 : __func__));
1147 :
1148 0 : if (usbd_is_dying(sc->axe_udev))
1149 0 : return;
1150 :
1151 : /* Perform periodic stuff in process context */
1152 0 : usb_add_task(sc->axe_udev, &sc->axe_tick_task);
1153 :
1154 0 : }
1155 :
1156 : void
1157 0 : axe_tick_task(void *xsc)
1158 : {
1159 : int s;
1160 : struct axe_softc *sc;
1161 : struct ifnet *ifp;
1162 : struct mii_data *mii;
1163 :
1164 0 : sc = xsc;
1165 :
1166 0 : if (sc == NULL)
1167 0 : return;
1168 :
1169 0 : if (usbd_is_dying(sc->axe_udev))
1170 0 : return;
1171 :
1172 0 : ifp = GET_IFP(sc);
1173 0 : mii = GET_MII(sc);
1174 0 : if (mii == NULL)
1175 0 : return;
1176 :
1177 0 : s = splnet();
1178 :
1179 0 : mii_tick(mii);
1180 0 : if (sc->axe_link == 0)
1181 0 : axe_miibus_statchg(&sc->axe_dev);
1182 0 : timeout_add_sec(&sc->axe_stat_ch, 1);
1183 :
1184 0 : splx(s);
1185 0 : }
1186 :
1187 : int
1188 0 : axe_encap(struct axe_softc *sc, struct mbuf *m, int idx)
1189 : {
1190 : struct axe_chain *c;
1191 : usbd_status err;
1192 : struct axe_sframe_hdr hdr;
1193 : int length, boundary;
1194 :
1195 0 : c = &sc->axe_cdata.axe_tx_chain[idx];
1196 :
1197 0 : if (sc->axe_flags & (AX178 | AX772)) {
1198 0 : boundary = (sc->axe_udev->speed == USB_SPEED_HIGH) ? 512 : 64;
1199 :
1200 0 : hdr.len = htole16(m->m_pkthdr.len);
1201 0 : hdr.ilen = ~hdr.len;
1202 :
1203 0 : memcpy(c->axe_buf, &hdr, sizeof(hdr));
1204 : length = sizeof(hdr);
1205 :
1206 0 : m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf + length);
1207 0 : length += m->m_pkthdr.len;
1208 :
1209 0 : if ((length % boundary) == 0) {
1210 : hdr.len = 0x0000;
1211 : hdr.ilen = 0xffff;
1212 0 : memcpy(c->axe_buf + length, &hdr, sizeof(hdr));
1213 0 : length += sizeof(hdr);
1214 0 : }
1215 :
1216 : } else {
1217 0 : m_copydata(m, 0, m->m_pkthdr.len, c->axe_buf);
1218 0 : length = m->m_pkthdr.len;
1219 : }
1220 :
1221 0 : c->axe_mbuf = m;
1222 :
1223 0 : usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_TX],
1224 0 : c, c->axe_buf, length, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
1225 : 10000, axe_txeof);
1226 :
1227 : /* Transmit */
1228 0 : err = usbd_transfer(c->axe_xfer);
1229 0 : if (err != USBD_IN_PROGRESS) {
1230 0 : axe_stop(sc);
1231 0 : return(EIO);
1232 : }
1233 :
1234 0 : sc->axe_cdata.axe_tx_cnt++;
1235 :
1236 0 : return(0);
1237 0 : }
1238 :
1239 : void
1240 0 : axe_start(struct ifnet *ifp)
1241 : {
1242 : struct axe_softc *sc;
1243 : struct mbuf *m_head = NULL;
1244 :
1245 0 : sc = ifp->if_softc;
1246 :
1247 0 : if (!sc->axe_link)
1248 0 : return;
1249 :
1250 0 : if (ifq_is_oactive(&ifp->if_snd))
1251 0 : return;
1252 :
1253 0 : m_head = ifq_deq_begin(&ifp->if_snd);
1254 0 : if (m_head == NULL)
1255 0 : return;
1256 :
1257 0 : if (axe_encap(sc, m_head, 0)) {
1258 0 : ifq_deq_rollback(&ifp->if_snd, m_head);
1259 0 : ifq_set_oactive(&ifp->if_snd);
1260 0 : return;
1261 : }
1262 0 : ifq_deq_commit(&ifp->if_snd, m_head);
1263 :
1264 : /*
1265 : * If there's a BPF listener, bounce a copy of this frame
1266 : * to him.
1267 : */
1268 : #if NBPFILTER > 0
1269 0 : if (ifp->if_bpf)
1270 0 : bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
1271 : #endif
1272 :
1273 0 : ifq_set_oactive(&ifp->if_snd);
1274 :
1275 : /*
1276 : * Set a timeout in case the chip goes out to lunch.
1277 : */
1278 0 : ifp->if_timer = 5;
1279 :
1280 0 : return;
1281 0 : }
1282 :
1283 : void
1284 0 : axe_init(void *xsc)
1285 : {
1286 0 : struct axe_softc *sc = xsc;
1287 0 : struct ifnet *ifp = &sc->arpcom.ac_if;
1288 : struct axe_chain *c;
1289 : usbd_status err;
1290 0 : uWord urxmode;
1291 : int rxmode;
1292 : int i, s;
1293 :
1294 0 : s = splnet();
1295 :
1296 : /*
1297 : * Cancel pending I/O and free all RX/TX buffers.
1298 : */
1299 0 : axe_reset(sc);
1300 :
1301 : /* set MAC address */
1302 0 : if (sc->axe_flags & (AX178 | AX772))
1303 0 : axe_cmd(sc, AXE_178_CMD_WRITE_NODEID, 0, 0,
1304 0 : &sc->arpcom.ac_enaddr);
1305 :
1306 : /* Enable RX logic. */
1307 :
1308 : /* Init RX ring. */
1309 0 : if (axe_rx_list_init(sc) == ENOBUFS) {
1310 0 : printf("axe%d: rx list init failed\n", sc->axe_unit);
1311 0 : splx(s);
1312 0 : return;
1313 : }
1314 :
1315 : /* Init TX ring. */
1316 0 : if (axe_tx_list_init(sc) == ENOBUFS) {
1317 0 : printf("axe%d: tx list init failed\n", sc->axe_unit);
1318 0 : splx(s);
1319 0 : return;
1320 : }
1321 :
1322 : /* Set transmitter IPG values */
1323 0 : if (sc->axe_flags & (AX178 | AX772))
1324 0 : axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->axe_ipgs[2],
1325 0 : (sc->axe_ipgs[1] << 8) | (sc->axe_ipgs[0]), NULL);
1326 : else {
1327 0 : axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->axe_ipgs[0], NULL);
1328 0 : axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->axe_ipgs[1], NULL);
1329 0 : axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->axe_ipgs[2], NULL);
1330 : }
1331 :
1332 : /* Program promiscuous mode and multicast filters. */
1333 0 : axe_iff(sc);
1334 :
1335 : /* Enable receiver, set RX mode */
1336 0 : axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, urxmode);
1337 0 : rxmode = UGETW(urxmode);
1338 0 : rxmode |= AXE_RXCMD_ENABLE;
1339 0 : if (sc->axe_flags & AX772B)
1340 0 : rxmode |= AXE_772B_RXCMD_RH1M;
1341 0 : else if (sc->axe_flags & (AX178 | AX772)) {
1342 0 : if (sc->axe_udev->speed == USB_SPEED_HIGH) {
1343 : /* largest possible USB buffer size for AX88178 */
1344 0 : rxmode |= AXE_178_RXCMD_MFB;
1345 0 : }
1346 : }
1347 0 : axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
1348 :
1349 : /* Open RX and TX pipes. */
1350 0 : err = usbd_open_pipe(sc->axe_iface, sc->axe_ed[AXE_ENDPT_RX],
1351 0 : USBD_EXCLUSIVE_USE, &sc->axe_ep[AXE_ENDPT_RX]);
1352 0 : if (err) {
1353 0 : printf("axe%d: open rx pipe failed: %s\n",
1354 0 : sc->axe_unit, usbd_errstr(err));
1355 0 : splx(s);
1356 0 : return;
1357 : }
1358 :
1359 0 : err = usbd_open_pipe(sc->axe_iface, sc->axe_ed[AXE_ENDPT_TX],
1360 0 : USBD_EXCLUSIVE_USE, &sc->axe_ep[AXE_ENDPT_TX]);
1361 0 : if (err) {
1362 0 : printf("axe%d: open tx pipe failed: %s\n",
1363 0 : sc->axe_unit, usbd_errstr(err));
1364 0 : splx(s);
1365 0 : return;
1366 : }
1367 :
1368 : /* Start up the receive pipe. */
1369 0 : for (i = 0; i < AXE_RX_LIST_CNT; i++) {
1370 0 : c = &sc->axe_cdata.axe_rx_chain[i];
1371 0 : usbd_setup_xfer(c->axe_xfer, sc->axe_ep[AXE_ENDPT_RX],
1372 0 : c, c->axe_buf, sc->axe_bufsz,
1373 : USBD_SHORT_XFER_OK | USBD_NO_COPY,
1374 : USBD_NO_TIMEOUT, axe_rxeof);
1375 0 : usbd_transfer(c->axe_xfer);
1376 : }
1377 :
1378 0 : sc->axe_link = 0;
1379 0 : ifp->if_flags |= IFF_RUNNING;
1380 0 : ifq_clr_oactive(&ifp->if_snd);
1381 :
1382 0 : splx(s);
1383 :
1384 0 : timeout_add_sec(&sc->axe_stat_ch, 1);
1385 0 : return;
1386 0 : }
1387 :
1388 : int
1389 0 : axe_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1390 : {
1391 0 : struct axe_softc *sc = ifp->if_softc;
1392 0 : struct ifreq *ifr = (struct ifreq *)data;
1393 : int s, error = 0;
1394 :
1395 0 : s = splnet();
1396 :
1397 0 : switch(cmd) {
1398 : case SIOCSIFADDR:
1399 0 : ifp->if_flags |= IFF_UP;
1400 0 : if (!(ifp->if_flags & IFF_RUNNING))
1401 0 : axe_init(sc);
1402 : break;
1403 :
1404 : case SIOCSIFFLAGS:
1405 0 : if (ifp->if_flags & IFF_UP) {
1406 0 : if (ifp->if_flags & IFF_RUNNING)
1407 0 : error = ENETRESET;
1408 : else
1409 0 : axe_init(sc);
1410 : } else {
1411 0 : if (ifp->if_flags & IFF_RUNNING)
1412 0 : axe_stop(sc);
1413 : }
1414 : break;
1415 :
1416 : case SIOCGIFMEDIA:
1417 : case SIOCSIFMEDIA:
1418 0 : error = ifmedia_ioctl(ifp, ifr, &sc->axe_mii.mii_media, cmd);
1419 0 : break;
1420 :
1421 : default:
1422 0 : error = ether_ioctl(ifp, &sc->arpcom, cmd, data);
1423 0 : }
1424 :
1425 0 : if (error == ENETRESET) {
1426 0 : if (ifp->if_flags & IFF_RUNNING)
1427 0 : axe_iff(sc);
1428 : error = 0;
1429 0 : }
1430 :
1431 0 : splx(s);
1432 0 : return(error);
1433 : }
1434 :
1435 : void
1436 0 : axe_watchdog(struct ifnet *ifp)
1437 : {
1438 : struct axe_softc *sc;
1439 : struct axe_chain *c;
1440 0 : usbd_status stat;
1441 : int s;
1442 :
1443 0 : sc = ifp->if_softc;
1444 :
1445 0 : ifp->if_oerrors++;
1446 0 : printf("axe%d: watchdog timeout\n", sc->axe_unit);
1447 :
1448 0 : s = splusb();
1449 0 : c = &sc->axe_cdata.axe_tx_chain[0];
1450 0 : usbd_get_xfer_status(c->axe_xfer, NULL, NULL, NULL, &stat);
1451 0 : axe_txeof(c->axe_xfer, c, stat);
1452 :
1453 0 : if (!IFQ_IS_EMPTY(&ifp->if_snd))
1454 0 : axe_start(ifp);
1455 0 : splx(s);
1456 0 : }
1457 :
1458 : /*
1459 : * Stop the adapter and free any mbufs allocated to the
1460 : * RX and TX lists.
1461 : */
1462 : void
1463 0 : axe_stop(struct axe_softc *sc)
1464 : {
1465 : usbd_status err;
1466 : struct ifnet *ifp;
1467 : int i;
1468 :
1469 0 : axe_reset(sc);
1470 :
1471 0 : ifp = &sc->arpcom.ac_if;
1472 0 : ifp->if_timer = 0;
1473 0 : ifp->if_flags &= ~IFF_RUNNING;
1474 0 : ifq_clr_oactive(&ifp->if_snd);
1475 :
1476 0 : timeout_del(&sc->axe_stat_ch);
1477 :
1478 : /* Stop transfers. */
1479 0 : if (sc->axe_ep[AXE_ENDPT_RX] != NULL) {
1480 0 : usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_RX]);
1481 0 : err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_RX]);
1482 0 : if (err) {
1483 0 : printf("axe%d: close rx pipe failed: %s\n",
1484 0 : sc->axe_unit, usbd_errstr(err));
1485 0 : }
1486 0 : sc->axe_ep[AXE_ENDPT_RX] = NULL;
1487 0 : }
1488 :
1489 0 : if (sc->axe_ep[AXE_ENDPT_TX] != NULL) {
1490 0 : usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_TX]);
1491 0 : err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_TX]);
1492 0 : if (err) {
1493 0 : printf("axe%d: close tx pipe failed: %s\n",
1494 0 : sc->axe_unit, usbd_errstr(err));
1495 0 : }
1496 0 : sc->axe_ep[AXE_ENDPT_TX] = NULL;
1497 0 : }
1498 :
1499 0 : if (sc->axe_ep[AXE_ENDPT_INTR] != NULL) {
1500 0 : usbd_abort_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
1501 0 : err = usbd_close_pipe(sc->axe_ep[AXE_ENDPT_INTR]);
1502 0 : if (err) {
1503 0 : printf("axe%d: close intr pipe failed: %s\n",
1504 0 : sc->axe_unit, usbd_errstr(err));
1505 0 : }
1506 0 : sc->axe_ep[AXE_ENDPT_INTR] = NULL;
1507 0 : }
1508 :
1509 : /* Free RX resources. */
1510 0 : for (i = 0; i < AXE_RX_LIST_CNT; i++) {
1511 0 : if (sc->axe_cdata.axe_rx_chain[i].axe_mbuf != NULL) {
1512 0 : m_freem(sc->axe_cdata.axe_rx_chain[i].axe_mbuf);
1513 0 : sc->axe_cdata.axe_rx_chain[i].axe_mbuf = NULL;
1514 0 : }
1515 0 : if (sc->axe_cdata.axe_rx_chain[i].axe_xfer != NULL) {
1516 0 : usbd_free_xfer(sc->axe_cdata.axe_rx_chain[i].axe_xfer);
1517 0 : sc->axe_cdata.axe_rx_chain[i].axe_xfer = NULL;
1518 0 : }
1519 : }
1520 :
1521 : /* Free TX resources. */
1522 0 : for (i = 0; i < AXE_TX_LIST_CNT; i++) {
1523 0 : if (sc->axe_cdata.axe_tx_chain[i].axe_mbuf != NULL) {
1524 0 : m_freem(sc->axe_cdata.axe_tx_chain[i].axe_mbuf);
1525 0 : sc->axe_cdata.axe_tx_chain[i].axe_mbuf = NULL;
1526 0 : }
1527 0 : if (sc->axe_cdata.axe_tx_chain[i].axe_xfer != NULL) {
1528 0 : usbd_free_xfer(sc->axe_cdata.axe_tx_chain[i].axe_xfer);
1529 0 : sc->axe_cdata.axe_tx_chain[i].axe_xfer = NULL;
1530 0 : }
1531 : }
1532 :
1533 0 : sc->axe_link = 0;
1534 0 : }
1535 :
|