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