| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: usbnet.c,v 1.22 2019/08/20 06:37:06 mrg Exp $ */ | | 1 | /* $NetBSD: usbnet.c,v 1.23 2019/08/23 04:29:28 mrg Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2019 Matthew R. Green | | 4 | * Copyright (c) 2019 Matthew R. Green |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -23,43 +23,43 @@ | | | @@ -23,43 +23,43 @@ |
23 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | | 23 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | 24 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 25 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
28 | * SUCH DAMAGE. | | 28 | * SUCH DAMAGE. |
29 | */ | | 29 | */ |
30 | | | 30 | |
31 | /* | | 31 | /* |
32 | * Common code shared between USB network drivers. | | 32 | * Common code shared between USB network drivers. |
33 | */ | | 33 | */ |
34 | | | 34 | |
35 | #include <sys/cdefs.h> | | 35 | #include <sys/cdefs.h> |
36 | __KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.22 2019/08/20 06:37:06 mrg Exp $"); | | 36 | __KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.23 2019/08/23 04:29:28 mrg Exp $"); |
37 | | | 37 | |
38 | #include <sys/param.h> | | 38 | #include <sys/param.h> |
39 | #include <sys/kernel.h> | | 39 | #include <sys/kernel.h> |
40 | #include <sys/kmem.h> | | 40 | #include <sys/kmem.h> |
41 | #include <sys/module.h> | | 41 | #include <sys/module.h> |
| | | 42 | #include <sys/atomic.h> |
42 | | | 43 | |
43 | #include <dev/usb/usbnet.h> | | 44 | #include <dev/usb/usbnet.h> |
44 | #include <dev/usb/usbhist.h> | | 45 | #include <dev/usb/usbhist.h> |
45 | | | 46 | |
46 | struct usbnet_cdata { | | 47 | struct usbnet_cdata { |
47 | struct usbnet_chain *uncd_tx_chain; | | 48 | struct usbnet_chain *uncd_tx_chain; |
48 | struct usbnet_chain *uncd_rx_chain; | | 49 | struct usbnet_chain *uncd_rx_chain; |
49 | | | 50 | |
50 | int uncd_tx_prod; | | 51 | int uncd_tx_prod; |
51 | int uncd_tx_cnt; | | 52 | int uncd_tx_cnt; |
52 | int uncd_rx_cnt; | | | |
53 | }; | | 53 | }; |
54 | | | 54 | |
55 | struct usbnet_private { | | 55 | struct usbnet_private { |
56 | /* | | 56 | /* |
57 | * - unp_lock protects most of the structure, and the public one | | 57 | * - unp_lock protects most of the structure, and the public one |
58 | * - unp_miilock must be held to access this device's MII bus | | 58 | * - unp_miilock must be held to access this device's MII bus |
59 | * - unp_rxlock protects the rx path and its data | | 59 | * - unp_rxlock protects the rx path and its data |
60 | * - unp_txlock protects the tx path and its data | | 60 | * - unp_txlock protects the tx path and its data |
61 | * - unp_detachcv handles detach vs open references | | 61 | * - unp_detachcv handles detach vs open references |
62 | */ | | 62 | */ |
63 | kmutex_t unp_lock; | | 63 | kmutex_t unp_lock; |
64 | kmutex_t unp_miilock; | | 64 | kmutex_t unp_miilock; |
65 | kmutex_t unp_rxlock; | | 65 | kmutex_t unp_rxlock; |
| @@ -72,36 +72,39 @@ struct usbnet_private { | | | @@ -72,36 +72,39 @@ struct usbnet_private { |
72 | struct mii_data unp_mii; | | 72 | struct mii_data unp_mii; |
73 | struct usb_task unp_ticktask; | | 73 | struct usb_task unp_ticktask; |
74 | struct callout unp_stat_ch; | | 74 | struct callout unp_stat_ch; |
75 | struct usbd_pipe *unp_ep[USBNET_ENDPT_MAX]; | | 75 | struct usbd_pipe *unp_ep[USBNET_ENDPT_MAX]; |
76 | | | 76 | |
77 | bool unp_dying; | | 77 | bool unp_dying; |
78 | bool unp_stopping; | | 78 | bool unp_stopping; |
79 | bool unp_attached; | | 79 | bool unp_attached; |
80 | bool unp_link; | | 80 | bool unp_link; |
81 | | | 81 | |
82 | int unp_refcnt; | | 82 | int unp_refcnt; |
83 | int unp_timer; | | 83 | int unp_timer; |
84 | int unp_if_flags; | | 84 | int unp_if_flags; |
| | | 85 | unsigned unp_number; |
85 | | | 86 | |
86 | krndsource_t unp_rndsrc; | | 87 | krndsource_t unp_rndsrc; |
87 | | | 88 | |
88 | struct timeval unp_rx_notice; | | 89 | struct timeval unp_rx_notice; |
89 | struct timeval unp_tx_notice; | | 90 | struct timeval unp_tx_notice; |
90 | struct timeval unp_intr_notice; | | 91 | struct timeval unp_intr_notice; |
91 | }; | | 92 | }; |
92 | | | 93 | |
93 | #define un_cdata(un) (&(un)->un_pri->unp_cdata) | | 94 | #define un_cdata(un) (&(un)->un_pri->unp_cdata) |
94 | | | 95 | |
| | | 96 | volatile unsigned usbnet_number; |
| | | 97 | |
95 | static int usbnet_modcmd(modcmd_t, void *); | | 98 | static int usbnet_modcmd(modcmd_t, void *); |
96 | | | 99 | |
97 | #ifdef USB_DEBUG | | 100 | #ifdef USB_DEBUG |
98 | #ifndef USBNET_DEBUG | | 101 | #ifndef USBNET_DEBUG |
99 | #define usbnetdebug 0 | | 102 | #define usbnetdebug 0 |
100 | #else | | 103 | #else |
101 | static int usbnetdebug = 1; | | 104 | static int usbnetdebug = 1; |
102 | | | 105 | |
103 | SYSCTL_SETUP(sysctl_hw_usbnet_setup, "sysctl hw.usbnet setup") | | 106 | SYSCTL_SETUP(sysctl_hw_usbnet_setup, "sysctl hw.usbnet setup") |
104 | { | | 107 | { |
105 | int err; | | 108 | int err; |
106 | const struct sysctlnode *rnode; | | 109 | const struct sysctlnode *rnode; |
107 | const struct sysctlnode *cnode; | | 110 | const struct sysctlnode *cnode; |
| @@ -126,26 +129,28 @@ SYSCTL_SETUP(sysctl_hw_usbnet_setup, "sy | | | @@ -126,26 +129,28 @@ SYSCTL_SETUP(sysctl_hw_usbnet_setup, "sy |
126 | fail: | | 129 | fail: |
127 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); | | 130 | aprint_error("%s: sysctl_createv failed (err = %d)\n", __func__, err); |
128 | } | | 131 | } |
129 | | | 132 | |
130 | #endif /* USBNET_DEBUG */ | | 133 | #endif /* USBNET_DEBUG */ |
131 | #endif /* USB_DEBUG */ | | 134 | #endif /* USB_DEBUG */ |
132 | | | 135 | |
133 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(usbnetdebug,1,FMT,A,B,C,D) | | 136 | #define DPRINTF(FMT,A,B,C,D) USBHIST_LOGN(usbnetdebug,1,FMT,A,B,C,D) |
134 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(usbnetdebug,N,FMT,A,B,C,D) | | 137 | #define DPRINTFN(N,FMT,A,B,C,D) USBHIST_LOGN(usbnetdebug,N,FMT,A,B,C,D) |
135 | #define USBNETHIST_FUNC() USBHIST_FUNC() | | 138 | #define USBNETHIST_FUNC() USBHIST_FUNC() |
136 | #define USBNETHIST_CALLED(name) USBHIST_CALLED(usbnetdebug) | | 139 | #define USBNETHIST_CALLED(name) USBHIST_CALLED(usbnetdebug) |
137 | #define USBNETHIST_CALLARGS(FMT,A,B,C,D) \ | | 140 | #define USBNETHIST_CALLARGS(FMT,A,B,C,D) \ |
138 | USBHIST_CALLARGS(usbnetdebug,FMT,A,B,C,D) | | 141 | USBHIST_CALLARGS(usbnetdebug,FMT,A,B,C,D) |
| | | 142 | #define USBNETHIST_CALLARGSN(N,FMT,A,B,C,D) \ |
| | | 143 | USBHIST_CALLARGSN(usbnetdebug,N,FMT,A,B,C,D) |
139 | | | 144 | |
140 | /* Callback vectors. */ | | 145 | /* Callback vectors. */ |
141 | | | 146 | |
142 | static void | | 147 | static void |
143 | uno_stop(struct usbnet *un, struct ifnet *ifp, int disable) | | 148 | uno_stop(struct usbnet *un, struct ifnet *ifp, int disable) |
144 | { | | 149 | { |
145 | if (un->un_ops->uno_stop) | | 150 | if (un->un_ops->uno_stop) |
146 | (*un->un_ops->uno_stop)(ifp, disable); | | 151 | (*un->un_ops->uno_stop)(ifp, disable); |
147 | } | | 152 | } |
148 | | | 153 | |
149 | static int | | 154 | static int |
150 | uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data) | | 155 | uno_ioctl(struct usbnet *un, struct ifnet *ifp, u_long cmd, void *data) |
151 | { | | 156 | { |
| @@ -236,86 +241,96 @@ usbnet_newbuf(size_t buflen) | | | @@ -236,86 +241,96 @@ usbnet_newbuf(size_t buflen) |
236 | } | | 241 | } |
237 | | | 242 | |
238 | /* | | 243 | /* |
239 | * usbnet_rxeof() is designed to be the done callback for rx completion. | | 244 | * usbnet_rxeof() is designed to be the done callback for rx completion. |
240 | * it provides generic setup and finalisation, calls a different usbnet | | 245 | * it provides generic setup and finalisation, calls a different usbnet |
241 | * rx_loop callback in the middle, which can use usbnet_enqueue() to | | 246 | * rx_loop callback in the middle, which can use usbnet_enqueue() to |
242 | * enqueue a packet for higher levels (or usbnet_input() if previously | | 247 | * enqueue a packet for higher levels (or usbnet_input() if previously |
243 | * using if_input() path.) | | 248 | * using if_input() path.) |
244 | */ | | 249 | */ |
245 | void | | 250 | void |
246 | usbnet_enqueue(struct usbnet * const un, uint8_t *buf, size_t buflen, | | 251 | usbnet_enqueue(struct usbnet * const un, uint8_t *buf, size_t buflen, |
247 | int csum_flags, uint32_t csum_data, int mbuf_flags) | | 252 | int csum_flags, uint32_t csum_data, int mbuf_flags) |
248 | { | | 253 | { |
249 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | 254 | USBNETHIST_FUNC(); |
250 | struct ifnet * const ifp = usbnet_ifp(un); | | 255 | struct ifnet * const ifp = usbnet_ifp(un); |
| | | 256 | struct usbnet_private * const unp __unused = un->un_pri; |
251 | struct mbuf *m; | | 257 | struct mbuf *m; |
252 | | | 258 | |
| | | 259 | USBNETHIST_CALLARGSN(5, "%d: enter: len=%zu csf %x mbf %x", |
| | | 260 | unp->unp_number, buflen, csum_flags, mbuf_flags); |
| | | 261 | |
253 | usbnet_isowned_rx(un); | | 262 | usbnet_isowned_rx(un); |
254 | | | 263 | |
255 | m = usbnet_newbuf(buflen); | | 264 | m = usbnet_newbuf(buflen); |
256 | if (m == NULL) { | | 265 | if (m == NULL) { |
| | | 266 | DPRINTF("%d: no memory", unp->unp_number, 0, 0, 0); |
257 | ifp->if_ierrors++; | | 267 | ifp->if_ierrors++; |
258 | return; | | 268 | return; |
259 | } | | 269 | } |
260 | | | 270 | |
261 | m_set_rcvif(m, ifp); | | 271 | m_set_rcvif(m, ifp); |
262 | m->m_pkthdr.csum_flags = csum_flags; | | 272 | m->m_pkthdr.csum_flags = csum_flags; |
263 | m->m_pkthdr.csum_data = csum_data; | | 273 | m->m_pkthdr.csum_data = csum_data; |
264 | m->m_flags |= mbuf_flags; | | 274 | m->m_flags |= mbuf_flags; |
265 | memcpy(mtod(m, uint8_t *), buf, buflen); | | 275 | memcpy(mtod(m, uint8_t *), buf, buflen); |
266 | | | 276 | |
267 | /* push the packet up */ | | 277 | /* push the packet up */ |
268 | if_percpuq_enqueue(ifp->if_percpuq, m); | | 278 | if_percpuq_enqueue(ifp->if_percpuq, m); |
269 | } | | 279 | } |
270 | | | 280 | |
271 | void | | 281 | void |
272 | usbnet_input(struct usbnet * const un, uint8_t *buf, size_t buflen) | | 282 | usbnet_input(struct usbnet * const un, uint8_t *buf, size_t buflen) |
273 | { | | 283 | { |
274 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | 284 | USBNETHIST_FUNC(); |
275 | struct ifnet * const ifp = usbnet_ifp(un); | | 285 | struct ifnet * const ifp = usbnet_ifp(un); |
| | | 286 | struct usbnet_private * const unp __unused = un->un_pri; |
276 | struct mbuf *m; | | 287 | struct mbuf *m; |
277 | | | 288 | |
| | | 289 | USBNETHIST_CALLARGSN(5, "%d: enter: buf %jx len %ju", |
| | | 290 | unp->unp_number, (uintptr_t)buf, buflen, 0); |
| | | 291 | |
278 | usbnet_isowned_rx(un); | | 292 | usbnet_isowned_rx(un); |
279 | DPRINTFN(0, "called! un %jx buf %jx len %ju", | | | |
280 | (uintmax_t)(uintptr_t)un, (uintmax_t)(uintptr_t)buf, buflen, 0); | | | |
281 | | | 293 | |
282 | m = usbnet_newbuf(buflen); | | 294 | m = usbnet_newbuf(buflen); |
283 | if (m == NULL) { | | 295 | if (m == NULL) { |
284 | ifp->if_ierrors++; | | 296 | ifp->if_ierrors++; |
285 | return; | | 297 | return; |
286 | } | | 298 | } |
287 | | | 299 | |
288 | m_set_rcvif(m, ifp); | | 300 | m_set_rcvif(m, ifp); |
289 | memcpy(mtod(m, char *), buf, buflen); | | 301 | memcpy(mtod(m, char *), buf, buflen); |
290 | | | 302 | |
291 | /* push the packet up */ | | 303 | /* push the packet up */ |
292 | if_input(ifp, m); | | 304 | if_input(ifp, m); |
293 | } | | 305 | } |
294 | | | 306 | |
295 | /* | | 307 | /* |
296 | * A frame has been uploaded: pass the resulting mbuf chain up to | | 308 | * A frame has been uploaded: pass the resulting mbuf chain up to |
297 | * the higher level protocols. | | 309 | * the higher level protocols. |
298 | */ | | 310 | */ |
299 | static void | | 311 | static void |
300 | usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | | 312 | usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) |
301 | { | | 313 | { |
302 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | 314 | USBNETHIST_FUNC(); |
303 | struct usbnet_chain * const c = priv; | | 315 | struct usbnet_chain * const c = priv; |
304 | struct usbnet * const un = c->unc_un; | | 316 | struct usbnet * const un = c->unc_un; |
305 | struct usbnet_private * const unp = un->un_pri; | | 317 | struct usbnet_private * const unp = un->un_pri; |
306 | struct ifnet * const ifp = usbnet_ifp(un); | | 318 | struct ifnet * const ifp = usbnet_ifp(un); |
307 | uint32_t total_len; | | 319 | uint32_t total_len; |
308 | | | 320 | |
| | | 321 | USBNETHIST_CALLARGSN(5, "%d: enter: status %x xfer %jx", |
| | | 322 | unp->unp_number, status, (uintptr_t)xfer, 0); |
| | | 323 | |
309 | mutex_enter(&unp->unp_rxlock); | | 324 | mutex_enter(&unp->unp_rxlock); |
310 | | | 325 | |
311 | if (unp->unp_dying || unp->unp_stopping || | | 326 | if (unp->unp_dying || unp->unp_stopping || |
312 | status == USBD_INVAL || status == USBD_NOT_STARTED || | | 327 | status == USBD_INVAL || status == USBD_NOT_STARTED || |
313 | status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING)) | | 328 | status == USBD_CANCELLED || !(ifp->if_flags & IFF_RUNNING)) |
314 | goto out; | | 329 | goto out; |
315 | | | 330 | |
316 | if (status != USBD_NORMAL_COMPLETION) { | | 331 | if (status != USBD_NORMAL_COMPLETION) { |
317 | if (usbd_ratecheck(&unp->unp_rx_notice)) | | 332 | if (usbd_ratecheck(&unp->unp_rx_notice)) |
318 | aprint_error_dev(un->un_dev, "usb errors on rx: %s\n", | | 333 | aprint_error_dev(un->un_dev, "usb errors on rx: %s\n", |
319 | usbd_errstr(status)); | | 334 | usbd_errstr(status)); |
320 | if (status == USBD_STALLED) | | 335 | if (status == USBD_STALLED) |
321 | usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_RX]); | | 336 | usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_RX]); |
| @@ -350,26 +365,29 @@ out: | | | @@ -350,26 +365,29 @@ out: |
350 | mutex_exit(&unp->unp_rxlock); | | 365 | mutex_exit(&unp->unp_rxlock); |
351 | } | | 366 | } |
352 | | | 367 | |
353 | static void | | 368 | static void |
354 | usbnet_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | | 369 | usbnet_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) |
355 | { | | 370 | { |
356 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | 371 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); |
357 | struct usbnet_chain * const c = priv; | | 372 | struct usbnet_chain * const c = priv; |
358 | struct usbnet * const un = c->unc_un; | | 373 | struct usbnet * const un = c->unc_un; |
359 | struct usbnet_cdata * const cd = un_cdata(un); | | 374 | struct usbnet_cdata * const cd = un_cdata(un); |
360 | struct usbnet_private * const unp = un->un_pri; | | 375 | struct usbnet_private * const unp = un->un_pri; |
361 | struct ifnet * const ifp = usbnet_ifp(un); | | 376 | struct ifnet * const ifp = usbnet_ifp(un); |
362 | | | 377 | |
| | | 378 | USBNETHIST_CALLARGSN(5, "%d: enter: status %x xfer %jx", |
| | | 379 | unp->unp_number, status, (uintptr_t)xfer, 0); |
| | | 380 | |
363 | mutex_enter(&unp->unp_txlock); | | 381 | mutex_enter(&unp->unp_txlock); |
364 | if (unp->unp_stopping || unp->unp_dying) { | | 382 | if (unp->unp_stopping || unp->unp_dying) { |
365 | mutex_exit(&unp->unp_txlock); | | 383 | mutex_exit(&unp->unp_txlock); |
366 | return; | | 384 | return; |
367 | } | | 385 | } |
368 | | | 386 | |
369 | KASSERT(cd->uncd_tx_cnt > 0); | | 387 | KASSERT(cd->uncd_tx_cnt > 0); |
370 | cd->uncd_tx_cnt--; | | 388 | cd->uncd_tx_cnt--; |
371 | | | 389 | |
372 | unp->unp_timer = 0; | | 390 | unp->unp_timer = 0; |
373 | | | 391 | |
374 | switch (status) { | | 392 | switch (status) { |
375 | case USBD_NOT_STARTED: | | 393 | case USBD_NOT_STARTED: |
| @@ -433,52 +451,64 @@ usbnet_start_locked(struct ifnet *ifp) | | | @@ -433,52 +451,64 @@ usbnet_start_locked(struct ifnet *ifp) |
433 | struct mbuf *m; | | 451 | struct mbuf *m; |
434 | unsigned length; | | 452 | unsigned length; |
435 | int idx; | | 453 | int idx; |
436 | | | 454 | |
437 | usbnet_isowned_tx(un); | | 455 | usbnet_isowned_tx(un); |
438 | KASSERT(cd->uncd_tx_cnt <= un->un_tx_list_cnt); | | 456 | KASSERT(cd->uncd_tx_cnt <= un->un_tx_list_cnt); |
439 | | | 457 | |
440 | if (!unp->unp_link || (ifp->if_flags & IFF_RUNNING) == 0) { | | 458 | if (!unp->unp_link || (ifp->if_flags & IFF_RUNNING) == 0) { |
441 | DPRINTF("start called no link (%x) or running (flags %x)", | | 459 | DPRINTF("start called no link (%x) or running (flags %x)", |
442 | unp->unp_link, ifp->if_flags, 0, 0); | | 460 | unp->unp_link, ifp->if_flags, 0, 0); |
443 | return; | | 461 | return; |
444 | } | | 462 | } |
445 | | | 463 | |
| | | 464 | if (cd->uncd_tx_cnt == un->un_tx_list_cnt) { |
| | | 465 | DPRINTF("start called, tx busy (%jx == %jx)", |
| | | 466 | cd->uncd_tx_cnt, un->un_tx_list_cnt, 0, 0); |
| | | 467 | return; |
| | | 468 | } |
| | | 469 | |
446 | idx = cd->uncd_tx_prod; | | 470 | idx = cd->uncd_tx_prod; |
447 | while (cd->uncd_tx_cnt < un->un_tx_list_cnt) { | | 471 | while (cd->uncd_tx_cnt < un->un_tx_list_cnt) { |
448 | IFQ_POLL(&ifp->if_snd, m); | | 472 | IFQ_POLL(&ifp->if_snd, m); |
449 | if (m == NULL) | | 473 | if (m == NULL) { |
| | | 474 | DPRINTF("start called, queue empty", 0, 0, 0, 0); |
450 | break; | | 475 | break; |
| | | 476 | } |
451 | KASSERT(m->m_pkthdr.len <= un->un_tx_bufsz); | | 477 | KASSERT(m->m_pkthdr.len <= un->un_tx_bufsz); |
452 | | | 478 | |
453 | struct usbnet_chain *c = &cd->uncd_tx_chain[idx]; | | 479 | struct usbnet_chain *c = &cd->uncd_tx_chain[idx]; |
454 | | | 480 | |
455 | length = uno_tx_prepare(un, m, c); | | 481 | length = uno_tx_prepare(un, m, c); |
456 | if (length == 0) { | | 482 | if (length == 0) { |
| | | 483 | DPRINTF("uno_tx_prepare gave zero length", 0, 0, 0, 0); |
457 | ifp->if_oerrors++; | | 484 | ifp->if_oerrors++; |
458 | break; | | 485 | break; |
459 | } | | 486 | } |
460 | | | 487 | |
461 | if (__predict_false(c->unc_xfer == NULL)) { | | 488 | if (__predict_false(c->unc_xfer == NULL)) { |
| | | 489 | DPRINTF("unc_xfer is NULL", 0, 0, 0, 0); |
462 | ifp->if_oerrors++; | | 490 | ifp->if_oerrors++; |
463 | break; | | 491 | break; |
464 | } | | 492 | } |
465 | | | 493 | |
466 | usbd_setup_xfer(c->unc_xfer, c, c->unc_buf, length, | | 494 | usbd_setup_xfer(c->unc_xfer, c, c->unc_buf, length, |
467 | un->un_tx_xfer_flags, 10000, usbnet_txeof); | | 495 | un->un_tx_xfer_flags, 10000, usbnet_txeof); |
468 | | | 496 | |
469 | /* Transmit */ | | 497 | /* Transmit */ |
470 | usbd_status err = usbd_transfer(c->unc_xfer); | | 498 | usbd_status err = usbd_transfer(c->unc_xfer); |
471 | if (err != USBD_IN_PROGRESS) { | | 499 | if (err != USBD_IN_PROGRESS) { |
| | | 500 | DPRINTF("usbd_transfer on %jx for %ju bytes: %d", |
| | | 501 | (uintptr_t)c->unc_buf, length, err, 0); |
472 | ifp->if_oerrors++; | | 502 | ifp->if_oerrors++; |
473 | break; | | 503 | break; |
474 | } | | 504 | } |
475 | | | 505 | |
476 | IFQ_DEQUEUE(&ifp->if_snd, m); | | 506 | IFQ_DEQUEUE(&ifp->if_snd, m); |
477 | | | 507 | |
478 | /* | | 508 | /* |
479 | * If there's a BPF listener, bounce a copy of this frame | | 509 | * If there's a BPF listener, bounce a copy of this frame |
480 | * to him. | | 510 | * to him. |
481 | */ | | 511 | */ |
482 | bpf_mtap(ifp, m, BPF_D_OUT); | | 512 | bpf_mtap(ifp, m, BPF_D_OUT); |
483 | m_freem(m); | | 513 | m_freem(m); |
484 | | | 514 | |
| @@ -655,26 +685,27 @@ static void | | | @@ -655,26 +685,27 @@ static void |
655 | usbnet_tx_list_fini(struct usbnet * const un) | | 685 | usbnet_tx_list_fini(struct usbnet * const un) |
656 | { | | 686 | { |
657 | struct usbnet_cdata * const cd = un_cdata(un); | | 687 | struct usbnet_cdata * const cd = un_cdata(un); |
658 | | | 688 | |
659 | for (size_t i = 0; i < un->un_tx_list_cnt; i++) { | | 689 | for (size_t i = 0; i < un->un_tx_list_cnt; i++) { |
660 | struct usbnet_chain *c = &cd->uncd_tx_chain[i]; | | 690 | struct usbnet_chain *c = &cd->uncd_tx_chain[i]; |
661 | | | 691 | |
662 | if (c->unc_xfer != NULL) { | | 692 | if (c->unc_xfer != NULL) { |
663 | usbd_destroy_xfer(c->unc_xfer); | | 693 | usbd_destroy_xfer(c->unc_xfer); |
664 | c->unc_xfer = NULL; | | 694 | c->unc_xfer = NULL; |
665 | c->unc_buf = NULL; | | 695 | c->unc_buf = NULL; |
666 | } | | 696 | } |
667 | } | | 697 | } |
| | | 698 | cd->uncd_tx_prod = cd->uncd_tx_cnt = 0; |
668 | } | | 699 | } |
669 | | | 700 | |
670 | /* End of common TX functions */ | | 701 | /* End of common TX functions */ |
671 | | | 702 | |
672 | /* Endpoint pipe management. */ | | 703 | /* Endpoint pipe management. */ |
673 | | | 704 | |
674 | static void | | 705 | static void |
675 | usbnet_ep_close_pipes(struct usbnet * const un) | | 706 | usbnet_ep_close_pipes(struct usbnet * const un) |
676 | { | | 707 | { |
677 | struct usbnet_private * const unp = un->un_pri; | | 708 | struct usbnet_private * const unp = un->un_pri; |
678 | | | 709 | |
679 | for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) { | | 710 | for (size_t i = 0; i < __arraycount(unp->unp_ep); i++) { |
680 | if (unp->unp_ep[i] == NULL) | | 711 | if (unp->unp_ep[i] == NULL) |
| @@ -966,30 +997,34 @@ usbnet_ifflags_cb(struct ethercom *ec) | | | @@ -966,30 +997,34 @@ usbnet_ifflags_cb(struct ethercom *ec) |
966 | rv = ENETRESET; | | 997 | rv = ENETRESET; |
967 | } else { | | 998 | } else { |
968 | rv = ENETRESET; | | 999 | rv = ENETRESET; |
969 | } | | 1000 | } |
970 | | | 1001 | |
971 | mutex_exit(&unp->unp_lock); | | 1002 | mutex_exit(&unp->unp_lock); |
972 | | | 1003 | |
973 | return rv; | | 1004 | return rv; |
974 | } | | 1005 | } |
975 | | | 1006 | |
976 | static int | | 1007 | static int |
977 | usbnet_ioctl(struct ifnet *ifp, u_long cmd, void *data) | | 1008 | usbnet_ioctl(struct ifnet *ifp, u_long cmd, void *data) |
978 | { | | 1009 | { |
979 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | 1010 | USBNETHIST_FUNC(); |
980 | struct usbnet * const un = ifp->if_softc; | | 1011 | struct usbnet * const un = ifp->if_softc; |
| | | 1012 | struct usbnet_private * const unp __unused = un->un_pri; |
981 | int error; | | 1013 | int error; |
982 | | | 1014 | |
| | | 1015 | USBNETHIST_CALLARGSN(11, "%d: enter %jx data %x", |
| | | 1016 | unp->unp_number, cmd, (uintptr_t)data, 0); |
| | | 1017 | |
983 | if (un->un_ops->uno_override_ioctl) | | 1018 | if (un->un_ops->uno_override_ioctl) |
984 | return uno_override_ioctl(un, ifp, cmd, data); | | 1019 | return uno_override_ioctl(un, ifp, cmd, data); |
985 | | | 1020 | |
986 | error = ether_ioctl(ifp, cmd, data); | | 1021 | error = ether_ioctl(ifp, cmd, data); |
987 | if (error == ENETRESET) | | 1022 | if (error == ENETRESET) |
988 | error = uno_ioctl(un, ifp, cmd, data); | | 1023 | error = uno_ioctl(un, ifp, cmd, data); |
989 | | | 1024 | |
990 | return error; | | 1025 | return error; |
991 | } | | 1026 | } |
992 | | | 1027 | |
993 | /* | | 1028 | /* |
994 | * Generic stop network function: | | 1029 | * Generic stop network function: |
995 | * - mark as stopping | | 1030 | * - mark as stopping |
| @@ -1067,49 +1102,52 @@ usbnet_tick(void *arg) | | | @@ -1067,49 +1102,52 @@ usbnet_tick(void *arg) |
1067 | struct usbnet_private * const unp = un->un_pri; | | 1102 | struct usbnet_private * const unp = un->un_pri; |
1068 | | | 1103 | |
1069 | mutex_enter(&unp->unp_lock); | | 1104 | mutex_enter(&unp->unp_lock); |
1070 | if (!unp->unp_stopping && !unp->unp_dying) { | | 1105 | if (!unp->unp_stopping && !unp->unp_dying) { |
1071 | /* Perform periodic stuff in process context */ | | 1106 | /* Perform periodic stuff in process context */ |
1072 | usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER); | | 1107 | usb_add_task(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER); |
1073 | } | | 1108 | } |
1074 | mutex_exit(&unp->unp_lock); | | 1109 | mutex_exit(&unp->unp_lock); |
1075 | } | | 1110 | } |
1076 | | | 1111 | |
1077 | static void | | 1112 | static void |
1078 | usbnet_watchdog(struct ifnet *ifp) | | 1113 | usbnet_watchdog(struct ifnet *ifp) |
1079 | { | | 1114 | { |
| | | 1115 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); |
1080 | struct usbnet * const un = ifp->if_softc; | | 1116 | struct usbnet * const un = ifp->if_softc; |
1081 | struct usbnet_private * const unp = un->un_pri; | | 1117 | struct usbnet_private * const unp = un->un_pri; |
1082 | struct usbnet_cdata * const cd = un_cdata(un); | | 1118 | struct usbnet_cdata * const cd = un_cdata(un); |
1083 | usbd_status err; | | 1119 | usbd_status err; |
1084 | | | 1120 | |
1085 | ifp->if_oerrors++; | | 1121 | ifp->if_oerrors++; |
1086 | aprint_error_dev(un->un_dev, "watchdog timeout\n"); | | 1122 | aprint_error_dev(un->un_dev, "watchdog timeout\n"); |
1087 | | | 1123 | |
1088 | if (cd->uncd_tx_cnt > 0) { | | 1124 | if (cd->uncd_tx_cnt > 0) { |
| | | 1125 | DPRINTF("uncd_tx_cnt=%u non zero, aborting pipe", 0, 0, 0, 0); |
1089 | err = usbd_abort_pipe(unp->unp_ep[USBNET_ENDPT_TX]); | | 1126 | err = usbd_abort_pipe(unp->unp_ep[USBNET_ENDPT_TX]); |
1090 | if (err) | | 1127 | if (err) |
1091 | aprint_error_dev(un->un_dev, "pipe abort failed: %s\n", | | 1128 | aprint_error_dev(un->un_dev, "pipe abort failed: %s\n", |
1092 | usbd_errstr(err)); | | 1129 | usbd_errstr(err)); |
| | | 1130 | if (cd->uncd_tx_cnt != 0) |
| | | 1131 | DPRINTF("uncd_tx_cnt now %u", cd->uncd_tx_cnt, 0, 0, 0); |
1093 | } | | 1132 | } |
1094 | | | 1133 | |
1095 | if (!IFQ_IS_EMPTY(&ifp->if_snd)) | | 1134 | if (!IFQ_IS_EMPTY(&ifp->if_snd)) |
1096 | (*ifp->if_start)(ifp); | | 1135 | (*ifp->if_start)(ifp); |
1097 | } | | 1136 | } |
1098 | | | 1137 | |
1099 | static void | | 1138 | static void |
1100 | usbnet_tick_task(void *arg) | | 1139 | usbnet_tick_task(void *arg) |
1101 | { | | 1140 | { |
1102 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | | |
1103 | struct usbnet * const un = arg; | | 1141 | struct usbnet * const un = arg; |
1104 | struct usbnet_private * const unp = un->un_pri; | | 1142 | struct usbnet_private * const unp = un->un_pri; |
1105 | | | 1143 | |
1106 | mutex_enter(&unp->unp_lock); | | 1144 | mutex_enter(&unp->unp_lock); |
1107 | if (unp->unp_stopping || unp->unp_dying) { | | 1145 | if (unp->unp_stopping || unp->unp_dying) { |
1108 | mutex_exit(&unp->unp_lock); | | 1146 | mutex_exit(&unp->unp_lock); |
1109 | return; | | 1147 | return; |
1110 | } | | 1148 | } |
1111 | | | 1149 | |
1112 | struct ifnet * const ifp = usbnet_ifp(un); | | 1150 | struct ifnet * const ifp = usbnet_ifp(un); |
1113 | struct mii_data * const mii = usbnet_mii(un); | | 1151 | struct mii_data * const mii = usbnet_mii(un); |
1114 | | | 1152 | |
1115 | unp->unp_refcnt++; | | 1153 | unp->unp_refcnt++; |
| @@ -1310,26 +1348,28 @@ usbnet_attach(struct usbnet *un, | | | @@ -1310,26 +1348,28 @@ usbnet_attach(struct usbnet *un, |
1310 | | | 1348 | |
1311 | mutex_init(&unp->unp_miilock, MUTEX_DEFAULT, IPL_NONE); | | 1349 | mutex_init(&unp->unp_miilock, MUTEX_DEFAULT, IPL_NONE); |
1312 | mutex_init(&unp->unp_txlock, MUTEX_DEFAULT, IPL_SOFTUSB); | | 1350 | mutex_init(&unp->unp_txlock, MUTEX_DEFAULT, IPL_SOFTUSB); |
1313 | mutex_init(&unp->unp_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB); | | 1351 | mutex_init(&unp->unp_rxlock, MUTEX_DEFAULT, IPL_SOFTUSB); |
1314 | mutex_init(&unp->unp_lock, MUTEX_DEFAULT, IPL_NONE); | | 1352 | mutex_init(&unp->unp_lock, MUTEX_DEFAULT, IPL_NONE); |
1315 | cv_init(&unp->unp_detachcv, detname); | | 1353 | cv_init(&unp->unp_detachcv, detname); |
1316 | | | 1354 | |
1317 | rnd_attach_source(&unp->unp_rndsrc, device_xname(un->un_dev), | | 1355 | rnd_attach_source(&unp->unp_rndsrc, device_xname(un->un_dev), |
1318 | RND_TYPE_NET, RND_FLAG_DEFAULT); | | 1356 | RND_TYPE_NET, RND_FLAG_DEFAULT); |
1319 | | | 1357 | |
1320 | usbnet_rx_list_alloc(un); | | 1358 | usbnet_rx_list_alloc(un); |
1321 | usbnet_tx_list_alloc(un); | | 1359 | usbnet_tx_list_alloc(un); |
1322 | | | 1360 | |
| | | 1361 | unp->unp_number = atomic_inc_uint_nv(&usbnet_number); |
| | | 1362 | |
1323 | unp->unp_attached = true; | | 1363 | unp->unp_attached = true; |
1324 | } | | 1364 | } |
1325 | | | 1365 | |
1326 | static void | | 1366 | static void |
1327 | usbnet_attach_mii(struct usbnet *un, const struct usbnet_mii *unm) | | 1367 | usbnet_attach_mii(struct usbnet *un, const struct usbnet_mii *unm) |
1328 | { | | 1368 | { |
1329 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | 1369 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); |
1330 | struct usbnet_private * const unp = un->un_pri; | | 1370 | struct usbnet_private * const unp = un->un_pri; |
1331 | struct mii_data * const mii = &unp->unp_mii; | | 1371 | struct mii_data * const mii = &unp->unp_mii; |
1332 | struct ifnet * const ifp = usbnet_ifp(un); | | 1372 | struct ifnet * const ifp = usbnet_ifp(un); |
1333 | | | 1373 | |
1334 | KASSERT(un->un_ops->uno_read_reg); | | 1374 | KASSERT(un->un_ops->uno_read_reg); |
1335 | KASSERT(un->un_ops->uno_write_reg); | | 1375 | KASSERT(un->un_ops->uno_write_reg); |