| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: usbnet.c,v 1.72 2022/03/03 05:50:31 riastradh Exp $ */ | | 1 | /* $NetBSD: usbnet.c,v 1.73 2022/03/03 05:50:39 riastradh 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. |
| @@ -21,27 +21,27 @@ | | | @@ -21,27 +21,27 @@ |
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | | 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | | 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. | | 26 | * SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | /* | | 29 | /* |
30 | * Common code shared between USB network drivers. | | 30 | * Common code shared between USB network drivers. |
31 | */ | | 31 | */ |
32 | | | 32 | |
33 | #include <sys/cdefs.h> | | 33 | #include <sys/cdefs.h> |
34 | __KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.72 2022/03/03 05:50:31 riastradh Exp $"); | | 34 | __KERNEL_RCSID(0, "$NetBSD: usbnet.c,v 1.73 2022/03/03 05:50:39 riastradh Exp $"); |
35 | | | 35 | |
36 | #include <sys/param.h> | | 36 | #include <sys/param.h> |
37 | #include <sys/kernel.h> | | 37 | #include <sys/kernel.h> |
38 | #include <sys/kmem.h> | | 38 | #include <sys/kmem.h> |
39 | #include <sys/module.h> | | 39 | #include <sys/module.h> |
40 | #include <sys/atomic.h> | | 40 | #include <sys/atomic.h> |
41 | | | 41 | |
42 | #include <dev/usb/usbnet.h> | | 42 | #include <dev/usb/usbnet.h> |
43 | #include <dev/usb/usbhist.h> | | 43 | #include <dev/usb/usbhist.h> |
44 | | | 44 | |
45 | struct usbnet_cdata { | | 45 | struct usbnet_cdata { |
46 | struct usbnet_chain *uncd_tx_chain; | | 46 | struct usbnet_chain *uncd_tx_chain; |
47 | struct usbnet_chain *uncd_rx_chain; | | 47 | struct usbnet_chain *uncd_rx_chain; |
| @@ -67,27 +67,27 @@ struct usbnet_private { | | | @@ -67,27 +67,27 @@ struct usbnet_private { |
67 | kmutex_t unp_rxlock; | | 67 | kmutex_t unp_rxlock; |
68 | kmutex_t unp_txlock; | | 68 | kmutex_t unp_txlock; |
69 | kcondvar_t unp_detachcv; | | 69 | kcondvar_t unp_detachcv; |
70 | | | 70 | |
71 | struct usbnet_cdata unp_cdata; | | 71 | struct usbnet_cdata unp_cdata; |
72 | | | 72 | |
73 | struct ethercom unp_ec; | | 73 | struct ethercom unp_ec; |
74 | struct mii_data unp_mii; | | 74 | struct mii_data unp_mii; |
75 | struct usb_task unp_mcasttask; | | 75 | struct usb_task unp_mcasttask; |
76 | struct usb_task unp_ticktask; | | 76 | struct usb_task unp_ticktask; |
77 | struct callout unp_stat_ch; | | 77 | struct callout unp_stat_ch; |
78 | struct usbd_pipe *unp_ep[USBNET_ENDPT_MAX]; | | 78 | struct usbd_pipe *unp_ep[USBNET_ENDPT_MAX]; |
79 | | | 79 | |
80 | bool unp_dying; | | 80 | volatile bool unp_dying; |
81 | bool unp_stopping; | | 81 | bool unp_stopping; |
82 | bool unp_attached; | | 82 | bool unp_attached; |
83 | bool unp_ifp_attached; | | 83 | bool unp_ifp_attached; |
84 | bool unp_link; | | 84 | bool unp_link; |
85 | | | 85 | |
86 | int unp_refcnt; | | 86 | int unp_refcnt; |
87 | int unp_timer; | | 87 | int unp_timer; |
88 | unsigned short unp_if_flags; | | 88 | unsigned short unp_if_flags; |
89 | unsigned unp_number; | | 89 | unsigned unp_number; |
90 | | | 90 | |
91 | krndsource_t unp_rndsrc; | | 91 | krndsource_t unp_rndsrc; |
92 | | | 92 | |
93 | struct timeval unp_rx_notice; | | 93 | struct timeval unp_rx_notice; |
| @@ -346,54 +346,54 @@ static void | | | @@ -346,54 +346,54 @@ static void |
346 | usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | | 346 | usbnet_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) |
347 | { | | 347 | { |
348 | USBNETHIST_FUNC(); | | 348 | USBNETHIST_FUNC(); |
349 | struct usbnet_chain * const c = priv; | | 349 | struct usbnet_chain * const c = priv; |
350 | struct usbnet * const un = c->unc_un; | | 350 | struct usbnet * const un = c->unc_un; |
351 | struct usbnet_private * const unp = un->un_pri; | | 351 | struct usbnet_private * const unp = un->un_pri; |
352 | uint32_t total_len; | | 352 | uint32_t total_len; |
353 | | | 353 | |
354 | USBNETHIST_CALLARGSN(5, "%jd: enter: status %#jx xfer %#jx", | | 354 | USBNETHIST_CALLARGSN(5, "%jd: enter: status %#jx xfer %#jx", |
355 | unp->unp_number, status, (uintptr_t)xfer, 0); | | 355 | unp->unp_number, status, (uintptr_t)xfer, 0); |
356 | | | 356 | |
357 | mutex_enter(&unp->unp_rxlock); | | 357 | mutex_enter(&unp->unp_rxlock); |
358 | | | 358 | |
359 | if (unp->unp_dying || unp->unp_stopping || | | 359 | if (usbnet_isdying(un) || unp->unp_stopping || |
360 | status == USBD_INVAL || status == USBD_NOT_STARTED || | | 360 | status == USBD_INVAL || status == USBD_NOT_STARTED || |
361 | status == USBD_CANCELLED) | | 361 | status == USBD_CANCELLED) |
362 | goto out; | | 362 | goto out; |
363 | | | 363 | |
364 | if (status != USBD_NORMAL_COMPLETION) { | | 364 | if (status != USBD_NORMAL_COMPLETION) { |
365 | if (usbd_ratecheck(&unp->unp_rx_notice)) | | 365 | if (usbd_ratecheck(&unp->unp_rx_notice)) |
366 | device_printf(un->un_dev, "usb errors on rx: %s\n", | | 366 | device_printf(un->un_dev, "usb errors on rx: %s\n", |
367 | usbd_errstr(status)); | | 367 | usbd_errstr(status)); |
368 | if (status == USBD_STALLED) | | 368 | if (status == USBD_STALLED) |
369 | usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_RX]); | | 369 | usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_RX]); |
370 | goto done; | | 370 | goto done; |
371 | } | | 371 | } |
372 | | | 372 | |
373 | usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); | | 373 | usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); |
374 | | | 374 | |
375 | if (total_len > un->un_rx_bufsz) { | | 375 | if (total_len > un->un_rx_bufsz) { |
376 | aprint_error_dev(un->un_dev, | | 376 | aprint_error_dev(un->un_dev, |
377 | "rxeof: too large transfer (%u > %u)\n", | | 377 | "rxeof: too large transfer (%u > %u)\n", |
378 | total_len, un->un_rx_bufsz); | | 378 | total_len, un->un_rx_bufsz); |
379 | goto done; | | 379 | goto done; |
380 | } | | 380 | } |
381 | | | 381 | |
382 | uno_rx_loop(un, c, total_len); | | 382 | uno_rx_loop(un, c, total_len); |
383 | usbnet_isowned_rx(un); | | 383 | usbnet_isowned_rx(un); |
384 | | | 384 | |
385 | done: | | 385 | done: |
386 | if (unp->unp_dying || unp->unp_stopping) | | 386 | if (usbnet_isdying(un) || unp->unp_stopping) |
387 | goto out; | | 387 | goto out; |
388 | | | 388 | |
389 | mutex_exit(&unp->unp_rxlock); | | 389 | mutex_exit(&unp->unp_rxlock); |
390 | | | 390 | |
391 | /* Setup new transfer. */ | | 391 | /* Setup new transfer. */ |
392 | usbd_setup_xfer(xfer, c, c->unc_buf, un->un_rx_bufsz, | | 392 | usbd_setup_xfer(xfer, c, c->unc_buf, un->un_rx_bufsz, |
393 | un->un_rx_xfer_flags, USBD_NO_TIMEOUT, usbnet_rxeof); | | 393 | un->un_rx_xfer_flags, USBD_NO_TIMEOUT, usbnet_rxeof); |
394 | usbd_transfer(xfer); | | 394 | usbd_transfer(xfer); |
395 | return; | | 395 | return; |
396 | | | 396 | |
397 | out: | | 397 | out: |
398 | mutex_exit(&unp->unp_rxlock); | | 398 | mutex_exit(&unp->unp_rxlock); |
399 | } | | 399 | } |
| @@ -402,27 +402,27 @@ static void | | | @@ -402,27 +402,27 @@ static void |
402 | usbnet_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | | 402 | usbnet_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) |
403 | { | | 403 | { |
404 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | 404 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); |
405 | struct usbnet_chain * const c = priv; | | 405 | struct usbnet_chain * const c = priv; |
406 | struct usbnet * const un = c->unc_un; | | 406 | struct usbnet * const un = c->unc_un; |
407 | struct usbnet_cdata * const cd = un_cdata(un); | | 407 | struct usbnet_cdata * const cd = un_cdata(un); |
408 | struct usbnet_private * const unp = un->un_pri; | | 408 | struct usbnet_private * const unp = un->un_pri; |
409 | struct ifnet * const ifp = usbnet_ifp(un); | | 409 | struct ifnet * const ifp = usbnet_ifp(un); |
410 | | | 410 | |
411 | USBNETHIST_CALLARGSN(5, "%jd: enter: status %#jx xfer %#jx", | | 411 | USBNETHIST_CALLARGSN(5, "%jd: enter: status %#jx xfer %#jx", |
412 | unp->unp_number, status, (uintptr_t)xfer, 0); | | 412 | unp->unp_number, status, (uintptr_t)xfer, 0); |
413 | | | 413 | |
414 | mutex_enter(&unp->unp_txlock); | | 414 | mutex_enter(&unp->unp_txlock); |
415 | if (unp->unp_stopping || unp->unp_dying) { | | 415 | if (unp->unp_stopping || usbnet_isdying(un)) { |
416 | mutex_exit(&unp->unp_txlock); | | 416 | mutex_exit(&unp->unp_txlock); |
417 | return; | | 417 | return; |
418 | } | | 418 | } |
419 | | | 419 | |
420 | KASSERT(cd->uncd_tx_cnt > 0); | | 420 | KASSERT(cd->uncd_tx_cnt > 0); |
421 | cd->uncd_tx_cnt--; | | 421 | cd->uncd_tx_cnt--; |
422 | | | 422 | |
423 | unp->unp_timer = 0; | | 423 | unp->unp_timer = 0; |
424 | | | 424 | |
425 | switch (status) { | | 425 | switch (status) { |
426 | case USBD_NOT_STARTED: | | 426 | case USBD_NOT_STARTED: |
427 | case USBD_CANCELLED: | | 427 | case USBD_CANCELLED: |
428 | break; | | 428 | break; |
| @@ -446,32 +446,32 @@ usbnet_txeof(struct usbd_xfer *xfer, voi | | | @@ -446,32 +446,32 @@ usbnet_txeof(struct usbd_xfer *xfer, voi |
446 | | | 446 | |
447 | if (status == USBD_NORMAL_COMPLETION && !IFQ_IS_EMPTY(&ifp->if_snd)) | | 447 | if (status == USBD_NORMAL_COMPLETION && !IFQ_IS_EMPTY(&ifp->if_snd)) |
448 | (*ifp->if_start)(ifp); | | 448 | (*ifp->if_start)(ifp); |
449 | } | | 449 | } |
450 | | | 450 | |
451 | static void | | 451 | static void |
452 | usbnet_pipe_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) | | 452 | usbnet_pipe_intr(struct usbd_xfer *xfer, void *priv, usbd_status status) |
453 | { | | 453 | { |
454 | USBNETHIST_FUNC(); | | 454 | USBNETHIST_FUNC(); |
455 | struct usbnet * const un = priv; | | 455 | struct usbnet * const un = priv; |
456 | struct usbnet_private * const unp = un->un_pri; | | 456 | struct usbnet_private * const unp = un->un_pri; |
457 | struct usbnet_intr * const uni = un->un_intr; | | 457 | struct usbnet_intr * const uni = un->un_intr; |
458 | | | 458 | |
459 | if (uni == NULL || unp->unp_dying || unp->unp_stopping || | | 459 | if (uni == NULL || usbnet_isdying(un) || unp->unp_stopping || |
460 | status == USBD_INVAL || status == USBD_NOT_STARTED || | | 460 | status == USBD_INVAL || status == USBD_NOT_STARTED || |
461 | status == USBD_CANCELLED) { | | 461 | status == USBD_CANCELLED) { |
462 | USBNETHIST_CALLARGS("%jd: uni %#jx d/s %#jx status %#jx", | | 462 | USBNETHIST_CALLARGS("%jd: uni %#jx d/s %#jx status %#jx", |
463 | unp->unp_number, (uintptr_t)uni, | | 463 | unp->unp_number, (uintptr_t)uni, |
464 | (unp->unp_dying << 8) | unp->unp_stopping, status); | | 464 | (usbnet_isdying(un) << 8) | unp->unp_stopping, status); |
465 | return; | | 465 | return; |
466 | } | | 466 | } |
467 | | | 467 | |
468 | if (status != USBD_NORMAL_COMPLETION) { | | 468 | if (status != USBD_NORMAL_COMPLETION) { |
469 | if (usbd_ratecheck(&unp->unp_intr_notice)) { | | 469 | if (usbd_ratecheck(&unp->unp_intr_notice)) { |
470 | aprint_error_dev(un->un_dev, "usb error on intr: %s\n", | | 470 | aprint_error_dev(un->un_dev, "usb error on intr: %s\n", |
471 | usbd_errstr(status)); | | 471 | usbd_errstr(status)); |
472 | } | | 472 | } |
473 | if (status == USBD_STALLED) | | 473 | if (status == USBD_STALLED) |
474 | usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_INTR]); | | 474 | usbd_clear_endpoint_stall_async(unp->unp_ep[USBNET_ENDPT_INTR]); |
475 | USBNETHIST_CALLARGS("%jd: not normal status %#jx", | | 475 | USBNETHIST_CALLARGS("%jd: not normal status %#jx", |
476 | unp->unp_number, status, 0, 0); | | 476 | unp->unp_number, status, 0, 0); |
477 | return; | | 477 | return; |
| @@ -827,27 +827,27 @@ int | | | @@ -827,27 +827,27 @@ int |
827 | usbnet_init_rx_tx(struct usbnet * const un) | | 827 | usbnet_init_rx_tx(struct usbnet * const un) |
828 | { | | 828 | { |
829 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | 829 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); |
830 | struct usbnet_private * const unp = un->un_pri; | | 830 | struct usbnet_private * const unp = un->un_pri; |
831 | struct ifnet * const ifp = usbnet_ifp(un); | | 831 | struct ifnet * const ifp = usbnet_ifp(un); |
832 | usbd_status err; | | 832 | usbd_status err; |
833 | int error = 0; | | 833 | int error = 0; |
834 | | | 834 | |
835 | KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), | | 835 | KASSERTMSG(!unp->unp_ifp_attached || IFNET_LOCKED(ifp), |
836 | "%s", ifp->if_xname); | | 836 | "%s", ifp->if_xname); |
837 | | | 837 | |
838 | usbnet_isowned_core(un); | | 838 | usbnet_isowned_core(un); |
839 | | | 839 | |
840 | if (unp->unp_dying) { | | 840 | if (usbnet_isdying(un)) { |
841 | return EIO; | | 841 | return EIO; |
842 | } | | 842 | } |
843 | | | 843 | |
844 | usbnet_busy(un); | | 844 | usbnet_busy(un); |
845 | | | 845 | |
846 | /* Open RX and TX pipes. */ | | 846 | /* Open RX and TX pipes. */ |
847 | err = usbnet_ep_open_pipes(un); | | 847 | err = usbnet_ep_open_pipes(un); |
848 | if (err) { | | 848 | if (err) { |
849 | aprint_error_dev(un->un_dev, "open rx/tx pipes failed: %s\n", | | 849 | aprint_error_dev(un->un_dev, "open rx/tx pipes failed: %s\n", |
850 | usbd_errstr(err)); | | 850 | usbd_errstr(err)); |
851 | error = EIO; | | 851 | error = EIO; |
852 | goto out; | | 852 | goto out; |
853 | } | | 853 | } |
| @@ -908,71 +908,69 @@ usbnet_unbusy(struct usbnet *un) | | | @@ -908,71 +908,69 @@ usbnet_unbusy(struct usbnet *un) |
908 | usbnet_isowned_core(un); | | 908 | usbnet_isowned_core(un); |
909 | | | 909 | |
910 | if (--unp->unp_refcnt < 0) | | 910 | if (--unp->unp_refcnt < 0) |
911 | cv_broadcast(&unp->unp_detachcv); | | 911 | cv_broadcast(&unp->unp_detachcv); |
912 | } | | 912 | } |
913 | | | 913 | |
914 | /* MII management. */ | | 914 | /* MII management. */ |
915 | | | 915 | |
916 | int | | 916 | int |
917 | usbnet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val) | | 917 | usbnet_mii_readreg(device_t dev, int phy, int reg, uint16_t *val) |
918 | { | | 918 | { |
919 | USBNETHIST_FUNC(); | | 919 | USBNETHIST_FUNC(); |
920 | struct usbnet * const un = device_private(dev); | | 920 | struct usbnet * const un = device_private(dev); |
921 | struct usbnet_private * const unp = un->un_pri; | | | |
922 | int err; | | 921 | int err; |
923 | | | 922 | |
924 | /* MII layer ensures core_lock is held. */ | | 923 | /* MII layer ensures core_lock is held. */ |
925 | usbnet_isowned_core(un); | | 924 | usbnet_isowned_core(un); |
926 | | | 925 | |
927 | if (unp->unp_dying) { | | 926 | if (usbnet_isdying(un)) { |
928 | return EIO; | | 927 | return EIO; |
929 | } | | 928 | } |
930 | | | 929 | |
931 | usbnet_busy(un); | | 930 | usbnet_busy(un); |
932 | err = uno_read_reg(un, phy, reg, val); | | 931 | err = uno_read_reg(un, phy, reg, val); |
933 | usbnet_unbusy(un); | | 932 | usbnet_unbusy(un); |
934 | | | 933 | |
935 | if (err) { | | 934 | if (err) { |
936 | USBNETHIST_CALLARGS("%jd: read PHY failed: %jd", | | 935 | USBNETHIST_CALLARGS("%jd: read PHY failed: %jd", |
937 | unp->unp_number, err, 0, 0); | | 936 | un->un_pri->unp_number, err, 0, 0); |
938 | return err; | | 937 | return err; |
939 | } | | 938 | } |
940 | | | 939 | |
941 | return 0; | | 940 | return 0; |
942 | } | | 941 | } |
943 | | | 942 | |
944 | int | | 943 | int |
945 | usbnet_mii_writereg(device_t dev, int phy, int reg, uint16_t val) | | 944 | usbnet_mii_writereg(device_t dev, int phy, int reg, uint16_t val) |
946 | { | | 945 | { |
947 | USBNETHIST_FUNC(); | | 946 | USBNETHIST_FUNC(); |
948 | struct usbnet * const un = device_private(dev); | | 947 | struct usbnet * const un = device_private(dev); |
949 | struct usbnet_private * const unp = un->un_pri; | | | |
950 | int err; | | 948 | int err; |
951 | | | 949 | |
952 | /* MII layer ensures core_lock is held. */ | | 950 | /* MII layer ensures core_lock is held. */ |
953 | usbnet_isowned_core(un); | | 951 | usbnet_isowned_core(un); |
954 | | | 952 | |
955 | if (unp->unp_dying) { | | 953 | if (usbnet_isdying(un)) { |
956 | return EIO; | | 954 | return EIO; |
957 | } | | 955 | } |
958 | | | 956 | |
959 | usbnet_busy(un); | | 957 | usbnet_busy(un); |
960 | err = uno_write_reg(un, phy, reg, val); | | 958 | err = uno_write_reg(un, phy, reg, val); |
961 | usbnet_unbusy(un); | | 959 | usbnet_unbusy(un); |
962 | | | 960 | |
963 | if (err) { | | 961 | if (err) { |
964 | USBNETHIST_CALLARGS("%jd: write PHY failed: %jd", | | 962 | USBNETHIST_CALLARGS("%jd: write PHY failed: %jd", |
965 | unp->unp_number, err, 0, 0); | | 963 | un->un_pri->unp_number, err, 0, 0); |
966 | return err; | | 964 | return err; |
967 | } | | 965 | } |
968 | | | 966 | |
969 | return 0; | | 967 | return 0; |
970 | } | | 968 | } |
971 | | | 969 | |
972 | void | | 970 | void |
973 | usbnet_mii_statchg(struct ifnet *ifp) | | 971 | usbnet_mii_statchg(struct ifnet *ifp) |
974 | { | | 972 | { |
975 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | 973 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); |
976 | struct usbnet * const un = ifp->if_softc; | | 974 | struct usbnet * const un = ifp->if_softc; |
977 | | | 975 | |
978 | /* MII layer ensures core_lock is held. */ | | 976 | /* MII layer ensures core_lock is held. */ |
| @@ -987,27 +985,27 @@ static int | | | @@ -987,27 +985,27 @@ static int |
987 | usbnet_media_upd(struct ifnet *ifp) | | 985 | usbnet_media_upd(struct ifnet *ifp) |
988 | { | | 986 | { |
989 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | 987 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); |
990 | struct usbnet * const un = ifp->if_softc; | | 988 | struct usbnet * const un = ifp->if_softc; |
991 | struct usbnet_private * const unp = un->un_pri; | | 989 | struct usbnet_private * const unp = un->un_pri; |
992 | struct mii_data * const mii = usbnet_mii(un); | | 990 | struct mii_data * const mii = usbnet_mii(un); |
993 | | | 991 | |
994 | /* ifmedia layer ensures core_lock is held. */ | | 992 | /* ifmedia layer ensures core_lock is held. */ |
995 | usbnet_isowned_core(un); | | 993 | usbnet_isowned_core(un); |
996 | | | 994 | |
997 | /* ifmedia changes only with IFNET_LOCK held. */ | | 995 | /* ifmedia changes only with IFNET_LOCK held. */ |
998 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | | 996 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); |
999 | | | 997 | |
1000 | if (unp->unp_dying) | | 998 | if (usbnet_isdying(un)) |
1001 | return EIO; | | 999 | return EIO; |
1002 | | | 1000 | |
1003 | unp->unp_link = false; | | 1001 | unp->unp_link = false; |
1004 | | | 1002 | |
1005 | if (mii->mii_instance) { | | 1003 | if (mii->mii_instance) { |
1006 | struct mii_softc *miisc; | | 1004 | struct mii_softc *miisc; |
1007 | | | 1005 | |
1008 | LIST_FOREACH(miisc, &mii->mii_phys, mii_list) | | 1006 | LIST_FOREACH(miisc, &mii->mii_phys, mii_list) |
1009 | mii_phy_reset(miisc); | | 1007 | mii_phy_reset(miisc); |
1010 | } | | 1008 | } |
1011 | | | 1009 | |
1012 | return ether_mediachange(ifp); | | 1010 | return ether_mediachange(ifp); |
1013 | } | | 1011 | } |
| @@ -1075,36 +1073,36 @@ usbnet_if_ioctl(struct ifnet *ifp, u_lon | | | @@ -1075,36 +1073,36 @@ usbnet_if_ioctl(struct ifnet *ifp, u_lon |
1075 | static void | | 1073 | static void |
1076 | usbnet_mcast_task(void *arg) | | 1074 | usbnet_mcast_task(void *arg) |
1077 | { | | 1075 | { |
1078 | USBNETHIST_FUNC(); | | 1076 | USBNETHIST_FUNC(); |
1079 | struct usbnet * const un = arg; | | 1077 | struct usbnet * const un = arg; |
1080 | struct usbnet_private * const unp = un->un_pri; | | 1078 | struct usbnet_private * const unp = un->un_pri; |
1081 | struct ifnet * const ifp = usbnet_ifp(un); | | 1079 | struct ifnet * const ifp = usbnet_ifp(un); |
1082 | bool dying; | | 1080 | bool dying; |
1083 | struct ifreq ifr; | | 1081 | struct ifreq ifr; |
1084 | | | 1082 | |
1085 | USBNETHIST_CALLARGSN(10, "%jd: enter", unp->unp_number, 0, 0, 0); | | 1083 | USBNETHIST_CALLARGSN(10, "%jd: enter", unp->unp_number, 0, 0, 0); |
1086 | | | 1084 | |
1087 | /* | | 1085 | /* |
1088 | * If we're detaching, we must check unp_dying _before_ | | 1086 | * If we're detaching, we must check usbnet_isdying _before_ |
1089 | * touching IFNET_LOCK -- the ifnet may have been detached by | | 1087 | * touching IFNET_LOCK -- the ifnet may have been detached by |
1090 | * the time this task runs. This is racy -- unp_dying may be | | 1088 | * the time this task runs. This is racy -- unp_dying may be |
1091 | * set immediately after we test it -- but nevertheless safe, | | 1089 | * set immediately after we test it -- but nevertheless safe, |
1092 | * because usbnet_detach waits for the task to complete before | | 1090 | * because usbnet_detach waits for the task to complete before |
1093 | * issuing if_detach, and necessary, so that we don't touch | | 1091 | * issuing if_detach, and necessary, so that we don't touch |
1094 | * IFNET_LOCK after if_detach. See usbnet_detach for details. | | 1092 | * IFNET_LOCK after if_detach. See usbnet_detach for details. |
1095 | */ | | 1093 | */ |
1096 | mutex_enter(&unp->unp_core_lock); | | 1094 | mutex_enter(&unp->unp_core_lock); |
1097 | dying = unp->unp_dying; | | 1095 | dying = usbnet_isdying(un); |
1098 | mutex_exit(&unp->unp_core_lock); | | 1096 | mutex_exit(&unp->unp_core_lock); |
1099 | if (dying) | | 1097 | if (dying) |
1100 | return; | | 1098 | return; |
1101 | | | 1099 | |
1102 | /* | | 1100 | /* |
1103 | * Pass a bogus ifr with SIOCDELMULTI -- the goal is to just | | 1101 | * Pass a bogus ifr with SIOCDELMULTI -- the goal is to just |
1104 | * notify the driver to reprogram any hardware multicast | | 1102 | * notify the driver to reprogram any hardware multicast |
1105 | * filter, according to what's already stored in the ethercom. | | 1103 | * filter, according to what's already stored in the ethercom. |
1106 | * None of the drivers actually examine this argument, so it | | 1104 | * None of the drivers actually examine this argument, so it |
1107 | * doesn't change the ABI as far as they can tell. | | 1105 | * doesn't change the ABI as far as they can tell. |
1108 | */ | | 1106 | */ |
1109 | IFNET_LOCK(ifp); | | 1107 | IFNET_LOCK(ifp); |
1110 | if (ifp->if_flags & IFF_RUNNING) { | | 1108 | if (ifp->if_flags & IFF_RUNNING) { |
| @@ -1161,27 +1159,27 @@ usbnet_stop(struct usbnet *un, struct if | | | @@ -1161,27 +1159,27 @@ usbnet_stop(struct usbnet *un, struct if |
1161 | usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, | | 1159 | usb_rem_task_wait(un->un_udev, &unp->unp_ticktask, USB_TASKQ_DRIVER, |
1162 | &unp->unp_core_lock); | | 1160 | &unp->unp_core_lock); |
1163 | | | 1161 | |
1164 | /* | | 1162 | /* |
1165 | * Now that the software is quiescent, ask the driver to stop | | 1163 | * Now that the software is quiescent, ask the driver to stop |
1166 | * the hardware. The driver's uno_stop routine now has | | 1164 | * the hardware. The driver's uno_stop routine now has |
1167 | * exclusive access to any registers that might previously have | | 1165 | * exclusive access to any registers that might previously have |
1168 | * been used by to ifmedia, mii, or ioctl callbacks. | | 1166 | * been used by to ifmedia, mii, or ioctl callbacks. |
1169 | * | | 1167 | * |
1170 | * Don't bother if the device is being detached, though -- if | | 1168 | * Don't bother if the device is being detached, though -- if |
1171 | * it's been unplugged then there's no point in trying to touch | | 1169 | * it's been unplugged then there's no point in trying to touch |
1172 | * the registers. | | 1170 | * the registers. |
1173 | */ | | 1171 | */ |
1174 | if (!unp->unp_dying) | | 1172 | if (!usbnet_isdying(un)) |
1175 | uno_stop(un, ifp, disable); | | 1173 | uno_stop(un, ifp, disable); |
1176 | | | 1174 | |
1177 | /* Stop transfers. */ | | 1175 | /* Stop transfers. */ |
1178 | usbnet_ep_stop_pipes(un); | | 1176 | usbnet_ep_stop_pipes(un); |
1179 | | | 1177 | |
1180 | /* Free RX/TX resources. */ | | 1178 | /* Free RX/TX resources. */ |
1181 | usbnet_rx_list_fini(un); | | 1179 | usbnet_rx_list_fini(un); |
1182 | usbnet_tx_list_fini(un); | | 1180 | usbnet_tx_list_fini(un); |
1183 | | | 1181 | |
1184 | /* Close pipes. */ | | 1182 | /* Close pipes. */ |
1185 | usbnet_ep_close_pipes(un); | | 1183 | usbnet_ep_close_pipes(un); |
1186 | | | 1184 | |
1187 | /* Everything is quesced now. */ | | 1185 | /* Everything is quesced now. */ |
| @@ -1270,47 +1268,47 @@ usbnet_tick_task(void *arg) | | | @@ -1270,47 +1268,47 @@ usbnet_tick_task(void *arg) |
1270 | DPRINTFN(8, "mii %#jx ifp %#jx", (uintptr_t)mii, (uintptr_t)ifp, 0, 0); | | 1268 | DPRINTFN(8, "mii %#jx ifp %#jx", (uintptr_t)mii, (uintptr_t)ifp, 0, 0); |
1271 | if (mii) { | | 1269 | if (mii) { |
1272 | mutex_enter(&unp->unp_core_lock); | | 1270 | mutex_enter(&unp->unp_core_lock); |
1273 | mii_tick(mii); | | 1271 | mii_tick(mii); |
1274 | if (!unp->unp_link) | | 1272 | if (!unp->unp_link) |
1275 | (*mii->mii_statchg)(ifp); | | 1273 | (*mii->mii_statchg)(ifp); |
1276 | mutex_exit(&unp->unp_core_lock); | | 1274 | mutex_exit(&unp->unp_core_lock); |
1277 | } | | 1275 | } |
1278 | | | 1276 | |
1279 | /* Call driver if requested. */ | | 1277 | /* Call driver if requested. */ |
1280 | uno_tick(un); | | 1278 | uno_tick(un); |
1281 | | | 1279 | |
1282 | mutex_enter(&unp->unp_core_lock); | | 1280 | mutex_enter(&unp->unp_core_lock); |
1283 | if (!unp->unp_stopping && !unp->unp_dying) | | 1281 | if (!unp->unp_stopping && !usbnet_isdying(un)) |
1284 | callout_schedule(&unp->unp_stat_ch, hz); | | 1282 | callout_schedule(&unp->unp_stat_ch, hz); |
1285 | mutex_exit(&unp->unp_core_lock); | | 1283 | mutex_exit(&unp->unp_core_lock); |
1286 | } | | 1284 | } |
1287 | | | 1285 | |
1288 | static int | | 1286 | static int |
1289 | usbnet_if_init(struct ifnet *ifp) | | 1287 | usbnet_if_init(struct ifnet *ifp) |
1290 | { | | 1288 | { |
1291 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | 1289 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); |
1292 | struct usbnet * const un = ifp->if_softc; | | 1290 | struct usbnet * const un = ifp->if_softc; |
1293 | bool dying; | | 1291 | bool dying; |
1294 | int error; | | 1292 | int error; |
1295 | | | 1293 | |
1296 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); | | 1294 | KASSERTMSG(IFNET_LOCKED(ifp), "%s", ifp->if_xname); |
1297 | | | 1295 | |
1298 | /* | | 1296 | /* |
1299 | * Prevent anyone from bringing the interface back up once | | 1297 | * Prevent anyone from bringing the interface back up once |
1300 | * we're detaching. | | 1298 | * we're detaching. |
1301 | */ | | 1299 | */ |
1302 | mutex_enter(&un->un_pri->unp_core_lock); | | 1300 | mutex_enter(&un->un_pri->unp_core_lock); |
1303 | dying = un->un_pri->unp_dying; | | 1301 | dying = usbnet_isdying(un); |
1304 | mutex_exit(&un->un_pri->unp_core_lock); | | 1302 | mutex_exit(&un->un_pri->unp_core_lock); |
1305 | if (dying) | | 1303 | if (dying) |
1306 | return EIO; | | 1304 | return EIO; |
1307 | | | 1305 | |
1308 | mutex_enter(&un->un_pri->unp_core_lock); | | 1306 | mutex_enter(&un->un_pri->unp_core_lock); |
1309 | error = uno_init(un, ifp); | | 1307 | error = uno_init(un, ifp); |
1310 | mutex_exit(&un->un_pri->unp_core_lock); | | 1308 | mutex_exit(&un->un_pri->unp_core_lock); |
1311 | | | 1309 | |
1312 | return error; | | 1310 | return error; |
1313 | } | | 1311 | } |
1314 | | | 1312 | |
1315 | | | 1313 | |
1316 | /* Various accessors. */ | | 1314 | /* Various accessors. */ |
| @@ -1350,27 +1348,27 @@ usbnet_softc(struct usbnet *un) | | | @@ -1350,27 +1348,27 @@ usbnet_softc(struct usbnet *un) |
1350 | { | | 1348 | { |
1351 | return un->un_sc; | | 1349 | return un->un_sc; |
1352 | } | | 1350 | } |
1353 | | | 1351 | |
1354 | bool | | 1352 | bool |
1355 | usbnet_havelink(struct usbnet *un) | | 1353 | usbnet_havelink(struct usbnet *un) |
1356 | { | | 1354 | { |
1357 | return un->un_pri->unp_link; | | 1355 | return un->un_pri->unp_link; |
1358 | } | | 1356 | } |
1359 | | | 1357 | |
1360 | bool | | 1358 | bool |
1361 | usbnet_isdying(struct usbnet *un) | | 1359 | usbnet_isdying(struct usbnet *un) |
1362 | { | | 1360 | { |
1363 | return un->un_pri->unp_dying; | | 1361 | return atomic_load_relaxed(&un->un_pri->unp_dying); |
1364 | } | | 1362 | } |
1365 | | | 1363 | |
1366 | | | 1364 | |
1367 | /* Locking. */ | | 1365 | /* Locking. */ |
1368 | | | 1366 | |
1369 | void | | 1367 | void |
1370 | usbnet_lock_core(struct usbnet *un) | | 1368 | usbnet_lock_core(struct usbnet *un) |
1371 | { | | 1369 | { |
1372 | mutex_enter(&un->un_pri->unp_core_lock); | | 1370 | mutex_enter(&un->un_pri->unp_core_lock); |
1373 | } | | 1371 | } |
1374 | | | 1372 | |
1375 | void | | 1373 | void |
1376 | usbnet_unlock_core(struct usbnet *un) | | 1374 | usbnet_unlock_core(struct usbnet *un) |
| @@ -1584,27 +1582,27 @@ usbnet_detach(device_t self, int flags) | | | @@ -1584,27 +1582,27 @@ usbnet_detach(device_t self, int flags) |
1584 | | | 1582 | |
1585 | /* Detached before attached finished, so just bail out. */ | | 1583 | /* Detached before attached finished, so just bail out. */ |
1586 | if (unp == NULL || !unp->unp_attached) | | 1584 | if (unp == NULL || !unp->unp_attached) |
1587 | return 0; | | 1585 | return 0; |
1588 | | | 1586 | |
1589 | struct ifnet * const ifp = usbnet_ifp(un); | | 1587 | struct ifnet * const ifp = usbnet_ifp(un); |
1590 | struct mii_data * const mii = usbnet_mii(un); | | 1588 | struct mii_data * const mii = usbnet_mii(un); |
1591 | | | 1589 | |
1592 | /* | | 1590 | /* |
1593 | * Prevent new activity. After we stop the interface, it | | 1591 | * Prevent new activity. After we stop the interface, it |
1594 | * cannot be brought back up. | | 1592 | * cannot be brought back up. |
1595 | */ | | 1593 | */ |
1596 | mutex_enter(&unp->unp_core_lock); | | 1594 | mutex_enter(&unp->unp_core_lock); |
1597 | unp->unp_dying = true; | | 1595 | atomic_store_relaxed(&unp->unp_dying, true); |
1598 | mutex_exit(&unp->unp_core_lock); | | 1596 | mutex_exit(&unp->unp_core_lock); |
1599 | | | 1597 | |
1600 | /* | | 1598 | /* |
1601 | * If we're still running on the network, stop and wait for all | | 1599 | * If we're still running on the network, stop and wait for all |
1602 | * asynchronous activity to finish. | | 1600 | * asynchronous activity to finish. |
1603 | * | | 1601 | * |
1604 | * If usbnet_attach_ifp never ran, IFNET_LOCK won't work, but | | 1602 | * If usbnet_attach_ifp never ran, IFNET_LOCK won't work, but |
1605 | * no activity is possible, so just skip this part. | | 1603 | * no activity is possible, so just skip this part. |
1606 | */ | | 1604 | */ |
1607 | if (unp->unp_ifp_attached) { | | 1605 | if (unp->unp_ifp_attached) { |
1608 | IFNET_LOCK(ifp); | | 1606 | IFNET_LOCK(ifp); |
1609 | if (ifp->if_flags & IFF_RUNNING) { | | 1607 | if (ifp->if_flags & IFF_RUNNING) { |
1610 | usbnet_if_stop(ifp, 1); | | 1608 | usbnet_if_stop(ifp, 1); |
| @@ -1713,27 +1711,27 @@ usbnet_detach(device_t self, int flags) | | | @@ -1713,27 +1711,27 @@ usbnet_detach(device_t self, int flags) |
1713 | int | | 1711 | int |
1714 | usbnet_activate(device_t self, devact_t act) | | 1712 | usbnet_activate(device_t self, devact_t act) |
1715 | { | | 1713 | { |
1716 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); | | 1714 | USBNETHIST_FUNC(); USBNETHIST_CALLED(); |
1717 | struct usbnet * const un = device_private(self); | | 1715 | struct usbnet * const un = device_private(self); |
1718 | struct usbnet_private * const unp = un->un_pri; | | 1716 | struct usbnet_private * const unp = un->un_pri; |
1719 | struct ifnet * const ifp = usbnet_ifp(un); | | 1717 | struct ifnet * const ifp = usbnet_ifp(un); |
1720 | | | 1718 | |
1721 | switch (act) { | | 1719 | switch (act) { |
1722 | case DVACT_DEACTIVATE: | | 1720 | case DVACT_DEACTIVATE: |
1723 | if_deactivate(ifp); | | 1721 | if_deactivate(ifp); |
1724 | | | 1722 | |
1725 | mutex_enter(&unp->unp_core_lock); | | 1723 | mutex_enter(&unp->unp_core_lock); |
1726 | unp->unp_dying = true; | | 1724 | atomic_store_relaxed(&unp->unp_dying, true); |
1727 | mutex_exit(&unp->unp_core_lock); | | 1725 | mutex_exit(&unp->unp_core_lock); |
1728 | | | 1726 | |
1729 | mutex_enter(&unp->unp_rxlock); | | 1727 | mutex_enter(&unp->unp_rxlock); |
1730 | mutex_enter(&unp->unp_txlock); | | 1728 | mutex_enter(&unp->unp_txlock); |
1731 | unp->unp_stopping = true; | | 1729 | unp->unp_stopping = true; |
1732 | mutex_exit(&unp->unp_txlock); | | 1730 | mutex_exit(&unp->unp_txlock); |
1733 | mutex_exit(&unp->unp_rxlock); | | 1731 | mutex_exit(&unp->unp_rxlock); |
1734 | | | 1732 | |
1735 | return 0; | | 1733 | return 0; |
1736 | default: | | 1734 | default: |
1737 | return EOPNOTSUPP; | | 1735 | return EOPNOTSUPP; |
1738 | } | | 1736 | } |
1739 | } | | 1737 | } |