if_ure.c revision 1.8.2.3 1 1.8.2.3 martin /* $NetBSD: if_ure.c,v 1.8.2.3 2020/04/13 08:04:49 martin Exp $ */
2 1.8.2.2 christos /* $OpenBSD: if_ure.c,v 1.10 2018/11/02 21:32:30 jcs Exp $ */
3 1.8.2.3 martin
4 1.8.2.2 christos /*-
5 1.8.2.2 christos * Copyright (c) 2015-2016 Kevin Lo <kevlo (at) FreeBSD.org>
6 1.8.2.2 christos * All rights reserved.
7 1.8.2.2 christos *
8 1.8.2.2 christos * Redistribution and use in source and binary forms, with or without
9 1.8.2.2 christos * modification, are permitted provided that the following conditions
10 1.8.2.2 christos * are met:
11 1.8.2.2 christos * 1. Redistributions of source code must retain the above copyright
12 1.8.2.2 christos * notice, this list of conditions and the following disclaimer.
13 1.8.2.2 christos * 2. Redistributions in binary form must reproduce the above copyright
14 1.8.2.2 christos * notice, this list of conditions and the following disclaimer in the
15 1.8.2.2 christos * documentation and/or other materials provided with the distribution.
16 1.8.2.2 christos *
17 1.8.2.2 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 1.8.2.2 christos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 1.8.2.2 christos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 1.8.2.2 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 1.8.2.2 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 1.8.2.2 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 1.8.2.2 christos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 1.8.2.2 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 1.8.2.2 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 1.8.2.2 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 1.8.2.2 christos * SUCH DAMAGE.
28 1.8.2.2 christos */
29 1.8.2.2 christos
30 1.8.2.2 christos /* RealTek RTL8152/RTL8153 10/100/Gigabit USB Ethernet device */
31 1.8.2.2 christos
32 1.8.2.2 christos #include <sys/cdefs.h>
33 1.8.2.3 martin __KERNEL_RCSID(0, "$NetBSD: if_ure.c,v 1.8.2.3 2020/04/13 08:04:49 martin Exp $");
34 1.8.2.2 christos
35 1.8.2.2 christos #ifdef _KERNEL_OPT
36 1.8.2.2 christos #include "opt_usb.h"
37 1.8.2.2 christos #include "opt_inet.h"
38 1.8.2.2 christos #endif
39 1.8.2.2 christos
40 1.8.2.2 christos #include <sys/param.h>
41 1.8.2.3 martin #include <sys/cprng.h>
42 1.8.2.2 christos
43 1.8.2.3 martin #include <net/route.h>
44 1.8.2.2 christos
45 1.8.2.3 martin #include <dev/usb/usbnet.h>
46 1.8.2.2 christos
47 1.8.2.2 christos #include <netinet/in_offload.h> /* XXX for in_undefer_cksum() */
48 1.8.2.2 christos #ifdef INET6
49 1.8.2.3 martin #include <netinet/in.h>
50 1.8.2.2 christos #include <netinet6/in6_offload.h> /* XXX for in6_undefer_cksum() */
51 1.8.2.2 christos #endif
52 1.8.2.2 christos
53 1.8.2.2 christos #include <dev/ic/rtl81x9reg.h> /* XXX for RTK_GMEDIASTAT */
54 1.8.2.2 christos #include <dev/usb/if_urereg.h>
55 1.8.2.2 christos #include <dev/usb/if_urevar.h>
56 1.8.2.2 christos
57 1.8.2.3 martin #define URE_PRINTF(un, fmt, args...) \
58 1.8.2.3 martin device_printf((un)->un_dev, "%s: " fmt, __func__, ##args);
59 1.8.2.2 christos
60 1.8.2.2 christos #define URE_DEBUG
61 1.8.2.2 christos #ifdef URE_DEBUG
62 1.8.2.2 christos #define DPRINTF(x) do { if (uredebug) printf x; } while (0)
63 1.8.2.2 christos #define DPRINTFN(n, x) do { if (uredebug >= (n)) printf x; } while (0)
64 1.8.2.3 martin int uredebug = 0;
65 1.8.2.2 christos #else
66 1.8.2.2 christos #define DPRINTF(x)
67 1.8.2.2 christos #define DPRINTFN(n, x)
68 1.8.2.2 christos #endif
69 1.8.2.2 christos
70 1.8.2.3 martin #define ETHER_IS_ZERO(addr) \
71 1.8.2.3 martin (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]))
72 1.8.2.3 martin
73 1.8.2.2 christos static const struct usb_devno ure_devs[] = {
74 1.8.2.2 christos { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8152 },
75 1.8.2.2 christos { USB_VENDOR_REALTEK, USB_PRODUCT_REALTEK_RTL8153 }
76 1.8.2.2 christos };
77 1.8.2.2 christos
78 1.8.2.3 martin #define URE_BUFSZ (16 * 1024)
79 1.8.2.2 christos
80 1.8.2.3 martin static void ure_reset(struct usbnet *);
81 1.8.2.2 christos static uint32_t ure_txcsum(struct mbuf *);
82 1.8.2.2 christos static int ure_rxcsum(struct ifnet *, struct ure_rxpkt *);
83 1.8.2.3 martin static void ure_rtl8152_init(struct usbnet *);
84 1.8.2.3 martin static void ure_rtl8153_init(struct usbnet *);
85 1.8.2.3 martin static void ure_disable_teredo(struct usbnet *);
86 1.8.2.3 martin static void ure_init_fifo(struct usbnet *);
87 1.8.2.3 martin
88 1.8.2.3 martin static void ure_uno_stop(struct ifnet *, int);
89 1.8.2.3 martin static int ure_uno_ioctl(struct ifnet *, u_long, void *);
90 1.8.2.3 martin static int ure_uno_mii_read_reg(struct usbnet *, int, int, uint16_t *);
91 1.8.2.3 martin static int ure_uno_mii_write_reg(struct usbnet *, int, int, uint16_t);
92 1.8.2.3 martin static void ure_uno_miibus_statchg(struct ifnet *);
93 1.8.2.3 martin static unsigned ure_uno_tx_prepare(struct usbnet *, struct mbuf *,
94 1.8.2.3 martin struct usbnet_chain *);
95 1.8.2.3 martin static void ure_uno_rx_loop(struct usbnet *, struct usbnet_chain *,
96 1.8.2.3 martin uint32_t);
97 1.8.2.3 martin static int ure_uno_init(struct ifnet *);
98 1.8.2.3 martin
99 1.8.2.3 martin static int ure_match(device_t, cfdata_t, void *);
100 1.8.2.3 martin static void ure_attach(device_t, device_t, void *);
101 1.8.2.2 christos
102 1.8.2.3 martin CFATTACH_DECL_NEW(ure, sizeof(struct usbnet), ure_match, ure_attach,
103 1.8.2.3 martin usbnet_detach, usbnet_activate);
104 1.8.2.3 martin
105 1.8.2.3 martin static const struct usbnet_ops ure_ops = {
106 1.8.2.3 martin .uno_stop = ure_uno_stop,
107 1.8.2.3 martin .uno_ioctl = ure_uno_ioctl,
108 1.8.2.3 martin .uno_read_reg = ure_uno_mii_read_reg,
109 1.8.2.3 martin .uno_write_reg = ure_uno_mii_write_reg,
110 1.8.2.3 martin .uno_statchg = ure_uno_miibus_statchg,
111 1.8.2.3 martin .uno_tx_prepare = ure_uno_tx_prepare,
112 1.8.2.3 martin .uno_rx_loop = ure_uno_rx_loop,
113 1.8.2.3 martin .uno_init = ure_uno_init,
114 1.8.2.3 martin };
115 1.8.2.2 christos
116 1.8.2.2 christos static int
117 1.8.2.3 martin ure_ctl(struct usbnet *un, uint8_t rw, uint16_t val, uint16_t index,
118 1.8.2.2 christos void *buf, int len)
119 1.8.2.2 christos {
120 1.8.2.2 christos usb_device_request_t req;
121 1.8.2.2 christos usbd_status err;
122 1.8.2.2 christos
123 1.8.2.3 martin if (usbnet_isdying(un))
124 1.8.2.2 christos return 0;
125 1.8.2.2 christos
126 1.8.2.2 christos if (rw == URE_CTL_WRITE)
127 1.8.2.2 christos req.bmRequestType = UT_WRITE_VENDOR_DEVICE;
128 1.8.2.2 christos else
129 1.8.2.2 christos req.bmRequestType = UT_READ_VENDOR_DEVICE;
130 1.8.2.2 christos req.bRequest = UR_SET_ADDRESS;
131 1.8.2.2 christos USETW(req.wValue, val);
132 1.8.2.2 christos USETW(req.wIndex, index);
133 1.8.2.2 christos USETW(req.wLength, len);
134 1.8.2.2 christos
135 1.8.2.3 martin DPRINTFN(5, ("ure_ctl: rw %d, val %04hu, index %04hu, len %d\n",
136 1.8.2.2 christos rw, val, index, len));
137 1.8.2.3 martin err = usbd_do_request(un->un_udev, &req, buf);
138 1.8.2.2 christos if (err) {
139 1.8.2.2 christos DPRINTF(("ure_ctl: error %d\n", err));
140 1.8.2.2 christos return -1;
141 1.8.2.2 christos }
142 1.8.2.2 christos
143 1.8.2.2 christos return 0;
144 1.8.2.2 christos }
145 1.8.2.2 christos
146 1.8.2.2 christos static int
147 1.8.2.3 martin ure_read_mem(struct usbnet *un, uint16_t addr, uint16_t index,
148 1.8.2.2 christos void *buf, int len)
149 1.8.2.2 christos {
150 1.8.2.3 martin return ure_ctl(un, URE_CTL_READ, addr, index, buf, len);
151 1.8.2.2 christos }
152 1.8.2.2 christos
153 1.8.2.2 christos static int
154 1.8.2.3 martin ure_write_mem(struct usbnet *un, uint16_t addr, uint16_t index,
155 1.8.2.2 christos void *buf, int len)
156 1.8.2.2 christos {
157 1.8.2.3 martin return ure_ctl(un, URE_CTL_WRITE, addr, index, buf, len);
158 1.8.2.2 christos }
159 1.8.2.2 christos
160 1.8.2.2 christos static uint8_t
161 1.8.2.3 martin ure_read_1(struct usbnet *un, uint16_t reg, uint16_t index)
162 1.8.2.2 christos {
163 1.8.2.2 christos uint32_t val;
164 1.8.2.2 christos uint8_t temp[4];
165 1.8.2.2 christos uint8_t shift;
166 1.8.2.2 christos
167 1.8.2.2 christos shift = (reg & 3) << 3;
168 1.8.2.2 christos reg &= ~3;
169 1.8.2.2 christos
170 1.8.2.3 martin ure_read_mem(un, reg, index, &temp, 4);
171 1.8.2.2 christos val = UGETDW(temp);
172 1.8.2.2 christos val >>= shift;
173 1.8.2.2 christos
174 1.8.2.2 christos return val & 0xff;
175 1.8.2.2 christos }
176 1.8.2.2 christos
177 1.8.2.2 christos static uint16_t
178 1.8.2.3 martin ure_read_2(struct usbnet *un, uint16_t reg, uint16_t index)
179 1.8.2.2 christos {
180 1.8.2.2 christos uint32_t val;
181 1.8.2.2 christos uint8_t temp[4];
182 1.8.2.2 christos uint8_t shift;
183 1.8.2.2 christos
184 1.8.2.2 christos shift = (reg & 2) << 3;
185 1.8.2.2 christos reg &= ~3;
186 1.8.2.2 christos
187 1.8.2.3 martin ure_read_mem(un, reg, index, &temp, 4);
188 1.8.2.2 christos val = UGETDW(temp);
189 1.8.2.2 christos val >>= shift;
190 1.8.2.2 christos
191 1.8.2.2 christos return val & 0xffff;
192 1.8.2.2 christos }
193 1.8.2.2 christos
194 1.8.2.2 christos static uint32_t
195 1.8.2.3 martin ure_read_4(struct usbnet *un, uint16_t reg, uint16_t index)
196 1.8.2.2 christos {
197 1.8.2.2 christos uint8_t temp[4];
198 1.8.2.2 christos
199 1.8.2.3 martin ure_read_mem(un, reg, index, &temp, 4);
200 1.8.2.2 christos return UGETDW(temp);
201 1.8.2.2 christos }
202 1.8.2.2 christos
203 1.8.2.2 christos static int
204 1.8.2.3 martin ure_write_1(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val)
205 1.8.2.2 christos {
206 1.8.2.2 christos uint16_t byen;
207 1.8.2.2 christos uint8_t temp[4];
208 1.8.2.2 christos uint8_t shift;
209 1.8.2.2 christos
210 1.8.2.2 christos byen = URE_BYTE_EN_BYTE;
211 1.8.2.2 christos shift = reg & 3;
212 1.8.2.2 christos val &= 0xff;
213 1.8.2.2 christos
214 1.8.2.2 christos if (reg & 3) {
215 1.8.2.2 christos byen <<= shift;
216 1.8.2.2 christos val <<= (shift << 3);
217 1.8.2.2 christos reg &= ~3;
218 1.8.2.2 christos }
219 1.8.2.2 christos
220 1.8.2.2 christos USETDW(temp, val);
221 1.8.2.3 martin return ure_write_mem(un, reg, index | byen, &temp, 4);
222 1.8.2.2 christos }
223 1.8.2.2 christos
224 1.8.2.2 christos static int
225 1.8.2.3 martin ure_write_2(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val)
226 1.8.2.2 christos {
227 1.8.2.2 christos uint16_t byen;
228 1.8.2.2 christos uint8_t temp[4];
229 1.8.2.2 christos uint8_t shift;
230 1.8.2.2 christos
231 1.8.2.2 christos byen = URE_BYTE_EN_WORD;
232 1.8.2.2 christos shift = reg & 2;
233 1.8.2.2 christos val &= 0xffff;
234 1.8.2.2 christos
235 1.8.2.2 christos if (reg & 2) {
236 1.8.2.2 christos byen <<= shift;
237 1.8.2.2 christos val <<= (shift << 3);
238 1.8.2.2 christos reg &= ~3;
239 1.8.2.2 christos }
240 1.8.2.2 christos
241 1.8.2.2 christos USETDW(temp, val);
242 1.8.2.3 martin return ure_write_mem(un, reg, index | byen, &temp, 4);
243 1.8.2.2 christos }
244 1.8.2.2 christos
245 1.8.2.2 christos static int
246 1.8.2.3 martin ure_write_4(struct usbnet *un, uint16_t reg, uint16_t index, uint32_t val)
247 1.8.2.2 christos {
248 1.8.2.2 christos uint8_t temp[4];
249 1.8.2.2 christos
250 1.8.2.2 christos USETDW(temp, val);
251 1.8.2.3 martin return ure_write_mem(un, reg, index | URE_BYTE_EN_DWORD, &temp, 4);
252 1.8.2.2 christos }
253 1.8.2.2 christos
254 1.8.2.2 christos static uint16_t
255 1.8.2.3 martin ure_ocp_reg_read(struct usbnet *un, uint16_t addr)
256 1.8.2.2 christos {
257 1.8.2.2 christos uint16_t reg;
258 1.8.2.2 christos
259 1.8.2.3 martin ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000);
260 1.8.2.2 christos reg = (addr & 0x0fff) | 0xb000;
261 1.8.2.2 christos
262 1.8.2.3 martin return ure_read_2(un, reg, URE_MCU_TYPE_PLA);
263 1.8.2.2 christos }
264 1.8.2.2 christos
265 1.8.2.2 christos static void
266 1.8.2.3 martin ure_ocp_reg_write(struct usbnet *un, uint16_t addr, uint16_t data)
267 1.8.2.2 christos {
268 1.8.2.2 christos uint16_t reg;
269 1.8.2.2 christos
270 1.8.2.3 martin ure_write_2(un, URE_PLA_OCP_GPHY_BASE, URE_MCU_TYPE_PLA, addr & 0xf000);
271 1.8.2.2 christos reg = (addr & 0x0fff) | 0xb000;
272 1.8.2.2 christos
273 1.8.2.3 martin ure_write_2(un, reg, URE_MCU_TYPE_PLA, data);
274 1.8.2.2 christos }
275 1.8.2.2 christos
276 1.8.2.2 christos static int
277 1.8.2.3 martin ure_uno_mii_read_reg(struct usbnet *un, int phy, int reg, uint16_t *val)
278 1.8.2.2 christos {
279 1.8.2.2 christos
280 1.8.2.3 martin if (un->un_phyno != phy)
281 1.8.2.3 martin return EINVAL;
282 1.8.2.2 christos
283 1.8.2.2 christos /* Let the rgephy driver read the URE_PLA_PHYSTATUS register. */
284 1.8.2.2 christos if (reg == RTK_GMEDIASTAT) {
285 1.8.2.3 martin *val = ure_read_1(un, URE_PLA_PHYSTATUS, URE_MCU_TYPE_PLA);
286 1.8.2.3 martin return USBD_NORMAL_COMPLETION;
287 1.8.2.2 christos }
288 1.8.2.2 christos
289 1.8.2.3 martin *val = ure_ocp_reg_read(un, URE_OCP_BASE_MII + reg * 2);
290 1.8.2.2 christos
291 1.8.2.2 christos return 0;
292 1.8.2.2 christos }
293 1.8.2.2 christos
294 1.8.2.2 christos static int
295 1.8.2.3 martin ure_uno_mii_write_reg(struct usbnet *un, int phy, int reg, uint16_t val)
296 1.8.2.2 christos {
297 1.8.2.2 christos
298 1.8.2.3 martin if (un->un_phyno != phy)
299 1.8.2.3 martin return EINVAL;
300 1.8.2.2 christos
301 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_BASE_MII + reg * 2, val);
302 1.8.2.2 christos
303 1.8.2.2 christos return 0;
304 1.8.2.2 christos }
305 1.8.2.2 christos
306 1.8.2.2 christos static void
307 1.8.2.3 martin ure_uno_miibus_statchg(struct ifnet *ifp)
308 1.8.2.2 christos {
309 1.8.2.3 martin struct usbnet * const un = ifp->if_softc;
310 1.8.2.3 martin struct mii_data * const mii = usbnet_mii(un);
311 1.8.2.2 christos
312 1.8.2.3 martin if (usbnet_isdying(un))
313 1.8.2.2 christos return;
314 1.8.2.2 christos
315 1.8.2.2 christos if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
316 1.8.2.2 christos (IFM_ACTIVE | IFM_AVALID)) {
317 1.8.2.2 christos switch (IFM_SUBTYPE(mii->mii_media_active)) {
318 1.8.2.2 christos case IFM_10_T:
319 1.8.2.2 christos case IFM_100_TX:
320 1.8.2.3 martin usbnet_set_link(un, true);
321 1.8.2.2 christos break;
322 1.8.2.2 christos case IFM_1000_T:
323 1.8.2.3 martin if ((un->un_flags & URE_FLAG_8152) != 0)
324 1.8.2.2 christos break;
325 1.8.2.3 martin usbnet_set_link(un, true);
326 1.8.2.2 christos break;
327 1.8.2.2 christos default:
328 1.8.2.2 christos break;
329 1.8.2.2 christos }
330 1.8.2.2 christos }
331 1.8.2.2 christos }
332 1.8.2.2 christos
333 1.8.2.2 christos static void
334 1.8.2.3 martin ure_rcvfilt_locked(struct usbnet *un)
335 1.8.2.2 christos {
336 1.8.2.3 martin struct ethercom *ec = usbnet_ec(un);
337 1.8.2.3 martin struct ifnet *ifp = usbnet_ifp(un);
338 1.8.2.2 christos struct ether_multi *enm;
339 1.8.2.2 christos struct ether_multistep step;
340 1.8.2.3 martin uint32_t mchash[2] = { 0, 0 };
341 1.8.2.3 martin uint32_t h = 0, rxmode;
342 1.8.2.2 christos
343 1.8.2.3 martin usbnet_isowned_core(un);
344 1.8.2.2 christos
345 1.8.2.3 martin if (usbnet_isdying(un))
346 1.8.2.3 martin return;
347 1.8.2.2 christos
348 1.8.2.3 martin rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA);
349 1.8.2.3 martin rxmode &= ~(URE_RCR_AAP | URE_RCR_AM);
350 1.8.2.3 martin /* continue to accept my own DA and bcast frames */
351 1.8.2.2 christos
352 1.8.2.3 martin ETHER_LOCK(ec);
353 1.8.2.2 christos if (ifp->if_flags & IFF_PROMISC) {
354 1.8.2.3 martin ec->ec_flags |= ETHER_F_ALLMULTI;
355 1.8.2.2 christos ETHER_UNLOCK(ec);
356 1.8.2.3 martin /* run promisc. mode */
357 1.8.2.3 martin rxmode |= URE_RCR_AM; /* ??? */
358 1.8.2.3 martin rxmode |= URE_RCR_AAP;
359 1.8.2.3 martin goto update;
360 1.8.2.2 christos }
361 1.8.2.3 martin ec->ec_flags &= ~ETHER_F_ALLMULTI;
362 1.8.2.3 martin ETHER_FIRST_MULTI(step, ec, enm);
363 1.8.2.3 martin while (enm != NULL) {
364 1.8.2.3 martin if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
365 1.8.2.3 martin ec->ec_flags |= ETHER_F_ALLMULTI;
366 1.8.2.3 martin ETHER_UNLOCK(ec);
367 1.8.2.3 martin /* accept all mcast frames */
368 1.8.2.3 martin rxmode |= URE_RCR_AM;
369 1.8.2.3 martin mchash[0] = mchash[1] = ~0U; /* necessary ?? */
370 1.8.2.3 martin goto update;
371 1.8.2.3 martin }
372 1.8.2.3 martin h = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN);
373 1.8.2.3 martin mchash[h >> 31] |= 1 << ((h >> 26) & 0x1f);
374 1.8.2.3 martin ETHER_NEXT_MULTI(step, enm);
375 1.8.2.3 martin }
376 1.8.2.3 martin ETHER_UNLOCK(ec);
377 1.8.2.3 martin if (h != 0) {
378 1.8.2.3 martin rxmode |= URE_RCR_AM; /* activate mcast hash filter */
379 1.8.2.3 martin h = bswap32(mchash[0]);
380 1.8.2.3 martin mchash[0] = bswap32(mchash[1]);
381 1.8.2.3 martin mchash[1] = h;
382 1.8.2.3 martin }
383 1.8.2.3 martin update:
384 1.8.2.3 martin ure_write_4(un, URE_PLA_MAR0, URE_MCU_TYPE_PLA, mchash[0]);
385 1.8.2.3 martin ure_write_4(un, URE_PLA_MAR4, URE_MCU_TYPE_PLA, mchash[1]);
386 1.8.2.3 martin ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode);
387 1.8.2.2 christos }
388 1.8.2.2 christos
389 1.8.2.2 christos static void
390 1.8.2.3 martin ure_reset(struct usbnet *un)
391 1.8.2.2 christos {
392 1.8.2.2 christos int i;
393 1.8.2.2 christos
394 1.8.2.3 martin usbnet_isowned_core(un);
395 1.8.2.3 martin
396 1.8.2.3 martin ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, URE_CR_RST);
397 1.8.2.2 christos
398 1.8.2.2 christos for (i = 0; i < URE_TIMEOUT; i++) {
399 1.8.2.3 martin if (!(ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) &
400 1.8.2.2 christos URE_CR_RST))
401 1.8.2.2 christos break;
402 1.8.2.3 martin usbd_delay_ms(un->un_udev, 10);
403 1.8.2.2 christos }
404 1.8.2.2 christos if (i == URE_TIMEOUT)
405 1.8.2.3 martin URE_PRINTF(un, "reset never completed\n");
406 1.8.2.2 christos }
407 1.8.2.2 christos
408 1.8.2.2 christos static int
409 1.8.2.3 martin ure_init_locked(struct ifnet *ifp)
410 1.8.2.2 christos {
411 1.8.2.3 martin struct usbnet * const un = ifp->if_softc;
412 1.8.2.2 christos uint8_t eaddr[8];
413 1.8.2.2 christos
414 1.8.2.3 martin usbnet_isowned_core(un);
415 1.8.2.3 martin
416 1.8.2.3 martin if (usbnet_isdying(un))
417 1.8.2.3 martin return EIO;
418 1.8.2.2 christos
419 1.8.2.2 christos /* Cancel pending I/O. */
420 1.8.2.2 christos if (ifp->if_flags & IFF_RUNNING)
421 1.8.2.3 martin usbnet_stop(un, ifp, 1);
422 1.8.2.2 christos
423 1.8.2.2 christos /* Set MAC address. */
424 1.8.2.2 christos memset(eaddr, 0, sizeof(eaddr));
425 1.8.2.2 christos memcpy(eaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN);
426 1.8.2.3 martin ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_CONFIG);
427 1.8.2.3 martin ure_write_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA | URE_BYTE_EN_SIX_BYTES,
428 1.8.2.2 christos eaddr, 8);
429 1.8.2.3 martin ure_write_1(un, URE_PLA_CRWECR, URE_MCU_TYPE_PLA, URE_CRWECR_NORAML);
430 1.8.2.2 christos
431 1.8.2.2 christos /* Reset the packet filter. */
432 1.8.2.3 martin ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA,
433 1.8.2.3 martin ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) &
434 1.8.2.2 christos ~URE_FMC_FCR_MCU_EN);
435 1.8.2.3 martin ure_write_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA,
436 1.8.2.3 martin ure_read_2(un, URE_PLA_FMC, URE_MCU_TYPE_PLA) |
437 1.8.2.2 christos URE_FMC_FCR_MCU_EN);
438 1.8.2.2 christos
439 1.8.2.2 christos /* Enable transmit and receive. */
440 1.8.2.3 martin ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA,
441 1.8.2.3 martin ure_read_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA) | URE_CR_RE |
442 1.8.2.2 christos URE_CR_TE);
443 1.8.2.2 christos
444 1.8.2.3 martin ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA,
445 1.8.2.3 martin ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) &
446 1.8.2.2 christos ~URE_RXDY_GATED_EN);
447 1.8.2.2 christos
448 1.8.2.3 martin /* Accept multicast frame or run promisc. mode. */
449 1.8.2.3 martin ure_rcvfilt_locked(un);
450 1.8.2.2 christos
451 1.8.2.3 martin return usbnet_init_rx_tx(un);
452 1.8.2.2 christos }
453 1.8.2.2 christos
454 1.8.2.3 martin static int
455 1.8.2.3 martin ure_uno_init(struct ifnet *ifp)
456 1.8.2.2 christos {
457 1.8.2.3 martin struct usbnet * const un = ifp->if_softc;
458 1.8.2.2 christos
459 1.8.2.3 martin usbnet_lock_core(un);
460 1.8.2.3 martin usbnet_busy(un);
461 1.8.2.3 martin int ret = ure_init_locked(ifp);
462 1.8.2.3 martin usbnet_unbusy(un);
463 1.8.2.3 martin usbnet_unlock_core(un);
464 1.8.2.2 christos
465 1.8.2.3 martin return ret;
466 1.8.2.2 christos }
467 1.8.2.2 christos
468 1.8.2.2 christos static void
469 1.8.2.3 martin ure_uno_stop(struct ifnet *ifp, int disable __unused)
470 1.8.2.2 christos {
471 1.8.2.3 martin struct usbnet * const un = ifp->if_softc;
472 1.8.2.2 christos
473 1.8.2.3 martin ure_reset(un);
474 1.8.2.2 christos }
475 1.8.2.2 christos
476 1.8.2.2 christos static void
477 1.8.2.3 martin ure_rtl8152_init(struct usbnet *un)
478 1.8.2.2 christos {
479 1.8.2.2 christos uint32_t pwrctrl;
480 1.8.2.2 christos
481 1.8.2.2 christos /* Disable ALDPS. */
482 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA |
483 1.8.2.2 christos URE_DIS_SDSAVE);
484 1.8.2.3 martin usbd_delay_ms(un->un_udev, 20);
485 1.8.2.2 christos
486 1.8.2.3 martin if (un->un_flags & URE_FLAG_VER_4C00) {
487 1.8.2.3 martin ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA,
488 1.8.2.3 martin ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) &
489 1.8.2.2 christos ~URE_LED_MODE_MASK);
490 1.8.2.2 christos }
491 1.8.2.2 christos
492 1.8.2.3 martin ure_write_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB,
493 1.8.2.3 martin ure_read_2(un, URE_USB_UPS_CTRL, URE_MCU_TYPE_USB) &
494 1.8.2.2 christos ~URE_POWER_CUT);
495 1.8.2.3 martin ure_write_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB,
496 1.8.2.3 martin ure_read_2(un, URE_USB_PM_CTRL_STATUS, URE_MCU_TYPE_USB) &
497 1.8.2.2 christos ~URE_RESUME_INDICATE);
498 1.8.2.2 christos
499 1.8.2.3 martin ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA,
500 1.8.2.3 martin ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) |
501 1.8.2.2 christos URE_TX_10M_IDLE_EN | URE_PFM_PWM_SWITCH);
502 1.8.2.3 martin pwrctrl = ure_read_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA);
503 1.8.2.2 christos pwrctrl &= ~URE_MCU_CLK_RATIO_MASK;
504 1.8.2.2 christos pwrctrl |= URE_MCU_CLK_RATIO | URE_D3_CLK_GATED_EN;
505 1.8.2.3 martin ure_write_4(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA, pwrctrl);
506 1.8.2.3 martin ure_write_2(un, URE_PLA_GPHY_INTR_IMR, URE_MCU_TYPE_PLA,
507 1.8.2.2 christos URE_GPHY_STS_MSK | URE_SPEED_DOWN_MSK | URE_SPDWN_RXDV_MSK |
508 1.8.2.2 christos URE_SPDWN_LINKCHG_MSK);
509 1.8.2.2 christos
510 1.8.2.2 christos /* Enable Rx aggregation. */
511 1.8.2.3 martin ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB,
512 1.8.2.3 martin ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) &
513 1.8.2.2 christos ~URE_RX_AGG_DISABLE);
514 1.8.2.2 christos
515 1.8.2.2 christos /* Disable ALDPS. */
516 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_ALDPS_CONFIG, URE_ENPDNPS | URE_LINKENA |
517 1.8.2.2 christos URE_DIS_SDSAVE);
518 1.8.2.3 martin usbd_delay_ms(un->un_udev, 20);
519 1.8.2.2 christos
520 1.8.2.3 martin ure_init_fifo(un);
521 1.8.2.2 christos
522 1.8.2.3 martin ure_write_1(un, URE_USB_TX_AGG, URE_MCU_TYPE_USB,
523 1.8.2.2 christos URE_TX_AGG_MAX_THRESHOLD);
524 1.8.2.3 martin ure_write_4(un, URE_USB_RX_BUF_TH, URE_MCU_TYPE_USB, URE_RX_THR_HIGH);
525 1.8.2.3 martin ure_write_4(un, URE_USB_TX_DMA, URE_MCU_TYPE_USB,
526 1.8.2.2 christos URE_TEST_MODE_DISABLE | URE_TX_SIZE_ADJUST1);
527 1.8.2.2 christos }
528 1.8.2.2 christos
529 1.8.2.2 christos static void
530 1.8.2.3 martin ure_rtl8153_init(struct usbnet *un)
531 1.8.2.2 christos {
532 1.8.2.2 christos uint16_t val;
533 1.8.2.2 christos uint8_t u1u2[8];
534 1.8.2.2 christos int i;
535 1.8.2.2 christos
536 1.8.2.2 christos /* Disable ALDPS. */
537 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_POWER_CFG,
538 1.8.2.3 martin ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS);
539 1.8.2.3 martin usbd_delay_ms(un->un_udev, 20);
540 1.8.2.2 christos
541 1.8.2.2 christos memset(u1u2, 0x00, sizeof(u1u2));
542 1.8.2.3 martin ure_write_mem(un, URE_USB_TOLERANCE,
543 1.8.2.2 christos URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
544 1.8.2.2 christos
545 1.8.2.2 christos for (i = 0; i < URE_TIMEOUT; i++) {
546 1.8.2.3 martin if (ure_read_2(un, URE_PLA_BOOT_CTRL, URE_MCU_TYPE_PLA) &
547 1.8.2.2 christos URE_AUTOLOAD_DONE)
548 1.8.2.2 christos break;
549 1.8.2.3 martin usbd_delay_ms(un->un_udev, 10);
550 1.8.2.2 christos }
551 1.8.2.2 christos if (i == URE_TIMEOUT)
552 1.8.2.3 martin URE_PRINTF(un, "timeout waiting for chip autoload\n");
553 1.8.2.2 christos
554 1.8.2.2 christos for (i = 0; i < URE_TIMEOUT; i++) {
555 1.8.2.3 martin val = ure_ocp_reg_read(un, URE_OCP_PHY_STATUS) &
556 1.8.2.2 christos URE_PHY_STAT_MASK;
557 1.8.2.2 christos if (val == URE_PHY_STAT_LAN_ON || val == URE_PHY_STAT_PWRDN)
558 1.8.2.2 christos break;
559 1.8.2.3 martin usbd_delay_ms(un->un_udev, 10);
560 1.8.2.2 christos }
561 1.8.2.2 christos if (i == URE_TIMEOUT)
562 1.8.2.3 martin URE_PRINTF(un, "timeout waiting for phy to stabilize\n");
563 1.8.2.2 christos
564 1.8.2.3 martin ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB,
565 1.8.2.3 martin ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB) &
566 1.8.2.2 christos ~URE_U2P3_ENABLE);
567 1.8.2.2 christos
568 1.8.2.3 martin if (un->un_flags & URE_FLAG_VER_5C10) {
569 1.8.2.3 martin val = ure_read_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB);
570 1.8.2.2 christos val &= ~URE_PWD_DN_SCALE_MASK;
571 1.8.2.2 christos val |= URE_PWD_DN_SCALE(96);
572 1.8.2.3 martin ure_write_2(un, URE_USB_SSPHYLINK2, URE_MCU_TYPE_USB, val);
573 1.8.2.2 christos
574 1.8.2.3 martin ure_write_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB,
575 1.8.2.3 martin ure_read_1(un, URE_USB_USB2PHY, URE_MCU_TYPE_USB) |
576 1.8.2.2 christos URE_USB2PHY_L1 | URE_USB2PHY_SUSPEND);
577 1.8.2.3 martin } else if (un->un_flags & URE_FLAG_VER_5C20) {
578 1.8.2.3 martin ure_write_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA,
579 1.8.2.3 martin ure_read_1(un, URE_PLA_DMY_REG0, URE_MCU_TYPE_PLA) &
580 1.8.2.2 christos ~URE_ECM_ALDPS);
581 1.8.2.2 christos }
582 1.8.2.3 martin if (un->un_flags & (URE_FLAG_VER_5C20 | URE_FLAG_VER_5C30)) {
583 1.8.2.3 martin val = ure_read_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB);
584 1.8.2.3 martin if (ure_read_2(un, URE_USB_BURST_SIZE, URE_MCU_TYPE_USB) ==
585 1.8.2.2 christos 0)
586 1.8.2.2 christos val &= ~URE_DYNAMIC_BURST;
587 1.8.2.2 christos else
588 1.8.2.2 christos val |= URE_DYNAMIC_BURST;
589 1.8.2.3 martin ure_write_1(un, URE_USB_CSR_DUMMY1, URE_MCU_TYPE_USB, val);
590 1.8.2.2 christos }
591 1.8.2.2 christos
592 1.8.2.3 martin ure_write_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB,
593 1.8.2.3 martin ure_read_1(un, URE_USB_CSR_DUMMY2, URE_MCU_TYPE_USB) |
594 1.8.2.2 christos URE_EP4_FULL_FC);
595 1.8.2.2 christos
596 1.8.2.3 martin ure_write_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB,
597 1.8.2.3 martin ure_read_2(un, URE_USB_WDT11_CTRL, URE_MCU_TYPE_USB) &
598 1.8.2.2 christos ~URE_TIMER11_EN);
599 1.8.2.2 christos
600 1.8.2.3 martin ure_write_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA,
601 1.8.2.3 martin ure_read_2(un, URE_PLA_LED_FEATURE, URE_MCU_TYPE_PLA) &
602 1.8.2.2 christos ~URE_LED_MODE_MASK);
603 1.8.2.2 christos
604 1.8.2.3 martin if ((un->un_flags & URE_FLAG_VER_5C10) &&
605 1.8.2.3 martin un->un_udev->ud_speed != USB_SPEED_SUPER)
606 1.8.2.2 christos val = URE_LPM_TIMER_500MS;
607 1.8.2.2 christos else
608 1.8.2.2 christos val = URE_LPM_TIMER_500US;
609 1.8.2.3 martin ure_write_1(un, URE_USB_LPM_CTRL, URE_MCU_TYPE_USB,
610 1.8.2.2 christos val | URE_FIFO_EMPTY_1FB | URE_ROK_EXIT_LPM);
611 1.8.2.2 christos
612 1.8.2.3 martin val = ure_read_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB);
613 1.8.2.2 christos val &= ~URE_SEN_VAL_MASK;
614 1.8.2.2 christos val |= URE_SEN_VAL_NORMAL | URE_SEL_RXIDLE;
615 1.8.2.3 martin ure_write_2(un, URE_USB_AFE_CTRL2, URE_MCU_TYPE_USB, val);
616 1.8.2.2 christos
617 1.8.2.3 martin ure_write_2(un, URE_USB_CONNECT_TIMER, URE_MCU_TYPE_USB, 0x0001);
618 1.8.2.2 christos
619 1.8.2.3 martin ure_write_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB,
620 1.8.2.3 martin ure_read_2(un, URE_USB_POWER_CUT, URE_MCU_TYPE_USB) &
621 1.8.2.2 christos ~(URE_PWR_EN | URE_PHASE2_EN));
622 1.8.2.3 martin ure_write_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB,
623 1.8.2.3 martin ure_read_2(un, URE_USB_MISC_0, URE_MCU_TYPE_USB) &
624 1.8.2.2 christos ~URE_PCUT_STATUS);
625 1.8.2.2 christos
626 1.8.2.2 christos memset(u1u2, 0xff, sizeof(u1u2));
627 1.8.2.3 martin ure_write_mem(un, URE_USB_TOLERANCE,
628 1.8.2.2 christos URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
629 1.8.2.2 christos
630 1.8.2.3 martin ure_write_2(un, URE_PLA_MAC_PWR_CTRL, URE_MCU_TYPE_PLA,
631 1.8.2.2 christos URE_ALDPS_SPDWN_RATIO);
632 1.8.2.3 martin ure_write_2(un, URE_PLA_MAC_PWR_CTRL2, URE_MCU_TYPE_PLA,
633 1.8.2.2 christos URE_EEE_SPDWN_RATIO);
634 1.8.2.3 martin ure_write_2(un, URE_PLA_MAC_PWR_CTRL3, URE_MCU_TYPE_PLA,
635 1.8.2.2 christos URE_PKT_AVAIL_SPDWN_EN | URE_SUSPEND_SPDWN_EN |
636 1.8.2.2 christos URE_U1U2_SPDWN_EN | URE_L1_SPDWN_EN);
637 1.8.2.3 martin ure_write_2(un, URE_PLA_MAC_PWR_CTRL4, URE_MCU_TYPE_PLA,
638 1.8.2.2 christos URE_PWRSAVE_SPDWN_EN | URE_RXDV_SPDWN_EN | URE_TX10MIDLE_EN |
639 1.8.2.2 christos URE_TP100_SPDWN_EN | URE_TP500_SPDWN_EN | URE_TP1000_SPDWN_EN |
640 1.8.2.2 christos URE_EEE_SPDWN_EN);
641 1.8.2.2 christos
642 1.8.2.3 martin val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB);
643 1.8.2.3 martin if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10)))
644 1.8.2.2 christos val |= URE_U2P3_ENABLE;
645 1.8.2.2 christos else
646 1.8.2.2 christos val &= ~URE_U2P3_ENABLE;
647 1.8.2.3 martin ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val);
648 1.8.2.2 christos
649 1.8.2.2 christos memset(u1u2, 0x00, sizeof(u1u2));
650 1.8.2.3 martin ure_write_mem(un, URE_USB_TOLERANCE,
651 1.8.2.2 christos URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
652 1.8.2.2 christos
653 1.8.2.2 christos /* Disable ALDPS. */
654 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_POWER_CFG,
655 1.8.2.3 martin ure_ocp_reg_read(un, URE_OCP_POWER_CFG) & ~URE_EN_ALDPS);
656 1.8.2.3 martin usbd_delay_ms(un->un_udev, 20);
657 1.8.2.2 christos
658 1.8.2.3 martin ure_init_fifo(un);
659 1.8.2.2 christos
660 1.8.2.2 christos /* Enable Rx aggregation. */
661 1.8.2.3 martin ure_write_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB,
662 1.8.2.3 martin ure_read_2(un, URE_USB_USB_CTRL, URE_MCU_TYPE_USB) &
663 1.8.2.2 christos ~URE_RX_AGG_DISABLE);
664 1.8.2.2 christos
665 1.8.2.3 martin val = ure_read_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB);
666 1.8.2.3 martin if (!(un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10)))
667 1.8.2.2 christos val |= URE_U2P3_ENABLE;
668 1.8.2.2 christos else
669 1.8.2.2 christos val &= ~URE_U2P3_ENABLE;
670 1.8.2.3 martin ure_write_2(un, URE_USB_U2P3_CTRL, URE_MCU_TYPE_USB, val);
671 1.8.2.2 christos
672 1.8.2.2 christos memset(u1u2, 0xff, sizeof(u1u2));
673 1.8.2.3 martin ure_write_mem(un, URE_USB_TOLERANCE,
674 1.8.2.2 christos URE_MCU_TYPE_USB | URE_BYTE_EN_SIX_BYTES, u1u2, sizeof(u1u2));
675 1.8.2.2 christos }
676 1.8.2.2 christos
677 1.8.2.2 christos static void
678 1.8.2.3 martin ure_disable_teredo(struct usbnet *un)
679 1.8.2.2 christos {
680 1.8.2.3 martin ure_write_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA,
681 1.8.2.3 martin ure_read_4(un, URE_PLA_TEREDO_CFG, URE_MCU_TYPE_PLA) &
682 1.8.2.2 christos ~(URE_TEREDO_SEL | URE_TEREDO_RS_EVENT_MASK | URE_OOB_TEREDO_EN));
683 1.8.2.3 martin ure_write_2(un, URE_PLA_WDT6_CTRL, URE_MCU_TYPE_PLA,
684 1.8.2.2 christos URE_WDT6_SET_MODE);
685 1.8.2.3 martin ure_write_2(un, URE_PLA_REALWOW_TIMER, URE_MCU_TYPE_PLA, 0);
686 1.8.2.3 martin ure_write_4(un, URE_PLA_TEREDO_TIMER, URE_MCU_TYPE_PLA, 0);
687 1.8.2.2 christos }
688 1.8.2.2 christos
689 1.8.2.2 christos static void
690 1.8.2.3 martin ure_init_fifo(struct usbnet *un)
691 1.8.2.2 christos {
692 1.8.2.3 martin uint32_t rxmode, rx_fifo1, rx_fifo2;
693 1.8.2.2 christos int i;
694 1.8.2.2 christos
695 1.8.2.3 martin ure_write_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA,
696 1.8.2.3 martin ure_read_2(un, URE_PLA_MISC_1, URE_MCU_TYPE_PLA) |
697 1.8.2.2 christos URE_RXDY_GATED_EN);
698 1.8.2.2 christos
699 1.8.2.3 martin ure_disable_teredo(un);
700 1.8.2.3 martin
701 1.8.2.3 martin rxmode = ure_read_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA);
702 1.8.2.3 martin rxmode &= ~URE_RCR_ACPT_ALL;
703 1.8.2.3 martin rxmode |= URE_RCR_APM | URE_RCR_AB; /* accept my own DA and bcast */
704 1.8.2.3 martin ure_write_4(un, URE_PLA_RCR, URE_MCU_TYPE_PLA, rxmode);
705 1.8.2.2 christos
706 1.8.2.3 martin if (!(un->un_flags & URE_FLAG_8152)) {
707 1.8.2.3 martin if (un->un_flags & (URE_FLAG_VER_5C00 | URE_FLAG_VER_5C10 |
708 1.8.2.3 martin URE_FLAG_VER_5C20))
709 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_ADC_CFG,
710 1.8.2.2 christos URE_CKADSEL_L | URE_ADC_EN | URE_EN_EMI_L);
711 1.8.2.3 martin if (un->un_flags & URE_FLAG_VER_5C00)
712 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_EEE_CFG,
713 1.8.2.3 martin ure_ocp_reg_read(un, URE_OCP_EEE_CFG) &
714 1.8.2.2 christos ~URE_CTAP_SHORT_EN);
715 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_POWER_CFG,
716 1.8.2.3 martin ure_ocp_reg_read(un, URE_OCP_POWER_CFG) |
717 1.8.2.2 christos URE_EEE_CLKDIV_EN);
718 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_DOWN_SPEED,
719 1.8.2.3 martin ure_ocp_reg_read(un, URE_OCP_DOWN_SPEED) |
720 1.8.2.2 christos URE_EN_10M_BGOFF);
721 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_POWER_CFG,
722 1.8.2.3 martin ure_ocp_reg_read(un, URE_OCP_POWER_CFG) |
723 1.8.2.2 christos URE_EN_10M_PLLOFF);
724 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_IMPEDANCE);
725 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0b13);
726 1.8.2.3 martin ure_write_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA,
727 1.8.2.3 martin ure_read_2(un, URE_PLA_PHY_PWR, URE_MCU_TYPE_PLA) |
728 1.8.2.2 christos URE_PFM_PWM_SWITCH);
729 1.8.2.2 christos
730 1.8.2.2 christos /* Enable LPF corner auto tune. */
731 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_LPF_CFG);
732 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0xf70f);
733 1.8.2.2 christos
734 1.8.2.2 christos /* Adjust 10M amplitude. */
735 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP1);
736 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x00af);
737 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_SRAM_ADDR, URE_SRAM_10M_AMP2);
738 1.8.2.3 martin ure_ocp_reg_write(un, URE_OCP_SRAM_DATA, 0x0208);
739 1.8.2.2 christos }
740 1.8.2.2 christos
741 1.8.2.3 martin ure_reset(un);
742 1.8.2.2 christos
743 1.8.2.3 martin ure_write_1(un, URE_PLA_CR, URE_MCU_TYPE_PLA, 0);
744 1.8.2.2 christos
745 1.8.2.3 martin ure_write_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA,
746 1.8.2.3 martin ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
747 1.8.2.2 christos ~URE_NOW_IS_OOB);
748 1.8.2.2 christos
749 1.8.2.3 martin ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA,
750 1.8.2.3 martin ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) &
751 1.8.2.2 christos ~URE_MCU_BORW_EN);
752 1.8.2.2 christos for (i = 0; i < URE_TIMEOUT; i++) {
753 1.8.2.3 martin if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
754 1.8.2.2 christos URE_LINK_LIST_READY)
755 1.8.2.2 christos break;
756 1.8.2.3 martin usbd_delay_ms(un->un_udev, 10);
757 1.8.2.2 christos }
758 1.8.2.2 christos if (i == URE_TIMEOUT)
759 1.8.2.3 martin URE_PRINTF(un, "timeout waiting for OOB control\n");
760 1.8.2.3 martin ure_write_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA,
761 1.8.2.3 martin ure_read_2(un, URE_PLA_SFF_STS_7, URE_MCU_TYPE_PLA) |
762 1.8.2.2 christos URE_RE_INIT_LL);
763 1.8.2.2 christos for (i = 0; i < URE_TIMEOUT; i++) {
764 1.8.2.3 martin if (ure_read_1(un, URE_PLA_OOB_CTRL, URE_MCU_TYPE_PLA) &
765 1.8.2.2 christos URE_LINK_LIST_READY)
766 1.8.2.2 christos break;
767 1.8.2.3 martin usbd_delay_ms(un->un_udev, 10);
768 1.8.2.2 christos }
769 1.8.2.2 christos if (i == URE_TIMEOUT)
770 1.8.2.3 martin URE_PRINTF(un, "timeout waiting for OOB control\n");
771 1.8.2.2 christos
772 1.8.2.3 martin ure_write_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA,
773 1.8.2.3 martin ure_read_2(un, URE_PLA_CPCR, URE_MCU_TYPE_PLA) &
774 1.8.2.2 christos ~URE_CPCR_RX_VLAN);
775 1.8.2.3 martin ure_write_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA,
776 1.8.2.3 martin ure_read_2(un, URE_PLA_TCR0, URE_MCU_TYPE_PLA) |
777 1.8.2.2 christos URE_TCR0_AUTO_FIFO);
778 1.8.2.2 christos
779 1.8.2.2 christos /* Configure Rx FIFO threshold and coalescing. */
780 1.8.2.3 martin ure_write_4(un, URE_PLA_RXFIFO_CTRL0, URE_MCU_TYPE_PLA,
781 1.8.2.2 christos URE_RXFIFO_THR1_NORMAL);
782 1.8.2.3 martin if (un->un_udev->ud_speed == USB_SPEED_FULL) {
783 1.8.2.2 christos rx_fifo1 = URE_RXFIFO_THR2_FULL;
784 1.8.2.2 christos rx_fifo2 = URE_RXFIFO_THR3_FULL;
785 1.8.2.2 christos } else {
786 1.8.2.2 christos rx_fifo1 = URE_RXFIFO_THR2_HIGH;
787 1.8.2.2 christos rx_fifo2 = URE_RXFIFO_THR3_HIGH;
788 1.8.2.2 christos }
789 1.8.2.3 martin ure_write_4(un, URE_PLA_RXFIFO_CTRL1, URE_MCU_TYPE_PLA, rx_fifo1);
790 1.8.2.3 martin ure_write_4(un, URE_PLA_RXFIFO_CTRL2, URE_MCU_TYPE_PLA, rx_fifo2);
791 1.8.2.2 christos
792 1.8.2.2 christos /* Configure Tx FIFO threshold. */
793 1.8.2.3 martin ure_write_4(un, URE_PLA_TXFIFO_CTRL, URE_MCU_TYPE_PLA,
794 1.8.2.2 christos URE_TXFIFO_THR_NORMAL);
795 1.8.2.2 christos }
796 1.8.2.2 christos
797 1.8.2.3 martin static int
798 1.8.2.3 martin ure_uno_ioctl(struct ifnet *ifp, u_long cmd, void *data)
799 1.8.2.2 christos {
800 1.8.2.3 martin struct usbnet * const un = ifp->if_softc;
801 1.8.2.2 christos
802 1.8.2.3 martin usbnet_lock_core(un);
803 1.8.2.3 martin usbnet_busy(un);
804 1.8.2.2 christos
805 1.8.2.2 christos switch (cmd) {
806 1.8.2.3 martin case SIOCADDMULTI:
807 1.8.2.3 martin case SIOCDELMULTI:
808 1.8.2.3 martin ure_rcvfilt_locked(un);
809 1.8.2.2 christos break;
810 1.8.2.2 christos default:
811 1.8.2.3 martin break;
812 1.8.2.2 christos }
813 1.8.2.2 christos
814 1.8.2.3 martin usbnet_unbusy(un);
815 1.8.2.3 martin usbnet_unlock_core(un);
816 1.8.2.2 christos
817 1.8.2.3 martin return 0;
818 1.8.2.2 christos }
819 1.8.2.2 christos
820 1.8.2.2 christos static int
821 1.8.2.2 christos ure_match(device_t parent, cfdata_t match, void *aux)
822 1.8.2.2 christos {
823 1.8.2.2 christos struct usb_attach_arg *uaa = aux;
824 1.8.2.2 christos
825 1.8.2.2 christos return usb_lookup(ure_devs, uaa->uaa_vendor, uaa->uaa_product) != NULL ?
826 1.8.2.2 christos UMATCH_VENDOR_PRODUCT : UMATCH_NONE;
827 1.8.2.2 christos }
828 1.8.2.2 christos
829 1.8.2.2 christos static void
830 1.8.2.2 christos ure_attach(device_t parent, device_t self, void *aux)
831 1.8.2.2 christos {
832 1.8.2.3 martin USBNET_MII_DECL_DEFAULT(unm);
833 1.8.2.3 martin struct usbnet * const un = device_private(self);
834 1.8.2.2 christos struct usb_attach_arg *uaa = aux;
835 1.8.2.2 christos struct usbd_device *dev = uaa->uaa_device;
836 1.8.2.2 christos usb_interface_descriptor_t *id;
837 1.8.2.2 christos usb_endpoint_descriptor_t *ed;
838 1.8.2.3 martin int error, i;
839 1.8.2.2 christos uint16_t ver;
840 1.8.2.2 christos uint8_t eaddr[8]; /* 2byte padded */
841 1.8.2.2 christos char *devinfop;
842 1.8.2.3 martin uint32_t maclo, machi;
843 1.8.2.2 christos
844 1.8.2.2 christos aprint_naive("\n");
845 1.8.2.2 christos aprint_normal("\n");
846 1.8.2.3 martin devinfop = usbd_devinfo_alloc(dev, 0);
847 1.8.2.2 christos aprint_normal_dev(self, "%s\n", devinfop);
848 1.8.2.2 christos usbd_devinfo_free(devinfop);
849 1.8.2.2 christos
850 1.8.2.3 martin un->un_dev = self;
851 1.8.2.3 martin un->un_udev = dev;
852 1.8.2.3 martin un->un_sc = un;
853 1.8.2.3 martin un->un_ops = &ure_ops;
854 1.8.2.3 martin un->un_rx_xfer_flags = USBD_SHORT_XFER_OK;
855 1.8.2.3 martin un->un_tx_xfer_flags = USBD_FORCE_SHORT_XFER;
856 1.8.2.3 martin un->un_rx_list_cnt = URE_RX_LIST_CNT;
857 1.8.2.3 martin un->un_tx_list_cnt = URE_TX_LIST_CNT;
858 1.8.2.3 martin un->un_rx_bufsz = URE_BUFSZ;
859 1.8.2.3 martin un->un_tx_bufsz = URE_BUFSZ;
860 1.8.2.2 christos
861 1.8.2.2 christos #define URE_CONFIG_NO 1 /* XXX */
862 1.8.2.2 christos error = usbd_set_config_no(dev, URE_CONFIG_NO, 1);
863 1.8.2.2 christos if (error) {
864 1.8.2.2 christos aprint_error_dev(self, "failed to set configuration: %s\n",
865 1.8.2.2 christos usbd_errstr(error));
866 1.8.2.2 christos return; /* XXX */
867 1.8.2.2 christos }
868 1.8.2.2 christos
869 1.8.2.2 christos if (uaa->uaa_product == USB_PRODUCT_REALTEK_RTL8152)
870 1.8.2.3 martin un->un_flags |= URE_FLAG_8152;
871 1.8.2.2 christos
872 1.8.2.2 christos #define URE_IFACE_IDX 0 /* XXX */
873 1.8.2.3 martin error = usbd_device2interface_handle(dev, URE_IFACE_IDX, &un->un_iface);
874 1.8.2.2 christos if (error) {
875 1.8.2.2 christos aprint_error_dev(self, "failed to get interface handle: %s\n",
876 1.8.2.2 christos usbd_errstr(error));
877 1.8.2.2 christos return; /* XXX */
878 1.8.2.2 christos }
879 1.8.2.2 christos
880 1.8.2.3 martin id = usbd_get_interface_descriptor(un->un_iface);
881 1.8.2.2 christos for (i = 0; i < id->bNumEndpoints; i++) {
882 1.8.2.3 martin ed = usbd_interface2endpoint_descriptor(un->un_iface, i);
883 1.8.2.2 christos if (ed == NULL) {
884 1.8.2.2 christos aprint_error_dev(self, "couldn't get ep %d\n", i);
885 1.8.2.2 christos return; /* XXX */
886 1.8.2.2 christos }
887 1.8.2.2 christos if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN &&
888 1.8.2.2 christos UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
889 1.8.2.3 martin un->un_ed[USBNET_ENDPT_RX] = ed->bEndpointAddress;
890 1.8.2.2 christos } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT &&
891 1.8.2.2 christos UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) {
892 1.8.2.3 martin un->un_ed[USBNET_ENDPT_TX] = ed->bEndpointAddress;
893 1.8.2.2 christos }
894 1.8.2.2 christos }
895 1.8.2.2 christos
896 1.8.2.3 martin /* Set these up now for ure_ctl(). */
897 1.8.2.3 martin usbnet_attach(un, "uredet");
898 1.8.2.2 christos
899 1.8.2.3 martin un->un_phyno = 0;
900 1.8.2.2 christos
901 1.8.2.3 martin ver = ure_read_2(un, URE_PLA_TCR1, URE_MCU_TYPE_PLA) & URE_VERSION_MASK;
902 1.8.2.2 christos switch (ver) {
903 1.8.2.2 christos case 0x4c00:
904 1.8.2.3 martin un->un_flags |= URE_FLAG_VER_4C00;
905 1.8.2.2 christos break;
906 1.8.2.2 christos case 0x4c10:
907 1.8.2.3 martin un->un_flags |= URE_FLAG_VER_4C10;
908 1.8.2.2 christos break;
909 1.8.2.2 christos case 0x5c00:
910 1.8.2.3 martin un->un_flags |= URE_FLAG_VER_5C00;
911 1.8.2.2 christos break;
912 1.8.2.2 christos case 0x5c10:
913 1.8.2.3 martin un->un_flags |= URE_FLAG_VER_5C10;
914 1.8.2.2 christos break;
915 1.8.2.2 christos case 0x5c20:
916 1.8.2.3 martin un->un_flags |= URE_FLAG_VER_5C20;
917 1.8.2.2 christos break;
918 1.8.2.2 christos case 0x5c30:
919 1.8.2.3 martin un->un_flags |= URE_FLAG_VER_5C30;
920 1.8.2.2 christos break;
921 1.8.2.2 christos default:
922 1.8.2.2 christos /* fake addr? or just fail? */
923 1.8.2.2 christos break;
924 1.8.2.2 christos }
925 1.8.2.2 christos aprint_normal_dev(self, "RTL%d %sver %04x\n",
926 1.8.2.3 martin (un->un_flags & URE_FLAG_8152) ? 8152 : 8153,
927 1.8.2.3 martin (un->un_flags != 0) ? "" : "unknown ",
928 1.8.2.2 christos ver);
929 1.8.2.2 christos
930 1.8.2.3 martin usbnet_lock_core(un);
931 1.8.2.3 martin if (un->un_flags & URE_FLAG_8152)
932 1.8.2.3 martin ure_rtl8152_init(un);
933 1.8.2.2 christos else
934 1.8.2.3 martin ure_rtl8153_init(un);
935 1.8.2.2 christos
936 1.8.2.3 martin if ((un->un_flags & URE_FLAG_VER_4C00) ||
937 1.8.2.3 martin (un->un_flags & URE_FLAG_VER_4C10))
938 1.8.2.3 martin ure_read_mem(un, URE_PLA_IDR, URE_MCU_TYPE_PLA, eaddr,
939 1.8.2.2 christos sizeof(eaddr));
940 1.8.2.2 christos else
941 1.8.2.3 martin ure_read_mem(un, URE_PLA_BACKUP, URE_MCU_TYPE_PLA, eaddr,
942 1.8.2.2 christos sizeof(eaddr));
943 1.8.2.3 martin usbnet_unlock_core(un);
944 1.8.2.3 martin if (ETHER_IS_ZERO(eaddr)) {
945 1.8.2.3 martin maclo = 0x00f2 | (cprng_strong32() & 0xffff0000);
946 1.8.2.3 martin machi = cprng_strong32() & 0xffff;
947 1.8.2.3 martin eaddr[0] = maclo & 0xff;
948 1.8.2.3 martin eaddr[1] = (maclo >> 8) & 0xff;
949 1.8.2.3 martin eaddr[2] = (maclo >> 16) & 0xff;
950 1.8.2.3 martin eaddr[3] = (maclo >> 24) & 0xff;
951 1.8.2.3 martin eaddr[4] = machi & 0xff;
952 1.8.2.3 martin eaddr[5] = (machi >> 8) & 0xff;
953 1.8.2.3 martin }
954 1.8.2.3 martin memcpy(un->un_eaddr, eaddr, sizeof(un->un_eaddr));
955 1.8.2.2 christos
956 1.8.2.3 martin struct ifnet *ifp = usbnet_ifp(un);
957 1.8.2.2 christos
958 1.8.2.2 christos /*
959 1.8.2.2 christos * We don't support TSOv4 and v6 for now, that are required to
960 1.8.2.2 christos * be handled in software for some cases.
961 1.8.2.2 christos */
962 1.8.2.2 christos ifp->if_capabilities = IFCAP_CSUM_IPv4_Tx |
963 1.8.2.2 christos IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_UDPv4_Tx;
964 1.8.2.2 christos #ifdef INET6
965 1.8.2.2 christos ifp->if_capabilities |= IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_UDPv6_Tx;
966 1.8.2.2 christos #endif
967 1.8.2.3 martin if (un->un_flags & ~URE_FLAG_VER_4C00) {
968 1.8.2.2 christos ifp->if_capabilities |= IFCAP_CSUM_IPv4_Rx |
969 1.8.2.2 christos IFCAP_CSUM_TCPv4_Rx | IFCAP_CSUM_UDPv4_Rx |
970 1.8.2.2 christos IFCAP_CSUM_TCPv6_Rx | IFCAP_CSUM_UDPv6_Rx;
971 1.8.2.2 christos }
972 1.8.2.3 martin struct ethercom *ec = usbnet_ec(un);
973 1.8.2.3 martin ec->ec_capabilities = ETHERCAP_VLAN_MTU;
974 1.8.2.2 christos #ifdef notyet
975 1.8.2.3 martin ec->ec_capabilities |= ETHERCAP_JUMBO_MTU;
976 1.8.2.2 christos #endif
977 1.8.2.2 christos
978 1.8.2.3 martin unm.un_mii_phyloc = un->un_phyno;
979 1.8.2.3 martin usbnet_attach_ifp(un, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST,
980 1.8.2.3 martin 0, &unm);
981 1.8.2.2 christos }
982 1.8.2.2 christos
983 1.8.2.2 christos static void
984 1.8.2.3 martin ure_uno_rx_loop(struct usbnet *un, struct usbnet_chain *c, uint32_t total_len)
985 1.8.2.2 christos {
986 1.8.2.3 martin struct ifnet *ifp = usbnet_ifp(un);
987 1.8.2.3 martin uint8_t *buf = c->unc_buf;
988 1.8.2.3 martin uint16_t pkt_len = 0;
989 1.8.2.3 martin uint16_t pkt_count = 0;
990 1.8.2.2 christos struct ure_rxpkt rxhdr;
991 1.8.2.2 christos
992 1.8.2.2 christos do {
993 1.8.2.2 christos if (total_len < sizeof(rxhdr)) {
994 1.8.2.2 christos DPRINTF(("too few bytes left for a packet header\n"));
995 1.8.2.3 martin if_statinc(ifp, if_ierrors);
996 1.8.2.3 martin return;
997 1.8.2.2 christos }
998 1.8.2.2 christos
999 1.8.2.3 martin buf += roundup(pkt_len, 8);
1000 1.8.2.2 christos
1001 1.8.2.2 christos memcpy(&rxhdr, buf, sizeof(rxhdr));
1002 1.8.2.2 christos total_len -= sizeof(rxhdr);
1003 1.8.2.2 christos
1004 1.8.2.3 martin pkt_len = le32toh(rxhdr.ure_pktlen) & URE_RXPKT_LEN_MASK;
1005 1.8.2.3 martin DPRINTFN(4, ("next packet is %d bytes\n", pkt_len));
1006 1.8.2.3 martin if (pkt_len > total_len) {
1007 1.8.2.2 christos DPRINTF(("not enough bytes left for next packet\n"));
1008 1.8.2.3 martin if_statinc(ifp, if_ierrors);
1009 1.8.2.3 martin return;
1010 1.8.2.2 christos }
1011 1.8.2.2 christos
1012 1.8.2.3 martin total_len -= roundup(pkt_len, 8);
1013 1.8.2.2 christos buf += sizeof(rxhdr);
1014 1.8.2.2 christos
1015 1.8.2.3 martin usbnet_enqueue(un, buf, pkt_len - ETHER_CRC_LEN,
1016 1.8.2.3 martin ure_rxcsum(ifp, &rxhdr), 0, 0);
1017 1.8.2.2 christos
1018 1.8.2.3 martin pkt_count++;
1019 1.8.2.3 martin
1020 1.8.2.2 christos } while (total_len > 0);
1021 1.8.2.2 christos
1022 1.8.2.3 martin if (pkt_count)
1023 1.8.2.3 martin rnd_add_uint32(usbnet_rndsrc(un), pkt_count);
1024 1.8.2.2 christos }
1025 1.8.2.2 christos
1026 1.8.2.2 christos static int
1027 1.8.2.2 christos ure_rxcsum(struct ifnet *ifp, struct ure_rxpkt *rp)
1028 1.8.2.2 christos {
1029 1.8.2.2 christos int enabled = ifp->if_csum_flags_rx, flags = 0;
1030 1.8.2.2 christos uint32_t csum, misc;
1031 1.8.2.2 christos
1032 1.8.2.2 christos if (enabled == 0)
1033 1.8.2.2 christos return 0;
1034 1.8.2.2 christos
1035 1.8.2.2 christos csum = le32toh(rp->ure_csum);
1036 1.8.2.2 christos misc = le32toh(rp->ure_misc);
1037 1.8.2.2 christos
1038 1.8.2.2 christos if (csum & URE_RXPKT_IPV4_CS) {
1039 1.8.2.2 christos flags |= M_CSUM_IPv4;
1040 1.8.2.2 christos if (csum & URE_RXPKT_TCP_CS)
1041 1.8.2.2 christos flags |= M_CSUM_TCPv4;
1042 1.8.2.2 christos if (csum & URE_RXPKT_UDP_CS)
1043 1.8.2.2 christos flags |= M_CSUM_UDPv4;
1044 1.8.2.2 christos } else if (csum & URE_RXPKT_IPV6_CS) {
1045 1.8.2.2 christos flags = 0;
1046 1.8.2.2 christos if (csum & URE_RXPKT_TCP_CS)
1047 1.8.2.2 christos flags |= M_CSUM_TCPv6;
1048 1.8.2.2 christos if (csum & URE_RXPKT_UDP_CS)
1049 1.8.2.2 christos flags |= M_CSUM_UDPv6;
1050 1.8.2.2 christos }
1051 1.8.2.2 christos
1052 1.8.2.2 christos flags &= enabled;
1053 1.8.2.2 christos if (__predict_false((flags & M_CSUM_IPv4) &&
1054 1.8.2.2 christos (misc & URE_RXPKT_IP_F)))
1055 1.8.2.2 christos flags |= M_CSUM_IPv4_BAD;
1056 1.8.2.2 christos if (__predict_false(
1057 1.8.2.2 christos ((flags & (M_CSUM_TCPv4 | M_CSUM_TCPv6)) && (misc & URE_RXPKT_TCP_F))
1058 1.8.2.2 christos || ((flags & (M_CSUM_UDPv4 | M_CSUM_UDPv6)) && (misc & URE_RXPKT_UDP_F))
1059 1.8.2.2 christos ))
1060 1.8.2.2 christos flags |= M_CSUM_TCP_UDP_BAD;
1061 1.8.2.2 christos
1062 1.8.2.2 christos return flags;
1063 1.8.2.2 christos }
1064 1.8.2.2 christos
1065 1.8.2.3 martin static unsigned
1066 1.8.2.3 martin ure_uno_tx_prepare(struct usbnet *un, struct mbuf *m, struct usbnet_chain *c)
1067 1.8.2.2 christos {
1068 1.8.2.2 christos struct ure_txpkt txhdr;
1069 1.8.2.2 christos uint32_t frm_len = 0;
1070 1.8.2.3 martin uint8_t *buf = c->unc_buf;
1071 1.8.2.2 christos
1072 1.8.2.3 martin if ((unsigned)m->m_pkthdr.len > un->un_tx_bufsz - sizeof(txhdr))
1073 1.8.2.3 martin return 0;
1074 1.8.2.2 christos
1075 1.8.2.2 christos /* header */
1076 1.8.2.2 christos txhdr.ure_pktlen = htole32(m->m_pkthdr.len | URE_TXPKT_TX_FS |
1077 1.8.2.2 christos URE_TXPKT_TX_LS);
1078 1.8.2.2 christos txhdr.ure_csum = htole32(ure_txcsum(m));
1079 1.8.2.2 christos memcpy(buf, &txhdr, sizeof(txhdr));
1080 1.8.2.2 christos buf += sizeof(txhdr);
1081 1.8.2.2 christos frm_len = sizeof(txhdr);
1082 1.8.2.2 christos
1083 1.8.2.2 christos /* packet */
1084 1.8.2.2 christos m_copydata(m, 0, m->m_pkthdr.len, buf);
1085 1.8.2.2 christos frm_len += m->m_pkthdr.len;
1086 1.8.2.2 christos
1087 1.8.2.2 christos DPRINTFN(2, ("tx %d bytes\n", frm_len));
1088 1.8.2.2 christos
1089 1.8.2.3 martin return frm_len;
1090 1.8.2.2 christos }
1091 1.8.2.2 christos
1092 1.8.2.2 christos /*
1093 1.8.2.2 christos * We need to calculate L4 checksum in software, if the offset of
1094 1.8.2.2 christos * L4 header is larger than 0x7ff = 2047.
1095 1.8.2.2 christos */
1096 1.8.2.2 christos static uint32_t
1097 1.8.2.2 christos ure_txcsum(struct mbuf *m)
1098 1.8.2.2 christos {
1099 1.8.2.2 christos struct ether_header *eh;
1100 1.8.2.2 christos int flags = m->m_pkthdr.csum_flags;
1101 1.8.2.2 christos uint32_t data = m->m_pkthdr.csum_data;
1102 1.8.2.2 christos uint32_t reg = 0;
1103 1.8.2.2 christos int l3off, l4off;
1104 1.8.2.2 christos uint16_t type;
1105 1.8.2.2 christos
1106 1.8.2.2 christos if (flags == 0)
1107 1.8.2.2 christos return 0;
1108 1.8.2.2 christos
1109 1.8.2.2 christos if (__predict_true(m->m_len >= (int)sizeof(*eh))) {
1110 1.8.2.2 christos eh = mtod(m, struct ether_header *);
1111 1.8.2.2 christos type = eh->ether_type;
1112 1.8.2.2 christos } else
1113 1.8.2.2 christos m_copydata(m, offsetof(struct ether_header, ether_type),
1114 1.8.2.2 christos sizeof(type), &type);
1115 1.8.2.2 christos switch (type = htons(type)) {
1116 1.8.2.2 christos case ETHERTYPE_IP:
1117 1.8.2.2 christos case ETHERTYPE_IPV6:
1118 1.8.2.2 christos l3off = ETHER_HDR_LEN;
1119 1.8.2.2 christos break;
1120 1.8.2.2 christos case ETHERTYPE_VLAN:
1121 1.8.2.2 christos l3off = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
1122 1.8.2.2 christos break;
1123 1.8.2.2 christos default:
1124 1.8.2.2 christos return 0;
1125 1.8.2.2 christos }
1126 1.8.2.2 christos
1127 1.8.2.2 christos if (flags & (M_CSUM_TCPv4 | M_CSUM_UDPv4)) {
1128 1.8.2.2 christos l4off = l3off + M_CSUM_DATA_IPv4_IPHL(data);
1129 1.8.2.2 christos if (__predict_false(l4off > URE_L4_OFFSET_MAX)) {
1130 1.8.2.2 christos in_undefer_cksum(m, l3off, flags);
1131 1.8.2.2 christos return 0;
1132 1.8.2.2 christos }
1133 1.8.2.2 christos reg |= URE_TXPKT_IPV4_CS;
1134 1.8.2.2 christos if (flags & M_CSUM_TCPv4)
1135 1.8.2.2 christos reg |= URE_TXPKT_TCP_CS;
1136 1.8.2.2 christos else
1137 1.8.2.2 christos reg |= URE_TXPKT_UDP_CS;
1138 1.8.2.2 christos reg |= l4off << URE_L4_OFFSET_SHIFT;
1139 1.8.2.2 christos }
1140 1.8.2.2 christos #ifdef INET6
1141 1.8.2.2 christos else if (flags & (M_CSUM_TCPv6 | M_CSUM_UDPv6)) {
1142 1.8.2.2 christos l4off = l3off + M_CSUM_DATA_IPv6_IPHL(data);
1143 1.8.2.2 christos if (__predict_false(l4off > URE_L4_OFFSET_MAX)) {
1144 1.8.2.2 christos in6_undefer_cksum(m, l3off, flags);
1145 1.8.2.2 christos return 0;
1146 1.8.2.2 christos }
1147 1.8.2.2 christos reg |= URE_TXPKT_IPV6_CS;
1148 1.8.2.2 christos if (flags & M_CSUM_TCPv6)
1149 1.8.2.2 christos reg |= URE_TXPKT_TCP_CS;
1150 1.8.2.2 christos else
1151 1.8.2.2 christos reg |= URE_TXPKT_UDP_CS;
1152 1.8.2.2 christos reg |= l4off << URE_L4_OFFSET_SHIFT;
1153 1.8.2.2 christos }
1154 1.8.2.2 christos #endif
1155 1.8.2.2 christos else if (flags & M_CSUM_IPv4)
1156 1.8.2.2 christos reg |= URE_TXPKT_IPV4_CS;
1157 1.8.2.2 christos
1158 1.8.2.2 christos return reg;
1159 1.8.2.2 christos }
1160 1.8.2.3 martin
1161 1.8.2.3 martin #ifdef _MODULE
1162 1.8.2.3 martin #include "ioconf.c"
1163 1.8.2.3 martin #endif
1164 1.8.2.3 martin
1165 1.8.2.3 martin USBNET_MODULE(ure)
1166