| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: if_vioif.c,v 1.81 2022/05/04 02:38:27 simonb Exp $ */ | | 1 | /* $NetBSD: if_vioif.c,v 1.82 2022/09/12 07:26:04 knakahara Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2020 The NetBSD Foundation, Inc. | | 4 | * Copyright (c) 2020 The NetBSD Foundation, Inc. |
5 | * Copyright (c) 2010 Minoura Makoto. | | 5 | * Copyright (c) 2010 Minoura Makoto. |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | | 8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions | | 9 | * modification, are permitted provided that the following conditions |
10 | * are met: | | 10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright | | 11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. | | 12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the | | 14 | * notice, this list of conditions and the following disclaimer in the |
| @@ -17,27 +17,27 @@ | | | @@ -17,27 +17,27 @@ |
17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 17 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 18 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 19 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 20 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 21 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 22 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 23 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 24 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ | | 27 | */ |
28 | | | 28 | |
29 | #include <sys/cdefs.h> | | 29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: if_vioif.c,v 1.81 2022/05/04 02:38:27 simonb Exp $"); | | 30 | __KERNEL_RCSID(0, "$NetBSD: if_vioif.c,v 1.82 2022/09/12 07:26:04 knakahara Exp $"); |
31 | | | 31 | |
32 | #ifdef _KERNEL_OPT | | 32 | #ifdef _KERNEL_OPT |
33 | #include "opt_net_mpsafe.h" | | 33 | #include "opt_net_mpsafe.h" |
34 | #endif | | 34 | #endif |
35 | | | 35 | |
36 | #include <sys/param.h> | | 36 | #include <sys/param.h> |
37 | #include <sys/systm.h> | | 37 | #include <sys/systm.h> |
38 | #include <sys/kernel.h> | | 38 | #include <sys/kernel.h> |
39 | #include <sys/atomic.h> | | 39 | #include <sys/atomic.h> |
40 | #include <sys/bus.h> | | 40 | #include <sys/bus.h> |
41 | #include <sys/condvar.h> | | 41 | #include <sys/condvar.h> |
42 | #include <sys/device.h> | | 42 | #include <sys/device.h> |
43 | #include <sys/evcnt.h> | | 43 | #include <sys/evcnt.h> |
| @@ -309,27 +309,27 @@ struct vioif_softc { | | | @@ -309,27 +309,27 @@ struct vioif_softc { |
309 | kmutex_t sc_lock; | | 309 | kmutex_t sc_lock; |
310 | struct sysctllog *sc_sysctllog; | | 310 | struct sysctllog *sc_sysctllog; |
311 | | | 311 | |
312 | struct virtio_softc *sc_virtio; | | 312 | struct virtio_softc *sc_virtio; |
313 | struct virtqueue *sc_vqs; | | 313 | struct virtqueue *sc_vqs; |
314 | u_int sc_hdr_size; | | 314 | u_int sc_hdr_size; |
315 | | | 315 | |
316 | int sc_max_nvq_pairs; | | 316 | int sc_max_nvq_pairs; |
317 | int sc_req_nvq_pairs; | | 317 | int sc_req_nvq_pairs; |
318 | int sc_act_nvq_pairs; | | 318 | int sc_act_nvq_pairs; |
319 | | | 319 | |
320 | uint8_t sc_mac[ETHER_ADDR_LEN]; | | 320 | uint8_t sc_mac[ETHER_ADDR_LEN]; |
321 | struct ethercom sc_ethercom; | | 321 | struct ethercom sc_ethercom; |
322 | bool sc_link_active; | | 322 | int sc_link_state; |
323 | | | 323 | |
324 | struct vioif_txqueue *sc_txq; | | 324 | struct vioif_txqueue *sc_txq; |
325 | struct vioif_rxqueue *sc_rxq; | | 325 | struct vioif_rxqueue *sc_rxq; |
326 | | | 326 | |
327 | bool sc_has_ctrl; | | 327 | bool sc_has_ctrl; |
328 | struct vioif_ctrlqueue sc_ctrlq; | | 328 | struct vioif_ctrlqueue sc_ctrlq; |
329 | | | 329 | |
330 | bus_dma_segment_t sc_hdr_segs[1]; | | 330 | bus_dma_segment_t sc_hdr_segs[1]; |
331 | void *sc_dmamem; | | 331 | void *sc_dmamem; |
332 | void *sc_kmem; | | 332 | void *sc_kmem; |
333 | | | 333 | |
334 | void *sc_ctl_softint; | | 334 | void *sc_ctl_softint; |
335 | | | 335 | |
| @@ -339,26 +339,28 @@ struct vioif_softc { | | | @@ -339,26 +339,28 @@ struct vioif_softc { |
339 | u_int sc_tx_process_limit; | | 339 | u_int sc_tx_process_limit; |
340 | u_int sc_rx_intr_process_limit; | | 340 | u_int sc_rx_intr_process_limit; |
341 | u_int sc_rx_process_limit; | | 341 | u_int sc_rx_process_limit; |
342 | }; | | 342 | }; |
343 | #define VIRTIO_NET_TX_MAXNSEGS (16) /* XXX */ | | 343 | #define VIRTIO_NET_TX_MAXNSEGS (16) /* XXX */ |
344 | #define VIRTIO_NET_CTRL_MAC_MAXENTRIES (64) /* XXX */ | | 344 | #define VIRTIO_NET_CTRL_MAC_MAXENTRIES (64) /* XXX */ |
345 | | | 345 | |
346 | #define VIOIF_TX_INTR_PROCESS_LIMIT 256 | | 346 | #define VIOIF_TX_INTR_PROCESS_LIMIT 256 |
347 | #define VIOIF_TX_PROCESS_LIMIT 256 | | 347 | #define VIOIF_TX_PROCESS_LIMIT 256 |
348 | #define VIOIF_RX_INTR_PROCESS_LIMIT 0U | | 348 | #define VIOIF_RX_INTR_PROCESS_LIMIT 0U |
349 | #define VIOIF_RX_PROCESS_LIMIT 256 | | 349 | #define VIOIF_RX_PROCESS_LIMIT 256 |
350 | | | 350 | |
351 | #define VIOIF_WORKQUEUE_PRI PRI_SOFTNET | | 351 | #define VIOIF_WORKQUEUE_PRI PRI_SOFTNET |
| | | 352 | #define VIOIF_IS_LINK_ACTIVE(_sc) ((_sc)->sc_link_state == LINK_STATE_UP ? \ |
| | | 353 | true : false) |
352 | | | 354 | |
353 | /* cfattach interface functions */ | | 355 | /* cfattach interface functions */ |
354 | static int vioif_match(device_t, cfdata_t, void *); | | 356 | static int vioif_match(device_t, cfdata_t, void *); |
355 | static void vioif_attach(device_t, device_t, void *); | | 357 | static void vioif_attach(device_t, device_t, void *); |
356 | static int vioif_finalize_teardown(device_t); | | 358 | static int vioif_finalize_teardown(device_t); |
357 | | | 359 | |
358 | /* ifnet interface functions */ | | 360 | /* ifnet interface functions */ |
359 | static int vioif_init(struct ifnet *); | | 361 | static int vioif_init(struct ifnet *); |
360 | static void vioif_stop(struct ifnet *, int); | | 362 | static void vioif_stop(struct ifnet *, int); |
361 | static void vioif_start(struct ifnet *); | | 363 | static void vioif_start(struct ifnet *); |
362 | static void vioif_start_locked(struct ifnet *, struct vioif_txqueue *); | | 364 | static void vioif_start_locked(struct ifnet *, struct vioif_txqueue *); |
363 | static int vioif_transmit(struct ifnet *, struct mbuf *); | | 365 | static int vioif_transmit(struct ifnet *, struct mbuf *); |
364 | static void vioif_transmit_locked(struct ifnet *, struct vioif_txqueue *); | | 366 | static void vioif_transmit_locked(struct ifnet *, struct vioif_txqueue *); |
| @@ -391,27 +393,27 @@ static bool vioif_tx_deq_locked(struct v | | | @@ -391,27 +393,27 @@ static bool vioif_tx_deq_locked(struct v |
391 | static void vioif_tx_drain(struct vioif_txqueue *); | | 393 | static void vioif_tx_drain(struct vioif_txqueue *); |
392 | static void vioif_deferred_transmit(void *); | | 394 | static void vioif_deferred_transmit(void *); |
393 | | | 395 | |
394 | /* workqueue */ | | 396 | /* workqueue */ |
395 | static struct workqueue* | | 397 | static struct workqueue* |
396 | vioif_workq_create(const char *, pri_t, int, int); | | 398 | vioif_workq_create(const char *, pri_t, int, int); |
397 | static void vioif_workq_destroy(struct workqueue *); | | 399 | static void vioif_workq_destroy(struct workqueue *); |
398 | static void vioif_workq_work(struct work *, void *); | | 400 | static void vioif_workq_work(struct work *, void *); |
399 | static void vioif_work_set(struct vioif_work *, void(*)(void *), void *); | | 401 | static void vioif_work_set(struct vioif_work *, void(*)(void *), void *); |
400 | static void vioif_work_add(struct workqueue *, struct vioif_work *); | | 402 | static void vioif_work_add(struct workqueue *, struct vioif_work *); |
401 | static void vioif_work_wait(struct workqueue *, struct vioif_work *); | | 403 | static void vioif_work_wait(struct workqueue *, struct vioif_work *); |
402 | | | 404 | |
403 | /* other control */ | | 405 | /* other control */ |
404 | static bool vioif_is_link_up(struct vioif_softc *); | | 406 | static int vioif_get_link_status(struct vioif_softc *); |
405 | static void vioif_update_link_status(struct vioif_softc *); | | 407 | static void vioif_update_link_status(struct vioif_softc *); |
406 | static int vioif_ctrl_rx(struct vioif_softc *, int, bool); | | 408 | static int vioif_ctrl_rx(struct vioif_softc *, int, bool); |
407 | static int vioif_set_promisc(struct vioif_softc *, bool); | | 409 | static int vioif_set_promisc(struct vioif_softc *, bool); |
408 | static int vioif_set_allmulti(struct vioif_softc *, bool); | | 410 | static int vioif_set_allmulti(struct vioif_softc *, bool); |
409 | static int vioif_set_rx_filter(struct vioif_softc *); | | 411 | static int vioif_set_rx_filter(struct vioif_softc *); |
410 | static int vioif_rx_filter(struct vioif_softc *); | | 412 | static int vioif_rx_filter(struct vioif_softc *); |
411 | static int vioif_set_mac_addr(struct vioif_softc *); | | 413 | static int vioif_set_mac_addr(struct vioif_softc *); |
412 | static int vioif_ctrl_intr(void *); | | 414 | static int vioif_ctrl_intr(void *); |
413 | static int vioif_config_change(struct virtio_softc *); | | 415 | static int vioif_config_change(struct virtio_softc *); |
414 | static void vioif_ctl_softint(void *); | | 416 | static void vioif_ctl_softint(void *); |
415 | static int vioif_ctrl_mq_vq_pairs_set(struct vioif_softc *, int); | | 417 | static int vioif_ctrl_mq_vq_pairs_set(struct vioif_softc *, int); |
416 | static void vioif_enable_interrupt_vqpairs(struct vioif_softc *); | | 418 | static void vioif_enable_interrupt_vqpairs(struct vioif_softc *); |
417 | static void vioif_disable_interrupt_vqpairs(struct vioif_softc *); | | 419 | static void vioif_disable_interrupt_vqpairs(struct vioif_softc *); |
| @@ -820,27 +822,27 @@ vioif_attach(device_t parent, device_t s | | | @@ -820,27 +822,27 @@ vioif_attach(device_t parent, device_t s |
820 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 822 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
821 | u_int softint_flags; | | 823 | u_int softint_flags; |
822 | int r, i, nvqs = 0, req_flags; | | 824 | int r, i, nvqs = 0, req_flags; |
823 | char xnamebuf[MAXCOMLEN]; | | 825 | char xnamebuf[MAXCOMLEN]; |
824 | | | 826 | |
825 | if (virtio_child(vsc) != NULL) { | | 827 | if (virtio_child(vsc) != NULL) { |
826 | aprint_normal(": child already attached for %s; " | | 828 | aprint_normal(": child already attached for %s; " |
827 | "something wrong...\n", device_xname(parent)); | | 829 | "something wrong...\n", device_xname(parent)); |
828 | return; | | 830 | return; |
829 | } | | 831 | } |
830 | | | 832 | |
831 | sc->sc_dev = self; | | 833 | sc->sc_dev = self; |
832 | sc->sc_virtio = vsc; | | 834 | sc->sc_virtio = vsc; |
833 | sc->sc_link_active = false; | | 835 | sc->sc_link_state = LINK_STATE_UNKNOWN; |
834 | | | 836 | |
835 | sc->sc_max_nvq_pairs = 1; | | 837 | sc->sc_max_nvq_pairs = 1; |
836 | sc->sc_req_nvq_pairs = 1; | | 838 | sc->sc_req_nvq_pairs = 1; |
837 | sc->sc_act_nvq_pairs = 1; | | 839 | sc->sc_act_nvq_pairs = 1; |
838 | sc->sc_txrx_workqueue_sysctl = true; | | 840 | sc->sc_txrx_workqueue_sysctl = true; |
839 | sc->sc_tx_intr_process_limit = VIOIF_TX_INTR_PROCESS_LIMIT; | | 841 | sc->sc_tx_intr_process_limit = VIOIF_TX_INTR_PROCESS_LIMIT; |
840 | sc->sc_tx_process_limit = VIOIF_TX_PROCESS_LIMIT; | | 842 | sc->sc_tx_process_limit = VIOIF_TX_PROCESS_LIMIT; |
841 | sc->sc_rx_intr_process_limit = VIOIF_RX_INTR_PROCESS_LIMIT; | | 843 | sc->sc_rx_intr_process_limit = VIOIF_RX_INTR_PROCESS_LIMIT; |
842 | sc->sc_rx_process_limit = VIOIF_RX_PROCESS_LIMIT; | | 844 | sc->sc_rx_process_limit = VIOIF_RX_PROCESS_LIMIT; |
843 | | | 845 | |
844 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); | | 846 | mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); |
845 | | | 847 | |
846 | snprintf(xnamebuf, sizeof(xnamebuf), "%s_txrx", device_xname(self)); | | 848 | snprintf(xnamebuf, sizeof(xnamebuf), "%s_txrx", device_xname(self)); |
| @@ -973,27 +975,27 @@ vioif_attach(device_t parent, device_t s | | | @@ -973,27 +975,27 @@ vioif_attach(device_t parent, device_t s |
973 | aprint_error_dev(self, "cannot establish tx softint\n"); | | 975 | aprint_error_dev(self, "cannot establish tx softint\n"); |
974 | goto err; | | 976 | goto err; |
975 | } | | 977 | } |
976 | | | 978 | |
977 | snprintf(qname, sizeof(qname), "tx%d", i); | | 979 | snprintf(qname, sizeof(qname), "tx%d", i); |
978 | r = virtio_alloc_vq(vsc, txq->txq_vq, nvqs, | | 980 | r = virtio_alloc_vq(vsc, txq->txq_vq, nvqs, |
979 | sc->sc_hdr_size + (ETHER_MAX_LEN - ETHER_HDR_LEN), | | 981 | sc->sc_hdr_size + (ETHER_MAX_LEN - ETHER_HDR_LEN), |
980 | VIRTIO_NET_TX_MAXNSEGS + 1, qname); | | 982 | VIRTIO_NET_TX_MAXNSEGS + 1, qname); |
981 | if (r != 0) | | 983 | if (r != 0) |
982 | goto err; | | 984 | goto err; |
983 | nvqs++; | | 985 | nvqs++; |
984 | txq->txq_vq->vq_intrhand = vioif_tx_intr; | | 986 | txq->txq_vq->vq_intrhand = vioif_tx_intr; |
985 | txq->txq_vq->vq_intrhand_arg = (void *)txq; | | 987 | txq->txq_vq->vq_intrhand_arg = (void *)txq; |
986 | txq->txq_link_active = sc->sc_link_active; | | 988 | txq->txq_link_active = VIOIF_IS_LINK_ACTIVE(sc); |
987 | txq->txq_stopping = false; | | 989 | txq->txq_stopping = false; |
988 | txq->txq_intrq = pcq_create(txq->txq_vq->vq_num, KM_SLEEP); | | 990 | txq->txq_intrq = pcq_create(txq->txq_vq->vq_num, KM_SLEEP); |
989 | vioif_work_set(&txq->txq_work, vioif_tx_handle, txq); | | 991 | vioif_work_set(&txq->txq_work, vioif_tx_handle, txq); |
990 | } | | 992 | } |
991 | | | 993 | |
992 | if (sc->sc_has_ctrl) { | | 994 | if (sc->sc_has_ctrl) { |
993 | /* | | 995 | /* |
994 | * Allocating a virtqueue for control channel | | 996 | * Allocating a virtqueue for control channel |
995 | */ | | 997 | */ |
996 | r = virtio_alloc_vq(vsc, ctrlq->ctrlq_vq, nvqs, | | 998 | r = virtio_alloc_vq(vsc, ctrlq->ctrlq_vq, nvqs, |
997 | NBPG, 1, "control"); | | 999 | NBPG, 1, "control"); |
998 | if (r != 0) { | | 1000 | if (r != 0) { |
999 | aprint_error_dev(self, "failed to allocate " | | 1001 | aprint_error_dev(self, "failed to allocate " |
| @@ -1247,34 +1249,31 @@ vioif_stop(struct ifnet *ifp, int disabl | | | @@ -1247,34 +1249,31 @@ vioif_stop(struct ifnet *ifp, int disabl |
1247 | mutex_exit(txq->txq_lock); | | 1249 | mutex_exit(txq->txq_lock); |
1248 | vioif_work_wait(sc->sc_txrx_workqueue, &txq->txq_work); | | 1250 | vioif_work_wait(sc->sc_txrx_workqueue, &txq->txq_work); |
1249 | } | | 1251 | } |
1250 | | | 1252 | |
1251 | /* only way to stop I/O and DMA is resetting... */ | | 1253 | /* only way to stop I/O and DMA is resetting... */ |
1252 | virtio_reset(vsc); | | 1254 | virtio_reset(vsc); |
1253 | | | 1255 | |
1254 | for (i = 0; i < sc->sc_act_nvq_pairs; i++) { | | 1256 | for (i = 0; i < sc->sc_act_nvq_pairs; i++) { |
1255 | vioif_rx_queue_clear(&sc->sc_rxq[i]); | | 1257 | vioif_rx_queue_clear(&sc->sc_rxq[i]); |
1256 | vioif_tx_queue_clear(&sc->sc_txq[i]); | | 1258 | vioif_tx_queue_clear(&sc->sc_txq[i]); |
1257 | } | | 1259 | } |
1258 | | | 1260 | |
1259 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | | 1261 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
1260 | sc->sc_link_active = false; | | | |
1261 | | | 1262 | |
1262 | for (i = 0; i < sc->sc_act_nvq_pairs; i++) { | | 1263 | for (i = 0; i < sc->sc_act_nvq_pairs; i++) { |
1263 | txq = &sc->sc_txq[i]; | | 1264 | txq = &sc->sc_txq[i]; |
1264 | rxq = &sc->sc_rxq[i]; | | 1265 | rxq = &sc->sc_rxq[i]; |
1265 | | | 1266 | |
1266 | txq->txq_link_active = false; | | | |
1267 | | | | |
1268 | if (disable) | | 1267 | if (disable) |
1269 | vioif_rx_drain(rxq); | | 1268 | vioif_rx_drain(rxq); |
1270 | | | 1269 | |
1271 | vioif_tx_drain(txq); | | 1270 | vioif_tx_drain(txq); |
1272 | } | | 1271 | } |
1273 | } | | 1272 | } |
1274 | | | 1273 | |
1275 | static void | | 1274 | static void |
1276 | vioif_send_common_locked(struct ifnet *ifp, struct vioif_txqueue *txq, | | 1275 | vioif_send_common_locked(struct ifnet *ifp, struct vioif_txqueue *txq, |
1277 | bool is_transmit) | | 1276 | bool is_transmit) |
1278 | { | | 1277 | { |
1279 | struct vioif_softc *sc = ifp->if_softc; | | 1278 | struct vioif_softc *sc = ifp->if_softc; |
1280 | struct virtio_softc *vsc = sc->sc_virtio; | | 1279 | struct virtio_softc *vsc = sc->sc_virtio; |
| @@ -2383,81 +2382,74 @@ vioif_rx_filter(struct vioif_softc *sc) | | | @@ -2383,81 +2382,74 @@ vioif_rx_filter(struct vioif_softc *sc) |
2383 | ifp->if_xname); | | 2382 | ifp->if_xname); |
2384 | /* what to do on failure? */ | | 2383 | /* what to do on failure? */ |
2385 | } | | 2384 | } |
2386 | | | 2385 | |
2387 | ifp->if_flags |= IFF_ALLMULTI; | | 2386 | ifp->if_flags |= IFF_ALLMULTI; |
2388 | } | | 2387 | } |
2389 | | | 2388 | |
2390 | set_ifflags: | | 2389 | set_ifflags: |
2391 | r = vioif_ifflags(sc); | | 2390 | r = vioif_ifflags(sc); |
2392 | | | 2391 | |
2393 | return r; | | 2392 | return r; |
2394 | } | | 2393 | } |
2395 | | | 2394 | |
2396 | static bool | | 2395 | static int |
2397 | vioif_is_link_up(struct vioif_softc *sc) | | 2396 | vioif_get_link_status(struct vioif_softc *sc) |
2398 | { | | 2397 | { |
2399 | struct virtio_softc *vsc = sc->sc_virtio; | | 2398 | struct virtio_softc *vsc = sc->sc_virtio; |
2400 | uint16_t status; | | 2399 | uint16_t status; |
2401 | | | 2400 | |
2402 | if (virtio_features(vsc) & VIRTIO_NET_F_STATUS) | | 2401 | if (virtio_features(vsc) & VIRTIO_NET_F_STATUS) |
2403 | status = virtio_read_device_config_2(vsc, | | 2402 | status = virtio_read_device_config_2(vsc, |
2404 | VIRTIO_NET_CONFIG_STATUS); | | 2403 | VIRTIO_NET_CONFIG_STATUS); |
2405 | else | | 2404 | else |
2406 | status = VIRTIO_NET_S_LINK_UP; | | 2405 | status = VIRTIO_NET_S_LINK_UP; |
2407 | | | 2406 | |
2408 | return ((status & VIRTIO_NET_S_LINK_UP) != 0); | | 2407 | if ((status & VIRTIO_NET_S_LINK_UP) != 0) |
| | | 2408 | return LINK_STATE_UP; |
| | | 2409 | |
| | | 2410 | return LINK_STATE_DOWN; |
2409 | } | | 2411 | } |
2410 | | | 2412 | |
2411 | /* change link status */ | | 2413 | /* change link status */ |
2412 | static void | | 2414 | static void |
2413 | vioif_update_link_status(struct vioif_softc *sc) | | 2415 | vioif_update_link_status(struct vioif_softc *sc) |
2414 | { | | 2416 | { |
2415 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; | | 2417 | struct ifnet *ifp = &sc->sc_ethercom.ec_if; |
2416 | struct vioif_txqueue *txq; | | 2418 | struct vioif_txqueue *txq; |
2417 | bool active, changed; | | 2419 | bool active; |
2418 | int link, i; | | 2420 | int link, i; |
2419 | | | 2421 | |
2420 | mutex_enter(&sc->sc_lock); | | 2422 | mutex_enter(&sc->sc_lock); |
2421 | | | 2423 | |
2422 | active = vioif_is_link_up(sc); | | 2424 | link = vioif_get_link_status(sc); |
2423 | changed = false; | | | |
2424 | | | 2425 | |
2425 | if (active) { | | 2426 | if (link == sc->sc_link_state) |
2426 | if (!sc->sc_link_active) | | 2427 | goto done; |
2427 | changed = true; | | | |
2428 | | | 2428 | |
2429 | link = LINK_STATE_UP; | | 2429 | sc->sc_link_state = link; |
2430 | sc->sc_link_active = true; | | | |
2431 | } else { | | | |
2432 | if (sc->sc_link_active) | | | |
2433 | changed = true; | | | |
2434 | | | | |
2435 | link = LINK_STATE_DOWN; | | | |
2436 | sc->sc_link_active = false; | | | |
2437 | } | | | |
2438 | | | 2430 | |
2439 | if (changed) { | | 2431 | active = VIOIF_IS_LINK_ACTIVE(sc); |
2440 | for (i = 0; i < sc->sc_act_nvq_pairs; i++) { | | 2432 | for (i = 0; i < sc->sc_act_nvq_pairs; i++) { |
2441 | txq = &sc->sc_txq[i]; | | 2433 | txq = &sc->sc_txq[i]; |
2442 | | | | |
2443 | mutex_enter(txq->txq_lock); | | | |
2444 | txq->txq_link_active = sc->sc_link_active; | | | |
2445 | mutex_exit(txq->txq_lock); | | | |
2446 | } | | | |
2447 | | | 2434 | |
2448 | if_link_state_change(ifp, link); | | 2435 | mutex_enter(txq->txq_lock); |
| | | 2436 | txq->txq_link_active = active; |
| | | 2437 | mutex_exit(txq->txq_lock); |
2449 | } | | 2438 | } |
2450 | | | 2439 | |
| | | 2440 | if_link_state_change(ifp, sc->sc_link_state); |
| | | 2441 | |
| | | 2442 | done: |
2451 | mutex_exit(&sc->sc_lock); | | 2443 | mutex_exit(&sc->sc_lock); |
2452 | } | | 2444 | } |
2453 | | | 2445 | |
2454 | static int | | 2446 | static int |
2455 | vioif_config_change(struct virtio_softc *vsc) | | 2447 | vioif_config_change(struct virtio_softc *vsc) |
2456 | { | | 2448 | { |
2457 | struct vioif_softc *sc = device_private(virtio_child(vsc)); | | 2449 | struct vioif_softc *sc = device_private(virtio_child(vsc)); |
2458 | | | 2450 | |
2459 | softint_schedule(sc->sc_ctl_softint); | | 2451 | softint_schedule(sc->sc_ctl_softint); |
2460 | return 0; | | 2452 | return 0; |
2461 | } | | 2453 | } |
2462 | | | 2454 | |
2463 | static void | | 2455 | static void |