1291557Skevlo/*-
2291557Skevlo * Copyright (c) 2015 Kevin Lo <kevlo@FreeBSD.org>
3291557Skevlo * All rights reserved.
4291557Skevlo *
5291557Skevlo * Redistribution and use in source and binary forms, with or without
6291557Skevlo * modification, are permitted provided that the following conditions
7291557Skevlo * are met:
8291557Skevlo * 1. Redistributions of source code must retain the above copyright
9291557Skevlo *    notice, this list of conditions and the following disclaimer.
10291557Skevlo * 2. Redistributions in binary form must reproduce the above copyright
11291557Skevlo *    notice, this list of conditions and the following disclaimer in the
12291557Skevlo *    documentation and/or other materials provided with the distribution.
13291557Skevlo *
14291557Skevlo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15291557Skevlo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16291557Skevlo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17291557Skevlo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18291557Skevlo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19291557Skevlo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20291557Skevlo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21291557Skevlo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22291557Skevlo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23291557Skevlo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24291557Skevlo * SUCH DAMAGE.
25291557Skevlo */
26291557Skevlo
27291557Skevlo#include <sys/cdefs.h>
28291557Skevlo__FBSDID("$FreeBSD: stable/11/sys/dev/usb/net/if_ure.c 365738 2020-09-15 00:22:30Z jmg $");
29291557Skevlo
30291557Skevlo#include <sys/param.h>
31291557Skevlo#include <sys/systm.h>
32291557Skevlo#include <sys/bus.h>
33291557Skevlo#include <sys/condvar.h>
34291557Skevlo#include <sys/kernel.h>
35291557Skevlo#include <sys/lock.h>
36291557Skevlo#include <sys/module.h>
37291557Skevlo#include <sys/mutex.h>
38291557Skevlo#include <sys/socket.h>
39291557Skevlo#include <sys/sysctl.h>
40291557Skevlo#include <sys/unistd.h>
41291557Skevlo
42291557Skevlo#include <net/if.h>
43291557Skevlo#include <net/if_var.h>
44291557Skevlo
45291557Skevlo#include <dev/usb/usb.h>
46291557Skevlo#include <dev/usb/usbdi.h>
47291557Skevlo#include <dev/usb/usbdi_util.h>
48291557Skevlo#include "usbdevs.h"
49291557Skevlo
50291557Skevlo#define USB_DEBUG_VAR	ure_debug
51291557Skevlo#include <dev/usb/usb_debug.h>
52291557Skevlo#include <dev/usb/usb_process.h>
53291557Skevlo
54291557Skevlo#include <dev/usb/net/usb_ethernet.h>
55291557Skevlo#include <dev/usb/net/if_urereg.h>
56291557Skevlo
57291557Skevlo#ifdef USB_DEBUG
58291557Skevlostatic int ure_debug = 0;
59291557Skevlo
60291557Skevlostatic SYSCTL_NODE(_hw_usb, OID_AUTO, ure, CTLFLAG_RW, 0, "USB ure");
61291557SkevloSYSCTL_INT(_hw_usb_ure, OID_AUTO, debug, CTLFLAG_RWTUN, &ure_debug, 0,
62291557Skevlo    "Debug level");
63291557Skevlo#endif
64291557Skevlo
65291557Skevlo/*
66291557Skevlo * Various supported device vendors/products.
67291557Skevlo */
68291557Skevlostatic const STRUCT_USB_HOST_ID ure_devs[] = {
69291557Skevlo#define	URE_DEV(v,p)	{ USB_VP(USB_VENDOR_##v, USB_PRODUCT_##v##_##p) }
70291557Skevlo	URE_DEV(REALTEK, RTL8152),
71291557Skevlo#undef URE_DEV
72291557Skevlo};
73291557Skevlo
74291557Skevlostatic device_probe_t ure_probe;
75291557Skevlostatic device_attach_t ure_attach;
76291557Skevlostatic device_detach_t ure_detach;
77291557Skevlo
78291557Skevlostatic usb_callback_t ure_bulk_read_callback;
79291557Skevlostatic usb_callback_t ure_bulk_write_callback;
80291557Skevlo
81291557Skevlostatic miibus_readreg_t ure_miibus_readreg;
82291557Skevlostatic miibus_writereg_t ure_miibus_writereg;
83291557Skevlostatic miibus_statchg_t ure_miibus_statchg;
84291557Skevlo
85291557Skevlostatic uether_fn_t ure_attach_post;
86291557Skevlostatic uether_fn_t ure_init;
87291557Skevlostatic uether_fn_t ure_stop;
88291557Skevlostatic uether_fn_t ure_start;
89291557Skevlostatic uether_fn_t ure_tick;
90291557Skevlostatic uether_fn_t ure_setmulti;
91291557Skevlostatic uether_fn_t ure_setpromisc;
92291557Skevlo
93291557Skevlostatic int	ure_ctl(struct ure_softc *, uint8_t, uint16_t, uint16_t,
94291557Skevlo		    void *, int);
95291557Skevlostatic int	ure_read_mem(struct ure_softc *, uint16_t, uint16_t, void *,
96291557Skevlo		    int);
97291557Skevlostatic int	ure_write_mem(struct ure_softc *, uint16_t, uint16_t, void *,
98291557Skevlo		    int);
99291557Skevlostatic uint8_t	ure_read_1(struct ure_softc *, uint16_t, uint16_t);
100291557Skevlostatic uint16_t	ure_read_2(struct ure_softc *, uint16_t, uint16_t);
101291557Skevlostatic uint32_t	ure_read_4(struct ure_softc *, uint16_t, uint16_t);
102291557Skevlostatic int	ure_write_1(struct ure_softc *, uint16_t, uint16_t, uint32_t);
103291557Skevlostatic int	ure_write_2(struct ure_softc *, uint16_t, uint16_t, uint32_t);
104291557Skevlostatic int	ure_write_4(struct ure_softc *, uint16_t, uint16_t, uint32_t);
105291557Skevlostatic uint16_t	ure_ocp_reg_read(struct ure_softc *, uint16_t);
106291557Skevlostatic void	ure_ocp_reg_write(struct ure_softc *, uint16_t, uint16_t);
107291557Skevlo
108291557Skevlostatic void	ure_read_chipver(struct ure_softc *);
109291557Skevlostatic int	ure_attach_post_sub(struct usb_ether *);
110291557Skevlostatic void	ure_reset(struct ure_softc *);
111291557Skevlostatic int	ure_ifmedia_upd(struct ifnet *);
112291557Skevlostatic void	ure_ifmedia_sts(struct ifnet *, struct ifmediareq *);
113291557Skevlostatic int	ure_ioctl(struct ifnet *, u_long, caddr_t);
114291557Skevlostatic void	ure_rtl8152_init(struct ure_softc *);
115291557Skevlostatic void	ure_disable_teredo(struct ure_softc *);
116291557Skevlostatic void	ure_init_fifo(struct ure_softc *);
117291557Skevlo
118291557Skevlostatic const struct usb_config ure_config[URE_N_TRANSFER] = {
119291557Skevlo	[URE_BULK_DT_WR] = {
120291557Skevlo		.type = UE_BULK,
121291557Skevlo		.endpoint = UE_ADDR_ANY,
122291557Skevlo		.direction = UE_DIR_OUT,
123291557Skevlo		.bufsize = MCLBYTES,
124291557Skevlo		.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
125291557Skevlo		.callback = ure_bulk_write_callback,
126291557Skevlo		.timeout = 10000,	/* 10 seconds */
127291557Skevlo	},
128291557Skevlo	[URE_BULK_DT_RD] = {
129291557Skevlo		.type = UE_BULK,
130291557Skevlo		.endpoint = UE_ADDR_ANY,
131291557Skevlo		.direction = UE_DIR_IN,
132291557Skevlo		.bufsize = MCLBYTES,
133291557Skevlo		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
134291557Skevlo		.callback = ure_bulk_read_callback,
135291557Skevlo		.timeout = 0,	/* no timeout */
136291557Skevlo	},
137291557Skevlo};
138291557Skevlo
139291557Skevlostatic device_method_t ure_methods[] = {
140291557Skevlo	/* Device interface. */
141291557Skevlo	DEVMETHOD(device_probe, ure_probe),
142291557Skevlo	DEVMETHOD(device_attach, ure_attach),
143291557Skevlo	DEVMETHOD(device_detach, ure_detach),
144291557Skevlo
145291557Skevlo	/* MII interface. */
146291557Skevlo	DEVMETHOD(miibus_readreg, ure_miibus_readreg),
147291557Skevlo	DEVMETHOD(miibus_writereg, ure_miibus_writereg),
148291557Skevlo	DEVMETHOD(miibus_statchg, ure_miibus_statchg),
149291557Skevlo
150291557Skevlo	DEVMETHOD_END
151291557Skevlo};
152291557Skevlo
153291557Skevlostatic driver_t ure_driver = {
154291557Skevlo	.name = "ure",
155291557Skevlo	.methods = ure_methods,
156291557Skevlo	.size = sizeof(struct ure_softc),
157291557Skevlo};
158291557Skevlo
159291557Skevlostatic devclass_t ure_devclass;
160291557Skevlo
161291557SkevloDRIVER_MODULE(ure, uhub, ure_driver, ure_devclass, NULL, NULL);
162291557SkevloDRIVER_MODULE(miibus, ure, miibus_driver, miibus_devclass, NULL, NULL);
163291557SkevloMODULE_DEPEND(ure, uether, 1, 1, 1);
164291557SkevloMODULE_DEPEND(ure, usb, 1, 1, 1);
165291557SkevloMODULE_DEPEND(ure, ether, 1, 1, 1);
166291557SkevloMODULE_DEPEND(ure, miibus, 1, 1, 1);
167291557SkevloMODULE_VERSION(ure, 1);
168291557Skevlo
169291557Skevlostatic const struct usb_ether_methods ure_ue_methods = {
170291557Skevlo	.ue_attach_post = ure_attach_post,
171291557Skevlo	.ue_attach_post_sub = ure_attach_post_sub,
172291557Skevlo	.ue_start = ure_start,
173291557Skevlo	.ue_init = ure_init,
174291557Skevlo	.ue_stop = ure_stop,
175291557Skevlo	.ue_tick = ure_tick,
176291557Skevlo	.ue_setmulti = ure_setmulti,
177291557Skevlo	.ue_setpromisc = ure_setpromisc,
178291557Skevlo	.ue_mii_upd = ure_ifmedia_upd,
179291557Skevlo	.ue_mii_sts = ure_ifmedia_sts,
180291557Skevlo};
181291557Skevlo
182291557Skevlostatic int
183291557Skevloure_ctl(struct ure_softc *sc, uint8_t rw, uint16_t val, uint16_t index,
184291557Skevlo    void *buf, int len)
185291557Skevlo{
186291557Skevlo	struct usb_device_request req;
187291557Skevlo
188291557Skevlo	URE_LOCK_ASSERT(sc, MA_OWNED);
189291557Skevlo
190291557Skevlo	if (rw == URE_CTL_WRITE)
191291557Skevlo		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
192291557Skevlo	else
193291557Skevlo		req.bmRequestType = UT_READ_VENDOR_DEVICE;
194291557Skevlo	req.bRequest = UR_SET_ADDRESS;
195291557Skevlo	USETW(req.wValue, val);
196291557Skevlo	USETW(req.wIndex, index);
197291557Skevlo	USETW(req.wLength, len);
198291557Skevlo
199291557Skevlo	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
200291557Skevlo}
201291557Skevlo
202291557Skevlostatic int
203291557Skevloure_read_mem(struct ure_softc *sc, uint16_t addr, uint16_t index,
204291557Skevlo    void *buf, int len)
205291557Skevlo{
206291557Skevlo
207291557Skevlo	return (ure_ctl(sc, URE_CTL_READ, addr, index, buf, len));
208291557Skevlo}
209291557Skevlo
210291557Skevlostatic int
211291557Skevloure_write_mem(struct ure_softc *sc, uint16_t addr, uint16_t index,
212291557Skevlo    void *buf, int len)
213291557Skevlo{
214291557Skevlo
215291557Skevlo	return (ure_ctl(sc, URE_CTL_WRITE, addr, index, buf, len));
216291557Skevlo}
217291557Skevlo
218291557Skevlostatic uint8_t
219291557Skevloure_read_1(struct ure_softc *sc, uint16_t reg, uint16_t index)
220291557Skevlo{
221291557Skevlo	uint32_t val;
222291557Skevlo	uint8_t temp[4];
223291557Skevlo	uint8_t shift;
224291557Skevlo
225291557Skevlo	shift = (reg & 3) << 3;
226291557Skevlo	reg &= ~3;
227291557Skevlo
228291557Skevlo	ure_read_mem(sc, reg, index, &temp, 4);
229291557Skevlo	val = UGETDW(temp);
230291557Skevlo	val >>= shift;
231291557Skevlo
232291557Skevlo	return (val & 0xff);
233291557Skevlo}
234291557Skevlo
235291557Skevlostatic uint16_t
236291557Skevloure_read_2(struct ure_softc *sc, uint16_t reg, uint16_t index)
237291557Skevlo{
238291557Skevlo	uint32_t val;
239291557Skevlo	uint8_t temp[4];
240291557Skevlo	uint8_t shift;
241291557Skevlo
242291557Skevlo	shift = (reg & 2) << 3;
243291557Skevlo	reg &= ~3;
244291557Skevlo
245291557Skevlo	ure_read_mem(sc, reg, index, &temp, 4);
246291557Skevlo	val = UGETDW(temp);
247291557Skevlo	val >>= shift;
248291557Skevlo
249291557Skevlo	return (val & 0xffff);
250291557Skevlo}
251291557Skevlo
252291557Skevlostatic uint32_t
253291557Skevloure_read_4(struct ure_softc *sc, uint16_t reg, uint16_t index)
254291557Skevlo{
255291557Skevlo	uint8_t temp[4];
256291557Skevlo
257291557Skevlo	ure_read_mem(sc, reg, index, &temp, 4);
258291557Skevlo	return (UGETDW(temp));
259291557Skevlo}
260291557Skevlo
261291557Skevlostatic int
262291557Skevloure_write_1(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val)
263291557Skevlo{
264291557Skevlo	uint16_t byen;
265291557Skevlo	uint8_t temp[4];
266291557Skevlo	uint8_t shift;
267291557Skevlo
268291557Skevlo	byen = URE_BYTE_EN_BYTE;
269291557Skevlo	shift = reg & 3;
270291557Skevlo	val &= 0xff;
271291557Skevlo
272291557Skevlo	if (reg & 3) {
273291557Skevlo		byen <<= shift;
274291557Skevlo		val <<= (shift << 3);
275291557Skevlo		reg &= ~3;
276291557Skevlo	}
277291557Skevlo
278291557Skevlo	USETDW(temp, val);
279291557Skevlo	return (ure_write_mem(sc, reg, index | byen, &temp, 4));
280291557Skevlo}
281291557Skevlo
282291557Skevlostatic int
283291557Skevloure_write_2(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val)
284291557Skevlo{
285291557Skevlo	uint16_t byen;
286291557Skevlo	uint8_t temp[4];
287291557Skevlo	uint8_t shift;
288291557Skevlo
289291557Skevlo	byen = URE_BYTE_EN_WORD;
290291557Skevlo	shift = reg & 2;
291291557Skevlo	val &= 0xffff;
292291557Skevlo
293291557Skevlo	if (reg & 2) {
294291557Skevlo		byen <<= shift;
295291557Skevlo		val <<= (shift << 3);
296291557Skevlo		reg &= ~3;
297291557Skevlo	}
298291557Skevlo
299291557Skevlo	USETDW(temp, val);
300291557Skevlo	return (ure_write_mem(sc, reg, index | byen, &temp, 4));
301291557Skevlo}
302291557Skevlo
303291557Skevlostatic int
304291557Skevloure_write_4(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val)
305291557Skevlo{
306291557Skevlo	uint8_t temp[4];
307291557Skevlo
308291557Skevlo	USETDW(temp, val);
309291557Skevlo	return (ure_write_mem(sc, reg, index | URE_BYTE_EN_DWORD, &temp, 4));
310291557Skevlo}
311291557Skevlo
312291557Skevlostatic uint16_t
313291557Skevloure_ocp_reg_read(struct ure_softc *sc, uint16_t addr)
314291557Skevlo{
315291557Skevlo	uint16_t reg;
316291557Skevlo
317291557Skevlo	ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000);
318291557Skevlo	reg = (addr & 0x0fff) | 0xb000;
319291557Skevlo
320291557Skevlo	return (ure_read_2(sc, reg, URE_MCU_TYPE_PLA));
321291557Skevlo}
322291557Skevlo
323291557Skevlostatic void
324291557Skevloure_ocp_reg_write(struct ure_softc *sc, uint16_t addr, uint16_t data)
325291557Skevlo{
326291557Skevlo	uint16_t reg;
327291557Skevlo
328291557Skevlo	ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000);
329291557Skevlo	reg = (addr & 0x0fff) | 0xb000;
330291557Skevlo
331291557Skevlo	ure_write_2(sc, reg, URE_MCU_TYPE_PLA, data);
332291557Skevlo}
333291557Skevlo
334291557Skevlostatic int
335291557Skevloure_miibus_readreg(device_t dev, int phy, int reg)
336291557Skevlo{
337291557Skevlo	struct ure_softc *sc;
338291557Skevlo	uint16_t val;
339291557Skevlo	int locked;
340291557Skevlo
341291557Skevlo	sc = device_get_softc(dev);
342291557Skevlo	locked = mtx_owned(&sc->sc_mtx);
343291557Skevlo	if (!locked)
344291557Skevlo		URE_LOCK(sc);
345291557Skevlo
346291557Skevlo	val = ure_ocp_reg_read(sc, URE_OCP_BASE_MII + reg * 2);
347291557Skevlo
348291557Skevlo	if (!locked)
349291557Skevlo		URE_UNLOCK(sc);
350291557Skevlo	return (val);
351291557Skevlo}
352291557Skevlo
353291557Skevlostatic int
354291557Skevloure_miibus_writereg(device_t dev, int phy, int reg, int val)
355291557Skevlo{
356291557Skevlo	struct ure_softc *sc;
357291557Skevlo	int locked;
358291557Skevlo
359291557Skevlo	sc = device_get_softc(dev);
360291557Skevlo	if (sc->sc_phyno != phy)
361291557Skevlo		return (0);
362291557Skevlo
363291557Skevlo	locked = mtx_owned(&sc->sc_mtx);
364291557Skevlo	if (!locked)
365291557Skevlo		URE_LOCK(sc);
366291557Skevlo
367291557Skevlo	ure_ocp_reg_write(sc, URE_OCP_BASE_MII + reg * 2, val);
368291557Skevlo
369291557Skevlo	if (!locked)
370291557Skevlo		URE_UNLOCK(sc);
371291557Skevlo	return (0);
372291557Skevlo}
373291557Skevlo
374291557Skevlostatic void
375291557Skevloure_miibus_statchg(device_t dev)
376291557Skevlo{
377291557Skevlo	struct ure_softc *sc;
378291557Skevlo	struct mii_data *mii;
379291557Skevlo	struct ifnet *ifp;
380291557Skevlo	int locked;
381291557Skevlo
382291557Skevlo	sc = device_get_softc(dev);
383291557Skevlo	mii = GET_MII(sc);
384291557Skevlo	locked = mtx_owned(&sc->sc_mtx);
385291557Skevlo	if (!locked)
386291557Skevlo		URE_LOCK(sc);
387291557Skevlo
388291557Skevlo	ifp = uether_getifp(&sc->sc_ue);
389291557Skevlo	if (mii == NULL || ifp == NULL ||
390291557Skevlo	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
391291557Skevlo		goto done;
392291557Skevlo
393291557Skevlo	sc->sc_flags &= ~URE_FLAG_LINK;
394291557Skevlo	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
395291557Skevlo	    (IFM_ACTIVE | IFM_AVALID)) {
396291557Skevlo		switch (IFM_SUBTYPE(mii->mii_media_active)) {
397291557Skevlo		case IFM_10_T:
398291557Skevlo		case IFM_100_TX:
399291557Skevlo			sc->sc_flags |= URE_FLAG_LINK;
400291557Skevlo			break;
401291557Skevlo		default:
402291557Skevlo			break;
403291557Skevlo		}
404291557Skevlo	}
405291557Skevlo
406291557Skevlo	/* Lost link, do nothing. */
407291557Skevlo	if ((sc->sc_flags & URE_FLAG_LINK) == 0)
408291557Skevlo		goto done;
409291557Skevlodone:
410291557Skevlo	if (!locked)
411291557Skevlo		URE_UNLOCK(sc);
412291557Skevlo}
413291557Skevlo
414291557Skevlo/*
415291557Skevlo * Probe for a RTL8152 chip.
416291557Skevlo */
417291557Skevlostatic int
418291557Skevloure_probe(device_t dev)
419291557Skevlo{
420291557Skevlo	struct usb_attach_arg *uaa;
421291557Skevlo
422297793Spfg	uaa = device_get_ivars(dev);
423291557Skevlo	if (uaa->usb_mode != USB_MODE_HOST)
424291557Skevlo		return (ENXIO);
425291557Skevlo	if (uaa->info.bConfigIndex != URE_CONFIG_IDX)
426291557Skevlo		return (ENXIO);
427291557Skevlo	if (uaa->info.bIfaceIndex != URE_IFACE_IDX)
428291557Skevlo		return (ENXIO);
429291557Skevlo
430291557Skevlo	return (usbd_lookup_id_by_uaa(ure_devs, sizeof(ure_devs), uaa));
431291557Skevlo}
432291557Skevlo
433291557Skevlo/*
434291557Skevlo * Attach the interface. Allocate softc structures, do ifmedia
435291557Skevlo * setup and ethernet/BPF attach.
436291557Skevlo */
437291557Skevlostatic int
438291557Skevloure_attach(device_t dev)
439291557Skevlo{
440291557Skevlo	struct usb_attach_arg *uaa = device_get_ivars(dev);
441291557Skevlo	struct ure_softc *sc = device_get_softc(dev);
442291557Skevlo	struct usb_ether *ue = &sc->sc_ue;
443291557Skevlo	uint8_t iface_index;
444291557Skevlo	int error;
445291557Skevlo
446291557Skevlo	device_set_usb_desc(dev);
447291557Skevlo	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
448291557Skevlo
449291557Skevlo	iface_index = URE_IFACE_IDX;
450291557Skevlo	error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
451291557Skevlo	    ure_config, URE_N_TRANSFER, sc, &sc->sc_mtx);
452291557Skevlo	if (error != 0) {
453291557Skevlo		device_printf(dev, "allocating USB transfers failed\n");
454291557Skevlo		goto detach;
455291557Skevlo	}
456291557Skevlo
457291557Skevlo	ue->ue_sc = sc;
458291557Skevlo	ue->ue_dev = dev;
459291557Skevlo	ue->ue_udev = uaa->device;
460291557Skevlo	ue->ue_mtx = &sc->sc_mtx;
461291557Skevlo	ue->ue_methods = &ure_ue_methods;
462291557Skevlo
463291557Skevlo	error = uether_ifattach(ue);
464291557Skevlo	if (error != 0) {
465291557Skevlo		device_printf(dev, "could not attach interface\n");
466291557Skevlo		goto detach;
467291557Skevlo	}
468291557Skevlo	return (0);			/* success */
469291557Skevlo
470291557Skevlodetach:
471291557Skevlo	ure_detach(dev);
472291557Skevlo	return (ENXIO);			/* failure */
473291557Skevlo}
474291557Skevlo
475291557Skevlostatic int
476291557Skevloure_detach(device_t dev)
477291557Skevlo{
478291557Skevlo	struct ure_softc *sc = device_get_softc(dev);
479291557Skevlo	struct usb_ether *ue = &sc->sc_ue;
480291557Skevlo
481291557Skevlo	usbd_transfer_unsetup(sc->sc_xfer, URE_N_TRANSFER);
482291557Skevlo	uether_ifdetach(ue);
483291557Skevlo	mtx_destroy(&sc->sc_mtx);
484291557Skevlo
485291557Skevlo	return (0);
486291557Skevlo}
487291557Skevlo
488291557Skevlostatic void
489291557Skevloure_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
490291557Skevlo{
491291557Skevlo	struct ure_softc *sc = usbd_xfer_softc(xfer);
492291557Skevlo	struct usb_ether *ue = &sc->sc_ue;
493291557Skevlo	struct ifnet *ifp = uether_getifp(ue);
494291557Skevlo	struct usb_page_cache *pc;
495291557Skevlo	struct ure_rxpkt pkt;
496291557Skevlo	int actlen, len;
497291557Skevlo
498291557Skevlo	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
499291557Skevlo
500291557Skevlo	switch (USB_GET_STATE(xfer)) {
501291557Skevlo	case USB_ST_TRANSFERRED:
502291557Skevlo		if (actlen < (int)(sizeof(pkt))) {
503291557Skevlo			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
504291557Skevlo			goto tr_setup;
505291557Skevlo		}
506291557Skevlo		pc = usbd_xfer_get_frame(xfer, 0);
507291557Skevlo		usbd_copy_out(pc, 0, &pkt, sizeof(pkt));
508291557Skevlo		len = le32toh(pkt.ure_pktlen) & URE_RXPKT_LEN_MASK;
509291557Skevlo		len -= ETHER_CRC_LEN;
510291557Skevlo		if (actlen < (int)(len + sizeof(pkt))) {
511291557Skevlo			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
512291557Skevlo			goto tr_setup;
513291557Skevlo		}
514291557Skevlo
515291557Skevlo		uether_rxbuf(ue, pc, sizeof(pkt), len);
516291557Skevlo		/* FALLTHROUGH */
517291557Skevlo	case USB_ST_SETUP:
518291557Skevlotr_setup:
519291557Skevlo		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
520291557Skevlo		usbd_transfer_submit(xfer);
521291557Skevlo		uether_rxflush(ue);
522291557Skevlo		return;
523291557Skevlo
524291557Skevlo	default:			/* Error */
525291557Skevlo		DPRINTF("bulk read error, %s\n",
526291557Skevlo		    usbd_errstr(error));
527291557Skevlo
528291557Skevlo		if (error != USB_ERR_CANCELLED) {
529291557Skevlo			/* try to clear stall first */
530291557Skevlo			usbd_xfer_set_stall(xfer);
531291557Skevlo			goto tr_setup;
532291557Skevlo		}
533291557Skevlo		return;
534291557Skevlo	}
535291557Skevlo}
536291557Skevlo
537291557Skevlostatic void
538291557Skevloure_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
539291557Skevlo{
540291557Skevlo	struct ure_softc *sc = usbd_xfer_softc(xfer);
541291557Skevlo	struct ifnet *ifp = uether_getifp(&sc->sc_ue);
542291557Skevlo	struct usb_page_cache *pc;
543291557Skevlo	struct mbuf *m;
544291557Skevlo	struct ure_txpkt txpkt;
545291557Skevlo	int len, pos;
546291557Skevlo
547291557Skevlo	switch (USB_GET_STATE(xfer)) {
548291557Skevlo	case USB_ST_TRANSFERRED:
549291557Skevlo		DPRINTFN(11, "transfer complete\n");
550291557Skevlo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
551291557Skevlo		/* FALLTHROUGH */
552291557Skevlo	case USB_ST_SETUP:
553291557Skevlotr_setup:
554291557Skevlo		if ((sc->sc_flags & URE_FLAG_LINK) == 0 ||
555291557Skevlo		    (ifp->if_drv_flags & IFF_DRV_OACTIVE) != 0) {
556291557Skevlo			/*
557291557Skevlo			 * don't send anything if there is no link !
558291557Skevlo			 */
559291557Skevlo			return;
560291557Skevlo		}
561291557Skevlo		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
562291557Skevlo		if (m == NULL)
563291557Skevlo			break;
564291557Skevlo		pos = 0;
565291557Skevlo		len = m->m_pkthdr.len;
566291557Skevlo		pc = usbd_xfer_get_frame(xfer, 0);
567291557Skevlo		memset(&txpkt, 0, sizeof(txpkt));
568291557Skevlo		txpkt.ure_pktlen = htole32((len & URE_TXPKT_LEN_MASK) |
569291557Skevlo		    URE_TKPKT_TX_FS | URE_TKPKT_TX_LS);
570291557Skevlo		usbd_copy_in(pc, pos, &txpkt, sizeof(txpkt));
571291557Skevlo		pos += sizeof(txpkt);
572291557Skevlo		usbd_m_copy_in(pc, pos, m, 0, m->m_pkthdr.len);
573291557Skevlo		pos += m->m_pkthdr.len;
574291557Skevlo
575291557Skevlo		if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
576291557Skevlo
577291557Skevlo		/*
578291557Skevlo		 * If there's a BPF listener, bounce a copy
579291557Skevlo		 * of this frame to him.
580291557Skevlo		 */
581291557Skevlo		BPF_MTAP(ifp, m);
582291557Skevlo
583291557Skevlo		m_freem(m);
584291557Skevlo
585291557Skevlo		/* Set frame length. */
586291557Skevlo		usbd_xfer_set_frame_len(xfer, 0, pos);
587291557Skevlo
588291557Skevlo		usbd_transfer_submit(xfer);
589291557Skevlo		ifp->if_drv_flags |= IFF_DRV_OACTIVE;
590291557Skevlo		return;
591291557Skevlo	default:			/* Error */
592291557Skevlo		DPRINTFN(11, "transfer error, %s\n",
593291557Skevlo		    usbd_errstr(error));
594291557Skevlo
595291557Skevlo		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
596291557Skevlo		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
597291557Skevlo
598291557Skevlo		if (error != USB_ERR_CANCELLED) {
599291557Skevlo			/* try to clear stall first */
600291557Skevlo			usbd_xfer_set_stall(xfer);
601291557Skevlo			goto tr_setup;
602291557Skevlo		}
603291557Skevlo		return;
604291557Skevlo	}
605291557Skevlo}
606291557Skevlo
607291557Skevlostatic void
608291557Skevloure_read_chipver(struct ure_softc *sc)
609291557Skevlo{
610291557Skevlo	uint16_t ver;
611291557Skevlo
612291557Skevlo	ver = ure_read_2(sc, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK;
613291557Skevlo	switch (ver) {
614291557Skevlo	case 0x4c00:
615291557Skevlo		sc->sc_chip |= URE_CHIP_VER_4C00;
616291557Skevlo		break;
617291557Skevlo	case 0x4c10:
618291557Skevlo		sc->sc_chip |= URE_CHIP_VER_4C10;
619291557Skevlo		break;
620291557Skevlo	default:
621291557Skevlo		device_printf(sc->sc_ue.ue_dev,
622291557Skevlo		    "unknown version 0x%04x\n", ver);
623291557Skevlo		break;
624291557Skevlo	}
625291557Skevlo}
626291557Skevlo
627291557Skevlostatic void
628291557Skevloure_attach_post(struct usb_ether *ue)
629291557Skevlo{
630291557Skevlo	struct ure_softc *sc = uether_getsc(ue);
631291557Skevlo
632291557Skevlo	sc->sc_phyno = 0;
633291557Skevlo
634291557Skevlo	/* Determine the chip version. */
635291557Skevlo	ure_read_chipver(sc);
636291557Skevlo
637291557Skevlo	/* Initialize controller and get station address. */
638291557Skevlo	ure_rtl8152_init(sc);
639291557Skevlo
640291557Skevlo	if (sc->sc_chip & URE_CHIP_VER_4C00)
641291557Skevlo		ure_read_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA,
642291557Skevlo		    ue->ue_eaddr, 8);
643291557Skevlo	else
644291557Skevlo		ure_read_mem(sc, URE_PLA_BACKUP, URE_MCU_TYPE_PLA,
645291557Skevlo		    ue->ue_eaddr, 8);
646291557Skevlo}
647291557Skevlo
648291557Skevlostatic int
649291557Skevloure_attach_post_sub(struct usb_ether *ue)
650291557Skevlo{
651291557Skevlo	struct ure_softc *sc;
652291557Skevlo	struct ifnet *ifp;
653291557Skevlo	int error;
654291557Skevlo
655291557Skevlo	sc = uether_getsc(ue);
656291557Skevlo	ifp = ue->ue_ifp;
657291557Skevlo	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
658291557Skevlo	ifp->if_start = uether_start;
659291557Skevlo	ifp->if_ioctl = ure_ioctl;
660291557Skevlo	ifp->if_init = uether_init;
661291557Skevlo	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
662291557Skevlo	ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
663291557Skevlo	IFQ_SET_READY(&ifp->if_snd);
664291557Skevlo
665291557Skevlo	mtx_lock(&Giant);
666291557Skevlo	error = mii_attach(ue->ue_dev, &ue->ue_miibus, ifp,
667291557Skevlo	    uether_ifmedia_upd, ue->ue_methods->ue_mii_sts,
668291557Skevlo	    BMSR_DEFCAPMASK, sc->sc_phyno, MII_OFFSET_ANY, 0);
669291557Skevlo	mtx_unlock(&Giant);
670291557Skevlo
671291557Skevlo	return (error);
672291557Skevlo}
673291557Skevlo
674291557Skevlostatic void
675291557Skevloure_init(struct usb_ether *ue)
676291557Skevlo{
677291557Skevlo	struct ure_softc *sc = uether_getsc(ue);
678291557Skevlo	struct ifnet *ifp = uether_getifp(ue);
679291557Skevlo	uint32_t rxmode;
680291557Skevlo
681291557Skevlo	URE_LOCK_ASSERT(sc, MA_OWNED);
682291557Skevlo
683291557Skevlo	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
684291557Skevlo		return;
685291557Skevlo
686291557Skevlo	/* Cancel pending I/O. */
687291557Skevlo	ure_stop(ue);
688291557Skevlo
689291557Skevlo	ure_reset(sc);
690291557Skevlo
691291557Skevlo	/* Set MAC address. */
692291557Skevlo	ure_write_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES,
693291557Skevlo	    IF_LLADDR(ifp), 8);
694291557Skevlo
695291557Skevlo	/* Reset the packet filter. */
696291557Skevlo	ure_write_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA,
697291557Skevlo	    ure_read_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA) &
698291557Skevlo	    ~URE_FMC_FCR_MCU_EN);
699291557Skevlo	ure_write_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA,
700291557Skevlo	    ure_read_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA) |
701291557Skevlo	    URE_FMC_FCR_MCU_EN);
702291557Skevlo
703291557Skevlo	/* Enable transmit and receive. */
704291557Skevlo	ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA,
705291557Skevlo	    ure_read_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA) | URE_CR_RE |
706291557Skevlo	    URE_CR_TE);
707291557Skevlo
708291557Skevlo	ure_write_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA,
709291557Skevlo	    ure_read_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) &
710291557Skevlo	    ~URE_RXDY_GATED_EN);
711291557Skevlo
712291557Skevlo	/* Set Rx mode. */
713365738Sjmg	rxmode = ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA);
714365738Sjmg	rxmode &= ~URE_RCR_ACPT_ALL;
715365738Sjmg	rxmode |= URE_RCR_APM;
716291557Skevlo
717291557Skevlo	/* If we want promiscuous mode, set the allframes bit. */
718291557Skevlo	if (ifp->if_flags & IFF_PROMISC)
719291557Skevlo		rxmode |= URE_RCR_AAP;
720291557Skevlo
721291557Skevlo	if (ifp->if_flags & IFF_BROADCAST)
722291557Skevlo		rxmode |= URE_RCR_AB;
723291557Skevlo
724291557Skevlo	ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode);
725291557Skevlo
726291557Skevlo	/* Load the multicast filter. */
727291557Skevlo	ure_setmulti(ue);
728291557Skevlo
729291557Skevlo	usbd_xfer_set_stall(sc->sc_xfer[URE_BULK_DT_WR]);
730291557Skevlo
731291557Skevlo	/* Indicate we are up and running. */
732291557Skevlo	ifp->if_drv_flags |= IFF_DRV_RUNNING;
733291557Skevlo
734291557Skevlo	/* Switch to selected media. */
735291557Skevlo	ure_ifmedia_upd(ifp);
736291557Skevlo}
737291557Skevlo
738291557Skevlostatic void
739291557Skevloure_tick(struct usb_ether *ue)
740291557Skevlo{
741291557Skevlo	struct ure_softc *sc = uether_getsc(ue);
742291557Skevlo	struct mii_data *mii = GET_MII(sc);
743291557Skevlo
744291557Skevlo	URE_LOCK_ASSERT(sc, MA_OWNED);
745291557Skevlo
746291557Skevlo	mii_tick(mii);
747291557Skevlo	if ((sc->sc_flags & URE_FLAG_LINK) == 0
748291557Skevlo	    && mii->mii_media_status & IFM_ACTIVE &&
749291557Skevlo	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
750291557Skevlo		sc->sc_flags |= URE_FLAG_LINK;
751291557Skevlo		ure_start(ue);
752291557Skevlo	}
753291557Skevlo}
754291557Skevlo
755291557Skevlostatic void
756291557Skevloure_setpromisc(struct usb_ether *ue)
757291557Skevlo{
758291557Skevlo	struct ure_softc *sc = uether_getsc(ue);
759291557Skevlo	struct ifnet *ifp = uether_getifp(ue);
760291557Skevlo	uint32_t rxmode;
761291557Skevlo
762291557Skevlo	rxmode = ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA);
763291557Skevlo
764291557Skevlo	if (ifp->if_flags & IFF_PROMISC)
765291557Skevlo		rxmode |= URE_RCR_AAP;
766291557Skevlo	else
767291557Skevlo		rxmode &= ~URE_RCR_AAP;
768291557Skevlo
769291557Skevlo	ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode);
770291557Skevlo
771291557Skevlo	ure_setmulti(ue);
772291557Skevlo}
773291557Skevlo
774291557Skevlo/*
775291557Skevlo * Program the 64-bit multicast hash filter.
776291557Skevlo */
777291557Skevlostatic void
778291557Skevloure_setmulti(struct usb_ether *ue)
779291557Skevlo{
780291557Skevlo	struct ure_softc *sc = uether_getsc(ue);
781291557Skevlo	struct ifnet *ifp = uether_getifp(ue);
782291557Skevlo	struct ifmultiaddr *ifma;
783291557Skevlo	uint32_t h, rxmode;
784291557Skevlo	uint32_t hashes[2] = { 0, 0 };
785291557Skevlo
786291557Skevlo	URE_LOCK_ASSERT(sc, MA_OWNED);
787291557Skevlo
788291557Skevlo	rxmode = ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA);
789291557Skevlo	if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) {
790291557Skevlo		if (ifp->if_flags & IFF_PROMISC)
791291557Skevlo			rxmode |= URE_RCR_AAP;
792291557Skevlo		rxmode |= URE_RCR_AM;
793291557Skevlo		hashes[0] = hashes[1] = 0xffffffff;
794291557Skevlo		goto done;
795291557Skevlo	}
796291557Skevlo
797291557Skevlo	if_maddr_rlock(ifp);
798291557Skevlo	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
799291557Skevlo		if (ifma->ifma_addr->sa_family != AF_LINK)
800291557Skevlo			continue;
801291557Skevlo		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
802291557Skevlo		ifma->ifma_addr), ETHER_ADDR_LEN) >> 26;
803291557Skevlo		if (h < 32)
804291557Skevlo			hashes[0] |= (1 << h);
805291557Skevlo		else
806291557Skevlo			hashes[1] |= (1 << (h - 32));
807291557Skevlo	}
808291557Skevlo	if_maddr_runlock(ifp);
809291557Skevlo
810291557Skevlo	h = bswap32(hashes[0]);
811291557Skevlo	hashes[0] = bswap32(hashes[1]);
812291557Skevlo	hashes[1] = h;
813291557Skevlo	rxmode |= URE_RCR_AM;
814291557Skevlo
815291557Skevlodone:
816291557Skevlo	ure_write_4(sc, URE_PLA_MAR0, URE_MCU_TYPE_PLA, hashes[0]);
817291557Skevlo	ure_write_4(sc, URE_PLA_MAR4, URE_MCU_TYPE_PLA, hashes[1]);
818291557Skevlo	ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode);
819291557Skevlo}
820291557Skevlo
821291557Skevlostatic void
822291557Skevloure_start(struct usb_ether *ue)
823291557Skevlo{
824291557Skevlo	struct ure_softc *sc = uether_getsc(ue);
825291557Skevlo
826291557Skevlo	/*
827291557Skevlo	 * start the USB transfers, if not already started:
828291557Skevlo	 */
829291557Skevlo	usbd_transfer_start(sc->sc_xfer[URE_BULK_DT_RD]);
830291557Skevlo	usbd_transfer_start(sc->sc_xfer[URE_BULK_DT_WR]);
831291557Skevlo}
832291557Skevlo
833291557Skevlostatic void
834291557Skevloure_reset(struct ure_softc *sc)
835291557Skevlo{
836291557Skevlo	int i;
837291557Skevlo
838291557Skevlo	ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST);
839291557Skevlo
840291557Skevlo	for (i = 0; i < URE_TIMEOUT; i++) {
841291557Skevlo		if (!(ure_read_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA) &
842291557Skevlo		    URE_CR_RST))
843291557Skevlo			break;
844291557Skevlo		uether_pause(&sc->sc_ue, hz / 100);
845291557Skevlo	}
846291557Skevlo	if (i == URE_TIMEOUT)
847291557Skevlo		device_printf(sc->sc_ue.ue_dev, "reset never completed\n");
848291557Skevlo}
849291557Skevlo
850291557Skevlo/*
851291557Skevlo * Set media options.
852291557Skevlo */
853291557Skevlostatic int
854291557Skevloure_ifmedia_upd(struct ifnet *ifp)
855291557Skevlo{
856291557Skevlo	struct ure_softc *sc = ifp->if_softc;
857291557Skevlo	struct mii_data *mii = GET_MII(sc);
858291557Skevlo	struct mii_softc *miisc;
859291557Skevlo	int error;
860291557Skevlo
861291557Skevlo	URE_LOCK_ASSERT(sc, MA_OWNED);
862291557Skevlo
863291557Skevlo	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
864291557Skevlo		PHY_RESET(miisc);
865291557Skevlo	error = mii_mediachg(mii);
866291557Skevlo	return (error);
867291557Skevlo}
868291557Skevlo
869291557Skevlo/*
870291557Skevlo * Report current media status.
871291557Skevlo */
872291557Skevlostatic void
873291557Skevloure_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
874291557Skevlo{
875291557Skevlo	struct ure_softc *sc;
876291557Skevlo	struct mii_data *mii;
877291557Skevlo
878291557Skevlo	sc = ifp->if_softc;
879291557Skevlo	mii = GET_MII(sc);
880291557Skevlo
881291557Skevlo	URE_LOCK(sc);
882291557Skevlo	mii_pollstat(mii);
883291557Skevlo	ifmr->ifm_active = mii->mii_media_active;
884291557Skevlo	ifmr->ifm_status = mii->mii_media_status;
885291557Skevlo	URE_UNLOCK(sc);
886291557Skevlo}
887291557Skevlo
888291557Skevlostatic int
889291557Skevloure_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
890291557Skevlo{
891291557Skevlo	struct usb_ether *ue = ifp->if_softc;
892291557Skevlo	struct ure_softc *sc;
893291557Skevlo	struct ifreq *ifr;
894291557Skevlo	int error, mask, reinit;
895291557Skevlo
896291557Skevlo	sc = uether_getsc(ue);
897291557Skevlo	ifr = (struct ifreq *)data;
898291557Skevlo	error = 0;
899291557Skevlo	reinit = 0;
900291557Skevlo	if (cmd == SIOCSIFCAP) {
901291557Skevlo		URE_LOCK(sc);
902291557Skevlo		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
903291557Skevlo		if (reinit > 0 && ifp->if_drv_flags & IFF_DRV_RUNNING)
904291557Skevlo			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
905291557Skevlo		else
906291557Skevlo			reinit = 0;
907291557Skevlo		URE_UNLOCK(sc);
908291557Skevlo		if (reinit > 0)
909291557Skevlo			uether_init(ue);
910291557Skevlo	} else
911291557Skevlo		error = uether_ioctl(ifp, cmd, data);
912291557Skevlo
913291557Skevlo	return (error);
914291557Skevlo}
915291557Skevlo
916291557Skevlostatic void
917291557Skevloure_rtl8152_init(struct ure_softc *sc)
918291557Skevlo{
919291557Skevlo	uint32_t pwrctrl;
920291557Skevlo
921291557Skevlo	/* Disable ALDPS. */
922291557Skevlo	ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA |
923291557Skevlo	    URE_DIS_SDSAVE);
924291557Skevlo	uether_pause(&sc->sc_ue, hz / 50);
925291557Skevlo
926291557Skevlo	if (sc->sc_chip & URE_CHIP_VER_4C00) {
927291557Skevlo		ure_write_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA,
928291557Skevlo		    ure_read_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) &
929291557Skevlo		    ~URE_LED_MODE_MASK);
930291557Skevlo	}
931291557Skevlo
932291557Skevlo	ure_write_2(sc, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB,
933291557Skevlo	    ure_read_2(sc, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) &
934291557Skevlo	    ~URE_POWER_CUT);
935291557Skevlo	ure_write_2(sc, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB,
936291557Skevlo	    ure_read_2(sc, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) &
937291557Skevlo	    ~URE_RESUME_INDICATE);
938291557Skevlo
939291557Skevlo	ure_write_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA,
940291557Skevlo	    ure_read_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) |
941291557Skevlo	    URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH);
942291557Skevlo	pwrctrl = ure_read_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA);
943291557Skevlo	pwrctrl &= ~URE_MCU_CLK_RATIO_MASK;
944291557Skevlo	pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN;
945291557Skevlo	ure_write_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl);
946291557Skevlo	ure_write_2(sc, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA,
947291557Skevlo	    URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK |
948291557Skevlo	    URE_SPDWN_LINKCHG_MSK);
949291557Skevlo
950291557Skevlo	/* Disable Rx aggregation. */
951291557Skevlo	ure_write_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB,
952291557Skevlo	    ure_read_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) |
953291557Skevlo	    URE_RX_AGG_DISABLE);
954291557Skevlo
955291557Skevlo        /* Disable ALDPS. */
956291557Skevlo	ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA |
957291557Skevlo	    URE_DIS_SDSAVE);
958291557Skevlo	uether_pause(&sc->sc_ue, hz / 50);
959291557Skevlo
960291557Skevlo	ure_init_fifo(sc);
961291557Skevlo
962291557Skevlo	ure_write_1(sc, URE_USB_TX_AGG, URE_MCU_TYPE_USB,
963291557Skevlo	    URE_TX_AGG_MAX_THRESHOLD);
964291557Skevlo	ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH);
965291557Skevlo	ure_write_4(sc, URE_USB_TX_DMA, URE_MCU_TYPE_USB,
966291557Skevlo	    URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1);
967291557Skevlo}
968291557Skevlo
969291557Skevlostatic void
970291557Skevloure_stop(struct usb_ether *ue)
971291557Skevlo{
972291557Skevlo	struct ure_softc *sc = uether_getsc(ue);
973291557Skevlo	struct ifnet *ifp = uether_getifp(ue);
974291557Skevlo
975291557Skevlo	URE_LOCK_ASSERT(sc, MA_OWNED);
976291557Skevlo
977291557Skevlo	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
978291557Skevlo	sc->sc_flags &= ~URE_FLAG_LINK;
979291557Skevlo
980291557Skevlo	/*
981291557Skevlo	 * stop all the transfers, if not already stopped:
982291557Skevlo	 */
983291557Skevlo	usbd_transfer_stop(sc->sc_xfer[URE_BULK_DT_WR]);
984291557Skevlo	usbd_transfer_stop(sc->sc_xfer[URE_BULK_DT_RD]);
985291557Skevlo}
986291557Skevlo
987291557Skevlostatic void
988291557Skevloure_disable_teredo(struct ure_softc *sc)
989291557Skevlo{
990291557Skevlo
991291557Skevlo	ure_write_4(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA,
992291557Skevlo	    ure_read_4(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) &
993291557Skevlo	    ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN));
994291557Skevlo	ure_write_2(sc, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA,
995291557Skevlo	    URE_WDT6_SET_MODE);
996291557Skevlo	ure_write_2(sc, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0);
997291557Skevlo	ure_write_4(sc, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0);
998291557Skevlo}
999291557Skevlo
1000291557Skevlostatic void
1001291557Skevloure_init_fifo(struct ure_softc *sc)
1002291557Skevlo{
1003291557Skevlo	uint32_t rx_fifo1, rx_fifo2;
1004291557Skevlo	int i;
1005291557Skevlo
1006291557Skevlo	ure_write_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA,
1007291557Skevlo	    ure_read_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) |
1008291557Skevlo	    URE_RXDY_GATED_EN);
1009291557Skevlo
1010291557Skevlo	ure_disable_teredo(sc);
1011291557Skevlo
1012291557Skevlo	ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA,
1013291557Skevlo	    ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA) &
1014291557Skevlo	    ~URE_RCR_ACPT_ALL);
1015291557Skevlo
1016291557Skevlo	ure_reset(sc);
1017291557Skevlo
1018291557Skevlo	ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, 0);
1019291557Skevlo
1020291557Skevlo	ure_write_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA,
1021291557Skevlo	    ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
1022291557Skevlo	    ~URE_NOW_IS_OOB);
1023291557Skevlo
1024291557Skevlo	ure_write_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA,
1025291557Skevlo	    ure_read_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) &
1026291557Skevlo	    ~URE_MCU_BORW_EN);
1027291557Skevlo	for (i = 0; i < URE_TIMEOUT; i++) {
1028291557Skevlo		if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
1029291557Skevlo		    URE_LINK_LIST_READY)
1030291557Skevlo			break;
1031291557Skevlo		uether_pause(&sc->sc_ue, hz / 100);
1032291557Skevlo	}
1033291557Skevlo	if (i == URE_TIMEOUT)
1034291557Skevlo		device_printf(sc->sc_ue.ue_dev,
1035291557Skevlo		    "timeout waiting for OOB control\n");
1036291557Skevlo	ure_write_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA,
1037291557Skevlo	    ure_read_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) |
1038291557Skevlo	    URE_RE_INIT_LL);
1039291557Skevlo	for (i = 0; i < URE_TIMEOUT; i++) {
1040291557Skevlo		if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
1041291557Skevlo		    URE_LINK_LIST_READY)
1042291557Skevlo			break;
1043291557Skevlo		uether_pause(&sc->sc_ue, hz / 100);
1044291557Skevlo	}
1045291557Skevlo	if (i == URE_TIMEOUT)
1046291557Skevlo		device_printf(sc->sc_ue.ue_dev,
1047291557Skevlo		    "timeout waiting for OOB control\n");
1048291557Skevlo
1049291557Skevlo	ure_write_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA,
1050291557Skevlo	    ure_read_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA) &
1051291557Skevlo	    ~URE_CPCR_RX_VLAN);
1052291557Skevlo	ure_write_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA,
1053291557Skevlo	    ure_read_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA) |
1054291557Skevlo	    URE_TCR0_AUTO_FIFO);
1055291557Skevlo
1056291557Skevlo	/* Configure Rx FIFO threshold. */
1057291557Skevlo	ure_write_4(sc, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA,
1058291557Skevlo	    URE_RXFIFO_THR1_NORMAL);
1059291557Skevlo	if (usbd_get_speed(sc->sc_ue.ue_udev) == USB_SPEED_FULL) {
1060291557Skevlo		rx_fifo1 = URE_RXFIFO_THR2_FULL;
1061291557Skevlo		rx_fifo2 = URE_RXFIFO_THR3_FULL;
1062291557Skevlo	} else {
1063291557Skevlo		rx_fifo1 = URE_RXFIFO_THR2_HIGH;
1064291557Skevlo		rx_fifo2 = URE_RXFIFO_THR3_HIGH;
1065291557Skevlo	}
1066291557Skevlo	ure_write_4(sc, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1);
1067291557Skevlo	ure_write_4(sc, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2);
1068291557Skevlo
1069291557Skevlo	/* Configure Tx FIFO threshold. */
1070291557Skevlo	ure_write_4(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA,
1071291557Skevlo	    URE_TXFIFO_THR_NORMAL);
1072291557Skevlo}
1073