if_axen.c revision 1.3.4.2 1 1.3.4.2 tls /* $NetBSD: if_axen.c,v 1.3.4.2 2014/08/20 00:03:51 tls Exp $ */
2 1.3.4.2 tls /* $OpenBSD: if_axen.c,v 1.3 2013/10/21 10:10:22 yuo Exp $ */
3 1.3.4.2 tls
4 1.3.4.2 tls /*
5 1.3.4.2 tls * Copyright (c) 2013 Yojiro UO <yuo (at) openbsd.org>
6 1.3.4.2 tls *
7 1.3.4.2 tls * Permission to use, copy, modify, and distribute this software for any
8 1.3.4.2 tls * purpose with or without fee is hereby granted, provided that the above
9 1.3.4.2 tls * copyright notice and this permission notice appear in all copies.
10 1.3.4.2 tls *
11 1.3.4.2 tls * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 1.3.4.2 tls * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 1.3.4.2 tls * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 1.3.4.2 tls * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 1.3.4.2 tls * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 1.3.4.2 tls * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 1.3.4.2 tls * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 1.3.4.2 tls */
19 1.3.4.2 tls
20 1.3.4.2 tls /*
21 1.3.4.2 tls * ASIX Electronics AX88178a USB 2.0 ethernet and AX88179 USB 3.0 Ethernet
22 1.3.4.2 tls * driver.
23 1.3.4.2 tls */
24 1.3.4.2 tls
25 1.3.4.2 tls #include <sys/cdefs.h>
26 1.3.4.2 tls __KERNEL_RCSID(0, "$NetBSD: if_axen.c,v 1.3.4.2 2014/08/20 00:03:51 tls Exp $");
27 1.3.4.2 tls
28 1.3.4.2 tls #ifdef _KERNEL_OPT
29 1.3.4.2 tls #include "opt_inet.h"
30 1.3.4.2 tls #endif
31 1.3.4.2 tls
32 1.3.4.2 tls #include <sys/param.h>
33 1.3.4.2 tls #include <sys/bus.h>
34 1.3.4.2 tls #include <sys/device.h>
35 1.3.4.2 tls #include <sys/kernel.h>
36 1.3.4.2 tls #include <sys/mbuf.h>
37 1.3.4.2 tls #include <sys/module.h>
38 1.3.4.2 tls #include <sys/rwlock.h>
39 1.3.4.2 tls #include <sys/socket.h>
40 1.3.4.2 tls #include <sys/sockio.h>
41 1.3.4.2 tls #include <sys/systm.h>
42 1.3.4.2 tls
43 1.3.4.2 tls #include <sys/rnd.h>
44 1.3.4.2 tls
45 1.3.4.2 tls #include <net/if.h>
46 1.3.4.2 tls #include <net/if_dl.h>
47 1.3.4.2 tls #include <net/if_ether.h>
48 1.3.4.2 tls #include <net/if_media.h>
49 1.3.4.2 tls
50 1.3.4.2 tls #include <net/bpf.h>
51 1.3.4.2 tls
52 1.3.4.2 tls #include <dev/mii/mii.h>
53 1.3.4.2 tls #include <dev/mii/miivar.h>
54 1.3.4.2 tls
55 1.3.4.2 tls #include <dev/usb/usb.h>
56 1.3.4.2 tls #include <dev/usb/usbdi.h>
57 1.3.4.2 tls #include <dev/usb/usbdi_util.h>
58 1.3.4.2 tls #include <dev/usb/usbdivar.h>
59 1.3.4.2 tls #include <dev/usb/usbdevs.h>
60 1.3.4.2 tls
61 1.3.4.2 tls #include <dev/usb/if_axenreg.h>
62 1.3.4.2 tls
63 1.3.4.2 tls #ifdef AXEN_DEBUG
64 1.3.4.2 tls #define DPRINTF(x) do { if (axendebug) printf x; } while (/*CONSTCOND*/0)
65 1.3.4.2 tls #define DPRINTFN(n,x) do { if (axendebug >= (n)) printf x; } while (/*CONSTCOND*/0)
66 1.3.4.2 tls int axendebug = 0;
67 1.3.4.2 tls #else
68 1.3.4.2 tls #define DPRINTF(x)
69 1.3.4.2 tls #define DPRINTFN(n,x)
70 1.3.4.2 tls #endif
71 1.3.4.2 tls
72 1.3.4.2 tls #define AXEN_TOE /* enable checksum offload function */
73 1.3.4.2 tls
74 1.3.4.2 tls /*
75 1.3.4.2 tls * Various supported device vendors/products.
76 1.3.4.2 tls */
77 1.3.4.2 tls static const struct axen_type axen_devs[] = {
78 1.3.4.2 tls #if 0 /* not tested */
79 1.3.4.2 tls { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88178A}, AX178A },
80 1.3.4.2 tls #endif
81 1.3.4.2 tls { { USB_VENDOR_ASIX, USB_PRODUCT_ASIX_AX88179}, AX179 }
82 1.3.4.2 tls };
83 1.3.4.2 tls
84 1.3.4.2 tls #define axen_lookup(v, p) ((const struct axen_type *)usb_lookup(axen_devs, v, p))
85 1.3.4.2 tls
86 1.3.4.2 tls static int axen_match(device_t, cfdata_t, void *);
87 1.3.4.2 tls static void axen_attach(device_t, device_t, void *);
88 1.3.4.2 tls static int axen_detach(device_t, int);
89 1.3.4.2 tls static int axen_activate(device_t, devact_t);
90 1.3.4.2 tls
91 1.3.4.2 tls CFATTACH_DECL_NEW(axen, sizeof(struct axen_softc),
92 1.3.4.2 tls axen_match, axen_attach, axen_detach, axen_activate);
93 1.3.4.2 tls
94 1.3.4.2 tls static int axen_tx_list_init(struct axen_softc *);
95 1.3.4.2 tls static int axen_rx_list_init(struct axen_softc *);
96 1.3.4.2 tls static struct mbuf *axen_newbuf(void);
97 1.3.4.2 tls static int axen_encap(struct axen_softc *, struct mbuf *, int);
98 1.3.4.2 tls static void axen_rxeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
99 1.3.4.2 tls static void axen_txeof(usbd_xfer_handle, usbd_private_handle, usbd_status);
100 1.3.4.2 tls static void axen_tick(void *);
101 1.3.4.2 tls static void axen_tick_task(void *);
102 1.3.4.2 tls static void axen_start(struct ifnet *);
103 1.3.4.2 tls static int axen_ioctl(struct ifnet *, u_long, void *);
104 1.3.4.2 tls static int axen_init(struct ifnet *);
105 1.3.4.2 tls static void axen_stop(struct ifnet *, int);
106 1.3.4.2 tls static void axen_watchdog(struct ifnet *);
107 1.3.4.2 tls static int axen_miibus_readreg(device_t, int, int);
108 1.3.4.2 tls static void axen_miibus_writereg(device_t, int, int, int);
109 1.3.4.2 tls static void axen_miibus_statchg(struct ifnet *);
110 1.3.4.2 tls static int axen_cmd(struct axen_softc *, int, int, int, void *);
111 1.3.4.2 tls static int axen_ifmedia_upd(struct ifnet *);
112 1.3.4.2 tls static void axen_ifmedia_sts(struct ifnet *, struct ifmediareq *);
113 1.3.4.2 tls static void axen_reset(struct axen_softc *sc);
114 1.3.4.2 tls #if 0
115 1.3.4.2 tls static int axen_ax88179_eeprom(struct axen_softc *, void *);
116 1.3.4.2 tls #endif
117 1.3.4.2 tls
118 1.3.4.2 tls static void axen_iff(struct axen_softc *);
119 1.3.4.2 tls static void axen_lock_mii(struct axen_softc *sc);
120 1.3.4.2 tls static void axen_unlock_mii(struct axen_softc *sc);
121 1.3.4.2 tls
122 1.3.4.2 tls static void axen_ax88179_init(struct axen_softc *);
123 1.3.4.2 tls
124 1.3.4.2 tls /* Get exclusive access to the MII registers */
125 1.3.4.2 tls static void
126 1.3.4.2 tls axen_lock_mii(struct axen_softc *sc)
127 1.3.4.2 tls {
128 1.3.4.2 tls
129 1.3.4.2 tls sc->axen_refcnt++;
130 1.3.4.2 tls rw_enter(&sc->axen_mii_lock, RW_WRITER);
131 1.3.4.2 tls }
132 1.3.4.2 tls
133 1.3.4.2 tls static void
134 1.3.4.2 tls axen_unlock_mii(struct axen_softc *sc)
135 1.3.4.2 tls {
136 1.3.4.2 tls
137 1.3.4.2 tls rw_exit(&sc->axen_mii_lock);
138 1.3.4.2 tls if (--sc->axen_refcnt < 0)
139 1.3.4.2 tls usb_detach_wakeupold(sc->axen_dev);
140 1.3.4.2 tls }
141 1.3.4.2 tls
142 1.3.4.2 tls static int
143 1.3.4.2 tls axen_cmd(struct axen_softc *sc, int cmd, int index, int val, void *buf)
144 1.3.4.2 tls {
145 1.3.4.2 tls usb_device_request_t req;
146 1.3.4.2 tls usbd_status err;
147 1.3.4.2 tls
148 1.3.4.2 tls KASSERT(rw_lock_held(&sc->axen_mii_lock));
149 1.3.4.2 tls
150 1.3.4.2 tls if (sc->axen_dying)
151 1.3.4.2 tls return 0;
152 1.3.4.2 tls
153 1.3.4.2 tls if (AXEN_CMD_DIR(cmd))
154 1.3.4.2 tls req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
155 1.3.4.2 tls else
156 1.3.4.2 tls req.bmRequestType = UT_READ_VENDOR_DEVICE;
157 1.3.4.2 tls req.bRequest = AXEN_CMD_CMD(cmd);
158 1.3.4.2 tls USETW(req.wValue, val);
159 1.3.4.2 tls USETW(req.wIndex, index);
160 1.3.4.2 tls USETW(req.wLength, AXEN_CMD_LEN(cmd));
161 1.3.4.2 tls
162 1.3.4.2 tls err = usbd_do_request(sc->axen_udev, &req, buf);
163 1.3.4.2 tls DPRINTFN(5, ("axen_cmd: cmd 0x%04x val 0x%04x len %d\n",
164 1.3.4.2 tls cmd, val, AXEN_CMD_LEN(cmd)));
165 1.3.4.2 tls
166 1.3.4.2 tls if (err) {
167 1.3.4.2 tls DPRINTF(("axen_cmd err: cmd: %d, error: %d\n", cmd, err));
168 1.3.4.2 tls return -1;
169 1.3.4.2 tls }
170 1.3.4.2 tls
171 1.3.4.2 tls return 0;
172 1.3.4.2 tls }
173 1.3.4.2 tls
174 1.3.4.2 tls static int
175 1.3.4.2 tls axen_miibus_readreg(device_t dev, int phy, int reg)
176 1.3.4.2 tls {
177 1.3.4.2 tls struct axen_softc *sc = device_private(dev);
178 1.3.4.2 tls usbd_status err;
179 1.3.4.2 tls uint16_t val;
180 1.3.4.2 tls int ival;
181 1.3.4.2 tls
182 1.3.4.2 tls if (sc->axen_dying) {
183 1.3.4.2 tls DPRINTF(("axen: dying\n"));
184 1.3.4.2 tls return 0;
185 1.3.4.2 tls }
186 1.3.4.2 tls
187 1.3.4.2 tls if (sc->axen_phyno != phy)
188 1.3.4.2 tls return 0;
189 1.3.4.2 tls
190 1.3.4.2 tls axen_lock_mii(sc);
191 1.3.4.2 tls err = axen_cmd(sc, AXEN_CMD_MII_READ_REG, reg, phy, &val);
192 1.3.4.2 tls axen_unlock_mii(sc);
193 1.3.4.2 tls
194 1.3.4.2 tls if (err) {
195 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "read PHY failed\n");
196 1.3.4.2 tls return -1;
197 1.3.4.2 tls }
198 1.3.4.2 tls
199 1.3.4.2 tls ival = le16toh(val);
200 1.3.4.2 tls DPRINTFN(2,("axen_miibus_readreg: phy 0x%x reg 0x%x val 0x%x\n",
201 1.3.4.2 tls phy, reg, ival));
202 1.3.4.2 tls
203 1.3.4.2 tls if (reg == MII_BMSR) {
204 1.3.4.2 tls ival &= ~BMSR_EXTCAP;
205 1.3.4.2 tls }
206 1.3.4.2 tls
207 1.3.4.2 tls return ival;
208 1.3.4.2 tls }
209 1.3.4.2 tls
210 1.3.4.2 tls static void
211 1.3.4.2 tls axen_miibus_writereg(device_t dev, int phy, int reg, int val)
212 1.3.4.2 tls {
213 1.3.4.2 tls struct axen_softc *sc = device_private(dev);
214 1.3.4.2 tls usbd_status err;
215 1.3.4.2 tls uint16_t uval;
216 1.3.4.2 tls
217 1.3.4.2 tls if (sc->axen_dying)
218 1.3.4.2 tls return;
219 1.3.4.2 tls
220 1.3.4.2 tls if (sc->axen_phyno != phy)
221 1.3.4.2 tls return;
222 1.3.4.2 tls
223 1.3.4.2 tls uval = htole16(val);
224 1.3.4.2 tls axen_lock_mii(sc);
225 1.3.4.2 tls err = axen_cmd(sc, AXEN_CMD_MII_WRITE_REG, reg, phy, &uval);
226 1.3.4.2 tls axen_unlock_mii(sc);
227 1.3.4.2 tls DPRINTFN(2, ("axen_miibus_writereg: phy 0x%x reg 0x%x val 0x%0x\n",
228 1.3.4.2 tls phy, reg, val));
229 1.3.4.2 tls
230 1.3.4.2 tls if (err) {
231 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "write PHY failed\n");
232 1.3.4.2 tls return;
233 1.3.4.2 tls }
234 1.3.4.2 tls }
235 1.3.4.2 tls
236 1.3.4.2 tls static void
237 1.3.4.2 tls axen_miibus_statchg(struct ifnet *ifp)
238 1.3.4.2 tls {
239 1.3.4.2 tls struct axen_softc *sc = ifp->if_softc;
240 1.3.4.2 tls struct mii_data *mii = GET_MII(sc);
241 1.3.4.2 tls int err;
242 1.3.4.2 tls uint16_t val;
243 1.3.4.2 tls uint16_t wval;
244 1.3.4.2 tls
245 1.3.4.2 tls sc->axen_link = 0;
246 1.3.4.2 tls if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
247 1.3.4.2 tls (IFM_ACTIVE | IFM_AVALID)) {
248 1.3.4.2 tls switch (IFM_SUBTYPE(mii->mii_media_active)) {
249 1.3.4.2 tls case IFM_10_T:
250 1.3.4.2 tls case IFM_100_TX:
251 1.3.4.2 tls sc->axen_link++;
252 1.3.4.2 tls break;
253 1.3.4.2 tls case IFM_1000_T:
254 1.3.4.2 tls sc->axen_link++;
255 1.3.4.2 tls break;
256 1.3.4.2 tls default:
257 1.3.4.2 tls break;
258 1.3.4.2 tls }
259 1.3.4.2 tls }
260 1.3.4.2 tls
261 1.3.4.2 tls /* Lost link, do nothing. */
262 1.3.4.2 tls if (sc->axen_link == 0)
263 1.3.4.2 tls return;
264 1.3.4.2 tls
265 1.3.4.2 tls val = 0;
266 1.3.4.2 tls if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
267 1.3.4.2 tls val |= AXEN_MEDIUM_FDX;
268 1.3.4.2 tls
269 1.3.4.2 tls val |= (AXEN_MEDIUM_RECV_EN | AXEN_MEDIUM_ALWAYS_ONE);
270 1.3.4.2 tls val |= (AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN);
271 1.3.4.2 tls
272 1.3.4.2 tls switch (IFM_SUBTYPE(mii->mii_media_active)) {
273 1.3.4.2 tls case IFM_1000_T:
274 1.3.4.2 tls val |= AXEN_MEDIUM_GIGA | AXEN_MEDIUM_EN_125MHZ;
275 1.3.4.2 tls break;
276 1.3.4.2 tls case IFM_100_TX:
277 1.3.4.2 tls val |= AXEN_MEDIUM_PS;
278 1.3.4.2 tls break;
279 1.3.4.2 tls case IFM_10_T:
280 1.3.4.2 tls /* doesn't need to be handled */
281 1.3.4.2 tls break;
282 1.3.4.2 tls }
283 1.3.4.2 tls
284 1.3.4.2 tls DPRINTF(("axen_miibus_statchg: val=0x%x\n", val));
285 1.3.4.2 tls wval = htole16(val);
286 1.3.4.2 tls axen_lock_mii(sc);
287 1.3.4.2 tls err = axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval);
288 1.3.4.2 tls axen_unlock_mii(sc);
289 1.3.4.2 tls if (err) {
290 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "media change failed\n");
291 1.3.4.2 tls return;
292 1.3.4.2 tls }
293 1.3.4.2 tls }
294 1.3.4.2 tls
295 1.3.4.2 tls /*
296 1.3.4.2 tls * Set media options.
297 1.3.4.2 tls */
298 1.3.4.2 tls static int
299 1.3.4.2 tls axen_ifmedia_upd(struct ifnet *ifp)
300 1.3.4.2 tls {
301 1.3.4.2 tls struct axen_softc *sc = ifp->if_softc;
302 1.3.4.2 tls struct mii_data *mii = GET_MII(sc);
303 1.3.4.2 tls int rc;
304 1.3.4.2 tls
305 1.3.4.2 tls sc->axen_link = 0;
306 1.3.4.2 tls
307 1.3.4.2 tls if (mii->mii_instance) {
308 1.3.4.2 tls struct mii_softc *miisc;
309 1.3.4.2 tls
310 1.3.4.2 tls LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
311 1.3.4.2 tls mii_phy_reset(miisc);
312 1.3.4.2 tls }
313 1.3.4.2 tls
314 1.3.4.2 tls if ((rc = mii_mediachg(mii)) == ENXIO)
315 1.3.4.2 tls return 0;
316 1.3.4.2 tls return rc;
317 1.3.4.2 tls }
318 1.3.4.2 tls
319 1.3.4.2 tls /*
320 1.3.4.2 tls * Report current media status.
321 1.3.4.2 tls */
322 1.3.4.2 tls static void
323 1.3.4.2 tls axen_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
324 1.3.4.2 tls {
325 1.3.4.2 tls struct axen_softc *sc = ifp->if_softc;
326 1.3.4.2 tls struct mii_data *mii = GET_MII(sc);
327 1.3.4.2 tls
328 1.3.4.2 tls mii_pollstat(mii);
329 1.3.4.2 tls ifmr->ifm_active = mii->mii_media_active;
330 1.3.4.2 tls ifmr->ifm_status = mii->mii_media_status;
331 1.3.4.2 tls }
332 1.3.4.2 tls
333 1.3.4.2 tls static void
334 1.3.4.2 tls axen_iff(struct axen_softc *sc)
335 1.3.4.2 tls {
336 1.3.4.2 tls struct ifnet *ifp = GET_IFP(sc);
337 1.3.4.2 tls struct ethercom *ec = &sc->axen_ec;
338 1.3.4.2 tls struct ether_multi *enm;
339 1.3.4.2 tls struct ether_multistep step;
340 1.3.4.2 tls uint32_t h = 0;
341 1.3.4.2 tls uint16_t rxmode;
342 1.3.4.2 tls uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
343 1.3.4.2 tls uint16_t wval;
344 1.3.4.2 tls
345 1.3.4.2 tls if (sc->axen_dying)
346 1.3.4.2 tls return;
347 1.3.4.2 tls
348 1.3.4.2 tls rxmode = 0;
349 1.3.4.2 tls
350 1.3.4.2 tls /* Enable receiver, set RX mode */
351 1.3.4.2 tls axen_lock_mii(sc);
352 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval);
353 1.3.4.2 tls rxmode = le16toh(wval);
354 1.3.4.2 tls rxmode &= ~(AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_ACPT_PHY_MCAST |
355 1.3.4.2 tls AXEN_RXCTL_PROMISC);
356 1.3.4.2 tls ifp->if_flags &= ~IFF_ALLMULTI;
357 1.3.4.2 tls
358 1.3.4.2 tls /*
359 1.3.4.2 tls * Always accept broadcast frames.
360 1.3.4.2 tls * Always accept frames destined to our station address.
361 1.3.4.2 tls */
362 1.3.4.2 tls rxmode |= AXEN_RXCTL_ACPT_BCAST;
363 1.3.4.2 tls
364 1.3.4.2 tls if (ifp->if_flags & IFF_PROMISC || ec->ec_multicnt > 0 /* XXX */) {
365 1.3.4.2 tls ifp->if_flags |= IFF_ALLMULTI;
366 1.3.4.2 tls rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_ACPT_PHY_MCAST;
367 1.3.4.2 tls if (ifp->if_flags & IFF_PROMISC)
368 1.3.4.2 tls rxmode |= AXEN_RXCTL_PROMISC;
369 1.3.4.2 tls } else {
370 1.3.4.2 tls rxmode |= AXEN_RXCTL_ACPT_ALL_MCAST | AXEN_RXCTL_ACPT_PHY_MCAST;
371 1.3.4.2 tls
372 1.3.4.2 tls /* now program new ones */
373 1.3.4.2 tls ETHER_FIRST_MULTI(step, ec, enm);
374 1.3.4.2 tls while (enm != NULL) {
375 1.3.4.2 tls h = ether_crc32_be(enm->enm_addrlo,
376 1.3.4.2 tls ETHER_ADDR_LEN) >> 26;
377 1.3.4.2 tls hashtbl[h / 8] |= 1 << (h % 8);
378 1.3.4.2 tls ETHER_NEXT_MULTI(step, enm);
379 1.3.4.2 tls }
380 1.3.4.2 tls }
381 1.3.4.2 tls
382 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE_FILTER, 8, AXEN_FILTER_MULTI, hashtbl);
383 1.3.4.2 tls wval = htole16(rxmode);
384 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval);
385 1.3.4.2 tls axen_unlock_mii(sc);
386 1.3.4.2 tls }
387 1.3.4.2 tls
388 1.3.4.2 tls static void
389 1.3.4.2 tls axen_reset(struct axen_softc *sc)
390 1.3.4.2 tls {
391 1.3.4.2 tls
392 1.3.4.2 tls if (sc->axen_dying)
393 1.3.4.2 tls return;
394 1.3.4.2 tls /* XXX What to reset? */
395 1.3.4.2 tls
396 1.3.4.2 tls /* Wait a little while for the chip to get its brains in order. */
397 1.3.4.2 tls DELAY(1000);
398 1.3.4.2 tls }
399 1.3.4.2 tls
400 1.3.4.2 tls #if 0 /* not used */
401 1.3.4.2 tls #define AXEN_GPIO_WRITE(x,y) do { \
402 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_WRITE_GPIO, 0, (x), NULL); \
403 1.3.4.2 tls usbd_delay_ms(sc->axen_udev, (y)); \
404 1.3.4.2 tls } while (/*CONSTCOND*/0)
405 1.3.4.2 tls
406 1.3.4.2 tls static int
407 1.3.4.2 tls axen_ax88179_eeprom(struct axen_softc *sc, void *addr)
408 1.3.4.2 tls {
409 1.3.4.2 tls int i, retry;
410 1.3.4.2 tls uint8_t eeprom[20];
411 1.3.4.2 tls uint16_t csum;
412 1.3.4.2 tls uint16_t buf;
413 1.3.4.2 tls
414 1.3.4.2 tls for (i = 0; i < 6; i++) {
415 1.3.4.2 tls /* set eeprom address */
416 1.3.4.2 tls buf = htole16(i);
417 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_MAC_EEPROM_ADDR, &buf);
418 1.3.4.2 tls
419 1.3.4.2 tls /* set eeprom command */
420 1.3.4.2 tls buf = htole16(AXEN_EEPROM_READ);
421 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_MAC_EEPROM_CMD, &buf);
422 1.3.4.2 tls
423 1.3.4.2 tls /* check the value is ready */
424 1.3.4.2 tls retry = 3;
425 1.3.4.2 tls do {
426 1.3.4.2 tls buf = htole16(AXEN_EEPROM_READ);
427 1.3.4.2 tls usbd_delay_ms(sc->axen_udev, 10);
428 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_MAC_EEPROM_CMD,
429 1.3.4.2 tls &buf);
430 1.3.4.2 tls retry--;
431 1.3.4.2 tls if (retry < 0)
432 1.3.4.2 tls return EINVAL;
433 1.3.4.2 tls } while ((le16toh(buf) & 0xff) & AXEN_EEPROM_BUSY);
434 1.3.4.2 tls
435 1.3.4.2 tls /* read data */
436 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_EEPROM_READ,
437 1.3.4.2 tls &eeprom[i * 2]);
438 1.3.4.2 tls
439 1.3.4.2 tls /* sanity check */
440 1.3.4.2 tls if ((i == 0) && (eeprom[0] == 0xff))
441 1.3.4.2 tls return EINVAL;
442 1.3.4.2 tls }
443 1.3.4.2 tls
444 1.3.4.2 tls /* check checksum */
445 1.3.4.2 tls csum = eeprom[6] + eeprom[7] + eeprom[8] + eeprom[9];
446 1.3.4.2 tls csum = (csum >> 8) + (csum & 0xff) + eeprom[10];
447 1.3.4.2 tls if (csum != 0xff) {
448 1.3.4.2 tls printf("eeprom checksum mismatchi(0x%02x)\n", csum);
449 1.3.4.2 tls return EINVAL;
450 1.3.4.2 tls }
451 1.3.4.2 tls
452 1.3.4.2 tls memcpy(addr, eeprom, ETHER_ADDR_LEN);
453 1.3.4.2 tls return 0;
454 1.3.4.2 tls }
455 1.3.4.2 tls #endif
456 1.3.4.2 tls
457 1.3.4.2 tls static void
458 1.3.4.2 tls axen_ax88179_init(struct axen_softc *sc)
459 1.3.4.2 tls {
460 1.3.4.2 tls struct axen_qctrl qctrl;
461 1.3.4.2 tls uint16_t ctl, temp;
462 1.3.4.2 tls uint16_t wval;
463 1.3.4.2 tls uint8_t val;
464 1.3.4.2 tls
465 1.3.4.2 tls axen_lock_mii(sc);
466 1.3.4.2 tls
467 1.3.4.2 tls /* XXX: ? */
468 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_UNK_05, &val);
469 1.3.4.2 tls DPRINTFN(5, ("AXEN_CMD_MAC_READ(0x05): 0x%02x\n", val));
470 1.3.4.2 tls
471 1.3.4.2 tls /* check AX88179 version, UA1 / UA2 */
472 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_GENERAL_STATUS, &val);
473 1.3.4.2 tls /* UA1 */
474 1.3.4.2 tls if (!(val & AXEN_GENERAL_STATUS_MASK)) {
475 1.3.4.2 tls sc->axen_rev = AXEN_REV_UA1;
476 1.3.4.2 tls DPRINTF(("AX88179 ver. UA1\n"));
477 1.3.4.2 tls } else {
478 1.3.4.2 tls sc->axen_rev = AXEN_REV_UA2;
479 1.3.4.2 tls DPRINTF(("AX88179 ver. UA2\n"));
480 1.3.4.2 tls }
481 1.3.4.2 tls
482 1.3.4.2 tls /* power up ethernet PHY */
483 1.3.4.2 tls wval = htole16(0);
484 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval);
485 1.3.4.2 tls
486 1.3.4.2 tls wval = htole16(AXEN_PHYPWR_RSTCTL_IPRL);
487 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval);
488 1.3.4.2 tls usbd_delay_ms(sc->axen_udev, 200);
489 1.3.4.2 tls
490 1.3.4.2 tls /* set clock mode */
491 1.3.4.2 tls val = AXEN_PHYCLK_ACS | AXEN_PHYCLK_BCS;
492 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val);
493 1.3.4.2 tls usbd_delay_ms(sc->axen_udev, 100);
494 1.3.4.2 tls
495 1.3.4.2 tls /* set monitor mode (disable) */
496 1.3.4.2 tls val = AXEN_MONITOR_NONE;
497 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val);
498 1.3.4.2 tls
499 1.3.4.2 tls /* enable auto detach */
500 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_EEPROM_READ, 2, AXEN_EEPROM_STAT, &wval);
501 1.3.4.2 tls temp = le16toh(wval);
502 1.3.4.2 tls DPRINTFN(2,("EEPROM0x43 = 0x%04x\n", temp));
503 1.3.4.2 tls if (!(temp == 0xffff) && !(temp & 0x0100)) {
504 1.3.4.2 tls /* Enable auto detach bit */
505 1.3.4.2 tls val = 0;
506 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val);
507 1.3.4.2 tls val = AXEN_PHYCLK_ULR;
508 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PHYCLK, &val);
509 1.3.4.2 tls usbd_delay_ms(sc->axen_udev, 100);
510 1.3.4.2 tls
511 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_PHYPWR_RSTCTL, &wval);
512 1.3.4.2 tls ctl = le16toh(wval);
513 1.3.4.2 tls ctl |= AXEN_PHYPWR_RSTCTL_AUTODETACH;
514 1.3.4.2 tls wval = htole16(ctl);
515 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_PHYPWR_RSTCTL, &wval);
516 1.3.4.2 tls usbd_delay_ms(sc->axen_udev, 200);
517 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "enable auto detach (0x%04x)\n",
518 1.3.4.2 tls ctl);
519 1.3.4.2 tls }
520 1.3.4.2 tls
521 1.3.4.2 tls /* bulkin queue setting */
522 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_USB_UPLINK, &val);
523 1.3.4.2 tls switch (val) {
524 1.3.4.2 tls case AXEN_USB_FS:
525 1.3.4.2 tls DPRINTF(("uplink: USB1.1\n"));
526 1.3.4.2 tls qctrl.ctrl = 0x07;
527 1.3.4.2 tls qctrl.timer_low = 0xcc;
528 1.3.4.2 tls qctrl.timer_high = 0x4c;
529 1.3.4.2 tls qctrl.bufsize = AXEN_BUFSZ_LS - 1;
530 1.3.4.2 tls qctrl.ifg = 0x08;
531 1.3.4.2 tls break;
532 1.3.4.2 tls case AXEN_USB_HS:
533 1.3.4.2 tls DPRINTF(("uplink: USB2.0\n"));
534 1.3.4.2 tls qctrl.ctrl = 0x07;
535 1.3.4.2 tls qctrl.timer_low = 0x02;
536 1.3.4.2 tls qctrl.timer_high = 0xa0;
537 1.3.4.2 tls qctrl.bufsize = AXEN_BUFSZ_HS - 1;
538 1.3.4.2 tls qctrl.ifg = 0xff;
539 1.3.4.2 tls break;
540 1.3.4.2 tls case AXEN_USB_SS:
541 1.3.4.2 tls DPRINTF(("uplink: USB3.0\n"));
542 1.3.4.2 tls qctrl.ctrl = 0x07;
543 1.3.4.2 tls qctrl.timer_low = 0x4f;
544 1.3.4.2 tls qctrl.timer_high = 0x00;
545 1.3.4.2 tls qctrl.bufsize = AXEN_BUFSZ_SS - 1;
546 1.3.4.2 tls qctrl.ifg = 0xff;
547 1.3.4.2 tls break;
548 1.3.4.2 tls default:
549 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "unknown uplink bus:0x%02x\n",
550 1.3.4.2 tls val);
551 1.3.4.2 tls axen_unlock_mii(sc);
552 1.3.4.2 tls return;
553 1.3.4.2 tls }
554 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_SET_RXSR, 5, AXEN_RX_BULKIN_QCTRL, &qctrl);
555 1.3.4.2 tls
556 1.3.4.2 tls /*
557 1.3.4.2 tls * set buffer high/low watermark to pause/resume.
558 1.3.4.2 tls * write 2byte will set high/log simultaneous with AXEN_PAUSE_HIGH.
559 1.3.4.2 tls * XXX: what is the best value? OSX driver uses 0x3c-0x4c as LOW-HIGH
560 1.3.4.2 tls * watermark parameters.
561 1.3.4.2 tls */
562 1.3.4.2 tls val = 0x34;
563 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_LOW_WATERMARK, &val);
564 1.3.4.2 tls val = 0x52;
565 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_PAUSE_HIGH_WATERMARK, &val);
566 1.3.4.2 tls
567 1.3.4.2 tls /* Set RX/TX configuration. */
568 1.3.4.2 tls /* Offloadng enable */
569 1.3.4.2 tls #ifdef AXEN_TOE
570 1.3.4.2 tls val = AXEN_RXCOE_IPv4 | AXEN_RXCOE_TCPv4 | AXEN_RXCOE_UDPv4 |
571 1.3.4.2 tls AXEN_RXCOE_TCPv6 | AXEN_RXCOE_UDPv6;
572 1.3.4.2 tls #else
573 1.3.4.2 tls val = AXEN_RXCOE_OFF;
574 1.3.4.2 tls #endif
575 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_RX_COE, &val);
576 1.3.4.2 tls
577 1.3.4.2 tls #ifdef AXEN_TOE
578 1.3.4.2 tls val = AXEN_TXCOE_IPv4 | AXEN_TXCOE_TCPv4 | AXEN_TXCOE_UDPv4 |
579 1.3.4.2 tls AXEN_TXCOE_TCPv6 | AXEN_TXCOE_UDPv6;
580 1.3.4.2 tls #else
581 1.3.4.2 tls val = AXEN_TXCOE_OFF;
582 1.3.4.2 tls #endif
583 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_TX_COE, &val);
584 1.3.4.2 tls
585 1.3.4.2 tls /* Set RX control register */
586 1.3.4.2 tls ctl = AXEN_RXCTL_IPE | AXEN_RXCTL_DROPCRCERR | AXEN_RXCTL_AUTOB;
587 1.3.4.2 tls ctl |= AXEN_RXCTL_ACPT_PHY_MCAST | AXEN_RXCTL_ACPT_ALL_MCAST;
588 1.3.4.2 tls ctl |= AXEN_RXCTL_START;
589 1.3.4.2 tls wval = htole16(ctl);
590 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval);
591 1.3.4.2 tls
592 1.3.4.2 tls /* set monitor mode (enable) */
593 1.3.4.2 tls val = AXEN_MONITOR_PMETYPE | AXEN_MONITOR_PMEPOL | AXEN_MONITOR_RWMP;
594 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_MONITOR_MODE, &val);
595 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_READ, 1, AXEN_MONITOR_MODE, &val);
596 1.3.4.2 tls DPRINTF(("axen: Monitor mode = 0x%02x\n", val));
597 1.3.4.2 tls
598 1.3.4.2 tls /* set medium type */
599 1.3.4.2 tls ctl = AXEN_MEDIUM_GIGA | AXEN_MEDIUM_FDX | AXEN_MEDIUM_ALWAYS_ONE |
600 1.3.4.2 tls AXEN_MEDIUM_RXFLOW_CTRL_EN | AXEN_MEDIUM_TXFLOW_CTRL_EN;
601 1.3.4.2 tls ctl |= AXEN_MEDIUM_RECV_EN;
602 1.3.4.2 tls wval = htole16(ctl);
603 1.3.4.2 tls DPRINTF(("axen: set to medium mode: 0x%04x\n", ctl));
604 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MEDIUM_STATUS, &wval);
605 1.3.4.2 tls usbd_delay_ms(sc->axen_udev, 100);
606 1.3.4.2 tls
607 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_MEDIUM_STATUS, &wval);
608 1.3.4.2 tls DPRINTF(("axen: current medium mode: 0x%04x\n", le16toh(wval)));
609 1.3.4.2 tls
610 1.3.4.2 tls axen_unlock_mii(sc);
611 1.3.4.2 tls
612 1.3.4.2 tls #if 0 /* XXX: TBD.... */
613 1.3.4.2 tls #define GMII_LED_ACTIVE 0x1a
614 1.3.4.2 tls #define GMII_PHY_PAGE_SEL 0x1e
615 1.3.4.2 tls #define GMII_PHY_PAGE_SEL 0x1f
616 1.3.4.2 tls #define GMII_PAGE_EXT 0x0007
617 1.3.4.2 tls axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, GMII_PHY_PAGE_SEL,
618 1.3.4.2 tls GMII_PAGE_EXT);
619 1.3.4.2 tls axen_miibus_writereg(&sc->axen_dev, sc->axen_phyno, GMII_PHY_PAGE,
620 1.3.4.2 tls 0x002c);
621 1.3.4.2 tls #endif
622 1.3.4.2 tls
623 1.3.4.2 tls #if 1 /* XXX: phy hack ? */
624 1.3.4.2 tls axen_miibus_writereg(sc->axen_dev, sc->axen_phyno, 0x1F, 0x0005);
625 1.3.4.2 tls axen_miibus_writereg(sc->axen_dev, sc->axen_phyno, 0x0C, 0x0000);
626 1.3.4.2 tls val = axen_miibus_readreg(sc->axen_dev, sc->axen_phyno, 0x0001);
627 1.3.4.2 tls axen_miibus_writereg(sc->axen_dev, sc->axen_phyno, 0x01,
628 1.3.4.2 tls val | 0x0080);
629 1.3.4.2 tls axen_miibus_writereg(sc->axen_dev, sc->axen_phyno, 0x1F, 0x0000);
630 1.3.4.2 tls #endif
631 1.3.4.2 tls }
632 1.3.4.2 tls
633 1.3.4.2 tls static int
634 1.3.4.2 tls axen_match(device_t parent, cfdata_t match, void *aux)
635 1.3.4.2 tls {
636 1.3.4.2 tls struct usb_attach_arg *uaa = aux;
637 1.3.4.2 tls
638 1.3.4.2 tls return axen_lookup(uaa->vendor, uaa->product) != NULL ?
639 1.3.4.2 tls UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
640 1.3.4.2 tls }
641 1.3.4.2 tls
642 1.3.4.2 tls static void
643 1.3.4.2 tls axen_attach(device_t parent, device_t self, void *aux)
644 1.3.4.2 tls {
645 1.3.4.2 tls struct axen_softc *sc = device_private(self);
646 1.3.4.2 tls struct usb_attach_arg *uaa = aux;
647 1.3.4.2 tls struct usbd_device *dev = uaa->device;
648 1.3.4.2 tls usbd_status err;
649 1.3.4.2 tls usb_interface_descriptor_t *id;
650 1.3.4.2 tls usb_endpoint_descriptor_t *ed;
651 1.3.4.2 tls struct mii_data *mii;
652 1.3.4.2 tls uint8_t eaddr[ETHER_ADDR_LEN];
653 1.3.4.2 tls char *devinfop;
654 1.3.4.2 tls const char *devname = device_xname(self);
655 1.3.4.2 tls struct ifnet *ifp;
656 1.3.4.2 tls int i, s;
657 1.3.4.2 tls
658 1.3.4.2 tls aprint_naive("\n");
659 1.3.4.2 tls aprint_normal("\n");
660 1.3.4.2 tls
661 1.3.4.2 tls sc->axen_dev = self;
662 1.3.4.2 tls sc->axen_udev = dev;
663 1.3.4.2 tls
664 1.3.4.2 tls devinfop = usbd_devinfo_alloc(dev, 0);
665 1.3.4.2 tls aprint_normal_dev(self, "%s\n", devinfop);
666 1.3.4.2 tls usbd_devinfo_free(devinfop);
667 1.3.4.2 tls
668 1.3.4.2 tls err = usbd_set_config_no(dev, AXEN_CONFIG_NO, 1);
669 1.3.4.2 tls if (err) {
670 1.3.4.2 tls aprint_error_dev(self, "failed to set configuration"
671 1.3.4.2 tls ", err=%s\n", usbd_errstr(err));
672 1.3.4.2 tls return;
673 1.3.4.2 tls }
674 1.3.4.2 tls
675 1.3.4.2 tls sc->axen_flags = axen_lookup(uaa->vendor, uaa->product)->axen_flags;
676 1.3.4.2 tls
677 1.3.4.2 tls rw_init(&sc->axen_mii_lock);
678 1.3.4.2 tls usb_init_task(&sc->axen_tick_task, axen_tick_task, sc, 0);
679 1.3.4.2 tls
680 1.3.4.2 tls err = usbd_device2interface_handle(dev, AXEN_IFACE_IDX,&sc->axen_iface);
681 1.3.4.2 tls if (err) {
682 1.3.4.2 tls aprint_error_dev(self, "getting interface handle failed\n");
683 1.3.4.2 tls return;
684 1.3.4.2 tls }
685 1.3.4.2 tls
686 1.3.4.2 tls sc->axen_product = uaa->product;
687 1.3.4.2 tls sc->axen_vendor = uaa->vendor;
688 1.3.4.2 tls
689 1.3.4.2 tls id = usbd_get_interface_descriptor(sc->axen_iface);
690 1.3.4.2 tls
691 1.3.4.2 tls /* XXX fix when USB3.0 HC is supported */
692 1.3.4.2 tls /* decide on what our bufsize will be */
693 1.3.4.2 tls sc->axen_bufsz = (sc->axen_udev->speed == USB_SPEED_HIGH) ?
694 1.3.4.2 tls AXEN_BUFSZ_HS * 1024 : AXEN_BUFSZ_LS * 1024;
695 1.3.4.2 tls
696 1.3.4.2 tls /* Find endpoints. */
697 1.3.4.2 tls for (i = 0; i < id->bNumEndpoints; i++) {
698 1.3.4.2 tls ed = usbd_interface2endpoint_descriptor(sc->axen_iface, i);
699 1.3.4.2 tls if (!ed) {
700 1.3.4.2 tls aprint_error_dev(self, "couldn't get ep %d\n", i);
701 1.3.4.2 tls return;
702 1.3.4.2 tls }
703 1.3.4.2 tls if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
704 1.3.4.2 tls UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
705 1.3.4.2 tls sc->axen_ed[AXEN_ENDPT_RX] = ed->bEndpointAddress;
706 1.3.4.2 tls } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
707 1.3.4.2 tls UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
708 1.3.4.2 tls sc->axen_ed[AXEN_ENDPT_TX] = ed->bEndpointAddress;
709 1.3.4.2 tls } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
710 1.3.4.2 tls UE_GET_XFERTYPE(ed->bmAttributes) == UE_INTERRUPT) {
711 1.3.4.2 tls sc->axen_ed[AXEN_ENDPT_INTR] = ed->bEndpointAddress;
712 1.3.4.2 tls }
713 1.3.4.2 tls }
714 1.3.4.2 tls
715 1.3.4.2 tls s = splnet();
716 1.3.4.2 tls
717 1.3.4.2 tls sc->axen_phyno = AXEN_PHY_ID;
718 1.3.4.2 tls DPRINTF(("%s: phyno %d\n", device_xname(self), sc->axen_phyno));
719 1.3.4.2 tls
720 1.3.4.2 tls /*
721 1.3.4.2 tls * Get station address.
722 1.3.4.2 tls */
723 1.3.4.2 tls #if 0 /* read from eeprom */
724 1.3.4.2 tls if (axen_ax88179_eeprom(sc, &eaddr)) {
725 1.3.4.2 tls printf("EEPROM checksum error\n");
726 1.3.4.2 tls return;
727 1.3.4.2 tls }
728 1.3.4.2 tls #else /* use MAC command */
729 1.3.4.2 tls axen_lock_mii(sc);
730 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_READ_ETHER, 6, AXEN_CMD_MAC_NODE_ID, &eaddr);
731 1.3.4.2 tls axen_unlock_mii(sc);
732 1.3.4.2 tls #endif
733 1.3.4.2 tls axen_ax88179_init(sc);
734 1.3.4.2 tls
735 1.3.4.2 tls /*
736 1.3.4.2 tls * An ASIX chip was detected. Inform the world.
737 1.3.4.2 tls */
738 1.3.4.2 tls if (sc->axen_flags & AX178A)
739 1.3.4.2 tls aprint_normal_dev(self, "AX88178a\n");
740 1.3.4.2 tls else if (sc->axen_flags & AX179)
741 1.3.4.2 tls aprint_normal_dev(self, "AX88179\n");
742 1.3.4.2 tls aprint_normal_dev(self, "Ethernet address %s\n", ether_sprintf(eaddr));
743 1.3.4.2 tls
744 1.3.4.2 tls /* Initialize interface info.*/
745 1.3.4.2 tls
746 1.3.4.2 tls ifp = &sc->sc_if;
747 1.3.4.2 tls ifp->if_softc = sc;
748 1.3.4.2 tls strlcpy(ifp->if_xname, devname, IFNAMSIZ);
749 1.3.4.2 tls ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
750 1.3.4.2 tls ifp->if_ioctl = axen_ioctl;
751 1.3.4.2 tls ifp->if_start = axen_start;
752 1.3.4.2 tls ifp->if_init = axen_init;
753 1.3.4.2 tls ifp->if_stop = axen_stop;
754 1.3.4.2 tls ifp->if_watchdog = axen_watchdog;
755 1.3.4.2 tls
756 1.3.4.2 tls IFQ_SET_READY(&ifp->if_snd);
757 1.3.4.2 tls
758 1.3.4.2 tls sc->axen_ec.ec_capabilities = ETHERCAP_VLAN_MTU;
759 1.3.4.2 tls #ifdef AXEN_TOE
760 1.3.4.2 tls ifp->if_capabilities |= IFCAP_CSUM_IPv4_Rx | IFCAP_CSUM_IPv4_Tx |
761 1.3.4.2 tls IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_TCPv4_Tx |
762 1.3.4.2 tls IFCAP_CSUM_UDPv4_Rx | IFCAP_CSUM_UDPv4_Tx |
763 1.3.4.2 tls IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_TCPv6_Tx |
764 1.3.4.2 tls IFCAP_CSUM_UDPv6_Rx | IFCAP_CSUM_UDPv6_Tx;
765 1.3.4.2 tls #endif
766 1.3.4.2 tls
767 1.3.4.2 tls /* Initialize MII/media info. */
768 1.3.4.2 tls mii = &sc->axen_mii;
769 1.3.4.2 tls mii->mii_ifp = ifp;
770 1.3.4.2 tls mii->mii_readreg = axen_miibus_readreg;
771 1.3.4.2 tls mii->mii_writereg = axen_miibus_writereg;
772 1.3.4.2 tls mii->mii_statchg = axen_miibus_statchg;
773 1.3.4.2 tls mii->mii_flags = MIIF_AUTOTSLEEP;
774 1.3.4.2 tls
775 1.3.4.2 tls sc->axen_ec.ec_mii = mii;
776 1.3.4.2 tls ifmedia_init(&mii->mii_media, 0, axen_ifmedia_upd, axen_ifmedia_sts);
777 1.3.4.2 tls mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
778 1.3.4.2 tls
779 1.3.4.2 tls if (LIST_FIRST(&mii->mii_phys) == NULL) {
780 1.3.4.2 tls ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
781 1.3.4.2 tls ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
782 1.3.4.2 tls } else
783 1.3.4.2 tls ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
784 1.3.4.2 tls
785 1.3.4.2 tls /* Attach the interface. */
786 1.3.4.2 tls if_attach(ifp);
787 1.3.4.2 tls ether_ifattach(ifp, eaddr);
788 1.3.4.2 tls rnd_attach_source(&sc->rnd_source, device_xname(sc->axen_dev),
789 1.3.4.2 tls RND_TYPE_NET, RND_FLAG_DEFAULT);
790 1.3.4.2 tls
791 1.3.4.2 tls callout_init(&sc->axen_stat_ch, 0);
792 1.3.4.2 tls callout_setfunc(&sc->axen_stat_ch, axen_tick, sc);
793 1.3.4.2 tls
794 1.3.4.2 tls sc->axen_attached = true;
795 1.3.4.2 tls splx(s);
796 1.3.4.2 tls
797 1.3.4.2 tls usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->axen_udev,sc->axen_dev);
798 1.3.4.2 tls }
799 1.3.4.2 tls
800 1.3.4.2 tls static int
801 1.3.4.2 tls axen_detach(device_t self, int flags)
802 1.3.4.2 tls {
803 1.3.4.2 tls struct axen_softc *sc = device_private(self);
804 1.3.4.2 tls struct ifnet *ifp = GET_IFP(sc);
805 1.3.4.2 tls int s;
806 1.3.4.2 tls
807 1.3.4.2 tls DPRINTFN(2,("%s: %s: enter\n", device_xname(sc->axen_dev), __func__));
808 1.3.4.2 tls
809 1.3.4.2 tls /* Detached before attached finished, so just bail out. */
810 1.3.4.2 tls if (!sc->axen_attached)
811 1.3.4.2 tls return 0;
812 1.3.4.2 tls
813 1.3.4.2 tls sc->axen_dying = true;
814 1.3.4.2 tls
815 1.3.4.2 tls /*
816 1.3.4.2 tls * Remove any pending tasks. They cannot be executing because they run
817 1.3.4.2 tls * in the same thread as detach.
818 1.3.4.2 tls */
819 1.3.4.2 tls usb_rem_task(sc->axen_udev, &sc->axen_tick_task);
820 1.3.4.2 tls
821 1.3.4.2 tls s = splusb();
822 1.3.4.2 tls
823 1.3.4.2 tls if (ifp->if_flags & IFF_RUNNING)
824 1.3.4.2 tls axen_stop(ifp, 1);
825 1.3.4.2 tls
826 1.3.4.2 tls callout_destroy(&sc->axen_stat_ch);
827 1.3.4.2 tls rnd_detach_source(&sc->rnd_source);
828 1.3.4.2 tls mii_detach(&sc->axen_mii, MII_PHY_ANY, MII_OFFSET_ANY);
829 1.3.4.2 tls ifmedia_delete_instance(&sc->axen_mii.mii_media, IFM_INST_ANY);
830 1.3.4.2 tls ether_ifdetach(ifp);
831 1.3.4.2 tls if_detach(ifp);
832 1.3.4.2 tls
833 1.3.4.2 tls #ifdef DIAGNOSTIC
834 1.3.4.2 tls if (sc->axen_ep[AXEN_ENDPT_TX] != NULL ||
835 1.3.4.2 tls sc->axen_ep[AXEN_ENDPT_RX] != NULL ||
836 1.3.4.2 tls sc->axen_ep[AXEN_ENDPT_INTR] != NULL)
837 1.3.4.2 tls aprint_debug_dev(self, "detach has active endpoints\n");
838 1.3.4.2 tls #endif
839 1.3.4.2 tls
840 1.3.4.2 tls sc->axen_attached = false;
841 1.3.4.2 tls
842 1.3.4.2 tls if (--sc->axen_refcnt >= 0) {
843 1.3.4.2 tls /* Wait for processes to go away. */
844 1.3.4.2 tls usb_detach_waitold(sc->axen_dev);
845 1.3.4.2 tls }
846 1.3.4.2 tls splx(s);
847 1.3.4.2 tls
848 1.3.4.2 tls usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->axen_udev,sc->axen_dev);
849 1.3.4.2 tls
850 1.3.4.2 tls rw_destroy(&sc->axen_mii_lock);
851 1.3.4.2 tls
852 1.3.4.2 tls return 0;
853 1.3.4.2 tls }
854 1.3.4.2 tls
855 1.3.4.2 tls static int
856 1.3.4.2 tls axen_activate(device_t self, devact_t act)
857 1.3.4.2 tls {
858 1.3.4.2 tls struct axen_softc *sc = device_private(self);
859 1.3.4.2 tls struct ifnet *ifp = GET_IFP(sc);
860 1.3.4.2 tls
861 1.3.4.2 tls DPRINTFN(2,("%s: %s: enter\n", device_xname(sc->axen_dev), __func__));
862 1.3.4.2 tls
863 1.3.4.2 tls switch (act) {
864 1.3.4.2 tls case DVACT_DEACTIVATE:
865 1.3.4.2 tls if_deactivate(ifp);
866 1.3.4.2 tls sc->axen_dying = true;
867 1.3.4.2 tls return 0;
868 1.3.4.2 tls default:
869 1.3.4.2 tls return EOPNOTSUPP;
870 1.3.4.2 tls }
871 1.3.4.2 tls }
872 1.3.4.2 tls
873 1.3.4.2 tls static struct mbuf *
874 1.3.4.2 tls axen_newbuf(void)
875 1.3.4.2 tls {
876 1.3.4.2 tls struct mbuf *m;
877 1.3.4.2 tls
878 1.3.4.2 tls MGETHDR(m, M_DONTWAIT, MT_DATA);
879 1.3.4.2 tls if (m == NULL)
880 1.3.4.2 tls return NULL;
881 1.3.4.2 tls
882 1.3.4.2 tls MCLGET(m, M_DONTWAIT);
883 1.3.4.2 tls if (!(m->m_flags & M_EXT)) {
884 1.3.4.2 tls m_freem(m);
885 1.3.4.2 tls return NULL;
886 1.3.4.2 tls }
887 1.3.4.2 tls
888 1.3.4.2 tls m->m_len = m->m_pkthdr.len = MCLBYTES;
889 1.3.4.2 tls m_adj(m, ETHER_ALIGN);
890 1.3.4.2 tls
891 1.3.4.2 tls return m;
892 1.3.4.2 tls }
893 1.3.4.2 tls
894 1.3.4.2 tls static int
895 1.3.4.2 tls axen_rx_list_init(struct axen_softc *sc)
896 1.3.4.2 tls {
897 1.3.4.2 tls struct axen_cdata *cd;
898 1.3.4.2 tls struct axen_chain *c;
899 1.3.4.2 tls int i;
900 1.3.4.2 tls
901 1.3.4.2 tls DPRINTF(("%s: %s: enter\n", device_xname(sc->axen_dev), __func__));
902 1.3.4.2 tls
903 1.3.4.2 tls cd = &sc->axen_cdata;
904 1.3.4.2 tls for (i = 0; i < AXEN_RX_LIST_CNT; i++) {
905 1.3.4.2 tls c = &cd->axen_rx_chain[i];
906 1.3.4.2 tls c->axen_sc = sc;
907 1.3.4.2 tls c->axen_idx = i;
908 1.3.4.2 tls if (c->axen_xfer == NULL) {
909 1.3.4.2 tls c->axen_xfer = usbd_alloc_xfer(sc->axen_udev);
910 1.3.4.2 tls if (c->axen_xfer == NULL)
911 1.3.4.2 tls return ENOBUFS;
912 1.3.4.2 tls c->axen_buf = usbd_alloc_buffer(c->axen_xfer,
913 1.3.4.2 tls sc->axen_bufsz);
914 1.3.4.2 tls if (c->axen_buf == NULL) {
915 1.3.4.2 tls usbd_free_xfer(c->axen_xfer);
916 1.3.4.2 tls return ENOBUFS;
917 1.3.4.2 tls }
918 1.3.4.2 tls }
919 1.3.4.2 tls }
920 1.3.4.2 tls
921 1.3.4.2 tls return 0;
922 1.3.4.2 tls }
923 1.3.4.2 tls
924 1.3.4.2 tls static int
925 1.3.4.2 tls axen_tx_list_init(struct axen_softc *sc)
926 1.3.4.2 tls {
927 1.3.4.2 tls struct axen_cdata *cd;
928 1.3.4.2 tls struct axen_chain *c;
929 1.3.4.2 tls int i;
930 1.3.4.2 tls
931 1.3.4.2 tls DPRINTF(("%s: %s: enter\n", device_xname(sc->axen_dev), __func__));
932 1.3.4.2 tls
933 1.3.4.2 tls cd = &sc->axen_cdata;
934 1.3.4.2 tls for (i = 0; i < AXEN_TX_LIST_CNT; i++) {
935 1.3.4.2 tls c = &cd->axen_tx_chain[i];
936 1.3.4.2 tls c->axen_sc = sc;
937 1.3.4.2 tls c->axen_idx = i;
938 1.3.4.2 tls if (c->axen_xfer == NULL) {
939 1.3.4.2 tls c->axen_xfer = usbd_alloc_xfer(sc->axen_udev);
940 1.3.4.2 tls if (c->axen_xfer == NULL)
941 1.3.4.2 tls return ENOBUFS;
942 1.3.4.2 tls c->axen_buf = usbd_alloc_buffer(c->axen_xfer,
943 1.3.4.2 tls sc->axen_bufsz);
944 1.3.4.2 tls if (c->axen_buf == NULL) {
945 1.3.4.2 tls usbd_free_xfer(c->axen_xfer);
946 1.3.4.2 tls return ENOBUFS;
947 1.3.4.2 tls }
948 1.3.4.2 tls }
949 1.3.4.2 tls }
950 1.3.4.2 tls
951 1.3.4.2 tls return 0;
952 1.3.4.2 tls }
953 1.3.4.2 tls
954 1.3.4.2 tls /*
955 1.3.4.2 tls * A frame has been uploaded: pass the resulting mbuf chain up to
956 1.3.4.2 tls * the higher level protocols.
957 1.3.4.2 tls */
958 1.3.4.2 tls static void
959 1.3.4.2 tls axen_rxeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
960 1.3.4.2 tls {
961 1.3.4.2 tls struct axen_chain *c = (struct axen_chain *)priv;
962 1.3.4.2 tls struct axen_softc *sc = c->axen_sc;
963 1.3.4.2 tls struct ifnet *ifp = GET_IFP(sc);
964 1.3.4.2 tls uint8_t *buf = c->axen_buf;
965 1.3.4.2 tls struct mbuf *m;
966 1.3.4.2 tls uint32_t total_len;
967 1.3.4.2 tls uint32_t rx_hdr, pkt_hdr;
968 1.3.4.2 tls uint32_t *hdr_p;
969 1.3.4.2 tls uint16_t hdr_offset, pkt_count;
970 1.3.4.2 tls size_t pkt_len;
971 1.3.4.2 tls size_t temp;
972 1.3.4.2 tls int s;
973 1.3.4.2 tls
974 1.3.4.2 tls DPRINTFN(10,("%s: %s: enter\n", device_xname(sc->axen_dev), __func__));
975 1.3.4.2 tls
976 1.3.4.2 tls if (sc->axen_dying)
977 1.3.4.2 tls return;
978 1.3.4.2 tls
979 1.3.4.2 tls if (!(ifp->if_flags & IFF_RUNNING))
980 1.3.4.2 tls return;
981 1.3.4.2 tls
982 1.3.4.2 tls if (status != USBD_NORMAL_COMPLETION) {
983 1.3.4.2 tls if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
984 1.3.4.2 tls return;
985 1.3.4.2 tls if (usbd_ratecheck(&sc->axen_rx_notice)) {
986 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "usb errors on rx: %s\n",
987 1.3.4.2 tls usbd_errstr(status));
988 1.3.4.2 tls }
989 1.3.4.2 tls if (status == USBD_STALLED)
990 1.3.4.2 tls usbd_clear_endpoint_stall_async(sc->axen_ep[AXEN_ENDPT_RX]);
991 1.3.4.2 tls goto done;
992 1.3.4.2 tls }
993 1.3.4.2 tls
994 1.3.4.2 tls usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
995 1.3.4.2 tls
996 1.3.4.2 tls if (total_len < sizeof(pkt_hdr)) {
997 1.3.4.2 tls ifp->if_ierrors++;
998 1.3.4.2 tls goto done;
999 1.3.4.2 tls }
1000 1.3.4.2 tls
1001 1.3.4.2 tls /*
1002 1.3.4.2 tls * buffer map
1003 1.3.4.2 tls * [packet #0]...[packet #n][pkt hdr#0]..[pkt hdr#n][recv_hdr]
1004 1.3.4.2 tls * each packet has 0xeeee as psuedo header..
1005 1.3.4.2 tls */
1006 1.3.4.2 tls hdr_p = (uint32_t *)(buf + total_len - sizeof(uint32_t));
1007 1.3.4.2 tls rx_hdr = le32toh(*hdr_p);
1008 1.3.4.2 tls hdr_offset = (uint16_t)(rx_hdr >> 16);
1009 1.3.4.2 tls pkt_count = (uint16_t)(rx_hdr & 0xffff);
1010 1.3.4.2 tls
1011 1.3.4.2 tls if (total_len > sc->axen_bufsz) {
1012 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "rxeof: too large transfer\n");
1013 1.3.4.2 tls goto done;
1014 1.3.4.2 tls }
1015 1.3.4.2 tls
1016 1.3.4.2 tls /* sanity check */
1017 1.3.4.2 tls if (hdr_offset > total_len) {
1018 1.3.4.2 tls ifp->if_ierrors++;
1019 1.3.4.2 tls usbd_delay_ms(sc->axen_udev, 100);
1020 1.3.4.2 tls goto done;
1021 1.3.4.2 tls }
1022 1.3.4.2 tls
1023 1.3.4.2 tls /* point first packet header */
1024 1.3.4.2 tls hdr_p = (uint32_t *)(buf + hdr_offset);
1025 1.3.4.2 tls
1026 1.3.4.2 tls /*
1027 1.3.4.2 tls * ax88179 will pack multiple ip packet to a USB transaction.
1028 1.3.4.2 tls * process all of packets in the buffer
1029 1.3.4.2 tls */
1030 1.3.4.2 tls
1031 1.3.4.2 tls #if 1 /* XXX: paranoiac check. need to remove later */
1032 1.3.4.2 tls #define AXEN_MAX_PACKED_PACKET 200
1033 1.3.4.2 tls if (pkt_count > AXEN_MAX_PACKED_PACKET) {
1034 1.3.4.2 tls DPRINTF(("%s: Too many packets (%d) in a transaction, discard.\n",
1035 1.3.4.2 tls device_xname(sc->axen_dev), pkt_count));
1036 1.3.4.2 tls goto done;
1037 1.3.4.2 tls }
1038 1.3.4.2 tls #endif
1039 1.3.4.2 tls
1040 1.3.4.2 tls do {
1041 1.3.4.2 tls if ((buf[0] != 0xee) || (buf[1] != 0xee)){
1042 1.3.4.2 tls aprint_error_dev(sc->axen_dev,
1043 1.3.4.2 tls "invalid buffer(pkt#%d), continue\n", pkt_count);
1044 1.3.4.2 tls ifp->if_ierrors += pkt_count;
1045 1.3.4.2 tls goto done;
1046 1.3.4.2 tls }
1047 1.3.4.2 tls
1048 1.3.4.2 tls pkt_hdr = le32toh(*hdr_p);
1049 1.3.4.2 tls pkt_len = (pkt_hdr >> 16) & 0x1fff;
1050 1.3.4.2 tls DPRINTFN(10,
1051 1.3.4.2 tls ("%s: rxeof: packet#%d, pkt_hdr 0x%08x, pkt_len %zu\n",
1052 1.3.4.2 tls device_xname(sc->axen_dev), pkt_count, pkt_hdr, pkt_len));
1053 1.3.4.2 tls
1054 1.3.4.2 tls if ((pkt_hdr & AXEN_RXHDR_CRC_ERR) ||
1055 1.3.4.2 tls (pkt_hdr & AXEN_RXHDR_DROP_ERR)) {
1056 1.3.4.2 tls ifp->if_ierrors++;
1057 1.3.4.2 tls /* move to next pkt header */
1058 1.3.4.2 tls DPRINTF(("%s: crc err (pkt#%d)\n",
1059 1.3.4.2 tls device_xname(sc->axen_dev), pkt_count));
1060 1.3.4.2 tls goto nextpkt;
1061 1.3.4.2 tls }
1062 1.3.4.2 tls
1063 1.3.4.2 tls /* process each packet */
1064 1.3.4.2 tls /* allocate mbuf */
1065 1.3.4.2 tls m = axen_newbuf();
1066 1.3.4.2 tls if (m == NULL) {
1067 1.3.4.2 tls ifp->if_ierrors++;
1068 1.3.4.2 tls goto nextpkt;
1069 1.3.4.2 tls }
1070 1.3.4.2 tls
1071 1.3.4.2 tls /* skip pseudo header (2byte) */
1072 1.3.4.2 tls ifp->if_ipackets++;
1073 1.3.4.2 tls m->m_pkthdr.rcvif = ifp;
1074 1.3.4.2 tls m->m_pkthdr.len = m->m_len = pkt_len - 2;
1075 1.3.4.2 tls
1076 1.3.4.2 tls #ifdef AXEN_TOE
1077 1.3.4.2 tls /* cheksum err */
1078 1.3.4.2 tls if ((pkt_hdr & AXEN_RXHDR_L3CSUM_ERR) ||
1079 1.3.4.2 tls (pkt_hdr & AXEN_RXHDR_L4CSUM_ERR)) {
1080 1.3.4.2 tls aprint_error_dev(sc->axen_dev,
1081 1.3.4.2 tls "checksum err (pkt#%d)\n", pkt_count);
1082 1.3.4.2 tls goto nextpkt;
1083 1.3.4.2 tls } else {
1084 1.3.4.2 tls m->m_pkthdr.csum_flags |= M_CSUM_IPv4;
1085 1.3.4.2 tls }
1086 1.3.4.2 tls
1087 1.3.4.2 tls int l4_type = (pkt_hdr & AXEN_RXHDR_L4_TYPE_MASK) >>
1088 1.3.4.2 tls AXEN_RXHDR_L4_TYPE_OFFSET;
1089 1.3.4.2 tls
1090 1.3.4.2 tls if ((l4_type == AXEN_RXHDR_L4_TYPE_TCP) ||
1091 1.3.4.2 tls (l4_type == AXEN_RXHDR_L4_TYPE_UDP)) {
1092 1.3.4.2 tls m->m_pkthdr.csum_flags |= M_CSUM_TCPv4 |
1093 1.3.4.2 tls M_CSUM_UDPv4; /* XXX v6? */
1094 1.3.4.2 tls }
1095 1.3.4.2 tls #endif
1096 1.3.4.2 tls
1097 1.3.4.2 tls memcpy(mtod(m, char *), buf + 2, pkt_len - 2);
1098 1.3.4.2 tls
1099 1.3.4.2 tls /* push the packet up */
1100 1.3.4.2 tls s = splnet();
1101 1.3.4.2 tls bpf_mtap(ifp, m);
1102 1.3.4.2 tls (*(ifp)->if_input)((ifp), (m));
1103 1.3.4.2 tls splx(s);
1104 1.3.4.2 tls
1105 1.3.4.2 tls nextpkt:
1106 1.3.4.2 tls /*
1107 1.3.4.2 tls * prepare next packet
1108 1.3.4.2 tls * as each packet will be aligned 8byte boundary,
1109 1.3.4.2 tls * need to fix up the start point of the buffer.
1110 1.3.4.2 tls */
1111 1.3.4.2 tls temp = ((pkt_len + 7) & 0xfff8);
1112 1.3.4.2 tls buf = buf + temp;
1113 1.3.4.2 tls hdr_p++;
1114 1.3.4.2 tls pkt_count--;
1115 1.3.4.2 tls } while( pkt_count > 0);
1116 1.3.4.2 tls
1117 1.3.4.2 tls done:
1118 1.3.4.2 tls /* clear buffer for next transaction */
1119 1.3.4.2 tls memset(c->axen_buf, 0, sc->axen_bufsz);
1120 1.3.4.2 tls
1121 1.3.4.2 tls /* Setup new transfer. */
1122 1.3.4.2 tls usbd_setup_xfer(xfer, sc->axen_ep[AXEN_ENDPT_RX],
1123 1.3.4.2 tls c, c->axen_buf, sc->axen_bufsz,
1124 1.3.4.2 tls USBD_SHORT_XFER_OK | USBD_NO_COPY,
1125 1.3.4.2 tls USBD_NO_TIMEOUT, axen_rxeof);
1126 1.3.4.2 tls usbd_transfer(xfer);
1127 1.3.4.2 tls
1128 1.3.4.2 tls DPRINTFN(10,("%s: %s: start rx\n",device_xname(sc->axen_dev),__func__));
1129 1.3.4.2 tls }
1130 1.3.4.2 tls
1131 1.3.4.2 tls /*
1132 1.3.4.2 tls * A frame was downloaded to the chip. It's safe for us to clean up
1133 1.3.4.2 tls * the list buffers.
1134 1.3.4.2 tls */
1135 1.3.4.2 tls static void
1136 1.3.4.2 tls axen_txeof(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status)
1137 1.3.4.2 tls {
1138 1.3.4.2 tls struct axen_chain *c = (struct axen_chain *)priv;
1139 1.3.4.2 tls struct axen_softc *sc = c->axen_sc;
1140 1.3.4.2 tls struct ifnet *ifp = GET_IFP(sc);
1141 1.3.4.2 tls int s;
1142 1.3.4.2 tls
1143 1.3.4.2 tls if (sc->axen_dying)
1144 1.3.4.2 tls return;
1145 1.3.4.2 tls
1146 1.3.4.2 tls s = splnet();
1147 1.3.4.2 tls
1148 1.3.4.2 tls if (status != USBD_NORMAL_COMPLETION) {
1149 1.3.4.2 tls if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
1150 1.3.4.2 tls splx(s);
1151 1.3.4.2 tls return;
1152 1.3.4.2 tls }
1153 1.3.4.2 tls ifp->if_oerrors++;
1154 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "usb error on tx: %s\n",
1155 1.3.4.2 tls usbd_errstr(status));
1156 1.3.4.2 tls if (status == USBD_STALLED)
1157 1.3.4.2 tls usbd_clear_endpoint_stall_async(sc->axen_ep[AXEN_ENDPT_TX]);
1158 1.3.4.2 tls splx(s);
1159 1.3.4.2 tls return;
1160 1.3.4.2 tls }
1161 1.3.4.2 tls
1162 1.3.4.2 tls ifp->if_timer = 0;
1163 1.3.4.2 tls ifp->if_flags &= ~IFF_OACTIVE;
1164 1.3.4.2 tls
1165 1.3.4.2 tls if (!IFQ_IS_EMPTY(&ifp->if_snd))
1166 1.3.4.2 tls axen_start(ifp);
1167 1.3.4.2 tls
1168 1.3.4.2 tls ifp->if_opackets++;
1169 1.3.4.2 tls splx(s);
1170 1.3.4.2 tls }
1171 1.3.4.2 tls
1172 1.3.4.2 tls static void
1173 1.3.4.2 tls axen_tick(void *xsc)
1174 1.3.4.2 tls {
1175 1.3.4.2 tls struct axen_softc *sc = xsc;
1176 1.3.4.2 tls
1177 1.3.4.2 tls if (sc == NULL)
1178 1.3.4.2 tls return;
1179 1.3.4.2 tls
1180 1.3.4.2 tls DPRINTFN(0xff,("%s: %s: enter\n", device_xname(sc->axen_dev),__func__));
1181 1.3.4.2 tls
1182 1.3.4.2 tls if (sc->axen_dying)
1183 1.3.4.2 tls return;
1184 1.3.4.2 tls
1185 1.3.4.2 tls /* Perform periodic stuff in process context */
1186 1.3.4.2 tls usb_add_task(sc->axen_udev, &sc->axen_tick_task, USB_TASKQ_DRIVER);
1187 1.3.4.2 tls }
1188 1.3.4.2 tls
1189 1.3.4.2 tls static void
1190 1.3.4.2 tls axen_tick_task(void *xsc)
1191 1.3.4.2 tls {
1192 1.3.4.2 tls int s;
1193 1.3.4.2 tls struct axen_softc *sc;
1194 1.3.4.2 tls struct ifnet *ifp;
1195 1.3.4.2 tls struct mii_data *mii;
1196 1.3.4.2 tls
1197 1.3.4.2 tls sc = xsc;
1198 1.3.4.2 tls
1199 1.3.4.2 tls if (sc == NULL)
1200 1.3.4.2 tls return;
1201 1.3.4.2 tls
1202 1.3.4.2 tls if (sc->axen_dying)
1203 1.3.4.2 tls return;
1204 1.3.4.2 tls
1205 1.3.4.2 tls ifp = GET_IFP(sc);
1206 1.3.4.2 tls mii = GET_MII(sc);
1207 1.3.4.2 tls if (mii == NULL)
1208 1.3.4.2 tls return;
1209 1.3.4.2 tls
1210 1.3.4.2 tls s = splnet();
1211 1.3.4.2 tls
1212 1.3.4.2 tls mii_tick(mii);
1213 1.3.4.2 tls if (sc->axen_link == 0 &&
1214 1.3.4.2 tls (mii->mii_media_status & IFM_ACTIVE) != 0 &&
1215 1.3.4.2 tls IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
1216 1.3.4.2 tls DPRINTF(("%s: %s: got link\n", device_xname(sc->axen_dev),
1217 1.3.4.2 tls __func__));
1218 1.3.4.2 tls sc->axen_link++;
1219 1.3.4.2 tls if (!IFQ_IS_EMPTY(&ifp->if_snd))
1220 1.3.4.2 tls axen_start(ifp);
1221 1.3.4.2 tls }
1222 1.3.4.2 tls
1223 1.3.4.2 tls callout_schedule(&sc->axen_stat_ch, hz);
1224 1.3.4.2 tls
1225 1.3.4.2 tls splx(s);
1226 1.3.4.2 tls }
1227 1.3.4.2 tls
1228 1.3.4.2 tls static int
1229 1.3.4.2 tls axen_encap(struct axen_softc *sc, struct mbuf *m, int idx)
1230 1.3.4.2 tls {
1231 1.3.4.2 tls struct ifnet *ifp = GET_IFP(sc);
1232 1.3.4.2 tls struct axen_chain *c;
1233 1.3.4.2 tls usbd_status err;
1234 1.3.4.2 tls struct axen_sframe_hdr hdr;
1235 1.3.4.2 tls int length, boundary;
1236 1.3.4.2 tls
1237 1.3.4.2 tls c = &sc->axen_cdata.axen_tx_chain[idx];
1238 1.3.4.2 tls
1239 1.3.4.2 tls boundary = (sc->axen_udev->speed == USB_SPEED_HIGH) ? 512 : 64;
1240 1.3.4.2 tls
1241 1.3.4.2 tls hdr.plen = htole32(m->m_pkthdr.len);
1242 1.3.4.2 tls hdr.gso = 0; /* disable segmentation offloading */
1243 1.3.4.2 tls
1244 1.3.4.2 tls memcpy(c->axen_buf, &hdr, sizeof(hdr));
1245 1.3.4.2 tls length = sizeof(hdr);
1246 1.3.4.2 tls
1247 1.3.4.2 tls m_copydata(m, 0, m->m_pkthdr.len, c->axen_buf + length);
1248 1.3.4.2 tls length += m->m_pkthdr.len;
1249 1.3.4.2 tls
1250 1.3.4.2 tls if ((length % boundary) == 0) {
1251 1.3.4.2 tls hdr.plen = 0x0;
1252 1.3.4.2 tls hdr.gso |= 0x80008000; /* enable padding */
1253 1.3.4.2 tls memcpy(c->axen_buf + length, &hdr, sizeof(hdr));
1254 1.3.4.2 tls length += sizeof(hdr);
1255 1.3.4.2 tls }
1256 1.3.4.2 tls
1257 1.3.4.2 tls usbd_setup_xfer(c->axen_xfer, sc->axen_ep[AXEN_ENDPT_TX],
1258 1.3.4.2 tls c, c->axen_buf, length, USBD_FORCE_SHORT_XFER | USBD_NO_COPY,
1259 1.3.4.2 tls 10000, axen_txeof);
1260 1.3.4.2 tls
1261 1.3.4.2 tls /* Transmit */
1262 1.3.4.2 tls err = usbd_transfer(c->axen_xfer);
1263 1.3.4.2 tls if (err != USBD_IN_PROGRESS) {
1264 1.3.4.2 tls axen_stop(ifp, 0);
1265 1.3.4.2 tls return EIO;
1266 1.3.4.2 tls }
1267 1.3.4.2 tls
1268 1.3.4.2 tls sc->axen_cdata.axen_tx_cnt++;
1269 1.3.4.2 tls
1270 1.3.4.2 tls return 0;
1271 1.3.4.2 tls }
1272 1.3.4.2 tls
1273 1.3.4.2 tls static void
1274 1.3.4.2 tls axen_start(struct ifnet *ifp)
1275 1.3.4.2 tls {
1276 1.3.4.2 tls struct axen_softc *sc;
1277 1.3.4.2 tls struct mbuf *m;
1278 1.3.4.2 tls
1279 1.3.4.2 tls sc = ifp->if_softc;
1280 1.3.4.2 tls
1281 1.3.4.2 tls if (sc->axen_link == 0)
1282 1.3.4.2 tls return;
1283 1.3.4.2 tls
1284 1.3.4.2 tls if ((ifp->if_flags & (IFF_OACTIVE|IFF_RUNNING)) != IFF_RUNNING)
1285 1.3.4.2 tls return;
1286 1.3.4.2 tls
1287 1.3.4.2 tls IFQ_POLL(&ifp->if_snd, m);
1288 1.3.4.2 tls if (m == NULL)
1289 1.3.4.2 tls return;
1290 1.3.4.2 tls
1291 1.3.4.2 tls if (axen_encap(sc, m, 0)) {
1292 1.3.4.2 tls ifp->if_flags |= IFF_OACTIVE;
1293 1.3.4.2 tls return;
1294 1.3.4.2 tls }
1295 1.3.4.2 tls IFQ_DEQUEUE(&ifp->if_snd, m);
1296 1.3.4.2 tls
1297 1.3.4.2 tls /*
1298 1.3.4.2 tls * If there's a BPF listener, bounce a copy of this frame
1299 1.3.4.2 tls * to him.
1300 1.3.4.2 tls */
1301 1.3.4.2 tls bpf_mtap(ifp, m);
1302 1.3.4.2 tls m_freem(m);
1303 1.3.4.2 tls
1304 1.3.4.2 tls ifp->if_flags |= IFF_OACTIVE;
1305 1.3.4.2 tls
1306 1.3.4.2 tls /*
1307 1.3.4.2 tls * Set a timeout in case the chip goes out to lunch.
1308 1.3.4.2 tls */
1309 1.3.4.2 tls ifp->if_timer = 5;
1310 1.3.4.2 tls }
1311 1.3.4.2 tls
1312 1.3.4.2 tls static int
1313 1.3.4.2 tls axen_init(struct ifnet *ifp)
1314 1.3.4.2 tls {
1315 1.3.4.2 tls struct axen_softc *sc = ifp->if_softc;
1316 1.3.4.2 tls struct axen_chain *c;
1317 1.3.4.2 tls usbd_status err;
1318 1.3.4.2 tls int i, s;
1319 1.3.4.2 tls uint16_t rxmode;
1320 1.3.4.2 tls uint16_t wval;
1321 1.3.4.2 tls uint8_t bval;
1322 1.3.4.2 tls
1323 1.3.4.2 tls s = splnet();
1324 1.3.4.2 tls
1325 1.3.4.2 tls if (ifp->if_flags & IFF_RUNNING)
1326 1.3.4.2 tls axen_stop(ifp, 0);
1327 1.3.4.2 tls
1328 1.3.4.2 tls /*
1329 1.3.4.2 tls * Cancel pending I/O and free all RX/TX buffers.
1330 1.3.4.2 tls */
1331 1.3.4.2 tls axen_reset(sc);
1332 1.3.4.2 tls
1333 1.3.4.2 tls /* XXX: ? */
1334 1.3.4.2 tls axen_lock_mii(sc);
1335 1.3.4.2 tls bval = 0x01;
1336 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE, 1, AXEN_UNK_28, &bval);
1337 1.3.4.2 tls axen_unlock_mii(sc);
1338 1.3.4.2 tls
1339 1.3.4.2 tls /* Init RX ring. */
1340 1.3.4.2 tls if (axen_rx_list_init(sc) == ENOBUFS) {
1341 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "rx list init failed\n");
1342 1.3.4.2 tls axen_unlock_mii(sc);
1343 1.3.4.2 tls splx(s);
1344 1.3.4.2 tls return ENOBUFS;
1345 1.3.4.2 tls }
1346 1.3.4.2 tls
1347 1.3.4.2 tls /* Init TX ring. */
1348 1.3.4.2 tls if (axen_tx_list_init(sc) == ENOBUFS) {
1349 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "tx list init failed\n");
1350 1.3.4.2 tls axen_unlock_mii(sc);
1351 1.3.4.2 tls splx(s);
1352 1.3.4.2 tls return ENOBUFS;
1353 1.3.4.2 tls }
1354 1.3.4.2 tls
1355 1.3.4.2 tls /* Program promiscuous mode and multicast filters. */
1356 1.3.4.2 tls axen_iff(sc);
1357 1.3.4.2 tls
1358 1.3.4.2 tls /* Enable receiver, set RX mode */
1359 1.3.4.2 tls axen_lock_mii(sc);
1360 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_READ2, 2, AXEN_MAC_RXCTL, &wval);
1361 1.3.4.2 tls rxmode = le16toh(wval);
1362 1.3.4.2 tls rxmode |= AXEN_RXCTL_START;
1363 1.3.4.2 tls wval = htole16(rxmode);
1364 1.3.4.2 tls axen_cmd(sc, AXEN_CMD_MAC_WRITE2, 2, AXEN_MAC_RXCTL, &wval);
1365 1.3.4.2 tls axen_unlock_mii(sc);
1366 1.3.4.2 tls
1367 1.3.4.2 tls /* Open RX and TX pipes. */
1368 1.3.4.2 tls err = usbd_open_pipe(sc->axen_iface, sc->axen_ed[AXEN_ENDPT_RX],
1369 1.3.4.2 tls USBD_EXCLUSIVE_USE, &sc->axen_ep[AXEN_ENDPT_RX]);
1370 1.3.4.2 tls if (err) {
1371 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "open rx pipe failed: %s\n",
1372 1.3.4.2 tls usbd_errstr(err));
1373 1.3.4.2 tls splx(s);
1374 1.3.4.2 tls return EIO;
1375 1.3.4.2 tls }
1376 1.3.4.2 tls
1377 1.3.4.2 tls err = usbd_open_pipe(sc->axen_iface, sc->axen_ed[AXEN_ENDPT_TX],
1378 1.3.4.2 tls USBD_EXCLUSIVE_USE, &sc->axen_ep[AXEN_ENDPT_TX]);
1379 1.3.4.2 tls if (err) {
1380 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "open tx pipe failed: %s\n",
1381 1.3.4.2 tls usbd_errstr(err));
1382 1.3.4.2 tls splx(s);
1383 1.3.4.2 tls return EIO;
1384 1.3.4.2 tls }
1385 1.3.4.2 tls
1386 1.3.4.2 tls /* Start up the receive pipe. */
1387 1.3.4.2 tls for (i = 0; i < AXEN_RX_LIST_CNT; i++) {
1388 1.3.4.2 tls c = &sc->axen_cdata.axen_rx_chain[i];
1389 1.3.4.2 tls usbd_setup_xfer(c->axen_xfer, sc->axen_ep[AXEN_ENDPT_RX],
1390 1.3.4.2 tls c, c->axen_buf, sc->axen_bufsz,
1391 1.3.4.2 tls USBD_SHORT_XFER_OK | USBD_NO_COPY,
1392 1.3.4.2 tls USBD_NO_TIMEOUT, axen_rxeof);
1393 1.3.4.2 tls usbd_transfer(c->axen_xfer);
1394 1.3.4.2 tls }
1395 1.3.4.2 tls
1396 1.3.4.2 tls ifp->if_flags |= IFF_RUNNING;
1397 1.3.4.2 tls ifp->if_flags &= ~IFF_OACTIVE;
1398 1.3.4.2 tls
1399 1.3.4.2 tls splx(s);
1400 1.3.4.2 tls
1401 1.3.4.2 tls callout_schedule(&sc->axen_stat_ch, hz);
1402 1.3.4.2 tls return 0;
1403 1.3.4.2 tls }
1404 1.3.4.2 tls
1405 1.3.4.2 tls static int
1406 1.3.4.2 tls axen_ioctl(struct ifnet *ifp, u_long cmd, void *data)
1407 1.3.4.2 tls {
1408 1.3.4.2 tls struct axen_softc *sc = ifp->if_softc;
1409 1.3.4.2 tls int s;
1410 1.3.4.2 tls int error = 0;
1411 1.3.4.2 tls
1412 1.3.4.2 tls s = splnet();
1413 1.3.4.2 tls
1414 1.3.4.2 tls switch (cmd) {
1415 1.3.4.2 tls case SIOCSIFFLAGS:
1416 1.3.4.2 tls if ((error = ifioctl_common(ifp, cmd, data)) != 0)
1417 1.3.4.2 tls break;
1418 1.3.4.2 tls
1419 1.3.4.2 tls switch (ifp->if_flags & (IFF_UP | IFF_RUNNING)) {
1420 1.3.4.2 tls case IFF_RUNNING:
1421 1.3.4.2 tls axen_stop(ifp, 1);
1422 1.3.4.2 tls break;
1423 1.3.4.2 tls case IFF_UP:
1424 1.3.4.2 tls axen_init(ifp);
1425 1.3.4.2 tls break;
1426 1.3.4.2 tls case IFF_UP | IFF_RUNNING:
1427 1.3.4.2 tls if ((ifp->if_flags ^ sc->axen_if_flags) == IFF_PROMISC)
1428 1.3.4.2 tls axen_iff(sc);
1429 1.3.4.2 tls else
1430 1.3.4.2 tls axen_init(ifp);
1431 1.3.4.2 tls break;
1432 1.3.4.2 tls }
1433 1.3.4.2 tls sc->axen_if_flags = ifp->if_flags;
1434 1.3.4.2 tls break;
1435 1.3.4.2 tls
1436 1.3.4.2 tls default:
1437 1.3.4.2 tls if ((error = ether_ioctl(ifp, cmd, data)) != ENETRESET)
1438 1.3.4.2 tls break;
1439 1.3.4.2 tls
1440 1.3.4.2 tls error = 0;
1441 1.3.4.2 tls
1442 1.3.4.2 tls if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI)
1443 1.3.4.2 tls axen_iff(sc);
1444 1.3.4.2 tls break;
1445 1.3.4.2 tls }
1446 1.3.4.2 tls splx(s);
1447 1.3.4.2 tls
1448 1.3.4.2 tls return error;
1449 1.3.4.2 tls }
1450 1.3.4.2 tls
1451 1.3.4.2 tls static void
1452 1.3.4.2 tls axen_watchdog(struct ifnet *ifp)
1453 1.3.4.2 tls {
1454 1.3.4.2 tls struct axen_softc *sc;
1455 1.3.4.2 tls struct axen_chain *c;
1456 1.3.4.2 tls usbd_status stat;
1457 1.3.4.2 tls int s;
1458 1.3.4.2 tls
1459 1.3.4.2 tls sc = ifp->if_softc;
1460 1.3.4.2 tls
1461 1.3.4.2 tls ifp->if_oerrors++;
1462 1.3.4.2 tls aprint_error_dev(sc->axen_dev, "watchdog timeout\n");
1463 1.3.4.2 tls
1464 1.3.4.2 tls s = splusb();
1465 1.3.4.2 tls c = &sc->axen_cdata.axen_tx_chain[0];
1466 1.3.4.2 tls usbd_get_xfer_status(c->axen_xfer, NULL, NULL, NULL, &stat);
1467 1.3.4.2 tls axen_txeof(c->axen_xfer, c, stat);
1468 1.3.4.2 tls
1469 1.3.4.2 tls if (!IFQ_IS_EMPTY(&ifp->if_snd))
1470 1.3.4.2 tls axen_start(ifp);
1471 1.3.4.2 tls splx(s);
1472 1.3.4.2 tls }
1473 1.3.4.2 tls
1474 1.3.4.2 tls /*
1475 1.3.4.2 tls * Stop the adapter and free any mbufs allocated to the
1476 1.3.4.2 tls * RX and TX lists.
1477 1.3.4.2 tls */
1478 1.3.4.2 tls static void
1479 1.3.4.2 tls axen_stop(struct ifnet *ifp, int disable)
1480 1.3.4.2 tls {
1481 1.3.4.2 tls struct axen_softc *sc = ifp->if_softc;
1482 1.3.4.2 tls usbd_status err;
1483 1.3.4.2 tls int i;
1484 1.3.4.2 tls
1485 1.3.4.2 tls axen_reset(sc);
1486 1.3.4.2 tls
1487 1.3.4.2 tls ifp->if_timer = 0;
1488 1.3.4.2 tls ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1489 1.3.4.2 tls
1490 1.3.4.2 tls callout_stop(&sc->axen_stat_ch);
1491 1.3.4.2 tls
1492 1.3.4.2 tls /* Stop transfers. */
1493 1.3.4.2 tls if (sc->axen_ep[AXEN_ENDPT_RX] != NULL) {
1494 1.3.4.2 tls err = usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_RX]);
1495 1.3.4.2 tls if (err) {
1496 1.3.4.2 tls aprint_error_dev(sc->axen_dev,
1497 1.3.4.2 tls "abort rx pipe failed: %s\n", usbd_errstr(err));
1498 1.3.4.2 tls
1499 1.3.4.2 tls }
1500 1.3.4.2 tls err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_RX]);
1501 1.3.4.2 tls if (err) {
1502 1.3.4.2 tls aprint_error_dev(sc->axen_dev,
1503 1.3.4.2 tls "close rx pipe failed: %s\n", usbd_errstr(err));
1504 1.3.4.2 tls }
1505 1.3.4.2 tls sc->axen_ep[AXEN_ENDPT_RX] = NULL;
1506 1.3.4.2 tls }
1507 1.3.4.2 tls
1508 1.3.4.2 tls if (sc->axen_ep[AXEN_ENDPT_TX] != NULL) {
1509 1.3.4.2 tls err = usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_TX]);
1510 1.3.4.2 tls if (err) {
1511 1.3.4.2 tls aprint_error_dev(sc->axen_dev,
1512 1.3.4.2 tls "abort tx pipe failed: %s\n", usbd_errstr(err));
1513 1.3.4.2 tls }
1514 1.3.4.2 tls err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_TX]);
1515 1.3.4.2 tls if (err) {
1516 1.3.4.2 tls aprint_error_dev(sc->axen_dev,
1517 1.3.4.2 tls "close tx pipe failed: %s\n", usbd_errstr(err));
1518 1.3.4.2 tls }
1519 1.3.4.2 tls sc->axen_ep[AXEN_ENDPT_TX] = NULL;
1520 1.3.4.2 tls }
1521 1.3.4.2 tls
1522 1.3.4.2 tls if (sc->axen_ep[AXEN_ENDPT_INTR] != NULL) {
1523 1.3.4.2 tls err = usbd_abort_pipe(sc->axen_ep[AXEN_ENDPT_INTR]);
1524 1.3.4.2 tls if (err) {
1525 1.3.4.2 tls aprint_error_dev(sc->axen_dev,
1526 1.3.4.2 tls "abort intr pipe failed: %s\n", usbd_errstr(err));
1527 1.3.4.2 tls }
1528 1.3.4.2 tls err = usbd_close_pipe(sc->axen_ep[AXEN_ENDPT_INTR]);
1529 1.3.4.2 tls if (err) {
1530 1.3.4.2 tls aprint_error_dev(sc->axen_dev,
1531 1.3.4.2 tls "close intr pipe failed: %s\n", usbd_errstr(err));
1532 1.3.4.2 tls }
1533 1.3.4.2 tls sc->axen_ep[AXEN_ENDPT_INTR] = NULL;
1534 1.3.4.2 tls }
1535 1.3.4.2 tls
1536 1.3.4.2 tls /* Free RX resources. */
1537 1.3.4.2 tls for (i = 0; i < AXEN_RX_LIST_CNT; i++) {
1538 1.3.4.2 tls if (sc->axen_cdata.axen_rx_chain[i].axen_xfer != NULL) {
1539 1.3.4.2 tls usbd_free_xfer(sc->axen_cdata.axen_rx_chain[i].axen_xfer);
1540 1.3.4.2 tls sc->axen_cdata.axen_rx_chain[i].axen_xfer = NULL;
1541 1.3.4.2 tls }
1542 1.3.4.2 tls }
1543 1.3.4.2 tls
1544 1.3.4.2 tls /* Free TX resources. */
1545 1.3.4.2 tls for (i = 0; i < AXEN_TX_LIST_CNT; i++) {
1546 1.3.4.2 tls if (sc->axen_cdata.axen_tx_chain[i].axen_xfer != NULL) {
1547 1.3.4.2 tls usbd_free_xfer(sc->axen_cdata.axen_tx_chain[i].axen_xfer);
1548 1.3.4.2 tls sc->axen_cdata.axen_tx_chain[i].axen_xfer = NULL;
1549 1.3.4.2 tls }
1550 1.3.4.2 tls }
1551 1.3.4.2 tls
1552 1.3.4.2 tls sc->axen_link = 0;
1553 1.3.4.2 tls }
1554 1.3.4.2 tls
1555 1.3.4.2 tls MODULE(MODULE_CLASS_DRIVER, if_axen, "bpf");
1556 1.3.4.2 tls
1557 1.3.4.2 tls #ifdef _MODULE
1558 1.3.4.2 tls #include "ioconf.c"
1559 1.3.4.2 tls #endif
1560 1.3.4.2 tls
1561 1.3.4.2 tls static int
1562 1.3.4.2 tls if_axen_modcmd(modcmd_t cmd, void *aux)
1563 1.3.4.2 tls {
1564 1.3.4.2 tls int error = 0;
1565 1.3.4.2 tls
1566 1.3.4.2 tls switch (cmd) {
1567 1.3.4.2 tls case MODULE_CMD_INIT:
1568 1.3.4.2 tls #ifdef _MODULE
1569 1.3.4.2 tls error = config_init_component(cfdriver_ioconf_axen,
1570 1.3.4.2 tls cfattach_ioconf_axen, cfdata_ioconf_axen);
1571 1.3.4.2 tls #endif
1572 1.3.4.2 tls return error;
1573 1.3.4.2 tls case MODULE_CMD_FINI:
1574 1.3.4.2 tls #ifdef _MODULE
1575 1.3.4.2 tls error = config_fini_component(cfdriver_ioconf_axen,
1576 1.3.4.2 tls cfattach_ioconf_axen, cfdata_ioconf_axen);
1577 1.3.4.2 tls #endif
1578 1.3.4.2 tls return error;
1579 1.3.4.2 tls default:
1580 1.3.4.2 tls return ENOTTY;
1581 1.3.4.2 tls }
1582 1.3.4.2 tls }
1583