1da089c14SMark Johnston /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni *
461c067adSKevin Lo * Copyright (c) 2013-2014 Kevin Lo
5da089c14SMark Johnston * All rights reserved.
6da089c14SMark Johnston *
7da089c14SMark Johnston * Redistribution and use in source and binary forms, with or without
8da089c14SMark Johnston * modification, are permitted provided that the following conditions
9da089c14SMark Johnston * are met:
10da089c14SMark Johnston * 1. Redistributions of source code must retain the above copyright
11da089c14SMark Johnston * notice, this list of conditions and the following disclaimer.
12da089c14SMark Johnston * 2. Redistributions in binary form must reproduce the above copyright
13da089c14SMark Johnston * notice, this list of conditions and the following disclaimer in the
14da089c14SMark Johnston * documentation and/or other materials provided with the distribution.
15da089c14SMark Johnston *
16da089c14SMark Johnston * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17da089c14SMark Johnston * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18da089c14SMark Johnston * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19da089c14SMark Johnston * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20da089c14SMark Johnston * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21da089c14SMark Johnston * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22da089c14SMark Johnston * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23da089c14SMark Johnston * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24da089c14SMark Johnston * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25da089c14SMark Johnston * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26da089c14SMark Johnston * SUCH DAMAGE.
27da089c14SMark Johnston */
28da089c14SMark Johnston
29da089c14SMark Johnston #include <sys/cdefs.h>
30da089c14SMark Johnston /*
31*6962da91SDamien Broka * ASIX Electronics AX88178A/AX88179/AX88179A USB 2.0/3.0 gigabit ethernet
32*6962da91SDamien Broka * driver.
33da089c14SMark Johnston */
34da089c14SMark Johnston
35da089c14SMark Johnston #include <sys/param.h>
36da089c14SMark Johnston #include <sys/systm.h>
37da089c14SMark Johnston #include <sys/bus.h>
38da089c14SMark Johnston #include <sys/condvar.h>
397c10cf8cSPyun YongHyeon #include <sys/endian.h>
40da089c14SMark Johnston #include <sys/kernel.h>
41da089c14SMark Johnston #include <sys/lock.h>
42da089c14SMark Johnston #include <sys/module.h>
43da089c14SMark Johnston #include <sys/mutex.h>
44da089c14SMark Johnston #include <sys/socket.h>
45da089c14SMark Johnston #include <sys/sysctl.h>
46da089c14SMark Johnston #include <sys/unistd.h>
47da089c14SMark Johnston
48da089c14SMark Johnston #include <net/if.h>
49da089c14SMark Johnston #include <net/if_var.h>
5031c484adSJustin Hibbits #include <net/if_media.h>
5131c484adSJustin Hibbits
5231c484adSJustin Hibbits #include <dev/mii/mii.h>
5331c484adSJustin Hibbits #include <dev/mii/miivar.h>
54da089c14SMark Johnston
55da089c14SMark Johnston #include <dev/usb/usb.h>
56da089c14SMark Johnston #include <dev/usb/usbdi.h>
57da089c14SMark Johnston #include <dev/usb/usbdi_util.h>
58da089c14SMark Johnston #include "usbdevs.h"
59da089c14SMark Johnston
60da089c14SMark Johnston #define USB_DEBUG_VAR axge_debug
61da089c14SMark Johnston #include <dev/usb/usb_debug.h>
62da089c14SMark Johnston #include <dev/usb/usb_process.h>
63da089c14SMark Johnston
64da089c14SMark Johnston #include <dev/usb/net/usb_ethernet.h>
65da089c14SMark Johnston #include <dev/usb/net/if_axgereg.h>
66da089c14SMark Johnston
6731c484adSJustin Hibbits #include "miibus_if.h"
6831c484adSJustin Hibbits
69da089c14SMark Johnston /*
70da089c14SMark Johnston * Various supported device vendors/products.
71da089c14SMark Johnston */
72da089c14SMark Johnston
73da089c14SMark Johnston static const STRUCT_USB_HOST_ID axge_devs[] = {
74*6962da91SDamien Broka #define AXGE_DEV(v,p,i,...) \
75*6962da91SDamien Broka { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i), __VA_ARGS__ }
76*6962da91SDamien Broka AXGE_DEV(ASIX, AX88178A, AXGE_FLAG_178A),
77*6962da91SDamien Broka AXGE_DEV(ASIX, AX88179, AXGE_FLAG_179, USB_DEV_BCD_LTEQ(0x0100)),
78*6962da91SDamien Broka AXGE_DEV(ASIX, AX88179, AXGE_FLAG_179A, USB_DEV_BCD_GTEQ(0x0200)),
79*6962da91SDamien Broka AXGE_DEV(BELKIN, B2B128, AXGE_FLAG_179),
80*6962da91SDamien Broka AXGE_DEV(DLINK, DUB1312, AXGE_FLAG_179),
81*6962da91SDamien Broka AXGE_DEV(LENOVO, GIGALAN, AXGE_FLAG_179),
82*6962da91SDamien Broka AXGE_DEV(SITECOMEU, LN032, AXGE_FLAG_179),
83da089c14SMark Johnston #undef AXGE_DEV
84da089c14SMark Johnston };
85da089c14SMark Johnston
86da089c14SMark Johnston static const struct {
8761c067adSKevin Lo uint8_t ctrl;
8861c067adSKevin Lo uint8_t timer_l;
8961c067adSKevin Lo uint8_t timer_h;
9061c067adSKevin Lo uint8_t size;
9161c067adSKevin Lo uint8_t ifg;
92948d799eSHans Petter Selasky } __packed axge_bulk_size[] = {
9361c067adSKevin Lo { 7, 0x4f, 0x00, 0x12, 0xff },
9461c067adSKevin Lo { 7, 0x20, 0x03, 0x16, 0xff },
9561c067adSKevin Lo { 7, 0xae, 0x07, 0x18, 0xff },
9661c067adSKevin Lo { 7, 0xcc, 0x4c, 0x18, 0x08 }
97da089c14SMark Johnston };
98da089c14SMark Johnston
99da089c14SMark Johnston /* prototypes */
100da089c14SMark Johnston
101da089c14SMark Johnston static device_probe_t axge_probe;
102da089c14SMark Johnston static device_attach_t axge_attach;
103da089c14SMark Johnston static device_detach_t axge_detach;
104da089c14SMark Johnston
105da089c14SMark Johnston static usb_callback_t axge_bulk_read_callback;
106da089c14SMark Johnston static usb_callback_t axge_bulk_write_callback;
107da089c14SMark Johnston
108da089c14SMark Johnston static miibus_readreg_t axge_miibus_readreg;
109da089c14SMark Johnston static miibus_writereg_t axge_miibus_writereg;
110da089c14SMark Johnston static miibus_statchg_t axge_miibus_statchg;
111da089c14SMark Johnston
112da089c14SMark Johnston static uether_fn_t axge_attach_post;
113da089c14SMark Johnston static uether_fn_t axge_init;
114da089c14SMark Johnston static uether_fn_t axge_stop;
115da089c14SMark Johnston static uether_fn_t axge_start;
116da089c14SMark Johnston static uether_fn_t axge_tick;
117a5d82655SPyun YongHyeon static uether_fn_t axge_rxfilter;
118da089c14SMark Johnston
119da089c14SMark Johnston static int axge_read_mem(struct axge_softc *, uint8_t, uint16_t,
120da089c14SMark Johnston uint16_t, void *, int);
121da089c14SMark Johnston static void axge_write_mem(struct axge_softc *, uint8_t, uint16_t,
122da089c14SMark Johnston uint16_t, void *, int);
123d32048bbSKevin Lo static uint8_t axge_read_cmd_1(struct axge_softc *, uint8_t, uint16_t);
124da089c14SMark Johnston static uint16_t axge_read_cmd_2(struct axge_softc *, uint8_t, uint16_t,
125da089c14SMark Johnston uint16_t);
126da089c14SMark Johnston static void axge_write_cmd_1(struct axge_softc *, uint8_t, uint16_t,
127d32048bbSKevin Lo uint8_t);
128da089c14SMark Johnston static void axge_write_cmd_2(struct axge_softc *, uint8_t, uint16_t,
129da089c14SMark Johnston uint16_t, uint16_t);
130da089c14SMark Johnston static void axge_chip_init(struct axge_softc *);
131da089c14SMark Johnston static void axge_reset(struct axge_softc *);
132da089c14SMark Johnston
133da089c14SMark Johnston static int axge_attach_post_sub(struct usb_ether *);
134935b194dSJustin Hibbits static int axge_ifmedia_upd(if_t);
135935b194dSJustin Hibbits static void axge_ifmedia_sts(if_t, struct ifmediareq *);
136935b194dSJustin Hibbits static int axge_ioctl(if_t, u_long, caddr_t);
1372110950bSHans Petter Selasky static void axge_rx_frame(struct usb_ether *, struct usb_page_cache *, int);
1382110950bSHans Petter Selasky static void axge_rxeof(struct usb_ether *, struct usb_page_cache *,
13962d42655SHans Petter Selasky unsigned, unsigned, uint32_t);
140da089c14SMark Johnston static void axge_csum_cfg(struct usb_ether *);
141da089c14SMark Johnston
142da089c14SMark Johnston #define AXGE_CSUM_FEATURES (CSUM_IP | CSUM_TCP | CSUM_UDP)
143da089c14SMark Johnston
144da089c14SMark Johnston #ifdef USB_DEBUG
145da089c14SMark Johnston static int axge_debug = 0;
146da089c14SMark Johnston
147f8d2b1f3SPawel Biernacki static SYSCTL_NODE(_hw_usb, OID_AUTO, axge, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
148f8d2b1f3SPawel Biernacki "USB axge");
149ece4b0bdSHans Petter Selasky SYSCTL_INT(_hw_usb_axge, OID_AUTO, debug, CTLFLAG_RWTUN, &axge_debug, 0,
150da089c14SMark Johnston "Debug level");
151da089c14SMark Johnston #endif
152da089c14SMark Johnston
153da089c14SMark Johnston static const struct usb_config axge_config[AXGE_N_TRANSFER] = {
154da089c14SMark Johnston [AXGE_BULK_DT_WR] = {
155da089c14SMark Johnston .type = UE_BULK,
156da089c14SMark Johnston .endpoint = UE_ADDR_ANY,
157da089c14SMark Johnston .direction = UE_DIR_OUT,
1587c10cf8cSPyun YongHyeon .frames = AXGE_N_FRAMES,
1597c10cf8cSPyun YongHyeon .bufsize = AXGE_N_FRAMES * MCLBYTES,
160da089c14SMark Johnston .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
161da089c14SMark Johnston .callback = axge_bulk_write_callback,
162da089c14SMark Johnston .timeout = 10000, /* 10 seconds */
163da089c14SMark Johnston },
164da089c14SMark Johnston [AXGE_BULK_DT_RD] = {
165da089c14SMark Johnston .type = UE_BULK,
166da089c14SMark Johnston .endpoint = UE_ADDR_ANY,
167da089c14SMark Johnston .direction = UE_DIR_IN,
168948d799eSHans Petter Selasky .bufsize = 65536,
169da089c14SMark Johnston .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
170da089c14SMark Johnston .callback = axge_bulk_read_callback,
171da089c14SMark Johnston .timeout = 0, /* no timeout */
172da089c14SMark Johnston },
173da089c14SMark Johnston };
174da089c14SMark Johnston
175da089c14SMark Johnston static device_method_t axge_methods[] = {
176da089c14SMark Johnston /* Device interface. */
177da089c14SMark Johnston DEVMETHOD(device_probe, axge_probe),
178da089c14SMark Johnston DEVMETHOD(device_attach, axge_attach),
179da089c14SMark Johnston DEVMETHOD(device_detach, axge_detach),
180da089c14SMark Johnston
181da089c14SMark Johnston /* MII interface. */
182da089c14SMark Johnston DEVMETHOD(miibus_readreg, axge_miibus_readreg),
183da089c14SMark Johnston DEVMETHOD(miibus_writereg, axge_miibus_writereg),
184da089c14SMark Johnston DEVMETHOD(miibus_statchg, axge_miibus_statchg),
185da089c14SMark Johnston
186da089c14SMark Johnston DEVMETHOD_END
187da089c14SMark Johnston };
188da089c14SMark Johnston
189da089c14SMark Johnston static driver_t axge_driver = {
190da089c14SMark Johnston .name = "axge",
191da089c14SMark Johnston .methods = axge_methods,
192da089c14SMark Johnston .size = sizeof(struct axge_softc),
193da089c14SMark Johnston };
194da089c14SMark Johnston
195bc9372d7SJohn Baldwin DRIVER_MODULE(axge, uhub, axge_driver, NULL, NULL);
1963e38757dSJohn Baldwin DRIVER_MODULE(miibus, axge, miibus_driver, NULL, NULL);
197da089c14SMark Johnston MODULE_DEPEND(axge, uether, 1, 1, 1);
198da089c14SMark Johnston MODULE_DEPEND(axge, usb, 1, 1, 1);
199da089c14SMark Johnston MODULE_DEPEND(axge, ether, 1, 1, 1);
200da089c14SMark Johnston MODULE_DEPEND(axge, miibus, 1, 1, 1);
201da089c14SMark Johnston MODULE_VERSION(axge, 1);
202f809f280SWarner Losh USB_PNP_HOST_INFO(axge_devs);
203da089c14SMark Johnston
204da089c14SMark Johnston static const struct usb_ether_methods axge_ue_methods = {
205da089c14SMark Johnston .ue_attach_post = axge_attach_post,
206da089c14SMark Johnston .ue_attach_post_sub = axge_attach_post_sub,
207da089c14SMark Johnston .ue_start = axge_start,
208da089c14SMark Johnston .ue_init = axge_init,
209da089c14SMark Johnston .ue_stop = axge_stop,
210da089c14SMark Johnston .ue_tick = axge_tick,
211a5d82655SPyun YongHyeon .ue_setmulti = axge_rxfilter,
212a5d82655SPyun YongHyeon .ue_setpromisc = axge_rxfilter,
213da089c14SMark Johnston .ue_mii_upd = axge_ifmedia_upd,
214da089c14SMark Johnston .ue_mii_sts = axge_ifmedia_sts,
215da089c14SMark Johnston };
216da089c14SMark Johnston
217da089c14SMark Johnston static int
axge_read_mem(struct axge_softc * sc,uint8_t cmd,uint16_t index,uint16_t val,void * buf,int len)218da089c14SMark Johnston axge_read_mem(struct axge_softc *sc, uint8_t cmd, uint16_t index,
219da089c14SMark Johnston uint16_t val, void *buf, int len)
220da089c14SMark Johnston {
221da089c14SMark Johnston struct usb_device_request req;
222da089c14SMark Johnston
223da089c14SMark Johnston AXGE_LOCK_ASSERT(sc, MA_OWNED);
224da089c14SMark Johnston
225da089c14SMark Johnston req.bmRequestType = UT_READ_VENDOR_DEVICE;
226da089c14SMark Johnston req.bRequest = cmd;
227da089c14SMark Johnston USETW(req.wValue, val);
228da089c14SMark Johnston USETW(req.wIndex, index);
229da089c14SMark Johnston USETW(req.wLength, len);
230da089c14SMark Johnston
231da089c14SMark Johnston return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
232da089c14SMark Johnston }
233da089c14SMark Johnston
234da089c14SMark Johnston static void
axge_write_mem(struct axge_softc * sc,uint8_t cmd,uint16_t index,uint16_t val,void * buf,int len)235da089c14SMark Johnston axge_write_mem(struct axge_softc *sc, uint8_t cmd, uint16_t index,
236da089c14SMark Johnston uint16_t val, void *buf, int len)
237da089c14SMark Johnston {
238da089c14SMark Johnston struct usb_device_request req;
239da089c14SMark Johnston
240da089c14SMark Johnston AXGE_LOCK_ASSERT(sc, MA_OWNED);
241da089c14SMark Johnston
242da089c14SMark Johnston req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
243da089c14SMark Johnston req.bRequest = cmd;
244da089c14SMark Johnston USETW(req.wValue, val);
245da089c14SMark Johnston USETW(req.wIndex, index);
246da089c14SMark Johnston USETW(req.wLength, len);
247da089c14SMark Johnston
248da089c14SMark Johnston if (uether_do_request(&sc->sc_ue, &req, buf, 1000)) {
249da089c14SMark Johnston /* Error ignored. */
250da089c14SMark Johnston }
251da089c14SMark Johnston }
252da089c14SMark Johnston
25361c067adSKevin Lo static uint8_t
axge_read_cmd_1(struct axge_softc * sc,uint8_t cmd,uint16_t reg)254d32048bbSKevin Lo axge_read_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg)
25561c067adSKevin Lo {
25661c067adSKevin Lo uint8_t val;
25761c067adSKevin Lo
258d32048bbSKevin Lo axge_read_mem(sc, cmd, 1, reg, &val, 1);
25961c067adSKevin Lo return (val);
26061c067adSKevin Lo }
26161c067adSKevin Lo
262da089c14SMark Johnston static uint16_t
axge_read_cmd_2(struct axge_softc * sc,uint8_t cmd,uint16_t index,uint16_t reg)263da089c14SMark Johnston axge_read_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index,
264da089c14SMark Johnston uint16_t reg)
265da089c14SMark Johnston {
266da089c14SMark Johnston uint8_t val[2];
267da089c14SMark Johnston
268da089c14SMark Johnston axge_read_mem(sc, cmd, index, reg, &val, 2);
269da089c14SMark Johnston return (UGETW(val));
270da089c14SMark Johnston }
271da089c14SMark Johnston
272da089c14SMark Johnston static void
axge_write_cmd_1(struct axge_softc * sc,uint8_t cmd,uint16_t reg,uint8_t val)273d32048bbSKevin Lo axge_write_cmd_1(struct axge_softc *sc, uint8_t cmd, uint16_t reg, uint8_t val)
274da089c14SMark Johnston {
275d32048bbSKevin Lo axge_write_mem(sc, cmd, 1, reg, &val, 1);
276da089c14SMark Johnston }
277da089c14SMark Johnston
278da089c14SMark Johnston static void
axge_write_cmd_2(struct axge_softc * sc,uint8_t cmd,uint16_t index,uint16_t reg,uint16_t val)279da089c14SMark Johnston axge_write_cmd_2(struct axge_softc *sc, uint8_t cmd, uint16_t index,
280da089c14SMark Johnston uint16_t reg, uint16_t val)
281da089c14SMark Johnston {
282da089c14SMark Johnston uint8_t temp[2];
283da089c14SMark Johnston
284da089c14SMark Johnston USETW(temp, val);
285da089c14SMark Johnston axge_write_mem(sc, cmd, index, reg, &temp, 2);
286da089c14SMark Johnston }
287da089c14SMark Johnston
288da089c14SMark Johnston static int
axge_miibus_readreg(device_t dev,int phy,int reg)289da089c14SMark Johnston axge_miibus_readreg(device_t dev, int phy, int reg)
290da089c14SMark Johnston {
291da089c14SMark Johnston struct axge_softc *sc;
292da089c14SMark Johnston uint16_t val;
293da089c14SMark Johnston int locked;
294da089c14SMark Johnston
295da089c14SMark Johnston sc = device_get_softc(dev);
296da089c14SMark Johnston locked = mtx_owned(&sc->sc_mtx);
297da089c14SMark Johnston if (!locked)
298da089c14SMark Johnston AXGE_LOCK(sc);
299da089c14SMark Johnston
300da089c14SMark Johnston val = axge_read_cmd_2(sc, AXGE_ACCESS_PHY, reg, phy);
301da089c14SMark Johnston
302da089c14SMark Johnston if (!locked)
303da089c14SMark Johnston AXGE_UNLOCK(sc);
304da089c14SMark Johnston
305da089c14SMark Johnston return (val);
306da089c14SMark Johnston }
307da089c14SMark Johnston
308da089c14SMark Johnston static int
axge_miibus_writereg(device_t dev,int phy,int reg,int val)309da089c14SMark Johnston axge_miibus_writereg(device_t dev, int phy, int reg, int val)
310da089c14SMark Johnston {
311da089c14SMark Johnston struct axge_softc *sc;
312da089c14SMark Johnston int locked;
313da089c14SMark Johnston
314da089c14SMark Johnston sc = device_get_softc(dev);
315da089c14SMark Johnston locked = mtx_owned(&sc->sc_mtx);
316da089c14SMark Johnston if (!locked)
317da089c14SMark Johnston AXGE_LOCK(sc);
318da089c14SMark Johnston
319da089c14SMark Johnston axge_write_cmd_2(sc, AXGE_ACCESS_PHY, reg, phy, val);
320da089c14SMark Johnston
321da089c14SMark Johnston if (!locked)
322da089c14SMark Johnston AXGE_UNLOCK(sc);
323da089c14SMark Johnston
324da089c14SMark Johnston return (0);
325da089c14SMark Johnston }
326da089c14SMark Johnston
327da089c14SMark Johnston static void
axge_miibus_statchg(device_t dev)328da089c14SMark Johnston axge_miibus_statchg(device_t dev)
329da089c14SMark Johnston {
330da089c14SMark Johnston struct axge_softc *sc;
331da089c14SMark Johnston struct mii_data *mii;
332935b194dSJustin Hibbits if_t ifp;
33361c067adSKevin Lo uint8_t link_status, tmp[5];
334da089c14SMark Johnston uint16_t val;
335da089c14SMark Johnston int locked;
336da089c14SMark Johnston
337da089c14SMark Johnston sc = device_get_softc(dev);
338da089c14SMark Johnston mii = GET_MII(sc);
339da089c14SMark Johnston locked = mtx_owned(&sc->sc_mtx);
340da089c14SMark Johnston if (!locked)
341da089c14SMark Johnston AXGE_LOCK(sc);
342da089c14SMark Johnston
343da089c14SMark Johnston ifp = uether_getifp(&sc->sc_ue);
344da089c14SMark Johnston if (mii == NULL || ifp == NULL ||
345935b194dSJustin Hibbits (if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
346da089c14SMark Johnston goto done;
347da089c14SMark Johnston
348da089c14SMark Johnston sc->sc_flags &= ~AXGE_FLAG_LINK;
349da089c14SMark Johnston if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
350da089c14SMark Johnston (IFM_ACTIVE | IFM_AVALID)) {
351da089c14SMark Johnston switch (IFM_SUBTYPE(mii->mii_media_active)) {
352da089c14SMark Johnston case IFM_10_T:
353da089c14SMark Johnston case IFM_100_TX:
354da089c14SMark Johnston case IFM_1000_T:
355da089c14SMark Johnston sc->sc_flags |= AXGE_FLAG_LINK;
356da089c14SMark Johnston break;
357da089c14SMark Johnston default:
358da089c14SMark Johnston break;
359da089c14SMark Johnston }
360da089c14SMark Johnston }
361da089c14SMark Johnston
362da089c14SMark Johnston /* Lost link, do nothing. */
363da089c14SMark Johnston if ((sc->sc_flags & AXGE_FLAG_LINK) == 0)
364da089c14SMark Johnston goto done;
365da089c14SMark Johnston
366d32048bbSKevin Lo link_status = axge_read_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PLSR);
36761c067adSKevin Lo
368da089c14SMark Johnston val = 0;
369da089c14SMark Johnston if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
370d32048bbSKevin Lo val |= MSR_FD;
371da089c14SMark Johnston if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0)
372d32048bbSKevin Lo val |= MSR_TFC;
373da089c14SMark Johnston if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0)
374d32048bbSKevin Lo val |= MSR_RFC;
375da089c14SMark Johnston }
376d32048bbSKevin Lo val |= MSR_RE;
377da089c14SMark Johnston switch (IFM_SUBTYPE(mii->mii_media_active)) {
378da089c14SMark Johnston case IFM_1000_T:
379d32048bbSKevin Lo val |= MSR_GM | MSR_EN_125MHZ;
380d32048bbSKevin Lo if (link_status & PLSR_USB_SS)
38161c067adSKevin Lo memcpy(tmp, &axge_bulk_size[0], 5);
382d32048bbSKevin Lo else if (link_status & PLSR_USB_HS)
38361c067adSKevin Lo memcpy(tmp, &axge_bulk_size[1], 5);
38461c067adSKevin Lo else
38561c067adSKevin Lo memcpy(tmp, &axge_bulk_size[3], 5);
38661c067adSKevin Lo break;
387da089c14SMark Johnston case IFM_100_TX:
388d32048bbSKevin Lo val |= MSR_PS;
389d32048bbSKevin Lo if (link_status & (PLSR_USB_SS | PLSR_USB_HS))
39061c067adSKevin Lo memcpy(tmp, &axge_bulk_size[2], 5);
39161c067adSKevin Lo else
39261c067adSKevin Lo memcpy(tmp, &axge_bulk_size[3], 5);
39361c067adSKevin Lo break;
394da089c14SMark Johnston case IFM_10_T:
39561c067adSKevin Lo memcpy(tmp, &axge_bulk_size[3], 5);
396da089c14SMark Johnston break;
397da089c14SMark Johnston }
39861c067adSKevin Lo /* Rx bulk configuration. */
39961c067adSKevin Lo axge_write_mem(sc, AXGE_ACCESS_MAC, 5, AXGE_RX_BULKIN_QCTRL, tmp, 5);
400d32048bbSKevin Lo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_MSR, val);
401da089c14SMark Johnston done:
402da089c14SMark Johnston if (!locked)
403da089c14SMark Johnston AXGE_UNLOCK(sc);
404da089c14SMark Johnston }
405da089c14SMark Johnston
406da089c14SMark Johnston static void
axge_chip_init(struct axge_softc * sc)407da089c14SMark Johnston axge_chip_init(struct axge_softc *sc)
408da089c14SMark Johnston {
409da089c14SMark Johnston /* Power up ethernet PHY. */
410d32048bbSKevin Lo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, 0);
411d32048bbSKevin Lo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, EPPRCR_IPRL);
412da089c14SMark Johnston uether_pause(&sc->sc_ue, hz / 4);
413d32048bbSKevin Lo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CLK_SELECT,
414da089c14SMark Johnston AXGE_CLK_SELECT_ACS | AXGE_CLK_SELECT_BCS);
415da089c14SMark Johnston uether_pause(&sc->sc_ue, hz / 10);
416*6962da91SDamien Broka
417*6962da91SDamien Broka if ((sc->sc_flags & AXGE_FLAG_179A) != 0) {
418*6962da91SDamien Broka /*
419*6962da91SDamien Broka * 179A chip has two firmware modes that each use different
420*6962da91SDamien Broka * transfer layouts for Ethernet over USB. The newer fw mode has
421*6962da91SDamien Broka * larger rx packet headers which seem to
422*6962da91SDamien Broka * accomodate for ethernet frames up to 9K length and a VLAN
423*6962da91SDamien Broka * field for hardware tagging, but is not backward compatible
424*6962da91SDamien Broka * with 178A/179 bulk transfer code due to the change in size
425*6962da91SDamien Broka * and field alignments. The other fw mode uses the same packet
426*6962da91SDamien Broka * headers as the older 178A/179 chips, which this driver uses.
427*6962da91SDamien Broka *
428*6962da91SDamien Broka * As we do not currently have VLAN hw tagging or jumbo support
429*6962da91SDamien Broka * in this driver anyway, we're ok forcing 179A into its compat
430*6962da91SDamien Broka * mode by default.
431*6962da91SDamien Broka */
432*6962da91SDamien Broka axge_write_cmd_1(sc, AXGE_FW_MODE, AXGE_FW_MODE_178A179, 0);
433*6962da91SDamien Broka }
434da089c14SMark Johnston }
435da089c14SMark Johnston
436da089c14SMark Johnston static void
axge_reset(struct axge_softc * sc)437da089c14SMark Johnston axge_reset(struct axge_softc *sc)
438da089c14SMark Johnston {
439da089c14SMark Johnston struct usb_config_descriptor *cd;
440da089c14SMark Johnston usb_error_t err;
441da089c14SMark Johnston
442da089c14SMark Johnston cd = usbd_get_config_descriptor(sc->sc_ue.ue_udev);
443da089c14SMark Johnston
444da089c14SMark Johnston err = usbd_req_set_config(sc->sc_ue.ue_udev, &sc->sc_mtx,
445da089c14SMark Johnston cd->bConfigurationValue);
446da089c14SMark Johnston if (err)
447da089c14SMark Johnston DPRINTF("reset failed (ignored)\n");
448da089c14SMark Johnston
449da089c14SMark Johnston /* Wait a little while for the chip to get its brains in order. */
450da089c14SMark Johnston uether_pause(&sc->sc_ue, hz / 100);
451da089c14SMark Johnston
452da089c14SMark Johnston /* Reinitialize controller to achieve full reset. */
453da089c14SMark Johnston axge_chip_init(sc);
454da089c14SMark Johnston }
455da089c14SMark Johnston
456da089c14SMark Johnston static void
axge_attach_post(struct usb_ether * ue)457da089c14SMark Johnston axge_attach_post(struct usb_ether *ue)
458da089c14SMark Johnston {
459da089c14SMark Johnston struct axge_softc *sc;
460da089c14SMark Johnston
461da089c14SMark Johnston sc = uether_getsc(ue);
462da089c14SMark Johnston
463da089c14SMark Johnston /* Initialize controller and get station address. */
464da089c14SMark Johnston axge_chip_init(sc);
465d32048bbSKevin Lo axge_read_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NIDR,
466da089c14SMark Johnston ue->ue_eaddr, ETHER_ADDR_LEN);
467da089c14SMark Johnston }
468da089c14SMark Johnston
469da089c14SMark Johnston static int
axge_attach_post_sub(struct usb_ether * ue)470da089c14SMark Johnston axge_attach_post_sub(struct usb_ether *ue)
471da089c14SMark Johnston {
472935b194dSJustin Hibbits if_t ifp;
473da089c14SMark Johnston int error;
474da089c14SMark Johnston
475da089c14SMark Johnston ifp = ue->ue_ifp;
476935b194dSJustin Hibbits if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
477935b194dSJustin Hibbits if_setstartfn(ifp, uether_start);
478935b194dSJustin Hibbits if_setioctlfn(ifp, axge_ioctl);
479935b194dSJustin Hibbits if_setinitfn(ifp, uether_init);
480935b194dSJustin Hibbits if_setsendqlen(ifp, ifqmaxlen);
481935b194dSJustin Hibbits if_setsendqready(ifp);
482da089c14SMark Johnston
483935b194dSJustin Hibbits if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU | IFCAP_TXCSUM | IFCAP_RXCSUM, 0);
484935b194dSJustin Hibbits if_sethwassist(ifp, AXGE_CSUM_FEATURES);
485935b194dSJustin Hibbits if_setcapenable(ifp, if_getcapabilities(ifp));
486da089c14SMark Johnston
487c6df6f53SWarner Losh bus_topo_lock();
488da089c14SMark Johnston error = mii_attach(ue->ue_dev, &ue->ue_miibus, ifp,
489da089c14SMark Johnston uether_ifmedia_upd, ue->ue_methods->ue_mii_sts,
490a42c5d9fSPyun YongHyeon BMSR_DEFCAPMASK, AXGE_PHY_ADDR, MII_OFFSET_ANY, MIIF_DOPAUSE);
491c6df6f53SWarner Losh bus_topo_unlock();
492da089c14SMark Johnston
493da089c14SMark Johnston return (error);
494da089c14SMark Johnston }
495da089c14SMark Johnston
496da089c14SMark Johnston /*
497da089c14SMark Johnston * Set media options.
498da089c14SMark Johnston */
499da089c14SMark Johnston static int
axge_ifmedia_upd(if_t ifp)500935b194dSJustin Hibbits axge_ifmedia_upd(if_t ifp)
501da089c14SMark Johnston {
502da089c14SMark Johnston struct axge_softc *sc;
503da089c14SMark Johnston struct mii_data *mii;
504da089c14SMark Johnston struct mii_softc *miisc;
505da089c14SMark Johnston int error;
506da089c14SMark Johnston
507935b194dSJustin Hibbits sc = if_getsoftc(ifp);
508da089c14SMark Johnston mii = GET_MII(sc);
509da089c14SMark Johnston AXGE_LOCK_ASSERT(sc, MA_OWNED);
510da089c14SMark Johnston
511da089c14SMark Johnston LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
512da089c14SMark Johnston PHY_RESET(miisc);
513da089c14SMark Johnston error = mii_mediachg(mii);
514da089c14SMark Johnston
515da089c14SMark Johnston return (error);
516da089c14SMark Johnston }
517da089c14SMark Johnston
518da089c14SMark Johnston /*
519da089c14SMark Johnston * Report current media status.
520da089c14SMark Johnston */
521da089c14SMark Johnston static void
axge_ifmedia_sts(if_t ifp,struct ifmediareq * ifmr)522935b194dSJustin Hibbits axge_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
523da089c14SMark Johnston {
524da089c14SMark Johnston struct axge_softc *sc;
525da089c14SMark Johnston struct mii_data *mii;
526da089c14SMark Johnston
527935b194dSJustin Hibbits sc = if_getsoftc(ifp);
528da089c14SMark Johnston mii = GET_MII(sc);
529da089c14SMark Johnston AXGE_LOCK(sc);
530da089c14SMark Johnston mii_pollstat(mii);
531da089c14SMark Johnston ifmr->ifm_active = mii->mii_media_active;
532da089c14SMark Johnston ifmr->ifm_status = mii->mii_media_status;
533da089c14SMark Johnston AXGE_UNLOCK(sc);
534da089c14SMark Johnston }
535da089c14SMark Johnston
536da089c14SMark Johnston /*
537da089c14SMark Johnston * Probe for a AX88179 chip.
538da089c14SMark Johnston */
539da089c14SMark Johnston static int
axge_probe(device_t dev)540da089c14SMark Johnston axge_probe(device_t dev)
541da089c14SMark Johnston {
542da089c14SMark Johnston struct usb_attach_arg *uaa;
543da089c14SMark Johnston
544da089c14SMark Johnston uaa = device_get_ivars(dev);
545da089c14SMark Johnston if (uaa->usb_mode != USB_MODE_HOST)
546da089c14SMark Johnston return (ENXIO);
547da089c14SMark Johnston if (uaa->info.bConfigIndex != AXGE_CONFIG_IDX)
548da089c14SMark Johnston return (ENXIO);
549da089c14SMark Johnston if (uaa->info.bIfaceIndex != AXGE_IFACE_IDX)
550da089c14SMark Johnston return (ENXIO);
551da089c14SMark Johnston
552da089c14SMark Johnston return (usbd_lookup_id_by_uaa(axge_devs, sizeof(axge_devs), uaa));
553da089c14SMark Johnston }
554da089c14SMark Johnston
555da089c14SMark Johnston /*
556da089c14SMark Johnston * Attach the interface. Allocate softc structures, do ifmedia
557da089c14SMark Johnston * setup and ethernet/BPF attach.
558da089c14SMark Johnston */
559da089c14SMark Johnston static int
axge_attach(device_t dev)560da089c14SMark Johnston axge_attach(device_t dev)
561da089c14SMark Johnston {
562da089c14SMark Johnston struct usb_attach_arg *uaa;
563da089c14SMark Johnston struct axge_softc *sc;
564da089c14SMark Johnston struct usb_ether *ue;
565da089c14SMark Johnston uint8_t iface_index;
566da089c14SMark Johnston int error;
567da089c14SMark Johnston
568da089c14SMark Johnston uaa = device_get_ivars(dev);
569da089c14SMark Johnston sc = device_get_softc(dev);
570da089c14SMark Johnston ue = &sc->sc_ue;
571da089c14SMark Johnston
572da089c14SMark Johnston device_set_usb_desc(dev);
573da089c14SMark Johnston mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
574da089c14SMark Johnston
575*6962da91SDamien Broka sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
576*6962da91SDamien Broka
577da089c14SMark Johnston iface_index = AXGE_IFACE_IDX;
578da089c14SMark Johnston error = usbd_transfer_setup(uaa->device, &iface_index,
579da089c14SMark Johnston sc->sc_xfer, axge_config, AXGE_N_TRANSFER, sc, &sc->sc_mtx);
580da089c14SMark Johnston if (error) {
581da089c14SMark Johnston device_printf(dev, "allocating USB transfers failed\n");
5822948462dSPyun YongHyeon mtx_destroy(&sc->sc_mtx);
5832948462dSPyun YongHyeon return (ENXIO);
584da089c14SMark Johnston }
585da089c14SMark Johnston
586da089c14SMark Johnston ue->ue_sc = sc;
587da089c14SMark Johnston ue->ue_dev = dev;
588da089c14SMark Johnston ue->ue_udev = uaa->device;
589da089c14SMark Johnston ue->ue_mtx = &sc->sc_mtx;
590da089c14SMark Johnston ue->ue_methods = &axge_ue_methods;
591da089c14SMark Johnston
592da089c14SMark Johnston error = uether_ifattach(ue);
593da089c14SMark Johnston if (error) {
594da089c14SMark Johnston device_printf(dev, "could not attach interface\n");
595da089c14SMark Johnston goto detach;
596da089c14SMark Johnston }
597da089c14SMark Johnston return (0); /* success */
598da089c14SMark Johnston
599da089c14SMark Johnston detach:
600da089c14SMark Johnston axge_detach(dev);
601da089c14SMark Johnston return (ENXIO); /* failure */
602da089c14SMark Johnston }
603da089c14SMark Johnston
604da089c14SMark Johnston static int
axge_detach(device_t dev)605da089c14SMark Johnston axge_detach(device_t dev)
606da089c14SMark Johnston {
607da089c14SMark Johnston struct axge_softc *sc;
608da089c14SMark Johnston struct usb_ether *ue;
6099ab0e2a7SPyun YongHyeon uint16_t val;
610da089c14SMark Johnston
611da089c14SMark Johnston sc = device_get_softc(dev);
612da089c14SMark Johnston ue = &sc->sc_ue;
6139ab0e2a7SPyun YongHyeon if (device_is_attached(dev)) {
6147ef4e76fSHans Petter Selasky /* wait for any post attach or other command to complete */
6157ef4e76fSHans Petter Selasky usb_proc_drain(&ue->ue_tq);
6167ef4e76fSHans Petter Selasky
6179ab0e2a7SPyun YongHyeon AXGE_LOCK(sc);
6189ab0e2a7SPyun YongHyeon /*
6199ab0e2a7SPyun YongHyeon * XXX
6209ab0e2a7SPyun YongHyeon * ether_ifdetach(9) should be called first.
6219ab0e2a7SPyun YongHyeon */
6229ab0e2a7SPyun YongHyeon axge_stop(ue);
6239ab0e2a7SPyun YongHyeon /* Force bulk-in to return a zero-length USB packet. */
6249ab0e2a7SPyun YongHyeon val = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR);
6259ab0e2a7SPyun YongHyeon val |= EPPRCR_BZ | EPPRCR_IPRL;
6269ab0e2a7SPyun YongHyeon axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_EPPRCR, val);
6279ab0e2a7SPyun YongHyeon /* Change clock. */
6289ab0e2a7SPyun YongHyeon axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CLK_SELECT, 0);
6299ab0e2a7SPyun YongHyeon /* Disable MAC. */
6309ab0e2a7SPyun YongHyeon axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, 0);
6319ab0e2a7SPyun YongHyeon AXGE_UNLOCK(sc);
6329ab0e2a7SPyun YongHyeon }
633da089c14SMark Johnston usbd_transfer_unsetup(sc->sc_xfer, AXGE_N_TRANSFER);
634da089c14SMark Johnston uether_ifdetach(ue);
635da089c14SMark Johnston mtx_destroy(&sc->sc_mtx);
636da089c14SMark Johnston
637da089c14SMark Johnston return (0);
638da089c14SMark Johnston }
639da089c14SMark Johnston
640da089c14SMark Johnston static void
axge_bulk_read_callback(struct usb_xfer * xfer,usb_error_t error)641da089c14SMark Johnston axge_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
642da089c14SMark Johnston {
643da089c14SMark Johnston struct axge_softc *sc;
644da089c14SMark Johnston struct usb_ether *ue;
645da089c14SMark Johnston struct usb_page_cache *pc;
646da089c14SMark Johnston int actlen;
647da089c14SMark Johnston
648da089c14SMark Johnston sc = usbd_xfer_softc(xfer);
649da089c14SMark Johnston ue = &sc->sc_ue;
650da089c14SMark Johnston usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
651da089c14SMark Johnston
652da089c14SMark Johnston switch (USB_GET_STATE(xfer)) {
653da089c14SMark Johnston case USB_ST_TRANSFERRED:
654da089c14SMark Johnston pc = usbd_xfer_get_frame(xfer, 0);
6552110950bSHans Petter Selasky axge_rx_frame(ue, pc, actlen);
656da089c14SMark Johnston
657da089c14SMark Johnston /* FALLTHROUGH */
658da089c14SMark Johnston case USB_ST_SETUP:
659da089c14SMark Johnston tr_setup:
660da089c14SMark Johnston usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
661da089c14SMark Johnston usbd_transfer_submit(xfer);
662da089c14SMark Johnston uether_rxflush(ue);
663948d799eSHans Petter Selasky break;
664da089c14SMark Johnston
665da089c14SMark Johnston default:
666da089c14SMark Johnston if (error != USB_ERR_CANCELLED) {
667da089c14SMark Johnston usbd_xfer_set_stall(xfer);
668da089c14SMark Johnston goto tr_setup;
669da089c14SMark Johnston }
670948d799eSHans Petter Selasky break;
671da089c14SMark Johnston }
672da089c14SMark Johnston }
673da089c14SMark Johnston
674da089c14SMark Johnston static void
axge_bulk_write_callback(struct usb_xfer * xfer,usb_error_t error)675da089c14SMark Johnston axge_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
676da089c14SMark Johnston {
677da089c14SMark Johnston struct axge_softc *sc;
678935b194dSJustin Hibbits if_t ifp;
679da089c14SMark Johnston struct usb_page_cache *pc;
680da089c14SMark Johnston struct mbuf *m;
6817c10cf8cSPyun YongHyeon struct axge_frame_txhdr txhdr;
682d32048bbSKevin Lo int nframes, pos;
683da089c14SMark Johnston
684da089c14SMark Johnston sc = usbd_xfer_softc(xfer);
685da089c14SMark Johnston ifp = uether_getifp(&sc->sc_ue);
686da089c14SMark Johnston
687da089c14SMark Johnston switch (USB_GET_STATE(xfer)) {
688da089c14SMark Johnston case USB_ST_TRANSFERRED:
689935b194dSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
690da089c14SMark Johnston /* FALLTHROUGH */
691da089c14SMark Johnston case USB_ST_SETUP:
692da089c14SMark Johnston tr_setup:
693da089c14SMark Johnston if ((sc->sc_flags & AXGE_FLAG_LINK) == 0 ||
694935b194dSJustin Hibbits (if_getdrvflags(ifp) & IFF_DRV_OACTIVE) != 0) {
695da089c14SMark Johnston /*
696da089c14SMark Johnston * Don't send anything if there is no link or
697da089c14SMark Johnston * controller is busy.
698da089c14SMark Johnston */
699da089c14SMark Johnston return;
700da089c14SMark Johnston }
701da089c14SMark Johnston
7027c10cf8cSPyun YongHyeon for (nframes = 0; nframes < AXGE_N_FRAMES &&
703935b194dSJustin Hibbits !if_sendq_empty(ifp); nframes++) {
704935b194dSJustin Hibbits m = if_dequeue(ifp);
705da089c14SMark Johnston if (m == NULL)
706da089c14SMark Johnston break;
707da089c14SMark Johnston usbd_xfer_set_frame_offset(xfer, nframes * MCLBYTES,
708da089c14SMark Johnston nframes);
709da089c14SMark Johnston pc = usbd_xfer_get_frame(xfer, nframes);
7107c10cf8cSPyun YongHyeon txhdr.mss = 0;
7117c10cf8cSPyun YongHyeon txhdr.len = htole32(AXGE_TXBYTES(m->m_pkthdr.len));
712935b194dSJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_TXCSUM) != 0 &&
7137c10cf8cSPyun YongHyeon (m->m_pkthdr.csum_flags & AXGE_CSUM_FEATURES) == 0)
7147c10cf8cSPyun YongHyeon txhdr.len |= htole32(AXGE_CSUM_DISABLE);
7157c10cf8cSPyun YongHyeon
7167c10cf8cSPyun YongHyeon pos = 0;
7177c10cf8cSPyun YongHyeon usbd_copy_in(pc, pos, &txhdr, sizeof(txhdr));
7187c10cf8cSPyun YongHyeon pos += sizeof(txhdr);
719d32048bbSKevin Lo usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len);
720d32048bbSKevin Lo pos += m->m_pkthdr.len;
721da089c14SMark Johnston
722da089c14SMark Johnston /*
723da089c14SMark Johnston * if there's a BPF listener, bounce a copy
724da089c14SMark Johnston * of this frame to him:
725da089c14SMark Johnston */
726da089c14SMark Johnston BPF_MTAP(ifp, m);
727da089c14SMark Johnston
728da089c14SMark Johnston m_freem(m);
729da089c14SMark Johnston
730da089c14SMark Johnston /* Set frame length. */
731d32048bbSKevin Lo usbd_xfer_set_frame_len(xfer, nframes, pos);
732da089c14SMark Johnston }
733da089c14SMark Johnston if (nframes != 0) {
7347c10cf8cSPyun YongHyeon /*
7357c10cf8cSPyun YongHyeon * XXX
7367c10cf8cSPyun YongHyeon * Update TX packet counter here. This is not
7377c10cf8cSPyun YongHyeon * correct way but it seems that there is no way
7387c10cf8cSPyun YongHyeon * to know how many packets are sent at the end
7397c10cf8cSPyun YongHyeon * of transfer because controller combines
7407c10cf8cSPyun YongHyeon * multiple writes into single one if there is
7417c10cf8cSPyun YongHyeon * room in TX buffer of controller.
7427c10cf8cSPyun YongHyeon */
7437c10cf8cSPyun YongHyeon if_inc_counter(ifp, IFCOUNTER_OPACKETS, nframes);
744da089c14SMark Johnston usbd_xfer_set_frames(xfer, nframes);
745da089c14SMark Johnston usbd_transfer_submit(xfer);
746935b194dSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_OACTIVE, 0);
747da089c14SMark Johnston }
748da089c14SMark Johnston return;
749da089c14SMark Johnston /* NOTREACHED */
750da089c14SMark Johnston default:
751ecc70d3fSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
752935b194dSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
753da089c14SMark Johnston
754da089c14SMark Johnston if (error != USB_ERR_CANCELLED) {
755da089c14SMark Johnston usbd_xfer_set_stall(xfer);
756da089c14SMark Johnston goto tr_setup;
757da089c14SMark Johnston }
758da089c14SMark Johnston return;
759da089c14SMark Johnston }
760da089c14SMark Johnston }
761da089c14SMark Johnston
762da089c14SMark Johnston static void
axge_tick(struct usb_ether * ue)763da089c14SMark Johnston axge_tick(struct usb_ether *ue)
764da089c14SMark Johnston {
765da089c14SMark Johnston struct axge_softc *sc;
766da089c14SMark Johnston struct mii_data *mii;
767da089c14SMark Johnston
768da089c14SMark Johnston sc = uether_getsc(ue);
769da089c14SMark Johnston mii = GET_MII(sc);
770da089c14SMark Johnston AXGE_LOCK_ASSERT(sc, MA_OWNED);
771da089c14SMark Johnston
772da089c14SMark Johnston mii_tick(mii);
773da089c14SMark Johnston }
774da089c14SMark Johnston
77519a1980eSGleb Smirnoff static u_int
axge_hash_maddr(void * arg,struct sockaddr_dl * sdl,u_int cnt)77619a1980eSGleb Smirnoff axge_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
77719a1980eSGleb Smirnoff {
77819a1980eSGleb Smirnoff uint8_t *hashtbl = arg;
77919a1980eSGleb Smirnoff uint32_t h;
78019a1980eSGleb Smirnoff
78119a1980eSGleb Smirnoff h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26;
78219a1980eSGleb Smirnoff hashtbl[h / 8] |= 1 << (h % 8);
78319a1980eSGleb Smirnoff
78419a1980eSGleb Smirnoff return (1);
78519a1980eSGleb Smirnoff }
78619a1980eSGleb Smirnoff
787da089c14SMark Johnston static void
axge_rxfilter(struct usb_ether * ue)788a5d82655SPyun YongHyeon axge_rxfilter(struct usb_ether *ue)
789da089c14SMark Johnston {
790da089c14SMark Johnston struct axge_softc *sc;
791935b194dSJustin Hibbits if_t ifp;
792da089c14SMark Johnston uint16_t rxmode;
793da089c14SMark Johnston uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
794da089c14SMark Johnston
795da089c14SMark Johnston sc = uether_getsc(ue);
796da089c14SMark Johnston ifp = uether_getifp(ue);
797da089c14SMark Johnston AXGE_LOCK_ASSERT(sc, MA_OWNED);
798da089c14SMark Johnston
799a5d82655SPyun YongHyeon /*
800a5d82655SPyun YongHyeon * Configure RX settings.
801a5d82655SPyun YongHyeon * Don't set RCR_IPE(IP header alignment on 32bit boundary) to disable
802a5d82655SPyun YongHyeon * inserting extra padding bytes. This wastes ethernet to USB host
803a5d82655SPyun YongHyeon * bandwidth as well as complicating RX handling logic. Current USB
804a5d82655SPyun YongHyeon * framework requires copying RX frames to mbufs so there is no need
805a5d82655SPyun YongHyeon * to worry about alignment.
806a5d82655SPyun YongHyeon */
807a5d82655SPyun YongHyeon rxmode = RCR_DROP_CRCERR | RCR_START;
808935b194dSJustin Hibbits if (if_getflags(ifp) & IFF_BROADCAST)
809a5d82655SPyun YongHyeon rxmode |= RCR_ACPT_BCAST;
810935b194dSJustin Hibbits if (if_getflags(ifp) & (IFF_ALLMULTI | IFF_PROMISC)) {
811935b194dSJustin Hibbits if (if_getflags(ifp) & IFF_PROMISC)
812a5d82655SPyun YongHyeon rxmode |= RCR_PROMISC;
813b2cdc7caSPyun YongHyeon rxmode |= RCR_ACPT_ALL_MCAST;
814d32048bbSKevin Lo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode);
815da089c14SMark Johnston return;
816da089c14SMark Johnston }
817da089c14SMark Johnston
818a5d82655SPyun YongHyeon rxmode |= RCR_ACPT_MCAST;
81919a1980eSGleb Smirnoff if_foreach_llmaddr(ifp, axge_hash_maddr, &hashtbl);
820da089c14SMark Johnston
821d32048bbSKevin Lo axge_write_mem(sc, AXGE_ACCESS_MAC, 8, AXGE_MFA, (void *)&hashtbl, 8);
822d32048bbSKevin Lo axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_RCR, rxmode);
823da089c14SMark Johnston }
824da089c14SMark Johnston
825da089c14SMark Johnston static void
axge_start(struct usb_ether * ue)826da089c14SMark Johnston axge_start(struct usb_ether *ue)
827da089c14SMark Johnston {
828da089c14SMark Johnston struct axge_softc *sc;
829da089c14SMark Johnston
830da089c14SMark Johnston sc = uether_getsc(ue);
831da089c14SMark Johnston /*
832da089c14SMark Johnston * Start the USB transfers, if not already started.
833da089c14SMark Johnston */
834da089c14SMark Johnston usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_RD]);
835da089c14SMark Johnston usbd_transfer_start(sc->sc_xfer[AXGE_BULK_DT_WR]);
836da089c14SMark Johnston }
837da089c14SMark Johnston
838da089c14SMark Johnston static void
axge_init(struct usb_ether * ue)839da089c14SMark Johnston axge_init(struct usb_ether *ue)
840da089c14SMark Johnston {
841da089c14SMark Johnston struct axge_softc *sc;
842935b194dSJustin Hibbits if_t ifp;
843da089c14SMark Johnston
844da089c14SMark Johnston sc = uether_getsc(ue);
845da089c14SMark Johnston ifp = uether_getifp(ue);
846da089c14SMark Johnston AXGE_LOCK_ASSERT(sc, MA_OWNED);
847da089c14SMark Johnston
848935b194dSJustin Hibbits if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0)
849da089c14SMark Johnston return;
850da089c14SMark Johnston
851da089c14SMark Johnston /*
852da089c14SMark Johnston * Cancel pending I/O and free all RX/TX buffers.
853da089c14SMark Johnston */
854da089c14SMark Johnston axge_stop(ue);
855da089c14SMark Johnston
856da089c14SMark Johnston axge_reset(sc);
857da089c14SMark Johnston
858da089c14SMark Johnston /* Set MAC address. */
859d32048bbSKevin Lo axge_write_mem(sc, AXGE_ACCESS_MAC, ETHER_ADDR_LEN, AXGE_NIDR,
860935b194dSJustin Hibbits if_getlladdr(ifp), ETHER_ADDR_LEN);
861da089c14SMark Johnston
862d32048bbSKevin Lo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLLR, 0x34);
863d32048bbSKevin Lo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_PWLHR, 0x52);
864da089c14SMark Johnston
865da089c14SMark Johnston /* Configure TX/RX checksum offloading. */
866da089c14SMark Johnston axge_csum_cfg(ue);
867da089c14SMark Johnston
868a5d82655SPyun YongHyeon /* Configure RX filters. */
869a5d82655SPyun YongHyeon axge_rxfilter(ue);
870da089c14SMark Johnston
871a5d82655SPyun YongHyeon /*
872a5d82655SPyun YongHyeon * XXX
873a5d82655SPyun YongHyeon * Controller supports wakeup on link change detection,
874a5d82655SPyun YongHyeon * magic packet and wakeup frame recpetion. But it seems
875a5d82655SPyun YongHyeon * there is no framework for USB ethernet suspend/wakeup.
876a5d82655SPyun YongHyeon * Disable all wakeup functions.
877a5d82655SPyun YongHyeon */
878a5d82655SPyun YongHyeon axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_MMSR, 0);
879a5d82655SPyun YongHyeon (void)axge_read_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_MMSR);
880da089c14SMark Johnston
881a5d82655SPyun YongHyeon /* Configure default medium type. */
882a5d82655SPyun YongHyeon axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_MSR, MSR_GM | MSR_FD |
883a5d82655SPyun YongHyeon MSR_RFC | MSR_TFC | MSR_RE);
884da089c14SMark Johnston
885da089c14SMark Johnston usbd_xfer_set_stall(sc->sc_xfer[AXGE_BULK_DT_WR]);
886da089c14SMark Johnston
887935b194dSJustin Hibbits if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
888da089c14SMark Johnston /* Switch to selected media. */
889da089c14SMark Johnston axge_ifmedia_upd(ifp);
890da089c14SMark Johnston }
891da089c14SMark Johnston
892da089c14SMark Johnston static void
axge_stop(struct usb_ether * ue)893da089c14SMark Johnston axge_stop(struct usb_ether *ue)
894da089c14SMark Johnston {
895da089c14SMark Johnston struct axge_softc *sc;
896935b194dSJustin Hibbits if_t ifp;
89715b5fb58SPyun YongHyeon uint16_t val;
898da089c14SMark Johnston
899da089c14SMark Johnston sc = uether_getsc(ue);
900da089c14SMark Johnston ifp = uether_getifp(ue);
901da089c14SMark Johnston
902da089c14SMark Johnston AXGE_LOCK_ASSERT(sc, MA_OWNED);
903da089c14SMark Johnston
90415b5fb58SPyun YongHyeon val = axge_read_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_MSR);
90515b5fb58SPyun YongHyeon val &= ~MSR_RE;
90615b5fb58SPyun YongHyeon axge_write_cmd_2(sc, AXGE_ACCESS_MAC, 2, AXGE_MSR, val);
90715b5fb58SPyun YongHyeon
9087ef4e76fSHans Petter Selasky if (ifp != NULL)
909935b194dSJustin Hibbits if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
910da089c14SMark Johnston sc->sc_flags &= ~AXGE_FLAG_LINK;
911da089c14SMark Johnston
912da089c14SMark Johnston /*
913da089c14SMark Johnston * Stop all the transfers, if not already stopped:
914da089c14SMark Johnston */
915da089c14SMark Johnston usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_WR]);
916da089c14SMark Johnston usbd_transfer_stop(sc->sc_xfer[AXGE_BULK_DT_RD]);
917da089c14SMark Johnston }
918da089c14SMark Johnston
919da089c14SMark Johnston static int
axge_ioctl(if_t ifp,u_long cmd,caddr_t data)920935b194dSJustin Hibbits axge_ioctl(if_t ifp, u_long cmd, caddr_t data)
921da089c14SMark Johnston {
922da089c14SMark Johnston struct usb_ether *ue;
923da089c14SMark Johnston struct axge_softc *sc;
924da089c14SMark Johnston struct ifreq *ifr;
925da089c14SMark Johnston int error, mask, reinit;
926da089c14SMark Johnston
927935b194dSJustin Hibbits ue = if_getsoftc(ifp);
928da089c14SMark Johnston sc = uether_getsc(ue);
929da089c14SMark Johnston ifr = (struct ifreq *)data;
930da089c14SMark Johnston error = 0;
931da089c14SMark Johnston reinit = 0;
932da089c14SMark Johnston if (cmd == SIOCSIFCAP) {
933da089c14SMark Johnston AXGE_LOCK(sc);
934935b194dSJustin Hibbits mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
935da089c14SMark Johnston if ((mask & IFCAP_TXCSUM) != 0 &&
936935b194dSJustin Hibbits (if_getcapabilities(ifp) & IFCAP_TXCSUM) != 0) {
937935b194dSJustin Hibbits if_togglecapenable(ifp, IFCAP_TXCSUM);
938935b194dSJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_TXCSUM) != 0)
939935b194dSJustin Hibbits if_sethwassistbits(ifp, AXGE_CSUM_FEATURES, 0);
940da089c14SMark Johnston else
941935b194dSJustin Hibbits if_sethwassistbits(ifp, 0, AXGE_CSUM_FEATURES);
942da089c14SMark Johnston reinit++;
943da089c14SMark Johnston }
944da089c14SMark Johnston if ((mask & IFCAP_RXCSUM) != 0 &&
945935b194dSJustin Hibbits (if_getcapabilities(ifp) & IFCAP_RXCSUM) != 0) {
946935b194dSJustin Hibbits if_togglecapenable(ifp, IFCAP_RXCSUM);
947da089c14SMark Johnston reinit++;
948da089c14SMark Johnston }
949935b194dSJustin Hibbits if (reinit > 0 && if_getdrvflags(ifp) & IFF_DRV_RUNNING)
950935b194dSJustin Hibbits if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING);
951da089c14SMark Johnston else
952da089c14SMark Johnston reinit = 0;
953da089c14SMark Johnston AXGE_UNLOCK(sc);
954da089c14SMark Johnston if (reinit > 0)
955da089c14SMark Johnston uether_init(ue);
956da089c14SMark Johnston } else
957da089c14SMark Johnston error = uether_ioctl(ifp, cmd, data);
958da089c14SMark Johnston
959da089c14SMark Johnston return (error);
960da089c14SMark Johnston }
961da089c14SMark Johnston
9622110950bSHans Petter Selasky static void
axge_rx_frame(struct usb_ether * ue,struct usb_page_cache * pc,int actlen)963da089c14SMark Johnston axge_rx_frame(struct usb_ether *ue, struct usb_page_cache *pc, int actlen)
964da089c14SMark Johnston {
965a5d82655SPyun YongHyeon struct axge_frame_rxhdr pkt_hdr;
966561227daSHans Petter Selasky uint32_t rxhdr;
967a5d82655SPyun YongHyeon uint32_t pos;
968a5d82655SPyun YongHyeon uint32_t pkt_cnt, pkt_end;
969561227daSHans Petter Selasky uint32_t hdr_off;
970561227daSHans Petter Selasky uint32_t pktlen;
971561227daSHans Petter Selasky
972561227daSHans Petter Selasky /* verify we have enough data */
973561227daSHans Petter Selasky if (actlen < (int)sizeof(rxhdr))
9742110950bSHans Petter Selasky return;
975da089c14SMark Johnston
976da089c14SMark Johnston pos = 0;
977da089c14SMark Johnston
978da089c14SMark Johnston usbd_copy_out(pc, actlen - sizeof(rxhdr), &rxhdr, sizeof(rxhdr));
979da089c14SMark Johnston rxhdr = le32toh(rxhdr);
980da089c14SMark Johnston
981a5d82655SPyun YongHyeon pkt_cnt = rxhdr & 0xFFFF;
982a5d82655SPyun YongHyeon hdr_off = pkt_end = (rxhdr >> 16) & 0xFFFF;
983da089c14SMark Johnston
984a5d82655SPyun YongHyeon /*
98570fbcd45SDamien Broka * On older firmware:
986a5d82655SPyun YongHyeon * <----------------------- actlen ------------------------>
987a5d82655SPyun YongHyeon * [frame #0]...[frame #N][pkt_hdr #0]...[pkt_hdr #N][rxhdr]
98870fbcd45SDamien Broka *
98970fbcd45SDamien Broka * On newer firmware:
99070fbcd45SDamien Broka * <----------------------- actlen -----------------
99170fbcd45SDamien Broka * [frame #0]...[frame #N][pkt_hdr #0][dummy_hdr]...
99270fbcd45SDamien Broka * -------------------------------->
99370fbcd45SDamien Broka * ...[pkt_hdr #N][dummy_hdr][rxhdr]
99470fbcd45SDamien Broka *
995a5d82655SPyun YongHyeon * Each RX frame would be aligned on 8 bytes boundary. If
996a5d82655SPyun YongHyeon * RCR_IPE bit is set in AXGE_RCR register, there would be 2
997a5d82655SPyun YongHyeon * padding bytes and 6 dummy bytes(as the padding also should
998a5d82655SPyun YongHyeon * be aligned on 8 bytes boundary) for each RX frame to align
999a5d82655SPyun YongHyeon * IP header on 32bits boundary. Driver don't set RCR_IPE bit
1000a5d82655SPyun YongHyeon * of AXGE_RCR register, so there should be no padding bytes
1001a5d82655SPyun YongHyeon * which simplifies RX logic a lot.
100270fbcd45SDamien Broka *
100370fbcd45SDamien Broka * Further, newer firmware interweaves dummy headers that have
100470fbcd45SDamien Broka * pktlen == 0 and should be skipped without being seen as
100570fbcd45SDamien Broka * dropped frames.
1006a5d82655SPyun YongHyeon */
10072110950bSHans Petter Selasky while (pkt_cnt--) {
1008561227daSHans Petter Selasky /* verify the header offset */
1009561227daSHans Petter Selasky if ((int)(hdr_off + sizeof(pkt_hdr)) > actlen) {
10102110950bSHans Petter Selasky DPRINTF("End of packet headers\n");
10112110950bSHans Petter Selasky break;
10122110950bSHans Petter Selasky }
1013a5d82655SPyun YongHyeon usbd_copy_out(pc, hdr_off, &pkt_hdr, sizeof(pkt_hdr));
1014a5d82655SPyun YongHyeon pkt_hdr.status = le32toh(pkt_hdr.status);
1015a5d82655SPyun YongHyeon pktlen = AXGE_RXBYTES(pkt_hdr.status);
101670fbcd45SDamien Broka hdr_off += sizeof(pkt_hdr);
101770fbcd45SDamien Broka
101870fbcd45SDamien Broka /* Skip dummy packet header. */
101970fbcd45SDamien Broka if (pktlen == 0)
102070fbcd45SDamien Broka continue;
102170fbcd45SDamien Broka
1022a5d82655SPyun YongHyeon if (pos + pktlen > pkt_end) {
10232110950bSHans Petter Selasky DPRINTF("Data position reached end\n");
1024da089c14SMark Johnston break;
1025da089c14SMark Johnston }
1026561227daSHans Petter Selasky
1027a5d82655SPyun YongHyeon if (AXGE_RX_ERR(pkt_hdr.status) != 0) {
10282110950bSHans Petter Selasky DPRINTF("Dropped a packet\n");
1029ecc70d3fSGleb Smirnoff if_inc_counter(ue->ue_ifp, IFCOUNTER_IERRORS, 1);
1030a5d82655SPyun YongHyeon } else
1031a5d82655SPyun YongHyeon axge_rxeof(ue, pc, pos, pktlen, pkt_hdr.status);
1032561227daSHans Petter Selasky pos += (pktlen + 7) & ~7;
1033da089c14SMark Johnston }
1034da089c14SMark Johnston }
1035da089c14SMark Johnston
10362110950bSHans Petter Selasky static void
axge_rxeof(struct usb_ether * ue,struct usb_page_cache * pc,unsigned offset,unsigned len,uint32_t status)103762d42655SHans Petter Selasky axge_rxeof(struct usb_ether *ue, struct usb_page_cache *pc, unsigned offset,
103862d42655SHans Petter Selasky unsigned len, uint32_t status)
1039da089c14SMark Johnston {
1040935b194dSJustin Hibbits if_t ifp;
1041da089c14SMark Johnston struct mbuf *m;
1042da089c14SMark Johnston
1043da089c14SMark Johnston ifp = ue->ue_ifp;
1044da089c14SMark Johnston if (len < ETHER_HDR_LEN || len > MCLBYTES - ETHER_ALIGN) {
1045ecc70d3fSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
10462110950bSHans Petter Selasky return;
1047da089c14SMark Johnston }
1048da089c14SMark Johnston
1049a5d82655SPyun YongHyeon if (len > MHLEN - ETHER_ALIGN)
1050da089c14SMark Johnston m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1051a5d82655SPyun YongHyeon else
1052a5d82655SPyun YongHyeon m = m_gethdr(M_NOWAIT, MT_DATA);
1053da089c14SMark Johnston if (m == NULL) {
1054ecc70d3fSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
10552110950bSHans Petter Selasky return;
1056da089c14SMark Johnston }
10572110950bSHans Petter Selasky m->m_pkthdr.rcvif = ifp;
1058a5d82655SPyun YongHyeon m->m_len = m->m_pkthdr.len = len;
1059a5d82655SPyun YongHyeon m->m_data += ETHER_ALIGN;
1060da089c14SMark Johnston
1061da089c14SMark Johnston usbd_copy_out(pc, offset, mtod(m, uint8_t *), len);
1062da089c14SMark Johnston
1063935b194dSJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0) {
1064a5d82655SPyun YongHyeon if ((status & AXGE_RX_L3_CSUM_ERR) == 0 &&
1065a5d82655SPyun YongHyeon (status & AXGE_RX_L3_TYPE_MASK) == AXGE_RX_L3_TYPE_IPV4)
1066a5d82655SPyun YongHyeon m->m_pkthdr.csum_flags |= CSUM_IP_CHECKED |
1067a5d82655SPyun YongHyeon CSUM_IP_VALID;
1068a5d82655SPyun YongHyeon if ((status & AXGE_RX_L4_CSUM_ERR) == 0 &&
1069a5d82655SPyun YongHyeon ((status & AXGE_RX_L4_TYPE_MASK) == AXGE_RX_L4_TYPE_UDP ||
1070a5d82655SPyun YongHyeon (status & AXGE_RX_L4_TYPE_MASK) == AXGE_RX_L4_TYPE_TCP)) {
1071d32048bbSKevin Lo m->m_pkthdr.csum_flags |= CSUM_DATA_VALID |
1072a5d82655SPyun YongHyeon CSUM_PSEUDO_HDR;
1073da089c14SMark Johnston m->m_pkthdr.csum_data = 0xffff;
1074da089c14SMark Johnston }
1075da089c14SMark Johnston }
1076a5d82655SPyun YongHyeon if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
1077948d799eSHans Petter Selasky
107835d3dd8bSGleb Smirnoff (void)mbufq_enqueue(&ue->ue_rxq, m);
1079da089c14SMark Johnston }
1080da089c14SMark Johnston
1081da089c14SMark Johnston static void
axge_csum_cfg(struct usb_ether * ue)1082da089c14SMark Johnston axge_csum_cfg(struct usb_ether *ue)
1083da089c14SMark Johnston {
1084da089c14SMark Johnston struct axge_softc *sc;
1085935b194dSJustin Hibbits if_t ifp;
1086da089c14SMark Johnston uint8_t csum;
1087da089c14SMark Johnston
1088da089c14SMark Johnston sc = uether_getsc(ue);
1089da089c14SMark Johnston AXGE_LOCK_ASSERT(sc, MA_OWNED);
1090da089c14SMark Johnston ifp = uether_getifp(ue);
1091da089c14SMark Johnston
1092da089c14SMark Johnston csum = 0;
1093935b194dSJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_TXCSUM) != 0)
1094d32048bbSKevin Lo csum |= CTCR_IP | CTCR_TCP | CTCR_UDP;
1095d32048bbSKevin Lo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CTCR, csum);
1096da089c14SMark Johnston
1097da089c14SMark Johnston csum = 0;
1098935b194dSJustin Hibbits if ((if_getcapenable(ifp) & IFCAP_RXCSUM) != 0)
1099d32048bbSKevin Lo csum |= CRCR_IP | CRCR_TCP | CRCR_UDP;
1100d32048bbSKevin Lo axge_write_cmd_1(sc, AXGE_ACCESS_MAC, AXGE_CRCR, csum);
1101da089c14SMark Johnston }
1102