xref: /freebsd-src/sys/dev/usb/net/if_ure.c (revision dc273058cb0b6bef075e77272afc66f1a1fd3889)
1e1b74f21SKevin Lo /*-
2a24d62b5SKevin Lo  * Copyright (c) 2015-2016 Kevin Lo <kevlo@FreeBSD.org>
3e1b74f21SKevin Lo  * All rights reserved.
4e1b74f21SKevin Lo  *
5e1b74f21SKevin Lo  * Redistribution and use in source and binary forms, with or without
6e1b74f21SKevin Lo  * modification, are permitted provided that the following conditions
7e1b74f21SKevin Lo  * are met:
8e1b74f21SKevin Lo  * 1. Redistributions of source code must retain the above copyright
9e1b74f21SKevin Lo  *    notice, this list of conditions and the following disclaimer.
10e1b74f21SKevin Lo  * 2. Redistributions in binary form must reproduce the above copyright
11e1b74f21SKevin Lo  *    notice, this list of conditions and the following disclaimer in the
12e1b74f21SKevin Lo  *    documentation and/or other materials provided with the distribution.
13e1b74f21SKevin Lo  *
14e1b74f21SKevin Lo  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15e1b74f21SKevin Lo  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16e1b74f21SKevin Lo  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17e1b74f21SKevin Lo  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18e1b74f21SKevin Lo  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19e1b74f21SKevin Lo  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20e1b74f21SKevin Lo  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21e1b74f21SKevin Lo  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22e1b74f21SKevin Lo  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23e1b74f21SKevin Lo  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24e1b74f21SKevin Lo  * SUCH DAMAGE.
25e1b74f21SKevin Lo  */
26e1b74f21SKevin Lo 
27e1b74f21SKevin Lo #include <sys/param.h>
28e1b74f21SKevin Lo #include <sys/systm.h>
29e1b74f21SKevin Lo #include <sys/bus.h>
30e1b74f21SKevin Lo #include <sys/condvar.h>
31e1b74f21SKevin Lo #include <sys/kernel.h>
32e1b74f21SKevin Lo #include <sys/lock.h>
33e1b74f21SKevin Lo #include <sys/module.h>
34e1b74f21SKevin Lo #include <sys/mutex.h>
357d5522e1SJohn-Mark Gurney #include <sys/sbuf.h>
36e1b74f21SKevin Lo #include <sys/socket.h>
37e1b74f21SKevin Lo #include <sys/sysctl.h>
38e1b74f21SKevin Lo #include <sys/unistd.h>
39e1b74f21SKevin Lo 
40e1b74f21SKevin Lo #include <net/if.h>
41e1b74f21SKevin Lo #include <net/if_var.h>
4231c484adSJustin Hibbits #include <net/if_media.h>
4331c484adSJustin Hibbits 
447d5522e1SJohn-Mark Gurney /* needed for checksum offload */
457d5522e1SJohn-Mark Gurney #include <netinet/in.h>
467d5522e1SJohn-Mark Gurney #include <netinet/ip.h>
477d5522e1SJohn-Mark Gurney 
4831c484adSJustin Hibbits #include <dev/mii/mii.h>
4931c484adSJustin Hibbits #include <dev/mii/miivar.h>
50e1b74f21SKevin Lo 
51e1b74f21SKevin Lo #include <dev/usb/usb.h>
52e1b74f21SKevin Lo #include <dev/usb/usbdi.h>
53e1b74f21SKevin Lo #include <dev/usb/usbdi_util.h>
54e1b74f21SKevin Lo #include "usbdevs.h"
55e1b74f21SKevin Lo 
56e1b74f21SKevin Lo #define USB_DEBUG_VAR	ure_debug
57e1b74f21SKevin Lo #include <dev/usb/usb_debug.h>
58e1b74f21SKevin Lo #include <dev/usb/usb_process.h>
59e1b74f21SKevin Lo 
60e1b74f21SKevin Lo #include <dev/usb/net/usb_ethernet.h>
61e1b74f21SKevin Lo #include <dev/usb/net/if_urereg.h>
62e1b74f21SKevin Lo 
6331c484adSJustin Hibbits #include "miibus_if.h"
6431c484adSJustin Hibbits 
657d5522e1SJohn-Mark Gurney #include "opt_inet6.h"
667d5522e1SJohn-Mark Gurney 
67e1b74f21SKevin Lo #ifdef USB_DEBUG
68e1b74f21SKevin Lo static int ure_debug = 0;
69e1b74f21SKevin Lo 
70f8d2b1f3SPawel Biernacki static SYSCTL_NODE(_hw_usb, OID_AUTO, ure, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
71f8d2b1f3SPawel Biernacki     "USB ure");
72e1b74f21SKevin Lo SYSCTL_INT(_hw_usb_ure, OID_AUTO, debug, CTLFLAG_RWTUN, &ure_debug, 0,
73e1b74f21SKevin Lo     "Debug level");
74e1b74f21SKevin Lo #endif
75e1b74f21SKevin Lo 
767d5522e1SJohn-Mark Gurney #ifdef USB_DEBUG_VAR
777d5522e1SJohn-Mark Gurney #ifdef USB_DEBUG
787d5522e1SJohn-Mark Gurney #define DEVPRINTFN(n,dev,fmt,...) do {			\
797d5522e1SJohn-Mark Gurney 	if ((USB_DEBUG_VAR) >= (n)) {			\
807d5522e1SJohn-Mark Gurney 		device_printf((dev), "%s: " fmt,	\
817d5522e1SJohn-Mark Gurney 		    __FUNCTION__ ,##__VA_ARGS__);	\
827d5522e1SJohn-Mark Gurney 	}						\
837d5522e1SJohn-Mark Gurney } while (0)
847d5522e1SJohn-Mark Gurney #define DEVPRINTF(...)    DEVPRINTFN(1, __VA_ARGS__)
857d5522e1SJohn-Mark Gurney #else
867d5522e1SJohn-Mark Gurney #define DEVPRINTF(...) do { } while (0)
877d5522e1SJohn-Mark Gurney #define DEVPRINTFN(...) do { } while (0)
887d5522e1SJohn-Mark Gurney #endif
897d5522e1SJohn-Mark Gurney #endif
907d5522e1SJohn-Mark Gurney 
91e1b74f21SKevin Lo /*
92e1b74f21SKevin Lo  * Various supported device vendors/products.
93e1b74f21SKevin Lo  */
94e1b74f21SKevin Lo static const STRUCT_USB_HOST_ID ure_devs[] = {
95dab84426SHans Petter Selasky #define	URE_DEV(v,p,i)	{ \
96dab84426SHans Petter Selasky   USB_VPI(USB_VENDOR_##v, USB_PRODUCT_##v##_##p, i), \
97dab84426SHans Petter Selasky   USB_IFACE_CLASS(UICLASS_VENDOR), \
98dab84426SHans Petter Selasky   USB_IFACE_SUBCLASS(UISUBCLASS_VENDOR) }
99*dc273058SFUKAUMI Naoki 	URE_DEV(ELECOM, EDCQUA3C, 0),
100d4cf41a9SHans Petter Selasky 	URE_DEV(LENOVO, RTL8153, URE_FLAG_8153),
101a8261b70SHans Petter Selasky 	URE_DEV(LENOVO, TBT3LANGEN2, 0),
102afa9b036SGavin Atkinson 	URE_DEV(LENOVO, ONELINK, 0),
10331937f7eSPoul-Henning Kamp 	URE_DEV(LENOVO, RTL8153_04, URE_FLAG_8153),
104a1bb5bdbSAlexander Motin 	URE_DEV(LENOVO, ONELINKPLUS, URE_FLAG_8153),
105146ebc76SPoul-Henning Kamp 	URE_DEV(LENOVO, USBCLAN, 0),
106a8261b70SHans Petter Selasky 	URE_DEV(LENOVO, USBCLANGEN2, 0),
10753a03e31SJoerg Pulz 	URE_DEV(LENOVO, USBCLANHYBRID, 0),
108e5b9b5eeSAndrew Turner 	URE_DEV(MICROSOFT, WINDEVETH, 0),
109d4cf41a9SHans Petter Selasky 	URE_DEV(NVIDIA, RTL8153, URE_FLAG_8153),
110a24d62b5SKevin Lo 	URE_DEV(REALTEK, RTL8152, URE_FLAG_8152),
111d4cf41a9SHans Petter Selasky 	URE_DEV(REALTEK, RTL8153, URE_FLAG_8153),
112d4cf41a9SHans Petter Selasky 	URE_DEV(TPLINK, RTL8153, URE_FLAG_8153),
113d4cf41a9SHans Petter Selasky 	URE_DEV(REALTEK, RTL8156, URE_FLAG_8156),
114e1b74f21SKevin Lo #undef URE_DEV
115e1b74f21SKevin Lo };
116e1b74f21SKevin Lo 
117e1b74f21SKevin Lo static device_probe_t ure_probe;
118e1b74f21SKevin Lo static device_attach_t ure_attach;
119e1b74f21SKevin Lo static device_detach_t ure_detach;
120e1b74f21SKevin Lo 
121e1b74f21SKevin Lo static usb_callback_t ure_bulk_read_callback;
122e1b74f21SKevin Lo static usb_callback_t ure_bulk_write_callback;
123e1b74f21SKevin Lo 
124e1b74f21SKevin Lo static miibus_readreg_t ure_miibus_readreg;
125e1b74f21SKevin Lo static miibus_writereg_t ure_miibus_writereg;
126e1b74f21SKevin Lo static miibus_statchg_t ure_miibus_statchg;
127e1b74f21SKevin Lo 
128e1b74f21SKevin Lo static uether_fn_t ure_attach_post;
129e1b74f21SKevin Lo static uether_fn_t ure_init;
130e1b74f21SKevin Lo static uether_fn_t ure_stop;
131e1b74f21SKevin Lo static uether_fn_t ure_start;
132e1b74f21SKevin Lo static uether_fn_t ure_tick;
133a24d62b5SKevin Lo static uether_fn_t ure_rxfilter;
134e1b74f21SKevin Lo 
135e1b74f21SKevin Lo static int	ure_ctl(struct ure_softc *, uint8_t, uint16_t, uint16_t,
136e1b74f21SKevin Lo 		    void *, int);
137e1b74f21SKevin Lo static int	ure_read_mem(struct ure_softc *, uint16_t, uint16_t, void *,
138e1b74f21SKevin Lo 		    int);
139e1b74f21SKevin Lo static int	ure_write_mem(struct ure_softc *, uint16_t, uint16_t, void *,
140e1b74f21SKevin Lo 		    int);
141e1b74f21SKevin Lo static uint8_t	ure_read_1(struct ure_softc *, uint16_t, uint16_t);
142e1b74f21SKevin Lo static uint16_t	ure_read_2(struct ure_softc *, uint16_t, uint16_t);
143e1b74f21SKevin Lo static uint32_t	ure_read_4(struct ure_softc *, uint16_t, uint16_t);
144e1b74f21SKevin Lo static int	ure_write_1(struct ure_softc *, uint16_t, uint16_t, uint32_t);
145e1b74f21SKevin Lo static int	ure_write_2(struct ure_softc *, uint16_t, uint16_t, uint32_t);
146e1b74f21SKevin Lo static int	ure_write_4(struct ure_softc *, uint16_t, uint16_t, uint32_t);
147e1b74f21SKevin Lo static uint16_t	ure_ocp_reg_read(struct ure_softc *, uint16_t);
148e1b74f21SKevin Lo static void	ure_ocp_reg_write(struct ure_softc *, uint16_t, uint16_t);
149d4cf41a9SHans Petter Selasky static void	ure_sram_write(struct ure_softc *, uint16_t, uint16_t);
150e1b74f21SKevin Lo 
1517d5522e1SJohn-Mark Gurney static int	ure_sysctl_chipver(SYSCTL_HANDLER_ARGS);
1527d5522e1SJohn-Mark Gurney 
153e1b74f21SKevin Lo static void	ure_read_chipver(struct ure_softc *);
154e1b74f21SKevin Lo static int	ure_attach_post_sub(struct usb_ether *);
155e1b74f21SKevin Lo static void	ure_reset(struct ure_softc *);
156935b194dSJustin Hibbits static int	ure_ifmedia_upd(if_t);
157935b194dSJustin Hibbits static void	ure_ifmedia_sts(if_t, struct ifmediareq *);
158d4cf41a9SHans Petter Selasky static void	ure_add_media_types(struct ure_softc *);
159d4cf41a9SHans Petter Selasky static void	ure_link_state(struct ure_softc *sc);
160d4cf41a9SHans Petter Selasky static int		ure_get_link_status(struct ure_softc *);
161935b194dSJustin Hibbits static int		ure_ioctl(if_t, u_long, caddr_t);
162e1b74f21SKevin Lo static void	ure_rtl8152_init(struct ure_softc *);
163d4cf41a9SHans Petter Selasky static void	ure_rtl8152_nic_reset(struct ure_softc *);
164a24d62b5SKevin Lo static void	ure_rtl8153_init(struct ure_softc *);
165d4cf41a9SHans Petter Selasky static void	ure_rtl8153b_init(struct ure_softc *);
166d4cf41a9SHans Petter Selasky static void	ure_rtl8153b_nic_reset(struct ure_softc *);
167e1b74f21SKevin Lo static void	ure_disable_teredo(struct ure_softc *);
168d4cf41a9SHans Petter Selasky static void	ure_enable_aldps(struct ure_softc *, bool);
169d4cf41a9SHans Petter Selasky static uint16_t	ure_phy_status(struct ure_softc *, uint16_t);
1707d5522e1SJohn-Mark Gurney static void	ure_rxcsum(int capenb, struct ure_rxpkt *rp, struct mbuf *m);
1717d5522e1SJohn-Mark Gurney static int	ure_txcsum(struct mbuf *m, int caps, uint32_t *regout);
172e1b74f21SKevin Lo 
173e1b74f21SKevin Lo static device_method_t ure_methods[] = {
174e1b74f21SKevin Lo 	/* Device interface. */
175e1b74f21SKevin Lo 	DEVMETHOD(device_probe, ure_probe),
176e1b74f21SKevin Lo 	DEVMETHOD(device_attach, ure_attach),
177e1b74f21SKevin Lo 	DEVMETHOD(device_detach, ure_detach),
178e1b74f21SKevin Lo 
179e1b74f21SKevin Lo 	/* MII interface. */
180e1b74f21SKevin Lo 	DEVMETHOD(miibus_readreg, ure_miibus_readreg),
181e1b74f21SKevin Lo 	DEVMETHOD(miibus_writereg, ure_miibus_writereg),
182e1b74f21SKevin Lo 	DEVMETHOD(miibus_statchg, ure_miibus_statchg),
183e1b74f21SKevin Lo 
184e1b74f21SKevin Lo 	DEVMETHOD_END
185e1b74f21SKevin Lo };
186e1b74f21SKevin Lo 
187e1b74f21SKevin Lo static driver_t ure_driver = {
188e1b74f21SKevin Lo 	.name = "ure",
189e1b74f21SKevin Lo 	.methods = ure_methods,
190e1b74f21SKevin Lo 	.size = sizeof(struct ure_softc),
191e1b74f21SKevin Lo };
192e1b74f21SKevin Lo 
193bc9372d7SJohn Baldwin DRIVER_MODULE(ure, uhub, ure_driver, NULL, NULL);
1943e38757dSJohn Baldwin DRIVER_MODULE(miibus, ure, miibus_driver, NULL, NULL);
195e1b74f21SKevin Lo MODULE_DEPEND(ure, uether, 1, 1, 1);
196e1b74f21SKevin Lo MODULE_DEPEND(ure, usb, 1, 1, 1);
197e1b74f21SKevin Lo MODULE_DEPEND(ure, ether, 1, 1, 1);
198e1b74f21SKevin Lo MODULE_DEPEND(ure, miibus, 1, 1, 1);
199e1b74f21SKevin Lo MODULE_VERSION(ure, 1);
20072851e85SAllan Jude USB_PNP_HOST_INFO(ure_devs);
201e1b74f21SKevin Lo 
202e1b74f21SKevin Lo static const struct usb_ether_methods ure_ue_methods = {
203e1b74f21SKevin Lo 	.ue_attach_post = ure_attach_post,
204e1b74f21SKevin Lo 	.ue_attach_post_sub = ure_attach_post_sub,
205e1b74f21SKevin Lo 	.ue_start = ure_start,
206e1b74f21SKevin Lo 	.ue_init = ure_init,
207e1b74f21SKevin Lo 	.ue_stop = ure_stop,
208e1b74f21SKevin Lo 	.ue_tick = ure_tick,
209a24d62b5SKevin Lo 	.ue_setmulti = ure_rxfilter,
210a24d62b5SKevin Lo 	.ue_setpromisc = ure_rxfilter,
211e1b74f21SKevin Lo 	.ue_mii_upd = ure_ifmedia_upd,
212e1b74f21SKevin Lo 	.ue_mii_sts = ure_ifmedia_sts,
213e1b74f21SKevin Lo };
214e1b74f21SKevin Lo 
215d4cf41a9SHans Petter Selasky #define	URE_SETBIT_1(sc, reg, index, x) \
216d4cf41a9SHans Petter Selasky 	ure_write_1(sc, reg, index, ure_read_1(sc, reg, index) | (x))
217d4cf41a9SHans Petter Selasky #define	URE_SETBIT_2(sc, reg, index, x) \
218d4cf41a9SHans Petter Selasky 	ure_write_2(sc, reg, index, ure_read_2(sc, reg, index) | (x))
219d4cf41a9SHans Petter Selasky #define	URE_SETBIT_4(sc, reg, index, x) \
220d4cf41a9SHans Petter Selasky 	ure_write_4(sc, reg, index, ure_read_4(sc, reg, index) | (x))
221d4cf41a9SHans Petter Selasky 
222d4cf41a9SHans Petter Selasky #define	URE_CLRBIT_1(sc, reg, index, x) \
223d4cf41a9SHans Petter Selasky 	ure_write_1(sc, reg, index, ure_read_1(sc, reg, index) & ~(x))
224d4cf41a9SHans Petter Selasky #define	URE_CLRBIT_2(sc, reg, index, x) \
225d4cf41a9SHans Petter Selasky 	ure_write_2(sc, reg, index, ure_read_2(sc, reg, index) & ~(x))
226d4cf41a9SHans Petter Selasky #define	URE_CLRBIT_4(sc, reg, index, x) \
227d4cf41a9SHans Petter Selasky 	ure_write_4(sc, reg, index, ure_read_4(sc, reg, index) & ~(x))
228d4cf41a9SHans Petter Selasky 
229e1b74f21SKevin Lo static int
230e1b74f21SKevin Lo ure_ctl(struct ure_softc *sc, uint8_t rw, uint16_t val, uint16_t index,
231e1b74f21SKevin Lo     void *buf, int len)
232e1b74f21SKevin Lo {
233e1b74f21SKevin Lo 	struct usb_device_request req;
234e1b74f21SKevin Lo 
235e1b74f21SKevin Lo 	URE_LOCK_ASSERT(sc, MA_OWNED);
236e1b74f21SKevin Lo 
237e1b74f21SKevin Lo 	if (rw == URE_CTL_WRITE)
238e1b74f21SKevin Lo 		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
239e1b74f21SKevin Lo 	else
240e1b74f21SKevin Lo 		req.bmRequestType = UT_READ_VENDOR_DEVICE;
241e1b74f21SKevin Lo 	req.bRequest = UR_SET_ADDRESS;
242e1b74f21SKevin Lo 	USETW(req.wValue, val);
243e1b74f21SKevin Lo 	USETW(req.wIndex, index);
244e1b74f21SKevin Lo 	USETW(req.wLength, len);
245e1b74f21SKevin Lo 
246e1b74f21SKevin Lo 	return (uether_do_request(&sc->sc_ue, &req, buf, 1000));
247e1b74f21SKevin Lo }
248e1b74f21SKevin Lo 
249e1b74f21SKevin Lo static int
250e1b74f21SKevin Lo ure_read_mem(struct ure_softc *sc, uint16_t addr, uint16_t index,
251e1b74f21SKevin Lo     void *buf, int len)
252e1b74f21SKevin Lo {
253e1b74f21SKevin Lo 
254e1b74f21SKevin Lo 	return (ure_ctl(sc, URE_CTL_READ, addr, index, buf, len));
255e1b74f21SKevin Lo }
256e1b74f21SKevin Lo 
257e1b74f21SKevin Lo static int
258e1b74f21SKevin Lo ure_write_mem(struct ure_softc *sc, uint16_t addr, uint16_t index,
259e1b74f21SKevin Lo     void *buf, int len)
260e1b74f21SKevin Lo {
261e1b74f21SKevin Lo 
262e1b74f21SKevin Lo 	return (ure_ctl(sc, URE_CTL_WRITE, addr, index, buf, len));
263e1b74f21SKevin Lo }
264e1b74f21SKevin Lo 
265e1b74f21SKevin Lo static uint8_t
266e1b74f21SKevin Lo ure_read_1(struct ure_softc *sc, uint16_t reg, uint16_t index)
267e1b74f21SKevin Lo {
268e1b74f21SKevin Lo 	uint32_t val;
269e1b74f21SKevin Lo 	uint8_t temp[4];
270e1b74f21SKevin Lo 	uint8_t shift;
271e1b74f21SKevin Lo 
272e1b74f21SKevin Lo 	shift = (reg & 3) << 3;
273e1b74f21SKevin Lo 	reg &= ~3;
274e1b74f21SKevin Lo 
275e1b74f21SKevin Lo 	ure_read_mem(sc, reg, index, &temp, 4);
276e1b74f21SKevin Lo 	val = UGETDW(temp);
277e1b74f21SKevin Lo 	val >>= shift;
278e1b74f21SKevin Lo 
279e1b74f21SKevin Lo 	return (val & 0xff);
280e1b74f21SKevin Lo }
281e1b74f21SKevin Lo 
282e1b74f21SKevin Lo static uint16_t
283e1b74f21SKevin Lo ure_read_2(struct ure_softc *sc, uint16_t reg, uint16_t index)
284e1b74f21SKevin Lo {
285e1b74f21SKevin Lo 	uint32_t val;
286e1b74f21SKevin Lo 	uint8_t temp[4];
287e1b74f21SKevin Lo 	uint8_t shift;
288e1b74f21SKevin Lo 
289e1b74f21SKevin Lo 	shift = (reg & 2) << 3;
290e1b74f21SKevin Lo 	reg &= ~3;
291e1b74f21SKevin Lo 
292e1b74f21SKevin Lo 	ure_read_mem(sc, reg, index, &temp, 4);
293e1b74f21SKevin Lo 	val = UGETDW(temp);
294e1b74f21SKevin Lo 	val >>= shift;
295e1b74f21SKevin Lo 
296e1b74f21SKevin Lo 	return (val & 0xffff);
297e1b74f21SKevin Lo }
298e1b74f21SKevin Lo 
299e1b74f21SKevin Lo static uint32_t
300e1b74f21SKevin Lo ure_read_4(struct ure_softc *sc, uint16_t reg, uint16_t index)
301e1b74f21SKevin Lo {
302e1b74f21SKevin Lo 	uint8_t temp[4];
303e1b74f21SKevin Lo 
304e1b74f21SKevin Lo 	ure_read_mem(sc, reg, index, &temp, 4);
305e1b74f21SKevin Lo 	return (UGETDW(temp));
306e1b74f21SKevin Lo }
307e1b74f21SKevin Lo 
308e1b74f21SKevin Lo static int
309e1b74f21SKevin Lo ure_write_1(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val)
310e1b74f21SKevin Lo {
311e1b74f21SKevin Lo 	uint16_t byen;
312e1b74f21SKevin Lo 	uint8_t temp[4];
313e1b74f21SKevin Lo 	uint8_t shift;
314e1b74f21SKevin Lo 
315e1b74f21SKevin Lo 	byen = URE_BYTE_EN_BYTE;
316e1b74f21SKevin Lo 	shift = reg & 3;
317e1b74f21SKevin Lo 	val &= 0xff;
318e1b74f21SKevin Lo 
319e1b74f21SKevin Lo 	if (reg & 3) {
320e1b74f21SKevin Lo 		byen <<= shift;
321e1b74f21SKevin Lo 		val <<= (shift << 3);
322e1b74f21SKevin Lo 		reg &= ~3;
323e1b74f21SKevin Lo 	}
324e1b74f21SKevin Lo 
325e1b74f21SKevin Lo 	USETDW(temp, val);
326e1b74f21SKevin Lo 	return (ure_write_mem(sc, reg, index | byen, &temp, 4));
327e1b74f21SKevin Lo }
328e1b74f21SKevin Lo 
329e1b74f21SKevin Lo static int
330e1b74f21SKevin Lo ure_write_2(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val)
331e1b74f21SKevin Lo {
332e1b74f21SKevin Lo 	uint16_t byen;
333e1b74f21SKevin Lo 	uint8_t temp[4];
334e1b74f21SKevin Lo 	uint8_t shift;
335e1b74f21SKevin Lo 
336e1b74f21SKevin Lo 	byen = URE_BYTE_EN_WORD;
337e1b74f21SKevin Lo 	shift = reg & 2;
338e1b74f21SKevin Lo 	val &= 0xffff;
339e1b74f21SKevin Lo 
340e1b74f21SKevin Lo 	if (reg & 2) {
341e1b74f21SKevin Lo 		byen <<= shift;
342e1b74f21SKevin Lo 		val <<= (shift << 3);
343e1b74f21SKevin Lo 		reg &= ~3;
344e1b74f21SKevin Lo 	}
345e1b74f21SKevin Lo 
346e1b74f21SKevin Lo 	USETDW(temp, val);
347e1b74f21SKevin Lo 	return (ure_write_mem(sc, reg, index | byen, &temp, 4));
348e1b74f21SKevin Lo }
349e1b74f21SKevin Lo 
350e1b74f21SKevin Lo static int
351e1b74f21SKevin Lo ure_write_4(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val)
352e1b74f21SKevin Lo {
353e1b74f21SKevin Lo 	uint8_t temp[4];
354e1b74f21SKevin Lo 
355e1b74f21SKevin Lo 	USETDW(temp, val);
356e1b74f21SKevin Lo 	return (ure_write_mem(sc, reg, index | URE_BYTE_EN_DWORD, &temp, 4));
357e1b74f21SKevin Lo }
358e1b74f21SKevin Lo 
359e1b74f21SKevin Lo static uint16_t
360e1b74f21SKevin Lo ure_ocp_reg_read(struct ure_softc *sc, uint16_t addr)
361e1b74f21SKevin Lo {
362e1b74f21SKevin Lo 	uint16_t reg;
363e1b74f21SKevin Lo 
364e1b74f21SKevin Lo 	ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000);
365e1b74f21SKevin Lo 	reg = (addr & 0x0fff) | 0xb000;
366e1b74f21SKevin Lo 
367e1b74f21SKevin Lo 	return (ure_read_2(sc, reg, URE_MCU_TYPE_PLA));
368e1b74f21SKevin Lo }
369e1b74f21SKevin Lo 
370e1b74f21SKevin Lo static void
371e1b74f21SKevin Lo ure_ocp_reg_write(struct ure_softc *sc, uint16_t addr, uint16_t data)
372e1b74f21SKevin Lo {
373e1b74f21SKevin Lo 	uint16_t reg;
374e1b74f21SKevin Lo 
375e1b74f21SKevin Lo 	ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000);
376e1b74f21SKevin Lo 	reg = (addr & 0x0fff) | 0xb000;
377e1b74f21SKevin Lo 
378e1b74f21SKevin Lo 	ure_write_2(sc, reg, URE_MCU_TYPE_PLA, data);
379e1b74f21SKevin Lo }
380e1b74f21SKevin Lo 
381d4cf41a9SHans Petter Selasky static void
382d4cf41a9SHans Petter Selasky ure_sram_write(struct ure_softc *sc, uint16_t addr, uint16_t data)
383d4cf41a9SHans Petter Selasky {
384d4cf41a9SHans Petter Selasky 	ure_ocp_reg_write(sc, URE_OCP_SRAM_ADDR, addr);
385d4cf41a9SHans Petter Selasky 	ure_ocp_reg_write(sc, URE_OCP_SRAM_DATA, data);
386d4cf41a9SHans Petter Selasky }
387d4cf41a9SHans Petter Selasky 
388e1b74f21SKevin Lo static int
389e1b74f21SKevin Lo ure_miibus_readreg(device_t dev, int phy, int reg)
390e1b74f21SKevin Lo {
391e1b74f21SKevin Lo 	struct ure_softc *sc;
392e1b74f21SKevin Lo 	uint16_t val;
393e1b74f21SKevin Lo 	int locked;
394e1b74f21SKevin Lo 
395e1b74f21SKevin Lo 	sc = device_get_softc(dev);
396e1b74f21SKevin Lo 	locked = mtx_owned(&sc->sc_mtx);
397e1b74f21SKevin Lo 	if (!locked)
398e1b74f21SKevin Lo 		URE_LOCK(sc);
399e1b74f21SKevin Lo 
400a24d62b5SKevin Lo 	/* Let the rgephy driver read the URE_GMEDIASTAT register. */
401a24d62b5SKevin Lo 	if (reg == URE_GMEDIASTAT) {
402a24d62b5SKevin Lo 		if (!locked)
403a24d62b5SKevin Lo 			URE_UNLOCK(sc);
404a24d62b5SKevin Lo 		return (ure_read_1(sc, URE_GMEDIASTAT, URE_MCU_TYPE_PLA));
405a24d62b5SKevin Lo 	}
406a24d62b5SKevin Lo 
407e1b74f21SKevin Lo 	val = ure_ocp_reg_read(sc, URE_OCP_BASE_MII + reg * 2);
408e1b74f21SKevin Lo 
409e1b74f21SKevin Lo 	if (!locked)
410e1b74f21SKevin Lo 		URE_UNLOCK(sc);
411e1b74f21SKevin Lo 	return (val);
412e1b74f21SKevin Lo }
413e1b74f21SKevin Lo 
414e1b74f21SKevin Lo static int
415e1b74f21SKevin Lo ure_miibus_writereg(device_t dev, int phy, int reg, int val)
416e1b74f21SKevin Lo {
417e1b74f21SKevin Lo 	struct ure_softc *sc;
418e1b74f21SKevin Lo 	int locked;
419e1b74f21SKevin Lo 
420e1b74f21SKevin Lo 	sc = device_get_softc(dev);
421e1b74f21SKevin Lo 	if (sc->sc_phyno != phy)
422e1b74f21SKevin Lo 		return (0);
423e1b74f21SKevin Lo 
424e1b74f21SKevin Lo 	locked = mtx_owned(&sc->sc_mtx);
425e1b74f21SKevin Lo 	if (!locked)
426e1b74f21SKevin Lo 		URE_LOCK(sc);
427e1b74f21SKevin Lo 
428e1b74f21SKevin Lo 	ure_ocp_reg_write(sc, URE_OCP_BASE_MII + reg * 2, val);
429e1b74f21SKevin Lo 
430e1b74f21SKevin Lo 	if (!locked)
431e1b74f21SKevin Lo 		URE_UNLOCK(sc);
432e1b74f21SKevin Lo 	return (0);
433e1b74f21SKevin Lo }
434e1b74f21SKevin Lo 
435e1b74f21SKevin Lo static void
436e1b74f21SKevin Lo ure_miibus_statchg(device_t dev)
437e1b74f21SKevin Lo {
438e1b74f21SKevin Lo 	struct ure_softc *sc;
439e1b74f21SKevin Lo 	struct mii_data *mii;
440935b194dSJustin Hibbits 	if_t ifp;
441e1b74f21SKevin Lo 	int locked;
442e1b74f21SKevin Lo 
443e1b74f21SKevin Lo 	sc = device_get_softc(dev);
444e1b74f21SKevin Lo 	mii = GET_MII(sc);
445e1b74f21SKevin Lo 	locked = mtx_owned(&sc->sc_mtx);
446e1b74f21SKevin Lo 	if (!locked)
447e1b74f21SKevin Lo 		URE_LOCK(sc);
448e1b74f21SKevin Lo 
449e1b74f21SKevin Lo 	ifp = uether_getifp(&sc->sc_ue);
450e1b74f21SKevin Lo 	if (mii == NULL || ifp == NULL ||
451935b194dSJustin Hibbits 	    (if_getdrvflags(ifp) & IFF_DRV_RUNNING) == 0)
452e1b74f21SKevin Lo 		goto done;
453e1b74f21SKevin Lo 
454e1b74f21SKevin Lo 	sc->sc_flags &= ~URE_FLAG_LINK;
455e1b74f21SKevin Lo 	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
456e1b74f21SKevin Lo 	    (IFM_ACTIVE | IFM_AVALID)) {
457e1b74f21SKevin Lo 		switch (IFM_SUBTYPE(mii->mii_media_active)) {
458e1b74f21SKevin Lo 		case IFM_10_T:
459e1b74f21SKevin Lo 		case IFM_100_TX:
460e1b74f21SKevin Lo 			sc->sc_flags |= URE_FLAG_LINK;
4617d5522e1SJohn-Mark Gurney 			sc->sc_rxstarted = 0;
462e1b74f21SKevin Lo 			break;
463a24d62b5SKevin Lo 		case IFM_1000_T:
464a24d62b5SKevin Lo 			if ((sc->sc_flags & URE_FLAG_8152) != 0)
465a24d62b5SKevin Lo 				break;
466a24d62b5SKevin Lo 			sc->sc_flags |= URE_FLAG_LINK;
4677d5522e1SJohn-Mark Gurney 			sc->sc_rxstarted = 0;
468a24d62b5SKevin Lo 			break;
469e1b74f21SKevin Lo 		default:
470e1b74f21SKevin Lo 			break;
471e1b74f21SKevin Lo 		}
472e1b74f21SKevin Lo 	}
473e1b74f21SKevin Lo 
474e1b74f21SKevin Lo 	/* Lost link, do nothing. */
475e1b74f21SKevin Lo 	if ((sc->sc_flags & URE_FLAG_LINK) == 0)
476e1b74f21SKevin Lo 		goto done;
477e1b74f21SKevin Lo done:
478e1b74f21SKevin Lo 	if (!locked)
479e1b74f21SKevin Lo 		URE_UNLOCK(sc);
480e1b74f21SKevin Lo }
481e1b74f21SKevin Lo 
482e1b74f21SKevin Lo /*
4836ea4d95fSLi-Wen Hsu  * Probe for a RTL8152/RTL8153/RTL8156 chip.
484e1b74f21SKevin Lo  */
485e1b74f21SKevin Lo static int
486e1b74f21SKevin Lo ure_probe(device_t dev)
487e1b74f21SKevin Lo {
488e1b74f21SKevin Lo 	struct usb_attach_arg *uaa;
489e1b74f21SKevin Lo 
49074b8d63dSPedro F. Giffuni 	uaa = device_get_ivars(dev);
491e1b74f21SKevin Lo 	if (uaa->usb_mode != USB_MODE_HOST)
492e1b74f21SKevin Lo 		return (ENXIO);
493e1b74f21SKevin Lo 	if (uaa->info.bIfaceIndex != URE_IFACE_IDX)
494e1b74f21SKevin Lo 		return (ENXIO);
495e1b74f21SKevin Lo 
496e1b74f21SKevin Lo 	return (usbd_lookup_id_by_uaa(ure_devs, sizeof(ure_devs), uaa));
497e1b74f21SKevin Lo }
498e1b74f21SKevin Lo 
499e1b74f21SKevin Lo /*
500e1b74f21SKevin Lo  * Attach the interface. Allocate softc structures, do ifmedia
501e1b74f21SKevin Lo  * setup and ethernet/BPF attach.
502e1b74f21SKevin Lo  */
503e1b74f21SKevin Lo static int
504e1b74f21SKevin Lo ure_attach(device_t dev)
505e1b74f21SKevin Lo {
506e1b74f21SKevin Lo 	struct usb_attach_arg *uaa = device_get_ivars(dev);
507e1b74f21SKevin Lo 	struct ure_softc *sc = device_get_softc(dev);
508e1b74f21SKevin Lo 	struct usb_ether *ue = &sc->sc_ue;
509d4cf41a9SHans Petter Selasky 	struct usb_config ure_config_rx[URE_MAX_RX];
510d4cf41a9SHans Petter Selasky 	struct usb_config ure_config_tx[URE_MAX_TX];
511e1b74f21SKevin Lo 	uint8_t iface_index;
512e1b74f21SKevin Lo 	int error;
513d4cf41a9SHans Petter Selasky 	int i;
514e1b74f21SKevin Lo 
515a24d62b5SKevin Lo 	sc->sc_flags = USB_GET_DRIVER_INFO(uaa);
516e1b74f21SKevin Lo 	device_set_usb_desc(dev);
517e1b74f21SKevin Lo 	mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
518e1b74f21SKevin Lo 
519e1b74f21SKevin Lo 	iface_index = URE_IFACE_IDX;
520d4cf41a9SHans Petter Selasky 
521d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & (URE_FLAG_8153 | URE_FLAG_8153B))
522d4cf41a9SHans Petter Selasky 		sc->sc_rxbufsz = URE_8153_RX_BUFSZ;
523d4cf41a9SHans Petter Selasky 	else if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B))
524d4cf41a9SHans Petter Selasky 		sc->sc_rxbufsz = URE_8156_RX_BUFSZ;
525d4cf41a9SHans Petter Selasky 	else
526d4cf41a9SHans Petter Selasky 		sc->sc_rxbufsz = URE_8152_RX_BUFSZ;
527d4cf41a9SHans Petter Selasky 
528d4cf41a9SHans Petter Selasky 	for (i = 0; i < URE_MAX_RX; i++) {
529d4cf41a9SHans Petter Selasky 		ure_config_rx[i] = (struct usb_config) {
530d4cf41a9SHans Petter Selasky 			.type = UE_BULK,
531d4cf41a9SHans Petter Selasky 			.endpoint = UE_ADDR_ANY,
532d4cf41a9SHans Petter Selasky 			.direction = UE_DIR_IN,
533d4cf41a9SHans Petter Selasky 			.bufsize = sc->sc_rxbufsz,
534d4cf41a9SHans Petter Selasky 			.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
535d4cf41a9SHans Petter Selasky 			.callback = ure_bulk_read_callback,
536d4cf41a9SHans Petter Selasky 			.timeout = 0,	/* no timeout */
537d4cf41a9SHans Petter Selasky 		};
538d4cf41a9SHans Petter Selasky 	}
5397d5522e1SJohn-Mark Gurney 	error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_rx_xfer,
540d4cf41a9SHans Petter Selasky 	    ure_config_rx, URE_MAX_RX, sc, &sc->sc_mtx);
541e1b74f21SKevin Lo 	if (error != 0) {
5427d5522e1SJohn-Mark Gurney 		device_printf(dev, "allocating USB RX transfers failed\n");
543e1b74f21SKevin Lo 		goto detach;
544e1b74f21SKevin Lo 	}
545e1b74f21SKevin Lo 
546d4cf41a9SHans Petter Selasky 	for (i = 0; i < URE_MAX_TX; i++) {
547d4cf41a9SHans Petter Selasky 		ure_config_tx[i] = (struct usb_config) {
548d4cf41a9SHans Petter Selasky 			.type = UE_BULK,
549d4cf41a9SHans Petter Selasky 			.endpoint = UE_ADDR_ANY,
550d4cf41a9SHans Petter Selasky 			.direction = UE_DIR_OUT,
551d4cf41a9SHans Petter Selasky 			.bufsize = URE_TX_BUFSZ,
552d4cf41a9SHans Petter Selasky 			.flags = {.pipe_bof = 1,.force_short_xfer = 1,},
553d4cf41a9SHans Petter Selasky 			.callback = ure_bulk_write_callback,
554d4cf41a9SHans Petter Selasky 			.timeout = 10000,	/* 10 seconds */
555d4cf41a9SHans Petter Selasky 		};
556d4cf41a9SHans Petter Selasky 	}
5577d5522e1SJohn-Mark Gurney 	error = usbd_transfer_setup(uaa->device, &iface_index, sc->sc_tx_xfer,
558d4cf41a9SHans Petter Selasky 	    ure_config_tx, URE_MAX_TX, sc, &sc->sc_mtx);
5597d5522e1SJohn-Mark Gurney 	if (error != 0) {
560d4cf41a9SHans Petter Selasky 		usbd_transfer_unsetup(sc->sc_rx_xfer, URE_MAX_RX);
5617d5522e1SJohn-Mark Gurney 		device_printf(dev, "allocating USB TX transfers failed\n");
5627d5522e1SJohn-Mark Gurney 		goto detach;
5637d5522e1SJohn-Mark Gurney 	}
5647d5522e1SJohn-Mark Gurney 
565e1b74f21SKevin Lo 	ue->ue_sc = sc;
566e1b74f21SKevin Lo 	ue->ue_dev = dev;
567e1b74f21SKevin Lo 	ue->ue_udev = uaa->device;
568e1b74f21SKevin Lo 	ue->ue_mtx = &sc->sc_mtx;
569e1b74f21SKevin Lo 	ue->ue_methods = &ure_ue_methods;
570e1b74f21SKevin Lo 
571e1b74f21SKevin Lo 	error = uether_ifattach(ue);
572e1b74f21SKevin Lo 	if (error != 0) {
573e1b74f21SKevin Lo 		device_printf(dev, "could not attach interface\n");
574e1b74f21SKevin Lo 		goto detach;
575e1b74f21SKevin Lo 	}
576e1b74f21SKevin Lo 	return (0);			/* success */
577e1b74f21SKevin Lo 
578e1b74f21SKevin Lo detach:
579e1b74f21SKevin Lo 	ure_detach(dev);
580e1b74f21SKevin Lo 	return (ENXIO);			/* failure */
581e1b74f21SKevin Lo }
582e1b74f21SKevin Lo 
583e1b74f21SKevin Lo static int
584e1b74f21SKevin Lo ure_detach(device_t dev)
585e1b74f21SKevin Lo {
586e1b74f21SKevin Lo 	struct ure_softc *sc = device_get_softc(dev);
587e1b74f21SKevin Lo 	struct usb_ether *ue = &sc->sc_ue;
588e1b74f21SKevin Lo 
589d4cf41a9SHans Petter Selasky 	usbd_transfer_unsetup(sc->sc_tx_xfer, URE_MAX_TX);
590d4cf41a9SHans Petter Selasky 	usbd_transfer_unsetup(sc->sc_rx_xfer, URE_MAX_RX);
591e1b74f21SKevin Lo 	uether_ifdetach(ue);
592e1b74f21SKevin Lo 	mtx_destroy(&sc->sc_mtx);
593e1b74f21SKevin Lo 
594e1b74f21SKevin Lo 	return (0);
595e1b74f21SKevin Lo }
596e1b74f21SKevin Lo 
5977d5522e1SJohn-Mark Gurney /*
5987d5522e1SJohn-Mark Gurney  * Copy from USB buffers to a new mbuf chain with pkt header.
5997d5522e1SJohn-Mark Gurney  *
6007d5522e1SJohn-Mark Gurney  * This will use m_getm2 to get a mbuf chain w/ properly sized mbuf
6017d5522e1SJohn-Mark Gurney  * clusters as necessary.
6027d5522e1SJohn-Mark Gurney  */
6037d5522e1SJohn-Mark Gurney static struct mbuf *
6047d5522e1SJohn-Mark Gurney ure_makembuf(struct usb_page_cache *pc, usb_frlength_t offset,
6057d5522e1SJohn-Mark Gurney     usb_frlength_t len)
6067d5522e1SJohn-Mark Gurney {
6077d5522e1SJohn-Mark Gurney 	struct usb_page_search_res;
6087d5522e1SJohn-Mark Gurney 	struct mbuf *m, *mb;
6097d5522e1SJohn-Mark Gurney 	usb_frlength_t tlen;
6107d5522e1SJohn-Mark Gurney 
6117d5522e1SJohn-Mark Gurney 	m = m_getm2(NULL, len + ETHER_ALIGN, M_NOWAIT, MT_DATA, M_PKTHDR);
6127d5522e1SJohn-Mark Gurney 	if (m == NULL)
6137d5522e1SJohn-Mark Gurney 		return (m);
6147d5522e1SJohn-Mark Gurney 
6157d5522e1SJohn-Mark Gurney 	/* uether_newbuf does this. */
6167d5522e1SJohn-Mark Gurney 	m_adj(m, ETHER_ALIGN);
6177d5522e1SJohn-Mark Gurney 
6187d5522e1SJohn-Mark Gurney 	m->m_pkthdr.len = len;
6197d5522e1SJohn-Mark Gurney 
6207d5522e1SJohn-Mark Gurney 	for (mb = m; len > 0; mb = mb->m_next) {
6217d5522e1SJohn-Mark Gurney 		tlen = MIN(len, M_TRAILINGSPACE(mb));
6227d5522e1SJohn-Mark Gurney 
6237d5522e1SJohn-Mark Gurney 		usbd_copy_out(pc, offset, mtod(mb, uint8_t *), tlen);
6247d5522e1SJohn-Mark Gurney 		mb->m_len = tlen;
6257d5522e1SJohn-Mark Gurney 
6267d5522e1SJohn-Mark Gurney 		offset += tlen;
6277d5522e1SJohn-Mark Gurney 		len -= tlen;
6287d5522e1SJohn-Mark Gurney 	}
6297d5522e1SJohn-Mark Gurney 
6307d5522e1SJohn-Mark Gurney 	return (m);
6317d5522e1SJohn-Mark Gurney }
6327d5522e1SJohn-Mark Gurney 
633e1b74f21SKevin Lo static void
634e1b74f21SKevin Lo ure_bulk_read_callback(struct usb_xfer *xfer, usb_error_t error)
635e1b74f21SKevin Lo {
636e1b74f21SKevin Lo 	struct ure_softc *sc = usbd_xfer_softc(xfer);
637e1b74f21SKevin Lo 	struct usb_ether *ue = &sc->sc_ue;
638935b194dSJustin Hibbits 	if_t ifp = uether_getifp(ue);
639e1b74f21SKevin Lo 	struct usb_page_cache *pc;
6407d5522e1SJohn-Mark Gurney 	struct mbuf *m;
641e1b74f21SKevin Lo 	struct ure_rxpkt pkt;
6427d5522e1SJohn-Mark Gurney 	int actlen, off, len;
6437d5522e1SJohn-Mark Gurney 	int caps;
6447d5522e1SJohn-Mark Gurney 	uint32_t pktcsum;
645e1b74f21SKevin Lo 
646e1b74f21SKevin Lo 	usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
647e1b74f21SKevin Lo 
648e1b74f21SKevin Lo 	switch (USB_GET_STATE(xfer)) {
649e1b74f21SKevin Lo 	case USB_ST_TRANSFERRED:
6507d5522e1SJohn-Mark Gurney 		off = 0;
6517d5522e1SJohn-Mark Gurney 		pc = usbd_xfer_get_frame(xfer, 0);
6527d5522e1SJohn-Mark Gurney 		caps = if_getcapenable(ifp);
6537d5522e1SJohn-Mark Gurney 		DEVPRINTFN(13, sc->sc_ue.ue_dev, "rcb start\n");
6547d5522e1SJohn-Mark Gurney 		while (actlen > 0) {
655e1b74f21SKevin Lo 			if (actlen < (int)(sizeof(pkt))) {
656e1b74f21SKevin Lo 				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
657e1b74f21SKevin Lo 				goto tr_setup;
658e1b74f21SKevin Lo 			}
6597d5522e1SJohn-Mark Gurney 			usbd_copy_out(pc, off, &pkt, sizeof(pkt));
6607d5522e1SJohn-Mark Gurney 
6617d5522e1SJohn-Mark Gurney 			off += sizeof(pkt);
6627d5522e1SJohn-Mark Gurney 			actlen -= sizeof(pkt);
6637d5522e1SJohn-Mark Gurney 
664e1b74f21SKevin Lo 			len = le32toh(pkt.ure_pktlen) & URE_RXPKT_LEN_MASK;
6657d5522e1SJohn-Mark Gurney 
6667d5522e1SJohn-Mark Gurney 			DEVPRINTFN(13, sc->sc_ue.ue_dev,
6677d5522e1SJohn-Mark Gurney 			    "rxpkt: %#x, %#x, %#x, %#x, %#x, %#x\n",
6687d5522e1SJohn-Mark Gurney 			    pkt.ure_pktlen, pkt.ure_csum, pkt.ure_misc,
6697d5522e1SJohn-Mark Gurney 			    pkt.ure_rsvd2, pkt.ure_rsvd3, pkt.ure_rsvd4);
6707d5522e1SJohn-Mark Gurney 			DEVPRINTFN(13, sc->sc_ue.ue_dev, "len: %d\n", len);
6717d5522e1SJohn-Mark Gurney 
6727d5522e1SJohn-Mark Gurney 			if (len >= URE_RXPKT_LEN_MASK) {
6737d5522e1SJohn-Mark Gurney 				/*
6747d5522e1SJohn-Mark Gurney 				 * drop the rest of this segment.  With out
6757d5522e1SJohn-Mark Gurney 				 * more information, we cannot know where next
6767d5522e1SJohn-Mark Gurney 				 * packet starts.  Blindly continuing would
6777d5522e1SJohn-Mark Gurney 				 * cause a packet in packet attack, allowing
6787d5522e1SJohn-Mark Gurney 				 * one VLAN to inject packets w/o a VLAN tag,
6797d5522e1SJohn-Mark Gurney 				 * or injecting packets into other VLANs.
6807d5522e1SJohn-Mark Gurney 				 */
681e1b74f21SKevin Lo 				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
682e1b74f21SKevin Lo 				goto tr_setup;
683e1b74f21SKevin Lo 			}
684e1b74f21SKevin Lo 
6857d5522e1SJohn-Mark Gurney 			if (actlen < len) {
6867d5522e1SJohn-Mark Gurney 				if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
6877d5522e1SJohn-Mark Gurney 				goto tr_setup;
6887d5522e1SJohn-Mark Gurney 			}
6897d5522e1SJohn-Mark Gurney 
6907d0368eeSHans Petter Selasky 			if (len >= (ETHER_HDR_LEN + ETHER_CRC_LEN))
6917d5522e1SJohn-Mark Gurney 				m = ure_makembuf(pc, off, len - ETHER_CRC_LEN);
6927d5522e1SJohn-Mark Gurney 			else
6937d5522e1SJohn-Mark Gurney 				m = NULL;
6947d5522e1SJohn-Mark Gurney 			if (m == NULL) {
6957d5522e1SJohn-Mark Gurney 				if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
6967d5522e1SJohn-Mark Gurney 			} else {
6977d5522e1SJohn-Mark Gurney 				/* make mbuf and queue */
6987d5522e1SJohn-Mark Gurney 				pktcsum = le32toh(pkt.ure_csum);
6997d5522e1SJohn-Mark Gurney 				if (caps & IFCAP_VLAN_HWTAGGING &&
7007d5522e1SJohn-Mark Gurney 				    pktcsum & URE_RXPKT_RX_VLAN_TAG) {
7017d5522e1SJohn-Mark Gurney 					m->m_pkthdr.ether_vtag =
7027d5522e1SJohn-Mark Gurney 					    bswap16(pktcsum &
7037d5522e1SJohn-Mark Gurney 					    URE_RXPKT_VLAN_MASK);
7047d5522e1SJohn-Mark Gurney 					m->m_flags |= M_VLANTAG;
7057d5522e1SJohn-Mark Gurney 				}
7067d5522e1SJohn-Mark Gurney 
7077d5522e1SJohn-Mark Gurney 				/* set the necessary flags for rx checksum */
7087d5522e1SJohn-Mark Gurney 				ure_rxcsum(caps, &pkt, m);
7097d5522e1SJohn-Mark Gurney 
7107d5522e1SJohn-Mark Gurney 				uether_rxmbuf(ue, m, len - ETHER_CRC_LEN);
7117d5522e1SJohn-Mark Gurney 			}
7127d5522e1SJohn-Mark Gurney 
7137d5522e1SJohn-Mark Gurney 			off += roundup(len, URE_RXPKT_ALIGN);
7147d5522e1SJohn-Mark Gurney 			actlen -= roundup(len, URE_RXPKT_ALIGN);
7157d5522e1SJohn-Mark Gurney 		}
7167d5522e1SJohn-Mark Gurney 		DEVPRINTFN(13, sc->sc_ue.ue_dev, "rcb end\n");
7177d5522e1SJohn-Mark Gurney 
718e1b74f21SKevin Lo 		/* FALLTHROUGH */
719e1b74f21SKevin Lo 	case USB_ST_SETUP:
720e1b74f21SKevin Lo tr_setup:
721e1b74f21SKevin Lo 		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
722e1b74f21SKevin Lo 		usbd_transfer_submit(xfer);
723e1b74f21SKevin Lo 		uether_rxflush(ue);
724e1b74f21SKevin Lo 		return;
725e1b74f21SKevin Lo 
726e1b74f21SKevin Lo 	default:			/* Error */
727e1b74f21SKevin Lo 		DPRINTF("bulk read error, %s\n",
728e1b74f21SKevin Lo 		    usbd_errstr(error));
729e1b74f21SKevin Lo 
730e1b74f21SKevin Lo 		if (error != USB_ERR_CANCELLED) {
731e1b74f21SKevin Lo 			/* try to clear stall first */
732e1b74f21SKevin Lo 			usbd_xfer_set_stall(xfer);
733e1b74f21SKevin Lo 			goto tr_setup;
734e1b74f21SKevin Lo 		}
735e1b74f21SKevin Lo 		return;
736e1b74f21SKevin Lo 	}
737e1b74f21SKevin Lo }
738e1b74f21SKevin Lo 
739e1b74f21SKevin Lo static void
740e1b74f21SKevin Lo ure_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
741e1b74f21SKevin Lo {
742e1b74f21SKevin Lo 	struct ure_softc *sc = usbd_xfer_softc(xfer);
743935b194dSJustin Hibbits 	if_t ifp = uether_getifp(&sc->sc_ue);
744e1b74f21SKevin Lo 	struct usb_page_cache *pc;
745e1b74f21SKevin Lo 	struct mbuf *m;
746e1b74f21SKevin Lo 	struct ure_txpkt txpkt;
7477d5522e1SJohn-Mark Gurney 	uint32_t regtmp;
748e1b74f21SKevin Lo 	int len, pos;
7497d5522e1SJohn-Mark Gurney 	int rem;
7507d5522e1SJohn-Mark Gurney 	int caps;
751e1b74f21SKevin Lo 
752e1b74f21SKevin Lo 	switch (USB_GET_STATE(xfer)) {
753e1b74f21SKevin Lo 	case USB_ST_TRANSFERRED:
754e1b74f21SKevin Lo 		DPRINTFN(11, "transfer complete\n");
755935b194dSJustin Hibbits 		if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
7567d5522e1SJohn-Mark Gurney 
757e1b74f21SKevin Lo 		/* FALLTHROUGH */
758e1b74f21SKevin Lo 	case USB_ST_SETUP:
759e1b74f21SKevin Lo tr_setup:
7607d5522e1SJohn-Mark Gurney 		if ((sc->sc_flags & URE_FLAG_LINK) == 0) {
7617d5522e1SJohn-Mark Gurney 			/* don't send anything if there is no link! */
7627d5522e1SJohn-Mark Gurney 			break;
763e1b74f21SKevin Lo 		}
7647d5522e1SJohn-Mark Gurney 
7657d5522e1SJohn-Mark Gurney 		pc = usbd_xfer_get_frame(xfer, 0);
7667d5522e1SJohn-Mark Gurney 		caps = if_getcapenable(ifp);
7677d5522e1SJohn-Mark Gurney 
7687d5522e1SJohn-Mark Gurney 		pos = 0;
769d4cf41a9SHans Petter Selasky 		rem = URE_TX_BUFSZ;
7707d5522e1SJohn-Mark Gurney 		while (rem > sizeof(txpkt)) {
771935b194dSJustin Hibbits 			m = if_dequeue(ifp);
772e1b74f21SKevin Lo 			if (m == NULL)
773e1b74f21SKevin Lo 				break;
7747d5522e1SJohn-Mark Gurney 
7757d5522e1SJohn-Mark Gurney 			/*
7767d5522e1SJohn-Mark Gurney 			 * make sure we don't ever send too large of a
7777d5522e1SJohn-Mark Gurney 			 * packet
7787d5522e1SJohn-Mark Gurney 			 */
779e1b74f21SKevin Lo 			len = m->m_pkthdr.len;
7807d5522e1SJohn-Mark Gurney 			if ((len & URE_TXPKT_LEN_MASK) != len) {
7817d5522e1SJohn-Mark Gurney 				device_printf(sc->sc_ue.ue_dev,
7827d5522e1SJohn-Mark Gurney 				    "pkt len too large: %#x", len);
7837d5522e1SJohn-Mark Gurney pkterror:
7847d5522e1SJohn-Mark Gurney 				if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
7857d5522e1SJohn-Mark Gurney 				m_freem(m);
7867d5522e1SJohn-Mark Gurney 				continue;
7877d5522e1SJohn-Mark Gurney 			}
7887d5522e1SJohn-Mark Gurney 
7897d5522e1SJohn-Mark Gurney 			if (sizeof(txpkt) +
7907d5522e1SJohn-Mark Gurney 			    roundup(len, URE_TXPKT_ALIGN) > rem) {
7917d5522e1SJohn-Mark Gurney 				/* out of space */
792935b194dSJustin Hibbits 				if_sendq_prepend(ifp, m);
7937d5522e1SJohn-Mark Gurney 				m = NULL;
7947d5522e1SJohn-Mark Gurney 				break;
7957d5522e1SJohn-Mark Gurney 			}
7967d5522e1SJohn-Mark Gurney 
7977d5522e1SJohn-Mark Gurney 			txpkt = (struct ure_txpkt){};
798e1b74f21SKevin Lo 			txpkt.ure_pktlen = htole32((len & URE_TXPKT_LEN_MASK) |
799e1b74f21SKevin Lo 			    URE_TKPKT_TX_FS | URE_TKPKT_TX_LS);
8007d5522e1SJohn-Mark Gurney 			if (m->m_flags & M_VLANTAG) {
8017d5522e1SJohn-Mark Gurney 				txpkt.ure_csum = htole32(
8027d5522e1SJohn-Mark Gurney 				    bswap16(m->m_pkthdr.ether_vtag &
8037d5522e1SJohn-Mark Gurney 				    URE_TXPKT_VLAN_MASK) | URE_TXPKT_VLAN);
8047d5522e1SJohn-Mark Gurney 			}
8057d5522e1SJohn-Mark Gurney 			if (ure_txcsum(m, caps, &regtmp)) {
8067d5522e1SJohn-Mark Gurney 				device_printf(sc->sc_ue.ue_dev,
8077d5522e1SJohn-Mark Gurney 				    "pkt l4 off too large");
8087d5522e1SJohn-Mark Gurney 				goto pkterror;
8097d5522e1SJohn-Mark Gurney 			}
8107d5522e1SJohn-Mark Gurney 			txpkt.ure_csum |= htole32(regtmp);
8117d5522e1SJohn-Mark Gurney 
8127d5522e1SJohn-Mark Gurney 			DEVPRINTFN(13, sc->sc_ue.ue_dev,
8137d5522e1SJohn-Mark Gurney 			    "txpkt: mbflg: %#x, %#x, %#x\n",
8147d5522e1SJohn-Mark Gurney 			    m->m_pkthdr.csum_flags, le32toh(txpkt.ure_pktlen),
8157d5522e1SJohn-Mark Gurney 			    le32toh(txpkt.ure_csum));
8167d5522e1SJohn-Mark Gurney 
817e1b74f21SKevin Lo 			usbd_copy_in(pc, pos, &txpkt, sizeof(txpkt));
8187d5522e1SJohn-Mark Gurney 
819e1b74f21SKevin Lo 			pos += sizeof(txpkt);
8207d5522e1SJohn-Mark Gurney 			rem -= sizeof(txpkt);
8217d5522e1SJohn-Mark Gurney 
8227d5522e1SJohn-Mark Gurney 			usbd_m_copy_in(pc, pos, m, 0, len);
8237d5522e1SJohn-Mark Gurney 
8247d5522e1SJohn-Mark Gurney 			pos += roundup(len, URE_TXPKT_ALIGN);
8257d5522e1SJohn-Mark Gurney 			rem -= roundup(len, URE_TXPKT_ALIGN);
826e1b74f21SKevin Lo 
827e1b74f21SKevin Lo 			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
828e1b74f21SKevin Lo 
829e1b74f21SKevin Lo 			/*
830e1b74f21SKevin Lo 			 * If there's a BPF listener, bounce a copy
831e1b74f21SKevin Lo 			 * of this frame to him.
832e1b74f21SKevin Lo 			 */
833e1b74f21SKevin Lo 			BPF_MTAP(ifp, m);
834e1b74f21SKevin Lo 
835e1b74f21SKevin Lo 			m_freem(m);
8367d5522e1SJohn-Mark Gurney 		}
8377d5522e1SJohn-Mark Gurney 
8387d5522e1SJohn-Mark Gurney 		/* no packets to send */
8397d5522e1SJohn-Mark Gurney 		if (pos == 0)
8407d5522e1SJohn-Mark Gurney 			break;
841e1b74f21SKevin Lo 
842e1b74f21SKevin Lo 		/* Set frame length. */
843e1b74f21SKevin Lo 		usbd_xfer_set_frame_len(xfer, 0, pos);
844e1b74f21SKevin Lo 
845e1b74f21SKevin Lo 		usbd_transfer_submit(xfer);
8467d5522e1SJohn-Mark Gurney 
847e1b74f21SKevin Lo 		return;
8487d5522e1SJohn-Mark Gurney 
849e1b74f21SKevin Lo 	default:			/* Error */
850e1b74f21SKevin Lo 		DPRINTFN(11, "transfer error, %s\n",
851e1b74f21SKevin Lo 		    usbd_errstr(error));
852e1b74f21SKevin Lo 
853e1b74f21SKevin Lo 		if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
854935b194dSJustin Hibbits 		if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
855e1b74f21SKevin Lo 
8567d5522e1SJohn-Mark Gurney 		if (error == USB_ERR_TIMEOUT) {
8577d5522e1SJohn-Mark Gurney 			DEVPRINTFN(12, sc->sc_ue.ue_dev,
8587d5522e1SJohn-Mark Gurney 			    "pkt tx timeout\n");
8597d5522e1SJohn-Mark Gurney 		}
8607d5522e1SJohn-Mark Gurney 
861e1b74f21SKevin Lo 		if (error != USB_ERR_CANCELLED) {
862e1b74f21SKevin Lo 			/* try to clear stall first */
863e1b74f21SKevin Lo 			usbd_xfer_set_stall(xfer);
864e1b74f21SKevin Lo 			goto tr_setup;
865e1b74f21SKevin Lo 		}
866e1b74f21SKevin Lo 	}
867e1b74f21SKevin Lo }
868e1b74f21SKevin Lo 
869e1b74f21SKevin Lo static void
870e1b74f21SKevin Lo ure_read_chipver(struct ure_softc *sc)
871e1b74f21SKevin Lo {
872e1b74f21SKevin Lo 	uint16_t ver;
873e1b74f21SKevin Lo 
874e1b74f21SKevin Lo 	ver = ure_read_2(sc, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK;
8757d5522e1SJohn-Mark Gurney 	sc->sc_ver = ver;
876e1b74f21SKevin Lo 	switch (ver) {
877e1b74f21SKevin Lo 	case 0x4c00:
878e1b74f21SKevin Lo 		sc->sc_chip |= URE_CHIP_VER_4C00;
879d4cf41a9SHans Petter Selasky 		sc->sc_flags = URE_FLAG_8152;
880e1b74f21SKevin Lo 		break;
881e1b74f21SKevin Lo 	case 0x4c10:
882e1b74f21SKevin Lo 		sc->sc_chip |= URE_CHIP_VER_4C10;
883d4cf41a9SHans Petter Selasky 		sc->sc_flags = URE_FLAG_8152;
884e1b74f21SKevin Lo 		break;
885a24d62b5SKevin Lo 	case 0x5c00:
886a24d62b5SKevin Lo 		sc->sc_chip |= URE_CHIP_VER_5C00;
887d4cf41a9SHans Petter Selasky 		sc->sc_flags = URE_FLAG_8153;
888a24d62b5SKevin Lo 		break;
889a24d62b5SKevin Lo 	case 0x5c10:
890a24d62b5SKevin Lo 		sc->sc_chip |= URE_CHIP_VER_5C10;
891d4cf41a9SHans Petter Selasky 		sc->sc_flags = URE_FLAG_8153;
892a24d62b5SKevin Lo 		break;
893a24d62b5SKevin Lo 	case 0x5c20:
894a24d62b5SKevin Lo 		sc->sc_chip |= URE_CHIP_VER_5C20;
895d4cf41a9SHans Petter Selasky 		sc->sc_flags = URE_FLAG_8153;
896a24d62b5SKevin Lo 		break;
897a24d62b5SKevin Lo 	case 0x5c30:
898a24d62b5SKevin Lo 		sc->sc_chip |= URE_CHIP_VER_5C30;
899d4cf41a9SHans Petter Selasky 		sc->sc_flags = URE_FLAG_8153;
900d4cf41a9SHans Petter Selasky 		break;
901d4cf41a9SHans Petter Selasky 	case 0x6000:
902d4cf41a9SHans Petter Selasky 		sc->sc_flags = URE_FLAG_8153B;
903d4cf41a9SHans Petter Selasky 		sc->sc_chip |= URE_CHIP_VER_6000;
904d4cf41a9SHans Petter Selasky 		break;
905d4cf41a9SHans Petter Selasky 	case 0x6010:
906d4cf41a9SHans Petter Selasky 		sc->sc_flags = URE_FLAG_8153B;
907d4cf41a9SHans Petter Selasky 		sc->sc_chip |= URE_CHIP_VER_6010;
908d4cf41a9SHans Petter Selasky 		break;
909d4cf41a9SHans Petter Selasky 	case 0x7020:
910d4cf41a9SHans Petter Selasky 		sc->sc_flags = URE_FLAG_8156;
911d4cf41a9SHans Petter Selasky 		sc->sc_chip |= URE_CHIP_VER_7020;
912d4cf41a9SHans Petter Selasky 		break;
913d4cf41a9SHans Petter Selasky 	case 0x7030:
914d4cf41a9SHans Petter Selasky 		sc->sc_flags = URE_FLAG_8156;
915d4cf41a9SHans Petter Selasky 		sc->sc_chip |= URE_CHIP_VER_7030;
916d4cf41a9SHans Petter Selasky 		break;
917d4cf41a9SHans Petter Selasky 	case 0x7400:
918d4cf41a9SHans Petter Selasky 		sc->sc_flags = URE_FLAG_8156B;
919d4cf41a9SHans Petter Selasky 		sc->sc_chip |= URE_CHIP_VER_7400;
920d4cf41a9SHans Petter Selasky 		break;
921d4cf41a9SHans Petter Selasky 	case 0x7410:
922d4cf41a9SHans Petter Selasky 		sc->sc_flags = URE_FLAG_8156B;
923d4cf41a9SHans Petter Selasky 		sc->sc_chip |= URE_CHIP_VER_7410;
924a24d62b5SKevin Lo 		break;
925e1b74f21SKevin Lo 	default:
926e1b74f21SKevin Lo 		device_printf(sc->sc_ue.ue_dev,
927e1b74f21SKevin Lo 		    "unknown version 0x%04x\n", ver);
928e1b74f21SKevin Lo 		break;
929e1b74f21SKevin Lo 	}
930e1b74f21SKevin Lo }
931e1b74f21SKevin Lo 
9327d5522e1SJohn-Mark Gurney static int
9337d5522e1SJohn-Mark Gurney ure_sysctl_chipver(SYSCTL_HANDLER_ARGS)
9347d5522e1SJohn-Mark Gurney {
9357d5522e1SJohn-Mark Gurney 	struct sbuf sb;
9367d5522e1SJohn-Mark Gurney 	struct ure_softc *sc = arg1;
9377d5522e1SJohn-Mark Gurney 	int error;
9387d5522e1SJohn-Mark Gurney 
9397d5522e1SJohn-Mark Gurney 	sbuf_new_for_sysctl(&sb, NULL, 0, req);
9407d5522e1SJohn-Mark Gurney 
9417d5522e1SJohn-Mark Gurney 	sbuf_printf(&sb, "%04x", sc->sc_ver);
9427d5522e1SJohn-Mark Gurney 
9437d5522e1SJohn-Mark Gurney 	error = sbuf_finish(&sb);
9447d5522e1SJohn-Mark Gurney 	sbuf_delete(&sb);
9457d5522e1SJohn-Mark Gurney 
9467d5522e1SJohn-Mark Gurney 	return (error);
9477d5522e1SJohn-Mark Gurney }
9487d5522e1SJohn-Mark Gurney 
949e1b74f21SKevin Lo static void
950e1b74f21SKevin Lo ure_attach_post(struct usb_ether *ue)
951e1b74f21SKevin Lo {
952e1b74f21SKevin Lo 	struct ure_softc *sc = uether_getsc(ue);
953e1b74f21SKevin Lo 
9547d5522e1SJohn-Mark Gurney 	sc->sc_rxstarted = 0;
955e1b74f21SKevin Lo 	sc->sc_phyno = 0;
956e1b74f21SKevin Lo 
957e1b74f21SKevin Lo 	/* Determine the chip version. */
958e1b74f21SKevin Lo 	ure_read_chipver(sc);
959e1b74f21SKevin Lo 
960e1b74f21SKevin Lo 	/* Initialize controller and get station address. */
961a24d62b5SKevin Lo 	if (sc->sc_flags & URE_FLAG_8152)
962e1b74f21SKevin Lo 		ure_rtl8152_init(sc);
963d4cf41a9SHans Petter Selasky 	else if (sc->sc_flags & (URE_FLAG_8153B | URE_FLAG_8156 | URE_FLAG_8156B))
964d4cf41a9SHans Petter Selasky 		ure_rtl8153b_init(sc);
965a24d62b5SKevin Lo 	else
966a24d62b5SKevin Lo 		ure_rtl8153_init(sc);
967e1b74f21SKevin Lo 
968cef38d45SGanbold Tsagaankhuu 	if ((sc->sc_chip & URE_CHIP_VER_4C00) ||
969cef38d45SGanbold Tsagaankhuu 	    (sc->sc_chip & URE_CHIP_VER_4C10))
970e1b74f21SKevin Lo 		ure_read_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA,
971e1b74f21SKevin Lo 		    ue->ue_eaddr, 8);
972e1b74f21SKevin Lo 	else
973e1b74f21SKevin Lo 		ure_read_mem(sc, URE_PLA_BACKUP, URE_MCU_TYPE_PLA,
974e1b74f21SKevin Lo 		    ue->ue_eaddr, 8);
975cef38d45SGanbold Tsagaankhuu 
976cef38d45SGanbold Tsagaankhuu 	if (ETHER_IS_ZERO(sc->sc_ue.ue_eaddr)) {
977cef38d45SGanbold Tsagaankhuu 		device_printf(sc->sc_ue.ue_dev, "MAC assigned randomly\n");
978cef38d45SGanbold Tsagaankhuu 		arc4rand(sc->sc_ue.ue_eaddr, ETHER_ADDR_LEN, 0);
979cef38d45SGanbold Tsagaankhuu 		sc->sc_ue.ue_eaddr[0] &= ~0x01; /* unicast */
980cef38d45SGanbold Tsagaankhuu 		sc->sc_ue.ue_eaddr[0] |= 0x02;  /* locally administered */
981cef38d45SGanbold Tsagaankhuu 	}
982e1b74f21SKevin Lo }
983e1b74f21SKevin Lo 
984e1b74f21SKevin Lo static int
985e1b74f21SKevin Lo ure_attach_post_sub(struct usb_ether *ue)
986e1b74f21SKevin Lo {
987412bbd08SHans Petter Selasky 	struct sysctl_ctx_list *sctx;
988412bbd08SHans Petter Selasky 	struct sysctl_oid *soid;
989e1b74f21SKevin Lo 	struct ure_softc *sc;
990935b194dSJustin Hibbits 	if_t ifp;
991e1b74f21SKevin Lo 	int error;
992e1b74f21SKevin Lo 
993e1b74f21SKevin Lo 	sc = uether_getsc(ue);
994e1b74f21SKevin Lo 	ifp = ue->ue_ifp;
995935b194dSJustin Hibbits 	if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
996935b194dSJustin Hibbits 	if_setstartfn(ifp, uether_start);
997935b194dSJustin Hibbits 	if_setioctlfn(ifp, ure_ioctl);
998935b194dSJustin Hibbits 	if_setinitfn(ifp, uether_init);
9997d5522e1SJohn-Mark Gurney 	/*
10007d5522e1SJohn-Mark Gurney 	 * Try to keep two transfers full at a time.
10017d5522e1SJohn-Mark Gurney 	 * ~(TRANSFER_SIZE / 80 bytes/pkt * 2 buffers in flight)
10027d5522e1SJohn-Mark Gurney 	 */
1003935b194dSJustin Hibbits 	if_setsendqlen(ifp, 512);
1004935b194dSJustin Hibbits 	if_setsendqready(ifp);
1005e1b74f21SKevin Lo 
10067d5522e1SJohn-Mark Gurney 	if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0);
10077d5522e1SJohn-Mark Gurney 	if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTAGGING, 0);
10087d5522e1SJohn-Mark Gurney 	if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWCSUM|IFCAP_HWCSUM, 0);
10097d5522e1SJohn-Mark Gurney 	if_sethwassist(ifp, CSUM_IP|CSUM_IP_UDP|CSUM_IP_TCP);
10107d5522e1SJohn-Mark Gurney #ifdef INET6
10117d5522e1SJohn-Mark Gurney 	if_setcapabilitiesbit(ifp, IFCAP_HWCSUM_IPV6, 0);
10127d5522e1SJohn-Mark Gurney #endif
10137d5522e1SJohn-Mark Gurney 	if_setcapenable(ifp, if_getcapabilities(ifp));
10147d5522e1SJohn-Mark Gurney 
1015d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
1016d4cf41a9SHans Petter Selasky 		ifmedia_init(&sc->sc_ifmedia, IFM_IMASK, ure_ifmedia_upd,
1017d4cf41a9SHans Petter Selasky 		    ure_ifmedia_sts);
1018d4cf41a9SHans Petter Selasky 		ure_add_media_types(sc);
1019d4cf41a9SHans Petter Selasky 		ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
1020d4cf41a9SHans Petter Selasky 		ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO);
1021d4cf41a9SHans Petter Selasky 		sc->sc_ifmedia.ifm_media = IFM_ETHER | IFM_AUTO;
1022d4cf41a9SHans Petter Selasky 		error = 0;
1023d4cf41a9SHans Petter Selasky 	} else {
1024c6df6f53SWarner Losh 		bus_topo_lock();
1025e1b74f21SKevin Lo 		error = mii_attach(ue->ue_dev, &ue->ue_miibus, ifp,
1026e1b74f21SKevin Lo 		    uether_ifmedia_upd, ue->ue_methods->ue_mii_sts,
1027e1b74f21SKevin Lo 		    BMSR_DEFCAPMASK, sc->sc_phyno, MII_OFFSET_ANY, 0);
1028c6df6f53SWarner Losh 		bus_topo_unlock();
1029d4cf41a9SHans Petter Selasky 	}
1030e1b74f21SKevin Lo 
1031412bbd08SHans Petter Selasky 	sctx = device_get_sysctl_ctx(sc->sc_ue.ue_dev);
1032412bbd08SHans Petter Selasky 	soid = device_get_sysctl_tree(sc->sc_ue.ue_dev);
1033412bbd08SHans Petter Selasky 	SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO, "chipver",
1034412bbd08SHans Petter Selasky 	    CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, sc, 0,
1035412bbd08SHans Petter Selasky 	    ure_sysctl_chipver, "A",
1036412bbd08SHans Petter Selasky 	    "Return string with chip version.");
1037412bbd08SHans Petter Selasky 
1038e1b74f21SKevin Lo 	return (error);
1039e1b74f21SKevin Lo }
1040e1b74f21SKevin Lo 
1041e1b74f21SKevin Lo static void
1042e1b74f21SKevin Lo ure_init(struct usb_ether *ue)
1043e1b74f21SKevin Lo {
1044e1b74f21SKevin Lo 	struct ure_softc *sc = uether_getsc(ue);
1045935b194dSJustin Hibbits 	if_t ifp = uether_getifp(ue);
10467d5522e1SJohn-Mark Gurney 	uint16_t cpcr;
1047d4cf41a9SHans Petter Selasky 	uint32_t reg;
1048e1b74f21SKevin Lo 
1049e1b74f21SKevin Lo 	URE_LOCK_ASSERT(sc, MA_OWNED);
1050e1b74f21SKevin Lo 
1051935b194dSJustin Hibbits 	if ((if_getdrvflags(ifp) & IFF_DRV_RUNNING) != 0)
1052e1b74f21SKevin Lo 		return;
1053e1b74f21SKevin Lo 
1054e1b74f21SKevin Lo 	/* Cancel pending I/O. */
1055e1b74f21SKevin Lo 	ure_stop(ue);
1056e1b74f21SKevin Lo 
1057d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & (URE_FLAG_8153B | URE_FLAG_8156 | URE_FLAG_8156B))
1058d4cf41a9SHans Petter Selasky 		ure_rtl8153b_nic_reset(sc);
1059d4cf41a9SHans Petter Selasky 	else
1060e1b74f21SKevin Lo 		ure_reset(sc);
1061e1b74f21SKevin Lo 
1062e1b74f21SKevin Lo 	/* Set MAC address. */
1063cef38d45SGanbold Tsagaankhuu 	ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG);
1064e1b74f21SKevin Lo 	ure_write_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES,
1065935b194dSJustin Hibbits 	    if_getlladdr(ifp), 8);
1066cef38d45SGanbold Tsagaankhuu 	ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML);
1067e1b74f21SKevin Lo 
1068d4cf41a9SHans Petter Selasky 	/* Set RX EARLY timeout and size */
1069d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & URE_FLAG_8153) {
1070d4cf41a9SHans Petter Selasky 		switch (usbd_get_speed(sc->sc_ue.ue_udev)) {
1071d4cf41a9SHans Petter Selasky 		case USB_SPEED_SUPER:
1072d4cf41a9SHans Petter Selasky 			reg = URE_COALESCE_SUPER / 8;
1073d4cf41a9SHans Petter Selasky 			break;
1074d4cf41a9SHans Petter Selasky 		case USB_SPEED_HIGH:
1075d4cf41a9SHans Petter Selasky 			reg = URE_COALESCE_HIGH / 8;
1076d4cf41a9SHans Petter Selasky 			break;
1077d4cf41a9SHans Petter Selasky 		default:
1078d4cf41a9SHans Petter Selasky 			reg = URE_COALESCE_SLOW / 8;
1079d4cf41a9SHans Petter Selasky 			break;
1080d4cf41a9SHans Petter Selasky 		}
1081d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_USB_RX_EARLY_AGG, URE_MCU_TYPE_USB, reg);
1082d4cf41a9SHans Petter Selasky 		reg = URE_8153_RX_BUFSZ - (URE_FRAMELEN(if_getmtu(ifp)) +
1083d4cf41a9SHans Petter Selasky 		    sizeof(struct ure_rxpkt) + URE_RXPKT_ALIGN);
1084d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_USB_RX_EARLY_SIZE, URE_MCU_TYPE_USB, reg / 4);
1085d4cf41a9SHans Petter Selasky 	} else if (sc->sc_flags & URE_FLAG_8153B) {
1086d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_USB_RX_EARLY_AGG, URE_MCU_TYPE_USB, 158);
1087d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_USB_RX_EXTRA_AGG_TMR, URE_MCU_TYPE_USB, 1875);
1088d4cf41a9SHans Petter Selasky 		reg = URE_8153_RX_BUFSZ - (URE_FRAMELEN(if_getmtu(ifp)) +
1089d4cf41a9SHans Petter Selasky 		    sizeof(struct ure_rxpkt) + URE_RXPKT_ALIGN);
1090d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_USB_RX_EARLY_SIZE, URE_MCU_TYPE_USB, reg / 8);
1091d4cf41a9SHans Petter Selasky 		ure_write_1(sc, URE_USB_UPT_RXDMA_OWN, URE_MCU_TYPE_USB,
1092d4cf41a9SHans Petter Selasky 		    URE_OWN_UPDATE | URE_OWN_CLEAR);
1093d4cf41a9SHans Petter Selasky 	} else if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
1094d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_USB_RX_EARLY_AGG, URE_MCU_TYPE_USB, 80);
1095d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_USB_RX_EXTRA_AGG_TMR, URE_MCU_TYPE_USB, 1875);
1096d4cf41a9SHans Petter Selasky 		reg = URE_8156_RX_BUFSZ - (URE_FRAMELEN(if_getmtu(ifp)) +
1097d4cf41a9SHans Petter Selasky 		    sizeof(struct ure_rxpkt) + URE_RXPKT_ALIGN);
1098d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_USB_RX_EARLY_SIZE, URE_MCU_TYPE_USB, reg / 8);
1099d4cf41a9SHans Petter Selasky 		ure_write_1(sc, URE_USB_UPT_RXDMA_OWN, URE_MCU_TYPE_USB,
1100d4cf41a9SHans Petter Selasky 		    URE_OWN_UPDATE | URE_OWN_CLEAR);
1101d4cf41a9SHans Petter Selasky 	}
1102d4cf41a9SHans Petter Selasky 
1103d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & URE_FLAG_8156B) {
1104d4cf41a9SHans Petter Selasky 		URE_CLRBIT_2(sc, URE_USB_FW_TASK, URE_MCU_TYPE_USB, URE_FC_PATCH_TASK);
1105d4cf41a9SHans Petter Selasky 		uether_pause(&sc->sc_ue, hz / 500);
1106d4cf41a9SHans Petter Selasky 		URE_SETBIT_2(sc, URE_USB_FW_TASK, URE_MCU_TYPE_USB, URE_FC_PATCH_TASK);
1107d4cf41a9SHans Petter Selasky 	}
1108d4cf41a9SHans Petter Selasky 
1109e1b74f21SKevin Lo 	/* Reset the packet filter. */
1110d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA, URE_FMC_FCR_MCU_EN);
1111d4cf41a9SHans Petter Selasky 	URE_SETBIT_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA, URE_FMC_FCR_MCU_EN);
1112e1b74f21SKevin Lo 
11137d5522e1SJohn-Mark Gurney 	/* Enable RX VLANs if enabled */
11147d5522e1SJohn-Mark Gurney 	cpcr = ure_read_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA);
11157d5522e1SJohn-Mark Gurney 	if (if_getcapenable(ifp) & IFCAP_VLAN_HWTAGGING) {
11167d5522e1SJohn-Mark Gurney 		DEVPRINTFN(12, sc->sc_ue.ue_dev, "enabled hw vlan tag\n");
11177d5522e1SJohn-Mark Gurney 		cpcr |= URE_CPCR_RX_VLAN;
11187d5522e1SJohn-Mark Gurney 	} else {
11197d5522e1SJohn-Mark Gurney 		DEVPRINTFN(12, sc->sc_ue.ue_dev, "disabled hw vlan tag\n");
11207d5522e1SJohn-Mark Gurney 		cpcr &= ~URE_CPCR_RX_VLAN;
11217d5522e1SJohn-Mark Gurney 	}
11227d5522e1SJohn-Mark Gurney 	ure_write_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA, cpcr);
11237d5522e1SJohn-Mark Gurney 
1124e1b74f21SKevin Lo 	/* Enable transmit and receive. */
1125d4cf41a9SHans Petter Selasky 	URE_SETBIT_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RE | URE_CR_TE);
1126e1b74f21SKevin Lo 
1127d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, URE_RXDY_GATED_EN);
1128e1b74f21SKevin Lo 
1129a24d62b5SKevin Lo 	/*  Configure RX filters. */
1130a24d62b5SKevin Lo 	ure_rxfilter(ue);
1131e1b74f21SKevin Lo 
11327d5522e1SJohn-Mark Gurney 	usbd_xfer_set_stall(sc->sc_tx_xfer[0]);
1133e1b74f21SKevin Lo 
1134e1b74f21SKevin Lo 	/* Indicate we are up and running. */
1135935b194dSJustin Hibbits 	if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
1136e1b74f21SKevin Lo 
1137e1b74f21SKevin Lo 	/* Switch to selected media. */
1138e1b74f21SKevin Lo 	ure_ifmedia_upd(ifp);
1139e1b74f21SKevin Lo }
1140e1b74f21SKevin Lo 
1141e1b74f21SKevin Lo static void
1142e1b74f21SKevin Lo ure_tick(struct usb_ether *ue)
1143e1b74f21SKevin Lo {
1144e1b74f21SKevin Lo 	struct ure_softc *sc = uether_getsc(ue);
1145935b194dSJustin Hibbits 	if_t ifp = uether_getifp(ue);
1146d4cf41a9SHans Petter Selasky 	struct mii_data *mii;
1147e1b74f21SKevin Lo 
1148e1b74f21SKevin Lo 	URE_LOCK_ASSERT(sc, MA_OWNED);
1149e1b74f21SKevin Lo 
11507d5522e1SJohn-Mark Gurney 	(void)ifp;
1151d4cf41a9SHans Petter Selasky 	for (int i = 0; i < URE_MAX_RX; i++)
11527d5522e1SJohn-Mark Gurney 		DEVPRINTFN(13, sc->sc_ue.ue_dev,
11537d5522e1SJohn-Mark Gurney 		    "rx[%d] = %d\n", i, USB_GET_STATE(sc->sc_rx_xfer[i]));
11547d5522e1SJohn-Mark Gurney 
1155d4cf41a9SHans Petter Selasky 	for (int i = 0; i < URE_MAX_TX; i++)
11567d5522e1SJohn-Mark Gurney 		DEVPRINTFN(13, sc->sc_ue.ue_dev,
11577d5522e1SJohn-Mark Gurney 		    "tx[%d] = %d\n", i, USB_GET_STATE(sc->sc_tx_xfer[i]));
11587d5522e1SJohn-Mark Gurney 
1159d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
1160d4cf41a9SHans Petter Selasky 		ure_link_state(sc);
1161d4cf41a9SHans Petter Selasky 	} else {
1162d4cf41a9SHans Petter Selasky 		mii = GET_MII(sc);
1163e1b74f21SKevin Lo 		mii_tick(mii);
1164e1b74f21SKevin Lo 		if ((sc->sc_flags & URE_FLAG_LINK) == 0
1165e1b74f21SKevin Lo 			&& mii->mii_media_status & IFM_ACTIVE &&
1166e1b74f21SKevin Lo 			IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
1167e1b74f21SKevin Lo 			sc->sc_flags |= URE_FLAG_LINK;
11687d5522e1SJohn-Mark Gurney 			sc->sc_rxstarted = 0;
1169e1b74f21SKevin Lo 			ure_start(ue);
1170e1b74f21SKevin Lo 		}
1171e1b74f21SKevin Lo 	}
1172d4cf41a9SHans Petter Selasky }
1173e1b74f21SKevin Lo 
1174a433f711SGleb Smirnoff static u_int
1175a433f711SGleb Smirnoff ure_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
1176a433f711SGleb Smirnoff {
1177a433f711SGleb Smirnoff 	uint32_t h, *hashes = arg;
1178a433f711SGleb Smirnoff 
1179a433f711SGleb Smirnoff 	h = ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 26;
1180a433f711SGleb Smirnoff 	if (h < 32)
1181a433f711SGleb Smirnoff 		hashes[0] |= (1 << h);
1182a433f711SGleb Smirnoff 	else
1183a433f711SGleb Smirnoff 		hashes[1] |= (1 << (h - 32));
1184a433f711SGleb Smirnoff 	return (1);
1185a433f711SGleb Smirnoff }
1186a433f711SGleb Smirnoff 
1187e1b74f21SKevin Lo /*
1188e1b74f21SKevin Lo  * Program the 64-bit multicast hash filter.
1189e1b74f21SKevin Lo  */
1190e1b74f21SKevin Lo static void
1191a24d62b5SKevin Lo ure_rxfilter(struct usb_ether *ue)
1192e1b74f21SKevin Lo {
1193e1b74f21SKevin Lo 	struct ure_softc *sc = uether_getsc(ue);
1194935b194dSJustin Hibbits 	if_t ifp = uether_getifp(ue);
1195a433f711SGleb Smirnoff 	uint32_t rxmode;
1196a433f711SGleb Smirnoff 	uint32_t h, hashes[2] = { 0, 0 };
1197e1b74f21SKevin Lo 
1198e1b74f21SKevin Lo 	URE_LOCK_ASSERT(sc, MA_OWNED);
1199e1b74f21SKevin Lo 
12000b39e344SJohn-Mark Gurney 	rxmode = ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA);
12010b39e344SJohn-Mark Gurney 	rxmode &= ~(URE_RCR_AAP | URE_RCR_AM);
12020b39e344SJohn-Mark Gurney 	rxmode |= URE_RCR_APM;	/* accept physical match packets */
12030b39e344SJohn-Mark Gurney 	rxmode |= URE_RCR_AB;	/* always accept broadcasts */
1204935b194dSJustin Hibbits 	if (if_getflags(ifp) & (IFF_ALLMULTI | IFF_PROMISC)) {
1205935b194dSJustin Hibbits 		if (if_getflags(ifp) & IFF_PROMISC)
1206e1b74f21SKevin Lo 			rxmode |= URE_RCR_AAP;
1207e1b74f21SKevin Lo 		rxmode |= URE_RCR_AM;
1208e1b74f21SKevin Lo 		hashes[0] = hashes[1] = 0xffffffff;
1209e1b74f21SKevin Lo 		goto done;
1210e1b74f21SKevin Lo 	}
1211e1b74f21SKevin Lo 
12127d5522e1SJohn-Mark Gurney 	/* calculate multicast masks */
1213a433f711SGleb Smirnoff 	if_foreach_llmaddr(ifp, ure_hash_maddr, &hashes);
1214e1b74f21SKevin Lo 
1215e1b74f21SKevin Lo 	h = bswap32(hashes[0]);
1216e1b74f21SKevin Lo 	hashes[0] = bswap32(hashes[1]);
1217e1b74f21SKevin Lo 	hashes[1] = h;
12187d5522e1SJohn-Mark Gurney 	rxmode |= URE_RCR_AM;	/* accept multicast packets */
1219e1b74f21SKevin Lo 
1220e1b74f21SKevin Lo done:
12217d5522e1SJohn-Mark Gurney 	DEVPRINTFN(14, ue->ue_dev, "rxfilt: RCR: %#x\n",
12227d5522e1SJohn-Mark Gurney 	    ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA));
1223e1b74f21SKevin Lo 	ure_write_4(sc, URE_PLA_MAR0, URE_MCU_TYPE_PLA, hashes[0]);
1224e1b74f21SKevin Lo 	ure_write_4(sc, URE_PLA_MAR4, URE_MCU_TYPE_PLA, hashes[1]);
1225e1b74f21SKevin Lo 	ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode);
1226e1b74f21SKevin Lo }
1227e1b74f21SKevin Lo 
1228e1b74f21SKevin Lo static void
1229e1b74f21SKevin Lo ure_start(struct usb_ether *ue)
1230e1b74f21SKevin Lo {
1231e1b74f21SKevin Lo 	struct ure_softc *sc = uether_getsc(ue);
12326e5baec3SHans Petter Selasky 	unsigned i;
12337d5522e1SJohn-Mark Gurney 
12347d5522e1SJohn-Mark Gurney 	URE_LOCK_ASSERT(sc, MA_OWNED);
12357d5522e1SJohn-Mark Gurney 
12367d5522e1SJohn-Mark Gurney 	if (!sc->sc_rxstarted) {
12377d5522e1SJohn-Mark Gurney 		sc->sc_rxstarted = 1;
1238d4cf41a9SHans Petter Selasky 		for (i = 0; i != URE_MAX_RX; i++)
12397d5522e1SJohn-Mark Gurney 			usbd_transfer_start(sc->sc_rx_xfer[i]);
12407d5522e1SJohn-Mark Gurney 	}
1241e1b74f21SKevin Lo 
1242d4cf41a9SHans Petter Selasky 	for (i = 0; i != URE_MAX_TX; i++)
12436e5baec3SHans Petter Selasky 		usbd_transfer_start(sc->sc_tx_xfer[i]);
1244e1b74f21SKevin Lo }
1245e1b74f21SKevin Lo 
1246e1b74f21SKevin Lo static void
1247e1b74f21SKevin Lo ure_reset(struct ure_softc *sc)
1248e1b74f21SKevin Lo {
1249e1b74f21SKevin Lo 	int i;
1250e1b74f21SKevin Lo 
1251e1b74f21SKevin Lo 	ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST);
1252e1b74f21SKevin Lo 
1253e1b74f21SKevin Lo 	for (i = 0; i < URE_TIMEOUT; i++) {
1254e1b74f21SKevin Lo 		if (!(ure_read_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA) &
1255e1b74f21SKevin Lo 		    URE_CR_RST))
1256e1b74f21SKevin Lo 			break;
1257e1b74f21SKevin Lo 		uether_pause(&sc->sc_ue, hz / 100);
1258e1b74f21SKevin Lo 	}
1259e1b74f21SKevin Lo 	if (i == URE_TIMEOUT)
1260e1b74f21SKevin Lo 		device_printf(sc->sc_ue.ue_dev, "reset never completed\n");
1261e1b74f21SKevin Lo }
1262e1b74f21SKevin Lo 
1263e1b74f21SKevin Lo /*
1264e1b74f21SKevin Lo  * Set media options.
1265e1b74f21SKevin Lo  */
1266e1b74f21SKevin Lo static int
1267935b194dSJustin Hibbits ure_ifmedia_upd(if_t ifp)
1268e1b74f21SKevin Lo {
1269935b194dSJustin Hibbits 	struct ure_softc *sc = if_getsoftc(ifp);
1270d4cf41a9SHans Petter Selasky 	struct ifmedia *ifm;
1271d4cf41a9SHans Petter Selasky 	struct mii_data *mii;
1272e1b74f21SKevin Lo 	struct mii_softc *miisc;
1273d4cf41a9SHans Petter Selasky 	int gig;
1274d4cf41a9SHans Petter Selasky 	int reg;
1275d4cf41a9SHans Petter Selasky 	int anar;
1276d4cf41a9SHans Petter Selasky 	int locked;
1277e1b74f21SKevin Lo 	int error;
1278e1b74f21SKevin Lo 
1279d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
1280d4cf41a9SHans Petter Selasky 		ifm = &sc->sc_ifmedia;
1281d4cf41a9SHans Petter Selasky 		if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
1282d4cf41a9SHans Petter Selasky 			return (EINVAL);
1283e1b74f21SKevin Lo 
1284d4cf41a9SHans Petter Selasky 		locked = mtx_owned(&sc->sc_mtx);
1285d4cf41a9SHans Petter Selasky 		if (!locked)
1286d4cf41a9SHans Petter Selasky 			URE_LOCK(sc);
1287d4cf41a9SHans Petter Selasky 		reg = ure_ocp_reg_read(sc, 0xa5d4);
1288d4cf41a9SHans Petter Selasky 		reg &= ~URE_ADV_2500TFDX;
1289d4cf41a9SHans Petter Selasky 
1290d4cf41a9SHans Petter Selasky 		anar = gig = 0;
1291d4cf41a9SHans Petter Selasky 		switch (IFM_SUBTYPE(ifm->ifm_media)) {
1292d4cf41a9SHans Petter Selasky 		case IFM_AUTO:
1293d4cf41a9SHans Petter Selasky 			anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
1294d4cf41a9SHans Petter Selasky 			gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
1295d4cf41a9SHans Petter Selasky 			reg |= URE_ADV_2500TFDX;
1296d4cf41a9SHans Petter Selasky 			break;
1297d4cf41a9SHans Petter Selasky 		case IFM_2500_T:
1298d4cf41a9SHans Petter Selasky 			anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
1299d4cf41a9SHans Petter Selasky 			gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
1300d4cf41a9SHans Petter Selasky 			reg |= URE_ADV_2500TFDX;
1301935b194dSJustin Hibbits 			if_setbaudrate(ifp, IF_Mbps(2500));
1302d4cf41a9SHans Petter Selasky 			break;
1303d4cf41a9SHans Petter Selasky 		case IFM_1000_T:
1304d4cf41a9SHans Petter Selasky 			anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
1305d4cf41a9SHans Petter Selasky 			gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
1306935b194dSJustin Hibbits 			if_setbaudrate(ifp, IF_Gbps(1));
1307d4cf41a9SHans Petter Selasky 			break;
1308d4cf41a9SHans Petter Selasky 		case IFM_100_TX:
1309d4cf41a9SHans Petter Selasky 			anar |= ANAR_TX | ANAR_TX_FD;
1310935b194dSJustin Hibbits 			if_setbaudrate(ifp, IF_Mbps(100));
1311d4cf41a9SHans Petter Selasky 			break;
1312d4cf41a9SHans Petter Selasky 		case IFM_10_T:
1313d4cf41a9SHans Petter Selasky 			anar |= ANAR_10 | ANAR_10_FD;
1314935b194dSJustin Hibbits 			if_setbaudrate(ifp, IF_Mbps(10));
1315d4cf41a9SHans Petter Selasky 			break;
1316d4cf41a9SHans Petter Selasky 		default:
1317d4cf41a9SHans Petter Selasky 			device_printf(sc->sc_ue.ue_dev, "unsupported media type\n");
1318d4cf41a9SHans Petter Selasky 			if (!locked)
1319d4cf41a9SHans Petter Selasky 				URE_UNLOCK(sc);
1320d4cf41a9SHans Petter Selasky 			return (EINVAL);
1321d4cf41a9SHans Petter Selasky 		}
1322d4cf41a9SHans Petter Selasky 
1323d4cf41a9SHans Petter Selasky 		ure_ocp_reg_write(sc, URE_OCP_BASE_MII + MII_ANAR * 2,
1324d4cf41a9SHans Petter Selasky 		    anar | ANAR_PAUSE_ASYM | ANAR_FC);
1325d4cf41a9SHans Petter Selasky 		ure_ocp_reg_write(sc, URE_OCP_BASE_MII + MII_100T2CR * 2, gig);
1326d4cf41a9SHans Petter Selasky 		ure_ocp_reg_write(sc, 0xa5d4, reg);
1327d4cf41a9SHans Petter Selasky 		ure_ocp_reg_write(sc, URE_OCP_BASE_MII + MII_BMCR,
1328d4cf41a9SHans Petter Selasky 		    BMCR_AUTOEN | BMCR_STARTNEG);
1329d4cf41a9SHans Petter Selasky 		if (!locked)
1330d4cf41a9SHans Petter Selasky 			URE_UNLOCK(sc);
1331d4cf41a9SHans Petter Selasky 		return (0);
1332d4cf41a9SHans Petter Selasky 	}
1333d4cf41a9SHans Petter Selasky 
1334d4cf41a9SHans Petter Selasky 	mii = GET_MII(sc);
1335d4cf41a9SHans Petter Selasky 
1336d4cf41a9SHans Petter Selasky 	URE_LOCK_ASSERT(sc, MA_OWNED);
1337e1b74f21SKevin Lo 	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1338e1b74f21SKevin Lo 		PHY_RESET(miisc);
1339e1b74f21SKevin Lo 	error = mii_mediachg(mii);
1340e1b74f21SKevin Lo 	return (error);
1341e1b74f21SKevin Lo }
1342e1b74f21SKevin Lo 
1343e1b74f21SKevin Lo /*
1344e1b74f21SKevin Lo  * Report current media status.
1345e1b74f21SKevin Lo  */
1346e1b74f21SKevin Lo static void
1347935b194dSJustin Hibbits ure_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr)
1348e1b74f21SKevin Lo {
1349e1b74f21SKevin Lo 	struct ure_softc *sc;
1350e1b74f21SKevin Lo 	struct mii_data *mii;
1351d4cf41a9SHans Petter Selasky 	uint16_t status;
1352e1b74f21SKevin Lo 
1353935b194dSJustin Hibbits 	sc = if_getsoftc(ifp);
1354d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
1355d4cf41a9SHans Petter Selasky 		URE_LOCK(sc);
1356d4cf41a9SHans Petter Selasky 		ifmr->ifm_status = IFM_AVALID;
1357d4cf41a9SHans Petter Selasky 		if (ure_get_link_status(sc)) {
1358d4cf41a9SHans Petter Selasky 			ifmr->ifm_status |= IFM_ACTIVE;
1359d4cf41a9SHans Petter Selasky 			status = ure_read_2(sc, URE_PLA_PHYSTATUS,
1360d4cf41a9SHans Petter Selasky 			    URE_MCU_TYPE_PLA);
1361d4cf41a9SHans Petter Selasky 			if ((status & URE_PHYSTATUS_FDX) ||
1362d4cf41a9SHans Petter Selasky 			    (status & URE_PHYSTATUS_2500MBPS))
1363d4cf41a9SHans Petter Selasky 				ifmr->ifm_active |= IFM_FDX;
1364d4cf41a9SHans Petter Selasky 			else
1365d4cf41a9SHans Petter Selasky 				ifmr->ifm_active |= IFM_HDX;
1366d4cf41a9SHans Petter Selasky 			if (status & URE_PHYSTATUS_10MBPS)
1367d4cf41a9SHans Petter Selasky 				ifmr->ifm_active |= IFM_10_T;
1368d4cf41a9SHans Petter Selasky 			else if (status & URE_PHYSTATUS_100MBPS)
1369d4cf41a9SHans Petter Selasky 				ifmr->ifm_active |= IFM_100_TX;
1370d4cf41a9SHans Petter Selasky 			else if (status & URE_PHYSTATUS_1000MBPS)
1371d4cf41a9SHans Petter Selasky 				ifmr->ifm_active |= IFM_1000_T;
1372d4cf41a9SHans Petter Selasky 			else if (status & URE_PHYSTATUS_2500MBPS)
1373d4cf41a9SHans Petter Selasky 				ifmr->ifm_active |= IFM_2500_T;
1374d4cf41a9SHans Petter Selasky 		}
1375d4cf41a9SHans Petter Selasky 		URE_UNLOCK(sc);
1376d4cf41a9SHans Petter Selasky 		return;
1377d4cf41a9SHans Petter Selasky 	}
1378d4cf41a9SHans Petter Selasky 
1379e1b74f21SKevin Lo 	mii = GET_MII(sc);
1380e1b74f21SKevin Lo 
1381e1b74f21SKevin Lo 	URE_LOCK(sc);
1382e1b74f21SKevin Lo 	mii_pollstat(mii);
1383e1b74f21SKevin Lo 	ifmr->ifm_active = mii->mii_media_active;
1384e1b74f21SKevin Lo 	ifmr->ifm_status = mii->mii_media_status;
1385e1b74f21SKevin Lo 	URE_UNLOCK(sc);
1386e1b74f21SKevin Lo }
1387e1b74f21SKevin Lo 
1388d4cf41a9SHans Petter Selasky static void
1389d4cf41a9SHans Petter Selasky ure_add_media_types(struct ure_softc *sc)
1390d4cf41a9SHans Petter Selasky {
1391d4cf41a9SHans Petter Selasky 	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
1392d4cf41a9SHans Petter Selasky 	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
1393d4cf41a9SHans Petter Selasky 	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL);
1394d4cf41a9SHans Petter Selasky 	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
1395d4cf41a9SHans Petter Selasky 	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_1000_T | IFM_FDX, 0, NULL);
1396d4cf41a9SHans Petter Selasky 	ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_2500_T | IFM_FDX, 0, NULL);
1397d4cf41a9SHans Petter Selasky }
1398d4cf41a9SHans Petter Selasky 
1399d4cf41a9SHans Petter Selasky static void
1400d4cf41a9SHans Petter Selasky ure_link_state(struct ure_softc *sc)
1401d4cf41a9SHans Petter Selasky {
1402935b194dSJustin Hibbits 	if_t ifp = uether_getifp(&sc->sc_ue);
1403d4cf41a9SHans Petter Selasky 
1404d4cf41a9SHans Petter Selasky 	if (ure_get_link_status(sc)) {
1405935b194dSJustin Hibbits 		if (if_getlinkstate(ifp) != LINK_STATE_UP) {
1406d4cf41a9SHans Petter Selasky 			if_link_state_change(ifp, LINK_STATE_UP);
1407d4cf41a9SHans Petter Selasky 			/* Enable transmit and receive. */
1408d4cf41a9SHans Petter Selasky 			URE_SETBIT_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RE | URE_CR_TE);
1409d4cf41a9SHans Petter Selasky 
1410d4cf41a9SHans Petter Selasky 			if (ure_read_2(sc, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA) &
1411d4cf41a9SHans Petter Selasky 			    URE_PHYSTATUS_2500MBPS)
1412d4cf41a9SHans Petter Selasky 				URE_CLRBIT_2(sc, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, 0x40);
1413d4cf41a9SHans Petter Selasky 			else
1414d4cf41a9SHans Petter Selasky 				URE_SETBIT_2(sc, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, 0x40);
1415d4cf41a9SHans Petter Selasky 		}
1416d4cf41a9SHans Petter Selasky 	} else {
1417935b194dSJustin Hibbits 		if (if_getlinkstate(ifp) != LINK_STATE_DOWN) {
1418d4cf41a9SHans Petter Selasky 			if_link_state_change(ifp, LINK_STATE_DOWN);
1419d4cf41a9SHans Petter Selasky 		}
1420d4cf41a9SHans Petter Selasky 	}
1421d4cf41a9SHans Petter Selasky }
1422d4cf41a9SHans Petter Selasky 
1423d4cf41a9SHans Petter Selasky static int
1424d4cf41a9SHans Petter Selasky ure_get_link_status(struct ure_softc *sc)
1425d4cf41a9SHans Petter Selasky {
1426d4cf41a9SHans Petter Selasky 	if (ure_read_2(sc, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA) &
1427d4cf41a9SHans Petter Selasky 	    URE_PHYSTATUS_LINK) {
1428d4cf41a9SHans Petter Selasky 		sc->sc_flags |= URE_FLAG_LINK;
1429d4cf41a9SHans Petter Selasky 		return (1);
1430d4cf41a9SHans Petter Selasky 	} else {
1431d4cf41a9SHans Petter Selasky 		sc->sc_flags &= ~URE_FLAG_LINK;
1432d4cf41a9SHans Petter Selasky 		return (0);
1433d4cf41a9SHans Petter Selasky 	}
1434d4cf41a9SHans Petter Selasky }
1435d4cf41a9SHans Petter Selasky 
1436e1b74f21SKevin Lo static int
1437935b194dSJustin Hibbits ure_ioctl(if_t ifp, u_long cmd, caddr_t data)
1438e1b74f21SKevin Lo {
1439935b194dSJustin Hibbits 	struct usb_ether *ue = if_getsoftc(ifp);
1440e1b74f21SKevin Lo 	struct ure_softc *sc;
1441e1b74f21SKevin Lo 	struct ifreq *ifr;
1442e1b74f21SKevin Lo 	int error, mask, reinit;
1443e1b74f21SKevin Lo 
1444e1b74f21SKevin Lo 	sc = uether_getsc(ue);
1445e1b74f21SKevin Lo 	ifr = (struct ifreq *)data;
1446e1b74f21SKevin Lo 	error = 0;
1447e1b74f21SKevin Lo 	reinit = 0;
14487d5522e1SJohn-Mark Gurney 	switch (cmd) {
14497d5522e1SJohn-Mark Gurney 	case SIOCSIFCAP:
1450e1b74f21SKevin Lo 		URE_LOCK(sc);
1451935b194dSJustin Hibbits 		mask = ifr->ifr_reqcap ^ if_getcapenable(ifp);
14527d5522e1SJohn-Mark Gurney 		if ((mask & IFCAP_VLAN_HWTAGGING) != 0 &&
1453935b194dSJustin Hibbits 		    (if_getcapabilities(ifp) & IFCAP_VLAN_HWTAGGING) != 0) {
1454935b194dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING);
14557d5522e1SJohn-Mark Gurney 			reinit++;
14567d5522e1SJohn-Mark Gurney 		}
14577d5522e1SJohn-Mark Gurney 		if ((mask & IFCAP_TXCSUM) != 0 &&
1458935b194dSJustin Hibbits 		    (if_getcapabilities(ifp) & IFCAP_TXCSUM) != 0) {
1459935b194dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TXCSUM);
14607d5522e1SJohn-Mark Gurney 		}
14617d5522e1SJohn-Mark Gurney 		if ((mask & IFCAP_RXCSUM) != 0 &&
1462935b194dSJustin Hibbits 		    (if_getcapabilities(ifp) & IFCAP_RXCSUM) != 0) {
1463935b194dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_RXCSUM);
14647d5522e1SJohn-Mark Gurney 		}
14657d5522e1SJohn-Mark Gurney 		if ((mask & IFCAP_TXCSUM_IPV6) != 0 &&
1466935b194dSJustin Hibbits 		    (if_getcapabilities(ifp) & IFCAP_TXCSUM_IPV6) != 0) {
1467935b194dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_TXCSUM_IPV6);
14687d5522e1SJohn-Mark Gurney 		}
14697d5522e1SJohn-Mark Gurney 		if ((mask & IFCAP_RXCSUM_IPV6) != 0 &&
1470935b194dSJustin Hibbits 		    (if_getcapabilities(ifp) & IFCAP_RXCSUM_IPV6) != 0) {
1471935b194dSJustin Hibbits 			if_togglecapenable(ifp, IFCAP_RXCSUM_IPV6);
14727d5522e1SJohn-Mark Gurney 		}
1473935b194dSJustin Hibbits 		if (reinit > 0 && if_getdrvflags(ifp) & IFF_DRV_RUNNING)
1474935b194dSJustin Hibbits 			if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING);
1475e1b74f21SKevin Lo 		else
1476e1b74f21SKevin Lo 			reinit = 0;
1477e1b74f21SKevin Lo 		URE_UNLOCK(sc);
1478e1b74f21SKevin Lo 		if (reinit > 0)
1479e1b74f21SKevin Lo 			uether_init(ue);
14807d5522e1SJohn-Mark Gurney 		break;
14817d5522e1SJohn-Mark Gurney 
14827d5522e1SJohn-Mark Gurney 	case SIOCSIFMTU:
14837d5522e1SJohn-Mark Gurney 		/*
14847d5522e1SJohn-Mark Gurney 		 * in testing large MTUs "crashes" the device, it
14857d5522e1SJohn-Mark Gurney 		 * leaves the device w/ a broken state where link
14867d5522e1SJohn-Mark Gurney 		 * is in a bad state.
14877d5522e1SJohn-Mark Gurney 		 */
14887d5522e1SJohn-Mark Gurney 		if (ifr->ifr_mtu < ETHERMIN ||
14897d5522e1SJohn-Mark Gurney 		    ifr->ifr_mtu > (4096 - ETHER_HDR_LEN -
14907d5522e1SJohn-Mark Gurney 		    ETHER_VLAN_ENCAP_LEN - ETHER_CRC_LEN)) {
14917d5522e1SJohn-Mark Gurney 			error = EINVAL;
14927d5522e1SJohn-Mark Gurney 			break;
14937d5522e1SJohn-Mark Gurney 		}
14947d5522e1SJohn-Mark Gurney 		URE_LOCK(sc);
14957d5522e1SJohn-Mark Gurney 		if (if_getmtu(ifp) != ifr->ifr_mtu)
14967d5522e1SJohn-Mark Gurney 			if_setmtu(ifp, ifr->ifr_mtu);
14977d5522e1SJohn-Mark Gurney 		URE_UNLOCK(sc);
14987d5522e1SJohn-Mark Gurney 		break;
14997d5522e1SJohn-Mark Gurney 
1500d4cf41a9SHans Petter Selasky 	case SIOCGIFMEDIA:
1501d4cf41a9SHans Petter Selasky 	case SIOCSIFMEDIA:
1502d4cf41a9SHans Petter Selasky 		if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B))
1503d4cf41a9SHans Petter Selasky 			error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
1504d4cf41a9SHans Petter Selasky 		else
1505d4cf41a9SHans Petter Selasky 			error = uether_ioctl(ifp, cmd, data);
1506d4cf41a9SHans Petter Selasky 		break;
1507d4cf41a9SHans Petter Selasky 
15087d5522e1SJohn-Mark Gurney 	default:
1509e1b74f21SKevin Lo 		error = uether_ioctl(ifp, cmd, data);
1510d4cf41a9SHans Petter Selasky 		break;
15117d5522e1SJohn-Mark Gurney 	}
1512e1b74f21SKevin Lo 
1513e1b74f21SKevin Lo 	return (error);
1514e1b74f21SKevin Lo }
1515e1b74f21SKevin Lo 
1516e1b74f21SKevin Lo static void
1517e1b74f21SKevin Lo ure_rtl8152_init(struct ure_softc *sc)
1518e1b74f21SKevin Lo {
1519e1b74f21SKevin Lo 	uint32_t pwrctrl;
1520e1b74f21SKevin Lo 
1521d4cf41a9SHans Petter Selasky 	ure_enable_aldps(sc, false);
1522e1b74f21SKevin Lo 
1523e1b74f21SKevin Lo 	if (sc->sc_chip & URE_CHIP_VER_4C00) {
1524d4cf41a9SHans Petter Selasky 		URE_CLRBIT_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, URE_LED_MODE_MASK);
1525e1b74f21SKevin Lo 	}
1526e1b74f21SKevin Lo 
1527d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, URE_POWER_CUT);
1528e1b74f21SKevin Lo 
1529d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB, URE_RESUME_INDICATE);
1530d4cf41a9SHans Petter Selasky 
1531d4cf41a9SHans Petter Selasky 	URE_SETBIT_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH);
1532d4cf41a9SHans Petter Selasky 
1533e1b74f21SKevin Lo 	pwrctrl = ure_read_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA);
1534e1b74f21SKevin Lo 	pwrctrl &= ~URE_MCU_CLK_RATIO_MASK;
1535e1b74f21SKevin Lo 	pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN;
1536e1b74f21SKevin Lo 	ure_write_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl);
1537e1b74f21SKevin Lo 	ure_write_2(sc, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA,
1538e1b74f21SKevin Lo 	    URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK |
1539e1b74f21SKevin Lo 	    URE_SPDWN_LINKCHG_MSK);
1540e1b74f21SKevin Lo 
15417d5522e1SJohn-Mark Gurney 	/* Enable Rx aggregation. */
1542d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, URE_RX_AGG_DISABLE | URE_RX_ZERO_EN);
1543e1b74f21SKevin Lo 
1544d4cf41a9SHans Petter Selasky 	ure_enable_aldps(sc, false);
1545e1b74f21SKevin Lo 
1546d4cf41a9SHans Petter Selasky 	ure_rtl8152_nic_reset(sc);
1547e1b74f21SKevin Lo 
1548e1b74f21SKevin Lo 	ure_write_1(sc, URE_USB_TX_AGG, URE_MCU_TYPE_USB,
1549e1b74f21SKevin Lo 	    URE_TX_AGG_MAX_THRESHOLD);
1550e1b74f21SKevin Lo 	ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH);
1551e1b74f21SKevin Lo 	ure_write_4(sc, URE_USB_TX_DMA, URE_MCU_TYPE_USB,
1552e1b74f21SKevin Lo 	    URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1);
1553e1b74f21SKevin Lo }
1554e1b74f21SKevin Lo 
1555e1b74f21SKevin Lo static void
1556a24d62b5SKevin Lo ure_rtl8153_init(struct ure_softc *sc)
1557a24d62b5SKevin Lo {
1558a24d62b5SKevin Lo 	uint16_t val;
1559a24d62b5SKevin Lo 	uint8_t u1u2[8];
1560a24d62b5SKevin Lo 	int i;
1561a24d62b5SKevin Lo 
1562d4cf41a9SHans Petter Selasky 	ure_enable_aldps(sc, false);
1563a24d62b5SKevin Lo 
1564a24d62b5SKevin Lo 	memset(u1u2, 0x00, sizeof(u1u2));
1565a24d62b5SKevin Lo 	ure_write_mem(sc, URE_USB_TOLERANCE,
1566a24d62b5SKevin Lo 	    URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
1567a24d62b5SKevin Lo 
1568a24d62b5SKevin Lo 	for (i = 0; i < URE_TIMEOUT; i++) {
1569a24d62b5SKevin Lo 		if (ure_read_2(sc, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) &
1570a24d62b5SKevin Lo 		    URE_AUTOLOAD_DONE)
1571a24d62b5SKevin Lo 			break;
1572a24d62b5SKevin Lo 		uether_pause(&sc->sc_ue, hz / 100);
1573a24d62b5SKevin Lo 	}
1574a24d62b5SKevin Lo 	if (i == URE_TIMEOUT)
1575a24d62b5SKevin Lo 		device_printf(sc->sc_ue.ue_dev,
1576a24d62b5SKevin Lo 		    "timeout waiting for chip autoload\n");
1577a24d62b5SKevin Lo 
1578a24d62b5SKevin Lo 	for (i = 0; i < URE_TIMEOUT; i++) {
1579a24d62b5SKevin Lo 		val = ure_ocp_reg_read(sc, URE_OCP_PHY_STATUS) &
1580a24d62b5SKevin Lo 		    URE_PHY_STAT_MASK;
1581a24d62b5SKevin Lo 		if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN)
1582a24d62b5SKevin Lo 			break;
1583a24d62b5SKevin Lo 		uether_pause(&sc->sc_ue, hz / 100);
1584a24d62b5SKevin Lo 	}
1585a24d62b5SKevin Lo 	if (i == URE_TIMEOUT)
1586a24d62b5SKevin Lo 		device_printf(sc->sc_ue.ue_dev,
1587a24d62b5SKevin Lo 		    "timeout waiting for phy to stabilize\n");
1588a24d62b5SKevin Lo 
1589d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, URE_U2P3_ENABLE);
1590a24d62b5SKevin Lo 
1591a24d62b5SKevin Lo 	if (sc->sc_chip & URE_CHIP_VER_5C10) {
1592a24d62b5SKevin Lo 		val = ure_read_2(sc, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB);
1593a24d62b5SKevin Lo 		val &= ~URE_PWD_DN_SCALE_MASK;
1594a24d62b5SKevin Lo 		val |= URE_PWD_DN_SCALE(96);
1595a24d62b5SKevin Lo 		ure_write_2(sc, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val);
1596a24d62b5SKevin Lo 
1597d4cf41a9SHans Petter Selasky 		URE_SETBIT_1(sc, URE_USB_USB2PHY, URE_MCU_TYPE_USB, URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND);
1598d4cf41a9SHans Petter Selasky 	} else if (sc->sc_chip & URE_CHIP_VER_5C20)
1599d4cf41a9SHans Petter Selasky 		URE_CLRBIT_1(sc, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA, URE_ECM_ALDPS);
1600d4cf41a9SHans Petter Selasky 
1601a24d62b5SKevin Lo 	if (sc->sc_chip & (URE_CHIP_VER_5C20 | URE_CHIP_VER_5C30)) {
1602a24d62b5SKevin Lo 		val = ure_read_1(sc, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB);
1603a24d62b5SKevin Lo 		if (ure_read_2(sc, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) ==
1604a24d62b5SKevin Lo 		    0)
1605a24d62b5SKevin Lo 			val &= ~URE_DYNAMIC_BURST;
1606a24d62b5SKevin Lo 		else
1607a24d62b5SKevin Lo 			val |= URE_DYNAMIC_BURST;
1608a24d62b5SKevin Lo 		ure_write_1(sc, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val);
1609a24d62b5SKevin Lo 	}
1610a24d62b5SKevin Lo 
1611d4cf41a9SHans Petter Selasky 	URE_SETBIT_1(sc, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, URE_EP4_FULL_FC);
1612a24d62b5SKevin Lo 
1613d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, URE_TIMER11_EN);
1614a24d62b5SKevin Lo 
1615d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA, URE_LED_MODE_MASK);
1616a24d62b5SKevin Lo 
1617a24d62b5SKevin Lo 	if ((sc->sc_chip & URE_CHIP_VER_5C10) &&
1618a24d62b5SKevin Lo 	    usbd_get_speed(sc->sc_ue.ue_udev) != USB_SPEED_SUPER)
1619a24d62b5SKevin Lo 		val = URE_LPM_TIMER_500MS;
1620a24d62b5SKevin Lo 	else
1621a24d62b5SKevin Lo 		val = URE_LPM_TIMER_500US;
1622a24d62b5SKevin Lo 	ure_write_1(sc, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB,
1623a24d62b5SKevin Lo 	    val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM);
1624a24d62b5SKevin Lo 
1625a24d62b5SKevin Lo 	val = ure_read_2(sc, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB);
1626a24d62b5SKevin Lo 	val &= ~URE_SEN_VAL_MASK;
1627a24d62b5SKevin Lo 	val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE;
1628a24d62b5SKevin Lo 	ure_write_2(sc, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val);
1629a24d62b5SKevin Lo 
1630a24d62b5SKevin Lo 	ure_write_2(sc, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001);
1631a24d62b5SKevin Lo 
1632d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, URE_PWR_EN | URE_PHASE2_EN);
1633d4cf41a9SHans Petter Selasky 
1634d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_MISC_0, URE_MCU_TYPE_USB, URE_PCUT_STATUS);
1635a24d62b5SKevin Lo 
1636a24d62b5SKevin Lo 	memset(u1u2, 0xff, sizeof(u1u2));
1637a24d62b5SKevin Lo 	ure_write_mem(sc, URE_USB_TOLERANCE,
1638a24d62b5SKevin Lo 	    URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
1639a24d62b5SKevin Lo 
1640a24d62b5SKevin Lo 	ure_write_2(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA,
1641a24d62b5SKevin Lo 	    URE_ALDPS_SPDWN_RATIO);
1642a24d62b5SKevin Lo 	ure_write_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA,
1643a24d62b5SKevin Lo 	    URE_EEE_SPDWN_RATIO);
1644a24d62b5SKevin Lo 	ure_write_2(sc, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA,
1645a24d62b5SKevin Lo 	    URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN |
1646a24d62b5SKevin Lo 	    URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN);
1647a24d62b5SKevin Lo 	ure_write_2(sc, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA,
1648a24d62b5SKevin Lo 	    URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN |
1649a24d62b5SKevin Lo 	    URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN |
1650a24d62b5SKevin Lo 	    URE_EEE_SPDWN_EN);
1651a24d62b5SKevin Lo 
1652a24d62b5SKevin Lo 	val = ure_read_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB);
1653a24d62b5SKevin Lo 	if (!(sc->sc_chip & (URE_CHIP_VER_5C00 | URE_CHIP_VER_5C10)))
1654a24d62b5SKevin Lo 		val |= URE_U2P3_ENABLE;
1655a24d62b5SKevin Lo 	else
1656a24d62b5SKevin Lo 		val &= ~URE_U2P3_ENABLE;
1657a24d62b5SKevin Lo 	ure_write_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val);
1658a24d62b5SKevin Lo 
1659a24d62b5SKevin Lo 	memset(u1u2, 0x00, sizeof(u1u2));
1660a24d62b5SKevin Lo 	ure_write_mem(sc, URE_USB_TOLERANCE,
1661a24d62b5SKevin Lo 	    URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
1662a24d62b5SKevin Lo 
1663d4cf41a9SHans Petter Selasky 	ure_enable_aldps(sc, false);
1664a24d62b5SKevin Lo 
1665a24d62b5SKevin Lo 	if (sc->sc_chip & (URE_CHIP_VER_5C00 | URE_CHIP_VER_5C10 |
1666a24d62b5SKevin Lo 	    URE_CHIP_VER_5C20)) {
1667a24d62b5SKevin Lo 		ure_ocp_reg_write(sc, URE_OCP_ADC_CFG,
1668a24d62b5SKevin Lo 		    URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L);
1669a24d62b5SKevin Lo 	}
1670a24d62b5SKevin Lo 	if (sc->sc_chip & URE_CHIP_VER_5C00) {
1671a24d62b5SKevin Lo 		ure_ocp_reg_write(sc, URE_OCP_EEE_CFG,
1672a24d62b5SKevin Lo 		    ure_ocp_reg_read(sc, URE_OCP_EEE_CFG) &
1673a24d62b5SKevin Lo 		    ~URE_CTAP_SHORT_EN);
1674a24d62b5SKevin Lo 	}
1675a24d62b5SKevin Lo 	ure_ocp_reg_write(sc, URE_OCP_POWER_CFG,
1676a24d62b5SKevin Lo 	    ure_ocp_reg_read(sc, URE_OCP_POWER_CFG) |
1677a24d62b5SKevin Lo 	    URE_EEE_CLKDIV_EN);
1678a24d62b5SKevin Lo 	ure_ocp_reg_write(sc, URE_OCP_DOWN_SPEED,
1679a24d62b5SKevin Lo 	    ure_ocp_reg_read(sc, URE_OCP_DOWN_SPEED) |
1680a24d62b5SKevin Lo 	    URE_EN_10M_BGOFF);
1681a24d62b5SKevin Lo 	ure_ocp_reg_write(sc, URE_OCP_POWER_CFG,
1682a24d62b5SKevin Lo 	    ure_ocp_reg_read(sc, URE_OCP_POWER_CFG) |
1683a24d62b5SKevin Lo 	    URE_EN_10M_PLLOFF);
1684d4cf41a9SHans Petter Selasky 	ure_sram_write(sc, URE_SRAM_IMPEDANCE, 0x0b13);
1685d4cf41a9SHans Petter Selasky 	URE_SETBIT_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA, URE_PFM_PWM_SWITCH);
1686a24d62b5SKevin Lo 
1687a24d62b5SKevin Lo 	/* Enable LPF corner auto tune. */
1688d4cf41a9SHans Petter Selasky 	ure_sram_write(sc, URE_SRAM_LPF_CFG, 0xf70f);
1689a24d62b5SKevin Lo 
1690a24d62b5SKevin Lo 	/* Adjust 10M amplitude. */
1691d4cf41a9SHans Petter Selasky 	ure_sram_write(sc, URE_SRAM_10M_AMP1, 0x00af);
1692d4cf41a9SHans Petter Selasky 	ure_sram_write(sc, URE_SRAM_10M_AMP2, 0x0208);
1693d4cf41a9SHans Petter Selasky 
1694d4cf41a9SHans Petter Selasky 	ure_rtl8152_nic_reset(sc);
1695d4cf41a9SHans Petter Selasky 
1696d4cf41a9SHans Petter Selasky 	/* Enable Rx aggregation. */
1697d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, URE_RX_AGG_DISABLE | URE_RX_ZERO_EN);
1698d4cf41a9SHans Petter Selasky 
1699d4cf41a9SHans Petter Selasky 	val = ure_read_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB);
1700d4cf41a9SHans Petter Selasky 	if (!(sc->sc_chip & (URE_CHIP_VER_5C00 | URE_CHIP_VER_5C10)))
1701d4cf41a9SHans Petter Selasky 		val |= URE_U2P3_ENABLE;
1702d4cf41a9SHans Petter Selasky 	else
1703d4cf41a9SHans Petter Selasky 		val &= ~URE_U2P3_ENABLE;
1704d4cf41a9SHans Petter Selasky 	ure_write_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val);
1705d4cf41a9SHans Petter Selasky 
1706d4cf41a9SHans Petter Selasky 	memset(u1u2, 0xff, sizeof(u1u2));
1707d4cf41a9SHans Petter Selasky 	ure_write_mem(sc, URE_USB_TOLERANCE,
1708d4cf41a9SHans Petter Selasky 	    URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
1709a24d62b5SKevin Lo }
1710a24d62b5SKevin Lo 
1711d4cf41a9SHans Petter Selasky static void
1712d4cf41a9SHans Petter Selasky ure_rtl8153b_init(struct ure_softc *sc)
1713d4cf41a9SHans Petter Selasky {
1714d4cf41a9SHans Petter Selasky 	uint16_t val;
1715d4cf41a9SHans Petter Selasky 	int i;
1716d4cf41a9SHans Petter Selasky 
1717d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
1718d4cf41a9SHans Petter Selasky 		URE_CLRBIT_1(sc, 0xd26b, URE_MCU_TYPE_USB, 0x01);
1719d4cf41a9SHans Petter Selasky 		ure_write_2(sc, 0xd32a, URE_MCU_TYPE_USB, 0);
1720d4cf41a9SHans Petter Selasky 		URE_SETBIT_2(sc, 0xcfee, URE_MCU_TYPE_USB, 0x0020);
1721d4cf41a9SHans Petter Selasky 	}
1722d4cf41a9SHans Petter Selasky 
1723d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & URE_FLAG_8156B) {
1724d4cf41a9SHans Petter Selasky 		URE_SETBIT_2(sc, 0xb460, URE_MCU_TYPE_USB, 0x08);
1725d4cf41a9SHans Petter Selasky 	}
1726d4cf41a9SHans Petter Selasky 
1727d4cf41a9SHans Petter Selasky 	ure_enable_aldps(sc, false);
1728d4cf41a9SHans Petter Selasky 
1729d4cf41a9SHans Petter Selasky 	/* Disable U1U2 */
1730d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_LPM_CONFIG, URE_MCU_TYPE_USB, URE_LPM_U1U2_EN);
1731d4cf41a9SHans Petter Selasky 
1732d4cf41a9SHans Petter Selasky 	/* Wait loading flash */
1733d4cf41a9SHans Petter Selasky 	if (sc->sc_chip == URE_CHIP_VER_7410) {
1734d4cf41a9SHans Petter Selasky 		if ((ure_read_2(sc, 0xd3ae, URE_MCU_TYPE_PLA) & 0x0002) &&
1735d4cf41a9SHans Petter Selasky 		    !(ure_read_2(sc, 0xd284, URE_MCU_TYPE_USB) & 0x0020)) {
1736d4cf41a9SHans Petter Selasky 			for (i=0; i < 100; i++) {
1737d4cf41a9SHans Petter Selasky 				if (ure_read_2(sc, 0xd284, URE_MCU_TYPE_USB) & 0x0004)
1738d4cf41a9SHans Petter Selasky 					break;
1739d4cf41a9SHans Petter Selasky 				uether_pause(&sc->sc_ue, hz / 1000);
1740d4cf41a9SHans Petter Selasky 			}
1741d4cf41a9SHans Petter Selasky 		}
1742d4cf41a9SHans Petter Selasky 	}
1743d4cf41a9SHans Petter Selasky 
1744d4cf41a9SHans Petter Selasky 	for (i = 0; i < URE_TIMEOUT; i++) {
1745d4cf41a9SHans Petter Selasky 		if (ure_read_2(sc, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) &
1746d4cf41a9SHans Petter Selasky 		    URE_AUTOLOAD_DONE)
1747d4cf41a9SHans Petter Selasky 			break;
1748d4cf41a9SHans Petter Selasky 		uether_pause(&sc->sc_ue, hz / 100);
1749d4cf41a9SHans Petter Selasky 	}
1750d4cf41a9SHans Petter Selasky 	if (i == URE_TIMEOUT)
1751d4cf41a9SHans Petter Selasky 		device_printf(sc->sc_ue.ue_dev,
1752d4cf41a9SHans Petter Selasky 		    "timeout waiting for chip autoload\n");
1753d4cf41a9SHans Petter Selasky 
1754d4cf41a9SHans Petter Selasky 	val = ure_phy_status(sc, 0);
1755d4cf41a9SHans Petter Selasky 	if ((val == URE_PHY_STAT_EXT_INIT) &
1756d4cf41a9SHans Petter Selasky 	    (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B))) {
1757d4cf41a9SHans Petter Selasky 		ure_ocp_reg_write(sc, 0xa468,
1758d4cf41a9SHans Petter Selasky 		    ure_ocp_reg_read(sc, 0xa468) & ~0x0a);
1759d4cf41a9SHans Petter Selasky 		if (sc->sc_flags & URE_FLAG_8156B)
1760d4cf41a9SHans Petter Selasky 			ure_ocp_reg_write(sc, 0xa466,
1761d4cf41a9SHans Petter Selasky 				ure_ocp_reg_read(sc, 0xa466) & ~0x01);
1762d4cf41a9SHans Petter Selasky 	}
1763d4cf41a9SHans Petter Selasky 
1764d4cf41a9SHans Petter Selasky 	val = ure_ocp_reg_read(sc, URE_OCP_BASE_MII + MII_BMCR);
1765d4cf41a9SHans Petter Selasky 	if (val & BMCR_PDOWN) {
1766d4cf41a9SHans Petter Selasky 		val &= ~BMCR_PDOWN;
1767d4cf41a9SHans Petter Selasky 		ure_ocp_reg_write(sc, URE_OCP_BASE_MII + MII_BMCR, val);
1768d4cf41a9SHans Petter Selasky 	}
1769d4cf41a9SHans Petter Selasky 
1770d4cf41a9SHans Petter Selasky 	ure_phy_status(sc, URE_PHY_STAT_LAN_ON);
1771d4cf41a9SHans Petter Selasky 
1772d4cf41a9SHans Petter Selasky 	/* Disable U2P3 */
1773d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, URE_U2P3_ENABLE);
1774d4cf41a9SHans Petter Selasky 
1775d4cf41a9SHans Petter Selasky 	/* MSC timer, 32760 ms. */
1776d4cf41a9SHans Petter Selasky 	ure_write_2(sc, URE_USB_MSC_TIMER, URE_MCU_TYPE_USB, 0x0fff);
1777d4cf41a9SHans Petter Selasky 
1778d4cf41a9SHans Petter Selasky 	/* U1/U2/L1 idle timer, 500 us. */
1779d4cf41a9SHans Petter Selasky 	ure_write_2(sc, URE_USB_U1U2_TIMER, URE_MCU_TYPE_USB, 500);
1780d4cf41a9SHans Petter Selasky 
1781d4cf41a9SHans Petter Selasky 	/* Disable power cut */
1782d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, URE_PWR_EN);
1783d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_MISC_0, URE_MCU_TYPE_USB, URE_PCUT_STATUS);
1784d4cf41a9SHans Petter Selasky 
1785d4cf41a9SHans Petter Selasky 	/* Disable ups */
1786d4cf41a9SHans Petter Selasky 	URE_CLRBIT_1(sc, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, URE_UPS_EN | URE_USP_PREWAKE);
1787d4cf41a9SHans Petter Selasky 	URE_CLRBIT_1(sc, 0xcfff, URE_MCU_TYPE_USB, 0x01);
1788d4cf41a9SHans Petter Selasky 
1789d4cf41a9SHans Petter Selasky 	/* Disable queue wake */
1790d4cf41a9SHans Petter Selasky 	URE_CLRBIT_1(sc, URE_PLA_INDICATE_FALG, URE_MCU_TYPE_USB, URE_UPCOMING_RUNTIME_D3);
1791d4cf41a9SHans Petter Selasky 	URE_CLRBIT_1(sc, URE_PLA_SUSPEND_FLAG, URE_MCU_TYPE_USB, URE_LINK_CHG_EVENT);
1792d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_PLA_EXTRA_STATUS, URE_MCU_TYPE_USB, URE_LINK_CHANGE_FLAG);
1793d4cf41a9SHans Petter Selasky 
1794d4cf41a9SHans Petter Selasky 	/* Disable runtime suspend */
1795d4cf41a9SHans Petter Selasky 	ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG);
1796d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_PLA_CONFIG34, URE_MCU_TYPE_USB, URE_LINK_OFF_WAKE_EN);
1797d4cf41a9SHans Petter Selasky 	ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML);
1798d4cf41a9SHans Petter Selasky 
1799d4cf41a9SHans Petter Selasky 	/* Enable U1U2 */
1800d4cf41a9SHans Petter Selasky 	if (usbd_get_speed(sc->sc_ue.ue_udev) == USB_SPEED_SUPER)
1801d4cf41a9SHans Petter Selasky 		URE_SETBIT_2(sc, URE_USB_LPM_CONFIG, URE_MCU_TYPE_USB, URE_LPM_U1U2_EN);
1802d4cf41a9SHans Petter Selasky 
1803d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & URE_FLAG_8156B) {
1804d4cf41a9SHans Petter Selasky 		URE_CLRBIT_2(sc, 0xc010, URE_MCU_TYPE_PLA, 0x0800);
1805d4cf41a9SHans Petter Selasky 		URE_SETBIT_2(sc, 0xe854, URE_MCU_TYPE_PLA, 0x0001);
1806d4cf41a9SHans Petter Selasky 
1807d4cf41a9SHans Petter Selasky 		/* enable fc timer and set timer to 600 ms. */
1808d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_USB_FC_TIMER, URE_MCU_TYPE_USB, URE_CTRL_TIMER_EN | (600 / 8));
1809d4cf41a9SHans Petter Selasky 
1810d4cf41a9SHans Petter Selasky 		if (!(ure_read_1(sc, 0xdc6b, URE_MCU_TYPE_PLA) & 0x80)) {
1811d4cf41a9SHans Petter Selasky 			val = ure_read_2(sc, URE_USB_FW_CTRL, URE_MCU_TYPE_USB);
1812d4cf41a9SHans Petter Selasky 			val |= URE_FLOW_CTRL_PATCH_OPT | 0x0100;
1813d4cf41a9SHans Petter Selasky 			val &= ~0x08;
1814d4cf41a9SHans Petter Selasky 			ure_write_2(sc, URE_USB_FW_CTRL, URE_MCU_TYPE_USB, val);
1815d4cf41a9SHans Petter Selasky 		}
1816d4cf41a9SHans Petter Selasky 
1817d4cf41a9SHans Petter Selasky 		URE_SETBIT_2(sc, URE_USB_FW_TASK, URE_MCU_TYPE_USB, URE_FC_PATCH_TASK);
1818d4cf41a9SHans Petter Selasky 	}
1819d4cf41a9SHans Petter Selasky 
1820d4cf41a9SHans Petter Selasky 	val = ure_read_2(sc, URE_PLA_EXTRA_STATUS, URE_MCU_TYPE_PLA);
1821d4cf41a9SHans Petter Selasky 	if (ure_get_link_status(sc))
1822d4cf41a9SHans Petter Selasky 		val |= URE_CUR_LINK_OK;
1823d4cf41a9SHans Petter Selasky 	else
1824d4cf41a9SHans Petter Selasky 		val &= ~URE_CUR_LINK_OK;
1825d4cf41a9SHans Petter Selasky 	val |= URE_POLL_LINK_CHG;
1826d4cf41a9SHans Petter Selasky 	ure_write_2(sc, URE_PLA_EXTRA_STATUS, URE_MCU_TYPE_PLA, val);
1827d4cf41a9SHans Petter Selasky 
1828d4cf41a9SHans Petter Selasky 	/* MAC clock speed down */
1829d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
1830d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, 0x0403);
1831d4cf41a9SHans Petter Selasky 		val = ure_read_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA);
1832d4cf41a9SHans Petter Selasky 		val &= ~0xff;
1833d4cf41a9SHans Petter Selasky 		val |= URE_MAC_CLK_SPDWN_EN | 0x03;
1834d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, val);
1835d4cf41a9SHans Petter Selasky 	} else {
1836d4cf41a9SHans Petter Selasky 		URE_SETBIT_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_USB, URE_MAC_CLK_SPDWN_EN);
1837d4cf41a9SHans Petter Selasky 	}
1838d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, URE_PLA_MCU_SPDWN_EN);
1839d4cf41a9SHans Petter Selasky 
1840d4cf41a9SHans Petter Selasky 	/* Enable Rx aggregation. */
1841d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB, URE_RX_AGG_DISABLE | URE_RX_ZERO_EN);
1842d4cf41a9SHans Petter Selasky 
1843d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & URE_FLAG_8156)
1844d4cf41a9SHans Petter Selasky 		URE_SETBIT_1(sc, 0xd4b4, URE_MCU_TYPE_USB, 0x02);
1845d4cf41a9SHans Petter Selasky 
1846d4cf41a9SHans Petter Selasky 	/* Reset tally */
1847d4cf41a9SHans Petter Selasky 	URE_SETBIT_2(sc, URE_PLA_RSTTALLY, URE_MCU_TYPE_USB, URE_TALLY_RESET);
1848d4cf41a9SHans Petter Selasky }
1849d4cf41a9SHans Petter Selasky 
1850d4cf41a9SHans Petter Selasky static void
1851d4cf41a9SHans Petter Selasky ure_rtl8153b_nic_reset(struct ure_softc *sc)
1852d4cf41a9SHans Petter Selasky {
1853935b194dSJustin Hibbits 	if_t ifp = uether_getifp(&sc->sc_ue);
1854d4cf41a9SHans Petter Selasky 	uint16_t val;
1855d4cf41a9SHans Petter Selasky 	int i;
1856d4cf41a9SHans Petter Selasky 
1857d4cf41a9SHans Petter Selasky 	/* Disable U1U2 */
1858d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_LPM_CONFIG, URE_MCU_TYPE_USB, URE_LPM_U1U2_EN);
1859d4cf41a9SHans Petter Selasky 
1860d4cf41a9SHans Petter Selasky 	/* Disable U2P3 */
1861d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, URE_U2P3_ENABLE);
1862d4cf41a9SHans Petter Selasky 
1863d4cf41a9SHans Petter Selasky 	ure_enable_aldps(sc, false);
1864d4cf41a9SHans Petter Selasky 
1865d4cf41a9SHans Petter Selasky 	/* Enable rxdy_gated */
1866d4cf41a9SHans Petter Selasky 	URE_SETBIT_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, URE_RXDY_GATED_EN);
1867d4cf41a9SHans Petter Selasky 
1868d4cf41a9SHans Petter Selasky 	/* Disable teredo */
1869d4cf41a9SHans Petter Selasky 	ure_disable_teredo(sc);
1870d4cf41a9SHans Petter Selasky 
1871d4cf41a9SHans Petter Selasky 	DEVPRINTFN(14, sc->sc_ue.ue_dev, "rtl8153b_nic_reset: RCR: %#x\n", ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA));
1872d4cf41a9SHans Petter Selasky 	URE_CLRBIT_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, URE_RCR_ACPT_ALL);
1873d4cf41a9SHans Petter Selasky 
1874d4cf41a9SHans Petter Selasky 	ure_reset(sc);
1875d4cf41a9SHans Petter Selasky 
1876d4cf41a9SHans Petter Selasky 	/* Reset BMU */
1877d4cf41a9SHans Petter Selasky 	URE_CLRBIT_1(sc, URE_USB_BMU_RESET, URE_MCU_TYPE_USB, URE_BMU_RESET_EP_IN | URE_BMU_RESET_EP_OUT);
1878d4cf41a9SHans Petter Selasky 	URE_SETBIT_1(sc, URE_USB_BMU_RESET, URE_MCU_TYPE_USB, URE_BMU_RESET_EP_IN | URE_BMU_RESET_EP_OUT);
1879d4cf41a9SHans Petter Selasky 
1880d4cf41a9SHans Petter Selasky 	URE_CLRBIT_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, URE_NOW_IS_OOB);
1881d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, URE_MCU_BORW_EN);
1882d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & URE_FLAG_8153B) {
1883d4cf41a9SHans Petter Selasky 		for (i = 0; i < URE_TIMEOUT; i++) {
1884d4cf41a9SHans Petter Selasky 			if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
1885d4cf41a9SHans Petter Selasky 			    URE_LINK_LIST_READY)
1886d4cf41a9SHans Petter Selasky 				break;
1887d4cf41a9SHans Petter Selasky 			uether_pause(&sc->sc_ue, hz / 100);
1888d4cf41a9SHans Petter Selasky 		}
1889d4cf41a9SHans Petter Selasky 		if (i == URE_TIMEOUT)
1890d4cf41a9SHans Petter Selasky 			device_printf(sc->sc_ue.ue_dev,
1891d4cf41a9SHans Petter Selasky 			    "timeout waiting for OOB control\n");
1892d4cf41a9SHans Petter Selasky 
1893d4cf41a9SHans Petter Selasky 		URE_SETBIT_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, URE_RE_INIT_LL);
1894d4cf41a9SHans Petter Selasky 		for (i = 0; i < URE_TIMEOUT; i++) {
1895d4cf41a9SHans Petter Selasky 			if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
1896d4cf41a9SHans Petter Selasky 			    URE_LINK_LIST_READY)
1897d4cf41a9SHans Petter Selasky 			break;
1898d4cf41a9SHans Petter Selasky 			uether_pause(&sc->sc_ue, hz / 100);
1899d4cf41a9SHans Petter Selasky 		}
1900d4cf41a9SHans Petter Selasky 		if (i == URE_TIMEOUT)
1901d4cf41a9SHans Petter Selasky 			device_printf(sc->sc_ue.ue_dev,
1902d4cf41a9SHans Petter Selasky 			    "timeout waiting for OOB control\n");
1903d4cf41a9SHans Petter Selasky 	}
1904d4cf41a9SHans Petter Selasky 
1905d4cf41a9SHans Petter Selasky 	/* Configure rxvlan */
1906d4cf41a9SHans Petter Selasky 	val = ure_read_2(sc, 0xc012, URE_MCU_TYPE_PLA);
1907d4cf41a9SHans Petter Selasky 	val &= ~0x00c0;
1908935b194dSJustin Hibbits 	if (if_getcapabilities(ifp) & IFCAP_VLAN_HWTAGGING)
1909d4cf41a9SHans Petter Selasky 		val |= 0x00c0;
1910d4cf41a9SHans Petter Selasky 	ure_write_2(sc, 0xc012, URE_MCU_TYPE_PLA, val);
1911d4cf41a9SHans Petter Selasky 
1912d4cf41a9SHans Petter Selasky 	val = if_getmtu(ifp);
1913d4cf41a9SHans Petter Selasky 	ure_write_2(sc, URE_PLA_RMS, URE_MCU_TYPE_PLA, URE_FRAMELEN(val));
1914d4cf41a9SHans Petter Selasky 	ure_write_1(sc, URE_PLA_MTPS, URE_MCU_TYPE_PLA, URE_MTPS_JUMBO);
1915d4cf41a9SHans Petter Selasky 
1916d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & URE_FLAG_8153B) {
1917d4cf41a9SHans Petter Selasky 		URE_SETBIT_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA, URE_TCR0_AUTO_FIFO);
1918d4cf41a9SHans Petter Selasky 		ure_reset(sc);
1919d4cf41a9SHans Petter Selasky 	}
1920d4cf41a9SHans Petter Selasky 
1921d4cf41a9SHans Petter Selasky 	/* Configure fc parameter */
1922d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & URE_FLAG_8156) {
1923d4cf41a9SHans Petter Selasky 		ure_write_2(sc, 0xc0a6, URE_MCU_TYPE_PLA, 0x0400);
1924d4cf41a9SHans Petter Selasky 		ure_write_2(sc, 0xc0aa, URE_MCU_TYPE_PLA, 0x0800);
1925d4cf41a9SHans Petter Selasky 	} else if (sc->sc_flags & URE_FLAG_8156B) {
1926d4cf41a9SHans Petter Selasky 		ure_write_2(sc, 0xc0a6, URE_MCU_TYPE_PLA, 0x0200);
1927d4cf41a9SHans Petter Selasky 		ure_write_2(sc, 0xc0aa, URE_MCU_TYPE_PLA, 0x0400);
1928d4cf41a9SHans Petter Selasky 	}
1929d4cf41a9SHans Petter Selasky 
1930d4cf41a9SHans Petter Selasky 	/* Configure Rx FIFO threshold. */
1931d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & URE_FLAG_8153B) {
1932d4cf41a9SHans Petter Selasky 		ure_write_4(sc, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA,	URE_RXFIFO_THR1_NORMAL);
1933d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, URE_RXFIFO_THR2_NORMAL);
1934d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, URE_RXFIFO_THR3_NORMAL);
1935d4cf41a9SHans Petter Selasky 		ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_B);
1936d4cf41a9SHans Petter Selasky 	} else {
1937d4cf41a9SHans Petter Selasky 		ure_write_2(sc, 0xc0a2, URE_MCU_TYPE_PLA,
1938d4cf41a9SHans Petter Selasky 		    (ure_read_2(sc, 0xc0a2, URE_MCU_TYPE_PLA) & ~0xfff) | 0x08);
1939d4cf41a9SHans Petter Selasky 		ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, 0x00600400);
1940d4cf41a9SHans Petter Selasky 	}
1941d4cf41a9SHans Petter Selasky 
1942d4cf41a9SHans Petter Selasky 	/* Configure Tx FIFO threshold. */
1943d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & URE_FLAG_8153B) {
1944d4cf41a9SHans Petter Selasky 		ure_write_4(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, URE_TXFIFO_THR_NORMAL2);
1945d4cf41a9SHans Petter Selasky 	} else if (sc->sc_flags & URE_FLAG_8156) {
1946d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, URE_TXFIFO_THR_NORMAL2);
1947d4cf41a9SHans Petter Selasky 		URE_SETBIT_2(sc, 0xd4b4, URE_MCU_TYPE_USB, 0x0002);
1948d4cf41a9SHans Petter Selasky 	} else if (sc->sc_flags & URE_FLAG_8156B) {
1949d4cf41a9SHans Petter Selasky 		ure_write_2(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, 0x0008);
1950d4cf41a9SHans Petter Selasky 		ure_write_2(sc, 0xe61a, URE_MCU_TYPE_PLA,
1951d4cf41a9SHans Petter Selasky 		    (URE_FRAMELEN(val) + 0x100) / 16 );
1952d4cf41a9SHans Petter Selasky 	}
1953d4cf41a9SHans Petter Selasky 
1954d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, URE_PLA_MCU_SPDWN_EN);
1955d4cf41a9SHans Petter Selasky 
1956d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B))
1957d4cf41a9SHans Petter Selasky 		URE_CLRBIT_2(sc, 0xd32a, URE_MCU_TYPE_USB, 0x300);
1958d4cf41a9SHans Petter Selasky 
1959d4cf41a9SHans Petter Selasky 	ure_enable_aldps(sc, true);
1960d4cf41a9SHans Petter Selasky 
1961d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
1962d4cf41a9SHans Petter Selasky 		/* Enable U2P3 */
1963d4cf41a9SHans Petter Selasky 		URE_SETBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, URE_U2P3_ENABLE);
1964d4cf41a9SHans Petter Selasky 	}
1965d4cf41a9SHans Petter Selasky 
1966d4cf41a9SHans Petter Selasky 	/* Enable U1U2 */
1967d4cf41a9SHans Petter Selasky 	if (usbd_get_speed(sc->sc_ue.ue_udev) == USB_SPEED_SUPER)
1968d4cf41a9SHans Petter Selasky 		URE_SETBIT_2(sc, URE_USB_LPM_CONFIG, URE_MCU_TYPE_USB, URE_LPM_U1U2_EN);
1969d4cf41a9SHans Petter Selasky }
1970d4cf41a9SHans Petter Selasky 
1971d4cf41a9SHans Petter Selasky static void
1972d4cf41a9SHans Petter Selasky ure_stop(struct usb_ether *ue)
1973d4cf41a9SHans Petter Selasky {
1974d4cf41a9SHans Petter Selasky 	struct ure_softc *sc = uether_getsc(ue);
1975935b194dSJustin Hibbits 	if_t ifp = uether_getifp(ue);
1976d4cf41a9SHans Petter Selasky 
1977d4cf41a9SHans Petter Selasky 	URE_LOCK_ASSERT(sc, MA_OWNED);
1978d4cf41a9SHans Petter Selasky 
1979935b194dSJustin Hibbits 	if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
1980d4cf41a9SHans Petter Selasky 	sc->sc_flags &= ~URE_FLAG_LINK;
1981d4cf41a9SHans Petter Selasky 	sc->sc_rxstarted = 0;
1982d4cf41a9SHans Petter Selasky 
1983d4cf41a9SHans Petter Selasky 	/*
1984d4cf41a9SHans Petter Selasky 	 * stop all the transfers, if not already stopped:
1985d4cf41a9SHans Petter Selasky 	 */
1986d4cf41a9SHans Petter Selasky 	for (int i = 0; i < URE_MAX_RX; i++)
1987d4cf41a9SHans Petter Selasky 		usbd_transfer_stop(sc->sc_rx_xfer[i]);
1988d4cf41a9SHans Petter Selasky 	for (int i = 0; i < URE_MAX_TX; i++)
1989d4cf41a9SHans Petter Selasky 		usbd_transfer_stop(sc->sc_tx_xfer[i]);
1990d4cf41a9SHans Petter Selasky }
1991d4cf41a9SHans Petter Selasky 
1992d4cf41a9SHans Petter Selasky static void
1993d4cf41a9SHans Petter Selasky ure_disable_teredo(struct ure_softc *sc)
1994d4cf41a9SHans Petter Selasky {
1995d4cf41a9SHans Petter Selasky 
1996d4cf41a9SHans Petter Selasky 	if (sc->sc_flags & (URE_FLAG_8153B | URE_FLAG_8156 | URE_FLAG_8156B))
1997d4cf41a9SHans Petter Selasky 		ure_write_1(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, 0xff);
1998d4cf41a9SHans Petter Selasky 	else {
1999d4cf41a9SHans Petter Selasky 		URE_CLRBIT_2(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA,
2000d4cf41a9SHans Petter Selasky 		    (URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN));
2001d4cf41a9SHans Petter Selasky 	}
2002d4cf41a9SHans Petter Selasky 	ure_write_2(sc, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, URE_WDT6_SET_MODE);
2003d4cf41a9SHans Petter Selasky 	ure_write_2(sc, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0);
2004d4cf41a9SHans Petter Selasky 	ure_write_4(sc, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0);
2005d4cf41a9SHans Petter Selasky }
2006d4cf41a9SHans Petter Selasky 
2007d4cf41a9SHans Petter Selasky static void
2008d4cf41a9SHans Petter Selasky ure_enable_aldps(struct ure_softc *sc, bool enable)
2009d4cf41a9SHans Petter Selasky {
2010d4cf41a9SHans Petter Selasky 	int i;
2011d4cf41a9SHans Petter Selasky 
2012d4cf41a9SHans Petter Selasky 	if (enable) {
2013d4cf41a9SHans Petter Selasky 		ure_ocp_reg_write(sc, URE_OCP_POWER_CFG,
2014d4cf41a9SHans Petter Selasky 			ure_ocp_reg_read(sc, URE_OCP_POWER_CFG) | URE_EN_ALDPS);
2015d4cf41a9SHans Petter Selasky 	} else {
2016d4cf41a9SHans Petter Selasky 		ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA |
2017d4cf41a9SHans Petter Selasky 			URE_DIS_SDSAVE);
2018d4cf41a9SHans Petter Selasky 		for (i = 0; i < 20; i++) {
2019d4cf41a9SHans Petter Selasky 			uether_pause(&sc->sc_ue, hz / 1000);
2020d4cf41a9SHans Petter Selasky 			if (ure_ocp_reg_read(sc, 0xe000) & 0x0100)
2021d4cf41a9SHans Petter Selasky 				break;
2022d4cf41a9SHans Petter Selasky 		}
2023d4cf41a9SHans Petter Selasky 	}
2024d4cf41a9SHans Petter Selasky }
2025d4cf41a9SHans Petter Selasky 
2026d4cf41a9SHans Petter Selasky static uint16_t
2027d4cf41a9SHans Petter Selasky ure_phy_status(struct ure_softc *sc, uint16_t desired)
2028d4cf41a9SHans Petter Selasky {
2029d4cf41a9SHans Petter Selasky 	uint16_t val;
2030d4cf41a9SHans Petter Selasky 	int i;
2031d4cf41a9SHans Petter Selasky 
2032d4cf41a9SHans Petter Selasky 	for (i = 0; i < URE_TIMEOUT; i++) {
2033d4cf41a9SHans Petter Selasky 		val = ure_ocp_reg_read(sc, URE_OCP_PHY_STATUS) &
2034d4cf41a9SHans Petter Selasky 		    URE_PHY_STAT_MASK;
2035d4cf41a9SHans Petter Selasky 		if (desired) {
2036d4cf41a9SHans Petter Selasky 			if (val == desired)
2037d4cf41a9SHans Petter Selasky 				break;
2038d4cf41a9SHans Petter Selasky 		} else {
2039d4cf41a9SHans Petter Selasky 			if (val == URE_PHY_STAT_LAN_ON ||
2040d4cf41a9SHans Petter Selasky 				val == URE_PHY_STAT_PWRDN ||
2041d4cf41a9SHans Petter Selasky 			    val == URE_PHY_STAT_EXT_INIT)
2042d4cf41a9SHans Petter Selasky 				break;
2043d4cf41a9SHans Petter Selasky 		}
2044d4cf41a9SHans Petter Selasky 		uether_pause(&sc->sc_ue, hz / 100);
2045d4cf41a9SHans Petter Selasky 	}
2046d4cf41a9SHans Petter Selasky 	if (i == URE_TIMEOUT)
2047d4cf41a9SHans Petter Selasky 		device_printf(sc->sc_ue.ue_dev,
2048d4cf41a9SHans Petter Selasky 		    "timeout waiting for phy to stabilize\n");
2049d4cf41a9SHans Petter Selasky 
2050d4cf41a9SHans Petter Selasky 	return (val);
2051d4cf41a9SHans Petter Selasky }
2052d4cf41a9SHans Petter Selasky 
2053d4cf41a9SHans Petter Selasky static void
2054d4cf41a9SHans Petter Selasky ure_rtl8152_nic_reset(struct ure_softc *sc)
2055d4cf41a9SHans Petter Selasky {
2056d4cf41a9SHans Petter Selasky 	uint32_t rx_fifo1, rx_fifo2;
2057d4cf41a9SHans Petter Selasky 	int i;
2058d4cf41a9SHans Petter Selasky 
2059d4cf41a9SHans Petter Selasky 	URE_SETBIT_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, URE_RXDY_GATED_EN);
2060d4cf41a9SHans Petter Selasky 
2061d4cf41a9SHans Petter Selasky 	ure_disable_teredo(sc);
2062d4cf41a9SHans Petter Selasky 
2063d4cf41a9SHans Petter Selasky 	DEVPRINTFN(14, sc->sc_ue.ue_dev, "rtl8152_nic_reset: RCR: %#x\n", ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA));
2064d4cf41a9SHans Petter Selasky 	URE_CLRBIT_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, URE_RCR_ACPT_ALL);
2065d4cf41a9SHans Petter Selasky 
2066e1b74f21SKevin Lo 	ure_reset(sc);
2067e1b74f21SKevin Lo 
2068e1b74f21SKevin Lo 	ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, 0);
2069e1b74f21SKevin Lo 
2070d4cf41a9SHans Petter Selasky 	URE_CLRBIT_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, URE_NOW_IS_OOB);
2071e1b74f21SKevin Lo 
2072d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, URE_MCU_BORW_EN);
2073e1b74f21SKevin Lo 	for (i = 0; i < URE_TIMEOUT; i++) {
2074e1b74f21SKevin Lo 		if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
2075e1b74f21SKevin Lo 		    URE_LINK_LIST_READY)
2076e1b74f21SKevin Lo 			break;
2077e1b74f21SKevin Lo 		uether_pause(&sc->sc_ue, hz / 100);
2078e1b74f21SKevin Lo 	}
2079e1b74f21SKevin Lo 	if (i == URE_TIMEOUT)
2080e1b74f21SKevin Lo 		device_printf(sc->sc_ue.ue_dev,
2081e1b74f21SKevin Lo 		    "timeout waiting for OOB control\n");
2082d4cf41a9SHans Petter Selasky 	URE_SETBIT_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, URE_RE_INIT_LL);
2083e1b74f21SKevin Lo 	for (i = 0; i < URE_TIMEOUT; i++) {
2084e1b74f21SKevin Lo 		if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
2085e1b74f21SKevin Lo 		    URE_LINK_LIST_READY)
2086e1b74f21SKevin Lo 			break;
2087e1b74f21SKevin Lo 		uether_pause(&sc->sc_ue, hz / 100);
2088e1b74f21SKevin Lo 	}
2089e1b74f21SKevin Lo 	if (i == URE_TIMEOUT)
2090e1b74f21SKevin Lo 		device_printf(sc->sc_ue.ue_dev,
2091e1b74f21SKevin Lo 		    "timeout waiting for OOB control\n");
2092e1b74f21SKevin Lo 
2093d4cf41a9SHans Petter Selasky 	URE_CLRBIT_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA, URE_CPCR_RX_VLAN);
2094d4cf41a9SHans Petter Selasky 
2095d4cf41a9SHans Petter Selasky 	URE_SETBIT_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA, URE_TCR0_AUTO_FIFO);
2096e1b74f21SKevin Lo 
2097e1b74f21SKevin Lo 	/* Configure Rx FIFO threshold. */
2098e1b74f21SKevin Lo 	ure_write_4(sc, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA,
2099e1b74f21SKevin Lo 	    URE_RXFIFO_THR1_NORMAL);
2100e1b74f21SKevin Lo 	if (usbd_get_speed(sc->sc_ue.ue_udev) == USB_SPEED_FULL) {
2101e1b74f21SKevin Lo 		rx_fifo1 = URE_RXFIFO_THR2_FULL;
2102e1b74f21SKevin Lo 		rx_fifo2 = URE_RXFIFO_THR3_FULL;
2103e1b74f21SKevin Lo 	} else {
2104e1b74f21SKevin Lo 		rx_fifo1 = URE_RXFIFO_THR2_HIGH;
2105e1b74f21SKevin Lo 		rx_fifo2 = URE_RXFIFO_THR3_HIGH;
2106e1b74f21SKevin Lo 	}
2107e1b74f21SKevin Lo 	ure_write_4(sc, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1);
2108e1b74f21SKevin Lo 	ure_write_4(sc, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2);
2109e1b74f21SKevin Lo 
2110e1b74f21SKevin Lo 	/* Configure Tx FIFO threshold. */
2111e1b74f21SKevin Lo 	ure_write_4(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA,
2112e1b74f21SKevin Lo 	    URE_TXFIFO_THR_NORMAL);
2113e1b74f21SKevin Lo }
21147d5522e1SJohn-Mark Gurney 
21157d5522e1SJohn-Mark Gurney /*
21167d5522e1SJohn-Mark Gurney  * Update mbuf for rx checksum from hardware
21177d5522e1SJohn-Mark Gurney  */
21187d5522e1SJohn-Mark Gurney static void
21197d5522e1SJohn-Mark Gurney ure_rxcsum(int capenb, struct ure_rxpkt *rp, struct mbuf *m)
21207d5522e1SJohn-Mark Gurney {
21217d5522e1SJohn-Mark Gurney 	int flags;
21227d5522e1SJohn-Mark Gurney 	uint32_t csum, misc;
21237d5522e1SJohn-Mark Gurney 	int tcp, udp;
21247d5522e1SJohn-Mark Gurney 
21257d5522e1SJohn-Mark Gurney 	m->m_pkthdr.csum_flags = 0;
21267d5522e1SJohn-Mark Gurney 
21277d5522e1SJohn-Mark Gurney 	if (!(capenb & IFCAP_RXCSUM))
21287d5522e1SJohn-Mark Gurney 		return;
21297d5522e1SJohn-Mark Gurney 
21307d5522e1SJohn-Mark Gurney 	csum = le32toh(rp->ure_csum);
21317d5522e1SJohn-Mark Gurney 	misc = le32toh(rp->ure_misc);
21327d5522e1SJohn-Mark Gurney 
21337d5522e1SJohn-Mark Gurney 	tcp = udp = 0;
21347d5522e1SJohn-Mark Gurney 
21357d5522e1SJohn-Mark Gurney 	flags = 0;
21367d5522e1SJohn-Mark Gurney 	if (csum & URE_RXPKT_IPV4_CS)
21377d5522e1SJohn-Mark Gurney 		flags |= CSUM_IP_CHECKED;
21387d5522e1SJohn-Mark Gurney 	else if (csum & URE_RXPKT_IPV6_CS)
21397d5522e1SJohn-Mark Gurney 		flags = 0;
21407d5522e1SJohn-Mark Gurney 
21417d5522e1SJohn-Mark Gurney 	tcp = rp->ure_csum & URE_RXPKT_TCP_CS;
21427d5522e1SJohn-Mark Gurney 	udp = rp->ure_csum & URE_RXPKT_UDP_CS;
21437d5522e1SJohn-Mark Gurney 
21447d5522e1SJohn-Mark Gurney 	if (__predict_true((flags & CSUM_IP_CHECKED) &&
21457d5522e1SJohn-Mark Gurney 	    !(misc & URE_RXPKT_IP_F))) {
21467d5522e1SJohn-Mark Gurney 		flags |= CSUM_IP_VALID;
21477d5522e1SJohn-Mark Gurney 	}
21487d5522e1SJohn-Mark Gurney 	if (__predict_true(
21497d5522e1SJohn-Mark Gurney 	    (tcp && !(misc & URE_RXPKT_TCP_F)) ||
21507d5522e1SJohn-Mark Gurney 	    (udp && !(misc & URE_RXPKT_UDP_F)))) {
21517d5522e1SJohn-Mark Gurney 		flags |= CSUM_DATA_VALID|CSUM_PSEUDO_HDR;
21527d5522e1SJohn-Mark Gurney 		m->m_pkthdr.csum_data = 0xFFFF;
21537d5522e1SJohn-Mark Gurney 	}
21547d5522e1SJohn-Mark Gurney 
21557d5522e1SJohn-Mark Gurney 	m->m_pkthdr.csum_flags = flags;
21567d5522e1SJohn-Mark Gurney }
21577d5522e1SJohn-Mark Gurney 
21587d5522e1SJohn-Mark Gurney /*
21597d5522e1SJohn-Mark Gurney  * If the L4 checksum offset is larger than 0x7ff (2047), return failure.
21607d5522e1SJohn-Mark Gurney  * We currently restrict MTU such that it can't happen, and even if we
21617d5522e1SJohn-Mark Gurney  * did have a large enough MTU, only a very specially crafted IPv6 packet
21627d5522e1SJohn-Mark Gurney  * with MANY headers could possibly come close.
21637d5522e1SJohn-Mark Gurney  *
21647d5522e1SJohn-Mark Gurney  * Returns 0 for success, and 1 if the packet cannot be checksummed and
21657d5522e1SJohn-Mark Gurney  * should be dropped.
21667d5522e1SJohn-Mark Gurney  */
21677d5522e1SJohn-Mark Gurney static int
21687d5522e1SJohn-Mark Gurney ure_txcsum(struct mbuf *m, int caps, uint32_t *regout)
21697d5522e1SJohn-Mark Gurney {
21707d5522e1SJohn-Mark Gurney 	struct ip ip;
21717d5522e1SJohn-Mark Gurney 	struct ether_header *eh;
21727d5522e1SJohn-Mark Gurney 	int flags;
21737d5522e1SJohn-Mark Gurney 	uint32_t data;
21747d5522e1SJohn-Mark Gurney 	uint32_t reg;
21757d5522e1SJohn-Mark Gurney 	int l3off, l4off;
21767d5522e1SJohn-Mark Gurney 	uint16_t type;
21777d5522e1SJohn-Mark Gurney 
21787d5522e1SJohn-Mark Gurney 	*regout = 0;
21797d5522e1SJohn-Mark Gurney 	flags = m->m_pkthdr.csum_flags;
21807d5522e1SJohn-Mark Gurney 	if (flags == 0)
21817d5522e1SJohn-Mark Gurney 		return (0);
21827d5522e1SJohn-Mark Gurney 
21837d5522e1SJohn-Mark Gurney 	if (__predict_true(m->m_len >= (int)sizeof(*eh))) {
21847d5522e1SJohn-Mark Gurney 		eh = mtod(m, struct ether_header *);
21857d5522e1SJohn-Mark Gurney 		type = eh->ether_type;
21867d5522e1SJohn-Mark Gurney 	} else
21877d5522e1SJohn-Mark Gurney 		m_copydata(m, offsetof(struct ether_header, ether_type),
21887d5522e1SJohn-Mark Gurney 		    sizeof(type), (caddr_t)&type);
21897d5522e1SJohn-Mark Gurney 
21907d5522e1SJohn-Mark Gurney 	switch (type = htons(type)) {
21917d5522e1SJohn-Mark Gurney 	case ETHERTYPE_IP:
21927d5522e1SJohn-Mark Gurney 	case ETHERTYPE_IPV6:
21937d5522e1SJohn-Mark Gurney 		l3off = ETHER_HDR_LEN;
21947d5522e1SJohn-Mark Gurney 		break;
21957d5522e1SJohn-Mark Gurney 	case ETHERTYPE_VLAN:
21967d5522e1SJohn-Mark Gurney 		/* XXX - what about QinQ? */
21977d5522e1SJohn-Mark Gurney 		l3off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
21987d5522e1SJohn-Mark Gurney 		break;
21997d5522e1SJohn-Mark Gurney 	default:
22007d5522e1SJohn-Mark Gurney 		return (0);
22017d5522e1SJohn-Mark Gurney 	}
22027d5522e1SJohn-Mark Gurney 
22037d5522e1SJohn-Mark Gurney 	reg = 0;
22047d5522e1SJohn-Mark Gurney 
22057d5522e1SJohn-Mark Gurney 	if (flags & CSUM_IP)
22067d5522e1SJohn-Mark Gurney 		reg |= URE_TXPKT_IPV4_CS;
22077d5522e1SJohn-Mark Gurney 
22087d5522e1SJohn-Mark Gurney 	data = m->m_pkthdr.csum_data;
22097d5522e1SJohn-Mark Gurney 	if (flags & (CSUM_IP_TCP | CSUM_IP_UDP)) {
22107d5522e1SJohn-Mark Gurney 		m_copydata(m, l3off, sizeof ip, (caddr_t)&ip);
22117d5522e1SJohn-Mark Gurney 		l4off = l3off + (ip.ip_hl << 2) + data;
22127d5522e1SJohn-Mark Gurney 		if (__predict_false(l4off > URE_L4_OFFSET_MAX))
22137d5522e1SJohn-Mark Gurney 			return (1);
22147d5522e1SJohn-Mark Gurney 
22157d5522e1SJohn-Mark Gurney 		reg |= URE_TXPKT_IPV4_CS;
22167d5522e1SJohn-Mark Gurney 		if (flags & CSUM_IP_TCP)
22177d5522e1SJohn-Mark Gurney 			reg |= URE_TXPKT_TCP_CS;
22187d5522e1SJohn-Mark Gurney 		else if (flags & CSUM_IP_UDP)
22197d5522e1SJohn-Mark Gurney 			reg |= URE_TXPKT_UDP_CS;
22207d5522e1SJohn-Mark Gurney 		reg |= l4off << URE_L4_OFFSET_SHIFT;
22217d5522e1SJohn-Mark Gurney 	}
22227d5522e1SJohn-Mark Gurney #ifdef INET6
22237d5522e1SJohn-Mark Gurney 	else if (flags & (CSUM_IP6_TCP | CSUM_IP6_UDP)) {
22247d5522e1SJohn-Mark Gurney 		l4off = l3off + data;
22257d5522e1SJohn-Mark Gurney 		if (__predict_false(l4off > URE_L4_OFFSET_MAX))
22267d5522e1SJohn-Mark Gurney 			return (1);
22277d5522e1SJohn-Mark Gurney 
22287d5522e1SJohn-Mark Gurney 		reg |= URE_TXPKT_IPV6_CS;
22297d5522e1SJohn-Mark Gurney 		if (flags & CSUM_IP6_TCP)
22307d5522e1SJohn-Mark Gurney 			reg |= URE_TXPKT_TCP_CS;
22317d5522e1SJohn-Mark Gurney 		else if (flags & CSUM_IP6_UDP)
22327d5522e1SJohn-Mark Gurney 			reg |= URE_TXPKT_UDP_CS;
22337d5522e1SJohn-Mark Gurney 		reg |= l4off << URE_L4_OFFSET_SHIFT;
22347d5522e1SJohn-Mark Gurney 	}
22357d5522e1SJohn-Mark Gurney #endif
22367d5522e1SJohn-Mark Gurney 	*regout = reg;
22377d5522e1SJohn-Mark Gurney 	return 0;
22387d5522e1SJohn-Mark Gurney }
2239