if_axe.c revision 215964
1184610Salfred/*-
2184610Salfred * Copyright (c) 1997, 1998, 1999, 2000-2003
3184610Salfred *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4184610Salfred *
5184610Salfred * Redistribution and use in source and binary forms, with or without
6184610Salfred * modification, are permitted provided that the following conditions
7184610Salfred * are met:
8184610Salfred * 1. Redistributions of source code must retain the above copyright
9184610Salfred *    notice, this list of conditions and the following disclaimer.
10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
11184610Salfred *    notice, this list of conditions and the following disclaimer in the
12184610Salfred *    documentation and/or other materials provided with the distribution.
13184610Salfred * 3. All advertising materials mentioning features or use of this software
14184610Salfred *    must display the following acknowledgement:
15184610Salfred *	This product includes software developed by Bill Paul.
16184610Salfred * 4. Neither the name of the author nor the names of any co-contributors
17184610Salfred *    may be used to endorse or promote products derived from this software
18184610Salfred *    without specific prior written permission.
19184610Salfred *
20184610Salfred * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30184610Salfred * THE POSSIBILITY OF SUCH DAMAGE.
31184610Salfred */
32184610Salfred
33184610Salfred#include <sys/cdefs.h>
34184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/net/if_axe.c 215964 2010-11-28 01:03:06Z yongari $");
35184610Salfred
36184610Salfred/*
37188412Sthompsa * ASIX Electronics AX88172/AX88178/AX88778 USB 2.0 ethernet driver.
38188412Sthompsa * Used in the LinkSys USB200M and various other adapters.
39184610Salfred *
40184610Salfred * Manuals available from:
41184610Salfred * http://www.asix.com.tw/datasheet/mac/Ax88172.PDF
42184610Salfred * Note: you need the manual for the AX88170 chip (USB 1.x ethernet
43184610Salfred * controller) to find the definitions for the RX control register.
44184610Salfred * http://www.asix.com.tw/datasheet/mac/Ax88170.PDF
45184610Salfred *
46184610Salfred * Written by Bill Paul <wpaul@windriver.com>
47184610Salfred * Senior Engineer
48184610Salfred * Wind River Systems
49184610Salfred */
50184610Salfred
51184610Salfred/*
52184610Salfred * The AX88172 provides USB ethernet supports at 10 and 100Mbps.
53184610Salfred * It uses an external PHY (reference designs use a RealTek chip),
54184610Salfred * and has a 64-bit multicast hash filter. There is some information
55184610Salfred * missing from the manual which one needs to know in order to make
56184610Salfred * the chip function:
57184610Salfred *
58184610Salfred * - You must set bit 7 in the RX control register, otherwise the
59184610Salfred *   chip won't receive any packets.
60184610Salfred * - You must initialize all 3 IPG registers, or you won't be able
61184610Salfred *   to send any packets.
62184610Salfred *
63184610Salfred * Note that this device appears to only support loading the station
64184610Salfred * address via autload from the EEPROM (i.e. there's no way to manaully
65184610Salfred * set it).
66184610Salfred *
67184610Salfred * (Adam Weinberger wanted me to name this driver if_gir.c.)
68184610Salfred */
69184610Salfred
70184610Salfred/*
71184610Salfred * Ax88178 and Ax88772 support backported from the OpenBSD driver.
72184610Salfred * 2007/02/12, J.R. Oldroyd, fbsd@opal.com
73184610Salfred *
74184610Salfred * Manual here:
75184610Salfred * http://www.asix.com.tw/FrootAttach/datasheet/AX88178_datasheet_Rev10.pdf
76184610Salfred * http://www.asix.com.tw/FrootAttach/datasheet/AX88772_datasheet_Rev10.pdf
77184610Salfred */
78184610Salfred
79194677Sthompsa#include <sys/stdint.h>
80194677Sthompsa#include <sys/stddef.h>
81194677Sthompsa#include <sys/param.h>
82194677Sthompsa#include <sys/queue.h>
83194677Sthompsa#include <sys/types.h>
84194677Sthompsa#include <sys/systm.h>
85194677Sthompsa#include <sys/kernel.h>
86194677Sthompsa#include <sys/bus.h>
87194677Sthompsa#include <sys/linker_set.h>
88194677Sthompsa#include <sys/module.h>
89194677Sthompsa#include <sys/lock.h>
90194677Sthompsa#include <sys/mutex.h>
91194677Sthompsa#include <sys/condvar.h>
92194677Sthompsa#include <sys/sysctl.h>
93194677Sthompsa#include <sys/sx.h>
94194677Sthompsa#include <sys/unistd.h>
95194677Sthompsa#include <sys/callout.h>
96194677Sthompsa#include <sys/malloc.h>
97194677Sthompsa#include <sys/priv.h>
98194677Sthompsa
99194677Sthompsa#include <dev/usb/usb.h>
100194677Sthompsa#include <dev/usb/usbdi.h>
101194677Sthompsa#include <dev/usb/usbdi_util.h>
102188746Sthompsa#include "usbdevs.h"
103184610Salfred
104184610Salfred#define	USB_DEBUG_VAR axe_debug
105194677Sthompsa#include <dev/usb/usb_debug.h>
106188942Sthompsa#include <dev/usb/usb_process.h>
107184610Salfred
108188942Sthompsa#include <dev/usb/net/usb_ethernet.h>
109188942Sthompsa#include <dev/usb/net/if_axereg.h>
110184610Salfred
111188412Sthompsa/*
112188412Sthompsa * AXE_178_MAX_FRAME_BURST
113188412Sthompsa * max frame burst size for Ax88178 and Ax88772
114188412Sthompsa *	0	2048 bytes
115188412Sthompsa *	1	4096 bytes
116188412Sthompsa *	2	8192 bytes
117188412Sthompsa *	3	16384 bytes
118188412Sthompsa * use the largest your system can handle without USB stalling.
119188412Sthompsa *
120188412Sthompsa * NB: 88772 parts appear to generate lots of input errors with
121188412Sthompsa * a 2K rx buffer and 8K is only slightly faster than 4K on an
122188412Sthompsa * EHCI port on a T42 so change at your own risk.
123188412Sthompsa */
124188412Sthompsa#define AXE_178_MAX_FRAME_BURST	1
125184610Salfred
126207077Sthompsa#ifdef USB_DEBUG
127184610Salfredstatic int axe_debug = 0;
128184610Salfred
129192502SthompsaSYSCTL_NODE(_hw_usb, OID_AUTO, axe, CTLFLAG_RW, 0, "USB axe");
130192502SthompsaSYSCTL_INT(_hw_usb_axe, OID_AUTO, debug, CTLFLAG_RW, &axe_debug, 0,
131184610Salfred    "Debug level");
132184610Salfred#endif
133184610Salfred
134184610Salfred/*
135184610Salfred * Various supported device vendors/products.
136184610Salfred */
137192984Sthompsastatic const struct usb_device_id axe_devs[] = {
138201028Sthompsa#define	AXE_DEV(v,p,i) { USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i) }
139201028Sthompsa	AXE_DEV(ABOCOM, UF200, 0),
140201028Sthompsa	AXE_DEV(ACERCM, EP1427X2, 0),
141201028Sthompsa	AXE_DEV(APPLE, ETHERNET, AXE_FLAG_772),
142201028Sthompsa	AXE_DEV(ASIX, AX88172, 0),
143201028Sthompsa	AXE_DEV(ASIX, AX88178, AXE_FLAG_178),
144201028Sthompsa	AXE_DEV(ASIX, AX88772, AXE_FLAG_772),
145201028Sthompsa	AXE_DEV(ASIX, AX88772A, AXE_FLAG_772),
146201028Sthompsa	AXE_DEV(ATEN, UC210T, 0),
147201028Sthompsa	AXE_DEV(BELKIN, F5D5055, AXE_FLAG_178),
148201028Sthompsa	AXE_DEV(BILLIONTON, USB2AR, 0),
149201028Sthompsa	AXE_DEV(CISCOLINKSYS, USB200MV2, AXE_FLAG_772),
150201028Sthompsa	AXE_DEV(COREGA, FETHER_USB2_TX, 0),
151201028Sthompsa	AXE_DEV(DLINK, DUBE100, 0),
152201028Sthompsa	AXE_DEV(DLINK, DUBE100B1, AXE_FLAG_772),
153201028Sthompsa	AXE_DEV(GOODWAY, GWUSB2E, 0),
154201028Sthompsa	AXE_DEV(IODATA, ETGUS2, AXE_FLAG_178),
155201028Sthompsa	AXE_DEV(JVC, MP_PRX1, 0),
156201028Sthompsa	AXE_DEV(LINKSYS2, USB200M, 0),
157201028Sthompsa	AXE_DEV(LINKSYS4, USB1000, AXE_FLAG_178),
158212980Ssanpei	AXE_DEV(LOGITEC, LAN_GTJU2A, AXE_FLAG_178),
159201028Sthompsa	AXE_DEV(MELCO, LUAU2KTX, 0),
160212980Ssanpei	AXE_DEV(MELCO, LUA3U2AGT, AXE_FLAG_178),
161201028Sthompsa	AXE_DEV(NETGEAR, FA120, 0),
162201028Sthompsa	AXE_DEV(OQO, ETHER01PLUS, AXE_FLAG_772),
163201028Sthompsa	AXE_DEV(PLANEX3, GU1000T, AXE_FLAG_178),
164201028Sthompsa	AXE_DEV(SITECOM, LN029, 0),
165201028Sthompsa	AXE_DEV(SITECOMEU, LN028, AXE_FLAG_178),
166201028Sthompsa	AXE_DEV(SYSTEMTALKS, SGCX2UL, 0),
167201028Sthompsa#undef AXE_DEV
168184610Salfred};
169184610Salfred
170184610Salfredstatic device_probe_t axe_probe;
171184610Salfredstatic device_attach_t axe_attach;
172184610Salfredstatic device_detach_t axe_detach;
173184610Salfred
174193045Sthompsastatic usb_callback_t axe_bulk_read_callback;
175193045Sthompsastatic usb_callback_t axe_bulk_write_callback;
176184610Salfred
177188412Sthompsastatic miibus_readreg_t axe_miibus_readreg;
178188412Sthompsastatic miibus_writereg_t axe_miibus_writereg;
179188412Sthompsastatic miibus_statchg_t axe_miibus_statchg;
180184610Salfred
181193045Sthompsastatic uether_fn_t axe_attach_post;
182193045Sthompsastatic uether_fn_t axe_init;
183193045Sthompsastatic uether_fn_t axe_stop;
184193045Sthompsastatic uether_fn_t axe_start;
185193045Sthompsastatic uether_fn_t axe_tick;
186193045Sthompsastatic uether_fn_t axe_setmulti;
187193045Sthompsastatic uether_fn_t axe_setpromisc;
188184610Salfred
189188412Sthompsastatic int	axe_ifmedia_upd(struct ifnet *);
190188412Sthompsastatic void	axe_ifmedia_sts(struct ifnet *, struct ifmediareq *);
191188412Sthompsastatic int	axe_cmd(struct axe_softc *, int, int, int, void *);
192188412Sthompsastatic void	axe_ax88178_init(struct axe_softc *);
193188412Sthompsastatic void	axe_ax88772_init(struct axe_softc *);
194186730Salfredstatic int	axe_get_phyno(struct axe_softc *, int);
195184610Salfred
196192984Sthompsastatic const struct usb_config axe_config[AXE_N_TRANSFER] = {
197184610Salfred
198187259Sthompsa	[AXE_BULK_DT_WR] = {
199184610Salfred		.type = UE_BULK,
200184610Salfred		.endpoint = UE_ADDR_ANY,
201184610Salfred		.direction = UE_DIR_OUT,
202190734Sthompsa		.bufsize = AXE_BULK_BUF_SIZE,
203190734Sthompsa		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
204190734Sthompsa		.callback = axe_bulk_write_callback,
205190734Sthompsa		.timeout = 10000,	/* 10 seconds */
206184610Salfred	},
207184610Salfred
208187259Sthompsa	[AXE_BULK_DT_RD] = {
209184610Salfred		.type = UE_BULK,
210184610Salfred		.endpoint = UE_ADDR_ANY,
211184610Salfred		.direction = UE_DIR_IN,
212197566Sthompsa		.bufsize = 16384,	/* bytes */
213190734Sthompsa		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
214190734Sthompsa		.callback = axe_bulk_read_callback,
215190734Sthompsa		.timeout = 0,	/* no timeout */
216184610Salfred	},
217184610Salfred};
218184610Salfred
219184610Salfredstatic device_method_t axe_methods[] = {
220184610Salfred	/* Device interface */
221184610Salfred	DEVMETHOD(device_probe, axe_probe),
222184610Salfred	DEVMETHOD(device_attach, axe_attach),
223184610Salfred	DEVMETHOD(device_detach, axe_detach),
224184610Salfred
225184610Salfred	/* bus interface */
226184610Salfred	DEVMETHOD(bus_print_child, bus_generic_print_child),
227184610Salfred	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
228184610Salfred
229184610Salfred	/* MII interface */
230188412Sthompsa	DEVMETHOD(miibus_readreg, axe_miibus_readreg),
231188412Sthompsa	DEVMETHOD(miibus_writereg, axe_miibus_writereg),
232188412Sthompsa	DEVMETHOD(miibus_statchg, axe_miibus_statchg),
233184610Salfred
234184610Salfred	{0, 0}
235184610Salfred};
236184610Salfred
237184610Salfredstatic driver_t axe_driver = {
238184610Salfred	.name = "axe",
239184610Salfred	.methods = axe_methods,
240184610Salfred	.size = sizeof(struct axe_softc),
241184610Salfred};
242184610Salfred
243184610Salfredstatic devclass_t axe_devclass;
244184610Salfred
245189275SthompsaDRIVER_MODULE(axe, uhub, axe_driver, axe_devclass, NULL, 0);
246184610SalfredDRIVER_MODULE(miibus, axe, miibus_driver, miibus_devclass, 0, 0);
247188942SthompsaMODULE_DEPEND(axe, uether, 1, 1, 1);
248188942SthompsaMODULE_DEPEND(axe, usb, 1, 1, 1);
249188412SthompsaMODULE_DEPEND(axe, ether, 1, 1, 1);
250188412SthompsaMODULE_DEPEND(axe, miibus, 1, 1, 1);
251212122SthompsaMODULE_VERSION(axe, 1);
252184610Salfred
253192984Sthompsastatic const struct usb_ether_methods axe_ue_methods = {
254188412Sthompsa	.ue_attach_post = axe_attach_post,
255188412Sthompsa	.ue_start = axe_start,
256188412Sthompsa	.ue_init = axe_init,
257188412Sthompsa	.ue_stop = axe_stop,
258188412Sthompsa	.ue_tick = axe_tick,
259188412Sthompsa	.ue_setmulti = axe_setmulti,
260188412Sthompsa	.ue_setpromisc = axe_setpromisc,
261188412Sthompsa	.ue_mii_upd = axe_ifmedia_upd,
262188412Sthompsa	.ue_mii_sts = axe_ifmedia_sts,
263188412Sthompsa};
264188412Sthompsa
265188412Sthompsastatic int
266188412Sthompsaaxe_cmd(struct axe_softc *sc, int cmd, int index, int val, void *buf)
267184610Salfred{
268192984Sthompsa	struct usb_device_request req;
269193045Sthompsa	usb_error_t err;
270184610Salfred
271188412Sthompsa	AXE_LOCK_ASSERT(sc, MA_OWNED);
272188412Sthompsa
273184610Salfred	req.bmRequestType = (AXE_CMD_IS_WRITE(cmd) ?
274184610Salfred	    UT_WRITE_VENDOR_DEVICE :
275184610Salfred	    UT_READ_VENDOR_DEVICE);
276184610Salfred	req.bRequest = AXE_CMD_CMD(cmd);
277184610Salfred	USETW(req.wValue, val);
278184610Salfred	USETW(req.wIndex, index);
279188412Sthompsa	USETW(req.wLength, AXE_CMD_LEN(cmd));
280184610Salfred
281194228Sthompsa	err = uether_do_request(&sc->sc_ue, &req, buf, 1000);
282184610Salfred
283188412Sthompsa	return (err);
284184610Salfred}
285184610Salfred
286184610Salfredstatic int
287188412Sthompsaaxe_miibus_readreg(device_t dev, int phy, int reg)
288184610Salfred{
289184610Salfred	struct axe_softc *sc = device_get_softc(dev);
290184610Salfred	uint16_t val;
291188412Sthompsa	int locked;
292184610Salfred
293188412Sthompsa	if (sc->sc_phyno != phy)
294188412Sthompsa		return (0);
295184610Salfred
296188412Sthompsa	locked = mtx_owned(&sc->sc_mtx);
297188412Sthompsa	if (!locked)
298188412Sthompsa		AXE_LOCK(sc);
299186730Salfred
300188412Sthompsa	axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
301188412Sthompsa	axe_cmd(sc, AXE_CMD_MII_READ_REG, reg, phy, &val);
302188412Sthompsa	axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
303184610Salfred
304184610Salfred	val = le16toh(val);
305186730Salfred	if ((sc->sc_flags & AXE_FLAG_772) != 0 && reg == MII_BMSR) {
306186730Salfred		/*
307186730Salfred		 * BMSR of AX88772 indicates that it supports extended
308186730Salfred		 * capability but the extended status register is
309186730Salfred		 * revered for embedded ethernet PHY. So clear the
310186730Salfred		 * extended capability bit of BMSR.
311186730Salfred		 */
312186730Salfred		val &= ~BMSR_EXTCAP;
313186730Salfred	}
314184610Salfred
315188412Sthompsa	if (!locked)
316188412Sthompsa		AXE_UNLOCK(sc);
317184610Salfred	return (val);
318184610Salfred}
319184610Salfred
320184610Salfredstatic int
321188412Sthompsaaxe_miibus_writereg(device_t dev, int phy, int reg, int val)
322184610Salfred{
323184610Salfred	struct axe_softc *sc = device_get_softc(dev);
324188412Sthompsa	int locked;
325184610Salfred
326189522Sthompsa	val = htole32(val);
327184610Salfred
328186730Salfred	if (sc->sc_phyno != phy)
329188412Sthompsa		return (0);
330186730Salfred
331188412Sthompsa	locked = mtx_owned(&sc->sc_mtx);
332188412Sthompsa	if (!locked)
333188412Sthompsa		AXE_LOCK(sc);
334184610Salfred
335188412Sthompsa	axe_cmd(sc, AXE_CMD_MII_OPMODE_SW, 0, 0, NULL);
336188412Sthompsa	axe_cmd(sc, AXE_CMD_MII_WRITE_REG, reg, phy, &val);
337188412Sthompsa	axe_cmd(sc, AXE_CMD_MII_OPMODE_HW, 0, 0, NULL);
338188412Sthompsa
339188412Sthompsa	if (!locked)
340188412Sthompsa		AXE_UNLOCK(sc);
341184610Salfred	return (0);
342184610Salfred}
343184610Salfred
344184610Salfredstatic void
345188412Sthompsaaxe_miibus_statchg(device_t dev)
346184610Salfred{
347184610Salfred	struct axe_softc *sc = device_get_softc(dev);
348184610Salfred	struct mii_data *mii = GET_MII(sc);
349188553Sthompsa	struct ifnet *ifp;
350184610Salfred	uint16_t val;
351188412Sthompsa	int err, locked;
352184610Salfred
353188412Sthompsa	locked = mtx_owned(&sc->sc_mtx);
354188412Sthompsa	if (!locked)
355188412Sthompsa		AXE_LOCK(sc);
356184610Salfred
357194228Sthompsa	ifp = uether_getifp(&sc->sc_ue);
358188553Sthompsa	if (mii == NULL || ifp == NULL ||
359188553Sthompsa	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
360188553Sthompsa		goto done;
361188553Sthompsa
362188553Sthompsa	sc->sc_flags &= ~AXE_FLAG_LINK;
363188553Sthompsa	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
364188553Sthompsa	    (IFM_ACTIVE | IFM_AVALID)) {
365188553Sthompsa		switch (IFM_SUBTYPE(mii->mii_media_active)) {
366188553Sthompsa		case IFM_10_T:
367188553Sthompsa		case IFM_100_TX:
368188553Sthompsa			sc->sc_flags |= AXE_FLAG_LINK;
369188553Sthompsa			break;
370188553Sthompsa		case IFM_1000_T:
371188553Sthompsa			if ((sc->sc_flags & AXE_FLAG_178) == 0)
372188553Sthompsa				break;
373188553Sthompsa			sc->sc_flags |= AXE_FLAG_LINK;
374188553Sthompsa			break;
375188553Sthompsa		default:
376188553Sthompsa			break;
377188553Sthompsa		}
378188553Sthompsa	}
379188553Sthompsa
380188553Sthompsa	/* Lost link, do nothing. */
381188553Sthompsa	if ((sc->sc_flags & AXE_FLAG_LINK) == 0)
382188553Sthompsa		goto done;
383188553Sthompsa
384188553Sthompsa	val = 0;
385188553Sthompsa	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
386188553Sthompsa		val |= AXE_MEDIA_FULL_DUPLEX;
387186730Salfred	if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) {
388186730Salfred		val |= AXE_178_MEDIA_RX_EN | AXE_178_MEDIA_MAGIC;
389188553Sthompsa		if ((sc->sc_flags & AXE_FLAG_178) != 0)
390188553Sthompsa			val |= AXE_178_MEDIA_ENCK;
391184610Salfred		switch (IFM_SUBTYPE(mii->mii_media_active)) {
392184610Salfred		case IFM_1000_T:
393184610Salfred			val |= AXE_178_MEDIA_GMII | AXE_178_MEDIA_ENCK;
394184610Salfred			break;
395184610Salfred		case IFM_100_TX:
396184610Salfred			val |= AXE_178_MEDIA_100TX;
397184610Salfred			break;
398184610Salfred		case IFM_10_T:
399184610Salfred			/* doesn't need to be handled */
400184610Salfred			break;
401184610Salfred		}
402184610Salfred	}
403188412Sthompsa	err = axe_cmd(sc, AXE_CMD_WRITE_MEDIA, 0, val, NULL);
404188412Sthompsa	if (err)
405188412Sthompsa		device_printf(dev, "media change failed, error %d\n", err);
406188553Sthompsadone:
407188412Sthompsa	if (!locked)
408188412Sthompsa		AXE_UNLOCK(sc);
409184610Salfred}
410184610Salfred
411184610Salfred/*
412184610Salfred * Set media options.
413184610Salfred */
414184610Salfredstatic int
415188412Sthompsaaxe_ifmedia_upd(struct ifnet *ifp)
416184610Salfred{
417184610Salfred	struct axe_softc *sc = ifp->if_softc;
418184610Salfred	struct mii_data *mii = GET_MII(sc);
419188553Sthompsa	int error;
420184610Salfred
421188412Sthompsa	AXE_LOCK_ASSERT(sc, MA_OWNED);
422184610Salfred
423184610Salfred	if (mii->mii_instance) {
424184610Salfred		struct mii_softc *miisc;
425184610Salfred
426188412Sthompsa		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
427184610Salfred			mii_phy_reset(miisc);
428184610Salfred	}
429188553Sthompsa	error = mii_mediachg(mii);
430188553Sthompsa	return (error);
431184610Salfred}
432184610Salfred
433184610Salfred/*
434184610Salfred * Report current media status.
435184610Salfred */
436184610Salfredstatic void
437188412Sthompsaaxe_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
438184610Salfred{
439184610Salfred	struct axe_softc *sc = ifp->if_softc;
440188412Sthompsa	struct mii_data *mii = GET_MII(sc);
441184610Salfred
442188412Sthompsa	AXE_LOCK(sc);
443188412Sthompsa	mii_pollstat(mii);
444188412Sthompsa	AXE_UNLOCK(sc);
445188412Sthompsa	ifmr->ifm_active = mii->mii_media_active;
446188412Sthompsa	ifmr->ifm_status = mii->mii_media_status;
447184610Salfred}
448184610Salfred
449184610Salfredstatic void
450192984Sthompsaaxe_setmulti(struct usb_ether *ue)
451184610Salfred{
452194228Sthompsa	struct axe_softc *sc = uether_getsc(ue);
453194228Sthompsa	struct ifnet *ifp = uether_getifp(ue);
454188412Sthompsa	struct ifmultiaddr *ifma;
455188412Sthompsa	uint32_t h = 0;
456184610Salfred	uint16_t rxmode;
457188412Sthompsa	uint8_t hashtbl[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
458184610Salfred
459188412Sthompsa	AXE_LOCK_ASSERT(sc, MA_OWNED);
460184610Salfred
461188412Sthompsa	axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode);
462184610Salfred	rxmode = le16toh(rxmode);
463184610Salfred
464188412Sthompsa	if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) {
465184610Salfred		rxmode |= AXE_RXCMD_ALLMULTI;
466188412Sthompsa		axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
467184610Salfred		return;
468184610Salfred	}
469184610Salfred	rxmode &= ~AXE_RXCMD_ALLMULTI;
470184610Salfred
471195049Srwatson	if_maddr_rlock(ifp);
472188412Sthompsa	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
473188412Sthompsa	{
474188412Sthompsa		if (ifma->ifma_addr->sa_family != AF_LINK)
475188412Sthompsa			continue;
476188412Sthompsa		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
477188412Sthompsa		    ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
478188412Sthompsa		hashtbl[h / 8] |= 1 << (h % 8);
479188412Sthompsa	}
480195049Srwatson	if_maddr_runlock(ifp);
481184610Salfred
482188412Sthompsa	axe_cmd(sc, AXE_CMD_WRITE_MCAST, 0, 0, (void *)&hashtbl);
483188412Sthompsa	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
484184610Salfred}
485184610Salfred
486186730Salfredstatic int
487186730Salfredaxe_get_phyno(struct axe_softc *sc, int sel)
488186730Salfred{
489188412Sthompsa	int phyno;
490186730Salfred
491186730Salfred	switch (AXE_PHY_TYPE(sc->sc_phyaddrs[sel])) {
492186730Salfred	case PHY_TYPE_100_HOME:
493186730Salfred	case PHY_TYPE_GIG:
494188412Sthompsa		phyno = AXE_PHY_NO(sc->sc_phyaddrs[sel]);
495186730Salfred		break;
496186730Salfred	case PHY_TYPE_SPECIAL:
497186730Salfred		/* FALLTHROUGH */
498186730Salfred	case PHY_TYPE_RSVD:
499186730Salfred		/* FALLTHROUGH */
500186730Salfred	case PHY_TYPE_NON_SUP:
501186730Salfred		/* FALLTHROUGH */
502186730Salfred	default:
503186730Salfred		phyno = -1;
504186730Salfred		break;
505186730Salfred	}
506186730Salfred
507186730Salfred	return (phyno);
508186730Salfred}
509186730Salfred
510212130Sthompsa#define	AXE_GPIO_WRITE(x, y)	do {				\
511212130Sthompsa	axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, (x), NULL);		\
512212130Sthompsa	uether_pause(ue, (y));					\
513212130Sthompsa} while (0)
514212130Sthompsa
515184610Salfredstatic void
516188412Sthompsaaxe_ax88178_init(struct axe_softc *sc)
517184610Salfred{
518212130Sthompsa	struct usb_ether *ue;
519212130Sthompsa	int gpio0, phymode;
520212130Sthompsa	uint16_t eeprom, val;
521184610Salfred
522212130Sthompsa	ue = &sc->sc_ue;
523188412Sthompsa	axe_cmd(sc, AXE_CMD_SROM_WR_ENABLE, 0, 0, NULL);
524184610Salfred	/* XXX magic */
525188412Sthompsa	axe_cmd(sc, AXE_CMD_SROM_READ, 0, 0x0017, &eeprom);
526184610Salfred	eeprom = le16toh(eeprom);
527188412Sthompsa	axe_cmd(sc, AXE_CMD_SROM_WR_DISABLE, 0, 0, NULL);
528184610Salfred
529184610Salfred	/* if EEPROM is invalid we have to use to GPIO0 */
530184610Salfred	if (eeprom == 0xffff) {
531212130Sthompsa		phymode = AXE_PHY_MODE_MARVELL;
532184610Salfred		gpio0 = 1;
533184610Salfred	} else {
534212130Sthompsa		phymode = eeprom & 0x7f;
535184610Salfred		gpio0 = (eeprom & 0x80) ? 0 : 1;
536184610Salfred	}
537184610Salfred
538212130Sthompsa	if (bootverbose)
539215960Syongari		device_printf(sc->sc_ue.ue_dev,
540215960Syongari		    "EEPROM data : 0x%04x, phymode : 0x%02x\n", eeprom,
541215960Syongari		    phymode);
542212130Sthompsa	/* Program GPIOs depending on PHY hardware. */
543212130Sthompsa	switch (phymode) {
544212130Sthompsa	case AXE_PHY_MODE_MARVELL:
545212130Sthompsa		if (gpio0 == 1) {
546212130Sthompsa			AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0_EN,
547212130Sthompsa			    hz / 32);
548212130Sthompsa			AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN,
549212130Sthompsa			    hz / 32);
550212130Sthompsa			AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2_EN, hz / 4);
551212130Sthompsa			AXE_GPIO_WRITE(AXE_GPIO0_EN | AXE_GPIO2 | AXE_GPIO2_EN,
552212130Sthompsa			    hz / 32);
553212130Sthompsa		} else
554212130Sthompsa			AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 |
555212130Sthompsa			    AXE_GPIO1_EN, hz / 32);
556212130Sthompsa		break;
557212130Sthompsa	case AXE_PHY_MODE_CICADA:
558215960Syongari	case AXE_PHY_MODE_CICADA_V2:
559215960Syongari	case AXE_PHY_MODE_CICADA_V2_ASIX:
560212130Sthompsa		if (gpio0 == 1)
561212130Sthompsa			AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO0 |
562212130Sthompsa			    AXE_GPIO0_EN, hz / 32);
563212130Sthompsa		else
564212130Sthompsa			AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 |
565212130Sthompsa			    AXE_GPIO1_EN, hz / 32);
566212130Sthompsa		break;
567212130Sthompsa	case AXE_PHY_MODE_AGERE:
568212130Sthompsa		AXE_GPIO_WRITE(AXE_GPIO_RELOAD_EEPROM | AXE_GPIO1 |
569212130Sthompsa		    AXE_GPIO1_EN, hz / 32);
570212130Sthompsa		AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 |
571212130Sthompsa		    AXE_GPIO2_EN, hz / 32);
572212130Sthompsa		AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2_EN, hz / 4);
573212130Sthompsa		AXE_GPIO_WRITE(AXE_GPIO1 | AXE_GPIO1_EN | AXE_GPIO2 |
574212130Sthompsa		    AXE_GPIO2_EN, hz / 32);
575212130Sthompsa		break;
576212130Sthompsa	case AXE_PHY_MODE_REALTEK_8211CL:
577212130Sthompsa	case AXE_PHY_MODE_REALTEK_8211BN:
578212130Sthompsa	case AXE_PHY_MODE_REALTEK_8251CL:
579212130Sthompsa		val = gpio0 == 1 ? AXE_GPIO0 | AXE_GPIO0_EN :
580212130Sthompsa		    AXE_GPIO1 | AXE_GPIO1_EN;
581212130Sthompsa		AXE_GPIO_WRITE(val, hz / 32);
582212130Sthompsa		AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32);
583212130Sthompsa		AXE_GPIO_WRITE(val | AXE_GPIO2_EN, hz / 4);
584212130Sthompsa		AXE_GPIO_WRITE(val | AXE_GPIO2 | AXE_GPIO2_EN, hz / 32);
585212130Sthompsa		if (phymode == AXE_PHY_MODE_REALTEK_8211CL) {
586212130Sthompsa			axe_miibus_writereg(ue->ue_dev, sc->sc_phyno,
587212130Sthompsa			    0x1F, 0x0005);
588212130Sthompsa			axe_miibus_writereg(ue->ue_dev, sc->sc_phyno,
589212130Sthompsa			    0x0C, 0x0000);
590212130Sthompsa			val = axe_miibus_readreg(ue->ue_dev, sc->sc_phyno,
591212130Sthompsa			    0x0001);
592212130Sthompsa			axe_miibus_writereg(ue->ue_dev, sc->sc_phyno,
593212130Sthompsa			    0x01, val | 0x0080);
594212130Sthompsa			axe_miibus_writereg(ue->ue_dev, sc->sc_phyno,
595212130Sthompsa			    0x1F, 0x0000);
596212130Sthompsa		}
597212130Sthompsa		break;
598212130Sthompsa	default:
599212130Sthompsa		/* Unknown PHY model or no need to program GPIOs. */
600212130Sthompsa		break;
601184610Salfred	}
602184610Salfred
603184610Salfred	/* soft reset */
604188412Sthompsa	axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_CLEAR, NULL);
605212130Sthompsa	uether_pause(ue, hz / 4);
606184610Salfred
607188412Sthompsa	axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
608184610Salfred	    AXE_SW_RESET_PRL | AXE_178_RESET_MAGIC, NULL);
609212130Sthompsa	uether_pause(ue, hz / 4);
610186730Salfred	/* Enable MII/GMII/RGMII interface to work with external PHY. */
611188412Sthompsa	axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0, NULL);
612212130Sthompsa	uether_pause(ue, hz / 4);
613184610Salfred
614188412Sthompsa	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
615184610Salfred}
616212130Sthompsa#undef	AXE_GPIO_WRITE
617184610Salfred
618184610Salfredstatic void
619188412Sthompsaaxe_ax88772_init(struct axe_softc *sc)
620184610Salfred{
621188412Sthompsa	axe_cmd(sc, AXE_CMD_WRITE_GPIO, 0, 0x00b0, NULL);
622194228Sthompsa	uether_pause(&sc->sc_ue, hz / 16);
623184610Salfred
624186730Salfred	if (sc->sc_phyno == AXE_772_PHY_NO_EPHY) {
625184610Salfred		/* ask for the embedded PHY */
626188412Sthompsa		axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x01, NULL);
627194228Sthompsa		uether_pause(&sc->sc_ue, hz / 64);
628184610Salfred
629184610Salfred		/* power down and reset state, pin reset state */
630188412Sthompsa		axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
631184610Salfred		    AXE_SW_RESET_CLEAR, NULL);
632194228Sthompsa		uether_pause(&sc->sc_ue, hz / 16);
633184610Salfred
634184610Salfred		/* power down/reset state, pin operating state */
635188412Sthompsa		axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
636184610Salfred		    AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
637194228Sthompsa		uether_pause(&sc->sc_ue, hz / 4);
638184610Salfred
639184610Salfred		/* power up, reset */
640188412Sthompsa		axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0, AXE_SW_RESET_PRL, NULL);
641184610Salfred
642184610Salfred		/* power up, operating */
643188412Sthompsa		axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
644184610Salfred		    AXE_SW_RESET_IPRL | AXE_SW_RESET_PRL, NULL);
645184610Salfred	} else {
646184610Salfred		/* ask for external PHY */
647188412Sthompsa		axe_cmd(sc, AXE_CMD_SW_PHY_SELECT, 0, 0x00, NULL);
648194228Sthompsa		uether_pause(&sc->sc_ue, hz / 64);
649184610Salfred
650184610Salfred		/* power down internal PHY */
651188412Sthompsa		axe_cmd(sc, AXE_CMD_SW_RESET_REG, 0,
652184610Salfred		    AXE_SW_RESET_IPPD | AXE_SW_RESET_PRL, NULL);
653184610Salfred	}
654184610Salfred
655194228Sthompsa	uether_pause(&sc->sc_ue, hz / 4);
656188412Sthompsa	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, 0, NULL);
657184610Salfred}
658184610Salfred
659184610Salfredstatic void
660188412Sthompsaaxe_reset(struct axe_softc *sc)
661184610Salfred{
662192984Sthompsa	struct usb_config_descriptor *cd;
663193045Sthompsa	usb_error_t err;
664184610Salfred
665194228Sthompsa	cd = usbd_get_config_descriptor(sc->sc_ue.ue_udev);
666184610Salfred
667194228Sthompsa	err = usbd_req_set_config(sc->sc_ue.ue_udev, &sc->sc_mtx,
668188412Sthompsa	    cd->bConfigurationValue);
669188412Sthompsa	if (err)
670188412Sthompsa		DPRINTF("reset failed (ignored)\n");
671188412Sthompsa
672188412Sthompsa	/* Wait a little while for the chip to get its brains in order. */
673194228Sthompsa	uether_pause(&sc->sc_ue, hz / 100);
674188412Sthompsa}
675188412Sthompsa
676188412Sthompsastatic void
677192984Sthompsaaxe_attach_post(struct usb_ether *ue)
678188412Sthompsa{
679194228Sthompsa	struct axe_softc *sc = uether_getsc(ue);
680188412Sthompsa
681184610Salfred	/*
682184610Salfred	 * Load PHY indexes first. Needed by axe_xxx_init().
683184610Salfred	 */
684188412Sthompsa	axe_cmd(sc, AXE_CMD_READ_PHYID, 0, 0, sc->sc_phyaddrs);
685212130Sthompsa	if (bootverbose)
686212130Sthompsa		device_printf(sc->sc_ue.ue_dev, "PHYADDR 0x%02x:0x%02x\n",
687212130Sthompsa		    sc->sc_phyaddrs[0], sc->sc_phyaddrs[1]);
688186730Salfred	sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_PRI);
689186730Salfred	if (sc->sc_phyno == -1)
690186730Salfred		sc->sc_phyno = axe_get_phyno(sc, AXE_PHY_SEL_SEC);
691186730Salfred	if (sc->sc_phyno == -1) {
692188412Sthompsa		device_printf(sc->sc_ue.ue_dev,
693188412Sthompsa		    "no valid PHY address found, assuming PHY address 0\n");
694186730Salfred		sc->sc_phyno = 0;
695186730Salfred	}
696184610Salfred
697188412Sthompsa	if (sc->sc_flags & AXE_FLAG_178)
698188412Sthompsa		axe_ax88178_init(sc);
699188412Sthompsa	else if (sc->sc_flags & AXE_FLAG_772)
700188412Sthompsa		axe_ax88772_init(sc);
701188412Sthompsa
702184610Salfred	/*
703184610Salfred	 * Get station address.
704184610Salfred	 */
705184610Salfred	if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772))
706188412Sthompsa		axe_cmd(sc, AXE_178_CMD_READ_NODEID, 0, 0, ue->ue_eaddr);
707184610Salfred	else
708188412Sthompsa		axe_cmd(sc, AXE_172_CMD_READ_NODEID, 0, 0, ue->ue_eaddr);
709184610Salfred
710184610Salfred	/*
711184610Salfred	 * Fetch IPG values.
712184610Salfred	 */
713188412Sthompsa	axe_cmd(sc, AXE_CMD_READ_IPG012, 0, 0, sc->sc_ipgs);
714188412Sthompsa}
715184610Salfred
716188412Sthompsa/*
717188412Sthompsa * Probe for a AX88172 chip.
718188412Sthompsa */
719188412Sthompsastatic int
720188412Sthompsaaxe_probe(device_t dev)
721188412Sthompsa{
722192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
723184610Salfred
724192499Sthompsa	if (uaa->usb_mode != USB_MODE_HOST)
725188412Sthompsa		return (ENXIO);
726188412Sthompsa	if (uaa->info.bConfigIndex != AXE_CONFIG_IDX)
727188412Sthompsa		return (ENXIO);
728188412Sthompsa	if (uaa->info.bIfaceIndex != AXE_IFACE_IDX)
729188412Sthompsa		return (ENXIO);
730184610Salfred
731194228Sthompsa	return (usbd_lookup_id_by_uaa(axe_devs, sizeof(axe_devs), uaa));
732188412Sthompsa}
733184610Salfred
734188412Sthompsa/*
735188412Sthompsa * Attach the interface. Allocate softc structures, do ifmedia
736188412Sthompsa * setup and ethernet/BPF attach.
737188412Sthompsa */
738188412Sthompsastatic int
739188412Sthompsaaxe_attach(device_t dev)
740188412Sthompsa{
741192984Sthompsa	struct usb_attach_arg *uaa = device_get_ivars(dev);
742188412Sthompsa	struct axe_softc *sc = device_get_softc(dev);
743192984Sthompsa	struct usb_ether *ue = &sc->sc_ue;
744188412Sthompsa	uint8_t iface_index;
745188412Sthompsa	int error;
746184610Salfred
747188412Sthompsa	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
748184610Salfred
749194228Sthompsa	device_set_usb_desc(dev);
750184610Salfred
751188412Sthompsa	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
752184610Salfred
753188412Sthompsa	iface_index = AXE_IFACE_IDX;
754194228Sthompsa	error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
755188412Sthompsa	    axe_config, AXE_N_TRANSFER, sc, &sc->sc_mtx);
756188412Sthompsa	if (error) {
757199816Sthompsa		device_printf(dev, "allocating USB transfers failed\n");
758188412Sthompsa		goto detach;
759188412Sthompsa	}
760184610Salfred
761188412Sthompsa	ue->ue_sc = sc;
762188412Sthompsa	ue->ue_dev = dev;
763188412Sthompsa	ue->ue_udev = uaa->device;
764188412Sthompsa	ue->ue_mtx = &sc->sc_mtx;
765188412Sthompsa	ue->ue_methods = &axe_ue_methods;
766184610Salfred
767194228Sthompsa	error = uether_ifattach(ue);
768184610Salfred	if (error) {
769188412Sthompsa		device_printf(dev, "could not attach interface\n");
770188412Sthompsa		goto detach;
771184610Salfred	}
772188412Sthompsa	return (0);			/* success */
773184610Salfred
774188412Sthompsadetach:
775188412Sthompsa	axe_detach(dev);
776188412Sthompsa	return (ENXIO);			/* failure */
777184610Salfred}
778184610Salfred
779184610Salfredstatic int
780184610Salfredaxe_detach(device_t dev)
781184610Salfred{
782184610Salfred	struct axe_softc *sc = device_get_softc(dev);
783192984Sthompsa	struct usb_ether *ue = &sc->sc_ue;
784184610Salfred
785194228Sthompsa	usbd_transfer_unsetup(sc->sc_xfer, AXE_N_TRANSFER);
786194228Sthompsa	uether_ifdetach(ue);
787184610Salfred	mtx_destroy(&sc->sc_mtx);
788184610Salfred
789184610Salfred	return (0);
790184610Salfred}
791184610Salfred
792184610Salfred#if (AXE_BULK_BUF_SIZE >= 0x10000)
793184610Salfred#error "Please update axe_bulk_read_callback()!"
794184610Salfred#endif
795184610Salfred
796184610Salfredstatic void
797194677Sthompsaaxe_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
798184610Salfred{
799194677Sthompsa	struct axe_softc *sc = usbd_xfer_softc(xfer);
800192984Sthompsa	struct usb_ether *ue = &sc->sc_ue;
801194228Sthompsa	struct ifnet *ifp = uether_getifp(ue);
802184610Salfred	struct axe_sframe_hdr hdr;
803194677Sthompsa	struct usb_page_cache *pc;
804197566Sthompsa	int err, pos, len;
805194677Sthompsa	int actlen;
806184610Salfred
807194677Sthompsa	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
808194677Sthompsa
809184610Salfred	switch (USB_GET_STATE(xfer)) {
810184610Salfred	case USB_ST_TRANSFERRED:
811184610Salfred		pos = 0;
812197566Sthompsa		len = 0;
813197566Sthompsa		err = 0;
814197566Sthompsa
815194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
816197566Sthompsa		if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) {
817197566Sthompsa			while (pos < actlen) {
818197566Sthompsa				if ((pos + sizeof(hdr)) > actlen) {
819184610Salfred					/* too little data */
820197566Sthompsa					err = EINVAL;
821184610Salfred					break;
822184610Salfred				}
823194677Sthompsa				usbd_copy_out(pc, pos, &hdr, sizeof(hdr));
824184610Salfred
825184610Salfred				if ((hdr.len ^ hdr.ilen) != 0xFFFF) {
826184610Salfred					/* we lost sync */
827197566Sthompsa					err = EINVAL;
828184610Salfred					break;
829184610Salfred				}
830184610Salfred				pos += sizeof(hdr);
831184610Salfred
832184610Salfred				len = le16toh(hdr.len);
833197566Sthompsa				if ((pos + len) > actlen) {
834184610Salfred					/* invalid length */
835197566Sthompsa					err = EINVAL;
836184610Salfred					break;
837184610Salfred				}
838213436Syongari				uether_rxbuf(ue, pc, pos, len);
839184610Salfred
840197566Sthompsa				pos += len + (len % 2);
841184610Salfred			}
842213436Syongari		} else
843213436Syongari			uether_rxbuf(ue, pc, 0, actlen);
844184610Salfred
845197566Sthompsa		if (err != 0)
846197566Sthompsa			ifp->if_ierrors++;
847184610Salfred
848188412Sthompsa		/* FALLTHROUGH */
849184610Salfred	case USB_ST_SETUP:
850184610Salfredtr_setup:
851194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
852194228Sthompsa		usbd_transfer_submit(xfer);
853194228Sthompsa		uether_rxflush(ue);
854184610Salfred		return;
855184610Salfred
856184610Salfred	default:			/* Error */
857194677Sthompsa		DPRINTF("bulk read error, %s\n", usbd_errstr(error));
858188412Sthompsa
859194677Sthompsa		if (error != USB_ERR_CANCELLED) {
860184610Salfred			/* try to clear stall first */
861194677Sthompsa			usbd_xfer_set_stall(xfer);
862188412Sthompsa			goto tr_setup;
863184610Salfred		}
864184610Salfred		return;
865184610Salfred
866184610Salfred	}
867184610Salfred}
868184610Salfred
869184610Salfred#if ((AXE_BULK_BUF_SIZE >= 0x10000) || (AXE_BULK_BUF_SIZE < (MCLBYTES+4)))
870184610Salfred#error "Please update axe_bulk_write_callback()!"
871184610Salfred#endif
872184610Salfred
873184610Salfredstatic void
874194677Sthompsaaxe_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
875184610Salfred{
876194677Sthompsa	struct axe_softc *sc = usbd_xfer_softc(xfer);
877184610Salfred	struct axe_sframe_hdr hdr;
878194228Sthompsa	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
879194677Sthompsa	struct usb_page_cache *pc;
880184610Salfred	struct mbuf *m;
881188412Sthompsa	int pos;
882184610Salfred
883184610Salfred	switch (USB_GET_STATE(xfer)) {
884184610Salfred	case USB_ST_TRANSFERRED:
885184610Salfred		DPRINTFN(11, "transfer complete\n");
886213424Syongari		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
887188412Sthompsa		/* FALLTHROUGH */
888184610Salfred	case USB_ST_SETUP:
889188412Sthompsatr_setup:
890213424Syongari		if ((sc->sc_flags & AXE_FLAG_LINK) == 0 ||
891213424Syongari		    (ifp->if_drv_flags & IFF_DRV_OACTIVE) != 0) {
892184610Salfred			/*
893213424Syongari			 * Don't send anything if there is no link or
894213424Syongari			 * controller is busy.
895184610Salfred			 */
896188412Sthompsa			return;
897184610Salfred		}
898184610Salfred		pos = 0;
899194677Sthompsa		pc = usbd_xfer_get_frame(xfer, 0);
900184610Salfred
901184610Salfred		while (1) {
902184610Salfred
903184610Salfred			IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
904184610Salfred
905184610Salfred			if (m == NULL) {
906184610Salfred				if (pos > 0)
907184610Salfred					break;	/* send out data */
908188412Sthompsa				return;
909184610Salfred			}
910184610Salfred			if (m->m_pkthdr.len > MCLBYTES) {
911184610Salfred				m->m_pkthdr.len = MCLBYTES;
912184610Salfred			}
913184610Salfred			if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) {
914184610Salfred
915184610Salfred				hdr.len = htole16(m->m_pkthdr.len);
916184610Salfred				hdr.ilen = ~hdr.len;
917184610Salfred
918194677Sthompsa				usbd_copy_in(pc, pos, &hdr, sizeof(hdr));
919184610Salfred
920184610Salfred				pos += sizeof(hdr);
921184610Salfred
922184610Salfred				/*
923184610Salfred				 * NOTE: Some drivers force a short packet
924184610Salfred				 * by appending a dummy header with zero
925184610Salfred				 * length at then end of the USB transfer.
926184610Salfred				 * This driver uses the
927184610Salfred				 * USB_FORCE_SHORT_XFER flag instead.
928184610Salfred				 */
929184610Salfred			}
930194677Sthompsa			usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len);
931184610Salfred			pos += m->m_pkthdr.len;
932184610Salfred
933184610Salfred			/*
934213423Syongari			 * XXX
935213423Syongari			 * Update TX packet counter here. This is not
936213423Syongari			 * correct way but it seems that there is no way
937213423Syongari			 * to know how many packets are sent at the end
938213423Syongari			 * of transfer because controller combines
939213423Syongari			 * multiple writes into single one if there is
940213423Syongari			 * room in TX buffer of controller.
941213423Syongari			 */
942213423Syongari			ifp->if_opackets++;
943213423Syongari
944213423Syongari			/*
945188412Sthompsa			 * if there's a BPF listener, bounce a copy
946188412Sthompsa			 * of this frame to him:
947188412Sthompsa			 */
948184610Salfred			BPF_MTAP(ifp, m);
949184610Salfred
950184610Salfred			m_freem(m);
951184610Salfred
952184610Salfred			if (sc->sc_flags & (AXE_FLAG_772 | AXE_FLAG_178)) {
953184610Salfred				if (pos > (AXE_BULK_BUF_SIZE - MCLBYTES - sizeof(hdr))) {
954184610Salfred					/* send out frame(s) */
955184610Salfred					break;
956184610Salfred				}
957184610Salfred			} else {
958184610Salfred				/* send out frame */
959184610Salfred				break;
960184610Salfred			}
961184610Salfred		}
962184610Salfred
963194677Sthompsa		usbd_xfer_set_frame_len(xfer, 0, pos);
964194228Sthompsa		usbd_transfer_submit(xfer);
965213424Syongari		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
966184610Salfred		return;
967184610Salfred
968184610Salfred	default:			/* Error */
969184610Salfred		DPRINTFN(11, "transfer error, %s\n",
970194677Sthompsa		    usbd_errstr(error));
971184610Salfred
972188412Sthompsa		ifp->if_oerrors++;
973213424Syongari		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
974188412Sthompsa
975194677Sthompsa		if (error != USB_ERR_CANCELLED) {
976184610Salfred			/* try to clear stall first */
977194677Sthompsa			usbd_xfer_set_stall(xfer);
978188412Sthompsa			goto tr_setup;
979184610Salfred		}
980184610Salfred		return;
981184610Salfred
982184610Salfred	}
983184610Salfred}
984184610Salfred
985184610Salfredstatic void
986192984Sthompsaaxe_tick(struct usb_ether *ue)
987184610Salfred{
988194228Sthompsa	struct axe_softc *sc = uether_getsc(ue);
989184610Salfred	struct mii_data *mii = GET_MII(sc);
990184610Salfred
991188412Sthompsa	AXE_LOCK_ASSERT(sc, MA_OWNED);
992188412Sthompsa
993184610Salfred	mii_tick(mii);
994188553Sthompsa	if ((sc->sc_flags & AXE_FLAG_LINK) == 0) {
995188553Sthompsa		axe_miibus_statchg(ue->ue_dev);
996188553Sthompsa		if ((sc->sc_flags & AXE_FLAG_LINK) != 0)
997188553Sthompsa			axe_start(ue);
998186730Salfred	}
999184610Salfred}
1000184610Salfred
1001184610Salfredstatic void
1002192984Sthompsaaxe_start(struct usb_ether *ue)
1003184610Salfred{
1004194228Sthompsa	struct axe_softc *sc = uether_getsc(ue);
1005184610Salfred
1006188412Sthompsa	/*
1007188412Sthompsa	 * start the USB transfers, if not already started:
1008188412Sthompsa	 */
1009194228Sthompsa	usbd_transfer_start(sc->sc_xfer[AXE_BULK_DT_RD]);
1010194228Sthompsa	usbd_transfer_start(sc->sc_xfer[AXE_BULK_DT_WR]);
1011184610Salfred}
1012184610Salfred
1013184610Salfredstatic void
1014192984Sthompsaaxe_init(struct usb_ether *ue)
1015184610Salfred{
1016194228Sthompsa	struct axe_softc *sc = uether_getsc(ue);
1017194228Sthompsa	struct ifnet *ifp = uether_getifp(ue);
1018184610Salfred	uint16_t rxmode;
1019184610Salfred
1020188412Sthompsa	AXE_LOCK_ASSERT(sc, MA_OWNED);
1021184610Salfred
1022215963Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
1023215963Syongari		return;
1024215963Syongari
1025188412Sthompsa	/* Cancel pending I/O */
1026188412Sthompsa	axe_stop(ue);
1027184610Salfred
1028215962Syongari	axe_reset(sc);
1029215962Syongari
1030197567Sthompsa	/* Set MAC address. */
1031197567Sthompsa	if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772))
1032197567Sthompsa		axe_cmd(sc, AXE_178_CMD_WRITE_NODEID, 0, 0, IF_LLADDR(ifp));
1033197567Sthompsa	else
1034197567Sthompsa		axe_cmd(sc, AXE_172_CMD_WRITE_NODEID, 0, 0, IF_LLADDR(ifp));
1035184610Salfred
1036184610Salfred	/* Set transmitter IPG values */
1037184610Salfred	if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) {
1038188412Sthompsa		axe_cmd(sc, AXE_178_CMD_WRITE_IPG012, sc->sc_ipgs[2],
1039184610Salfred		    (sc->sc_ipgs[1] << 8) | (sc->sc_ipgs[0]), NULL);
1040184610Salfred	} else {
1041188412Sthompsa		axe_cmd(sc, AXE_172_CMD_WRITE_IPG0, 0, sc->sc_ipgs[0], NULL);
1042188412Sthompsa		axe_cmd(sc, AXE_172_CMD_WRITE_IPG1, 0, sc->sc_ipgs[1], NULL);
1043188412Sthompsa		axe_cmd(sc, AXE_172_CMD_WRITE_IPG2, 0, sc->sc_ipgs[2], NULL);
1044184610Salfred	}
1045184610Salfred
1046184610Salfred	/* Enable receiver, set RX mode */
1047184610Salfred	rxmode = (AXE_RXCMD_MULTICAST | AXE_RXCMD_ENABLE);
1048184610Salfred	if (sc->sc_flags & (AXE_FLAG_178 | AXE_FLAG_772)) {
1049197566Sthompsa#if 0
1050184610Salfred		rxmode |= AXE_178_RXCMD_MFB_2048;	/* chip default */
1051197566Sthompsa#else
1052197566Sthompsa		/*
1053197566Sthompsa		 * Default Rx buffer size is too small to get
1054197566Sthompsa		 * maximum performance.
1055197566Sthompsa		 */
1056197566Sthompsa		rxmode |= AXE_178_RXCMD_MFB_16384;
1057197566Sthompsa#endif
1058184610Salfred	} else {
1059184610Salfred		rxmode |= AXE_172_RXCMD_UNICAST;
1060184610Salfred	}
1061184610Salfred
1062184610Salfred	/* If we want promiscuous mode, set the allframes bit. */
1063188412Sthompsa	if (ifp->if_flags & IFF_PROMISC)
1064184610Salfred		rxmode |= AXE_RXCMD_PROMISC;
1065188412Sthompsa
1066188412Sthompsa	if (ifp->if_flags & IFF_BROADCAST)
1067184610Salfred		rxmode |= AXE_RXCMD_BROADCAST;
1068184610Salfred
1069188412Sthompsa	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
1070188412Sthompsa
1071184610Salfred	/* Load the multicast filter. */
1072188412Sthompsa	axe_setmulti(ue);
1073184610Salfred
1074194677Sthompsa	usbd_xfer_set_stall(sc->sc_xfer[AXE_BULK_DT_WR]);
1075184610Salfred
1076188412Sthompsa	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1077215964Syongari	/* Switch to selected media. */
1078215964Syongari	axe_ifmedia_upd(ifp);
1079188412Sthompsa	axe_start(ue);
1080184610Salfred}
1081184610Salfred
1082184610Salfredstatic void
1083192984Sthompsaaxe_setpromisc(struct usb_ether *ue)
1084184610Salfred{
1085194228Sthompsa	struct axe_softc *sc = uether_getsc(ue);
1086194228Sthompsa	struct ifnet *ifp = uether_getifp(ue);
1087184610Salfred	uint16_t rxmode;
1088184610Salfred
1089188412Sthompsa	axe_cmd(sc, AXE_CMD_RXCTL_READ, 0, 0, &rxmode);
1090184610Salfred
1091184610Salfred	rxmode = le16toh(rxmode);
1092184610Salfred
1093188412Sthompsa	if (ifp->if_flags & IFF_PROMISC) {
1094184610Salfred		rxmode |= AXE_RXCMD_PROMISC;
1095184610Salfred	} else {
1096184610Salfred		rxmode &= ~AXE_RXCMD_PROMISC;
1097184610Salfred	}
1098184610Salfred
1099188412Sthompsa	axe_cmd(sc, AXE_CMD_RXCTL_WRITE, 0, rxmode, NULL);
1100184610Salfred
1101188412Sthompsa	axe_setmulti(ue);
1102184610Salfred}
1103184610Salfred
1104184610Salfredstatic void
1105192984Sthompsaaxe_stop(struct usb_ether *ue)
1106184610Salfred{
1107194228Sthompsa	struct axe_softc *sc = uether_getsc(ue);
1108194228Sthompsa	struct ifnet *ifp = uether_getifp(ue);
1109184610Salfred
1110188412Sthompsa	AXE_LOCK_ASSERT(sc, MA_OWNED);
1111184610Salfred
1112213424Syongari	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1113186730Salfred	sc->sc_flags &= ~AXE_FLAG_LINK;
1114184610Salfred
1115184610Salfred	/*
1116184610Salfred	 * stop all the transfers, if not already stopped:
1117184610Salfred	 */
1118194228Sthompsa	usbd_transfer_stop(sc->sc_xfer[AXE_BULK_DT_WR]);
1119194228Sthompsa	usbd_transfer_stop(sc->sc_xfer[AXE_BULK_DT_RD]);
1120184610Salfred}
1121