diff --git a/sys/dev/pci/if_vioif.c b/sys/dev/pci/if_vioif.c index 0550782a5b26..043f70e3246d 100644 --- a/sys/dev/pci/if_vioif.c +++ b/sys/dev/pci/if_vioif.c @@ -56,7 +56,6 @@ __KERNEL_RCSID(0, "$NetBSD: if_vioif.c,v 1.77 2022/03/31 06:17:34 yamaguchi Exp #include #include -#include #include #include @@ -158,7 +157,6 @@ struct virtio_net_ctrl_cmd { #define VIRTIO_NET_CTRL_MAC 1 # define VIRTIO_NET_CTRL_MAC_TABLE_SET 0 -# define VIRTIO_NET_CTRL_MAC_ADDR_SET 1 #define VIRTIO_NET_CTRL_VLAN 2 # define VIRTIO_NET_CTRL_VLAN_ADD 0 @@ -184,10 +182,6 @@ struct virtio_net_ctrl_mac_tbl { uint8_t macs[][ETHER_ADDR_LEN]; } __packed; -struct virtio_net_ctrl_mac_addr { - uint8_t mac[ETHER_ADDR_LEN]; -} __packed; - struct virtio_net_ctrl_vlan { uint16_t id; } __packed; @@ -287,7 +281,6 @@ struct vioif_ctrlqueue { struct virtio_net_ctrl_rx *ctrlq_rx; struct virtio_net_ctrl_mac_tbl *ctrlq_mac_tbl_uc; struct virtio_net_ctrl_mac_tbl *ctrlq_mac_tbl_mc; - struct virtio_net_ctrl_mac_addr *ctrlq_mac_addr; struct virtio_net_ctrl_mq *ctrlq_mq; bus_dmamap_t ctrlq_cmd_dmamap; @@ -295,7 +288,6 @@ struct vioif_ctrlqueue { bus_dmamap_t ctrlq_rx_dmamap; bus_dmamap_t ctrlq_tbl_uc_dmamap; bus_dmamap_t ctrlq_tbl_mc_dmamap; - bus_dmamap_t ctrlq_mac_addr_dmamap; bus_dmamap_t ctrlq_mq_dmamap; struct evcnt ctrlq_cmd_load_failed; @@ -317,6 +309,7 @@ struct vioif_softc { uint8_t sc_mac[ETHER_ADDR_LEN]; struct ethercom sc_ethercom; + short sc_deferred_init_done; bool sc_link_active; struct vioif_txqueue *sc_txq; @@ -351,6 +344,7 @@ struct vioif_softc { /* cfattach interface functions */ static int vioif_match(device_t, cfdata_t, void *); static void vioif_attach(device_t, device_t, void *); +static void vioif_deferred_init(device_t); static int vioif_finalize_teardown(device_t); /* ifnet interface functions */ @@ -362,7 +356,6 @@ static int vioif_transmit(struct ifnet *, struct mbuf *); static void vioif_transmit_locked(struct ifnet *, struct vioif_txqueue *); static int vioif_ioctl(struct ifnet *, u_long, void *); static void vioif_watchdog(struct ifnet *); -static int vioif_ifflags_cb(struct ethercom *); /* rx */ static int vioif_add_rx_mbuf(struct vioif_rxqueue *, int); @@ -406,7 +399,6 @@ static int vioif_set_promisc(struct vioif_softc *, bool); static int vioif_set_allmulti(struct vioif_softc *, bool); static int vioif_set_rx_filter(struct vioif_softc *); static int vioif_rx_filter(struct vioif_softc *); -static int vioif_set_mac_addr(struct vioif_softc *); static int vioif_ctrl_intr(void *); static int vioif_config_change(struct virtio_softc *); static void vioif_ctl_softint(void *); @@ -415,7 +407,6 @@ static void vioif_enable_interrupt_vqpairs(struct vioif_softc *); static void vioif_disable_interrupt_vqpairs(struct vioif_softc *); static int vioif_setup_sysctl(struct vioif_softc *); static void vioif_setup_stats(struct vioif_softc *); -static int vioif_ifflags(struct vioif_softc *); CFATTACH_DECL_NEW(vioif, sizeof(struct vioif_softc), vioif_match, vioif_attach, NULL, NULL); @@ -588,15 +579,13 @@ vioif_alloc_mems(struct vioif_softc *sc) (rxq->rxq_vq->vq_num + txq->txq_vq->vq_num); } if (sc->sc_has_ctrl) { - allocsize += sizeof(struct virtio_net_ctrl_cmd); - allocsize += sizeof(struct virtio_net_ctrl_status); - allocsize += sizeof(struct virtio_net_ctrl_rx); - allocsize += sizeof(struct virtio_net_ctrl_mac_tbl) - + ETHER_ADDR_LEN; + allocsize += sizeof(struct virtio_net_ctrl_cmd) * 1; + allocsize += sizeof(struct virtio_net_ctrl_status) * 1; + allocsize += sizeof(struct virtio_net_ctrl_rx) * 1; allocsize += sizeof(struct virtio_net_ctrl_mac_tbl) + + sizeof(struct virtio_net_ctrl_mac_tbl) + ETHER_ADDR_LEN * VIRTIO_NET_CTRL_MAC_MAXENTRIES; - allocsize += sizeof(struct virtio_net_ctrl_mac_addr); - allocsize += sizeof(struct virtio_net_ctrl_mq); + allocsize += sizeof(struct virtio_net_ctrl_mq) * 1; } r = bus_dmamem_alloc(virtio_dmat(vsc), allocsize, 0, 0, &sc->sc_hdr_segs[0], 1, &rsegs, BUS_DMA_NOWAIT); @@ -635,13 +624,10 @@ vioif_alloc_mems(struct vioif_softc *sc) ctrlq->ctrlq_rx = vioif_assign_mem(&p, sizeof(*ctrlq->ctrlq_rx)); ctrlq->ctrlq_mac_tbl_uc = vioif_assign_mem(&p, - sizeof(*ctrlq->ctrlq_mac_tbl_uc) - + ETHER_ADDR_LEN); + sizeof(*ctrlq->ctrlq_mac_tbl_uc)); ctrlq->ctrlq_mac_tbl_mc = vioif_assign_mem(&p, sizeof(*ctrlq->ctrlq_mac_tbl_mc) + ETHER_ADDR_LEN * VIRTIO_NET_CTRL_MAC_MAXENTRIES); - ctrlq->ctrlq_mac_addr = vioif_assign_mem(&p, - sizeof(*ctrlq->ctrlq_mac_addr)); ctrlq->ctrlq_mq = vioif_assign_mem(&p, sizeof(*ctrlq->ctrlq_mq)); } @@ -749,8 +735,7 @@ vioif_alloc_mems(struct vioif_softc *sc) /* control vq MAC filter table for unicast */ /* do not load now since its length is variable */ r = vioif_dmamap_create(sc, &ctrlq->ctrlq_tbl_uc_dmamap, - sizeof(*ctrlq->ctrlq_mac_tbl_uc) - + ETHER_ADDR_LEN, 1, + sizeof(*ctrlq->ctrlq_mac_tbl_uc) + 0, 1, "unicast MAC address filter command"); if (r != 0) goto err_reqs; @@ -762,15 +747,6 @@ vioif_alloc_mems(struct vioif_softc *sc) "multicast MAC address filter command"); if (r != 0) goto err_reqs; - - /* control vq MAC address set command */ - r = vioif_dmamap_create_load(sc, - &ctrlq->ctrlq_mac_addr_dmamap, - ctrlq->ctrlq_mac_addr, - sizeof(*ctrlq->ctrlq_mac_addr), 1, - BUS_DMA_WRITE, "mac addr set command"); - if (r != 0) - goto err_reqs; } return 0; @@ -781,7 +757,6 @@ err_reqs: vioif_dmamap_destroy(sc, &ctrlq->ctrlq_rx_dmamap); vioif_dmamap_destroy(sc, &ctrlq->ctrlq_status_dmamap); vioif_dmamap_destroy(sc, &ctrlq->ctrlq_cmd_dmamap); - vioif_dmamap_destroy(sc, &ctrlq->ctrlq_mac_addr_dmamap); for (qid = 0; qid < sc->sc_max_nvq_pairs; qid++) { rxq = &sc->sc_rxq[qid]; txq = &sc->sc_txq[qid]; @@ -1050,7 +1025,6 @@ vioif_attach(device_t parent, device_t self, void *aux) if_attach(ifp); if_deferred_start_init(ifp, NULL); ether_ifattach(ifp, sc->sc_mac); - ether_set_ifflags_cb(&sc->sc_ethercom, vioif_ifflags_cb); return; @@ -1119,6 +1093,23 @@ vioif_finalize_teardown(device_t self) return 0; } +/* we need interrupts to make promiscuous mode off */ +static void +vioif_deferred_init(device_t self) +{ + struct vioif_softc *sc = device_private(self); + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + int r; + + if (ifp->if_flags & IFF_PROMISC) + return; + + r = vioif_set_promisc(sc, false); + if (r != 0) + aprint_error_dev(self, "resetting promisc mode failed, " + "error code %d\n", r); +} + static void vioif_enable_interrupt_vqpairs(struct vioif_softc *sc) { @@ -1202,12 +1193,18 @@ vioif_init(struct ifnet *ifp) vioif_enable_interrupt_vqpairs(sc); + if (!sc->sc_deferred_init_done) { + sc->sc_deferred_init_done = 1; + if (sc->sc_has_ctrl) + vioif_deferred_init(sc->sc_dev); + } + vioif_update_link_status(sc); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; - r = vioif_rx_filter(sc); + vioif_rx_filter(sc); - return r; + return 0; } static void @@ -1464,12 +1461,12 @@ vioif_ioctl(struct ifnet *ifp, u_long cmd, void *data) s = splnet(); r = ether_ioctl(ifp, cmd, data); - if (r == ENETRESET && (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI)) { - if (ifp->if_flags & IFF_RUNNING) { + if ((r == 0 && cmd == SIOCSIFFLAGS) || + (r == ENETRESET && (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI))) { + if (ifp->if_flags & IFF_RUNNING) r = vioif_rx_filter(ifp->if_softc); - } else { + else r = 0; - } } splx(s); @@ -2162,35 +2159,6 @@ out: return r; } -static int -vioif_set_mac_addr(struct vioif_softc *sc) -{ - struct virtio_net_ctrl_mac_addr *ma = - sc->sc_ctrlq.ctrlq_mac_addr; - struct vioif_ctrl_cmdspec specs[1]; - struct ifnet *ifp = &sc->sc_ethercom.ec_if; - int nspecs = __arraycount(specs); - int r; - - if (!sc->sc_has_ctrl) - return ENOTSUP; - - vioif_ctrl_acquire(sc); - - memcpy(ma->mac, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); - specs[0].dmamap = sc->sc_ctrlq.ctrlq_mac_addr_dmamap; - specs[0].buf = ma; - specs[0].bufsize = sizeof(*ma); - - r = vioif_ctrl_send_command(sc, - VIRTIO_NET_CTRL_MAC, VIRTIO_NET_CTRL_MAC_ADDR_SET, - specs, nspecs); - - vioif_ctrl_release(sc); - - return r; -} - static int vioif_ctrl_mq_vq_pairs_set(struct vioif_softc *sc, int nvq_pairs) { @@ -2245,57 +2213,14 @@ vioif_ctrl_intr(void *arg) return 1; } -static int -vioif_ifflags(struct vioif_softc *sc) -{ - struct ifnet *ifp = &sc->sc_ethercom.ec_if; - bool onoff; - int r; - - if (!sc->sc_has_ctrl) { - /* no ctrl vq; always promisc and allmulti */ - ifp->if_flags |= (IFF_PROMISC | IFF_ALLMULTI); - return 0; - } - - onoff = ifp->if_flags & IFF_ALLMULTI ? true : false; - r = vioif_set_allmulti(sc, onoff); - if (r != 0) { - log(LOG_WARNING, - "%s: couldn't %sable ALLMULTI\n", - ifp->if_xname, onoff ? "en" : "dis"); - if (onoff == false) { - ifp->if_flags |= IFF_ALLMULTI; - } - } - - onoff = ifp->if_flags & IFF_PROMISC ? true : false; - r = vioif_set_promisc(sc, onoff); - if (r != 0) { - log(LOG_WARNING, - "%s: couldn't %sable PROMISC\n", - ifp->if_xname, onoff ? "en" : "dis"); - if (onoff == false) { - ifp->if_flags |= IFF_PROMISC; - } - } - - return 0; -} - -static int -vioif_ifflags_cb(struct ethercom *ec) -{ - struct ifnet *ifp = &ec->ec_if; - struct vioif_softc *sc = ifp->if_softc; - - return vioif_ifflags(sc); -} - /* + * If IFF_PROMISC requested, set promiscuous * If multicast filter small enough (<=MAXENTRIES) set rx filter * If large multicast filter exist use ALLMULTI + */ +/* * If setting rx filter fails fall back to ALLMULTI + * If ALLMULTI fails fall back to PROMISC */ static int vioif_rx_filter(struct vioif_softc *sc) @@ -2307,67 +2232,71 @@ vioif_rx_filter(struct vioif_softc *sc) struct ether_multistep step; struct vioif_ctrlqueue *ctrlq = &sc->sc_ctrlq; int nentries; - bool allmulti = 0; + int promisc = 0, allmulti = 0, rxfilter = 0; int r; - if (!sc->sc_has_ctrl) { - goto set_ifflags; + if (!sc->sc_has_ctrl) { /* no ctrl vq; always promisc */ + ifp->if_flags |= IFF_PROMISC; + return 0; } - memcpy(ctrlq->ctrlq_mac_tbl_uc->macs[0], - CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); - - nentries = 0; - allmulti = false; + if (ifp->if_flags & IFF_PROMISC) { + promisc = 1; + goto set; + } + nentries = -1; ETHER_LOCK(ec); - for (ETHER_FIRST_MULTI(step, ec, enm); enm != NULL; - ETHER_NEXT_MULTI(step, enm)) { + ETHER_FIRST_MULTI(step, ec, enm); + while (nentries++, enm != NULL) { if (nentries >= VIRTIO_NET_CTRL_MAC_MAXENTRIES) { - allmulti = true; - break; + allmulti = 1; + goto set_unlock; } if (memcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) { - allmulti = true; - break; + allmulti = 1; + goto set_unlock; } - memcpy(ctrlq->ctrlq_mac_tbl_mc->macs[nentries], enm->enm_addrlo, ETHER_ADDR_LEN); - nentries++; + ETHER_NEXT_MULTI(step, enm); } - ETHER_UNLOCK(ec); + rxfilter = 1; - r = vioif_set_mac_addr(sc); - if (r != 0) { - log(LOG_WARNING, "%s: couldn't set MAC address\n", - ifp->if_xname); - } +set_unlock: + ETHER_UNLOCK(ec); - if (!allmulti) { - ctrlq->ctrlq_mac_tbl_uc->nentries = virtio_rw32(vsc, 1); +set: + if (rxfilter) { + ctrlq->ctrlq_mac_tbl_uc->nentries = virtio_rw32(vsc, 0); ctrlq->ctrlq_mac_tbl_mc->nentries = virtio_rw32(vsc, nentries); r = vioif_set_rx_filter(sc); if (r != 0) { - allmulti = true; /* fallback */ + rxfilter = 0; + allmulti = 1; /* fallback */ } - } - - if (allmulti) { + } else { + /* remove rx filter */ ctrlq->ctrlq_mac_tbl_uc->nentries = virtio_rw32(vsc, 0); ctrlq->ctrlq_mac_tbl_mc->nentries = virtio_rw32(vsc, 0); r = vioif_set_rx_filter(sc); + /* what to do on failure? */ + } + if (allmulti) { + r = vioif_set_allmulti(sc, true); if (r != 0) { - log(LOG_DEBUG, "%s: couldn't clear RX filter\n", - ifp->if_xname); - /* what to do on failure? */ + allmulti = 0; + promisc = 1; /* fallback */ } - - ifp->if_flags |= IFF_ALLMULTI; + } else { + r = vioif_set_allmulti(sc, false); + /* what to do on failure? */ + } + if (promisc) { + r = vioif_set_promisc(sc, true); + } else { + r = vioif_set_promisc(sc, false); } - -set_ifflags: - r = vioif_ifflags(sc); return r; }