xref: /netbsd-src/sys/dev/usb/if_ure.c (revision 770fbbf7f72d86e3cde4dad17f9b99b790918636)
1*770fbbf7Schristos /*	$NetBSD: if_ure.c,v 1.60 2024/05/12 17:17:56 christos Exp $	*/
23b617907Srin /*	$OpenBSD: if_ure.c,v 1.10 2018/11/02 21:32:30 jcs Exp $	*/
320f8866fSmrg 
43b617907Srin /*-
53b617907Srin  * Copyright (c) 2015-2016 Kevin Lo <kevlo@FreeBSD.org>
63b617907Srin  * All rights reserved.
73b617907Srin  *
83b617907Srin  * Redistribution and use in source and binary forms, with or without
93b617907Srin  * modification, are permitted provided that the following conditions
103b617907Srin  * are met:
113b617907Srin  * 1. Redistributions of source code must retain the above copyright
123b617907Srin  *    notice, this list of conditions and the following disclaimer.
133b617907Srin  * 2. Redistributions in binary form must reproduce the above copyright
143b617907Srin  *    notice, this list of conditions and the following disclaimer in the
153b617907Srin  *    documentation and/or other materials provided with the distribution.
163b617907Srin  *
173b617907Srin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
183b617907Srin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
193b617907Srin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
203b617907Srin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
213b617907Srin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
223b617907Srin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
233b617907Srin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
243b617907Srin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
253b617907Srin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
263b617907Srin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
273b617907Srin  * SUCH DAMAGE.
283b617907Srin  */
293b617907Srin 
303b617907Srin /* RealTek RTL8152/RTL8153 10/100/Gigabit USB Ethernet device */
313b617907Srin 
323b617907Srin #include <sys/cdefs.h>
33*770fbbf7Schristos __KERNEL_RCSID(0, "$NetBSD: if_ure.c,v 1.60 2024/05/12 17:17:56 christos Exp $");
343b617907Srin 
353b617907Srin #ifdef _KERNEL_OPT
363b617907Srin #include "opt_usb.h"
373b617907Srin #include "opt_inet.h"
383b617907Srin #endif
393b617907Srin 
403b617907Srin #include <sys/param.h>
41580b92a4Sbad #include <sys/cprng.h>
423b617907Srin 
4320f8866fSmrg #include <net/route.h>
443b617907Srin 
45916d2ae8Smrg #include <dev/usb/usbnet.h>
46916d2ae8Smrg 
473b617907Srin #include <netinet/in_offload.h>		/* XXX for in_undefer_cksum() */
483b617907Srin #ifdef INET6
49916d2ae8Smrg #include <netinet/in.h>
503b617907Srin #include <netinet6/in6_offload.h>	/* XXX for in6_undefer_cksum() */
513b617907Srin #endif
523b617907Srin 
533b617907Srin #include <dev/ic/rtl81x9reg.h>		/* XXX for RTK_GMEDIASTAT */
543b617907Srin #include <dev/usb/if_urereg.h>
553b617907Srin #include <dev/usb/if_urevar.h>
563b617907Srin 
5720f8866fSmrg #define URE_PRINTF(un, fmt, args...) \
5820f8866fSmrg 	device_printf((un)->un_dev, "%s: " fmt, __func__, ##args);
593b617907Srin 
603b617907Srin #define URE_DEBUG
613b617907Srin #ifdef URE_DEBUG
623b617907Srin #define DPRINTF(x)	do { if (uredebug) printf x; } while (0)
633b617907Srin #define DPRINTFN(n, x)	do { if (uredebug >= (n)) printf x; } while (0)
6410dd8246Smrg int	uredebug = 0;
653b617907Srin #else
663b617907Srin #define DPRINTF(x)
673b617907Srin #define DPRINTFN(n, x)
683b617907Srin #endif
693b617907Srin 
70580b92a4Sbad #define ETHER_IS_ZERO(addr) \
71580b92a4Sbad 	(!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]))
72580b92a4Sbad 
733b617907Srin static const struct usb_devno ure_devs[] = {
743b617907Srin 	{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8152 },
75*770fbbf7Schristos 	{ USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8153 },
76*770fbbf7Schristos 	{ USB_VENDOR_TPLINK,  USB_PRODUCT_TPLINK_UE300 },
773b617907Srin };
783b617907Srin 
79d066f229Smrg #define URE_BUFSZ	(16 * 1024)
80d066f229Smrg 
8120f8866fSmrg static void	ure_reset(struct usbnet *);
823b617907Srin static uint32_t	ure_txcsum(struct mbuf *);
833b617907Srin static int	ure_rxcsum(struct ifnet *, struct ure_rxpkt *);
84e4ce9137Smrg static void	ure_rtl8152_init(struct usbnet *);
85e4ce9137Smrg static void	ure_rtl8153_init(struct usbnet *);
86e4ce9137Smrg static void	ure_disable_teredo(struct usbnet *);
87e4ce9137Smrg static void	ure_init_fifo(struct usbnet *);
883b617907Srin 
897a9a30c5Sthorpej static void	ure_uno_stop(struct ifnet *, int);
90d9c770e7Sriastradh static void	ure_uno_mcast(struct ifnet *);
917a9a30c5Sthorpej static int	ure_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
927a9a30c5Sthorpej static int	ure_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
937a9a30c5Sthorpej static void	ure_uno_miibus_statchg(struct ifnet *);
947a9a30c5Sthorpej static unsigned ure_uno_tx_prepare(struct usbnet *, struct mbuf *,
95d066f229Smrg 				   struct usbnet_chain *);
967a9a30c5Sthorpej static void	ure_uno_rx_loop(struct usbnet *, struct usbnet_chain *,
977a9a30c5Sthorpej 				uint32_t);
987a9a30c5Sthorpej static int	ure_uno_init(struct ifnet *);
99d066f229Smrg 
100d066f229Smrg static int	ure_match(device_t, cfdata_t, void *);
101d066f229Smrg static void	ure_attach(device_t, device_t, void *);
102d066f229Smrg 
103e4ce9137Smrg CFATTACH_DECL_NEW(ure, sizeof(struct usbnet), ure_match, ure_attach,
10420f8866fSmrg     usbnet_detach, usbnet_activate);
1053b617907Srin 
106f76a6828Smaxv static const struct usbnet_ops ure_ops = {
1077a9a30c5Sthorpej 	.uno_stop = ure_uno_stop,
108d9c770e7Sriastradh 	.uno_mcast = ure_uno_mcast,
1097a9a30c5Sthorpej 	.uno_read_reg = ure_uno_mii_read_reg,
1107a9a30c5Sthorpej 	.uno_write_reg = ure_uno_mii_write_reg,
1117a9a30c5Sthorpej 	.uno_statchg = ure_uno_miibus_statchg,
1127a9a30c5Sthorpej 	.uno_tx_prepare = ure_uno_tx_prepare,
1137a9a30c5Sthorpej 	.uno_rx_loop = ure_uno_rx_loop,
1147a9a30c5Sthorpej 	.uno_init = ure_uno_init,
115d066f229Smrg };
116d066f229Smrg 
1173b617907Srin static int
ure_ctl(struct usbnet * un,uint8_t rw,uint16_t val,uint16_t index,void * buf,int len)11820f8866fSmrg ure_ctl(struct usbnet *un, uint8_t rw, uint16_t val, uint16_t index,
1193b617907Srin     void *buf, int len)
1203b617907Srin {
1213b617907Srin 	usb_device_request_t req;
1223b617907Srin 	usbd_status err;
1233b617907Srin 
124d066f229Smrg 	if (usbnet_isdying(un))
1253b617907Srin 		return 0;
1263b617907Srin 
1273b617907Srin 	if (rw == URE_CTL_WRITE)
1283b617907Srin 		req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
1293b617907Srin 	else
1303b617907Srin 		req.bmRequestType = UT_READ_VENDOR_DEVICE;
1313b617907Srin 	req.bRequest = UR_SET_ADDRESS;
1323b617907Srin 	USETW(req.wValue, val);
1333b617907Srin 	USETW(req.wIndex, index);
1343b617907Srin 	USETW(req.wLength, len);
1353b617907Srin 
1364c92faedSmartin 	DPRINTFN(5, ("ure_ctl: rw %d, val %04hu, index %04hu, len %d\n",
1373b617907Srin 	    rw, val, index, len));
13820f8866fSmrg 	err = usbd_do_request(un->un_udev, &req, buf);
1393b617907Srin 	if (err) {
1403b617907Srin 		DPRINTF(("ure_ctl: error %d\n", err));
1419e1fa980Sriastradh 		if (rw == URE_CTL_READ)
1429e1fa980Sriastradh 			memset(buf, 0, len);
1433b617907Srin 		return -1;
1443b617907Srin 	}
1453b617907Srin 
1463b617907Srin 	return 0;
1473b617907Srin }
1483b617907Srin 
1493b617907Srin static int
ure_read_mem(struct usbnet * un,uint16_t addr,uint16_t index,void * buf,int len)15020f8866fSmrg ure_read_mem(struct usbnet *un, uint16_t addr, uint16_t index,
1513b617907Srin     void *buf, int len)
1523b617907Srin {
15320f8866fSmrg 	return ure_ctl(un, URE_CTL_READ, addr, index, buf, len);
1543b617907Srin }
1553b617907Srin 
1563b617907Srin static int
ure_write_mem(struct usbnet * un,uint16_t addr,uint16_t index,void * buf,int len)15720f8866fSmrg ure_write_mem(struct usbnet *un, uint16_t addr, uint16_t index,
1583b617907Srin     void *buf, int len)
1593b617907Srin {
16020f8866fSmrg 	return ure_ctl(un, URE_CTL_WRITE, addr, index, buf, len);
1613b617907Srin }
1623b617907Srin 
1633b617907Srin static uint8_t
ure_read_1(struct usbnet * un,uint16_t reg,uint16_t index)16420f8866fSmrg ure_read_1(struct usbnet *un, uint16_t reg, uint16_t index)
1653b617907Srin {
1663b617907Srin 	uint32_t val;
1673b617907Srin 	uint8_t temp[4];
1683b617907Srin 	uint8_t shift;
1693b617907Srin 
1703b617907Srin 	shift = (reg & 3) << 3;
1713b617907Srin 	reg &= ~3;
1723b617907Srin 
17320f8866fSmrg 	ure_read_mem(un, reg, index, &temp, 4);
1743b617907Srin 	val = UGETDW(temp);
1753b617907Srin 	val >>= shift;
1763b617907Srin 
1773b617907Srin 	return val & 0xff;
1783b617907Srin }
1793b617907Srin 
1803b617907Srin static uint16_t
ure_read_2(struct usbnet * un,uint16_t reg,uint16_t index)18120f8866fSmrg ure_read_2(struct usbnet *un, uint16_t reg, uint16_t index)
1823b617907Srin {
1833b617907Srin 	uint32_t val;
1843b617907Srin 	uint8_t temp[4];
1853b617907Srin 	uint8_t shift;
1863b617907Srin 
1873b617907Srin 	shift = (reg & 2) << 3;
1883b617907Srin 	reg &= ~3;
1893b617907Srin 
19020f8866fSmrg 	ure_read_mem(un, reg, index, &temp, 4);
1913b617907Srin 	val = UGETDW(temp);
1923b617907Srin 	val >>= shift;
1933b617907Srin 
1943b617907Srin 	return val & 0xffff;
1953b617907Srin }
1963b617907Srin 
1973b617907Srin static uint32_t
ure_read_4(struct usbnet * un,uint16_t reg,uint16_t index)19820f8866fSmrg ure_read_4(struct usbnet *un, uint16_t reg, uint16_t index)
1993b617907Srin {
2003b617907Srin 	uint8_t temp[4];
2013b617907Srin 
20220f8866fSmrg 	ure_read_mem(un, reg, index, &temp, 4);
2033b617907Srin 	return UGETDW(temp);
2043b617907Srin }
2053b617907Srin 
2063b617907Srin static int
ure_write_1(struct usbnet * un,uint16_t reg,uint16_t index,uint32_t val)20720f8866fSmrg ure_write_1(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val)
2083b617907Srin {
2093b617907Srin 	uint16_t byen;
2103b617907Srin 	uint8_t temp[4];
2113b617907Srin 	uint8_t shift;
2123b617907Srin 
2133b617907Srin 	byen = URE_BYTE_EN_BYTE;
2143b617907Srin 	shift = reg & 3;
2153b617907Srin 	val &= 0xff;
2163b617907Srin 
2173b617907Srin 	if (reg & 3) {
2183b617907Srin 		byen <<= shift;
2193b617907Srin 		val <<= (shift << 3);
2203b617907Srin 		reg &= ~3;
2213b617907Srin 	}
2223b617907Srin 
2233b617907Srin 	USETDW(temp, val);
22420f8866fSmrg 	return ure_write_mem(un, reg, index | byen, &temp, 4);
2253b617907Srin }
2263b617907Srin 
2273b617907Srin static int
ure_write_2(struct usbnet * un,uint16_t reg,uint16_t index,uint32_t val)22820f8866fSmrg ure_write_2(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val)
2293b617907Srin {
2303b617907Srin 	uint16_t byen;
2313b617907Srin 	uint8_t temp[4];
2323b617907Srin 	uint8_t shift;
2333b617907Srin 
2343b617907Srin 	byen = URE_BYTE_EN_WORD;
2353b617907Srin 	shift = reg & 2;
2363b617907Srin 	val &= 0xffff;
2373b617907Srin 
2383b617907Srin 	if (reg & 2) {
2393b617907Srin 		byen <<= shift;
2403b617907Srin 		val <<= (shift << 3);
2413b617907Srin 		reg &= ~3;
2423b617907Srin 	}
2433b617907Srin 
2443b617907Srin 	USETDW(temp, val);
24520f8866fSmrg 	return ure_write_mem(un, reg, index | byen, &temp, 4);
2463b617907Srin }
2473b617907Srin 
2483b617907Srin static int
ure_write_4(struct usbnet * un,uint16_t reg,uint16_t index,uint32_t val)24920f8866fSmrg ure_write_4(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val)
2503b617907Srin {
2513b617907Srin 	uint8_t temp[4];
2523b617907Srin 
2533b617907Srin 	USETDW(temp, val);
25420f8866fSmrg 	return ure_write_mem(un, reg, index | URE_BYTE_EN_DWORD, &temp, 4);
2553b617907Srin }
2563b617907Srin 
2573b617907Srin static uint16_t
ure_ocp_reg_read(struct usbnet * un,uint16_t addr)25820f8866fSmrg ure_ocp_reg_read(struct usbnet *un, uint16_t addr)
2593b617907Srin {
2603b617907Srin 	uint16_t reg;
2613b617907Srin 
26220f8866fSmrg 	ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000);
2633b617907Srin 	reg = (addr & 0x0fff) | 0xb000;
2643b617907Srin 
26520f8866fSmrg 	return ure_read_2(un, reg, URE_MCU_TYPE_PLA);
2663b617907Srin }
2673b617907Srin 
2683b617907Srin static void
ure_ocp_reg_write(struct usbnet * un,uint16_t addr,uint16_t data)26920f8866fSmrg ure_ocp_reg_write(struct usbnet *un, uint16_t addr, uint16_t data)
2703b617907Srin {
2713b617907Srin 	uint16_t reg;
2723b617907Srin 
27320f8866fSmrg 	ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000);
2743b617907Srin 	reg = (addr & 0x0fff) | 0xb000;
2753b617907Srin 
27620f8866fSmrg 	ure_write_2(un, reg, URE_MCU_TYPE_PLA, data);
2773b617907Srin }
2783b617907Srin 
27965dae968Smrg static int
ure_uno_mii_read_reg(struct usbnet * un,int phy,int reg,uint16_t * val)2807a9a30c5Sthorpej ure_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val)
2813b617907Srin {
28243e0dcd1Smrg 
2839e1fa980Sriastradh 	if (un->un_phyno != phy) {
2849e1fa980Sriastradh 		*val = 0;
28565dae968Smrg 		return EINVAL;
2869e1fa980Sriastradh 	}
28743e0dcd1Smrg 
2883b617907Srin 	/* Let the rgephy driver read the URE_PLA_PHYSTATUS register. */
2893b617907Srin 	if (reg == RTK_GMEDIASTAT) {
29020f8866fSmrg 		*val = ure_read_1(un, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA);
29120f8866fSmrg 		return USBD_NORMAL_COMPLETION;
2923b617907Srin 	}
2933b617907Srin 
29420f8866fSmrg 	*val = ure_ocp_reg_read(un, URE_OCP_BASE_MII + reg * 2);
2953b617907Srin 
29665dae968Smrg 	return 0;
2973b617907Srin }
2983b617907Srin 
29965dae968Smrg static int
ure_uno_mii_write_reg(struct usbnet * un,int phy,int reg,uint16_t val)3007a9a30c5Sthorpej ure_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val)
3013b617907Srin {
30243e0dcd1Smrg 
30343e0dcd1Smrg 	if (un->un_phyno != phy)
30465dae968Smrg 		return EINVAL;
30543e0dcd1Smrg 
30620f8866fSmrg 	ure_ocp_reg_write(un, URE_OCP_BASE_MII + reg * 2, val);
3073b617907Srin 
30865dae968Smrg 	return 0;
3093b617907Srin }
3103b617907Srin 
3113b617907Srin static void
ure_uno_miibus_statchg(struct ifnet * ifp)3127a9a30c5Sthorpej ure_uno_miibus_statchg(struct ifnet *ifp)
3133b617907Srin {
31420f8866fSmrg 	struct usbnet * const un = ifp->if_softc;
31520f8866fSmrg 	struct mii_data * const mii = usbnet_mii(un);
3163b617907Srin 
317d066f229Smrg 	if (usbnet_isdying(un))
3183b617907Srin 		return;
3193b617907Srin 
3203b617907Srin 	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
3213b617907Srin 	    (IFM_ACTIVE | IFM_AVALID)) {
3223b617907Srin 		switch (IFM_SUBTYPE(mii->mii_media_active)) {
3233b617907Srin 		case IFM_10_T:
3243b617907Srin 		case IFM_100_TX:
325dbbc1953Smrg 			usbnet_set_link(un, true);
3263b617907Srin 			break;
3273b617907Srin 		case IFM_1000_T:
328e4ce9137Smrg 			if ((un->un_flags & URE_FLAG_8152) != 0)
3293b617907Srin 				break;
330dbbc1953Smrg 			usbnet_set_link(un, true);
3313b617907Srin 			break;
3323b617907Srin 		default:
3333b617907Srin 			break;
3343b617907Srin 		}
3353b617907Srin 	}
3363b617907Srin }
3373b617907Srin 
3383b617907Srin static void
ure_uno_mcast(struct ifnet * ifp)3392a987a0aSriastradh ure_uno_mcast(struct ifnet *ifp)
3403b617907Srin {
3412a987a0aSriastradh 	struct usbnet *un = ifp->if_softc;
34220f8866fSmrg 	struct ethercom *ec = usbnet_ec(un);
3433b617907Srin 	struct ether_multi *enm;
3443b617907Srin 	struct ether_multistep step;
34539dc622eSnisimura 	uint32_t mchash[2] = { 0, 0 };
34639dc622eSnisimura 	uint32_t h = 0, rxmode;
3473b617907Srin 
348d066f229Smrg 	if (usbnet_isdying(un))
3493b617907Srin 		return;
3503b617907Srin 
35120f8866fSmrg 	rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA);
35239dc622eSnisimura 	rxmode &= ~(URE_RCR_AAP | URE_RCR_AM);
35339dc622eSnisimura 	/* continue to accept my own DA and bcast frames */
3543b617907Srin 
35505bd3687Smrg 	ETHER_LOCK(ec);
356a06a0449Sriastradh 	if (usbnet_ispromisc(un)) {
35705bd3687Smrg 		ec->ec_flags |= ETHER_F_ALLMULTI;
35805bd3687Smrg 		ETHER_UNLOCK(ec);
35939dc622eSnisimura 		/* run promisc. mode */
36039dc622eSnisimura 		rxmode |= URE_RCR_AM;	/* ??? */
36139dc622eSnisimura 		rxmode |= URE_RCR_AAP;
3628228640cSriastradh 		mchash[0] = mchash[1] = 0xffffffff;
36339dc622eSnisimura 		goto update;
36439dc622eSnisimura 	}
36505bd3687Smrg 	ec->ec_flags &= ~ETHER_F_ALLMULTI;
36683759283Smsaitoh 	ETHER_FIRST_MULTI(step, ec, enm);
3673b617907Srin 	while (enm != NULL) {
36839dc622eSnisimura 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
36939dc622eSnisimura 			ec->ec_flags |= ETHER_F_ALLMULTI;
37083759283Smsaitoh 			ETHER_UNLOCK(ec);
37139dc622eSnisimura 			/* accept all mcast frames */
37239dc622eSnisimura 			rxmode |= URE_RCR_AM;
37339dc622eSnisimura 			mchash[0] = mchash[1] = ~0U; /* necessary ?? */
37439dc622eSnisimura 			goto update;
37583759283Smsaitoh 		}
37639dc622eSnisimura 		h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN);
3773c6a8667Smsaitoh 		mchash[h >> 31] |= 1U << ((h >> 26) & 0x1f);
3783b617907Srin 		ETHER_NEXT_MULTI(step, enm);
3793b617907Srin 	}
38083759283Smsaitoh 	ETHER_UNLOCK(ec);
38139dc622eSnisimura 	if (h != 0) {
38239dc622eSnisimura 		rxmode |= URE_RCR_AM;	/* activate mcast hash filter */
38339dc622eSnisimura 		h = bswap32(mchash[0]);
38439dc622eSnisimura 		mchash[0] = bswap32(mchash[1]);
38539dc622eSnisimura 		mchash[1] = h;
3863b617907Srin 	}
38739dc622eSnisimura  update:
38839dc622eSnisimura 	ure_write_4(un, URE_PLA_MAR0, URE_MCU_TYPE_PLA, mchash[0]);
38939dc622eSnisimura 	ure_write_4(un, URE_PLA_MAR4, URE_MCU_TYPE_PLA, mchash[1]);
39020f8866fSmrg 	ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode);
3913b617907Srin }
3923b617907Srin 
3933b617907Srin static void
ure_reset(struct usbnet * un)39420f8866fSmrg ure_reset(struct usbnet *un)
3953b617907Srin {
3963b617907Srin 	int i;
3973b617907Srin 
39820f8866fSmrg 	ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST);
3993b617907Srin 
4003b617907Srin 	for (i = 0; i < URE_TIMEOUT; i++) {
4017f15b701Sriastradh 		if (usbnet_isdying(un))
4027f15b701Sriastradh 			return;
40320f8866fSmrg 		if (!(ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) &
4043b617907Srin 		    URE_CR_RST))
4053b617907Srin 			break;
40620f8866fSmrg 		usbd_delay_ms(un->un_udev, 10);
4073b617907Srin 	}
4083b617907Srin 	if (i == URE_TIMEOUT)
40920f8866fSmrg 		URE_PRINTF(un, "reset never completed\n");
4103b617907Srin }
4113b617907Srin 
4123b617907Srin static int
ure_uno_init(struct ifnet * ifp)4131da4c156Sriastradh ure_uno_init(struct ifnet *ifp)
4143b617907Srin {
41520f8866fSmrg 	struct usbnet * const un = ifp->if_softc;
4163b617907Srin 	uint8_t eaddr[8];
4173b617907Srin 
4183b617907Srin 	/* Set MAC address. */
4193b617907Srin 	memset(eaddr, 0, sizeof(eaddr));
4203b617907Srin 	memcpy(eaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
42120f8866fSmrg 	ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG);
42220f8866fSmrg 	ure_write_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES,
4233b617907Srin 	    eaddr, 8);
42420f8866fSmrg 	ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML);
4253b617907Srin 
4263b617907Srin 	/* Reset the packet filter. */
42720f8866fSmrg 	ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA,
42820f8866fSmrg 	    ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) &
4293b617907Srin 	    ~URE_FMC_FCR_MCU_EN);
43020f8866fSmrg 	ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA,
43120f8866fSmrg 	    ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) |
4323b617907Srin 	    URE_FMC_FCR_MCU_EN);
4333b617907Srin 
4343b617907Srin 	/* Enable transmit and receive. */
43520f8866fSmrg 	ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA,
43620f8866fSmrg 	    ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) | URE_CR_RE |
4373b617907Srin 	    URE_CR_TE);
4383b617907Srin 
43920f8866fSmrg 	ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA,
44020f8866fSmrg 	    ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) &
4413b617907Srin 	    ~URE_RXDY_GATED_EN);
4423b617907Srin 
44393ec4d73Sriastradh 	return 0;
4443b617907Srin }
4453b617907Srin 
4463b617907Srin static void
ure_uno_stop(struct ifnet * ifp,int disable __unused)4477a9a30c5Sthorpej ure_uno_stop(struct ifnet *ifp, int disable __unused)
4483b617907Srin {
44920f8866fSmrg 	struct usbnet * const un = ifp->if_softc;
4503b617907Srin 
45120f8866fSmrg 	ure_reset(un);
452aefaaa77Smrg }
453aefaaa77Smrg 
454aefaaa77Smrg static void
ure_rtl8152_init(struct usbnet * un)455e4ce9137Smrg ure_rtl8152_init(struct usbnet *un)
4563b617907Srin {
4573b617907Srin 	uint32_t pwrctrl;
4583b617907Srin 
4593b617907Srin 	/* Disable ALDPS. */
46020f8866fSmrg 	ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA |
4613b617907Srin 	    URE_DIS_SDSAVE);
46220f8866fSmrg 	usbd_delay_ms(un->un_udev, 20);
4633b617907Srin 
464e4ce9137Smrg 	if (un->un_flags & URE_FLAG_VER_4C00) {
46520f8866fSmrg 		ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA,
46620f8866fSmrg 		    ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) &
4673b617907Srin 		    ~URE_LED_MODE_MASK);
4683b617907Srin 	}
4693b617907Srin 
47020f8866fSmrg 	ure_write_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB,
47120f8866fSmrg 	    ure_read_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) &
4723b617907Srin 	    ~URE_POWER_CUT);
47320f8866fSmrg 	ure_write_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB,
47420f8866fSmrg 	    ure_read_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) &
4753b617907Srin 	    ~URE_RESUME_INDICATE);
4763b617907Srin 
47720f8866fSmrg 	ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA,
47820f8866fSmrg 	    ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) |
4793b617907Srin 	    URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH);
48020f8866fSmrg 	pwrctrl = ure_read_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA);
4813b617907Srin 	pwrctrl &= ~URE_MCU_CLK_RATIO_MASK;
4823b617907Srin 	pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN;
48320f8866fSmrg 	ure_write_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl);
48420f8866fSmrg 	ure_write_2(un, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA,
4853b617907Srin 	    URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK |
4863b617907Srin 	    URE_SPDWN_LINKCHG_MSK);
4873b617907Srin 
4883b617907Srin 	/* Enable Rx aggregation. */
48920f8866fSmrg 	ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB,
49020f8866fSmrg 	    ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) &
4913b617907Srin 	    ~URE_RX_AGG_DISABLE);
4923b617907Srin 
4933b617907Srin 	/* Disable ALDPS. */
49420f8866fSmrg 	ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA |
4953b617907Srin 	    URE_DIS_SDSAVE);
49620f8866fSmrg 	usbd_delay_ms(un->un_udev, 20);
4973b617907Srin 
498e4ce9137Smrg 	ure_init_fifo(un);
4993b617907Srin 
50020f8866fSmrg 	ure_write_1(un, URE_USB_TX_AGG, URE_MCU_TYPE_USB,
5013b617907Srin 	    URE_TX_AGG_MAX_THRESHOLD);
50220f8866fSmrg 	ure_write_4(un, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH);
50320f8866fSmrg 	ure_write_4(un, URE_USB_TX_DMA, URE_MCU_TYPE_USB,
5043b617907Srin 	    URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1);
5053b617907Srin }
5063b617907Srin 
5073b617907Srin static void
ure_rtl8153_init(struct usbnet * un)508e4ce9137Smrg ure_rtl8153_init(struct usbnet *un)
5093b617907Srin {
5103b617907Srin 	uint16_t val;
5113b617907Srin 	uint8_t u1u2[8];
5123b617907Srin 	int i;
5133b617907Srin 
5143b617907Srin 	/* Disable ALDPS. */
51520f8866fSmrg 	ure_ocp_reg_write(un, URE_OCP_POWER_CFG,
51620f8866fSmrg 	    ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS);
51720f8866fSmrg 	usbd_delay_ms(un->un_udev, 20);
5183b617907Srin 
5193b617907Srin 	memset(u1u2, 0x00, sizeof(u1u2));
52020f8866fSmrg 	ure_write_mem(un, URE_USB_TOLERANCE,
5213b617907Srin 	    URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
5223b617907Srin 
5233b617907Srin 	for (i = 0; i < URE_TIMEOUT; i++) {
5247f15b701Sriastradh 		if (usbnet_isdying(un))
5257f15b701Sriastradh 			return;
52620f8866fSmrg 		if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) &
5273b617907Srin 		    URE_AUTOLOAD_DONE)
5283b617907Srin 			break;
52920f8866fSmrg 		usbd_delay_ms(un->un_udev, 10);
5303b617907Srin 	}
5313b617907Srin 	if (i == URE_TIMEOUT)
53220f8866fSmrg 		URE_PRINTF(un, "timeout waiting for chip autoload\n");
5333b617907Srin 
5343b617907Srin 	for (i = 0; i < URE_TIMEOUT; i++) {
5357f15b701Sriastradh 		if (usbnet_isdying(un))
5367f15b701Sriastradh 			return;
53720f8866fSmrg 		val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) &
5383b617907Srin 		    URE_PHY_STAT_MASK;
5393b617907Srin 		if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN)
5403b617907Srin 			break;
54120f8866fSmrg 		usbd_delay_ms(un->un_udev, 10);
5423b617907Srin 	}
5433b617907Srin 	if (i == URE_TIMEOUT)
54420f8866fSmrg 		URE_PRINTF(un, "timeout waiting for phy to stabilize\n");
5453b617907Srin 
54620f8866fSmrg 	ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB,
54720f8866fSmrg 	    ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB) &
5483b617907Srin 	    ~URE_U2P3_ENABLE);
5493b617907Srin 
550e4ce9137Smrg 	if (un->un_flags & URE_FLAG_VER_5C10) {
55120f8866fSmrg 		val = ure_read_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB);
5523b617907Srin 		val &= ~URE_PWD_DN_SCALE_MASK;
5533b617907Srin 		val |= URE_PWD_DN_SCALE(96);
55420f8866fSmrg 		ure_write_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val);
5553b617907Srin 
55620f8866fSmrg 		ure_write_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB,
55720f8866fSmrg 		    ure_read_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB) |
5583b617907Srin 		    URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND);
559e4ce9137Smrg 	} else if (un->un_flags & URE_FLAG_VER_5C20) {
56020f8866fSmrg 		ure_write_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA,
56120f8866fSmrg 		    ure_read_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA) &
5623b617907Srin 		    ~URE_ECM_ALDPS);
5633b617907Srin 	}
564e4ce9137Smrg 	if (un->un_flags & (URE_FLAG_VER_5C20 | URE_FLAG_VER_5C30)) {
56520f8866fSmrg 		val = ure_read_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB);
56620f8866fSmrg 		if (ure_read_2(un, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) ==
5673b617907Srin 		    0)
5683b617907Srin 			val &= ~URE_DYNAMIC_BURST;
5693b617907Srin 		else
5703b617907Srin 			val |= URE_DYNAMIC_BURST;
57120f8866fSmrg 		ure_write_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val);
5723b617907Srin 	}
5733b617907Srin 
57420f8866fSmrg 	ure_write_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB,
57520f8866fSmrg 	    ure_read_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB) |
5763b617907Srin 	    URE_EP4_FULL_FC);
5773b617907Srin 
57820f8866fSmrg 	ure_write_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB,
57920f8866fSmrg 	    ure_read_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB) &
5803b617907Srin 	    ~URE_TIMER11_EN);
5813b617907Srin 
58220f8866fSmrg 	ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA,
58320f8866fSmrg 	    ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) &
5843b617907Srin 	    ~URE_LED_MODE_MASK);
5853b617907Srin 
586e4ce9137Smrg 	if ((un->un_flags & URE_FLAG_VER_5C10) &&
58720f8866fSmrg 	    un->un_udev->ud_speed != USB_SPEED_SUPER)
5883b617907Srin 		val = URE_LPM_TIMER_500MS;
5893b617907Srin 	else
5903b617907Srin 		val = URE_LPM_TIMER_500US;
59120f8866fSmrg 	ure_write_1(un, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB,
5923b617907Srin 	    val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM);
5933b617907Srin 
59420f8866fSmrg 	val = ure_read_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB);
5953b617907Srin 	val &= ~URE_SEN_VAL_MASK;
5963b617907Srin 	val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE;
59720f8866fSmrg 	ure_write_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val);
5983b617907Srin 
59920f8866fSmrg 	ure_write_2(un, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001);
6003b617907Srin 
60120f8866fSmrg 	ure_write_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB,
60220f8866fSmrg 	    ure_read_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB) &
6033b617907Srin 	    ~(URE_PWR_EN | URE_PHASE2_EN));
60420f8866fSmrg 	ure_write_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB,
60520f8866fSmrg 	    ure_read_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB) &
6063b617907Srin 	    ~URE_PCUT_STATUS);
6073b617907Srin 
6083b617907Srin 	memset(u1u2, 0xff, sizeof(u1u2));
60920f8866fSmrg 	ure_write_mem(un, URE_USB_TOLERANCE,
6103b617907Srin 	    URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
6113b617907Srin 
61220f8866fSmrg 	ure_write_2(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA,
6133b617907Srin 	    URE_ALDPS_SPDWN_RATIO);
61420f8866fSmrg 	ure_write_2(un, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA,
6153b617907Srin 	    URE_EEE_SPDWN_RATIO);
61620f8866fSmrg 	ure_write_2(un, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA,
6173b617907Srin 	    URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN |
6183b617907Srin 	    URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN);
61920f8866fSmrg 	ure_write_2(un, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA,
6203b617907Srin 	    URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN |
6213b617907Srin 	    URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN |
6223b617907Srin 	    URE_EEE_SPDWN_EN);
6233b617907Srin 
62420f8866fSmrg 	val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB);
625e4ce9137Smrg 	if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10)))
6263b617907Srin 		val |= URE_U2P3_ENABLE;
6273b617907Srin 	else
6283b617907Srin 		val &= ~URE_U2P3_ENABLE;
62920f8866fSmrg 	ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val);
6303b617907Srin 
6313b617907Srin 	memset(u1u2, 0x00, sizeof(u1u2));
63220f8866fSmrg 	ure_write_mem(un, URE_USB_TOLERANCE,
6333b617907Srin 	    URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
6343b617907Srin 
6353b617907Srin 	/* Disable ALDPS. */
63620f8866fSmrg 	ure_ocp_reg_write(un, URE_OCP_POWER_CFG,
63720f8866fSmrg 	    ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS);
63820f8866fSmrg 	usbd_delay_ms(un->un_udev, 20);
6393b617907Srin 
640e4ce9137Smrg 	ure_init_fifo(un);
6413b617907Srin 
6423b617907Srin 	/* Enable Rx aggregation. */
64320f8866fSmrg 	ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB,
64420f8866fSmrg 	    ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) &
6453b617907Srin 	    ~URE_RX_AGG_DISABLE);
6463b617907Srin 
64720f8866fSmrg 	val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB);
648e4ce9137Smrg 	if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10)))
6493b617907Srin 		val |= URE_U2P3_ENABLE;
6503b617907Srin 	else
6513b617907Srin 		val &= ~URE_U2P3_ENABLE;
65220f8866fSmrg 	ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val);
6533b617907Srin 
6543b617907Srin 	memset(u1u2, 0xff, sizeof(u1u2));
65520f8866fSmrg 	ure_write_mem(un, URE_USB_TOLERANCE,
6563b617907Srin 	    URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
6573b617907Srin }
6583b617907Srin 
6593b617907Srin static void
ure_disable_teredo(struct usbnet * un)660e4ce9137Smrg ure_disable_teredo(struct usbnet *un)
6613b617907Srin {
66220f8866fSmrg 	ure_write_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA,
66320f8866fSmrg 	    ure_read_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) &
6643b617907Srin 	    ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN));
66520f8866fSmrg 	ure_write_2(un, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA,
6663b617907Srin 	    URE_WDT6_SET_MODE);
66720f8866fSmrg 	ure_write_2(un, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0);
66820f8866fSmrg 	ure_write_4(un, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0);
6693b617907Srin }
6703b617907Srin 
6713b617907Srin static void
ure_init_fifo(struct usbnet * un)672e4ce9137Smrg ure_init_fifo(struct usbnet *un)
6733b617907Srin {
67439dc622eSnisimura 	uint32_t rxmode, rx_fifo1, rx_fifo2;
6753b617907Srin 	int i;
6763b617907Srin 
67720f8866fSmrg 	ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA,
67820f8866fSmrg 	    ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) |
6793b617907Srin 	    URE_RXDY_GATED_EN);
6803b617907Srin 
681e4ce9137Smrg 	ure_disable_teredo(un);
6823b617907Srin 
68339dc622eSnisimura 	rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA);
68439dc622eSnisimura 	rxmode &= ~URE_RCR_ACPT_ALL;
68539dc622eSnisimura 	rxmode |= URE_RCR_APM | URE_RCR_AB; /* accept my own DA and bcast */
68639dc622eSnisimura 	ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode);
6873b617907Srin 
688e4ce9137Smrg 	if (!(un->un_flags & URE_FLAG_8152)) {
689e4ce9137Smrg 		if (un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10 |
690e4ce9137Smrg 		    URE_FLAG_VER_5C20))
69120f8866fSmrg 			ure_ocp_reg_write(un, URE_OCP_ADC_CFG,
6923b617907Srin 			    URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L);
693e4ce9137Smrg 		if (un->un_flags & URE_FLAG_VER_5C00)
69420f8866fSmrg 			ure_ocp_reg_write(un, URE_OCP_EEE_CFG,
69520f8866fSmrg 			    ure_ocp_reg_read(un, URE_OCP_EEE_CFG) &
6963b617907Srin 			    ~URE_CTAP_SHORT_EN);
69720f8866fSmrg 		ure_ocp_reg_write(un, URE_OCP_POWER_CFG,
69820f8866fSmrg 		    ure_ocp_reg_read(un, URE_OCP_POWER_CFG) |
6993b617907Srin 		    URE_EEE_CLKDIV_EN);
70020f8866fSmrg 		ure_ocp_reg_write(un, URE_OCP_DOWN_SPEED,
70120f8866fSmrg 		    ure_ocp_reg_read(un, URE_OCP_DOWN_SPEED) |
7023b617907Srin 		    URE_EN_10M_BGOFF);
70320f8866fSmrg 		ure_ocp_reg_write(un, URE_OCP_POWER_CFG,
70420f8866fSmrg 		    ure_ocp_reg_read(un, URE_OCP_POWER_CFG) |
7053b617907Srin 		    URE_EN_10M_PLLOFF);
70620f8866fSmrg 		ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_IMPEDANCE);
70720f8866fSmrg 		ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0b13);
70820f8866fSmrg 		ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA,
70920f8866fSmrg 		    ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) |
7103b617907Srin 		    URE_PFM_PWM_SWITCH);
7113b617907Srin 
7123b617907Srin 		/* Enable LPF corner auto tune. */
71320f8866fSmrg 		ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_LPF_CFG);
71420f8866fSmrg 		ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0xf70f);
7153b617907Srin 
7163b617907Srin 		/* Adjust 10M amplitude. */
71720f8866fSmrg 		ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP1);
71820f8866fSmrg 		ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x00af);
71920f8866fSmrg 		ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP2);
72020f8866fSmrg 		ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0208);
7213b617907Srin 	}
7223b617907Srin 
72320f8866fSmrg 	ure_reset(un);
7243b617907Srin 
72520f8866fSmrg 	ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, 0);
7263b617907Srin 
72720f8866fSmrg 	ure_write_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA,
72820f8866fSmrg 	    ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
7293b617907Srin 	    ~URE_NOW_IS_OOB);
7303b617907Srin 
73120f8866fSmrg 	ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA,
73220f8866fSmrg 	    ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) &
7333b617907Srin 	    ~URE_MCU_BORW_EN);
7343b617907Srin 	for (i = 0; i < URE_TIMEOUT; i++) {
7357f15b701Sriastradh 		if (usbnet_isdying(un))
7367f15b701Sriastradh 			return;
73720f8866fSmrg 		if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
7383b617907Srin 		    URE_LINK_LIST_READY)
7393b617907Srin 			break;
74020f8866fSmrg 		usbd_delay_ms(un->un_udev, 10);
7413b617907Srin 	}
7423b617907Srin 	if (i == URE_TIMEOUT)
74320f8866fSmrg 		URE_PRINTF(un, "timeout waiting for OOB control\n");
74420f8866fSmrg 	ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA,
74520f8866fSmrg 	    ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) |
7463b617907Srin 	    URE_RE_INIT_LL);
7473b617907Srin 	for (i = 0; i < URE_TIMEOUT; i++) {
7487f15b701Sriastradh 		if (usbnet_isdying(un))
7497f15b701Sriastradh 			return;
75020f8866fSmrg 		if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
7513b617907Srin 		    URE_LINK_LIST_READY)
7523b617907Srin 			break;
75320f8866fSmrg 		usbd_delay_ms(un->un_udev, 10);
7543b617907Srin 	}
7553b617907Srin 	if (i == URE_TIMEOUT)
75620f8866fSmrg 		URE_PRINTF(un, "timeout waiting for OOB control\n");
7573b617907Srin 
75820f8866fSmrg 	ure_write_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA,
75920f8866fSmrg 	    ure_read_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA) &
7603b617907Srin 	    ~URE_CPCR_RX_VLAN);
76120f8866fSmrg 	ure_write_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA,
76220f8866fSmrg 	    ure_read_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA) |
7633b617907Srin 	    URE_TCR0_AUTO_FIFO);
7643b617907Srin 
7653b617907Srin 	/* Configure Rx FIFO threshold and coalescing. */
76620f8866fSmrg 	ure_write_4(un, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA,
7673b617907Srin 	    URE_RXFIFO_THR1_NORMAL);
76820f8866fSmrg 	if (un->un_udev->ud_speed == USB_SPEED_FULL) {
7693b617907Srin 		rx_fifo1 = URE_RXFIFO_THR2_FULL;
7703b617907Srin 		rx_fifo2 = URE_RXFIFO_THR3_FULL;
7713b617907Srin 	} else {
7723b617907Srin 		rx_fifo1 = URE_RXFIFO_THR2_HIGH;
7733b617907Srin 		rx_fifo2 = URE_RXFIFO_THR3_HIGH;
7743b617907Srin 	}
77520f8866fSmrg 	ure_write_4(un, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1);
77620f8866fSmrg 	ure_write_4(un, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2);
7773b617907Srin 
7783b617907Srin 	/* Configure Tx FIFO threshold. */
77920f8866fSmrg 	ure_write_4(un, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA,
7803b617907Srin 	    URE_TXFIFO_THR_NORMAL);
7813b617907Srin }
7823b617907Srin 
7833b617907Srin static int
ure_match(device_t parent,cfdata_t match,void * aux)7843b617907Srin ure_match(device_t parent, cfdata_t match, void *aux)
7853b617907Srin {
7863b617907Srin 	struct usb_attach_arg *uaa = aux;
7873b617907Srin 
7883b617907Srin 	return usb_lookup(ure_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ?
7893b617907Srin 	    UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
7903b617907Srin }
7913b617907Srin 
7923b617907Srin static void
ure_attach(device_t parent,device_t self,void * aux)7933b617907Srin ure_attach(device_t parent, device_t self, void *aux)
7943b617907Srin {
7958352fa65Smrg 	USBNET_MII_DECL_DEFAULT(unm);
796e4ce9137Smrg 	struct usbnet * const un = device_private(self);
7973b617907Srin 	struct usb_attach_arg *uaa = aux;
7983b617907Srin 	struct usbd_device *dev = uaa->uaa_device;
7993b617907Srin 	usb_interface_descriptor_t *id;
8003b617907Srin 	usb_endpoint_descriptor_t *ed;
801aefaaa77Smrg 	int error, i;
8023b617907Srin 	uint16_t ver;
8033b617907Srin 	uint8_t eaddr[8]; /* 2byte padded */
8043b617907Srin 	char *devinfop;
805580b92a4Sbad 	uint32_t maclo, machi;
8063b617907Srin 
8073b617907Srin 	aprint_naive("\n");
8083b617907Srin 	aprint_normal("\n");
80920f8866fSmrg 	devinfop = usbd_devinfo_alloc(dev, 0);
8103b617907Srin 	aprint_normal_dev(self, "%s\n", devinfop);
8113b617907Srin 	usbd_devinfo_free(devinfop);
8123b617907Srin 
81320f8866fSmrg 	un->un_dev = self;
81420f8866fSmrg 	un->un_udev = dev;
815e4ce9137Smrg 	un->un_sc = un;
816d066f229Smrg 	un->un_ops = &ure_ops;
817dbbc1953Smrg 	un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
818dbbc1953Smrg 	un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
819dbbc1953Smrg 	un->un_rx_list_cnt = URE_RX_LIST_CNT;
820dbbc1953Smrg 	un->un_tx_list_cnt = URE_TX_LIST_CNT;
821dbbc1953Smrg 	un->un_rx_bufsz = URE_BUFSZ;
822dbbc1953Smrg 	un->un_tx_bufsz = URE_BUFSZ;
8232e7079bcSmrg 
8243b617907Srin #define URE_CONFIG_NO	1 /* XXX */
8253b617907Srin 	error = usbd_set_config_no(dev, URE_CONFIG_NO, 1);
8263b617907Srin 	if (error) {
8273b617907Srin 		aprint_error_dev(self, "failed to set configuration: %s\n",
8283b617907Srin 		    usbd_errstr(error));
8293b617907Srin 		return; /* XXX */
8303b617907Srin 	}
8313b617907Srin 
8323b617907Srin 	if (uaa->uaa_product == USB_PRODUCT_REALTEK_RTL8152)
833e4ce9137Smrg 		un->un_flags |= URE_FLAG_8152;
8343b617907Srin 
8353b617907Srin #define URE_IFACE_IDX  0 /* XXX */
83620f8866fSmrg 	error = usbd_device2interface_handle(dev, URE_IFACE_IDX, &un->un_iface);
8373b617907Srin 	if (error) {
8383b617907Srin 		aprint_error_dev(self, "failed to get interface handle: %s\n",
8393b617907Srin 		    usbd_errstr(error));
8403b617907Srin 		return; /* XXX */
8413b617907Srin 	}
8423b617907Srin 
84320f8866fSmrg 	id = usbd_get_interface_descriptor(un->un_iface);
8443b617907Srin 	for (i = 0; i < id->bNumEndpoints; i++) {
84520f8866fSmrg 		ed = usbd_interface2endpoint_descriptor(un->un_iface, i);
8463b617907Srin 		if (ed == NULL) {
8473b617907Srin 			aprint_error_dev(self, "couldn't get ep %d\n", i);
8483b617907Srin 			return; /* XXX */
8493b617907Srin 		}
8503b617907Srin 		if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
8513b617907Srin 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
85220f8866fSmrg 			un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress;
8533b617907Srin 		} else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
8543b617907Srin 		    UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
85520f8866fSmrg 			un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress;
8563b617907Srin 		}
8573b617907Srin 	}
8583b617907Srin 
85920f8866fSmrg 	/* Set these up now for ure_ctl().  */
8600b4ab8ceSriastradh 	usbnet_attach(un);
8613b617907Srin 
86220f8866fSmrg 	un->un_phyno = 0;
86320f8866fSmrg 
86420f8866fSmrg 	ver = ure_read_2(un, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK;
8653b617907Srin 	switch (ver) {
8663b617907Srin 	case 0x4c00:
867e4ce9137Smrg 		un->un_flags |= URE_FLAG_VER_4C00;
8683b617907Srin 		break;
8693b617907Srin 	case 0x4c10:
870e4ce9137Smrg 		un->un_flags |= URE_FLAG_VER_4C10;
8713b617907Srin 		break;
8723b617907Srin 	case 0x5c00:
873e4ce9137Smrg 		un->un_flags |= URE_FLAG_VER_5C00;
8743b617907Srin 		break;
8753b617907Srin 	case 0x5c10:
876e4ce9137Smrg 		un->un_flags |= URE_FLAG_VER_5C10;
8773b617907Srin 		break;
8783b617907Srin 	case 0x5c20:
879e4ce9137Smrg 		un->un_flags |= URE_FLAG_VER_5C20;
8803b617907Srin 		break;
8813b617907Srin 	case 0x5c30:
882e4ce9137Smrg 		un->un_flags |= URE_FLAG_VER_5C30;
8833b617907Srin 		break;
8843b617907Srin 	default:
8853b617907Srin 		/* fake addr?  or just fail? */
8863b617907Srin 		break;
8873b617907Srin 	}
88883f776bfSrin 	aprint_normal_dev(self, "RTL%d %sver %04x\n",
889e4ce9137Smrg 	    (un->un_flags & URE_FLAG_8152) ? 8152 : 8153,
890e4ce9137Smrg 	    (un->un_flags != 0) ? "" : "unknown ",
89183f776bfSrin 	    ver);
8923b617907Srin 
893e4ce9137Smrg 	if (un->un_flags & URE_FLAG_8152)
894e4ce9137Smrg 		ure_rtl8152_init(un);
8953b617907Srin 	else
896e4ce9137Smrg 		ure_rtl8153_init(un);
8973b617907Srin 
8988197ba69Sbad 	if ((un->un_flags & URE_FLAG_VER_4C00) ||
8998197ba69Sbad 	    (un->un_flags & URE_FLAG_VER_4C10))
90020f8866fSmrg 		ure_read_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA, eaddr,
9013b617907Srin 		    sizeof(eaddr));
9023b617907Srin 	else
90320f8866fSmrg 		ure_read_mem(un, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr,
9043b617907Srin 		    sizeof(eaddr));
905580b92a4Sbad 	if (ETHER_IS_ZERO(eaddr)) {
906580b92a4Sbad 		maclo = 0x00f2 | (cprng_strong32() & 0xffff0000);
907580b92a4Sbad 		machi = cprng_strong32() & 0xffff;
908580b92a4Sbad 		eaddr[0] = maclo & 0xff;
909580b92a4Sbad 		eaddr[1] = (maclo >> 8) & 0xff;
910580b92a4Sbad 		eaddr[2] = (maclo >> 16) & 0xff;
911580b92a4Sbad 		eaddr[3] = (maclo >> 24) & 0xff;
912580b92a4Sbad 		eaddr[4] = machi & 0xff;
913580b92a4Sbad 		eaddr[5] = (machi >> 8) & 0xff;
914580b92a4Sbad 	}
915dd4b336bSskrll 	memcpy(un->un_eaddr, eaddr, sizeof(un->un_eaddr));
9163b617907Srin 
91720f8866fSmrg 	struct ifnet *ifp = usbnet_ifp(un);
9183b617907Srin 
9193b617907Srin 	/*
9203b617907Srin 	 * We don't support TSOv4 and v6 for now, that are required to
9213b617907Srin 	 * be handled in software for some cases.
9223b617907Srin 	 */
9233b617907Srin 	ifp->if_capabilities = IFCAP_CSUM_IPv4_Tx |
9243b617907Srin 	    IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx;
9253b617907Srin #ifdef INET6
9263b617907Srin 	ifp->if_capabilities |= IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx;
9273b617907Srin #endif
928e4ce9137Smrg 	if (un->un_flags & ~URE_FLAG_VER_4C00) {
9293b617907Srin 		ifp->if_capabilities |= IFCAP_CSUM_IPv4_Rx |
9303b617907Srin 		    IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx |
9313b617907Srin 		    IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx;
9323b617907Srin 	}
93320f8866fSmrg 	struct ethercom *ec = usbnet_ec(un);
93420f8866fSmrg 	ec->ec_capabilities = ETHERCAP_VLAN_MTU;
9353b617907Srin #ifdef notyet
93620f8866fSmrg 	ec->ec_capabilities |= ETHERCAP_JUMBO_MTU;
9373b617907Srin #endif
9383b617907Srin 
93965dae968Smrg 	unm.un_mii_phyloc = un->un_phyno;
94065dae968Smrg 	usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST,
94165dae968Smrg 	    0, &unm);
9423b617907Srin }
9433b617907Srin 
9443b617907Srin static void
ure_uno_rx_loop(struct usbnet * un,struct usbnet_chain * c,uint32_t total_len)9457a9a30c5Sthorpej ure_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len)
9463b617907Srin {
94720f8866fSmrg 	struct ifnet *ifp = usbnet_ifp(un);
94820f8866fSmrg 	uint8_t *buf = c->unc_buf;
94920f8866fSmrg 	uint16_t pkt_len = 0;
95020f8866fSmrg 	uint16_t pkt_count = 0;
9513b617907Srin 	struct ure_rxpkt rxhdr;
9523b617907Srin 
9533b617907Srin 	do {
9543b617907Srin 		if (total_len < sizeof(rxhdr)) {
9553b617907Srin 			DPRINTF(("too few bytes left for a packet header\n"));
956cdaa0e91Sthorpej 			if_statinc(ifp, if_ierrors);
95720f8866fSmrg 			return;
9583b617907Srin 		}
9593b617907Srin 
96020f8866fSmrg 		buf += roundup(pkt_len, 8);
9613b617907Srin 
9623b617907Srin 		memcpy(&rxhdr, buf, sizeof(rxhdr));
9633b617907Srin 		total_len -= sizeof(rxhdr);
9643b617907Srin 
96520f8866fSmrg 		pkt_len = le32toh(rxhdr.ure_pktlen) & URE_RXPKT_LEN_MASK;
96620f8866fSmrg 		DPRINTFN(4, ("next packet is %d bytes\n", pkt_len));
96720f8866fSmrg 		if (pkt_len > total_len) {
9683b617907Srin 			DPRINTF(("not enough bytes left for next packet\n"));
969cdaa0e91Sthorpej 			if_statinc(ifp, if_ierrors);
970aefaaa77Smrg 			return;
971aefaaa77Smrg 		}
972aefaaa77Smrg 
97320f8866fSmrg 		total_len -= roundup(pkt_len, 8);
97420f8866fSmrg 		buf += sizeof(rxhdr);
97520f8866fSmrg 
97620f8866fSmrg 		usbnet_enqueue(un, buf, pkt_len - ETHER_CRC_LEN,
97776b0c5e3Smrg 			       ure_rxcsum(ifp, &rxhdr), 0, 0);
97820f8866fSmrg 
97920f8866fSmrg 		pkt_count++;
98020f8866fSmrg 
9813b617907Srin 	} while (total_len > 0);
9823b617907Srin 
98320f8866fSmrg 	if (pkt_count)
984d066f229Smrg 		rnd_add_uint32(usbnet_rndsrc(un), pkt_count);
9853b617907Srin }
9863b617907Srin 
9873b617907Srin static int
ure_rxcsum(struct ifnet * ifp,struct ure_rxpkt * rp)9883b617907Srin ure_rxcsum(struct ifnet *ifp, struct ure_rxpkt *rp)
9893b617907Srin {
9903b617907Srin 	int enabled = ifp->if_csum_flags_rx, flags = 0;
9913b617907Srin 	uint32_t csum, misc;
9923b617907Srin 
9933b617907Srin 	if (enabled == 0)
9943b617907Srin 		return 0;
9953b617907Srin 
9963b617907Srin 	csum = le32toh(rp->ure_csum);
9973b617907Srin 	misc = le32toh(rp->ure_misc);
9983b617907Srin 
9993b617907Srin 	if (csum & URE_RXPKT_IPV4_CS) {
10003b617907Srin 		flags |= M_CSUM_IPv4;
10013b617907Srin 		if (csum & URE_RXPKT_TCP_CS)
10023b617907Srin 			flags |= M_CSUM_TCPv4;
10033b617907Srin 		if (csum & URE_RXPKT_UDP_CS)
10043b617907Srin 			flags |= M_CSUM_UDPv4;
10053b617907Srin 	} else if (csum & URE_RXPKT_IPV6_CS) {
10063b617907Srin 		flags = 0;
10073b617907Srin 		if (csum & URE_RXPKT_TCP_CS)
10083b617907Srin 			flags |= M_CSUM_TCPv6;
10093b617907Srin 		if (csum & URE_RXPKT_UDP_CS)
10103b617907Srin 			flags |= M_CSUM_UDPv6;
10113b617907Srin 	}
10123b617907Srin 
10133b617907Srin 	flags &= enabled;
10143b617907Srin 	if (__predict_false((flags & M_CSUM_IPv4) &&
10153b617907Srin 	    (misc & URE_RXPKT_IP_F)))
10163b617907Srin 		flags |= M_CSUM_IPv4_BAD;
10173b617907Srin 	if (__predict_false(
10183b617907Srin 	   ((flags & (M_CSUM_TCPv4 | M_CSUM_TCPv6)) && (misc & URE_RXPKT_TCP_F))
10193b617907Srin 	|| ((flags & (M_CSUM_UDPv4 | M_CSUM_UDPv6)) && (misc & URE_RXPKT_UDP_F))
10203b617907Srin 	))
10213b617907Srin 		flags |= M_CSUM_TCP_UDP_BAD;
10223b617907Srin 
10233b617907Srin 	return flags;
10243b617907Srin }
10253b617907Srin 
102620f8866fSmrg static unsigned
ure_uno_tx_prepare(struct usbnet * un,struct mbuf * m,struct usbnet_chain * c)10277a9a30c5Sthorpej ure_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
10283b617907Srin {
10293b617907Srin 	struct ure_txpkt txhdr;
10303b617907Srin 	uint32_t frm_len = 0;
103120f8866fSmrg 	uint8_t *buf = c->unc_buf;
10323b617907Srin 
1033a4d53673Sskrll 	if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(txhdr))
103497f70a3cSmrg 		return 0;
103597f70a3cSmrg 
10363b617907Srin 	/* header */
10373b617907Srin 	txhdr.ure_pktlen = htole32(m->m_pkthdr.len | URE_TXPKT_TX_FS |
10383b617907Srin 	    URE_TXPKT_TX_LS);
10393b617907Srin 	txhdr.ure_csum = htole32(ure_txcsum(m));
10403b617907Srin 	memcpy(buf, &txhdr, sizeof(txhdr));
10413b617907Srin 	buf += sizeof(txhdr);
10423b617907Srin 	frm_len = sizeof(txhdr);
10433b617907Srin 
10443b617907Srin 	/* packet */
10453b617907Srin 	m_copydata(m, 0, m->m_pkthdr.len, buf);
10463b617907Srin 	frm_len += m->m_pkthdr.len;
10473b617907Srin 
10483b617907Srin 	DPRINTFN(2, ("tx %d bytes\n", frm_len));
10493b617907Srin 
105020f8866fSmrg 	return frm_len;
10513b617907Srin }
10523b617907Srin 
10533b617907Srin /*
10543b617907Srin  * We need to calculate L4 checksum in software, if the offset of
10553b617907Srin  * L4 header is larger than 0x7ff = 2047.
10563b617907Srin  */
10573b617907Srin static uint32_t
ure_txcsum(struct mbuf * m)10583b617907Srin ure_txcsum(struct mbuf *m)
10593b617907Srin {
10603b617907Srin 	struct ether_header *eh;
10613b617907Srin 	int flags = m->m_pkthdr.csum_flags;
10623b617907Srin 	uint32_t data = m->m_pkthdr.csum_data;
10633b617907Srin 	uint32_t reg = 0;
10643b617907Srin 	int l3off, l4off;
10653b617907Srin 	uint16_t type;
10663b617907Srin 
10673b617907Srin 	if (flags == 0)
10683b617907Srin 		return 0;
10693b617907Srin 
1070808d89bdSrin 	if (__predict_true(m->m_len >= (int)sizeof(*eh))) {
10713b617907Srin 		eh = mtod(m, struct ether_header *);
10723b617907Srin 		type = eh->ether_type;
10733b617907Srin 	} else
10743b617907Srin 		m_copydata(m, offsetof(struct ether_header, ether_type),
10753b617907Srin 		    sizeof(type), &type);
10763b617907Srin 	switch (type = htons(type)) {
10773b617907Srin 	case ETHERTYPE_IP:
10783b617907Srin 	case ETHERTYPE_IPV6:
10793b617907Srin 		l3off = ETHER_HDR_LEN;
10803b617907Srin 		break;
10813b617907Srin 	case ETHERTYPE_VLAN:
10823b617907Srin 		l3off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
10833b617907Srin 		break;
10843b617907Srin 	default:
10853b617907Srin 		return 0;
10863b617907Srin 	}
10873b617907Srin 
10883b617907Srin 	if (flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) {
10893b617907Srin 		l4off = l3off + M_CSUM_DATA_IPv4_IPHL(data);
10903b617907Srin 		if (__predict_false(l4off > URE_L4_OFFSET_MAX)) {
10913b617907Srin 			in_undefer_cksum(m, l3off, flags);
10923b617907Srin 			return 0;
10933b617907Srin 		}
10943b617907Srin 		reg |= URE_TXPKT_IPV4_CS;
10953b617907Srin 		if (flags & M_CSUM_TCPv4)
10963b617907Srin 			reg |= URE_TXPKT_TCP_CS;
10973b617907Srin 		else
10983b617907Srin 			reg |= URE_TXPKT_UDP_CS;
10993b617907Srin 		reg |= l4off << URE_L4_OFFSET_SHIFT;
11003b617907Srin 	}
11013b617907Srin #ifdef INET6
11023b617907Srin 	else if (flags & (M_CSUM_TCPv6 | M_CSUM_UDPv6)) {
11033b617907Srin 		l4off = l3off + M_CSUM_DATA_IPv6_IPHL(data);
11043b617907Srin 		if (__predict_false(l4off > URE_L4_OFFSET_MAX)) {
11053b617907Srin 			in6_undefer_cksum(m, l3off, flags);
11063b617907Srin 			return 0;
11073b617907Srin 		}
11083b617907Srin 		reg |= URE_TXPKT_IPV6_CS;
11093b617907Srin 		if (flags & M_CSUM_TCPv6)
11103b617907Srin 			reg |= URE_TXPKT_TCP_CS;
11113b617907Srin 		else
11123b617907Srin 			reg |= URE_TXPKT_UDP_CS;
11133b617907Srin 		reg |= l4off << URE_L4_OFFSET_SHIFT;
11143b617907Srin 	}
11153b617907Srin #endif
11163b617907Srin 	else if (flags & M_CSUM_IPv4)
11173b617907Srin 		reg |= URE_TXPKT_IPV4_CS;
11183b617907Srin 
11193b617907Srin 	return reg;
11203b617907Srin }
1121e4ce9137Smrg 
1122f1e87e99Smrg #ifdef _MODULE
1123f1e87e99Smrg #include "ioconf.c"
1124f1e87e99Smrg #endif
1125f1e87e99Smrg 
1126f1e87e99Smrg USBNET_MODULE(ure)
1127