if_rue.c revision 187259
1184610Salfred/*-
2184610Salfred * Copyright (c) 2001-2003, Shunsuke Akiyama <akiyama@FreeBSD.org>.
3184610Salfred * Copyright (c) 1997, 1998, 1999, 2000 Bill Paul <wpaul@ee.columbia.edu>.
4184610Salfred * All rights reserved.
5184610Salfred *
6184610Salfred * Redistribution and use in source and binary forms, with or without
7184610Salfred * modification, are permitted provided that the following conditions
8184610Salfred * are met:
9184610Salfred * 1. Redistributions of source code must retain the above copyright
10184610Salfred *    notice, this list of conditions and the following disclaimer.
11184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
12184610Salfred *    notice, this list of conditions and the following disclaimer in the
13184610Salfred *    documentation and/or other materials provided with the distribution.
14184610Salfred *
15184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25184610Salfred * SUCH DAMAGE.
26184610Salfred */
27184610Salfred/*-
28184610Salfred * Copyright (c) 1997, 1998, 1999, 2000
29184610Salfred *	Bill Paul <wpaul@ee.columbia.edu>.  All rights reserved.
30184610Salfred *
31184610Salfred * Redistribution and use in source and binary forms, with or without
32184610Salfred * modification, are permitted provided that the following conditions
33184610Salfred * are met:
34184610Salfred * 1. Redistributions of source code must retain the above copyright
35184610Salfred *    notice, this list of conditions and the following disclaimer.
36184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
37184610Salfred *    notice, this list of conditions and the following disclaimer in the
38184610Salfred *    documentation and/or other materials provided with the distribution.
39184610Salfred * 3. All advertising materials mentioning features or use of this software
40184610Salfred *    must display the following acknowledgement:
41184610Salfred *	This product includes software developed by Bill Paul.
42184610Salfred * 4. Neither the name of the author nor the names of any co-contributors
43184610Salfred *    may be used to endorse or promote products derived from this software
44184610Salfred *    without specific prior written permission.
45184610Salfred *
46184610Salfred * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
47184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
50184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
51184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
52184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
53184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
54184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
56184610Salfred * THE POSSIBILITY OF SUCH DAMAGE.
57184610Salfred */
58184610Salfred
59184610Salfred#include <sys/cdefs.h>
60184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb2/ethernet/if_rue2.c 187259 2009-01-15 02:35:40Z thompsa $");
61184610Salfred
62184610Salfred/*
63184610Salfred * RealTek RTL8150 USB to fast ethernet controller driver.
64184610Salfred * Datasheet is available from
65184610Salfred * ftp://ftp.realtek.com.tw/lancard/data_sheet/8150/.
66184610Salfred */
67184610Salfred
68184610Salfred/*
69184610Salfred * NOTE: all function names beginning like "rue_cfg_" can only
70184610Salfred * be called from within the config thread function !
71184610Salfred */
72184610Salfred
73184610Salfred#include <dev/usb2/include/usb2_devid.h>
74184610Salfred#include <dev/usb2/include/usb2_standard.h>
75184610Salfred#include <dev/usb2/include/usb2_mfunc.h>
76184610Salfred#include <dev/usb2/include/usb2_error.h>
77184610Salfred
78184610Salfred#define	usb2_config_td_cc usb2_ether_cc
79184610Salfred#define	usb2_config_td_softc rue_softc
80184610Salfred
81184610Salfred#define	USB_DEBUG_VAR rue_debug
82184610Salfred
83184610Salfred#include <dev/usb2/core/usb2_core.h>
84184610Salfred#include <dev/usb2/core/usb2_lookup.h>
85184610Salfred#include <dev/usb2/core/usb2_process.h>
86184610Salfred#include <dev/usb2/core/usb2_config_td.h>
87184610Salfred#include <dev/usb2/core/usb2_debug.h>
88184610Salfred#include <dev/usb2/core/usb2_request.h>
89184610Salfred#include <dev/usb2/core/usb2_busdma.h>
90184610Salfred#include <dev/usb2/core/usb2_util.h>
91184610Salfred
92184610Salfred#include <dev/usb2/ethernet/usb2_ethernet.h>
93187192Sthompsa#include <dev/usb2/ethernet/if_ruereg.h>
94184610Salfred
95184610Salfred#if USB_DEBUG
96184610Salfredstatic int rue_debug = 0;
97184610Salfred
98184610SalfredSYSCTL_NODE(_hw_usb2, OID_AUTO, rue, CTLFLAG_RW, 0, "USB rue");
99184610SalfredSYSCTL_INT(_hw_usb2_rue, OID_AUTO, debug, CTLFLAG_RW,
100184610Salfred    &rue_debug, 0, "Debug level");
101184610Salfred#endif
102184610Salfred
103184610Salfred/*
104184610Salfred * Various supported device vendors/products.
105184610Salfred */
106184610Salfred
107184610Salfredstatic const struct usb2_device_id rue_devs[] = {
108184610Salfred	{USB_VPI(USB_VENDOR_MELCO, USB_PRODUCT_MELCO_LUAKTX, 0)},
109184610Salfred	{USB_VPI(USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_USBKR100, 0)},
110184610Salfred};
111184610Salfred
112184610Salfred/* prototypes */
113184610Salfred
114184610Salfredstatic device_probe_t rue_probe;
115184610Salfredstatic device_attach_t rue_attach;
116184610Salfredstatic device_detach_t rue_detach;
117184610Salfredstatic device_shutdown_t rue_shutdown;
118184610Salfred
119184610Salfredstatic usb2_callback_t rue_intr_clear_stall_callback;
120184610Salfredstatic usb2_callback_t rue_intr_callback;
121184610Salfredstatic usb2_callback_t rue_bulk_read_clear_stall_callback;
122184610Salfredstatic usb2_callback_t rue_bulk_read_callback;
123184610Salfredstatic usb2_callback_t rue_bulk_write_clear_stall_callback;
124184610Salfredstatic usb2_callback_t rue_bulk_write_callback;
125184610Salfred
126184610Salfredstatic usb2_config_td_command_t rue_config_copy;
127184610Salfredstatic usb2_config_td_command_t rue_cfg_promisc_upd;
128184610Salfredstatic usb2_config_td_command_t rue_cfg_first_time_setup;
129184610Salfredstatic usb2_config_td_command_t rue_cfg_tick;
130184610Salfredstatic usb2_config_td_command_t rue_cfg_pre_init;
131184610Salfredstatic usb2_config_td_command_t rue_cfg_init;
132184610Salfredstatic usb2_config_td_command_t rue_cfg_ifmedia_upd;
133184610Salfredstatic usb2_config_td_command_t rue_cfg_pre_stop;
134184610Salfredstatic usb2_config_td_command_t rue_cfg_stop;
135184610Salfred
136184610Salfredstatic void rue_cfg_do_request(struct rue_softc *sc, struct usb2_device_request *req, void *data);
137184610Salfredstatic void rue_cfg_read_mem(struct rue_softc *sc, uint16_t addr, void *buf, uint16_t len);
138184610Salfredstatic void rue_cfg_write_mem(struct rue_softc *sc, uint16_t addr, void *buf, uint16_t len);
139184610Salfredstatic uint8_t rue_cfg_csr_read_1(struct rue_softc *sc, uint16_t reg);
140184610Salfredstatic uint16_t rue_cfg_csr_read_2(struct rue_softc *sc, uint16_t reg);
141184610Salfredstatic void rue_cfg_csr_write_1(struct rue_softc *sc, uint16_t reg, uint8_t val);
142184610Salfredstatic void rue_cfg_csr_write_2(struct rue_softc *sc, uint16_t reg, uint16_t val);
143184610Salfredstatic void rue_cfg_csr_write_4(struct rue_softc *sc, int reg, uint32_t val);
144184610Salfred
145184610Salfredstatic miibus_readreg_t rue_cfg_miibus_readreg;
146184610Salfredstatic miibus_writereg_t rue_cfg_miibus_writereg;
147184610Salfredstatic miibus_statchg_t rue_cfg_miibus_statchg;
148184610Salfred
149184610Salfredstatic void rue_cfg_reset(struct rue_softc *sc);
150184610Salfredstatic void rue_start_cb(struct ifnet *ifp);
151184610Salfredstatic void rue_start_transfers(struct rue_softc *sc);
152184610Salfredstatic void rue_init_cb(void *arg);
153184610Salfredstatic int rue_ifmedia_upd_cb(struct ifnet *ifp);
154184610Salfredstatic void rue_ifmedia_sts_cb(struct ifnet *ifp, struct ifmediareq *ifmr);
155184610Salfredstatic int rue_ioctl_cb(struct ifnet *ifp, u_long command, caddr_t data);
156184610Salfredstatic void rue_watchdog(void *arg);
157184610Salfred
158187259Sthompsastatic const struct usb2_config rue_config[RUE_N_TRANSFER] = {
159184610Salfred
160187259Sthompsa	[RUE_BULK_DT_WR] = {
161184610Salfred		.type = UE_BULK,
162184610Salfred		.endpoint = UE_ADDR_ANY,
163184610Salfred		.direction = UE_DIR_OUT,
164184610Salfred		.mh.bufsize = MCLBYTES,
165184610Salfred		.mh.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
166184610Salfred		.mh.callback = &rue_bulk_write_callback,
167184610Salfred		.mh.timeout = 10000,	/* 10 seconds */
168184610Salfred	},
169184610Salfred
170187259Sthompsa	[RUE_BULK_DT_RD] = {
171184610Salfred		.type = UE_BULK,
172184610Salfred		.endpoint = UE_ADDR_ANY,
173184610Salfred		.direction = UE_DIR_IN,
174184610Salfred		.mh.bufsize = (MCLBYTES + 4),
175184610Salfred		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
176184610Salfred		.mh.callback = &rue_bulk_read_callback,
177184610Salfred		.mh.timeout = 0,	/* no timeout */
178184610Salfred	},
179184610Salfred
180187259Sthompsa	[RUE_BULK_CS_WR] = {
181184610Salfred		.type = UE_CONTROL,
182184610Salfred		.endpoint = 0x00,	/* Control pipe */
183184610Salfred		.direction = UE_DIR_ANY,
184184610Salfred		.mh.bufsize = sizeof(struct usb2_device_request),
185184610Salfred		.mh.flags = {},
186184610Salfred		.mh.callback = &rue_bulk_write_clear_stall_callback,
187184610Salfred		.mh.timeout = 1000,	/* 1 second */
188184610Salfred		.mh.interval = 50,	/* 50ms */
189184610Salfred	},
190184610Salfred
191187259Sthompsa	[RUE_BULK_CS_RD] = {
192184610Salfred		.type = UE_CONTROL,
193184610Salfred		.endpoint = 0x00,	/* Control pipe */
194184610Salfred		.direction = UE_DIR_ANY,
195184610Salfred		.mh.bufsize = sizeof(struct usb2_device_request),
196184610Salfred		.mh.flags = {},
197184610Salfred		.mh.callback = &rue_bulk_read_clear_stall_callback,
198184610Salfred		.mh.timeout = 1000,	/* 1 second */
199184610Salfred		.mh.interval = 50,	/* 50ms */
200184610Salfred	},
201184610Salfred
202187259Sthompsa	[RUE_INTR_DT_RD] = {
203184610Salfred		.type = UE_INTERRUPT,
204184610Salfred		.endpoint = UE_ADDR_ANY,
205184610Salfred		.direction = UE_DIR_IN,
206184610Salfred		.mh.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
207184610Salfred		.mh.bufsize = 0,	/* use wMaxPacketSize */
208184610Salfred		.mh.callback = &rue_intr_callback,
209184610Salfred	},
210184610Salfred
211187259Sthompsa	[RUE_INTR_CS_RD] = {
212184610Salfred		.type = UE_CONTROL,
213184610Salfred		.endpoint = 0x00,	/* Control pipe */
214184610Salfred		.direction = UE_DIR_ANY,
215184610Salfred		.mh.bufsize = sizeof(struct usb2_device_request),
216184610Salfred		.mh.flags = {},
217184610Salfred		.mh.callback = &rue_intr_clear_stall_callback,
218184610Salfred		.mh.timeout = 1000,	/* 1 second */
219184610Salfred		.mh.interval = 50,	/* 50ms */
220184610Salfred	},
221184610Salfred};
222184610Salfred
223184610Salfredstatic device_method_t rue_methods[] = {
224184610Salfred	/* Device interface */
225184610Salfred	DEVMETHOD(device_probe, rue_probe),
226184610Salfred	DEVMETHOD(device_attach, rue_attach),
227184610Salfred	DEVMETHOD(device_detach, rue_detach),
228184610Salfred	DEVMETHOD(device_shutdown, rue_shutdown),
229184610Salfred
230184610Salfred	/* Bus interface */
231184610Salfred	DEVMETHOD(bus_print_child, bus_generic_print_child),
232184610Salfred	DEVMETHOD(bus_driver_added, bus_generic_driver_added),
233184610Salfred
234184610Salfred	/* MII interface */
235184610Salfred	DEVMETHOD(miibus_readreg, rue_cfg_miibus_readreg),
236184610Salfred	DEVMETHOD(miibus_writereg, rue_cfg_miibus_writereg),
237184610Salfred	DEVMETHOD(miibus_statchg, rue_cfg_miibus_statchg),
238184610Salfred
239184610Salfred	{0, 0}
240184610Salfred};
241184610Salfred
242184610Salfredstatic driver_t rue_driver = {
243184610Salfred	.name = "rue",
244184610Salfred	.methods = rue_methods,
245184610Salfred	.size = sizeof(struct rue_softc),
246184610Salfred};
247184610Salfred
248184610Salfredstatic devclass_t rue_devclass;
249184610Salfred
250184610SalfredDRIVER_MODULE(rue, ushub, rue_driver, rue_devclass, NULL, 0);
251184610SalfredDRIVER_MODULE(miibus, rue, miibus_driver, miibus_devclass, 0, 0);
252184610SalfredMODULE_DEPEND(rue, usb2_ethernet, 1, 1, 1);
253184610SalfredMODULE_DEPEND(rue, usb2_core, 1, 1, 1);
254184610SalfredMODULE_DEPEND(rue, ether, 1, 1, 1);
255184610SalfredMODULE_DEPEND(rue, miibus, 1, 1, 1);
256184610Salfred
257184610Salfredstatic void
258184610Salfredrue_cfg_do_request(struct rue_softc *sc, struct usb2_device_request *req,
259184610Salfred    void *data)
260184610Salfred{
261184610Salfred	uint16_t length;
262184610Salfred	usb2_error_t err;
263184610Salfred
264184610Salfred	if (usb2_config_td_is_gone(&sc->sc_config_td)) {
265184610Salfred		goto error;
266184610Salfred	}
267184610Salfred	err = usb2_do_request_flags
268184610Salfred	    (sc->sc_udev, &sc->sc_mtx, req, data, 0, NULL, 1000);
269184610Salfred
270184610Salfred	if (err) {
271184610Salfred
272184610Salfred		DPRINTF("device request failed, err=%s "
273184610Salfred		    "(ignored)\n", usb2_errstr(err));
274184610Salfred
275184610Salfrederror:
276184610Salfred		length = UGETW(req->wLength);
277184610Salfred
278184610Salfred		if ((req->bmRequestType & UT_READ) && length) {
279184610Salfred			bzero(data, length);
280184610Salfred		}
281184610Salfred	}
282184610Salfred}
283184610Salfred
284184610Salfred#define	RUE_CFG_SETBIT(sc, reg, x) \
285184610Salfred	rue_cfg_csr_write_1(sc, reg, rue_cfg_csr_read_1(sc, reg) | (x))
286184610Salfred
287184610Salfred#define	RUE_CFG_CLRBIT(sc, reg, x) \
288184610Salfred	rue_cfg_csr_write_1(sc, reg, rue_cfg_csr_read_1(sc, reg) & ~(x))
289184610Salfred
290184610Salfredstatic void
291184610Salfredrue_cfg_read_mem(struct rue_softc *sc, uint16_t addr, void *buf,
292184610Salfred    uint16_t len)
293184610Salfred{
294184610Salfred	struct usb2_device_request req;
295184610Salfred
296184610Salfred	req.bmRequestType = UT_READ_VENDOR_DEVICE;
297184610Salfred	req.bRequest = UR_SET_ADDRESS;
298184610Salfred	USETW(req.wValue, addr);
299184610Salfred	USETW(req.wIndex, 0);
300184610Salfred	USETW(req.wLength, len);
301184610Salfred
302184610Salfred	rue_cfg_do_request(sc, &req, buf);
303184610Salfred}
304184610Salfred
305184610Salfredstatic void
306184610Salfredrue_cfg_write_mem(struct rue_softc *sc, uint16_t addr, void *buf,
307184610Salfred    uint16_t len)
308184610Salfred{
309184610Salfred	struct usb2_device_request req;
310184610Salfred
311184610Salfred	req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
312184610Salfred	req.bRequest = UR_SET_ADDRESS;
313184610Salfred	USETW(req.wValue, addr);
314184610Salfred	USETW(req.wIndex, 0);
315184610Salfred	USETW(req.wLength, len);
316184610Salfred
317184610Salfred	rue_cfg_do_request(sc, &req, buf);
318184610Salfred}
319184610Salfred
320184610Salfredstatic uint8_t
321184610Salfredrue_cfg_csr_read_1(struct rue_softc *sc, uint16_t reg)
322184610Salfred{
323184610Salfred	uint8_t val;
324184610Salfred
325184610Salfred	rue_cfg_read_mem(sc, reg, &val, 1);
326184610Salfred	return (val);
327184610Salfred}
328184610Salfred
329184610Salfredstatic uint16_t
330184610Salfredrue_cfg_csr_read_2(struct rue_softc *sc, uint16_t reg)
331184610Salfred{
332184610Salfred	uint8_t val[2];
333184610Salfred
334184610Salfred	rue_cfg_read_mem(sc, reg, &val, 2);
335184610Salfred	return (UGETW(val));
336184610Salfred}
337184610Salfred
338184610Salfredstatic void
339184610Salfredrue_cfg_csr_write_1(struct rue_softc *sc, uint16_t reg, uint8_t val)
340184610Salfred{
341184610Salfred	rue_cfg_write_mem(sc, reg, &val, 1);
342184610Salfred}
343184610Salfred
344184610Salfredstatic void
345184610Salfredrue_cfg_csr_write_2(struct rue_softc *sc, uint16_t reg, uint16_t val)
346184610Salfred{
347184610Salfred	uint8_t temp[2];
348184610Salfred
349184610Salfred	USETW(temp, val);
350184610Salfred	rue_cfg_write_mem(sc, reg, &temp, 2);
351184610Salfred}
352184610Salfred
353184610Salfredstatic void
354184610Salfredrue_cfg_csr_write_4(struct rue_softc *sc, int reg, uint32_t val)
355184610Salfred{
356184610Salfred	uint8_t temp[4];
357184610Salfred
358184610Salfred	USETDW(temp, val);
359184610Salfred	rue_cfg_write_mem(sc, reg, &temp, 4);
360184610Salfred}
361184610Salfred
362184610Salfredstatic int
363184610Salfredrue_cfg_miibus_readreg(device_t dev, int phy, int reg)
364184610Salfred{
365184610Salfred	struct rue_softc *sc = device_get_softc(dev);
366184610Salfred	uint16_t rval;
367184610Salfred	uint16_t ruereg;
368184610Salfred	uint8_t do_unlock;
369184610Salfred
370184610Salfred	if (phy != 0) {			/* RTL8150 supports PHY == 0, only */
371184610Salfred		return (0);
372184610Salfred	}
373184610Salfred	/* avoid recursive locking */
374184610Salfred	if (mtx_owned(&sc->sc_mtx)) {
375184610Salfred		do_unlock = 0;
376184610Salfred	} else {
377184610Salfred		mtx_lock(&sc->sc_mtx);
378184610Salfred		do_unlock = 1;
379184610Salfred	}
380184610Salfred
381184610Salfred	switch (reg) {
382184610Salfred	case MII_BMCR:
383184610Salfred		ruereg = RUE_BMCR;
384184610Salfred		break;
385184610Salfred	case MII_BMSR:
386184610Salfred		ruereg = RUE_BMSR;
387184610Salfred		break;
388184610Salfred	case MII_ANAR:
389184610Salfred		ruereg = RUE_ANAR;
390184610Salfred		break;
391184610Salfred	case MII_ANER:
392184610Salfred		ruereg = RUE_AER;
393184610Salfred		break;
394184610Salfred	case MII_ANLPAR:
395184610Salfred		ruereg = RUE_ANLP;
396184610Salfred		break;
397184610Salfred	case MII_PHYIDR1:
398184610Salfred	case MII_PHYIDR2:
399184610Salfred		rval = 0;
400184610Salfred		goto done;
401184610Salfred	default:
402184610Salfred		if ((RUE_REG_MIN <= reg) && (reg <= RUE_REG_MAX)) {
403184610Salfred			rval = rue_cfg_csr_read_1(sc, reg);
404184610Salfred			goto done;
405184610Salfred		}
406184610Salfred		printf("rue%d: bad phy register\n", sc->sc_unit);
407184610Salfred		rval = 0;
408184610Salfred		goto done;
409184610Salfred	}
410184610Salfred
411184610Salfred	rval = rue_cfg_csr_read_2(sc, ruereg);
412184610Salfreddone:
413184610Salfred	if (do_unlock) {
414184610Salfred		mtx_unlock(&sc->sc_mtx);
415184610Salfred	}
416184610Salfred	return (rval);
417184610Salfred}
418184610Salfred
419184610Salfredstatic int
420184610Salfredrue_cfg_miibus_writereg(device_t dev, int phy, int reg, int data)
421184610Salfred{
422184610Salfred	struct rue_softc *sc = device_get_softc(dev);
423184610Salfred	uint16_t ruereg;
424184610Salfred	uint8_t do_unlock;
425184610Salfred
426184610Salfred	if (phy != 0) {			/* RTL8150 supports PHY == 0, only */
427184610Salfred		return (0);
428184610Salfred	}
429184610Salfred	/* avoid recursive locking */
430184610Salfred	if (mtx_owned(&sc->sc_mtx)) {
431184610Salfred		do_unlock = 0;
432184610Salfred	} else {
433184610Salfred		mtx_lock(&sc->sc_mtx);
434184610Salfred		do_unlock = 1;
435184610Salfred	}
436184610Salfred
437184610Salfred	switch (reg) {
438184610Salfred	case MII_BMCR:
439184610Salfred		ruereg = RUE_BMCR;
440184610Salfred		break;
441184610Salfred	case MII_BMSR:
442184610Salfred		ruereg = RUE_BMSR;
443184610Salfred		break;
444184610Salfred	case MII_ANAR:
445184610Salfred		ruereg = RUE_ANAR;
446184610Salfred		break;
447184610Salfred	case MII_ANER:
448184610Salfred		ruereg = RUE_AER;
449184610Salfred		break;
450184610Salfred	case MII_ANLPAR:
451184610Salfred		ruereg = RUE_ANLP;
452184610Salfred		break;
453184610Salfred	case MII_PHYIDR1:
454184610Salfred	case MII_PHYIDR2:
455184610Salfred		goto done;
456184610Salfred	default:
457184610Salfred		if ((RUE_REG_MIN <= reg) && (reg <= RUE_REG_MAX)) {
458184610Salfred			rue_cfg_csr_write_1(sc, reg, data);
459184610Salfred			goto done;
460184610Salfred		}
461184610Salfred		printf("%s: bad phy register\n",
462184610Salfred		    sc->sc_name);
463184610Salfred		goto done;
464184610Salfred	}
465184610Salfred	rue_cfg_csr_write_2(sc, ruereg, data);
466184610Salfreddone:
467184610Salfred	if (do_unlock) {
468184610Salfred		mtx_unlock(&sc->sc_mtx);
469184610Salfred	}
470184610Salfred	return (0);
471184610Salfred}
472184610Salfred
473184610Salfredstatic void
474184610Salfredrue_cfg_miibus_statchg(device_t dev)
475184610Salfred{
476184610Salfred	/*
477184610Salfred	 * When the code below is enabled the card starts doing weird
478184610Salfred	 * things after link going from UP to DOWN and back UP.
479184610Salfred	 *
480184610Salfred	 * Looks like some of register writes below messes up PHY
481184610Salfred	 * interface.
482184610Salfred	 *
483184610Salfred	 * No visible regressions were found after commenting this code
484184610Salfred	 * out, so that disable it for good.
485184610Salfred	 */
486184610Salfred#if 0
487184610Salfred	struct rue_softc *sc = device_get_softc(dev);
488184610Salfred	struct mii_data *mii = GET_MII(sc);
489184610Salfred	uint16_t bmcr;
490184610Salfred	uint8_t do_unlock;
491184610Salfred
492184610Salfred	/* avoid recursive locking */
493184610Salfred	if (mtx_owned(&sc->sc_mtx)) {
494184610Salfred		do_unlock = 0;
495184610Salfred	} else {
496184610Salfred		mtx_lock(&sc->sc_mtx);
497184610Salfred		do_unlock = 1;
498184610Salfred	}
499184610Salfred
500184610Salfred	RUE_CFG_CLRBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE));
501184610Salfred
502184610Salfred	bmcr = rue_cfg_csr_read_2(sc, RUE_BMCR);
503184610Salfred
504184610Salfred	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX)
505184610Salfred		bmcr |= RUE_BMCR_SPD_SET;
506184610Salfred	else
507184610Salfred		bmcr &= ~RUE_BMCR_SPD_SET;
508184610Salfred
509184610Salfred	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX)
510184610Salfred		bmcr |= RUE_BMCR_DUPLEX;
511184610Salfred	else
512184610Salfred		bmcr &= ~RUE_BMCR_DUPLEX;
513184610Salfred
514184610Salfred	rue_cfg_csr_write_2(sc, RUE_BMCR, bmcr);
515184610Salfred
516184610Salfred	RUE_CFG_SETBIT(sc, RUE_CR, (RUE_CR_RE | RUE_CR_TE));
517184610Salfred
518184610Salfred	if (do_unlock) {
519184610Salfred		mtx_unlock(&sc->sc_mtx);
520184610Salfred	}
521184610Salfred#endif
522184610Salfred}
523184610Salfred
524184610Salfredstatic void
525184610Salfredrue_mchash(struct usb2_config_td_cc *cc, const uint8_t *ptr)
526184610Salfred{
527184610Salfred	uint8_t h;
528184610Salfred
529184610Salfred	h = ether_crc32_be(ptr, ETHER_ADDR_LEN) >> 26;
530184610Salfred	cc->if_hash[h / 8] |= 1 << (h & 7);
531184610Salfred	cc->if_nhash = 1;
532184610Salfred}
533184610Salfred
534184610Salfredstatic void
535184610Salfredrue_config_copy(struct rue_softc *sc,
536184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
537184610Salfred{
538184610Salfred	bzero(cc, sizeof(*cc));
539184610Salfred	usb2_ether_cc(sc->sc_ifp, &rue_mchash, cc);
540184610Salfred}
541184610Salfred
542184610Salfred/*
543184610Salfred * Program the 64-bit multicast hash filter.
544184610Salfred */
545184610Salfredstatic void
546184610Salfredrue_cfg_promisc_upd(struct rue_softc *sc,
547184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
548184610Salfred{
549184610Salfred	uint16_t rxcfg;
550184610Salfred
551184610Salfred	rxcfg = rue_cfg_csr_read_2(sc, RUE_RCR);
552184610Salfred
553184610Salfred	if ((cc->if_flags & IFF_ALLMULTI) ||
554184610Salfred	    (cc->if_flags & IFF_PROMISC)) {
555184610Salfred		rxcfg |= (RUE_RCR_AAM | RUE_RCR_AAP);
556184610Salfred		rxcfg &= ~RUE_RCR_AM;
557184610Salfred		rue_cfg_csr_write_2(sc, RUE_RCR, rxcfg);
558184610Salfred		rue_cfg_csr_write_4(sc, RUE_MAR0, 0xFFFFFFFF);
559184610Salfred		rue_cfg_csr_write_4(sc, RUE_MAR4, 0xFFFFFFFF);
560184610Salfred		return;
561184610Salfred	}
562184610Salfred	/* first, zero all the existing hash bits */
563184610Salfred	rue_cfg_csr_write_4(sc, RUE_MAR0, 0);
564184610Salfred	rue_cfg_csr_write_4(sc, RUE_MAR4, 0);
565184610Salfred
566184610Salfred	if (cc->if_nhash)
567184610Salfred		rxcfg |= RUE_RCR_AM;
568184610Salfred	else
569184610Salfred		rxcfg &= ~RUE_RCR_AM;
570184610Salfred
571184610Salfred	rxcfg &= ~(RUE_RCR_AAM | RUE_RCR_AAP);
572184610Salfred
573184610Salfred	rue_cfg_csr_write_2(sc, RUE_RCR, rxcfg);
574184610Salfred	rue_cfg_write_mem(sc, RUE_MAR0, cc->if_hash, 4);
575184610Salfred	rue_cfg_write_mem(sc, RUE_MAR4, cc->if_hash + 4, 4);
576184610Salfred}
577184610Salfred
578184610Salfredstatic void
579184610Salfredrue_cfg_reset(struct rue_softc *sc)
580184610Salfred{
581184610Salfred	usb2_error_t err;
582184610Salfred	uint16_t to;
583184610Salfred
584184610Salfred	rue_cfg_csr_write_1(sc, RUE_CR, RUE_CR_SOFT_RST);
585184610Salfred
586184610Salfred	for (to = 0;; to++) {
587184610Salfred
588184610Salfred		if (to < RUE_TIMEOUT) {
589184610Salfred
590184610Salfred			err = usb2_config_td_sleep(&sc->sc_config_td, hz / 100);
591184610Salfred
592184610Salfred			if (err) {
593184610Salfred				break;
594184610Salfred			}
595184610Salfred			if (!(rue_cfg_csr_read_1(sc, RUE_CR) & RUE_CR_SOFT_RST)) {
596184610Salfred				break;
597184610Salfred			}
598184610Salfred		} else {
599184610Salfred			printf("%s: reset timeout!\n",
600184610Salfred			    sc->sc_name);
601184610Salfred			break;
602184610Salfred		}
603184610Salfred	}
604184610Salfred
605184610Salfred	err = usb2_config_td_sleep(&sc->sc_config_td, hz / 100);
606184610Salfred}
607184610Salfred
608184610Salfred/*
609184610Salfred * Probe for a RTL8150 chip.
610184610Salfred */
611184610Salfredstatic int
612184610Salfredrue_probe(device_t dev)
613184610Salfred{
614184610Salfred	struct usb2_attach_arg *uaa = device_get_ivars(dev);
615184610Salfred
616184610Salfred	if (uaa->usb2_mode != USB_MODE_HOST) {
617184610Salfred		return (ENXIO);
618184610Salfred	}
619184610Salfred	if (uaa->info.bConfigIndex != RUE_CONFIG_IDX) {
620184610Salfred		return (ENXIO);
621184610Salfred	}
622184610Salfred	if (uaa->info.bIfaceIndex != RUE_IFACE_IDX) {
623184610Salfred		return (ENXIO);
624184610Salfred	}
625184610Salfred	return (usb2_lookup_id_by_uaa(rue_devs, sizeof(rue_devs), uaa));
626184610Salfred}
627184610Salfred
628184610Salfred/*
629184610Salfred * Attach the interface. Allocate softc structures, do ifmedia
630184610Salfred * setup and ethernet/BPF attach.
631184610Salfred */
632184610Salfredstatic int
633184610Salfredrue_attach(device_t dev)
634184610Salfred{
635184610Salfred	struct usb2_attach_arg *uaa = device_get_ivars(dev);
636184610Salfred	struct rue_softc *sc = device_get_softc(dev);
637184610Salfred	int32_t error;
638184610Salfred	uint8_t iface_index;
639184610Salfred
640184610Salfred	if (sc == NULL) {
641184610Salfred		return (ENOMEM);
642184610Salfred	}
643184610Salfred	sc->sc_udev = uaa->device;
644184610Salfred	sc->sc_dev = dev;
645184610Salfred	sc->sc_unit = device_get_unit(dev);
646184610Salfred
647184610Salfred	device_set_usb2_desc(dev);
648184610Salfred
649184610Salfred	snprintf(sc->sc_name, sizeof(sc->sc_name), "%s",
650184610Salfred	    device_get_nameunit(dev));
651184610Salfred
652184610Salfred	mtx_init(&sc->sc_mtx, "rue lock", NULL, MTX_DEF | MTX_RECURSE);
653184610Salfred
654186454Sthompsa	usb2_callout_init_mtx(&sc->sc_watchdog, &sc->sc_mtx, 0);
655184610Salfred
656184610Salfred	iface_index = RUE_IFACE_IDX;
657184610Salfred	error = usb2_transfer_setup(uaa->device, &iface_index,
658187259Sthompsa	    sc->sc_xfer, rue_config, RUE_N_TRANSFER,
659184610Salfred	    sc, &sc->sc_mtx);
660184610Salfred	if (error) {
661184610Salfred		device_printf(dev, "allocating USB "
662184610Salfred		    "transfers failed!\n");
663184610Salfred		goto detach;
664184610Salfred	}
665184610Salfred	error = usb2_config_td_setup(&sc->sc_config_td, sc, &sc->sc_mtx,
666184610Salfred	    NULL, sizeof(struct usb2_config_td_cc), 16);
667184610Salfred	if (error) {
668184610Salfred		device_printf(dev, "could not setup config "
669184610Salfred		    "thread!\n");
670184610Salfred		goto detach;
671184610Salfred	}
672184610Salfred	mtx_lock(&sc->sc_mtx);
673184610Salfred
674184610Salfred	sc->sc_flags |= RUE_FLAG_WAIT_LINK;
675184610Salfred
676184610Salfred	/* start setup */
677184610Salfred
678184610Salfred	usb2_config_td_queue_command
679184610Salfred	    (&sc->sc_config_td, NULL, &rue_cfg_first_time_setup, 0, 0);
680184610Salfred
681184610Salfred	rue_watchdog(sc);
682186454Sthompsa	mtx_unlock(&sc->sc_mtx);
683184610Salfred	return (0);			/* success */
684184610Salfred
685184610Salfreddetach:
686184610Salfred	rue_detach(dev);
687184610Salfred	return (ENXIO);			/* failure */
688184610Salfred}
689184610Salfred
690184610Salfredstatic void
691184610Salfredrue_cfg_first_time_setup(struct rue_softc *sc,
692184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
693184610Salfred{
694184610Salfred	struct ifnet *ifp;
695184610Salfred	int error;
696184610Salfred	uint8_t eaddr[min(ETHER_ADDR_LEN, 6)];
697184610Salfred
698184610Salfred	/* reset the adapter */
699184610Salfred	rue_cfg_reset(sc);
700184610Salfred
701184610Salfred	/* get station address from the EEPROM */
702184610Salfred	rue_cfg_read_mem(sc, RUE_EEPROM_IDR0,
703184610Salfred	    eaddr, ETHER_ADDR_LEN);
704184610Salfred
705184610Salfred	mtx_unlock(&sc->sc_mtx);
706184610Salfred
707184610Salfred	ifp = if_alloc(IFT_ETHER);
708184610Salfred
709184610Salfred	mtx_lock(&sc->sc_mtx);
710184610Salfred
711184610Salfred	if (ifp == NULL) {
712184610Salfred		printf("%s: could not if_alloc()\n",
713184610Salfred		    sc->sc_name);
714184610Salfred		goto done;
715184610Salfred	}
716184610Salfred	sc->sc_evilhack = ifp;
717184610Salfred
718184610Salfred	ifp->if_softc = sc;
719184610Salfred	if_initname(ifp, "rue", sc->sc_unit);
720184610Salfred	ifp->if_mtu = ETHERMTU;
721184610Salfred	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
722184610Salfred	ifp->if_ioctl = rue_ioctl_cb;
723184610Salfred	ifp->if_start = rue_start_cb;
724184610Salfred	ifp->if_watchdog = NULL;
725184610Salfred	ifp->if_init = rue_init_cb;
726184610Salfred	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
727184610Salfred	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
728184610Salfred	IFQ_SET_READY(&ifp->if_snd);
729184610Salfred
730184610Salfred	/*
731184610Salfred	 * XXX need Giant when accessing the device structures !
732184610Salfred	 */
733184610Salfred
734184610Salfred	mtx_unlock(&sc->sc_mtx);
735184610Salfred
736184610Salfred	mtx_lock(&Giant);
737184610Salfred
738184610Salfred	/* MII setup */
739184610Salfred	error = mii_phy_probe(sc->sc_dev, &sc->sc_miibus,
740184610Salfred	    &rue_ifmedia_upd_cb,
741184610Salfred	    &rue_ifmedia_sts_cb);
742184610Salfred	mtx_unlock(&Giant);
743184610Salfred
744184610Salfred	mtx_lock(&sc->sc_mtx);
745184610Salfred
746184610Salfred	if (error) {
747184610Salfred		printf("%s: MII without any PHY!\n",
748184610Salfred		    sc->sc_name);
749184610Salfred		if_free(ifp);
750184610Salfred		goto done;
751184610Salfred	}
752184610Salfred	sc->sc_ifp = ifp;
753184610Salfred
754184610Salfred	mtx_unlock(&sc->sc_mtx);
755184610Salfred
756184610Salfred	/*
757184610Salfred	 * Call MI attach routine.
758184610Salfred	 */
759184610Salfred
760184610Salfred	ether_ifattach(ifp, eaddr);
761184610Salfred
762184610Salfred	mtx_lock(&sc->sc_mtx);
763184610Salfred
764184610Salfreddone:
765184610Salfred	return;
766184610Salfred}
767184610Salfred
768184610Salfredstatic int
769184610Salfredrue_detach(device_t dev)
770184610Salfred{
771184610Salfred	struct rue_softc *sc = device_get_softc(dev);
772184610Salfred	struct ifnet *ifp;
773184610Salfred
774184610Salfred	usb2_config_td_drain(&sc->sc_config_td);
775184610Salfred
776184610Salfred	mtx_lock(&sc->sc_mtx);
777184610Salfred
778184610Salfred	usb2_callout_stop(&sc->sc_watchdog);
779184610Salfred
780184610Salfred	rue_cfg_pre_stop(sc, NULL, 0);
781184610Salfred
782184610Salfred	ifp = sc->sc_ifp;
783184610Salfred
784184610Salfred	mtx_unlock(&sc->sc_mtx);
785184610Salfred
786184610Salfred	/* stop all USB transfers first */
787187259Sthompsa	usb2_transfer_unsetup(sc->sc_xfer, RUE_N_TRANSFER);
788184610Salfred
789184610Salfred	/* get rid of any late children */
790184610Salfred	bus_generic_detach(dev);
791184610Salfred
792184610Salfred	if (ifp) {
793184610Salfred		ether_ifdetach(ifp);
794184610Salfred		if_free(ifp);
795184610Salfred	}
796184610Salfred	usb2_config_td_unsetup(&sc->sc_config_td);
797184610Salfred
798184610Salfred	usb2_callout_drain(&sc->sc_watchdog);
799184610Salfred
800184610Salfred	mtx_destroy(&sc->sc_mtx);
801184610Salfred
802184610Salfred	return (0);
803184610Salfred}
804184610Salfred
805184610Salfredstatic void
806184610Salfredrue_intr_clear_stall_callback(struct usb2_xfer *xfer)
807184610Salfred{
808184610Salfred	struct rue_softc *sc = xfer->priv_sc;
809187259Sthompsa	struct usb2_xfer *xfer_other = sc->sc_xfer[RUE_INTR_DT_RD];
810184610Salfred
811184610Salfred	if (usb2_clear_stall_callback(xfer, xfer_other)) {
812184610Salfred		DPRINTF("stall cleared\n");
813184610Salfred		sc->sc_flags &= ~RUE_FLAG_INTR_STALL;
814184610Salfred		usb2_transfer_start(xfer_other);
815184610Salfred	}
816184610Salfred}
817184610Salfred
818184610Salfredstatic void
819184610Salfredrue_intr_callback(struct usb2_xfer *xfer)
820184610Salfred{
821184610Salfred	struct rue_softc *sc = xfer->priv_sc;
822184610Salfred	struct ifnet *ifp = sc->sc_ifp;
823184610Salfred	struct rue_intrpkt pkt;
824184610Salfred
825184610Salfred	switch (USB_GET_STATE(xfer)) {
826184610Salfred	case USB_ST_TRANSFERRED:
827184610Salfred
828184610Salfred		if (ifp && (ifp->if_drv_flags & IFF_DRV_RUNNING) &&
829184610Salfred		    (xfer->actlen >= sizeof(pkt))) {
830184610Salfred
831184610Salfred			usb2_copy_out(xfer->frbuffers, 0, &pkt, sizeof(pkt));
832184610Salfred
833184610Salfred			ifp->if_ierrors += pkt.rue_rxlost_cnt;
834184610Salfred			ifp->if_ierrors += pkt.rue_crcerr_cnt;
835184610Salfred			ifp->if_collisions += pkt.rue_col_cnt;
836184610Salfred		}
837184610Salfred	case USB_ST_SETUP:
838184610Salfred		if (sc->sc_flags & RUE_FLAG_INTR_STALL) {
839187259Sthompsa			usb2_transfer_start(sc->sc_xfer[RUE_INTR_CS_RD]);
840184610Salfred		} else {
841184610Salfred			xfer->frlengths[0] = xfer->max_data_length;
842184610Salfred			usb2_start_hardware(xfer);
843184610Salfred		}
844184610Salfred		return;
845184610Salfred
846184610Salfred	default:			/* Error */
847184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
848184610Salfred			/* start clear stall */
849184610Salfred			sc->sc_flags |= RUE_FLAG_INTR_STALL;
850187259Sthompsa			usb2_transfer_start(sc->sc_xfer[RUE_INTR_CS_RD]);
851184610Salfred		}
852184610Salfred		return;
853184610Salfred	}
854184610Salfred}
855184610Salfred
856184610Salfredstatic void
857184610Salfredrue_bulk_read_clear_stall_callback(struct usb2_xfer *xfer)
858184610Salfred{
859184610Salfred	struct rue_softc *sc = xfer->priv_sc;
860187259Sthompsa	struct usb2_xfer *xfer_other = sc->sc_xfer[RUE_BULK_DT_RD];
861184610Salfred
862184610Salfred	if (usb2_clear_stall_callback(xfer, xfer_other)) {
863184610Salfred		DPRINTF("stall cleared\n");
864184610Salfred		sc->sc_flags &= ~RUE_FLAG_READ_STALL;
865184610Salfred		usb2_transfer_start(xfer_other);
866184610Salfred	}
867184610Salfred}
868184610Salfred
869184610Salfredstatic void
870184610Salfredrue_bulk_read_callback(struct usb2_xfer *xfer)
871184610Salfred{
872184610Salfred	struct rue_softc *sc = xfer->priv_sc;
873184610Salfred	struct ifnet *ifp = sc->sc_ifp;
874184610Salfred	uint16_t status;
875184610Salfred	struct mbuf *m = NULL;
876184610Salfred
877184610Salfred	switch (USB_GET_STATE(xfer)) {
878184610Salfred	case USB_ST_TRANSFERRED:
879184610Salfred
880184610Salfred		if (xfer->actlen < 4) {
881184610Salfred			ifp->if_ierrors++;
882184610Salfred			goto tr_setup;
883184610Salfred		}
884184610Salfred		usb2_copy_out(xfer->frbuffers, xfer->actlen - 4,
885184610Salfred		    &status, sizeof(status));
886184610Salfred
887184610Salfred		status = le16toh(status);
888184610Salfred
889184610Salfred		/* check recieve packet was valid or not */
890184610Salfred
891184610Salfred		if ((status & RUE_RXSTAT_VALID) == 0) {
892184610Salfred			ifp->if_ierrors++;
893184610Salfred			goto tr_setup;
894184610Salfred		}
895184610Salfred		xfer->actlen -= 4;
896184610Salfred
897184610Salfred		if (xfer->actlen < sizeof(struct ether_header)) {
898184610Salfred			ifp->if_ierrors++;
899184610Salfred			goto tr_setup;
900184610Salfred		}
901184610Salfred		m = usb2_ether_get_mbuf();
902184610Salfred
903184610Salfred		if (m == NULL) {
904184610Salfred			ifp->if_ierrors++;
905184610Salfred			goto tr_setup;
906184610Salfred		}
907184610Salfred		xfer->actlen = min(xfer->actlen, m->m_len);
908184610Salfred
909184610Salfred		usb2_copy_out(xfer->frbuffers, 0, m->m_data, xfer->actlen);
910184610Salfred
911184610Salfred		ifp->if_ipackets++;
912184610Salfred		m->m_pkthdr.rcvif = ifp;
913184610Salfred		m->m_pkthdr.len = m->m_len = xfer->actlen;
914184610Salfred
915184610Salfred	case USB_ST_SETUP:
916184610Salfredtr_setup:
917184610Salfred
918184610Salfred		if (sc->sc_flags & RUE_FLAG_READ_STALL) {
919187259Sthompsa			usb2_transfer_start(sc->sc_xfer[RUE_BULK_CS_RD]);
920184610Salfred		} else {
921184610Salfred			xfer->frlengths[0] = xfer->max_data_length;
922184610Salfred			usb2_start_hardware(xfer);
923184610Salfred		}
924184610Salfred
925184610Salfred		/*
926184610Salfred		 * At the end of a USB callback it is always safe to unlock
927184610Salfred		 * the private mutex of a device! That is why we do the
928184610Salfred		 * "if_input" here, and not some lines up!
929184610Salfred		 */
930184610Salfred		if (m) {
931184610Salfred			mtx_unlock(&sc->sc_mtx);
932184610Salfred			(ifp->if_input) (ifp, m);
933184610Salfred			mtx_lock(&sc->sc_mtx);
934184610Salfred		}
935184610Salfred		return;
936184610Salfred
937184610Salfred	default:			/* Error */
938184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
939184610Salfred			/* try to clear stall first */
940184610Salfred			sc->sc_flags |= RUE_FLAG_READ_STALL;
941187259Sthompsa			usb2_transfer_start(sc->sc_xfer[RUE_BULK_CS_RD]);
942184610Salfred		}
943184610Salfred		DPRINTF("bulk read error, %s\n",
944184610Salfred		    usb2_errstr(xfer->error));
945184610Salfred		return;
946184610Salfred
947184610Salfred	}
948184610Salfred}
949184610Salfred
950184610Salfredstatic void
951184610Salfredrue_bulk_write_clear_stall_callback(struct usb2_xfer *xfer)
952184610Salfred{
953184610Salfred	struct rue_softc *sc = xfer->priv_sc;
954187259Sthompsa	struct usb2_xfer *xfer_other = sc->sc_xfer[RUE_BULK_DT_WR];
955184610Salfred
956184610Salfred	if (usb2_clear_stall_callback(xfer, xfer_other)) {
957184610Salfred		DPRINTF("stall cleared\n");
958184610Salfred		sc->sc_flags &= ~RUE_FLAG_WRITE_STALL;
959184610Salfred		usb2_transfer_start(xfer_other);
960184610Salfred	}
961184610Salfred}
962184610Salfred
963184610Salfredstatic void
964184610Salfredrue_bulk_write_callback(struct usb2_xfer *xfer)
965184610Salfred{
966184610Salfred	struct rue_softc *sc = xfer->priv_sc;
967184610Salfred	struct ifnet *ifp = sc->sc_ifp;
968184610Salfred	struct mbuf *m;
969184610Salfred	uint32_t temp_len;
970184610Salfred
971184610Salfred	switch (USB_GET_STATE(xfer)) {
972184610Salfred	case USB_ST_TRANSFERRED:
973184610Salfred		DPRINTFN(11, "transfer complete\n");
974184610Salfred
975184610Salfred		ifp->if_opackets++;
976184610Salfred
977184610Salfred	case USB_ST_SETUP:
978184610Salfred
979184610Salfred		if (sc->sc_flags & RUE_FLAG_WRITE_STALL) {
980187259Sthompsa			usb2_transfer_start(sc->sc_xfer[RUE_BULK_CS_WR]);
981184610Salfred			goto done;
982184610Salfred		}
983184610Salfred		if (sc->sc_flags & RUE_FLAG_WAIT_LINK) {
984184610Salfred			/*
985184610Salfred			 * don't send anything if there is no link !
986184610Salfred			 */
987184610Salfred			goto done;
988184610Salfred		}
989184610Salfred		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
990184610Salfred
991184610Salfred		if (m == NULL) {
992184610Salfred			goto done;
993184610Salfred		}
994184610Salfred		if (m->m_pkthdr.len > MCLBYTES) {
995184610Salfred			m->m_pkthdr.len = MCLBYTES;
996184610Salfred		}
997184610Salfred		temp_len = m->m_pkthdr.len;
998184610Salfred
999184610Salfred		usb2_m_copy_in(xfer->frbuffers, 0,
1000184610Salfred		    m, 0, m->m_pkthdr.len);
1001184610Salfred
1002184610Salfred		/*
1003184610Salfred		 * This is an undocumented behavior.
1004184610Salfred		 * RTL8150 chip doesn't send frame length smaller than
1005184610Salfred		 * RUE_MIN_FRAMELEN (60) byte packet.
1006184610Salfred		 */
1007184610Salfred		if (temp_len < RUE_MIN_FRAMELEN) {
1008184610Salfred			usb2_bzero(xfer->frbuffers, temp_len,
1009184610Salfred			    RUE_MIN_FRAMELEN - temp_len);
1010184610Salfred			temp_len = RUE_MIN_FRAMELEN;
1011184610Salfred		}
1012184610Salfred		xfer->frlengths[0] = temp_len;
1013184610Salfred
1014184610Salfred		/*
1015184610Salfred		 * if there's a BPF listener, bounce a copy
1016184610Salfred		 * of this frame to him:
1017184610Salfred		 */
1018184610Salfred		BPF_MTAP(ifp, m);
1019184610Salfred
1020184610Salfred		m_freem(m);
1021184610Salfred
1022184610Salfred		usb2_start_hardware(xfer);
1023184610Salfred
1024184610Salfreddone:
1025184610Salfred		return;
1026184610Salfred
1027184610Salfred	default:			/* Error */
1028184610Salfred		DPRINTFN(11, "transfer error, %s\n",
1029184610Salfred		    usb2_errstr(xfer->error));
1030184610Salfred
1031184610Salfred		if (xfer->error != USB_ERR_CANCELLED) {
1032184610Salfred			/* try to clear stall first */
1033184610Salfred			sc->sc_flags |= RUE_FLAG_WRITE_STALL;
1034187259Sthompsa			usb2_transfer_start(sc->sc_xfer[RUE_BULK_CS_WR]);
1035184610Salfred		}
1036184610Salfred		ifp->if_oerrors++;
1037184610Salfred		return;
1038184610Salfred
1039184610Salfred	}
1040184610Salfred}
1041184610Salfred
1042184610Salfredstatic void
1043184610Salfredrue_cfg_tick(struct rue_softc *sc,
1044184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
1045184610Salfred{
1046184610Salfred	struct ifnet *ifp = sc->sc_ifp;
1047184610Salfred	struct mii_data *mii = GET_MII(sc);
1048184610Salfred
1049184610Salfred	if ((ifp == NULL) ||
1050184610Salfred	    (mii == NULL)) {
1051184610Salfred		/* not ready */
1052184610Salfred		return;
1053184610Salfred	}
1054184610Salfred	mii_tick(mii);
1055184610Salfred
1056184610Salfred	mii_pollstat(mii);
1057184610Salfred
1058184610Salfred	if ((sc->sc_flags & RUE_FLAG_WAIT_LINK) &&
1059184610Salfred	    (mii->mii_media_status & IFM_ACTIVE) &&
1060184610Salfred	    (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)) {
1061184610Salfred		sc->sc_flags &= ~RUE_FLAG_WAIT_LINK;
1062184610Salfred	}
1063184610Salfred	sc->sc_media_active = mii->mii_media_active;
1064184610Salfred	sc->sc_media_status = mii->mii_media_status;
1065184610Salfred
1066184610Salfred	/* start stopped transfers, if any */
1067184610Salfred
1068184610Salfred	rue_start_transfers(sc);
1069184610Salfred}
1070184610Salfred
1071184610Salfredstatic void
1072184610Salfredrue_start_cb(struct ifnet *ifp)
1073184610Salfred{
1074184610Salfred	struct rue_softc *sc = ifp->if_softc;
1075184610Salfred
1076184610Salfred	mtx_lock(&sc->sc_mtx);
1077184610Salfred
1078184610Salfred	rue_start_transfers(sc);
1079184610Salfred
1080184610Salfred	mtx_unlock(&sc->sc_mtx);
1081184610Salfred}
1082184610Salfred
1083184610Salfredstatic void
1084184610Salfredrue_start_transfers(struct rue_softc *sc)
1085184610Salfred{
1086184610Salfred	if ((sc->sc_flags & RUE_FLAG_LL_READY) &&
1087184610Salfred	    (sc->sc_flags & RUE_FLAG_HL_READY)) {
1088184610Salfred
1089184610Salfred		/*
1090184610Salfred		 * start the USB transfers, if not already started:
1091184610Salfred		 */
1092187259Sthompsa		usb2_transfer_start(sc->sc_xfer[RUE_INTR_DT_RD]);
1093187259Sthompsa		usb2_transfer_start(sc->sc_xfer[RUE_BULK_DT_RD]);
1094187259Sthompsa		usb2_transfer_start(sc->sc_xfer[RUE_BULK_DT_WR]);
1095184610Salfred	}
1096184610Salfred}
1097184610Salfred
1098184610Salfredstatic void
1099184610Salfredrue_init_cb(void *arg)
1100184610Salfred{
1101184610Salfred	struct rue_softc *sc = arg;
1102184610Salfred
1103184610Salfred	mtx_lock(&sc->sc_mtx);
1104184610Salfred	usb2_config_td_queue_command
1105184610Salfred	    (&sc->sc_config_td, &rue_cfg_pre_init,
1106184610Salfred	    &rue_cfg_init, 0, 0);
1107184610Salfred	mtx_unlock(&sc->sc_mtx);
1108184610Salfred}
1109184610Salfred
1110184610Salfredstatic void
1111184610Salfredrue_cfg_pre_init(struct rue_softc *sc,
1112184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
1113184610Salfred{
1114184610Salfred	struct ifnet *ifp = sc->sc_ifp;
1115184610Salfred
1116184610Salfred	/* immediate configuration */
1117184610Salfred
1118184610Salfred	rue_cfg_pre_stop(sc, cc, 0);
1119184610Salfred
1120184610Salfred	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1121184610Salfred
1122184610Salfred	sc->sc_flags |= RUE_FLAG_HL_READY;
1123184610Salfred}
1124184610Salfred
1125184610Salfredstatic void
1126184610Salfredrue_cfg_init(struct rue_softc *sc,
1127184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
1128184610Salfred{
1129184610Salfred	struct mii_data *mii = GET_MII(sc);
1130184610Salfred	uint16_t rxcfg;
1131184610Salfred
1132184610Salfred	/*
1133184610Salfred	 * Cancel pending I/O
1134184610Salfred	 */
1135184610Salfred
1136184610Salfred	rue_cfg_stop(sc, cc, 0);
1137184610Salfred
1138184610Salfred	/* set MAC address */
1139184610Salfred
1140184610Salfred	rue_cfg_write_mem(sc, RUE_IDR0, cc->if_lladdr, ETHER_ADDR_LEN);
1141184610Salfred
1142184610Salfred	/*
1143184610Salfred	 * Set the initial TX and RX configuration.
1144184610Salfred	 */
1145184610Salfred	rue_cfg_csr_write_1(sc, RUE_TCR, RUE_TCR_CONFIG);
1146184610Salfred
1147184610Salfred	rxcfg = RUE_RCR_CONFIG;
1148184610Salfred
1149184610Salfred	/* Set capture broadcast bit to capture broadcast frames. */
1150184610Salfred	if (cc->if_flags & IFF_BROADCAST)
1151184610Salfred		rxcfg |= RUE_RCR_AB;
1152184610Salfred	else
1153184610Salfred		rxcfg &= ~RUE_RCR_AB;
1154184610Salfred
1155184610Salfred	rue_cfg_csr_write_2(sc, RUE_RCR, rxcfg);
1156184610Salfred
1157184610Salfred	/* Load the multicast filter */
1158184610Salfred	rue_cfg_promisc_upd(sc, cc, 0);
1159184610Salfred
1160184610Salfred	/* Enable RX and TX */
1161184610Salfred	rue_cfg_csr_write_1(sc, RUE_CR, (RUE_CR_TE | RUE_CR_RE | RUE_CR_EP3CLREN));
1162184610Salfred
1163184610Salfred	mii_mediachg(mii);
1164184610Salfred
1165184610Salfred	sc->sc_flags |= (RUE_FLAG_READ_STALL |
1166184610Salfred	    RUE_FLAG_WRITE_STALL |
1167184610Salfred	    RUE_FLAG_LL_READY);
1168184610Salfred
1169184610Salfred	rue_start_transfers(sc);
1170184610Salfred}
1171184610Salfred
1172184610Salfred/*
1173184610Salfred * Set media options.
1174184610Salfred */
1175184610Salfredstatic int
1176184610Salfredrue_ifmedia_upd_cb(struct ifnet *ifp)
1177184610Salfred{
1178184610Salfred	struct rue_softc *sc = ifp->if_softc;
1179184610Salfred
1180184610Salfred	mtx_lock(&sc->sc_mtx);
1181184610Salfred	usb2_config_td_queue_command
1182184610Salfred	    (&sc->sc_config_td, NULL,
1183184610Salfred	    &rue_cfg_ifmedia_upd, 0, 0);
1184184610Salfred	mtx_unlock(&sc->sc_mtx);
1185184610Salfred
1186184610Salfred	return (0);
1187184610Salfred}
1188184610Salfred
1189184610Salfredstatic void
1190184610Salfredrue_cfg_ifmedia_upd(struct rue_softc *sc,
1191184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
1192184610Salfred{
1193184610Salfred	struct ifnet *ifp = sc->sc_ifp;
1194184610Salfred	struct mii_data *mii = GET_MII(sc);
1195184610Salfred
1196184610Salfred	if ((ifp == NULL) ||
1197184610Salfred	    (mii == NULL)) {
1198184610Salfred		/* not ready */
1199184610Salfred		return;
1200184610Salfred	}
1201184610Salfred	sc->sc_flags |= RUE_FLAG_WAIT_LINK;
1202184610Salfred
1203184610Salfred	if (mii->mii_instance) {
1204184610Salfred		struct mii_softc *miisc;
1205184610Salfred
1206184610Salfred		LIST_FOREACH(miisc, &mii->mii_phys, mii_list) {
1207184610Salfred			mii_phy_reset(miisc);
1208184610Salfred		}
1209184610Salfred	}
1210184610Salfred	mii_mediachg(mii);
1211184610Salfred}
1212184610Salfred
1213184610Salfred/*
1214184610Salfred * Report current media status.
1215184610Salfred */
1216184610Salfredstatic void
1217184610Salfredrue_ifmedia_sts_cb(struct ifnet *ifp, struct ifmediareq *ifmr)
1218184610Salfred{
1219184610Salfred	struct rue_softc *sc = ifp->if_softc;
1220184610Salfred
1221184610Salfred	mtx_lock(&sc->sc_mtx);
1222184610Salfred
1223184610Salfred	ifmr->ifm_active = sc->sc_media_active;
1224184610Salfred	ifmr->ifm_status = sc->sc_media_status;
1225184610Salfred
1226184610Salfred	mtx_unlock(&sc->sc_mtx);
1227184610Salfred}
1228184610Salfred
1229184610Salfredstatic int
1230184610Salfredrue_ioctl_cb(struct ifnet *ifp, u_long command, caddr_t data)
1231184610Salfred{
1232184610Salfred	struct rue_softc *sc = ifp->if_softc;
1233184610Salfred	struct mii_data *mii;
1234184610Salfred	int error = 0;
1235184610Salfred
1236184610Salfred	switch (command) {
1237184610Salfred	case SIOCSIFFLAGS:
1238184610Salfred
1239184610Salfred		mtx_lock(&sc->sc_mtx);
1240184610Salfred		if (ifp->if_flags & IFF_UP) {
1241184610Salfred			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1242184610Salfred				usb2_config_td_queue_command
1243184610Salfred				    (&sc->sc_config_td, &rue_config_copy,
1244184610Salfred				    &rue_cfg_promisc_upd, 0, 0);
1245184610Salfred			} else {
1246184610Salfred				usb2_config_td_queue_command
1247184610Salfred				    (&sc->sc_config_td, &rue_cfg_pre_init,
1248184610Salfred				    &rue_cfg_init, 0, 0);
1249184610Salfred			}
1250184610Salfred		} else {
1251184610Salfred			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
1252184610Salfred				usb2_config_td_queue_command
1253184610Salfred				    (&sc->sc_config_td, &rue_cfg_pre_stop,
1254184610Salfred				    &rue_cfg_stop, 0, 0);
1255184610Salfred			}
1256184610Salfred		}
1257184610Salfred		mtx_unlock(&sc->sc_mtx);
1258184610Salfred		break;
1259184610Salfred
1260184610Salfred	case SIOCADDMULTI:
1261184610Salfred	case SIOCDELMULTI:
1262184610Salfred		mtx_lock(&sc->sc_mtx);
1263184610Salfred		usb2_config_td_queue_command
1264184610Salfred		    (&sc->sc_config_td, &rue_config_copy,
1265184610Salfred		    &rue_cfg_promisc_upd, 0, 0);
1266184610Salfred		mtx_unlock(&sc->sc_mtx);
1267184610Salfred		break;
1268184610Salfred
1269184610Salfred	case SIOCGIFMEDIA:
1270184610Salfred	case SIOCSIFMEDIA:
1271184610Salfred		mii = GET_MII(sc);
1272184610Salfred		if (mii == NULL) {
1273184610Salfred			error = EINVAL;
1274184610Salfred		} else {
1275184610Salfred			error = ifmedia_ioctl
1276184610Salfred			    (ifp, (void *)data, &mii->mii_media, command);
1277184610Salfred		}
1278184610Salfred		break;
1279184610Salfred
1280184610Salfred	default:
1281184610Salfred		error = ether_ioctl(ifp, command, data);
1282184610Salfred		break;
1283184610Salfred	}
1284184610Salfred	return (error);
1285184610Salfred}
1286184610Salfred
1287184610Salfredstatic void
1288184610Salfredrue_watchdog(void *arg)
1289184610Salfred{
1290184610Salfred	struct rue_softc *sc = arg;
1291184610Salfred
1292184610Salfred	mtx_assert(&sc->sc_mtx, MA_OWNED);
1293184610Salfred
1294184610Salfred	usb2_config_td_queue_command
1295184610Salfred	    (&sc->sc_config_td, NULL, &rue_cfg_tick, 0, 0);
1296184610Salfred
1297184610Salfred	usb2_callout_reset(&sc->sc_watchdog,
1298184610Salfred	    hz, &rue_watchdog, sc);
1299184610Salfred}
1300184610Salfred
1301184610Salfred/*
1302184610Salfred * NOTE: can be called when "ifp" is NULL
1303184610Salfred */
1304184610Salfredstatic void
1305184610Salfredrue_cfg_pre_stop(struct rue_softc *sc,
1306184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
1307184610Salfred{
1308184610Salfred	struct ifnet *ifp = sc->sc_ifp;
1309184610Salfred
1310184610Salfred	if (cc) {
1311184610Salfred		/* copy the needed configuration */
1312184610Salfred		rue_config_copy(sc, cc, refcount);
1313184610Salfred	}
1314184610Salfred	/* immediate configuration */
1315184610Salfred
1316184610Salfred	if (ifp) {
1317184610Salfred		/* clear flags */
1318184610Salfred		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1319184610Salfred	}
1320184610Salfred	sc->sc_flags &= ~(RUE_FLAG_HL_READY |
1321184610Salfred	    RUE_FLAG_LL_READY);
1322184610Salfred
1323184610Salfred	sc->sc_flags |= RUE_FLAG_WAIT_LINK;
1324184610Salfred
1325184610Salfred	/*
1326184610Salfred	 * stop all the transfers, if not already stopped:
1327184610Salfred	 */
1328187259Sthompsa	usb2_transfer_stop(sc->sc_xfer[RUE_BULK_DT_WR]);
1329187259Sthompsa	usb2_transfer_stop(sc->sc_xfer[RUE_BULK_DT_RD]);
1330187259Sthompsa	usb2_transfer_stop(sc->sc_xfer[RUE_BULK_CS_WR]);
1331187259Sthompsa	usb2_transfer_stop(sc->sc_xfer[RUE_BULK_CS_RD]);
1332187259Sthompsa	usb2_transfer_stop(sc->sc_xfer[RUE_INTR_DT_RD]);
1333187259Sthompsa	usb2_transfer_stop(sc->sc_xfer[RUE_INTR_CS_RD]);
1334184610Salfred}
1335184610Salfred
1336184610Salfredstatic void
1337184610Salfredrue_cfg_stop(struct rue_softc *sc,
1338184610Salfred    struct usb2_config_td_cc *cc, uint16_t refcount)
1339184610Salfred{
1340184610Salfred	rue_cfg_csr_write_1(sc, RUE_CR, 0x00);
1341184610Salfred
1342184610Salfred	rue_cfg_reset(sc);
1343184610Salfred}
1344184610Salfred
1345184610Salfred/*
1346184610Salfred * Stop all chip I/O so that the kernel's probe routines don't
1347184610Salfred * get confused by errant DMAs when rebooting.
1348184610Salfred */
1349184610Salfredstatic int
1350184610Salfredrue_shutdown(device_t dev)
1351184610Salfred{
1352184610Salfred	struct rue_softc *sc = device_get_softc(dev);
1353184610Salfred
1354184610Salfred	mtx_lock(&sc->sc_mtx);
1355184610Salfred
1356184610Salfred	usb2_config_td_queue_command
1357184610Salfred	    (&sc->sc_config_td, &rue_cfg_pre_stop,
1358184610Salfred	    &rue_cfg_stop, 0, 0);
1359184610Salfred
1360184610Salfred	mtx_unlock(&sc->sc_mtx);
1361184610Salfred
1362184610Salfred	return (0);
1363184610Salfred}
1364