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