xref: /openbsd-src/sys/dev/usb/if_ure.c (revision 81508fe356eb7772a68118f65f91723ce5261d7d)
1*81508fe3Sjsg /*	$OpenBSD: if_ure.c,v 1.35 2024/05/23 03:21:09 jsg Exp $	*/
242c54c93Sjmatthew /*-
355929a15Skevlo  * Copyright (c) 2015, 2016, 2019 Kevin Lo <kevlo@openbsd.org>
4fd07ab7eSkevlo  * Copyright (c) 2020 Jonathon Fletcher <jonathon.fletcher@gmail.com>
542c54c93Sjmatthew  * All rights reserved.
642c54c93Sjmatthew  *
742c54c93Sjmatthew  * Redistribution and use in source and binary forms, with or without
842c54c93Sjmatthew  * modification, are permitted provided that the following conditions
942c54c93Sjmatthew  * are met:
1042c54c93Sjmatthew  * 1. Redistributions of source code must retain the above copyright
1142c54c93Sjmatthew  *    notice, this list of conditions and the following disclaimer.
1242c54c93Sjmatthew  * 2. Redistributions in binary form must reproduce the above copyright
1342c54c93Sjmatthew  *    notice, this list of conditions and the following disclaimer in the
1442c54c93Sjmatthew  *    documentation and/or other materials provided with the distribution.
1542c54c93Sjmatthew  *
1642c54c93Sjmatthew  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1742c54c93Sjmatthew  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1842c54c93Sjmatthew  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1942c54c93Sjmatthew  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2042c54c93Sjmatthew  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2142c54c93Sjmatthew  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2242c54c93Sjmatthew  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2342c54c93Sjmatthew  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2442c54c93Sjmatthew  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2542c54c93Sjmatthew  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2642c54c93Sjmatthew  * SUCH DAMAGE.
2742c54c93Sjmatthew  */
2842c54c93Sjmatthew 
2942c54c93Sjmatthew #include "bpfilter.h"
30c096a1a3Skevlo #include "vlan.h"
3142c54c93Sjmatthew 
3242c54c93Sjmatthew #include <sys/param.h>
3342c54c93Sjmatthew #include <sys/systm.h>
3442c54c93Sjmatthew #include <sys/sockio.h>
3542c54c93Sjmatthew #include <sys/rwlock.h>
3642c54c93Sjmatthew #include <sys/mbuf.h>
3742c54c93Sjmatthew #include <sys/device.h>
3842c54c93Sjmatthew 
3942c54c93Sjmatthew #include <machine/bus.h>
4042c54c93Sjmatthew 
4142c54c93Sjmatthew #include <net/if.h>
4242c54c93Sjmatthew #include <net/if_media.h>
4342c54c93Sjmatthew 
4442c54c93Sjmatthew #if NBPFILTER > 0
4542c54c93Sjmatthew #include <net/bpf.h>
4642c54c93Sjmatthew #endif
4742c54c93Sjmatthew 
4842c54c93Sjmatthew #include <netinet/in.h>
4942c54c93Sjmatthew #include <netinet/if_ether.h>
5042c54c93Sjmatthew 
51c096a1a3Skevlo #include <dev/mii/mii.h>
5242c54c93Sjmatthew #include <dev/mii/miivar.h>
5342c54c93Sjmatthew 
5442c54c93Sjmatthew #include <dev/usb/usb.h>
5542c54c93Sjmatthew #include <dev/usb/usbdi.h>
5642c54c93Sjmatthew #include <dev/usb/usbdi_util.h>
5742c54c93Sjmatthew #include <dev/usb/usbdivar.h>
5842c54c93Sjmatthew #include <dev/usb/usbdevs.h>
5942c54c93Sjmatthew 
60794a317fSkettenis #include <dev/ic/rtl81x9reg.h>
61794a317fSkettenis #include <dev/usb/if_urereg.h>
6242c54c93Sjmatthew 
6342c54c93Sjmatthew #ifdef URE_DEBUG
6442c54c93Sjmatthew #define DPRINTF(x)	do { if (uredebug) printf x; } while (0)
6542c54c93Sjmatthew #define DPRINTFN(n,x)	do { if (uredebug >= (n)) printf x; } while (0)
6642c54c93Sjmatthew int	uredebug = 0;
6742c54c93Sjmatthew #else
6842c54c93Sjmatthew #define DPRINTF(x)
6942c54c93Sjmatthew #define DPRINTFN(n,x)
7042c54c93Sjmatthew #endif
7142c54c93Sjmatthew 
7242c54c93Sjmatthew const struct usb_devno ure_devs[] = {
7311bacf69Sjsg 	{ USB_VENDOR_ASUS, USB_PRODUCT_ASUS_RTL8156 },
7411bacf69Sjsg 	{ USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_RTL8152B },
7511bacf69Sjsg 	{ USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_RTL8153 },
7611bacf69Sjsg 	{ USB_VENDOR_CISCOLINKSYS, USB_PRODUCT_CISCOLINKSYS_USB3GIGV1 },
7711bacf69Sjsg 	{ USB_VENDOR_CLEVO, USB_PRODUCT_CLEVO_RTL8153B },
7811bacf69Sjsg 	{ USB_VENDOR_CLUB3D, USB_PRODUCT_CLUB3D_RTL8153 },
7911bacf69Sjsg 	{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_RTL8153_1 },
8011bacf69Sjsg 	{ USB_VENDOR_DLINK, USB_PRODUCT_DLINK_RTL8153_2 },
8111bacf69Sjsg 	{ USB_VENDOR_DYNABOOK, USB_PRODUCT_DYNABOOK_RTL8153B_1 },
8211bacf69Sjsg 	{ USB_VENDOR_DYNABOOK, USB_PRODUCT_DYNABOOK_RTL8153B_2 },
8311bacf69Sjsg 	{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_RTL8153B },
8411bacf69Sjsg 	{ USB_VENDOR_ELECOM, USB_PRODUCT_ELECOM_RTL8156B },
8511bacf69Sjsg 	{ USB_VENDOR_IOI, USB_PRODUCT_IOI_RTL8153 },
860a68adefSjcs 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_DOCK_ETHERNET },
8711bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_ONELINK },
8811bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_ONELINKPLUS },
8911bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_ONELINKPRO },
9011bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_RTL8153B_1 },
9111bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_RTL8153B_2 },
9211bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_RTL8153B_3 },
9311bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_RTL8153B_4 },
9411bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_RTL8153B_5 },
9511bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_RTL8153B_6 },
9611bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_RTL8153B_7 },
9711bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_RTL8153B_8 },
9811bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_RTL8153B_9 },
9911bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_RTL8153_1 },
10011bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_RTL8153_2 },
10111bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_RTL8153_3 },
10211bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_TABLETDOCK },
10311bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_TB3DOCK },
10411bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_TB3DOCKGEN2 },
10511bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_TB3GFXDOCK },
10611bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_USBCDOCKGEN2 },
10711bacf69Sjsg 	{ USB_VENDOR_LENOVO, USB_PRODUCT_LENOVO_WIGIGDOCK },
10811bacf69Sjsg 	{ USB_VENDOR_LG, USB_PRODUCT_LG_RTL8153 },
10911bacf69Sjsg 	{ USB_VENDOR_LG, USB_PRODUCT_LG_RTL8153B },
11011bacf69Sjsg 	{ USB_VENDOR_LUXSHARE, USB_PRODUCT_LUXSHARE_RTL8153 },
11111bacf69Sjsg 	{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_DOCKETH },
11211bacf69Sjsg 	{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_DOCKETH2 },
11311bacf69Sjsg 	{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_SURFETH },
1140e1617aaSpatrick 	{ USB_VENDOR_MICROSOFT, USB_PRODUCT_MICROSOFT_WINDEVETH },
11511bacf69Sjsg 	{ USB_VENDOR_NVIDIA, USB_PRODUCT_NVIDIA_TEGRAETH },
11611bacf69Sjsg 	{ USB_VENDOR_PIONEERDJ, USB_PRODUCT_PIONEERDJ_RTL8152B },
11711bacf69Sjsg 	{ USB_VENDOR_PIONEERDJ, USB_PRODUCT_PIONEERDJ_RTL8153B },
118794a317fSkettenis 	{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8152 },
11911bacf69Sjsg 	{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8152B },
120c096a1a3Skevlo 	{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8153 },
121d19edd3aSkevlo 	{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8156 },
12211bacf69Sjsg 	{ USB_VENDOR_SAMSUNG2, USB_PRODUCT_SAMSUNG2_RTL8153 },
12311bacf69Sjsg 	{ USB_VENDOR_TOSHIBA, USB_PRODUCT_TOSHIBA_RTL8153B },
12411bacf69Sjsg 	{ USB_VENDOR_TPLINK, USB_PRODUCT_TPLINK_EU300 },
12511bacf69Sjsg 	{ USB_VENDOR_TPLINK, USB_PRODUCT_TPLINK_RTL8152B_1 },
12611bacf69Sjsg 	{ USB_VENDOR_TPLINK, USB_PRODUCT_TPLINK_RTL8152B_2 },
12711bacf69Sjsg 	{ USB_VENDOR_TRENDNET, USB_PRODUCT_TRENDNET_RTL8156 },
12811bacf69Sjsg 	{ USB_VENDOR_TTL, USB_PRODUCT_TTL_RTL8153 },
12911bacf69Sjsg 	{ USB_VENDOR_TWINHEAD, USB_PRODUCT_TWINHEAD_RTL8153B },
13011bacf69Sjsg 	{ USB_VENDOR_XIAOMI, USB_PRODUCT_XIAOMI_RTL8152B },
13142c54c93Sjmatthew };
13242c54c93Sjmatthew 
13342c54c93Sjmatthew int	ure_match(struct device *, void *, void *);
13442c54c93Sjmatthew void	ure_attach(struct device *, struct device *, void *);
13542c54c93Sjmatthew int	ure_detach(struct device *, int);
13642c54c93Sjmatthew 
13742c54c93Sjmatthew struct cfdriver ure_cd = {
13842c54c93Sjmatthew 	NULL, "ure", DV_IFNET
13942c54c93Sjmatthew };
14042c54c93Sjmatthew 
14142c54c93Sjmatthew const struct cfattach ure_ca = {
14242c54c93Sjmatthew 	sizeof(struct ure_softc), ure_match, ure_attach, ure_detach
14342c54c93Sjmatthew };
14442c54c93Sjmatthew 
14542c54c93Sjmatthew int		ure_ctl(struct ure_softc *, uint8_t, uint16_t, uint16_t,
14642c54c93Sjmatthew 		    void *, int);
14742c54c93Sjmatthew int		ure_read_mem(struct ure_softc *, uint16_t, uint16_t, void *,
14842c54c93Sjmatthew 		    int);
14942c54c93Sjmatthew int		ure_write_mem(struct ure_softc *, uint16_t, uint16_t, void *,
15042c54c93Sjmatthew 		    int);
15142c54c93Sjmatthew uint8_t		ure_read_1(struct ure_softc *, uint16_t, uint16_t);
15242c54c93Sjmatthew uint16_t	ure_read_2(struct ure_softc *, uint16_t, uint16_t);
15342c54c93Sjmatthew uint32_t	ure_read_4(struct ure_softc *, uint16_t, uint16_t);
15442c54c93Sjmatthew int		ure_write_1(struct ure_softc *, uint16_t, uint16_t, uint32_t);
15542c54c93Sjmatthew int		ure_write_2(struct ure_softc *, uint16_t, uint16_t, uint32_t);
15642c54c93Sjmatthew int		ure_write_4(struct ure_softc *, uint16_t, uint16_t, uint32_t);
15742c54c93Sjmatthew uint16_t	ure_ocp_reg_read(struct ure_softc *, uint16_t);
15842c54c93Sjmatthew void		ure_ocp_reg_write(struct ure_softc *, uint16_t, uint16_t);
15942c54c93Sjmatthew 
16042c54c93Sjmatthew void		ure_init(void *);
16142c54c93Sjmatthew void		ure_stop(struct ure_softc *);
16242c54c93Sjmatthew void		ure_start(struct ifnet *);
16342c54c93Sjmatthew void		ure_reset(struct ure_softc *);
164c096a1a3Skevlo void		ure_watchdog(struct ifnet *);
16542c54c93Sjmatthew 
16642c54c93Sjmatthew void		ure_miibus_statchg(struct device *);
16742c54c93Sjmatthew int		ure_miibus_readreg(struct device *, int, int);
16842c54c93Sjmatthew void		ure_miibus_writereg(struct device *, int, int, int);
16942c54c93Sjmatthew void		ure_lock_mii(struct ure_softc *);
17042c54c93Sjmatthew void		ure_unlock_mii(struct ure_softc *);
17142c54c93Sjmatthew 
172fd07ab7eSkevlo int		ure_encap_txpkt(struct mbuf *, char *, uint32_t);
173fd07ab7eSkevlo int		ure_encap_xfer(struct ifnet *, struct ure_softc *,
174fd07ab7eSkevlo 		    struct ure_chain *);
17542c54c93Sjmatthew void		ure_rxeof(struct usbd_xfer *, void *, usbd_status);
17642c54c93Sjmatthew void		ure_txeof(struct usbd_xfer *, void *, usbd_status);
177fd07ab7eSkevlo int		ure_xfer_list_init(struct ure_softc *, struct ure_chain *,
178fd07ab7eSkevlo 		    uint32_t, int);
179fd07ab7eSkevlo void		ure_xfer_list_free(struct ure_softc *, struct ure_chain *, int);
18042c54c93Sjmatthew 
18142c54c93Sjmatthew void		ure_tick_task(void *);
18242c54c93Sjmatthew void		ure_tick(void *);
18342c54c93Sjmatthew 
184c0ad8833Smglocker void		ure_ifmedia_init(struct ifnet *);
18542c54c93Sjmatthew int		ure_ifmedia_upd(struct ifnet *);
18642c54c93Sjmatthew void		ure_ifmedia_sts(struct ifnet *, struct ifmediareq *);
187c096a1a3Skevlo void		ure_add_media_types(struct ure_softc *);
188c096a1a3Skevlo void		ure_link_state(struct ure_softc *);
189c096a1a3Skevlo int		ure_get_link_status(struct ure_softc *);
19055929a15Skevlo void		ure_iff(struct ure_softc *);
19155929a15Skevlo void		ure_rxvlan(struct ure_softc *);
19242c54c93Sjmatthew int		ure_ioctl(struct ifnet *, u_long, caddr_t);
19342c54c93Sjmatthew void		ure_rtl8152_init(struct ure_softc *);
194794a317fSkettenis void		ure_rtl8153_init(struct ure_softc *);
19555929a15Skevlo void		ure_rtl8153b_init(struct ure_softc *);
19655929a15Skevlo void		ure_rtl8152_nic_reset(struct ure_softc *);
19755929a15Skevlo void		ure_rtl8153_nic_reset(struct ure_softc *);
1988a3a1b1fSkevlo uint16_t	ure_rtl8153_phy_status(struct ure_softc *, int);
1998a3a1b1fSkevlo void		ure_wait_for_flash(struct ure_softc *);
20055929a15Skevlo void		ure_reset_bmu(struct ure_softc *);
20142c54c93Sjmatthew void		ure_disable_teredo(struct ure_softc *);
20242c54c93Sjmatthew 
20355929a15Skevlo #define URE_SETBIT_1(sc, reg, index, x) \
20455929a15Skevlo 	ure_write_1(sc, reg, index, ure_read_1(sc, reg, index) | (x))
20555929a15Skevlo #define URE_SETBIT_2(sc, reg, index, x) \
20655929a15Skevlo 	ure_write_2(sc, reg, index, ure_read_2(sc, reg, index) | (x))
20755929a15Skevlo #define URE_SETBIT_4(sc, reg, index, x) \
20855929a15Skevlo 	ure_write_4(sc, reg, index, ure_read_4(sc, reg, index) | (x))
20942c54c93Sjmatthew 
21055929a15Skevlo #define URE_CLRBIT_1(sc, reg, index, x) \
21155929a15Skevlo 	ure_write_1(sc, reg, index, ure_read_1(sc, reg, index) & ~(x))
21255929a15Skevlo #define URE_CLRBIT_2(sc, reg, index, x) \
21355929a15Skevlo 	ure_write_2(sc, reg, index, ure_read_2(sc, reg, index) & ~(x))
21455929a15Skevlo #define URE_CLRBIT_4(sc, reg, index, x) \
21555929a15Skevlo 	ure_write_4(sc, reg, index, ure_read_4(sc, reg, index) & ~(x))
21642c54c93Sjmatthew 
21742c54c93Sjmatthew int
ure_ctl(struct ure_softc * sc,uint8_t rw,uint16_t val,uint16_t index,void * buf,int len)21842c54c93Sjmatthew ure_ctl(struct ure_softc *sc, uint8_t rw, uint16_t val, uint16_t index,
21942c54c93Sjmatthew     void *buf, int len)
22042c54c93Sjmatthew {
22142c54c93Sjmatthew 	usb_device_request_t	req;
22242c54c93Sjmatthew 	usbd_status		err;
22342c54c93Sjmatthew 
22442c54c93Sjmatthew 	if (usbd_is_dying(sc->ure_udev))
225ca35d093Skevlo 		return 0;
22642c54c93Sjmatthew 
22742c54c93Sjmatthew 	if (rw == URE_CTL_WRITE)
22842c54c93Sjmatthew 		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
22942c54c93Sjmatthew 	else
23042c54c93Sjmatthew 		req.bmRequestType = UT_READ_VENDOR_DEVICE;
23142c54c93Sjmatthew 	req.bRequest = UR_SET_ADDRESS;
23242c54c93Sjmatthew 	USETW(req.wValue, val);
23342c54c93Sjmatthew 	USETW(req.wIndex, index);
23442c54c93Sjmatthew 	USETW(req.wLength, len);
23542c54c93Sjmatthew 
23642c54c93Sjmatthew 	DPRINTFN(5, ("ure_ctl: rw %d, val 0x%04hu, index 0x%04hu, len %d\n",
23742c54c93Sjmatthew 	    rw, val, index, len));
23842c54c93Sjmatthew 	err = usbd_do_request(sc->ure_udev, &req, buf);
23942c54c93Sjmatthew 	if (err) {
24042c54c93Sjmatthew 		DPRINTF(("ure_ctl: error %d\n", err));
24142c54c93Sjmatthew 		return -1;
24242c54c93Sjmatthew 	}
24342c54c93Sjmatthew 
24442c54c93Sjmatthew 	return 0;
24542c54c93Sjmatthew }
24642c54c93Sjmatthew 
24742c54c93Sjmatthew int
ure_read_mem(struct ure_softc * sc,uint16_t addr,uint16_t index,void * buf,int len)24842c54c93Sjmatthew ure_read_mem(struct ure_softc *sc, uint16_t addr, uint16_t index,
24942c54c93Sjmatthew     void *buf, int len)
25042c54c93Sjmatthew {
25142c54c93Sjmatthew 	return (ure_ctl(sc, URE_CTL_READ, addr, index, buf, len));
25242c54c93Sjmatthew }
25342c54c93Sjmatthew 
25442c54c93Sjmatthew int
ure_write_mem(struct ure_softc * sc,uint16_t addr,uint16_t index,void * buf,int len)25542c54c93Sjmatthew ure_write_mem(struct ure_softc *sc, uint16_t addr, uint16_t index,
25642c54c93Sjmatthew     void *buf, int len)
25742c54c93Sjmatthew {
25842c54c93Sjmatthew 	return (ure_ctl(sc, URE_CTL_WRITE, addr, index, buf, len));
25942c54c93Sjmatthew }
26042c54c93Sjmatthew 
26142c54c93Sjmatthew uint8_t
ure_read_1(struct ure_softc * sc,uint16_t reg,uint16_t index)26242c54c93Sjmatthew ure_read_1(struct ure_softc *sc, uint16_t reg, uint16_t index)
26342c54c93Sjmatthew {
26442c54c93Sjmatthew 	uint32_t	val;
26542c54c93Sjmatthew 	uint8_t		temp[4];
26642c54c93Sjmatthew 	uint8_t		shift;
26742c54c93Sjmatthew 
26842c54c93Sjmatthew 	shift = (reg & 3) << 3;
26942c54c93Sjmatthew 	reg &= ~3;
27042c54c93Sjmatthew 
27142c54c93Sjmatthew 	ure_read_mem(sc, reg, index, &temp, 4);
27242c54c93Sjmatthew 	val = UGETDW(temp);
27342c54c93Sjmatthew 	val >>= shift;
27442c54c93Sjmatthew 
27542c54c93Sjmatthew 	return (val & 0xff);
27642c54c93Sjmatthew }
27742c54c93Sjmatthew 
27842c54c93Sjmatthew uint16_t
ure_read_2(struct ure_softc * sc,uint16_t reg,uint16_t index)27942c54c93Sjmatthew ure_read_2(struct ure_softc *sc, uint16_t reg, uint16_t index)
28042c54c93Sjmatthew {
28142c54c93Sjmatthew 	uint32_t	val;
28242c54c93Sjmatthew 	uint8_t		temp[4];
28342c54c93Sjmatthew 	uint8_t		shift;
28442c54c93Sjmatthew 
28542c54c93Sjmatthew 	shift = (reg & 2) << 3;
28642c54c93Sjmatthew 	reg &= ~3;
28742c54c93Sjmatthew 
28842c54c93Sjmatthew 	ure_read_mem(sc, reg, index, &temp, 4);
28942c54c93Sjmatthew 	val = UGETDW(temp);
29042c54c93Sjmatthew 	val >>= shift;
29142c54c93Sjmatthew 
29242c54c93Sjmatthew 	return (val & 0xffff);
29342c54c93Sjmatthew }
29442c54c93Sjmatthew 
29542c54c93Sjmatthew uint32_t
ure_read_4(struct ure_softc * sc,uint16_t reg,uint16_t index)29642c54c93Sjmatthew ure_read_4(struct ure_softc *sc, uint16_t reg, uint16_t index)
29742c54c93Sjmatthew {
29842c54c93Sjmatthew 	uint8_t	temp[4];
29942c54c93Sjmatthew 
30042c54c93Sjmatthew 	ure_read_mem(sc, reg, index, &temp, 4);
30142c54c93Sjmatthew 	return (UGETDW(temp));
30242c54c93Sjmatthew }
30342c54c93Sjmatthew 
30442c54c93Sjmatthew int
ure_write_1(struct ure_softc * sc,uint16_t reg,uint16_t index,uint32_t val)30542c54c93Sjmatthew ure_write_1(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val)
30642c54c93Sjmatthew {
30742c54c93Sjmatthew 	uint16_t	byen;
30842c54c93Sjmatthew 	uint8_t		temp[4];
30942c54c93Sjmatthew 	uint8_t		shift;
31042c54c93Sjmatthew 
31142c54c93Sjmatthew 	byen = URE_BYTE_EN_BYTE;
31242c54c93Sjmatthew 	shift = reg & 3;
31342c54c93Sjmatthew 	val &= 0xff;
31442c54c93Sjmatthew 
31542c54c93Sjmatthew 	if (reg & 3) {
31642c54c93Sjmatthew 		byen <<= shift;
31742c54c93Sjmatthew 		val <<= (shift << 3);
31842c54c93Sjmatthew 		reg &= ~3;
31942c54c93Sjmatthew 	}
32042c54c93Sjmatthew 
32142c54c93Sjmatthew 	USETDW(temp, val);
32242c54c93Sjmatthew 	return (ure_write_mem(sc, reg, index | byen, &temp, 4));
32342c54c93Sjmatthew }
32442c54c93Sjmatthew 
32542c54c93Sjmatthew int
ure_write_2(struct ure_softc * sc,uint16_t reg,uint16_t index,uint32_t val)32642c54c93Sjmatthew ure_write_2(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val)
32742c54c93Sjmatthew {
32842c54c93Sjmatthew 	uint16_t	byen;
32942c54c93Sjmatthew 	uint8_t		temp[4];
33042c54c93Sjmatthew 	uint8_t		shift;
33142c54c93Sjmatthew 
33242c54c93Sjmatthew 	byen = URE_BYTE_EN_WORD;
33342c54c93Sjmatthew 	shift = reg & 2;
33442c54c93Sjmatthew 	val &= 0xffff;
33542c54c93Sjmatthew 
33642c54c93Sjmatthew 	if (reg & 2) {
33742c54c93Sjmatthew 		byen <<= shift;
33842c54c93Sjmatthew 		val <<= (shift << 3);
33942c54c93Sjmatthew 		reg &= ~3;
34042c54c93Sjmatthew 	}
34142c54c93Sjmatthew 
34242c54c93Sjmatthew 	USETDW(temp, val);
34342c54c93Sjmatthew 	return (ure_write_mem(sc, reg, index | byen, &temp, 4));
34442c54c93Sjmatthew }
34542c54c93Sjmatthew 
34642c54c93Sjmatthew int
ure_write_4(struct ure_softc * sc,uint16_t reg,uint16_t index,uint32_t val)34742c54c93Sjmatthew ure_write_4(struct ure_softc *sc, uint16_t reg, uint16_t index, uint32_t val)
34842c54c93Sjmatthew {
34942c54c93Sjmatthew 	uint8_t	temp[4];
35042c54c93Sjmatthew 
35142c54c93Sjmatthew 	USETDW(temp, val);
35242c54c93Sjmatthew 	return (ure_write_mem(sc, reg, index | URE_BYTE_EN_DWORD, &temp, 4));
35342c54c93Sjmatthew }
35442c54c93Sjmatthew 
35542c54c93Sjmatthew uint16_t
ure_ocp_reg_read(struct ure_softc * sc,uint16_t addr)35642c54c93Sjmatthew ure_ocp_reg_read(struct ure_softc *sc, uint16_t addr)
35742c54c93Sjmatthew {
35842c54c93Sjmatthew 	uint16_t	reg;
35942c54c93Sjmatthew 
36042c54c93Sjmatthew 	ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000);
36142c54c93Sjmatthew 	reg = (addr & 0x0fff) | 0xb000;
36242c54c93Sjmatthew 
36342c54c93Sjmatthew 	return (ure_read_2(sc, reg, URE_MCU_TYPE_PLA));
36442c54c93Sjmatthew }
36542c54c93Sjmatthew 
36642c54c93Sjmatthew void
ure_ocp_reg_write(struct ure_softc * sc,uint16_t addr,uint16_t data)36742c54c93Sjmatthew ure_ocp_reg_write(struct ure_softc *sc, uint16_t addr, uint16_t data)
36842c54c93Sjmatthew {
36942c54c93Sjmatthew 	uint16_t	reg;
37042c54c93Sjmatthew 
37142c54c93Sjmatthew 	ure_write_2(sc, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000);
37242c54c93Sjmatthew 	reg = (addr & 0x0fff) | 0xb000;
37342c54c93Sjmatthew 
37442c54c93Sjmatthew 	ure_write_2(sc, reg, URE_MCU_TYPE_PLA, data);
37542c54c93Sjmatthew }
37642c54c93Sjmatthew 
37742c54c93Sjmatthew int
ure_miibus_readreg(struct device * dev,int phy,int reg)37842c54c93Sjmatthew ure_miibus_readreg(struct device *dev, int phy, int reg)
37942c54c93Sjmatthew {
38042c54c93Sjmatthew 	struct ure_softc	*sc = (void *)dev;
38142c54c93Sjmatthew 	uint16_t		val;
38242c54c93Sjmatthew 
38342c54c93Sjmatthew 	if (usbd_is_dying(sc->ure_udev))
38442c54c93Sjmatthew 		return 0;
38542c54c93Sjmatthew 
386794a317fSkettenis 	/* Let the rgephy driver read the URE_PLA_PHYSTATUS register. */
387794a317fSkettenis 	if (reg == RL_GMEDIASTAT)
388794a317fSkettenis 		return ure_read_1(sc, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA);
389794a317fSkettenis 
39042c54c93Sjmatthew 	ure_lock_mii(sc);
39142c54c93Sjmatthew 	val = ure_ocp_reg_read(sc, URE_OCP_BASE_MII + reg * 2);
39242c54c93Sjmatthew 	ure_unlock_mii(sc);
39342c54c93Sjmatthew 
39442c54c93Sjmatthew 	return val;	/* letoh16? */
39542c54c93Sjmatthew }
39642c54c93Sjmatthew 
39742c54c93Sjmatthew void
ure_miibus_writereg(struct device * dev,int phy,int reg,int val)39842c54c93Sjmatthew ure_miibus_writereg(struct device *dev, int phy, int reg, int val)
39942c54c93Sjmatthew {
40042c54c93Sjmatthew 	struct ure_softc	*sc = (void *)dev;
40142c54c93Sjmatthew 
40242c54c93Sjmatthew 	ure_lock_mii(sc);
40342c54c93Sjmatthew 	ure_ocp_reg_write(sc, URE_OCP_BASE_MII + reg * 2, val);	/* htole16? */
40442c54c93Sjmatthew 	ure_unlock_mii(sc);
40542c54c93Sjmatthew }
40642c54c93Sjmatthew 
40742c54c93Sjmatthew void
ure_miibus_statchg(struct device * dev)40842c54c93Sjmatthew ure_miibus_statchg(struct device *dev)
40942c54c93Sjmatthew {
41042c54c93Sjmatthew 	struct ure_softc	*sc = (void *)dev;
41142c54c93Sjmatthew 	struct mii_data		*mii = &sc->ure_mii;
41242c54c93Sjmatthew 	struct ifnet		*ifp = &sc->ure_ac.ac_if;
41342c54c93Sjmatthew 
41442c54c93Sjmatthew 	if ((ifp->if_flags & IFF_RUNNING) == 0)
41542c54c93Sjmatthew 		return;
41642c54c93Sjmatthew 
41742c54c93Sjmatthew 	sc->ure_flags &= ~URE_FLAG_LINK;
41842c54c93Sjmatthew 	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
41942c54c93Sjmatthew 	    (IFM_ACTIVE | IFM_AVALID)) {
42042c54c93Sjmatthew 		switch (IFM_SUBTYPE(mii->mii_media_active)) {
42142c54c93Sjmatthew 		case IFM_10_T:
42242c54c93Sjmatthew 		case IFM_100_TX:
42342c54c93Sjmatthew 			sc->ure_flags |= URE_FLAG_LINK;
42442c54c93Sjmatthew 			break;
425794a317fSkettenis 		case IFM_1000_T:
426794a317fSkettenis 			if ((sc->ure_flags & URE_FLAG_8152) != 0)
427794a317fSkettenis 				break;
428794a317fSkettenis 			sc->ure_flags |= URE_FLAG_LINK;
429794a317fSkettenis 			break;
43042c54c93Sjmatthew 		default:
43142c54c93Sjmatthew 			break;
43242c54c93Sjmatthew 		}
43342c54c93Sjmatthew 	}
43455929a15Skevlo 
43555929a15Skevlo 	/* Lost link, do nothing. */
43655929a15Skevlo 	if ((sc->ure_flags & URE_FLAG_LINK) == 0)
43755929a15Skevlo 		return;
438c0ad8833Smglocker 
439c0ad8833Smglocker 	/*
440c0ad8833Smglocker 	 * After a link change the media settings are getting reset on the
441c0ad8833Smglocker 	 * hardware, and need to be re-initialized again for communication
442c0ad8833Smglocker 	 * to continue work.
443c0ad8833Smglocker 	 */
444c0ad8833Smglocker 	ure_ifmedia_init(ifp);
445c0ad8833Smglocker }
446c0ad8833Smglocker 
447c0ad8833Smglocker void
ure_ifmedia_init(struct ifnet * ifp)448c0ad8833Smglocker ure_ifmedia_init(struct ifnet *ifp)
449c0ad8833Smglocker {
450c0ad8833Smglocker 	struct ure_softc *sc = ifp->if_softc;
451c0ad8833Smglocker 	uint32_t reg = 0;
452c0ad8833Smglocker 
453c0ad8833Smglocker 	/* Set MAC address. */
454c0ad8833Smglocker 	ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG);
455c0ad8833Smglocker 	ure_write_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES,
456c0ad8833Smglocker 	    sc->ure_ac.ac_enaddr, 8);
457c0ad8833Smglocker 	ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML);
458c0ad8833Smglocker 
459c0ad8833Smglocker 	if (!(sc->ure_flags & URE_FLAG_8152)) {
4608a3a1b1fSkevlo 		if (sc->ure_flags & URE_FLAG_8156B)
4618a3a1b1fSkevlo 			URE_CLRBIT_2(sc, URE_USB_RX_AGGR_NUM, URE_MCU_TYPE_USB,
4628a3a1b1fSkevlo 			    URE_RX_AGGR_NUM_MASK);
4638a3a1b1fSkevlo 
464c0ad8833Smglocker 		reg = sc->ure_rxbufsz - URE_FRAMELEN(ifp->if_mtu) -
465c0ad8833Smglocker 		    sizeof(struct ure_rxpkt) - URE_RX_BUF_ALIGN;
4663dd6ed5fSkevlo 		if (sc->ure_flags &
4673dd6ed5fSkevlo 		    (URE_FLAG_8153B | URE_FLAG_8156 | URE_FLAG_8156B)) {
468c0ad8833Smglocker 			ure_write_2(sc, URE_USB_RX_EARLY_SIZE, URE_MCU_TYPE_USB,
469c0ad8833Smglocker 			    reg / 8);
470c0ad8833Smglocker 
471c0ad8833Smglocker 			ure_write_2(sc, URE_USB_RX_EARLY_AGG, URE_MCU_TYPE_USB,
4728a3a1b1fSkevlo 			    (sc->ure_flags & URE_FLAG_8153B) ? 158 : 80);
473c0ad8833Smglocker 			ure_write_2(sc, URE_USB_PM_CTRL_STATUS,
474c0ad8833Smglocker 			    URE_MCU_TYPE_USB, 1875);
475c0ad8833Smglocker 		} else {
476c0ad8833Smglocker 			ure_write_2(sc, URE_USB_RX_EARLY_SIZE, URE_MCU_TYPE_USB,
477c0ad8833Smglocker 			    reg / 4);
478c0ad8833Smglocker 			switch (sc->ure_udev->speed) {
479c0ad8833Smglocker 			case USB_SPEED_SUPER:
480c0ad8833Smglocker 				reg = URE_COALESCE_SUPER / 8;
481c0ad8833Smglocker 				break;
482c0ad8833Smglocker 			case USB_SPEED_HIGH:
483c0ad8833Smglocker 				reg = URE_COALESCE_HIGH / 8;
484c0ad8833Smglocker 				break;
485c0ad8833Smglocker 			default:
486c0ad8833Smglocker 				reg = URE_COALESCE_SLOW / 8;
487c0ad8833Smglocker 				break;
488c0ad8833Smglocker 			}
489c0ad8833Smglocker 			ure_write_2(sc, URE_USB_RX_EARLY_AGG, URE_MCU_TYPE_USB,
490c0ad8833Smglocker 			    reg);
491c0ad8833Smglocker 		}
4928a3a1b1fSkevlo 
4933dd6ed5fSkevlo 		if (sc->ure_chip & URE_CHIP_VER_7420) {
4943dd6ed5fSkevlo 			URE_SETBIT_2(sc, URE_PLA_MAC_PWR_CTRL4,
4953dd6ed5fSkevlo 			    URE_MCU_TYPE_PLA, URE_IDLE_SPDWN_EN);
4963dd6ed5fSkevlo 		}
4973dd6ed5fSkevlo 
4988a3a1b1fSkevlo 		if ((sc->ure_chip & URE_CHIP_VER_6010) ||
4998a3a1b1fSkevlo 		    (sc->ure_flags & URE_FLAG_8156B)) {
5008a3a1b1fSkevlo 			URE_CLRBIT_2(sc, URE_USB_FW_TASK, URE_MCU_TYPE_USB,
5018a3a1b1fSkevlo 			    URE_FC_PATCH_TASK);
5028a3a1b1fSkevlo 			usbd_delay_ms(sc->ure_udev, 1);
5038a3a1b1fSkevlo 			URE_SETBIT_2(sc, URE_USB_FW_TASK, URE_MCU_TYPE_USB,
5048a3a1b1fSkevlo 			    URE_FC_PATCH_TASK);
5058a3a1b1fSkevlo 		}
506c0ad8833Smglocker 	}
507c0ad8833Smglocker 
508c0ad8833Smglocker 	/* Reset the packet filter. */
509c0ad8833Smglocker 	URE_CLRBIT_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA, URE_FMC_FCR_MCU_EN);
510c0ad8833Smglocker 	URE_SETBIT_2(sc, URE_PLA_FMC, URE_MCU_TYPE_PLA, URE_FMC_FCR_MCU_EN);
511c0ad8833Smglocker 
512c0ad8833Smglocker 	/* Enable transmit and receive. */
513c0ad8833Smglocker 	URE_SETBIT_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RE | URE_CR_TE);
514c0ad8833Smglocker 
5158a3a1b1fSkevlo 	if (sc->ure_flags & (URE_FLAG_8153B | URE_FLAG_8156 | URE_FLAG_8156B)) {
516c0ad8833Smglocker 		ure_write_1(sc, URE_USB_UPT_RXDMA_OWN, URE_MCU_TYPE_USB,
517c0ad8833Smglocker 		    URE_OWN_UPDATE | URE_OWN_CLEAR);
518c0ad8833Smglocker 	}
519c0ad8833Smglocker 
520c0ad8833Smglocker 	URE_CLRBIT_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, URE_RXDY_GATED_EN);
52142c54c93Sjmatthew }
52242c54c93Sjmatthew 
52342c54c93Sjmatthew int
ure_ifmedia_upd(struct ifnet * ifp)52442c54c93Sjmatthew ure_ifmedia_upd(struct ifnet *ifp)
52542c54c93Sjmatthew {
52642c54c93Sjmatthew 	struct ure_softc	*sc = ifp->if_softc;
52742c54c93Sjmatthew 	struct mii_data		*mii = &sc->ure_mii;
528c096a1a3Skevlo 	struct ifmedia		*ifm = &sc->ure_ifmedia;
529c096a1a3Skevlo 	int			anar, gig, err, reg;
530c096a1a3Skevlo 
5318a3a1b1fSkevlo 	if (sc->ure_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
532c096a1a3Skevlo 		if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER)
533c096a1a3Skevlo 			return (EINVAL);
534c096a1a3Skevlo 
5353dd6ed5fSkevlo 		if (!(sc->ure_chip & URE_CHIP_VER_7420)) {
5363dd6ed5fSkevlo 			reg = ure_ocp_reg_read(sc, URE_OCP_10GBT_CTRL);
537c096a1a3Skevlo 			reg &= ~URE_ADV_2500TFDX;
5383dd6ed5fSkevlo 		}
539c096a1a3Skevlo 
540c096a1a3Skevlo 		anar = gig = 0;
541c096a1a3Skevlo 		switch (IFM_SUBTYPE(ifm->ifm_media)) {
542c096a1a3Skevlo 		case IFM_AUTO:
543c096a1a3Skevlo 			anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
544c096a1a3Skevlo 			gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
5453dd6ed5fSkevlo 			if (!(sc->ure_chip & URE_CHIP_VER_7420))
546c096a1a3Skevlo 				reg |= URE_ADV_2500TFDX;
547c096a1a3Skevlo 			break;
548c096a1a3Skevlo 		case IFM_2500_T:
549c096a1a3Skevlo 			anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
550c096a1a3Skevlo 			gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
551c096a1a3Skevlo 			reg |= URE_ADV_2500TFDX;
552c096a1a3Skevlo 			ifp->if_baudrate = IF_Mbps(2500);
553c096a1a3Skevlo 			break;
554c096a1a3Skevlo 		case IFM_1000_T:
555c096a1a3Skevlo 			anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
556c096a1a3Skevlo 			gig |= GTCR_ADV_1000TFDX | GTCR_ADV_1000THDX;
557c096a1a3Skevlo 			ifp->if_baudrate = IF_Gbps(1);
558c096a1a3Skevlo 			break;
559c096a1a3Skevlo 		case IFM_100_TX:
560c096a1a3Skevlo 			anar |= ANAR_TX | ANAR_TX_FD;
561c096a1a3Skevlo 			ifp->if_baudrate = IF_Mbps(100);
562c096a1a3Skevlo 			break;
563c096a1a3Skevlo 		case IFM_10_T:
564c096a1a3Skevlo 			anar |= ANAR_10 | ANAR_10_FD;
565c096a1a3Skevlo 			ifp->if_baudrate = IF_Mbps(10);
566c096a1a3Skevlo 			break;
567c096a1a3Skevlo 		default:
568c096a1a3Skevlo 			printf("%s: unsupported media type\n",
569c096a1a3Skevlo 			    sc->ure_dev.dv_xname);
570c096a1a3Skevlo 			return (EINVAL);
571c096a1a3Skevlo 		}
572c096a1a3Skevlo 
573c096a1a3Skevlo 		ure_ocp_reg_write(sc, URE_OCP_BASE_MII + MII_ANAR * 2,
574c096a1a3Skevlo 		    anar | ANAR_PAUSE_ASYM | ANAR_FC);
575c096a1a3Skevlo 		ure_ocp_reg_write(sc, URE_OCP_BASE_MII + MII_100T2CR * 2, gig);
5763dd6ed5fSkevlo 		if (!(sc->ure_chip & URE_CHIP_VER_7420))
5773dd6ed5fSkevlo 			ure_ocp_reg_write(sc, URE_OCP_10GBT_CTRL, reg);
578c096a1a3Skevlo 		ure_ocp_reg_write(sc, URE_OCP_BASE_MII + MII_BMCR,
579c096a1a3Skevlo 		    BMCR_AUTOEN | BMCR_STARTNEG);
580c096a1a3Skevlo 
581c096a1a3Skevlo 		return (0);
582c096a1a3Skevlo 	}
58342c54c93Sjmatthew 
58442c54c93Sjmatthew 	if (mii->mii_instance) {
58542c54c93Sjmatthew 		struct mii_softc *miisc;
58642c54c93Sjmatthew 		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
58742c54c93Sjmatthew 			PHY_RESET(miisc);
58842c54c93Sjmatthew 	}
58942c54c93Sjmatthew 
59042c54c93Sjmatthew 	err = mii_mediachg(mii);
59142c54c93Sjmatthew 	if (err == ENXIO)
59255929a15Skevlo 		return (0);
59342c54c93Sjmatthew 	else
59455929a15Skevlo 		return (err);
59542c54c93Sjmatthew }
59642c54c93Sjmatthew 
59742c54c93Sjmatthew void
ure_ifmedia_sts(struct ifnet * ifp,struct ifmediareq * ifmr)59842c54c93Sjmatthew ure_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
59942c54c93Sjmatthew {
60042c54c93Sjmatthew 	struct ure_softc	*sc = ifp->if_softc;
60142c54c93Sjmatthew 	struct mii_data		*mii = &sc->ure_mii;
602c096a1a3Skevlo 	uint16_t		status = 0;
603c096a1a3Skevlo 
6048a3a1b1fSkevlo 	if (sc->ure_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
605c096a1a3Skevlo 		ifmr->ifm_status = IFM_AVALID;
606c096a1a3Skevlo 		if (ure_get_link_status(sc)) {
607c096a1a3Skevlo 			ifmr->ifm_status |= IFM_ACTIVE;
608c096a1a3Skevlo 			status = ure_read_2(sc, URE_PLA_PHYSTATUS,
609c096a1a3Skevlo 			    URE_MCU_TYPE_PLA);
610c096a1a3Skevlo 			if ((status & URE_PHYSTATUS_FDX) ||
611c096a1a3Skevlo 			    (status & URE_PHYSTATUS_2500MBPS))
612c096a1a3Skevlo 				ifmr->ifm_active |= IFM_FDX;
613c096a1a3Skevlo 			else
614c096a1a3Skevlo 				ifmr->ifm_active |= IFM_HDX;
615c096a1a3Skevlo 			if (status & URE_PHYSTATUS_10MBPS)
616c096a1a3Skevlo 				ifmr->ifm_active |= IFM_10_T;
617c096a1a3Skevlo 			else if (status & URE_PHYSTATUS_100MBPS)
618c096a1a3Skevlo 				ifmr->ifm_active |= IFM_100_TX;
619c096a1a3Skevlo 			else if (status & URE_PHYSTATUS_1000MBPS)
620c096a1a3Skevlo 				ifmr->ifm_active |= IFM_1000_T;
621c096a1a3Skevlo 			else if (status & URE_PHYSTATUS_2500MBPS)
622c096a1a3Skevlo 				ifmr->ifm_active |= IFM_2500_T;
623c096a1a3Skevlo 		}
624c096a1a3Skevlo 		return;
625c096a1a3Skevlo 	}
62642c54c93Sjmatthew 
62742c54c93Sjmatthew 	mii_pollstat(mii);
62842c54c93Sjmatthew 	ifmr->ifm_active = mii->mii_media_active;
62942c54c93Sjmatthew 	ifmr->ifm_status = mii->mii_media_status;
63042c54c93Sjmatthew }
63142c54c93Sjmatthew 
63242c54c93Sjmatthew void
ure_add_media_types(struct ure_softc * sc)633c096a1a3Skevlo ure_add_media_types(struct ure_softc *sc)
634c096a1a3Skevlo {
635c096a1a3Skevlo 	ifmedia_add(&sc->ure_ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
636c096a1a3Skevlo 	ifmedia_add(&sc->ure_ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
637c096a1a3Skevlo 	ifmedia_add(&sc->ure_ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL);
638c096a1a3Skevlo 	ifmedia_add(&sc->ure_ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX, 0,
639c096a1a3Skevlo 	    NULL);
640c096a1a3Skevlo 	ifmedia_add(&sc->ure_ifmedia, IFM_ETHER | IFM_1000_T, 0, NULL);
641c096a1a3Skevlo 	ifmedia_add(&sc->ure_ifmedia, IFM_ETHER | IFM_1000_T | IFM_FDX, 0,
642c096a1a3Skevlo 	    NULL);
6433dd6ed5fSkevlo 	if (!(sc->ure_chip & URE_CHIP_VER_7420)) {
644c096a1a3Skevlo 		ifmedia_add(&sc->ure_ifmedia, IFM_ETHER | IFM_2500_T, 0, NULL);
6453dd6ed5fSkevlo 		ifmedia_add(&sc->ure_ifmedia, IFM_ETHER | IFM_2500_T | IFM_FDX,
6463dd6ed5fSkevlo 		    0, NULL);
6473dd6ed5fSkevlo 	}
648c096a1a3Skevlo }
649c096a1a3Skevlo 
650c096a1a3Skevlo void
ure_link_state(struct ure_softc * sc)651c096a1a3Skevlo ure_link_state(struct ure_softc *sc)
652c096a1a3Skevlo {
653c096a1a3Skevlo 	struct ifnet	*ifp = &sc->ure_ac.ac_if;
654c096a1a3Skevlo 	int		link = LINK_STATE_DOWN;
655c096a1a3Skevlo 
656c096a1a3Skevlo 	if (ure_get_link_status(sc))
657c096a1a3Skevlo 		link = LINK_STATE_UP;
658c096a1a3Skevlo 
659c096a1a3Skevlo 	if (ifp->if_link_state != link) {
660c096a1a3Skevlo 		ifp->if_link_state = link;
661c096a1a3Skevlo 		if_link_state_change(ifp);
662c096a1a3Skevlo 	}
663c096a1a3Skevlo }
664c096a1a3Skevlo 
665c096a1a3Skevlo int
ure_get_link_status(struct ure_softc * sc)666c096a1a3Skevlo ure_get_link_status(struct ure_softc *sc)
667c096a1a3Skevlo {
668c096a1a3Skevlo 	if (ure_read_2(sc, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA) &
669c096a1a3Skevlo 	    URE_PHYSTATUS_LINK) {
670c096a1a3Skevlo 		sc->ure_flags |= URE_FLAG_LINK;
671c096a1a3Skevlo 		return (1);
672c096a1a3Skevlo 	} else {
673c096a1a3Skevlo 		sc->ure_flags &= ~URE_FLAG_LINK;
674c096a1a3Skevlo 		return (0);
675c096a1a3Skevlo 	}
676c096a1a3Skevlo }
677c096a1a3Skevlo 
678c096a1a3Skevlo void
ure_iff(struct ure_softc * sc)67942c54c93Sjmatthew ure_iff(struct ure_softc *sc)
68042c54c93Sjmatthew {
68142c54c93Sjmatthew 	struct ifnet		*ifp = &sc->ure_ac.ac_if;
68242c54c93Sjmatthew 	struct ether_multi	*enm;
68342c54c93Sjmatthew 	struct ether_multistep	step;
68442c54c93Sjmatthew 	uint32_t		hashes[2] = { 0, 0 };
68542c54c93Sjmatthew 	uint32_t		hash;
68642c54c93Sjmatthew 	uint32_t		rxmode;
68742c54c93Sjmatthew 
68842c54c93Sjmatthew 	if (usbd_is_dying(sc->ure_udev))
68942c54c93Sjmatthew 		return;
69042c54c93Sjmatthew 
69170646515Sjmatthew 	rxmode = ure_read_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA);
69270646515Sjmatthew 	rxmode &= ~URE_RCR_ACPT_ALL;
69342c54c93Sjmatthew 	ifp->if_flags &= ~IFF_ALLMULTI;
69470646515Sjmatthew 
69570646515Sjmatthew 	/*
69670646515Sjmatthew 	 * Always accept frames destined to our station address.
69770646515Sjmatthew 	 * Always accept broadcast frames.
69870646515Sjmatthew 	 */
69970646515Sjmatthew 	rxmode |= URE_RCR_APM | URE_RCR_AB;
70070646515Sjmatthew 
70142c54c93Sjmatthew 	if (ifp->if_flags & IFF_PROMISC || sc->ure_ac.ac_multirangecnt > 0) {
70242c54c93Sjmatthew 		ifp->if_flags |= IFF_ALLMULTI;
70370646515Sjmatthew 		rxmode |= URE_RCR_AM;
70442c54c93Sjmatthew 		if (ifp->if_flags & IFF_PROMISC)
70542c54c93Sjmatthew 			rxmode |= URE_RCR_AAP;
70642c54c93Sjmatthew 		hashes[0] = hashes[1] = 0xffffffff;
70742c54c93Sjmatthew 	} else {
70870646515Sjmatthew 		rxmode |= URE_RCR_AM;
70970646515Sjmatthew 
71042c54c93Sjmatthew 		ETHER_FIRST_MULTI(step, &sc->ure_ac, enm);
71142c54c93Sjmatthew 		while (enm != NULL) {
71242c54c93Sjmatthew 			hash = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN)
71342c54c93Sjmatthew 			    >> 26;
71442c54c93Sjmatthew 			if (hash < 32)
71542c54c93Sjmatthew 				hashes[0] |= (1 << hash);
71642c54c93Sjmatthew 			else
71742c54c93Sjmatthew 				hashes[1] |= (1 << (hash - 32));
71842c54c93Sjmatthew 
71942c54c93Sjmatthew 			ETHER_NEXT_MULTI(step, enm);
72042c54c93Sjmatthew 		}
72142c54c93Sjmatthew 
72242c54c93Sjmatthew 		hash = swap32(hashes[0]);
72342c54c93Sjmatthew 		hashes[0] = swap32(hashes[1]);
72442c54c93Sjmatthew 		hashes[1] = hash;
72542c54c93Sjmatthew 	}
72642c54c93Sjmatthew 
72755929a15Skevlo 	ure_write_mem(sc, URE_PLA_MAR, URE_MCU_TYPE_PLA | URE_BYTE_EN_DWORD,
72855929a15Skevlo 	    hashes, sizeof(hashes));
72942c54c93Sjmatthew 	ure_write_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode);
73042c54c93Sjmatthew }
73142c54c93Sjmatthew 
73242c54c93Sjmatthew void
ure_rxvlan(struct ure_softc * sc)73355929a15Skevlo ure_rxvlan(struct ure_softc *sc)
73455929a15Skevlo {
73555929a15Skevlo 	struct ifnet	*ifp = &sc->ure_ac.ac_if;
73655929a15Skevlo 	uint16_t	reg;
73755929a15Skevlo 
7388a3a1b1fSkevlo 	if (sc->ure_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
7398a3a1b1fSkevlo 		reg = ure_read_2(sc, URE_PLA_RCR1, URE_MCU_TYPE_PLA);
7408a3a1b1fSkevlo 		reg &= ~(URE_INNER_VLAN | URE_OUTER_VLAN);
741c096a1a3Skevlo 		if (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING)
7428a3a1b1fSkevlo 			reg |= (URE_INNER_VLAN | URE_OUTER_VLAN);
7438a3a1b1fSkevlo 		ure_write_2(sc, URE_PLA_RCR1, URE_MCU_TYPE_PLA, reg);
744c096a1a3Skevlo 	} else {
74555929a15Skevlo 		reg = ure_read_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA);
74655929a15Skevlo 		reg &= ~URE_CPCR_RX_VLAN;
74755929a15Skevlo 		if (ifp->if_capabilities & IFCAP_VLAN_HWTAGGING)
74855929a15Skevlo 			reg |= URE_CPCR_RX_VLAN;
74955929a15Skevlo 		ure_write_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA, reg);
75055929a15Skevlo 	}
751c096a1a3Skevlo }
75255929a15Skevlo 
75355929a15Skevlo void
ure_reset(struct ure_softc * sc)75442c54c93Sjmatthew ure_reset(struct ure_softc *sc)
75542c54c93Sjmatthew {
75642c54c93Sjmatthew 	int	i;
75742c54c93Sjmatthew 
7588a3a1b1fSkevlo 	if (sc->ure_flags & URE_FLAG_8156) {
7598a3a1b1fSkevlo 		URE_CLRBIT_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_TE);
7608a3a1b1fSkevlo 		URE_CLRBIT_2(sc, URE_USB_BMU_RESET, URE_MCU_TYPE_USB,
7618a3a1b1fSkevlo 		    BMU_RESET_EP_IN);
7628a3a1b1fSkevlo 		URE_SETBIT_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB,
7638a3a1b1fSkevlo 		    URE_CDC_ECM_EN);
7648a3a1b1fSkevlo 		URE_CLRBIT_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RE);
7658a3a1b1fSkevlo 		URE_SETBIT_2(sc, URE_USB_BMU_RESET, URE_MCU_TYPE_USB,
7668a3a1b1fSkevlo 		    BMU_RESET_EP_IN);
7678a3a1b1fSkevlo 		URE_CLRBIT_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB,
7688a3a1b1fSkevlo 		    URE_CDC_ECM_EN);
7698a3a1b1fSkevlo 	} else {
77042c54c93Sjmatthew 		ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST);
77142c54c93Sjmatthew 
77242c54c93Sjmatthew 		for (i = 0; i < URE_TIMEOUT; i++) {
77342c54c93Sjmatthew 			if (!(ure_read_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA) &
77442c54c93Sjmatthew 			    URE_CR_RST))
77542c54c93Sjmatthew 				break;
77655929a15Skevlo 			DELAY(100);
77742c54c93Sjmatthew 		}
77842c54c93Sjmatthew 		if (i == URE_TIMEOUT)
7798a3a1b1fSkevlo 			printf("%s: reset never completed\n",
7808a3a1b1fSkevlo 			    sc->ure_dev.dv_xname);
7818a3a1b1fSkevlo 	}
78242c54c93Sjmatthew }
78342c54c93Sjmatthew 
78442c54c93Sjmatthew void
ure_watchdog(struct ifnet * ifp)785c096a1a3Skevlo ure_watchdog(struct ifnet *ifp)
786c096a1a3Skevlo {
787c096a1a3Skevlo 	struct ure_softc	*sc = ifp->if_softc;
788fd07ab7eSkevlo 	struct ure_chain	*c;
789fd07ab7eSkevlo 	usbd_status		err;
790fd07ab7eSkevlo 	int			i, s;
791fd07ab7eSkevlo 
792fd07ab7eSkevlo 	ifp->if_timer = 0;
793c096a1a3Skevlo 
794c096a1a3Skevlo 	if (usbd_is_dying(sc->ure_udev))
795c096a1a3Skevlo 		return;
796c096a1a3Skevlo 
797fd07ab7eSkevlo 	if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP))
798fd07ab7eSkevlo 		return;
799fd07ab7eSkevlo 
800fd07ab7eSkevlo 	sc = ifp->if_softc;
801fd07ab7eSkevlo 	s = splnet();
802fd07ab7eSkevlo 
803c096a1a3Skevlo 	ifp->if_oerrors++;
804fd07ab7eSkevlo 	DPRINTF(("%s: watchdog timeout\n", sc->ure_dev.dv_xname));
805fd07ab7eSkevlo 
806fd07ab7eSkevlo 	for (i = 0; i < URE_TX_LIST_CNT; i++) {
807fd07ab7eSkevlo 		c = &sc->ure_cdata.ure_tx_chain[i];
808fd07ab7eSkevlo 		if (c->uc_cnt > 0) {
809fd07ab7eSkevlo 			usbd_get_xfer_status(c->uc_xfer, NULL, NULL, NULL,
810fd07ab7eSkevlo 			    &err);
811fd07ab7eSkevlo 			ure_txeof(c->uc_xfer, c, err);
812fd07ab7eSkevlo 		}
813fd07ab7eSkevlo 	}
814fd07ab7eSkevlo 
815fd07ab7eSkevlo 	if (ifq_is_oactive(&ifp->if_snd))
816fd07ab7eSkevlo 		ifq_restart(&ifp->if_snd);
817fd07ab7eSkevlo 	splx(s);
818c096a1a3Skevlo }
819c096a1a3Skevlo 
820c096a1a3Skevlo void
ure_init(void * xsc)82142c54c93Sjmatthew ure_init(void *xsc)
82242c54c93Sjmatthew {
82342c54c93Sjmatthew 	struct ure_softc	*sc = xsc;
82442c54c93Sjmatthew 	struct ure_chain	*c;
82542c54c93Sjmatthew 	struct ifnet		*ifp = &sc->ure_ac.ac_if;
82642c54c93Sjmatthew 	usbd_status		err;
82742c54c93Sjmatthew 	int			s, i;
82842c54c93Sjmatthew 
82942c54c93Sjmatthew 	s = splnet();
83042c54c93Sjmatthew 
83142c54c93Sjmatthew 	/* Cancel pending I/O. */
83242c54c93Sjmatthew 	ure_stop(sc);
83342c54c93Sjmatthew 
83455929a15Skevlo 	if (sc->ure_flags & URE_FLAG_8152)
83555929a15Skevlo 		ure_rtl8152_nic_reset(sc);
83655929a15Skevlo 	else
83755929a15Skevlo 		ure_rtl8153_nic_reset(sc);
83855929a15Skevlo 
839fd07ab7eSkevlo 	if (ure_xfer_list_init(sc, sc->ure_cdata.ure_rx_chain,
840fd07ab7eSkevlo 		sc->ure_rxbufsz, URE_RX_LIST_CNT) == ENOBUFS) {
84142c54c93Sjmatthew 		printf("%s: rx list init failed\n", sc->ure_dev.dv_xname);
84242c54c93Sjmatthew 		splx(s);
84342c54c93Sjmatthew 		return;
84442c54c93Sjmatthew 	}
84542c54c93Sjmatthew 
846fd07ab7eSkevlo 	if (ure_xfer_list_init(sc, sc->ure_cdata.ure_tx_chain,
847fd07ab7eSkevlo 		sc->ure_txbufsz, URE_TX_LIST_CNT) == ENOBUFS) {
84842c54c93Sjmatthew 		printf("%s: tx list init failed\n", sc->ure_dev.dv_xname);
84942c54c93Sjmatthew 		splx(s);
85042c54c93Sjmatthew 		return;
85142c54c93Sjmatthew 	}
85242c54c93Sjmatthew 
853fd07ab7eSkevlo 	/* Initialize the SLIST we are using for the multiple tx buffers */
854fd07ab7eSkevlo 	SLIST_INIT(&sc->ure_cdata.ure_tx_free);
855fd07ab7eSkevlo 	for (i = 0; i < URE_TX_LIST_CNT; i++)
856fd07ab7eSkevlo 		SLIST_INSERT_HEAD(&sc->ure_cdata.ure_tx_free,
857fd07ab7eSkevlo 		    &sc->ure_cdata.ure_tx_chain[i], uc_list);
858fd07ab7eSkevlo 
859c0ad8833Smglocker 	/* Setup MAC address, and enable TX/RX. */
860c0ad8833Smglocker 	ure_ifmedia_init(ifp);
86142c54c93Sjmatthew 
86242c54c93Sjmatthew 	/* Load the multicast filter. */
86342c54c93Sjmatthew 	ure_iff(sc);
86442c54c93Sjmatthew 
86542c54c93Sjmatthew 	/* Open RX and TX pipes. */
86642c54c93Sjmatthew 	err = usbd_open_pipe(sc->ure_iface, sc->ure_ed[URE_ENDPT_RX],
86742c54c93Sjmatthew 	    USBD_EXCLUSIVE_USE, &sc->ure_ep[URE_ENDPT_RX]);
86842c54c93Sjmatthew 	if (err) {
86942c54c93Sjmatthew 		printf("%s: open rx pipe failed: %s\n",
87042c54c93Sjmatthew 		    sc->ure_dev.dv_xname, usbd_errstr(err));
87142c54c93Sjmatthew 		splx(s);
87242c54c93Sjmatthew 		return;
87342c54c93Sjmatthew 	}
87442c54c93Sjmatthew 
87542c54c93Sjmatthew 	err = usbd_open_pipe(sc->ure_iface, sc->ure_ed[URE_ENDPT_TX],
87642c54c93Sjmatthew 	    USBD_EXCLUSIVE_USE, &sc->ure_ep[URE_ENDPT_TX]);
87742c54c93Sjmatthew 	if (err) {
87842c54c93Sjmatthew 		printf("%s: open tx pipe failed: %s\n",
87942c54c93Sjmatthew 		    sc->ure_dev.dv_xname, usbd_errstr(err));
88042c54c93Sjmatthew 		splx(s);
88142c54c93Sjmatthew 		return;
88242c54c93Sjmatthew 	}
88342c54c93Sjmatthew 
88442c54c93Sjmatthew 	/* Start up the receive pipe. */
88542c54c93Sjmatthew 	for (i = 0; i < URE_RX_LIST_CNT; i++) {
886fd07ab7eSkevlo 		c = &sc->ure_cdata.ure_rx_chain[i];
88742c54c93Sjmatthew 		usbd_setup_xfer(c->uc_xfer, sc->ure_ep[URE_ENDPT_RX],
888fd07ab7eSkevlo 		    c, c->uc_buf, c->uc_bufmax,
88942c54c93Sjmatthew 		    USBD_SHORT_XFER_OK | USBD_NO_COPY,
89042c54c93Sjmatthew 		    USBD_NO_TIMEOUT, ure_rxeof);
89142c54c93Sjmatthew 		usbd_transfer(c->uc_xfer);
89242c54c93Sjmatthew 	}
89342c54c93Sjmatthew 
894c096a1a3Skevlo 	ure_ifmedia_upd(ifp);
895c096a1a3Skevlo 
89642c54c93Sjmatthew 	/* Indicate we are up and running. */
89755929a15Skevlo 	sc->ure_flags &= ~URE_FLAG_LINK;
89842c54c93Sjmatthew 	ifp->if_flags |= IFF_RUNNING;
89942c54c93Sjmatthew 	ifq_clr_oactive(&ifp->if_snd);
90042c54c93Sjmatthew 
90142c54c93Sjmatthew 	timeout_add_sec(&sc->ure_stat_ch, 1);
90242c54c93Sjmatthew 
90342c54c93Sjmatthew 	splx(s);
90442c54c93Sjmatthew }
90542c54c93Sjmatthew 
90642c54c93Sjmatthew void
ure_start(struct ifnet * ifp)90742c54c93Sjmatthew ure_start(struct ifnet *ifp)
90842c54c93Sjmatthew {
90942c54c93Sjmatthew 	struct ure_softc	*sc = ifp->if_softc;
910fd07ab7eSkevlo 	struct ure_cdata	*cd = &sc->ure_cdata;
911fd07ab7eSkevlo 	struct ure_chain	*c;
912fd07ab7eSkevlo 	struct mbuf		*m = NULL;
913fd07ab7eSkevlo 	uint32_t		new_buflen;
914fd07ab7eSkevlo 	int			s, mlen;
91542c54c93Sjmatthew 
916fd07ab7eSkevlo 	if (!(sc->ure_flags & URE_FLAG_LINK) ||
917fd07ab7eSkevlo 		(ifp->if_flags & (IFF_RUNNING|IFF_UP)) !=
918fd07ab7eSkevlo 		    (IFF_RUNNING|IFF_UP)) {
91942c54c93Sjmatthew 		return;
920fd07ab7eSkevlo 	}
921c096a1a3Skevlo 
922fd07ab7eSkevlo 	s = splnet();
923fd07ab7eSkevlo 
924fd07ab7eSkevlo 	c = SLIST_FIRST(&cd->ure_tx_free);
925fd07ab7eSkevlo 	while (c != NULL) {
926fd07ab7eSkevlo 		m = ifq_deq_begin(&ifp->if_snd);
927fd07ab7eSkevlo 		if (m == NULL)
928fd07ab7eSkevlo 			break;
929fd07ab7eSkevlo 
930fd07ab7eSkevlo 		mlen = m->m_pkthdr.len;
931fd07ab7eSkevlo 
932fd07ab7eSkevlo 		/* Discard packet larger than buffer. */
933fd07ab7eSkevlo 		if (mlen + sizeof(struct ure_txpkt) >= c->uc_bufmax) {
934fd07ab7eSkevlo 			ifq_deq_commit(&ifp->if_snd, m);
935fd07ab7eSkevlo 			m_freem(m);
936fd07ab7eSkevlo 			ifp->if_oerrors++;
937fd07ab7eSkevlo 			continue;
938fd07ab7eSkevlo 		}
939fd07ab7eSkevlo 
940fd07ab7eSkevlo 		/*
941fd07ab7eSkevlo 		 * If packet larger than remaining space, send buffer and
942fd07ab7eSkevlo 		 * continue.
943fd07ab7eSkevlo 		 */
944fd07ab7eSkevlo 		new_buflen = roundup(c->uc_buflen, URE_TX_BUF_ALIGN);
945fd07ab7eSkevlo 		if (new_buflen + sizeof(struct ure_txpkt) + mlen >=
946fd07ab7eSkevlo 		    c->uc_bufmax) {
947fd07ab7eSkevlo 			ifq_deq_rollback(&ifp->if_snd, m);
948fd07ab7eSkevlo 			SLIST_REMOVE_HEAD(&cd->ure_tx_free, uc_list);
949fd07ab7eSkevlo 			if (ure_encap_xfer(ifp, sc, c)) {
950fd07ab7eSkevlo 				SLIST_INSERT_HEAD(&cd->ure_tx_free, c,
951fd07ab7eSkevlo 				    uc_list);
952fd07ab7eSkevlo 				break;
953fd07ab7eSkevlo 			}
954fd07ab7eSkevlo 			c = SLIST_FIRST(&cd->ure_tx_free);
955fd07ab7eSkevlo 			continue;
956fd07ab7eSkevlo 		}
957fd07ab7eSkevlo 
958fd07ab7eSkevlo 		/* Append packet to current buffer. */
959fd07ab7eSkevlo 		mlen = ure_encap_txpkt(m, c->uc_buf + new_buflen,
960fd07ab7eSkevlo 		    c->uc_bufmax - new_buflen);
961fd07ab7eSkevlo 		if (mlen <= 0) {
962fd07ab7eSkevlo 			ifq_deq_rollback(&ifp->if_snd, m);
963c096a1a3Skevlo 			break;
96442c54c93Sjmatthew 		}
96542c54c93Sjmatthew 
966fd07ab7eSkevlo 		ifq_deq_commit(&ifp->if_snd, m);
967fd07ab7eSkevlo 		c->uc_cnt += 1;
968fd07ab7eSkevlo 		c->uc_buflen = new_buflen + mlen;
96942c54c93Sjmatthew 
97042c54c93Sjmatthew #if NBPFILTER > 0
97142c54c93Sjmatthew 		if (ifp->if_bpf)
972fd07ab7eSkevlo 			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
97342c54c93Sjmatthew #endif
974fd07ab7eSkevlo 
975fd07ab7eSkevlo 		m_freem(m);
976c096a1a3Skevlo 	}
977fd07ab7eSkevlo 
978fd07ab7eSkevlo 	if (c != NULL) {
979fd07ab7eSkevlo 		/* Send current buffer unless empty */
980fd07ab7eSkevlo 		if (c->uc_buflen > 0 && c->uc_cnt > 0) {
981fd07ab7eSkevlo 			SLIST_REMOVE_HEAD(&cd->ure_tx_free, uc_list);
982fd07ab7eSkevlo 			if (ure_encap_xfer(ifp, sc, c)) {
983fd07ab7eSkevlo 				SLIST_INSERT_HEAD(&cd->ure_tx_free, c,
984fd07ab7eSkevlo 				    uc_list);
985fd07ab7eSkevlo 			}
986fd07ab7eSkevlo 			c = SLIST_FIRST(&cd->ure_tx_free);
987fd07ab7eSkevlo 		}
988fd07ab7eSkevlo 	}
989fd07ab7eSkevlo 
990fd07ab7eSkevlo 	ifp->if_timer = 5;
991fd07ab7eSkevlo 	if (c == NULL)
992fd07ab7eSkevlo 		ifq_set_oactive(&ifp->if_snd);
993fd07ab7eSkevlo 	splx(s);
99442c54c93Sjmatthew }
99542c54c93Sjmatthew 
99642c54c93Sjmatthew void
ure_tick(void * xsc)99742c54c93Sjmatthew ure_tick(void *xsc)
99842c54c93Sjmatthew {
99942c54c93Sjmatthew 	struct ure_softc	*sc = xsc;
100042c54c93Sjmatthew 
100142c54c93Sjmatthew 	if (sc == NULL)
100242c54c93Sjmatthew 		return;
100342c54c93Sjmatthew 
100442c54c93Sjmatthew 	if (usbd_is_dying(sc->ure_udev))
100542c54c93Sjmatthew 		return;
100642c54c93Sjmatthew 
100742c54c93Sjmatthew 	usb_add_task(sc->ure_udev, &sc->ure_tick_task);
100842c54c93Sjmatthew }
100942c54c93Sjmatthew 
101042c54c93Sjmatthew void
ure_stop(struct ure_softc * sc)101142c54c93Sjmatthew ure_stop(struct ure_softc *sc)
101242c54c93Sjmatthew {
1013fd07ab7eSkevlo 	struct ure_cdata	*cd;
101442c54c93Sjmatthew 	struct ifnet		*ifp;
1015fd07ab7eSkevlo 	usbd_status		err;
101642c54c93Sjmatthew 
101742c54c93Sjmatthew 	ure_reset(sc);
101842c54c93Sjmatthew 
101942c54c93Sjmatthew 	ifp = &sc->ure_ac.ac_if;
102042c54c93Sjmatthew 	ifp->if_timer = 0;
102142c54c93Sjmatthew 	ifp->if_flags &= ~IFF_RUNNING;
102242c54c93Sjmatthew 	ifq_clr_oactive(&ifp->if_snd);
102342c54c93Sjmatthew 
102442c54c93Sjmatthew 	timeout_del(&sc->ure_stat_ch);
1025c096a1a3Skevlo 	sc->ure_flags &= ~URE_FLAG_LINK;
102642c54c93Sjmatthew 
102742c54c93Sjmatthew 	if (sc->ure_ep[URE_ENDPT_RX] != NULL) {
102842c54c93Sjmatthew 		err = usbd_close_pipe(sc->ure_ep[URE_ENDPT_RX]);
102942c54c93Sjmatthew 		if (err) {
103042c54c93Sjmatthew 			printf("%s: close rx pipe failed: %s\n",
103142c54c93Sjmatthew 			    sc->ure_dev.dv_xname, usbd_errstr(err));
103242c54c93Sjmatthew 		}
103342c54c93Sjmatthew 		sc->ure_ep[URE_ENDPT_RX] = NULL;
103442c54c93Sjmatthew 	}
103542c54c93Sjmatthew 
103642c54c93Sjmatthew 	if (sc->ure_ep[URE_ENDPT_TX] != NULL) {
103742c54c93Sjmatthew 		err = usbd_close_pipe(sc->ure_ep[URE_ENDPT_TX]);
103842c54c93Sjmatthew 		if (err) {
103942c54c93Sjmatthew 			printf("%s: close tx pipe failed: %s\n",
104042c54c93Sjmatthew 			    sc->ure_dev.dv_xname, usbd_errstr(err));
104142c54c93Sjmatthew 		}
104242c54c93Sjmatthew 		sc->ure_ep[URE_ENDPT_TX] = NULL;
104342c54c93Sjmatthew 	}
104442c54c93Sjmatthew 
1045fd07ab7eSkevlo 	cd = &sc->ure_cdata;
1046fd07ab7eSkevlo 	ure_xfer_list_free(sc, cd->ure_rx_chain, URE_RX_LIST_CNT);
1047fd07ab7eSkevlo 	ure_xfer_list_free(sc, cd->ure_tx_chain, URE_TX_LIST_CNT);
104842c54c93Sjmatthew }
1049fd07ab7eSkevlo 
1050fd07ab7eSkevlo int
ure_xfer_list_init(struct ure_softc * sc,struct ure_chain * ch,uint32_t bufsize,int listlen)1051fd07ab7eSkevlo ure_xfer_list_init(struct ure_softc *sc, struct ure_chain *ch,
1052fd07ab7eSkevlo     uint32_t bufsize, int listlen)
1053fd07ab7eSkevlo {
1054fd07ab7eSkevlo 	struct ure_chain	*c;
1055fd07ab7eSkevlo 	int			i;
1056fd07ab7eSkevlo 
1057fd07ab7eSkevlo 	for (i = 0; i < listlen; i++) {
1058fd07ab7eSkevlo 		c = &ch[i];
1059fd07ab7eSkevlo 		c->uc_sc = sc;
1060fd07ab7eSkevlo 		c->uc_idx = i;
1061fd07ab7eSkevlo 		c->uc_buflen = 0;
1062fd07ab7eSkevlo 		c->uc_bufmax = bufsize;
1063fd07ab7eSkevlo 		c->uc_cnt = 0;
1064fd07ab7eSkevlo 		if (c->uc_xfer == NULL) {
1065fd07ab7eSkevlo 			c->uc_xfer = usbd_alloc_xfer(sc->ure_udev);
1066fd07ab7eSkevlo 			if (c->uc_xfer == NULL)
1067fd07ab7eSkevlo 				return (ENOBUFS);
1068fd07ab7eSkevlo 			c->uc_buf = usbd_alloc_buffer(c->uc_xfer, c->uc_bufmax);
1069fd07ab7eSkevlo 			if (c->uc_buf == NULL) {
1070fd07ab7eSkevlo 				usbd_free_xfer(c->uc_xfer);
1071fd07ab7eSkevlo 				c->uc_xfer = NULL;
1072fd07ab7eSkevlo 				return (ENOBUFS);
1073fd07ab7eSkevlo 			}
107442c54c93Sjmatthew 		}
107542c54c93Sjmatthew 	}
107642c54c93Sjmatthew 
1077fd07ab7eSkevlo 	return (0);
107842c54c93Sjmatthew }
1079fd07ab7eSkevlo 
1080fd07ab7eSkevlo void
ure_xfer_list_free(struct ure_softc * sc,struct ure_chain * ch,int listlen)1081fd07ab7eSkevlo ure_xfer_list_free(struct ure_softc *sc, struct ure_chain *ch, int listlen)
1082fd07ab7eSkevlo {
1083fd07ab7eSkevlo 	int	i;
1084fd07ab7eSkevlo 
1085fd07ab7eSkevlo 	for (i = 0; i < listlen; i++) {
1086fd07ab7eSkevlo 		if (ch[i].uc_buf != NULL) {
1087fd07ab7eSkevlo 			ch[i].uc_buf = NULL;
1088fd07ab7eSkevlo 		}
1089fd07ab7eSkevlo 		ch[i].uc_cnt = 0;
1090fd07ab7eSkevlo 		if (ch[i].uc_xfer != NULL) {
1091fd07ab7eSkevlo 			usbd_free_xfer(ch[i].uc_xfer);
1092fd07ab7eSkevlo 			ch[i].uc_xfer = NULL;
109342c54c93Sjmatthew 		}
109442c54c93Sjmatthew 	}
109542c54c93Sjmatthew }
109642c54c93Sjmatthew 
109742c54c93Sjmatthew void
ure_rtl8152_init(struct ure_softc * sc)109842c54c93Sjmatthew ure_rtl8152_init(struct ure_softc *sc)
109942c54c93Sjmatthew {
110042c54c93Sjmatthew 	uint32_t	pwrctrl;
110142c54c93Sjmatthew 
110242c54c93Sjmatthew 	/* Disable ALDPS. */
110342c54c93Sjmatthew 	ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA |
110442c54c93Sjmatthew 	    URE_DIS_SDSAVE);
110542c54c93Sjmatthew 	usbd_delay_ms(sc->ure_udev, 20);
110642c54c93Sjmatthew 
110755929a15Skevlo 	if (sc->ure_chip & URE_CHIP_VER_4C00)
110855929a15Skevlo 		URE_CLRBIT_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA,
110955929a15Skevlo 		    URE_LED_MODE_MASK);
111042c54c93Sjmatthew 
111155929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB, URE_POWER_CUT);
111255929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB,
111355929a15Skevlo 	    URE_RESUME_INDICATE);
111442c54c93Sjmatthew 
111555929a15Skevlo 	URE_SETBIT_2(sc, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA,
111642c54c93Sjmatthew 	    URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH);
111742c54c93Sjmatthew 	pwrctrl = ure_read_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA);
111842c54c93Sjmatthew 	pwrctrl &= ~URE_MCU_CLK_RATIO_MASK;
111942c54c93Sjmatthew 	pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN;
112042c54c93Sjmatthew 	ure_write_4(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl);
112142c54c93Sjmatthew 	ure_write_2(sc, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA,
112242c54c93Sjmatthew 	    URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK |
112342c54c93Sjmatthew 	    URE_SPDWN_LINKCHG_MSK);
112442c54c93Sjmatthew 
112555929a15Skevlo 	URE_SETBIT_2(sc, URE_PLA_RSTTALLY, URE_MCU_TYPE_PLA, URE_TALLY_RESET);
112655929a15Skevlo 
112793362a8fSmpi 	/* Enable Rx aggregation. */
112855929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB,
112955929a15Skevlo 	    URE_RX_AGG_DISABLE | URE_RX_ZERO_EN);
113055929a15Skevlo }
113155929a15Skevlo 
113255929a15Skevlo void
ure_rtl8153_init(struct ure_softc * sc)113355929a15Skevlo ure_rtl8153_init(struct ure_softc *sc)
113455929a15Skevlo {
113555929a15Skevlo 	uint16_t	reg;
113655929a15Skevlo 	uint8_t		u1u2[8];
113755929a15Skevlo 	int		i;
113855929a15Skevlo 
113955929a15Skevlo 	memset(u1u2, 0x00, sizeof(u1u2));
114055929a15Skevlo 	ure_write_mem(sc, URE_USB_TOLERANCE, URE_BYTE_EN_SIX_BYTES, u1u2,
114155929a15Skevlo 	    sizeof(u1u2));
114255929a15Skevlo 
114355929a15Skevlo         for (i = 0; i < 500; i++) {
114455929a15Skevlo 		if (ure_read_2(sc, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) &
114555929a15Skevlo 		    URE_AUTOLOAD_DONE)
114655929a15Skevlo 			break;
114755929a15Skevlo 		usbd_delay_ms(sc->ure_udev, 20);
114855929a15Skevlo 	}
114955929a15Skevlo 	if (i == 500)
115055929a15Skevlo 		printf("%s: timeout waiting for chip autoload\n",
115155929a15Skevlo 		    sc->ure_dev.dv_xname);
115255929a15Skevlo 
115355929a15Skevlo 	ure_rtl8153_phy_status(sc, 0);
115455929a15Skevlo 
115555929a15Skevlo 	if (sc->ure_chip & (URE_CHIP_VER_5C00 | URE_CHIP_VER_5C10 |
115655929a15Skevlo 	    URE_CHIP_VER_5C20)) {
115755929a15Skevlo 		ure_ocp_reg_write(sc, URE_OCP_ADC_CFG,
115855929a15Skevlo 		    URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L);
115955929a15Skevlo 	}
116055929a15Skevlo 
11618a3a1b1fSkevlo 	ure_rtl8153_phy_status(sc, URE_PHY_STAT_LAN_ON);
116255929a15Skevlo 
116355929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, URE_U2P3_ENABLE);
116455929a15Skevlo 
116555929a15Skevlo 	if (sc->ure_chip & URE_CHIP_VER_5C10) {
116655929a15Skevlo 		reg = ure_read_2(sc, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB);
116755929a15Skevlo 		reg &= ~URE_PWD_DN_SCALE_MASK;
116855929a15Skevlo 		reg |= URE_PWD_DN_SCALE(96);
116955929a15Skevlo 		ure_write_2(sc, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, reg);
117055929a15Skevlo 
117155929a15Skevlo 		URE_SETBIT_1(sc, URE_USB_USB2PHY, URE_MCU_TYPE_USB,
117255929a15Skevlo 		    URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND);
117355929a15Skevlo 	} else if (sc->ure_chip & URE_CHIP_VER_5C20) {
117455929a15Skevlo 		URE_CLRBIT_1(sc, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA,
117555929a15Skevlo 		    URE_ECM_ALDPS);
117655929a15Skevlo 	}
117755929a15Skevlo 	if (sc->ure_chip & (URE_CHIP_VER_5C20 | URE_CHIP_VER_5C30)) {
117855929a15Skevlo 		if (ure_read_2(sc, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB))
117955929a15Skevlo 			URE_SETBIT_1(sc, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB,
118055929a15Skevlo 			    URE_DYNAMIC_BURST);
118155929a15Skevlo 		else
118255929a15Skevlo 			URE_CLRBIT_1(sc, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB,
118355929a15Skevlo 			    URE_DYNAMIC_BURST);
118455929a15Skevlo 	}
118555929a15Skevlo 
118655929a15Skevlo 	URE_SETBIT_1(sc, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB, URE_EP4_FULL_FC);
118755929a15Skevlo 
118855929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB, URE_TIMER11_EN);
118955929a15Skevlo 
119055929a15Skevlo 	URE_CLRBIT_2(sc, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA,
119155929a15Skevlo 	    URE_LED_MODE_MASK);
119255929a15Skevlo 
119355929a15Skevlo 	if ((sc->ure_chip & URE_CHIP_VER_5C10) &&
119455929a15Skevlo 	    sc->ure_udev->speed != USB_SPEED_SUPER)
119555929a15Skevlo 		reg = URE_LPM_TIMER_500MS;
119655929a15Skevlo 	else
119755929a15Skevlo 		reg = URE_LPM_TIMER_500US;
119855929a15Skevlo 	ure_write_1(sc, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB,
119955929a15Skevlo 	    URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM | reg);
120055929a15Skevlo 
120155929a15Skevlo 	reg = ure_read_2(sc, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB);
120255929a15Skevlo 	reg &= ~URE_SEN_VAL_MASK;
120355929a15Skevlo 	reg |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE;
120455929a15Skevlo 	ure_write_2(sc, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, reg);
120555929a15Skevlo 
120655929a15Skevlo 	ure_write_2(sc, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001);
120755929a15Skevlo 
120855929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_POWER_CUT, URE_MCU_TYPE_USB,
120955929a15Skevlo 	    URE_PWR_EN | URE_PHASE2_EN);
121055929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_MISC_0, URE_MCU_TYPE_USB, URE_PCUT_STATUS);
121155929a15Skevlo 
121255929a15Skevlo 	memset(u1u2, 0xff, sizeof(u1u2));
121355929a15Skevlo 	ure_write_mem(sc, URE_USB_TOLERANCE, URE_BYTE_EN_SIX_BYTES, u1u2,
121455929a15Skevlo 	    sizeof(u1u2));
121555929a15Skevlo 
121655929a15Skevlo 	ure_write_2(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, 0);
121755929a15Skevlo 	ure_write_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, 0);
121855929a15Skevlo 	ure_write_2(sc, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA, 0);
121955929a15Skevlo 	ure_write_2(sc, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA, 0);
122055929a15Skevlo 
122155929a15Skevlo 	/* Enable Rx aggregation. */
122255929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB,
122355929a15Skevlo 	    URE_RX_AGG_DISABLE | URE_RX_ZERO_EN);
122455929a15Skevlo 
122555929a15Skevlo 	URE_SETBIT_2(sc, URE_PLA_RSTTALLY, URE_MCU_TYPE_PLA, URE_TALLY_RESET);
122655929a15Skevlo }
122755929a15Skevlo 
122855929a15Skevlo void
ure_rtl8153b_init(struct ure_softc * sc)122955929a15Skevlo ure_rtl8153b_init(struct ure_softc *sc)
123055929a15Skevlo {
1231c096a1a3Skevlo 	uint16_t	reg;
123255929a15Skevlo 	int		i;
123355929a15Skevlo 
12348a3a1b1fSkevlo 	if (sc->ure_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
12358a3a1b1fSkevlo 		URE_CLRBIT_1(sc, URE_USB_ECM_OP, URE_MCU_TYPE_USB,
12368a3a1b1fSkevlo 		    URE_EN_ALL_SPEED);
12378a3a1b1fSkevlo 		ure_write_2(sc, URE_USB_SPEED_OPTION, URE_MCU_TYPE_USB, 0);
12388a3a1b1fSkevlo 		URE_SETBIT_2(sc, URE_USB_ECM_OPTION, URE_MCU_TYPE_USB,
12398a3a1b1fSkevlo 		    URE_BYPASS_MAC_RESET);
12408a3a1b1fSkevlo 
12418a3a1b1fSkevlo 		if (sc->ure_flags & URE_FLAG_8156B)
12428a3a1b1fSkevlo 			URE_SETBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB,
12438a3a1b1fSkevlo 			    URE_RX_DETECT8);
1244c096a1a3Skevlo 	}
1245c096a1a3Skevlo 
124655929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_LPM_CONFIG, URE_MCU_TYPE_USB, LPM_U1U2_EN);
124755929a15Skevlo 
12488a3a1b1fSkevlo 	if (sc->ure_flags & URE_FLAG_8156B)
12498a3a1b1fSkevlo 		ure_wait_for_flash(sc);
12508a3a1b1fSkevlo 
125155929a15Skevlo         for (i = 0; i < 500; i++) {
125255929a15Skevlo 		if (ure_read_2(sc, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) &
125355929a15Skevlo 		    URE_AUTOLOAD_DONE)
125455929a15Skevlo 			break;
125555929a15Skevlo 		usbd_delay_ms(sc->ure_udev, 20);
125655929a15Skevlo 	}
125755929a15Skevlo 	if (i == 500)
125855929a15Skevlo 		printf("%s: timeout waiting for chip autoload\n",
125955929a15Skevlo 		    sc->ure_dev.dv_xname);
126055929a15Skevlo 
126155929a15Skevlo 	ure_rtl8153_phy_status(sc, 0);
12628a3a1b1fSkevlo 	ure_rtl8153_phy_status(sc, URE_PHY_STAT_LAN_ON);
126355929a15Skevlo 
126455929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, URE_U2P3_ENABLE);
126555929a15Skevlo 
126655929a15Skevlo 	/* MSC timer, 32760 ms. */
12678a3a1b1fSkevlo 	ure_write_2(sc, URE_USB_MSC_TIMER, URE_MCU_TYPE_USB, 4095);
126855929a15Skevlo 
12698a3a1b1fSkevlo 	if (!(sc->ure_flags & URE_FLAG_8153B)) {
127055929a15Skevlo 		/* U1/U2/L1 idle timer, 500 us. */
127155929a15Skevlo 		ure_write_2(sc, URE_USB_U1U2_TIMER, URE_MCU_TYPE_USB, 500);
12728a3a1b1fSkevlo 	}
127355929a15Skevlo 
127455929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_POWER_CUT, URE_MCU_TYPE_USB, URE_PWR_EN);
127555929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_MISC_0, URE_MCU_TYPE_USB, URE_PCUT_STATUS);
127655929a15Skevlo 
127755929a15Skevlo 	URE_CLRBIT_1(sc, URE_USB_POWER_CUT, URE_MCU_TYPE_USB,
127855929a15Skevlo 	    URE_UPS_EN | URE_USP_PREWAKE);
12798a3a1b1fSkevlo 	URE_CLRBIT_1(sc, URE_USB_MISC_2, URE_MCU_TYPE_USB,
12803dd6ed5fSkevlo 	    URE_UPS_FORCE_PWR_DOWN | URE_UPS_NO_UPS);
128155929a15Skevlo 
128255929a15Skevlo 	URE_CLRBIT_1(sc, URE_PLA_INDICATE_FALG, URE_MCU_TYPE_PLA,
128355929a15Skevlo 	    URE_UPCOMING_RUNTIME_D3);
128455929a15Skevlo 	URE_CLRBIT_1(sc, URE_PLA_SUSPEND_FLAG, URE_MCU_TYPE_PLA,
128555929a15Skevlo 	    URE_LINK_CHG_EVENT);
128655929a15Skevlo 	URE_CLRBIT_2(sc, URE_PLA_EXTRA_STATUS, URE_MCU_TYPE_PLA,
128755929a15Skevlo 	    URE_LINK_CHANGE_FLAG);
128855929a15Skevlo 
128955929a15Skevlo 	ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG);
129055929a15Skevlo 	URE_CLRBIT_2(sc, URE_PLA_CONFIG34, URE_MCU_TYPE_PLA,
129155929a15Skevlo 	    URE_LINK_OFF_WAKE_EN);
129255929a15Skevlo 	ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML);
129355929a15Skevlo 
12948a3a1b1fSkevlo 	if (sc->ure_flags & URE_FLAG_8153B) {
12958a3a1b1fSkevlo 		reg = ure_read_2(sc, URE_PLA_EXTRA_STATUS, URE_MCU_TYPE_PLA);
12968a3a1b1fSkevlo 		if (ure_read_2(sc, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA) &
12978a3a1b1fSkevlo 		    URE_PHYSTATUS_LINK)
12988a3a1b1fSkevlo 			reg |= URE_CUR_LINK_OK;
12998a3a1b1fSkevlo 		else
13008a3a1b1fSkevlo 			reg &= ~URE_CUR_LINK_OK;
13018a3a1b1fSkevlo 		ure_write_2(sc, URE_PLA_EXTRA_STATUS, URE_MCU_TYPE_PLA,
13028a3a1b1fSkevlo 		    reg | URE_POLL_LINK_CHG);
13038a3a1b1fSkevlo 	}
13048a3a1b1fSkevlo 
13058a3a1b1fSkevlo 	if (sc->ure_udev->speed == USB_SPEED_SUPER) {
13068a3a1b1fSkevlo 		URE_SETBIT_2(sc, URE_USB_LPM_CONFIG, URE_MCU_TYPE_USB,
13078a3a1b1fSkevlo 		    LPM_U1U2_EN);
13088a3a1b1fSkevlo 	}
13098a3a1b1fSkevlo 
13108a3a1b1fSkevlo 	if (sc->ure_flags & URE_FLAG_8156B) {
13118a3a1b1fSkevlo 		URE_CLRBIT_2(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, URE_SLOT_EN);
13128a3a1b1fSkevlo 		URE_SETBIT_2(sc, URE_PLA_CPCR, URE_MCU_TYPE_PLA,
13138a3a1b1fSkevlo 		    URE_FLOW_CTRL_EN);
13148a3a1b1fSkevlo 
13158a3a1b1fSkevlo 		/* Enable fc timer and set timer to 600 ms. */
13168a3a1b1fSkevlo 		ure_write_2(sc, URE_USB_FC_TIMER, URE_MCU_TYPE_USB,
13178a3a1b1fSkevlo 		    URE_CTRL_TIMER_EN | 75);
13188a3a1b1fSkevlo 
13198a3a1b1fSkevlo 		reg = ure_read_2(sc, URE_USB_FW_CTRL, URE_MCU_TYPE_USB);
13208a3a1b1fSkevlo 		if (!(ure_read_2(sc, URE_PLA_POL_GPIO_CTRL, URE_MCU_TYPE_PLA) &
13218a3a1b1fSkevlo 		    URE_DACK_DET_EN))
13228a3a1b1fSkevlo 			reg |= URE_FLOW_CTRL_PATCH_2;
13238a3a1b1fSkevlo 		reg &= ~URE_AUTO_SPEEDUP;
13248a3a1b1fSkevlo 		ure_write_2(sc, URE_USB_FW_CTRL, URE_MCU_TYPE_USB, reg);
13258a3a1b1fSkevlo 
13268a3a1b1fSkevlo 		URE_SETBIT_2(sc, URE_USB_FW_TASK, URE_MCU_TYPE_USB,
13278a3a1b1fSkevlo 		    URE_FC_PATCH_TASK);
13288a3a1b1fSkevlo 	}
132955929a15Skevlo 
133055929a15Skevlo 	/* MAC clock speed down. */
13318a3a1b1fSkevlo 	if (sc->ure_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
1332c096a1a3Skevlo 		ure_write_2(sc, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, 0x0403);
13338a3a1b1fSkevlo 		reg = ure_read_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA);
13348a3a1b1fSkevlo 		reg &= ~URE_EEE_SPDWN_RATIO_MASK;
1335c096a1a3Skevlo 		reg |= URE_MAC_CLK_SPDWN_EN | 0x0003;
1336c096a1a3Skevlo 		ure_write_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA, reg);
1337c096a1a3Skevlo 
1338c096a1a3Skevlo 		URE_CLRBIT_2(sc, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA,
13398a3a1b1fSkevlo 		    URE_PLA_MCU_SPDWN_EN);
1340c096a1a3Skevlo 
1341c096a1a3Skevlo 		reg = ure_read_2(sc, URE_PLA_EXTRA_STATUS, URE_MCU_TYPE_PLA);
13428a3a1b1fSkevlo 		if (ure_read_2(sc, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA) &
13438a3a1b1fSkevlo 		    URE_PHYSTATUS_LINK)
13448a3a1b1fSkevlo 			reg |= URE_CUR_LINK_OK;
1345c096a1a3Skevlo 		else
13468a3a1b1fSkevlo 			reg &= ~URE_CUR_LINK_OK;
13478a3a1b1fSkevlo 		ure_write_2(sc, URE_PLA_EXTRA_STATUS, URE_MCU_TYPE_PLA,
13488a3a1b1fSkevlo 		    reg | URE_POLL_LINK_CHG);
1349c096a1a3Skevlo 	} else
135055929a15Skevlo 		URE_SETBIT_2(sc, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA,
135155929a15Skevlo 		    URE_MAC_CLK_SPDWN_EN);
135255929a15Skevlo 
135355929a15Skevlo 	/* Enable Rx aggregation. */
135455929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_USB_CTRL, URE_MCU_TYPE_USB,
135555929a15Skevlo 	    URE_RX_AGG_DISABLE | URE_RX_ZERO_EN);
135655929a15Skevlo 
1357c096a1a3Skevlo 	if (sc->ure_flags & URE_FLAG_8156)
13588a3a1b1fSkevlo 		URE_SETBIT_1(sc, URE_USB_BMU_CONFIG, URE_MCU_TYPE_USB,
13598a3a1b1fSkevlo 		    URE_ACT_ODMA);
1360c096a1a3Skevlo 
13613dd6ed5fSkevlo 	if (!(sc->ure_flags & URE_FLAG_8153B)) {
13623dd6ed5fSkevlo 		/*
13633dd6ed5fSkevlo 		 * Select force mode through 0xa5b4 bit 15
13643dd6ed5fSkevlo 		 * 0: MDIO force mode
13653dd6ed5fSkevlo 		 * 1: MMD force mode
13663dd6ed5fSkevlo 		 */
13673dd6ed5fSkevlo 		reg = ure_ocp_reg_read(sc, 0xa5b4);
13683dd6ed5fSkevlo 		if (reg & 0x8000)
13693dd6ed5fSkevlo 			ure_ocp_reg_write(sc, 0xa5b4, reg & ~0x8000);
13703dd6ed5fSkevlo 	}
13713dd6ed5fSkevlo 
137255929a15Skevlo 	URE_SETBIT_2(sc, URE_PLA_RSTTALLY, URE_MCU_TYPE_PLA, URE_TALLY_RESET);
137355929a15Skevlo }
137455929a15Skevlo 
137555929a15Skevlo void
ure_rtl8152_nic_reset(struct ure_softc * sc)137655929a15Skevlo ure_rtl8152_nic_reset(struct ure_softc *sc)
137755929a15Skevlo {
137855929a15Skevlo 	uint32_t	rx_fifo1, rx_fifo2;
137955929a15Skevlo 	int		i;
138042c54c93Sjmatthew 
138142c54c93Sjmatthew 	/* Disable ALDPS. */
138242c54c93Sjmatthew 	ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA |
138342c54c93Sjmatthew 	    URE_DIS_SDSAVE);
138442c54c93Sjmatthew 	usbd_delay_ms(sc->ure_udev, 20);
138542c54c93Sjmatthew 
138655929a15Skevlo 	URE_CLRBIT_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, URE_RCR_ACPT_ALL);
138742c54c93Sjmatthew 
138855929a15Skevlo 	URE_SETBIT_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, URE_RXDY_GATED_EN);
138942c54c93Sjmatthew 	ure_disable_teredo(sc);
139055929a15Skevlo 	ure_write_1(sc, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML);
139155929a15Skevlo 	ure_write_1(sc, URE_PLA_CR, URE_MCU_TYPE_PLA, 0);
139242c54c93Sjmatthew 
139355929a15Skevlo 	URE_CLRBIT_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, URE_NOW_IS_OOB);
139455929a15Skevlo 	URE_CLRBIT_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, URE_MCU_BORW_EN);
139555929a15Skevlo 	for (i = 0; i < URE_TIMEOUT; i++) {
139655929a15Skevlo 		if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
139755929a15Skevlo 		    URE_LINK_LIST_READY)
139855929a15Skevlo 			break;
139955929a15Skevlo 		usbd_delay_ms(sc->ure_udev, 1);
1400794a317fSkettenis 	}
140155929a15Skevlo 	if (i == URE_TIMEOUT)
140255929a15Skevlo 		printf("%s: timeout waiting for OOB control\n",
140355929a15Skevlo 		    sc->ure_dev.dv_xname);
140455929a15Skevlo 	URE_SETBIT_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, URE_RE_INIT_LL);
140555929a15Skevlo 	for (i = 0; i < URE_TIMEOUT; i++) {
140655929a15Skevlo 		if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
140755929a15Skevlo 		    URE_LINK_LIST_READY)
140855929a15Skevlo 			break;
140955929a15Skevlo 		usbd_delay_ms(sc->ure_udev, 1);
1410794a317fSkettenis 	}
141155929a15Skevlo 	if (i == URE_TIMEOUT)
141255929a15Skevlo 		printf("%s: timeout waiting for OOB control\n",
141355929a15Skevlo 		    sc->ure_dev.dv_xname);
1414794a317fSkettenis 
141542c54c93Sjmatthew 	ure_reset(sc);
141642c54c93Sjmatthew 
141755929a15Skevlo 	/* Configure Rx FIFO threshold. */
141842c54c93Sjmatthew 	ure_write_4(sc, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA,
141942c54c93Sjmatthew 	    URE_RXFIFO_THR1_NORMAL);
142042c54c93Sjmatthew 	if (sc->ure_udev->speed == USB_SPEED_FULL) {
142142c54c93Sjmatthew 		rx_fifo1 = URE_RXFIFO_THR2_FULL;
142242c54c93Sjmatthew 		rx_fifo2 = URE_RXFIFO_THR3_FULL;
142342c54c93Sjmatthew 	} else {
142442c54c93Sjmatthew 		rx_fifo1 = URE_RXFIFO_THR2_HIGH;
142542c54c93Sjmatthew 		rx_fifo2 = URE_RXFIFO_THR3_HIGH;
142642c54c93Sjmatthew 	}
142742c54c93Sjmatthew 	ure_write_4(sc, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1);
142842c54c93Sjmatthew 	ure_write_4(sc, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2);
142942c54c93Sjmatthew 
143042c54c93Sjmatthew 	/* Configure Tx FIFO threshold. */
143142c54c93Sjmatthew 	ure_write_4(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA,
143242c54c93Sjmatthew 	    URE_TXFIFO_THR_NORMAL);
143355929a15Skevlo 
143455929a15Skevlo 	ure_write_1(sc, URE_USB_TX_AGG, URE_MCU_TYPE_USB,
143555929a15Skevlo 	    URE_TX_AGG_MAX_THRESHOLD);
143655929a15Skevlo 	ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH);
143755929a15Skevlo 	ure_write_4(sc, URE_USB_TX_DMA, URE_MCU_TYPE_USB,
143855929a15Skevlo 	    URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1);
143955929a15Skevlo 
144055929a15Skevlo 	ure_rxvlan(sc);
144155929a15Skevlo         ure_write_2(sc, URE_PLA_RMS, URE_MCU_TYPE_PLA,
144255929a15Skevlo 	    ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
144355929a15Skevlo 	URE_SETBIT_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA, URE_TCR0_AUTO_FIFO);
144455929a15Skevlo 
144555929a15Skevlo 	/* Enable ALDPS. */
144655929a15Skevlo 	ure_ocp_reg_write(sc, URE_OCP_ALDPS_CONFIG,
144755929a15Skevlo 	    URE_ENPWRSAVE | URE_ENPDNPS | URE_LINKENA | URE_DIS_SDSAVE);
144855929a15Skevlo }
144955929a15Skevlo 
145055929a15Skevlo void
ure_rtl8153_nic_reset(struct ure_softc * sc)145155929a15Skevlo ure_rtl8153_nic_reset(struct ure_softc *sc)
145255929a15Skevlo {
145355929a15Skevlo 	struct ifnet	*ifp = &sc->ure_ac.ac_if;
145455929a15Skevlo 	uint32_t	reg = 0;
145555929a15Skevlo 	uint8_t		u1u2[8] = { 0 };
145655929a15Skevlo 	int		i;
145755929a15Skevlo 
14588a3a1b1fSkevlo 	if (sc->ure_flags & (URE_FLAG_8153B | URE_FLAG_8156 | URE_FLAG_8156B)) {
145955929a15Skevlo 		URE_CLRBIT_2(sc, URE_USB_LPM_CONFIG, URE_MCU_TYPE_USB,
146055929a15Skevlo 		    LPM_U1U2_EN);
146155929a15Skevlo 	} else {
146255929a15Skevlo 		memset(u1u2, 0x00, sizeof(u1u2));
146355929a15Skevlo 		ure_write_mem(sc, URE_USB_TOLERANCE, URE_BYTE_EN_SIX_BYTES,
146455929a15Skevlo 		    u1u2, sizeof(u1u2));
146555929a15Skevlo 	}
146655929a15Skevlo 	URE_CLRBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, URE_U2P3_ENABLE);
146755929a15Skevlo 
146855929a15Skevlo 	/* Disable ALDPS. */
146955929a15Skevlo 	ure_ocp_reg_write(sc, URE_OCP_POWER_CFG,
147055929a15Skevlo 	    ure_ocp_reg_read(sc, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS);
147155929a15Skevlo 	for (i = 0; i < 20; i++) {
147255929a15Skevlo 		usbd_delay_ms(sc->ure_udev, 1);
147355929a15Skevlo 		if (ure_read_2(sc, 0xe000, URE_MCU_TYPE_PLA) & 0x0100)
147455929a15Skevlo 			break;
147555929a15Skevlo 	}
147655929a15Skevlo 
147755929a15Skevlo 	URE_SETBIT_2(sc, URE_PLA_MISC_1, URE_MCU_TYPE_PLA, URE_RXDY_GATED_EN);
147855929a15Skevlo 	ure_disable_teredo(sc);
147955929a15Skevlo 
148055929a15Skevlo 	URE_CLRBIT_4(sc, URE_PLA_RCR, URE_MCU_TYPE_PLA, URE_RCR_ACPT_ALL);
148155929a15Skevlo 
148255929a15Skevlo 	ure_reset(sc);
148355929a15Skevlo 	ure_reset_bmu(sc);
148455929a15Skevlo 
148555929a15Skevlo 	URE_CLRBIT_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA, URE_NOW_IS_OOB);
148655929a15Skevlo 	URE_CLRBIT_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA, URE_MCU_BORW_EN);
148755929a15Skevlo 
14888a3a1b1fSkevlo 	if (!(sc->ure_flags & (URE_FLAG_8156 | URE_FLAG_8156B))) {
1489c096a1a3Skevlo 		for (i = 0; i < URE_TIMEOUT; i++) {
1490c096a1a3Skevlo 			if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
1491c096a1a3Skevlo 			    URE_LINK_LIST_READY)
1492c096a1a3Skevlo 				break;
1493c096a1a3Skevlo 			usbd_delay_ms(sc->ure_udev, 1);
1494c096a1a3Skevlo 		}
1495c096a1a3Skevlo 		if (i == URE_TIMEOUT)
1496c096a1a3Skevlo 			printf("%s: timeout waiting for OOB control\n",
1497c096a1a3Skevlo 			    sc->ure_dev.dv_xname);
1498c096a1a3Skevlo 		URE_SETBIT_2(sc, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA,
1499c096a1a3Skevlo 		    URE_RE_INIT_LL);
1500c096a1a3Skevlo 		for (i = 0; i < URE_TIMEOUT; i++) {
1501c096a1a3Skevlo 			if (ure_read_1(sc, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
1502c096a1a3Skevlo 			    URE_LINK_LIST_READY)
1503c096a1a3Skevlo 				break;
1504c096a1a3Skevlo 			usbd_delay_ms(sc->ure_udev, 1);
1505c096a1a3Skevlo 		}
1506c096a1a3Skevlo 		if (i == URE_TIMEOUT)
1507c096a1a3Skevlo 			printf("%s: timeout waiting for OOB control\n",
1508c096a1a3Skevlo 			    sc->ure_dev.dv_xname);
1509c096a1a3Skevlo 	}
15108a3a1b1fSkevlo 
151155929a15Skevlo 	ure_rxvlan(sc);
15128a3a1b1fSkevlo 
151355929a15Skevlo 	ure_write_2(sc, URE_PLA_RMS, URE_MCU_TYPE_PLA,
151455929a15Skevlo 	    URE_FRAMELEN(ifp->if_mtu));
151555929a15Skevlo 	ure_write_1(sc, URE_PLA_MTPS, URE_MCU_TYPE_PLA, MTPS_JUMBO);
151655929a15Skevlo 
15178a3a1b1fSkevlo 	if (sc->ure_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
15188a3a1b1fSkevlo 		ure_write_2(sc, URE_PLA_RX_FIFO_FULL, URE_MCU_TYPE_PLA,
15198a3a1b1fSkevlo 		    (sc->ure_flags & URE_FLAG_8156) ? 1024 : 512);
15208a3a1b1fSkevlo 		ure_write_2(sc, URE_PLA_RX_FIFO_EMPTY, URE_MCU_TYPE_PLA,
15218a3a1b1fSkevlo 		    (sc->ure_flags & URE_FLAG_8156) ? 2048 : 1024);
15228a3a1b1fSkevlo 
15238a3a1b1fSkevlo 		/* Tx share fifo free credit full threshold. */
15248a3a1b1fSkevlo 		ure_write_2(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA, 8);
15258a3a1b1fSkevlo 		ure_write_2(sc, URE_PLA_TXFIFO_FULL, URE_MCU_TYPE_PLA, 128);
15268a3a1b1fSkevlo 
15278a3a1b1fSkevlo 		if (sc->ure_flags & URE_FLAG_8156)
15288a3a1b1fSkevlo 			URE_SETBIT_2(sc, URE_USB_BMU_CONFIG, URE_MCU_TYPE_USB,
15298a3a1b1fSkevlo 			    URE_ACT_ODMA);
15308a3a1b1fSkevlo 
15318a3a1b1fSkevlo 		/* FIFO settings */
15328a3a1b1fSkevlo 		reg = ure_read_2(sc, URE_PLA_RXFIFO_FULL, URE_MCU_TYPE_PLA);
15338a3a1b1fSkevlo 		reg &= ~URE_RXFIFO_FULL_MASK;
15348a3a1b1fSkevlo 		ure_write_2(sc, URE_PLA_RXFIFO_FULL, URE_MCU_TYPE_PLA,
15358a3a1b1fSkevlo 		    reg | 0x0008);
15368a3a1b1fSkevlo 
15378a3a1b1fSkevlo 		URE_CLRBIT_2(sc, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA,
15388a3a1b1fSkevlo 		    URE_PLA_MCU_SPDWN_EN);
15398a3a1b1fSkevlo 
15408a3a1b1fSkevlo 		URE_CLRBIT_2(sc, URE_USB_SPEED_OPTION, URE_MCU_TYPE_USB,
15418a3a1b1fSkevlo 		    URE_RG_PWRDN_EN | URE_ALL_SPEED_OFF);
15428a3a1b1fSkevlo 
15438a3a1b1fSkevlo 		ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB,
15448a3a1b1fSkevlo 		    0x00600400);
15453dd6ed5fSkevlo 	} else {
1546c096a1a3Skevlo 		URE_SETBIT_2(sc, URE_PLA_TCR0, URE_MCU_TYPE_PLA,
1547c096a1a3Skevlo 		    URE_TCR0_AUTO_FIFO);
154855929a15Skevlo 		ure_reset(sc);
154955929a15Skevlo 
155055929a15Skevlo 		/* Configure Rx FIFO threshold. */
155155929a15Skevlo 		ure_write_4(sc, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA,
155255929a15Skevlo 		    URE_RXFIFO_THR1_NORMAL);
155355929a15Skevlo 		ure_write_2(sc, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA,
155455929a15Skevlo 		    URE_RXFIFO_THR2_NORMAL);
155555929a15Skevlo 		ure_write_2(sc, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA,
155655929a15Skevlo 		    URE_RXFIFO_THR3_NORMAL);
155755929a15Skevlo 
155855929a15Skevlo 		/* Configure Tx FIFO threshold. */
155955929a15Skevlo 		ure_write_4(sc, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA,
156055929a15Skevlo 		    URE_TXFIFO_THR_NORMAL2);
156155929a15Skevlo 
15628a3a1b1fSkevlo 		if (sc->ure_flags & URE_FLAG_8153B) {
156355929a15Skevlo 			ure_write_4(sc, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB,
156455929a15Skevlo 			    URE_RX_THR_B);
15658a3a1b1fSkevlo 
15668a3a1b1fSkevlo 			URE_CLRBIT_2(sc, URE_PLA_MAC_PWR_CTRL3,
15678a3a1b1fSkevlo 			    URE_MCU_TYPE_PLA, URE_PLA_MCU_SPDWN_EN);
15688a3a1b1fSkevlo 		} else {
15698a3a1b1fSkevlo 			URE_SETBIT_1(sc, URE_PLA_CONFIG6, URE_MCU_TYPE_PLA,
15708a3a1b1fSkevlo 			    URE_LANWAKE_CLR_EN);
15718a3a1b1fSkevlo 			URE_CLRBIT_1(sc, URE_PLA_LWAKE_CTRL_REG,
15728a3a1b1fSkevlo 			    URE_MCU_TYPE_PLA, URE_LANWAKE_PIN);
15738a3a1b1fSkevlo 			URE_CLRBIT_2(sc, URE_USB_SSPHYLINK1, URE_MCU_TYPE_USB,
15748a3a1b1fSkevlo 			    URE_DELAY_PHY_PWR_CHG);
15758a3a1b1fSkevlo 		}
157655929a15Skevlo 	}
157755929a15Skevlo 
157855929a15Skevlo 	/* Enable ALDPS. */
157955929a15Skevlo 	ure_ocp_reg_write(sc, URE_OCP_POWER_CFG,
158055929a15Skevlo 	    ure_ocp_reg_read(sc, URE_OCP_POWER_CFG) | URE_EN_ALDPS);
158155929a15Skevlo 
158255929a15Skevlo 	if ((sc->ure_chip & (URE_CHIP_VER_5C20 | URE_CHIP_VER_5C30)) ||
15838a3a1b1fSkevlo 	    (sc->ure_flags & (URE_FLAG_8156 | URE_FLAG_8156B)))
158455929a15Skevlo 		URE_SETBIT_2(sc, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB,
158555929a15Skevlo 		    URE_U2P3_ENABLE);
158655929a15Skevlo 
15878a3a1b1fSkevlo 	if (sc->ure_flags & (URE_FLAG_8153B | URE_FLAG_8156 | URE_FLAG_8156B)) {
15888a3a1b1fSkevlo 		if (sc->ure_udev->speed == USB_SPEED_SUPER)
158955929a15Skevlo 			URE_SETBIT_2(sc, URE_USB_LPM_CONFIG, URE_MCU_TYPE_USB,
159055929a15Skevlo 			    LPM_U1U2_EN);
159155929a15Skevlo 	} else {
159255929a15Skevlo 		memset(u1u2, 0xff, sizeof(u1u2));
159355929a15Skevlo 		ure_write_mem(sc, URE_USB_TOLERANCE, URE_BYTE_EN_SIX_BYTES,
159455929a15Skevlo 		    u1u2, sizeof(u1u2));
159555929a15Skevlo 	}
159655929a15Skevlo }
159755929a15Skevlo 
15988a3a1b1fSkevlo uint16_t
ure_rtl8153_phy_status(struct ure_softc * sc,int desired)15998a3a1b1fSkevlo ure_rtl8153_phy_status(struct ure_softc *sc, int desired)
160055929a15Skevlo {
160155929a15Skevlo 	uint16_t	reg;
160255929a15Skevlo 	int		i;
160355929a15Skevlo 
160455929a15Skevlo 	for (i = 0; i < 500; i++) {
160555929a15Skevlo 		reg = ure_ocp_reg_read(sc, URE_OCP_PHY_STATUS) &
160655929a15Skevlo 		    URE_PHY_STAT_MASK;
16078a3a1b1fSkevlo 		if (desired) {
16088a3a1b1fSkevlo 			if (reg == desired)
160955929a15Skevlo 				break;
161055929a15Skevlo 		} else {
161155929a15Skevlo 			if (reg == URE_PHY_STAT_LAN_ON ||
161255929a15Skevlo 			    reg == URE_PHY_STAT_PWRDN ||
161355929a15Skevlo 			    reg == URE_PHY_STAT_EXT_INIT)
161455929a15Skevlo 				break;
161555929a15Skevlo 		}
161655929a15Skevlo 		usbd_delay_ms(sc->ure_udev, 20);
161755929a15Skevlo 	}
161855929a15Skevlo 	if (i == 500)
161955929a15Skevlo 		printf("%s: timeout waiting for phy to stabilize\n",
162055929a15Skevlo 		    sc->ure_dev.dv_xname);
16218a3a1b1fSkevlo 
16228a3a1b1fSkevlo 	return reg;
16238a3a1b1fSkevlo }
16248a3a1b1fSkevlo 
16258a3a1b1fSkevlo void
ure_wait_for_flash(struct ure_softc * sc)16268a3a1b1fSkevlo ure_wait_for_flash(struct ure_softc *sc)
16278a3a1b1fSkevlo {
16288a3a1b1fSkevlo 	int i;
16298a3a1b1fSkevlo 
16308a3a1b1fSkevlo 	if ((ure_read_2(sc, URE_PLA_GPHY_CTRL, URE_MCU_TYPE_PLA) &
16318a3a1b1fSkevlo 	    URE_GPHY_FLASH) &&
16328a3a1b1fSkevlo 	    !(ure_read_2(sc, URE_USB_GPHY_CTRL, URE_MCU_TYPE_USB) &
16338a3a1b1fSkevlo 	    URE_BYPASS_FLASH)) {
16348a3a1b1fSkevlo 	    	for (i = 0; i < 100; i++) {
16358a3a1b1fSkevlo 			if (ure_read_2(sc, URE_USB_GPHY_CTRL,
16368a3a1b1fSkevlo 			    URE_MCU_TYPE_USB) & URE_GPHY_PATCH_DONE)
16378a3a1b1fSkevlo 				break;
16388a3a1b1fSkevlo 			DELAY(1000);
16398a3a1b1fSkevlo 		}
16408a3a1b1fSkevlo 		if (i == 100)
16418a3a1b1fSkevlo 			printf("%s: timeout waiting for loading flash\n",
16428a3a1b1fSkevlo 			    sc->ure_dev.dv_xname);
16438a3a1b1fSkevlo 	}
164455929a15Skevlo }
164555929a15Skevlo 
164655929a15Skevlo void
ure_reset_bmu(struct ure_softc * sc)164755929a15Skevlo ure_reset_bmu(struct ure_softc *sc)
164855929a15Skevlo {
16498a3a1b1fSkevlo 	uint8_t	reg;
16508a3a1b1fSkevlo 
16518a3a1b1fSkevlo 	reg = ure_read_1(sc, URE_USB_BMU_RESET, URE_MCU_TYPE_USB);
16528a3a1b1fSkevlo 	reg &= ~(BMU_RESET_EP_IN | BMU_RESET_EP_OUT);
16538a3a1b1fSkevlo 	ure_write_1(sc, URE_USB_BMU_RESET, URE_MCU_TYPE_USB, reg);
16548a3a1b1fSkevlo 	reg |= BMU_RESET_EP_IN | BMU_RESET_EP_OUT;
16558a3a1b1fSkevlo 	ure_write_1(sc, URE_USB_BMU_RESET, URE_MCU_TYPE_USB, reg);
165655929a15Skevlo }
165755929a15Skevlo 
165855929a15Skevlo void
ure_disable_teredo(struct ure_softc * sc)165955929a15Skevlo ure_disable_teredo(struct ure_softc *sc)
166055929a15Skevlo {
16618a3a1b1fSkevlo 	if (sc->ure_flags & (URE_FLAG_8153B | URE_FLAG_8156 | URE_FLAG_8156B))
166255929a15Skevlo 		ure_write_1(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA, 0xff);
166355929a15Skevlo 	else {
166455929a15Skevlo 		URE_CLRBIT_2(sc, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA,
166555929a15Skevlo 		    URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK |
166655929a15Skevlo 		    URE_OOB_TEREDO_EN);
166755929a15Skevlo 	}
166855929a15Skevlo 	ure_write_2(sc, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA, URE_WDT6_SET_MODE);
166955929a15Skevlo 	ure_write_2(sc, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0);
167055929a15Skevlo 	ure_write_4(sc, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0);
167142c54c93Sjmatthew }
167242c54c93Sjmatthew 
167342c54c93Sjmatthew int
ure_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)167442c54c93Sjmatthew ure_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
167542c54c93Sjmatthew {
1676114e9c63Sderaadt 	struct ure_softc	*sc = ifp->if_softc;
167742c54c93Sjmatthew 	struct ifreq		*ifr = (struct ifreq *)data;
167842c54c93Sjmatthew 	int			s, error = 0;
167942c54c93Sjmatthew 
168042c54c93Sjmatthew 	s = splnet();
168142c54c93Sjmatthew 
168242c54c93Sjmatthew 	switch (cmd) {
168342c54c93Sjmatthew 	case SIOCSIFADDR:
168442c54c93Sjmatthew 		ifp->if_flags |= IFF_UP;
168542c54c93Sjmatthew 		if (!(ifp->if_flags & IFF_RUNNING))
168642c54c93Sjmatthew 			ure_init(sc);
168742c54c93Sjmatthew 		break;
168842c54c93Sjmatthew 
168942c54c93Sjmatthew 	case SIOCSIFFLAGS:
169042c54c93Sjmatthew 		if (ifp->if_flags & IFF_UP) {
169142c54c93Sjmatthew 			if (ifp->if_flags & IFF_RUNNING)
169242c54c93Sjmatthew 				error = ENETRESET;
169342c54c93Sjmatthew 			else
169442c54c93Sjmatthew 				ure_init(sc);
169542c54c93Sjmatthew 		} else {
169642c54c93Sjmatthew 			if (ifp->if_flags & IFF_RUNNING)
169742c54c93Sjmatthew 				ure_stop(sc);
169842c54c93Sjmatthew 		}
169942c54c93Sjmatthew 		break;
170042c54c93Sjmatthew 
170142c54c93Sjmatthew 	case SIOCGIFMEDIA:
170242c54c93Sjmatthew 	case SIOCSIFMEDIA:
17038a3a1b1fSkevlo 		if (sc->ure_flags & (URE_FLAG_8156 | URE_FLAG_8156B))
1704c096a1a3Skevlo 			error = ifmedia_ioctl(ifp, ifr, &sc->ure_ifmedia, cmd);
1705c096a1a3Skevlo 		else
1706c096a1a3Skevlo 			error = ifmedia_ioctl(ifp, ifr, &sc->ure_mii.mii_media,
1707c096a1a3Skevlo 			    cmd);
170842c54c93Sjmatthew 		break;
170942c54c93Sjmatthew 
171042c54c93Sjmatthew 	default:
171142c54c93Sjmatthew 		error = ether_ioctl(ifp, &sc->ure_ac, cmd, data);
171242c54c93Sjmatthew 	}
171342c54c93Sjmatthew 
171442c54c93Sjmatthew 	if (error == ENETRESET) {
171542c54c93Sjmatthew 		if (ifp->if_flags & IFF_RUNNING)
171642c54c93Sjmatthew 			ure_iff(sc);
171742c54c93Sjmatthew 		error = 0;
171842c54c93Sjmatthew 	}
171942c54c93Sjmatthew 
172042c54c93Sjmatthew 	splx(s);
172142c54c93Sjmatthew 
172242c54c93Sjmatthew 	return (error);
172342c54c93Sjmatthew }
172442c54c93Sjmatthew 
172542c54c93Sjmatthew int
ure_match(struct device * parent,void * match,void * aux)172642c54c93Sjmatthew ure_match(struct device *parent, void *match, void *aux)
172742c54c93Sjmatthew {
172842c54c93Sjmatthew 	struct usb_attach_arg	*uaa = aux;
172942c54c93Sjmatthew 
173042c54c93Sjmatthew 	if (uaa->iface == NULL || uaa->configno != 1)
173155929a15Skevlo 		return (UMATCH_NONE);
173242c54c93Sjmatthew 
173342c54c93Sjmatthew 	return (usb_lookup(ure_devs, uaa->vendor, uaa->product) != NULL ?
173442c54c93Sjmatthew 	    UMATCH_VENDOR_PRODUCT_CONF_IFACE : UMATCH_NONE);
173542c54c93Sjmatthew }
173642c54c93Sjmatthew 
173742c54c93Sjmatthew void
ure_attach(struct device * parent,struct device * self,void * aux)173842c54c93Sjmatthew ure_attach(struct device *parent, struct device *self, void *aux)
173942c54c93Sjmatthew {
174042c54c93Sjmatthew 	struct ure_softc		*sc = (struct ure_softc *)self;
174142c54c93Sjmatthew 	struct usb_attach_arg		*uaa = aux;
174242c54c93Sjmatthew 	usb_interface_descriptor_t	*id;
174342c54c93Sjmatthew 	usb_endpoint_descriptor_t	*ed;
174442c54c93Sjmatthew 	u_char				eaddr[8]; /* 4byte padded */
174542c54c93Sjmatthew 	struct ifnet			*ifp;
1746c096a1a3Skevlo 	int				i, mii_flags = 0, s;
174742c54c93Sjmatthew 	uint16_t			ver;
174842c54c93Sjmatthew 
174942c54c93Sjmatthew 	sc->ure_udev = uaa->device;
175042c54c93Sjmatthew 	sc->ure_iface = uaa->iface;
175142c54c93Sjmatthew 
175242c54c93Sjmatthew 	usb_init_task(&sc->ure_tick_task, ure_tick_task, sc,
175342c54c93Sjmatthew 	    USB_TASK_TYPE_GENERIC);
175442c54c93Sjmatthew 
175542c54c93Sjmatthew 	id = usbd_get_interface_descriptor(sc->ure_iface);
175642c54c93Sjmatthew 
175742c54c93Sjmatthew 	for (i = 0; i < id->bNumEndpoints; i++) {
175842c54c93Sjmatthew 		ed = usbd_interface2endpoint_descriptor(sc->ure_iface, i);
175942c54c93Sjmatthew 		if (!ed) {
176042c54c93Sjmatthew 			printf("%s: couldn't get ep %d\n",
176142c54c93Sjmatthew 			    sc->ure_dev.dv_xname, i);
176242c54c93Sjmatthew 			return;
176342c54c93Sjmatthew 		}
176442c54c93Sjmatthew 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
176542c54c93Sjmatthew 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
176642c54c93Sjmatthew 			sc->ure_ed[URE_ENDPT_RX] = ed->bEndpointAddress;
176742c54c93Sjmatthew 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
176842c54c93Sjmatthew 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
176942c54c93Sjmatthew 			sc->ure_ed[URE_ENDPT_TX] = ed->bEndpointAddress;
177042c54c93Sjmatthew 		}
177142c54c93Sjmatthew 	}
177242c54c93Sjmatthew 
1773fd07ab7eSkevlo 	sc->ure_txbufsz = URE_TX_BUFSZ;
1774fd07ab7eSkevlo 	sc->ure_rxbufsz = URE_8153_RX_BUFSZ;
1775c096a1a3Skevlo 
177642c54c93Sjmatthew 	s = splnet();
177742c54c93Sjmatthew 
177842c54c93Sjmatthew 	sc->ure_phyno = 0;
177942c54c93Sjmatthew 	printf("%s: ", sc->ure_dev.dv_xname);
178042c54c93Sjmatthew 
178142c54c93Sjmatthew 	ver = ure_read_2(sc, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK;
178242c54c93Sjmatthew 	switch (ver) {
178342c54c93Sjmatthew 	case 0x4c00:
1784fd07ab7eSkevlo 		sc->ure_flags = URE_FLAG_8152;
1785fd07ab7eSkevlo 		sc->ure_rxbufsz = URE_8152_RX_BUFSZ;
178642c54c93Sjmatthew 		sc->ure_chip |= URE_CHIP_VER_4C00;
1787c096a1a3Skevlo 		printf("RTL8152 (0x4c00)");
178842c54c93Sjmatthew 		break;
178942c54c93Sjmatthew 	case 0x4c10:
1790fd07ab7eSkevlo 		sc->ure_flags = URE_FLAG_8152;
1791fd07ab7eSkevlo 		sc->ure_rxbufsz = URE_8152_RX_BUFSZ;
179242c54c93Sjmatthew 		sc->ure_chip |= URE_CHIP_VER_4C10;
1793c096a1a3Skevlo 		printf("RTL8152 (0x4c10)");
1794794a317fSkettenis 		break;
1795794a317fSkettenis 	case 0x5c00:
1796794a317fSkettenis 		sc->ure_chip |= URE_CHIP_VER_5C00;
1797c096a1a3Skevlo 		printf("RTL8153 (0x5c00)");
1798794a317fSkettenis 		break;
1799794a317fSkettenis 	case 0x5c10:
1800794a317fSkettenis 		sc->ure_chip |= URE_CHIP_VER_5C10;
1801c096a1a3Skevlo 		printf("RTL8153 (0x5c10)");
1802794a317fSkettenis 		break;
1803794a317fSkettenis 	case 0x5c20:
1804794a317fSkettenis 		sc->ure_chip |= URE_CHIP_VER_5C20;
1805c096a1a3Skevlo 		printf("RTL8153 (0x5c20)");
1806794a317fSkettenis 		break;
1807794a317fSkettenis 	case 0x5c30:
1808794a317fSkettenis 		sc->ure_chip |= URE_CHIP_VER_5C30;
1809c096a1a3Skevlo 		printf("RTL8153 (0x5c30)");
181042c54c93Sjmatthew 		break;
181155929a15Skevlo 	case 0x6000:
181255929a15Skevlo 		sc->ure_flags = URE_FLAG_8153B;
1813c096a1a3Skevlo 		printf("RTL8153B (0x6000)");
181455929a15Skevlo 		break;
181555929a15Skevlo 	case 0x6010:
181655929a15Skevlo 		sc->ure_flags = URE_FLAG_8153B;
1817c096a1a3Skevlo 		printf("RTL8153B (0x6010)");
1818c096a1a3Skevlo 		break;
1819c096a1a3Skevlo 	case 0x7020:
1820fd07ab7eSkevlo 		sc->ure_flags = URE_FLAG_8156;
1821c096a1a3Skevlo 		printf("RTL8156 (0x7020)");
1822c096a1a3Skevlo 		break;
1823c096a1a3Skevlo 	case 0x7030:
1824fd07ab7eSkevlo 		sc->ure_flags = URE_FLAG_8156;
1825c096a1a3Skevlo 		printf("RTL8156 (0x7030)");
182655929a15Skevlo 		break;
18278a3a1b1fSkevlo 	case 0x7410:
18288a3a1b1fSkevlo 		sc->ure_flags = URE_FLAG_8156B;
18298a3a1b1fSkevlo 		printf("RTL8156B (0x7410)");
18308a3a1b1fSkevlo 		break;
18313dd6ed5fSkevlo 	case 0x7420:
18323dd6ed5fSkevlo 		sc->ure_flags = URE_FLAG_8156B;
18333dd6ed5fSkevlo 		sc->ure_chip = URE_CHIP_VER_7420;
18343dd6ed5fSkevlo 		printf("RTL8153D (0x7420)");
18353dd6ed5fSkevlo 		break;
183642c54c93Sjmatthew 	default:
183742c54c93Sjmatthew 		printf(", unknown ver %02x", ver);
183842c54c93Sjmatthew 		break;
183942c54c93Sjmatthew 	}
184042c54c93Sjmatthew 
1841794a317fSkettenis 	if (sc->ure_flags & URE_FLAG_8152)
1842794a317fSkettenis 		ure_rtl8152_init(sc);
18438a3a1b1fSkevlo 	else if (sc->ure_flags & (URE_FLAG_8153B | URE_FLAG_8156 |
18448a3a1b1fSkevlo 	    URE_FLAG_8156B))
184555929a15Skevlo 		ure_rtl8153b_init(sc);
1846794a317fSkettenis 	else
1847794a317fSkettenis 		ure_rtl8153_init(sc);
1848794a317fSkettenis 
1849794a317fSkettenis 	if (sc->ure_chip & URE_CHIP_VER_4C00)
1850794a317fSkettenis 		ure_read_mem(sc, URE_PLA_IDR, URE_MCU_TYPE_PLA, eaddr,
1851794a317fSkettenis 		    sizeof(eaddr));
1852794a317fSkettenis 	else
1853794a317fSkettenis 		ure_read_mem(sc, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr,
1854794a317fSkettenis 		    sizeof(eaddr));
1855794a317fSkettenis 
185642c54c93Sjmatthew 	printf(", address %s\n", ether_sprintf(eaddr));
185742c54c93Sjmatthew 
185842c54c93Sjmatthew 	bcopy(eaddr, (char *)&sc->ure_ac.ac_enaddr, ETHER_ADDR_LEN);
185942c54c93Sjmatthew 
186042c54c93Sjmatthew 	ifp = &sc->ure_ac.ac_if;
186142c54c93Sjmatthew 	ifp->if_softc = sc;
186242c54c93Sjmatthew 	strlcpy(ifp->if_xname, sc->ure_dev.dv_xname, IFNAMSIZ);
186342c54c93Sjmatthew 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
186442c54c93Sjmatthew 	ifp->if_ioctl = ure_ioctl;
186542c54c93Sjmatthew 	ifp->if_start = ure_start;
1866c096a1a3Skevlo 	ifp->if_watchdog = ure_watchdog;
186742c54c93Sjmatthew 
1868c096a1a3Skevlo 	ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_CSUM_IPv4 |
1869c096a1a3Skevlo 	    IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4;
187042c54c93Sjmatthew 
1871c096a1a3Skevlo #if NVLAN > 0
1872c096a1a3Skevlo 	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
1873c096a1a3Skevlo #endif
1874c096a1a3Skevlo 
18758a3a1b1fSkevlo 	if (sc->ure_flags & (URE_FLAG_8156 | URE_FLAG_8156B)) {
1876c096a1a3Skevlo 		ifmedia_init(&sc->ure_ifmedia, IFM_IMASK, ure_ifmedia_upd,
1877c096a1a3Skevlo 		    ure_ifmedia_sts);
1878c096a1a3Skevlo 		ure_add_media_types(sc);
1879c096a1a3Skevlo 		ifmedia_add(&sc->ure_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
1880c096a1a3Skevlo 		ifmedia_set(&sc->ure_ifmedia, IFM_ETHER | IFM_AUTO);
1881c096a1a3Skevlo 		sc->ure_ifmedia.ifm_media = sc->ure_ifmedia.ifm_cur->ifm_media;
1882c096a1a3Skevlo 	} else {
1883c096a1a3Skevlo 		rw_init(&sc->ure_mii_lock, "uremii");
1884c096a1a3Skevlo 
1885c096a1a3Skevlo 		sc->ure_mii.mii_ifp = ifp;
1886c096a1a3Skevlo 		sc->ure_mii.mii_readreg = ure_miibus_readreg;
1887c096a1a3Skevlo 		sc->ure_mii.mii_writereg = ure_miibus_writereg;
1888c096a1a3Skevlo 		sc->ure_mii.mii_statchg = ure_miibus_statchg;
1889c096a1a3Skevlo 		sc->ure_mii.mii_flags = MIIF_AUTOTSLEEP;
1890c096a1a3Skevlo 
1891c096a1a3Skevlo 		ifmedia_init(&sc->ure_mii.mii_media, 0, ure_ifmedia_upd,
1892c096a1a3Skevlo 		    ure_ifmedia_sts);
189355929a15Skevlo 		if (!(sc->ure_flags & URE_FLAG_8152))
189455929a15Skevlo 			mii_flags |= MIIF_DOPAUSE;
1895c096a1a3Skevlo 		mii_attach(self, &sc->ure_mii, 0xffffffff, sc->ure_phyno,
1896c096a1a3Skevlo 		    MII_OFFSET_ANY, mii_flags);
1897c096a1a3Skevlo 		if (LIST_FIRST(&sc->ure_mii.mii_phys) == NULL) {
1898c096a1a3Skevlo 			ifmedia_add(&sc->ure_mii.mii_media,
1899c096a1a3Skevlo 			    IFM_ETHER | IFM_NONE, 0, NULL);
1900c096a1a3Skevlo 			ifmedia_set(&sc->ure_mii.mii_media,
1901c096a1a3Skevlo 			    IFM_ETHER | IFM_NONE);
190242c54c93Sjmatthew 		} else
1903c096a1a3Skevlo 			ifmedia_set(&sc->ure_mii.mii_media,
1904c096a1a3Skevlo 			    IFM_ETHER | IFM_AUTO);
1905c096a1a3Skevlo 	}
190642c54c93Sjmatthew 
190742c54c93Sjmatthew 	if_attach(ifp);
190842c54c93Sjmatthew 	ether_ifattach(ifp);
190942c54c93Sjmatthew 
191042c54c93Sjmatthew 	timeout_set(&sc->ure_stat_ch, ure_tick, sc);
191142c54c93Sjmatthew 
191242c54c93Sjmatthew 	splx(s);
191342c54c93Sjmatthew }
191442c54c93Sjmatthew 
191542c54c93Sjmatthew int
ure_detach(struct device * self,int flags)191642c54c93Sjmatthew ure_detach(struct device *self, int flags)
191742c54c93Sjmatthew {
191842c54c93Sjmatthew 	struct ure_softc	*sc = (struct ure_softc *)self;
191942c54c93Sjmatthew 	struct ifnet		*ifp = &sc->ure_ac.ac_if;
192042c54c93Sjmatthew 	int			s;
192142c54c93Sjmatthew 
192242c54c93Sjmatthew 	if (timeout_initialized(&sc->ure_stat_ch))
192342c54c93Sjmatthew 		timeout_del(&sc->ure_stat_ch);
192442c54c93Sjmatthew 
192542c54c93Sjmatthew 	if (sc->ure_ep[URE_ENDPT_TX] != NULL)
192642c54c93Sjmatthew 		usbd_abort_pipe(sc->ure_ep[URE_ENDPT_TX]);
192742c54c93Sjmatthew 	if (sc->ure_ep[URE_ENDPT_RX] != NULL)
192842c54c93Sjmatthew 		usbd_abort_pipe(sc->ure_ep[URE_ENDPT_RX]);
192942c54c93Sjmatthew 
193042c54c93Sjmatthew 	usb_rem_task(sc->ure_udev, &sc->ure_tick_task);
193142c54c93Sjmatthew 
193242c54c93Sjmatthew 	s = splusb();
193342c54c93Sjmatthew 
193442c54c93Sjmatthew 	if (--sc->ure_refcnt >= 0) {
193542c54c93Sjmatthew 		usb_detach_wait(&sc->ure_dev);
193642c54c93Sjmatthew 	}
193742c54c93Sjmatthew 
193842c54c93Sjmatthew 	if (ifp->if_flags & IFF_RUNNING)
193942c54c93Sjmatthew 		ure_stop(sc);
194042c54c93Sjmatthew 
194142c54c93Sjmatthew 	mii_detach(&sc->ure_mii, MII_PHY_ANY, MII_OFFSET_ANY);
194242c54c93Sjmatthew 	ifmedia_delete_instance(&sc->ure_mii.mii_media, IFM_INST_ANY);
194342c54c93Sjmatthew 	if (ifp->if_softc != NULL) {
194442c54c93Sjmatthew 		ether_ifdetach(ifp);
194542c54c93Sjmatthew 		if_detach(ifp);
194642c54c93Sjmatthew 	}
194742c54c93Sjmatthew 
194842c54c93Sjmatthew 	splx(s);
194942c54c93Sjmatthew 
195042c54c93Sjmatthew 	return 0;
195142c54c93Sjmatthew }
195242c54c93Sjmatthew 
195342c54c93Sjmatthew void
ure_tick_task(void * xsc)195442c54c93Sjmatthew ure_tick_task(void *xsc)
195542c54c93Sjmatthew {
195642c54c93Sjmatthew 	struct ure_softc	*sc = xsc;
195742c54c93Sjmatthew 	struct mii_data		*mii;
1958fd07ab7eSkevlo 	int			s;
195942c54c93Sjmatthew 
196042c54c93Sjmatthew 	if (sc == NULL)
196142c54c93Sjmatthew 		return;
196242c54c93Sjmatthew 
196342c54c93Sjmatthew 	if (usbd_is_dying(sc->ure_udev))
196442c54c93Sjmatthew 		return;
196542c54c93Sjmatthew 	mii = &sc->ure_mii;
196642c54c93Sjmatthew 
196742c54c93Sjmatthew 	s = splnet();
19688a3a1b1fSkevlo 	if (sc->ure_flags & (URE_FLAG_8156 | URE_FLAG_8156B))
1969c096a1a3Skevlo 		ure_link_state(sc);
1970c096a1a3Skevlo 	else {
197142c54c93Sjmatthew 		mii_tick(mii);
197242c54c93Sjmatthew 		if ((sc->ure_flags & URE_FLAG_LINK) == 0)
197342c54c93Sjmatthew 			ure_miibus_statchg(&sc->ure_dev);
1974c096a1a3Skevlo 	}
197542c54c93Sjmatthew 	timeout_add_sec(&sc->ure_stat_ch, 1);
197642c54c93Sjmatthew 	splx(s);
197742c54c93Sjmatthew }
197842c54c93Sjmatthew 
197942c54c93Sjmatthew void
ure_lock_mii(struct ure_softc * sc)198042c54c93Sjmatthew ure_lock_mii(struct ure_softc *sc)
198142c54c93Sjmatthew {
198242c54c93Sjmatthew 	sc->ure_refcnt++;
198342c54c93Sjmatthew 	rw_enter_write(&sc->ure_mii_lock);
198442c54c93Sjmatthew }
198542c54c93Sjmatthew 
198642c54c93Sjmatthew void
ure_unlock_mii(struct ure_softc * sc)198742c54c93Sjmatthew ure_unlock_mii(struct ure_softc *sc)
198842c54c93Sjmatthew {
198942c54c93Sjmatthew 	rw_exit_write(&sc->ure_mii_lock);
199042c54c93Sjmatthew 	if (--sc->ure_refcnt < 0)
199142c54c93Sjmatthew 		usb_detach_wakeup(&sc->ure_dev);
199242c54c93Sjmatthew }
199342c54c93Sjmatthew 
199442c54c93Sjmatthew void
ure_rxeof(struct usbd_xfer * xfer,void * priv,usbd_status status)199542c54c93Sjmatthew ure_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
199642c54c93Sjmatthew {
199742c54c93Sjmatthew 	struct ure_chain	*c = (struct ure_chain *)priv;
199842c54c93Sjmatthew 	struct ure_softc	*sc = c->uc_sc;
199942c54c93Sjmatthew 	struct ifnet		*ifp = &sc->ure_ac.ac_if;
200042c54c93Sjmatthew 	u_char			*buf = c->uc_buf;
2001c096a1a3Skevlo 	uint32_t		cflags, rxvlan, total_len;
200242c54c93Sjmatthew 	struct mbuf_list	ml = MBUF_LIST_INITIALIZER();
200342c54c93Sjmatthew 	struct mbuf		*m;
2004c096a1a3Skevlo 	int			pktlen = 0, s;
200542c54c93Sjmatthew 	struct ure_rxpkt	rxhdr;
200642c54c93Sjmatthew 
200742c54c93Sjmatthew 	if (usbd_is_dying(sc->ure_udev))
200842c54c93Sjmatthew 		return;
200942c54c93Sjmatthew 
201042c54c93Sjmatthew 	if (!(ifp->if_flags & IFF_RUNNING))
201142c54c93Sjmatthew 		return;
201242c54c93Sjmatthew 
201342c54c93Sjmatthew 	if (status != USBD_NORMAL_COMPLETION) {
201442c54c93Sjmatthew 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
201542c54c93Sjmatthew 			return;
201642c54c93Sjmatthew 		if (usbd_ratecheck(&sc->ure_rx_notice)) {
201742c54c93Sjmatthew 			printf("%s: usb errors on rx: %s\n",
201842c54c93Sjmatthew 				sc->ure_dev.dv_xname, usbd_errstr(status));
201942c54c93Sjmatthew 		}
202042c54c93Sjmatthew 		if (status == USBD_STALLED)
2021c096a1a3Skevlo 			usbd_clear_endpoint_stall_async(
2022c096a1a3Skevlo 			    sc->ure_ep[URE_ENDPT_RX]);
202342c54c93Sjmatthew 		goto done;
202442c54c93Sjmatthew 	}
202542c54c93Sjmatthew 
202642c54c93Sjmatthew 	usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL);
202742c54c93Sjmatthew 	DPRINTFN(3, ("received %d bytes\n", total_len));
202842c54c93Sjmatthew 
202942c54c93Sjmatthew 	do {
203042c54c93Sjmatthew 		if (total_len < sizeof(rxhdr)) {
203142c54c93Sjmatthew 			DPRINTF(("too few bytes left for a packet header\n"));
203242c54c93Sjmatthew 			ifp->if_ierrors++;
203342c54c93Sjmatthew 			goto done;
203442c54c93Sjmatthew 		}
203542c54c93Sjmatthew 
2036fd07ab7eSkevlo 		buf += roundup(pktlen, URE_RX_BUF_ALIGN);
203742c54c93Sjmatthew 
203842c54c93Sjmatthew 		memcpy(&rxhdr, buf, sizeof(rxhdr));
203942c54c93Sjmatthew 		total_len -= sizeof(rxhdr);
204042c54c93Sjmatthew 
2041c096a1a3Skevlo 		pktlen = letoh32(rxhdr.ure_pktlen) & URE_RXPKT_LEN_MASK;
204242c54c93Sjmatthew 		DPRINTFN(4, ("next packet is %d bytes\n", pktlen));
204342c54c93Sjmatthew 		if (pktlen > total_len) {
204442c54c93Sjmatthew 			DPRINTF(("not enough bytes left for next packet\n"));
204542c54c93Sjmatthew 			ifp->if_ierrors++;
204642c54c93Sjmatthew 			goto done;
204742c54c93Sjmatthew 		}
204842c54c93Sjmatthew 
2049fd07ab7eSkevlo 		total_len -= roundup(pktlen, URE_RX_BUF_ALIGN);
205042c54c93Sjmatthew 		buf += sizeof(rxhdr);
205142c54c93Sjmatthew 
20528a3a1b1fSkevlo 		m = m_devget(buf, pktlen - ETHER_CRC_LEN, ETHER_ALIGN);
205342c54c93Sjmatthew 		if (m == NULL) {
205442c54c93Sjmatthew 			DPRINTF(("unable to allocate mbuf for next packet\n"));
205542c54c93Sjmatthew 			ifp->if_ierrors++;
205642c54c93Sjmatthew 			goto done;
205742c54c93Sjmatthew 		}
205842c54c93Sjmatthew 
2059c096a1a3Skevlo 		cflags = letoh32(rxhdr.ure_csum);
2060c096a1a3Skevlo 		rxvlan = letoh32(rxhdr.ure_vlan);
2061c096a1a3Skevlo 
2062c096a1a3Skevlo 		/* Check IP header checksum. */
2063c096a1a3Skevlo 		if ((rxvlan & URE_RXPKT_IPV4) &&
2064c096a1a3Skevlo 		    !(cflags & URE_RXPKT_IPSUMBAD))
2065c096a1a3Skevlo 			m->m_pkthdr.csum_flags |= M_IPV4_CSUM_IN_OK;
2066c096a1a3Skevlo 
2067c096a1a3Skevlo 		/* Check TCP/UDP checksum. */
2068c096a1a3Skevlo 		if ((rxvlan & (URE_RXPKT_IPV4 | URE_RXPKT_IPV6)) &&
2069c096a1a3Skevlo 		    (((rxvlan & URE_RXPKT_TCP) &&
2070c096a1a3Skevlo 		    !(cflags & URE_RXPKT_TCPSUMBAD)) ||
2071c096a1a3Skevlo 		    ((rxvlan & URE_RXPKT_UDP) &&
2072c096a1a3Skevlo 		    !(cflags & URE_RXPKT_UDPSUMBAD))))
2073c096a1a3Skevlo 			 m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_OK |
2074c096a1a3Skevlo 			     M_UDP_CSUM_IN_OK;
2075c096a1a3Skevlo #if NVLAN > 0
2076c096a1a3Skevlo 		if (rxvlan & URE_RXPKT_VLAN_TAG) {
2077c096a1a3Skevlo 			m->m_pkthdr.ether_vtag =
2078c096a1a3Skevlo 			    swap16(rxvlan & URE_RXPKT_VLAN_DATA);
2079c096a1a3Skevlo 			m->m_flags |= M_VLANTAG;
2080c096a1a3Skevlo 		}
2081c096a1a3Skevlo #endif
2082c096a1a3Skevlo 
208342c54c93Sjmatthew 		ml_enqueue(&ml, m);
208442c54c93Sjmatthew 	} while (total_len > 0);
208542c54c93Sjmatthew 
208642c54c93Sjmatthew done:
208742c54c93Sjmatthew 	s = splnet();
208842c54c93Sjmatthew 	if_input(ifp, &ml);
208942c54c93Sjmatthew 	splx(s);
2090c096a1a3Skevlo 	memset(c->uc_buf, 0, sc->ure_rxbufsz);
209142c54c93Sjmatthew 
209242c54c93Sjmatthew 	usbd_setup_xfer(xfer, sc->ure_ep[URE_ENDPT_RX], c, c->uc_buf,
2093c096a1a3Skevlo 	    sc->ure_rxbufsz, USBD_SHORT_XFER_OK | USBD_NO_COPY,
209442c54c93Sjmatthew 	    USBD_NO_TIMEOUT, ure_rxeof);
209542c54c93Sjmatthew 	usbd_transfer(xfer);
209642c54c93Sjmatthew }
209742c54c93Sjmatthew 
209842c54c93Sjmatthew 
209942c54c93Sjmatthew void
ure_txeof(struct usbd_xfer * xfer,void * priv,usbd_status status)210042c54c93Sjmatthew ure_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status)
210142c54c93Sjmatthew {
210242c54c93Sjmatthew 	struct ure_softc	*sc;
210342c54c93Sjmatthew 	struct ure_chain	*c;
210442c54c93Sjmatthew 	struct ifnet		*ifp;
210542c54c93Sjmatthew 	int			s;
210642c54c93Sjmatthew 
210742c54c93Sjmatthew 	c = priv;
210842c54c93Sjmatthew 	sc = c->uc_sc;
210942c54c93Sjmatthew 	ifp = &sc->ure_ac.ac_if;
211042c54c93Sjmatthew 
211142c54c93Sjmatthew 	if (usbd_is_dying(sc->ure_udev))
211242c54c93Sjmatthew 		return;
211342c54c93Sjmatthew 
2114fd07ab7eSkevlo 	if (status != USBD_NORMAL_COMPLETION)
2115fd07ab7eSkevlo 		DPRINTF(("%s: %s uc_idx=%u : %s\n", sc->ure_dev.dv_xname,
2116fd07ab7eSkevlo 			__func__, c->uc_idx, usbd_errstr(status)));
211742c54c93Sjmatthew 
211842c54c93Sjmatthew 	s = splnet();
2119fd07ab7eSkevlo 
2120fd07ab7eSkevlo 	c->uc_cnt = 0;
2121fd07ab7eSkevlo 	c->uc_buflen = 0;
2122fd07ab7eSkevlo 
2123fd07ab7eSkevlo 	SLIST_INSERT_HEAD(&sc->ure_cdata.ure_tx_free, c, uc_list);
2124fd07ab7eSkevlo 
212542c54c93Sjmatthew 	if (status != USBD_NORMAL_COMPLETION) {
212642c54c93Sjmatthew 		if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) {
212742c54c93Sjmatthew 			splx(s);
212842c54c93Sjmatthew 			return;
212942c54c93Sjmatthew 		}
2130fd07ab7eSkevlo 
213142c54c93Sjmatthew 		ifp->if_oerrors++;
213242c54c93Sjmatthew 		printf("%s: usb error on tx: %s\n", sc->ure_dev.dv_xname,
213342c54c93Sjmatthew 		    usbd_errstr(status));
2134fd07ab7eSkevlo 
213542c54c93Sjmatthew 		if (status == USBD_STALLED)
2136c096a1a3Skevlo 			usbd_clear_endpoint_stall_async(
2137c096a1a3Skevlo 			    sc->ure_ep[URE_ENDPT_TX]);
213842c54c93Sjmatthew 		splx(s);
213942c54c93Sjmatthew 		return;
214042c54c93Sjmatthew 	}
214142c54c93Sjmatthew 
214242c54c93Sjmatthew 	ifp->if_timer = 0;
2143fd07ab7eSkevlo 	if (ifq_is_oactive(&ifp->if_snd))
2144fd07ab7eSkevlo 		ifq_restart(&ifp->if_snd);
214542c54c93Sjmatthew 	splx(s);
214642c54c93Sjmatthew }
214742c54c93Sjmatthew 
214842c54c93Sjmatthew int
ure_encap_txpkt(struct mbuf * m,char * buf,uint32_t maxlen)2149fd07ab7eSkevlo ure_encap_txpkt(struct mbuf *m, char *buf, uint32_t maxlen)
215042c54c93Sjmatthew {
215142c54c93Sjmatthew 	struct ure_txpkt	txhdr;
2152fd07ab7eSkevlo 	uint32_t		len = sizeof(txhdr), cflags = 0;
2153fd07ab7eSkevlo 
2154fd07ab7eSkevlo 	if (len + m->m_pkthdr.len > maxlen)
2155fd07ab7eSkevlo 		return (-1);
215642c54c93Sjmatthew 
2157c096a1a3Skevlo 	if ((m->m_pkthdr.csum_flags &
2158c096a1a3Skevlo 	    (M_IPV4_CSUM_OUT | M_TCP_CSUM_OUT | M_UDP_CSUM_OUT)) != 0) {
2159c096a1a3Skevlo 		cflags |= URE_TXPKT_IPV4;
2160c096a1a3Skevlo 		if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT)
2161c096a1a3Skevlo 			cflags |= URE_TXPKT_TCP;
2162c096a1a3Skevlo 		if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT)
2163c096a1a3Skevlo 			cflags |= URE_TXPKT_UDP;
2164c096a1a3Skevlo 	}
2165c096a1a3Skevlo 
2166c096a1a3Skevlo #if NVLAN > 0
2167c096a1a3Skevlo 	if (m->m_flags & M_VLANTAG)
2168fe07c298Ssthen 		cflags |= URE_TXPKT_VLAN_TAG | swap16(m->m_pkthdr.ether_vtag);
2169c096a1a3Skevlo #endif
2170c096a1a3Skevlo 
2171c096a1a3Skevlo 	txhdr.ure_pktlen = htole32(m->m_pkthdr.len | URE_TXPKT_TX_FS |
217242c54c93Sjmatthew 	    URE_TXPKT_TX_LS);
2173c096a1a3Skevlo 	txhdr.ure_vlan = htole32(cflags);
2174fd07ab7eSkevlo 	memcpy(buf, &txhdr, len);
217542c54c93Sjmatthew 
2176fd07ab7eSkevlo 	m_copydata(m, 0, m->m_pkthdr.len, buf + len);
2177fd07ab7eSkevlo 	len += m->m_pkthdr.len;
217842c54c93Sjmatthew 
2179fd07ab7eSkevlo 	return (len);
2180fd07ab7eSkevlo }
218142c54c93Sjmatthew 
2182fd07ab7eSkevlo int
ure_encap_xfer(struct ifnet * ifp,struct ure_softc * sc,struct ure_chain * c)2183fd07ab7eSkevlo ure_encap_xfer(struct ifnet *ifp, struct ure_softc *sc, struct ure_chain *c)
2184fd07ab7eSkevlo {
2185fd07ab7eSkevlo 	usbd_status	err;
2186fd07ab7eSkevlo 
218742c54c93Sjmatthew 	usbd_setup_xfer(c->uc_xfer, sc->ure_ep[URE_ENDPT_TX], c, c->uc_buf,
2188fd07ab7eSkevlo 	    c->uc_buflen, USBD_FORCE_SHORT_XFER | USBD_NO_COPY, 10000,
2189fd07ab7eSkevlo 	    ure_txeof);
219042c54c93Sjmatthew 
219142c54c93Sjmatthew 	err = usbd_transfer(c->uc_xfer);
2192fd07ab7eSkevlo 	if (err != USBD_IN_PROGRESS) {
2193fd07ab7eSkevlo 		c->uc_cnt = 0;
2194fd07ab7eSkevlo 		c->uc_buflen = 0;
219542c54c93Sjmatthew 		ure_stop(sc);
2196c096a1a3Skevlo 		return (EIO);
219742c54c93Sjmatthew 	}
219842c54c93Sjmatthew 
2199c096a1a3Skevlo 	return (0);
220042c54c93Sjmatthew }
2201