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