On Sat, Jan 19, 2019 at 05:37:34PM +0100, Stefan Fritsch wrote: > Add a sc_driver_features field that is automatically used by > virtio_negotiate_features() and during reinit. > > Make virtio_negotiate_features() return an error code. Virtio 1.0 has a > special status bit for feature negotiation that means that negotiation > can fail. Make virtio_negotiate_features() return an error code instead > of the features. > > Make virtio_reinit_start() automatically call > virtio_negotiate_features(). > > Add a convenience function virtio_has_feature() to make checking bits > easier. > > Add an error check in viomb for virtio_negotiate_features because it has > some feature bits that may cause negotiation to fail. More error > checking in the child drivers is still missing.
ok mlarkin > --- > sys/dev/fdt/virtio_mmio.c | 38 ++++++++++++++++++++++++++------------ > sys/dev/pci/virtio_pci.c | 39 +++++++++++++++++++++++++++------------ > sys/dev/pv/if_vio.c | 38 +++++++++++++------------------------- > sys/dev/pv/vioblk.c | 25 +++++++++---------------- > sys/dev/pv/viocon.c | 6 +++--- > sys/dev/pv/viomb.c | 9 +++++---- > sys/dev/pv/viornd.c | 2 +- > sys/dev/pv/vioscsi.c | 2 +- > sys/dev/pv/virtio.c | 13 +++++++------ > sys/dev/pv/virtiovar.h | 15 ++++++++++++--- > sys/dev/pv/vmmci.c | 13 ++++++------- > 11 files changed, 110 insertions(+), 90 deletions(-) > > diff --git a/sys/dev/fdt/virtio_mmio.c b/sys/dev/fdt/virtio_mmio.c > index 2d7a131125d..6e09fb0e76f 100644 > --- a/sys/dev/fdt/virtio_mmio.c > +++ b/sys/dev/fdt/virtio_mmio.c > @@ -91,8 +91,8 @@ void > virtio_mmio_write_device_config_8(struct virtio_softc *, int, uint64_t); > uint16_t virtio_mmio_read_queue_size(struct virtio_softc *, uint16_t); > void virtio_mmio_setup_queue(struct virtio_softc *, struct virtqueue > *, uint64_t); > void virtio_mmio_set_status(struct virtio_softc *, int); > -uint64_t virtio_mmio_negotiate_features(struct virtio_softc *, uint64_t, > - const struct virtio_feature_name > *); > +int virtio_mmio_negotiate_features(struct virtio_softc *, > + const struct virtio_feature_name *); > int virtio_mmio_intr(void *); > > struct virtio_mmio_softc { > @@ -300,28 +300,42 @@ virtio_mmio_detach(struct device *self, int flags) > * Prints available / negotiated features if guest_feature_names != NULL and > * VIRTIO_DEBUG is 1 > */ > -uint64_t > -virtio_mmio_negotiate_features(struct virtio_softc *vsc, uint64_t > guest_features, > - const struct virtio_feature_name *guest_feature_names) > +int > +virtio_mmio_negotiate_features(struct virtio_softc *vsc, > + const struct virtio_feature_name *guest_feature_names) > { > struct virtio_mmio_softc *sc = (struct virtio_mmio_softc *)vsc; > uint64_t host, neg; > > + vsc->sc_active_features = 0; > + > /* > - * indirect descriptors can be switched off by setting bit 1 in the > - * driver flags, see config(8) > + * We enable indirect descriptors by default. They can be switched > + * off by setting bit 1 in the driver flags, see config(8). > */ > if (!(vsc->sc_dev.dv_cfdata->cf_flags & VIRTIO_CF_NO_INDIRECT) && > !(vsc->sc_child->dv_cfdata->cf_flags & VIRTIO_CF_NO_INDIRECT)) { > - guest_features |= VIRTIO_F_RING_INDIRECT_DESC; > - } else { > + vsc->sc_driver_features |= VIRTIO_F_RING_INDIRECT_DESC; > + } else if (guest_feature_names != NULL) { > printf("RingIndirectDesc disabled by UKC\n"); > } > + /* > + * The driver must add VIRTIO_F_RING_EVENT_IDX if it supports it. > + * If it did, check if it is disabled by bit 2 in the driver flags. > + */ > + if ((vsc->sc_driver_features & VIRTIO_F_RING_EVENT_IDX) && > + ((vsc->sc_dev.dv_cfdata->cf_flags & VIRTIO_CF_NO_EVENT_IDX) || > + (vsc->sc_child->dv_cfdata->cf_flags & VIRTIO_CF_NO_EVENT_IDX))) { > + if (guest_feature_names != NULL) > + printf(" RingEventIdx disabled by UKC"); > + vsc->sc_driver_features &= ~(VIRTIO_F_RING_EVENT_IDX); > + } > + > bus_space_write_4(sc->sc_iot, sc->sc_ioh, > VIRTIO_MMIO_HOST_FEATURES_SEL, 0); > host = bus_space_read_4(sc->sc_iot, sc->sc_ioh, > VIRTIO_MMIO_HOST_FEATURES); > - neg = host & guest_features; > + neg = host & vsc->sc_driver_features; > #if VIRTIO_DEBUG > if (guest_feature_names) > virtio_log_features(host, neg, guest_feature_names); > @@ -330,13 +344,13 @@ virtio_mmio_negotiate_features(struct virtio_softc > *vsc, uint64_t guest_features > VIRTIO_MMIO_GUEST_FEATURES_SEL, 0); > bus_space_write_4(sc->sc_iot, sc->sc_ioh, > VIRTIO_MMIO_GUEST_FEATURES, neg); > - vsc->sc_features = neg; > + vsc->sc_active_features = neg; > if (neg & VIRTIO_F_RING_INDIRECT_DESC) > vsc->sc_indirect = 1; > else > vsc->sc_indirect = 0; > > - return neg; > + return 0; > } > > /* > diff --git a/sys/dev/pci/virtio_pci.c b/sys/dev/pci/virtio_pci.c > index 7be93684a68..f370f513e85 100644 > --- a/sys/dev/pci/virtio_pci.c > +++ b/sys/dev/pci/virtio_pci.c > @@ -67,8 +67,8 @@ void virtio_pci_write_device_config_8(struct > virtio_softc *, int, uint64_t); > uint16_t virtio_pci_read_queue_size(struct virtio_softc *, uint16_t); > void virtio_pci_setup_queue(struct virtio_softc *, struct virtqueue > *, uint64_t); > void virtio_pci_set_status(struct virtio_softc *, int); > -uint64_t virtio_pci_negotiate_features(struct virtio_softc *, uint64_t, > - const struct virtio_feature_name > *); > +int virtio_pci_negotiate_features(struct virtio_softc *, > + const struct virtio_feature_name *); > void virtio_pci_set_msix_queue_vector(struct virtio_pci_softc *, > uint32_t, uint16_t); > void virtio_pci_set_msix_config_vector(struct virtio_pci_softc *, > uint16_t); > int virtio_pci_msix_establish(struct virtio_pci_softc *, struct > pci_attach_args *, int, int (*)(void *), void *); > @@ -374,39 +374,54 @@ virtio_pci_adjust_config_region(struct virtio_pci_softc > *sc) > * Prints available / negotiated features if guest_feature_names != NULL and > * VIRTIO_DEBUG is 1 > */ > -uint64_t > -virtio_pci_negotiate_features(struct virtio_softc *vsc, uint64_t > guest_features, > +int > +virtio_pci_negotiate_features(struct virtio_softc *vsc, > const struct virtio_feature_name *guest_feature_names) > { > struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc; > uint64_t host, neg; > > + vsc->sc_active_features = 0; > + > /* > - * indirect descriptors can be switched off by setting bit 1 in the > - * driver flags, see config(8) > + * We enable indirect descriptors by default. They can be switched > + * off by setting bit 1 in the driver flags, see config(8) > */ > if (!(vsc->sc_dev.dv_cfdata->cf_flags & VIRTIO_CF_NO_INDIRECT) && > !(vsc->sc_child->dv_cfdata->cf_flags & VIRTIO_CF_NO_INDIRECT)) { > - guest_features |= VIRTIO_F_RING_INDIRECT_DESC; > - } else { > - printf("RingIndirectDesc disabled by UKC\n"); > + vsc->sc_driver_features |= VIRTIO_F_RING_INDIRECT_DESC; > + } else if (guest_feature_names != NULL) { > + printf(" RingIndirectDesc disabled by UKC"); > + } > + > + /* > + * The driver must add VIRTIO_F_RING_EVENT_IDX if it supports it. > + * If it did, check if it is disabled by bit 2 in the driver flags. > + */ > + if ((vsc->sc_driver_features & VIRTIO_F_RING_EVENT_IDX) && > + ((vsc->sc_dev.dv_cfdata->cf_flags & VIRTIO_CF_NO_EVENT_IDX) || > + (vsc->sc_child->dv_cfdata->cf_flags & VIRTIO_CF_NO_EVENT_IDX))) { > + if (guest_feature_names != NULL) > + printf(" RingEventIdx disabled by UKC"); > + vsc->sc_driver_features &= ~(VIRTIO_F_RING_EVENT_IDX); > } > + > host = bus_space_read_4(sc->sc_iot, sc->sc_ioh, > VIRTIO_CONFIG_DEVICE_FEATURES); > - neg = host & guest_features; > + neg = host & vsc->sc_driver_features; > #if VIRTIO_DEBUG > if (guest_feature_names) > virtio_log_features(host, neg, guest_feature_names); > #endif > bus_space_write_4(sc->sc_iot, sc->sc_ioh, > VIRTIO_CONFIG_GUEST_FEATURES, neg); > - vsc->sc_features = neg; > + vsc->sc_active_features = neg; > if (neg & VIRTIO_F_RING_INDIRECT_DESC) > vsc->sc_indirect = 1; > else > vsc->sc_indirect = 0; > > - return neg; > + return 0; > } > > /* > diff --git a/sys/dev/pv/if_vio.c b/sys/dev/pv/if_vio.c > index bfc7cfd1ddc..252ad2fdf9b 100644 > --- a/sys/dev/pv/if_vio.c > +++ b/sys/dev/pv/if_vio.c > @@ -515,7 +515,6 @@ vio_attach(struct device *parent, struct device *self, > void *aux) > { > struct vio_softc *sc = (struct vio_softc *)self; > struct virtio_softc *vsc = (struct virtio_softc *)parent; > - uint64_t features; > int i; > struct ifnet *ifp = &sc->sc_ac.ac_if; > > @@ -531,23 +530,13 @@ vio_attach(struct device *parent, struct device *self, > void *aux) > vsc->sc_ipl = IPL_NET; > vsc->sc_vqs = &sc->sc_vq[0]; > vsc->sc_config_change = 0; > - > - features = VIRTIO_NET_F_MAC | VIRTIO_NET_F_STATUS | > + vsc->sc_driver_features = VIRTIO_NET_F_MAC | VIRTIO_NET_F_STATUS | > VIRTIO_NET_F_CTRL_VQ | VIRTIO_NET_F_CTRL_RX | > - VIRTIO_NET_F_MRG_RXBUF | VIRTIO_NET_F_CSUM; > - /* > - * VIRTIO_F_RING_EVENT_IDX can be switched off by setting bit 2 in the > - * driver flags, see config(8) > - */ > - if (!(sc->sc_dev.dv_cfdata->cf_flags & VIRTIO_CF_NO_EVENT_IDX) && > - !(vsc->sc_dev.dv_cfdata->cf_flags & VIRTIO_CF_NO_EVENT_IDX)) > - features |= VIRTIO_F_RING_EVENT_IDX; > - else > - printf(": RingEventIdx disabled by UKC"); > + VIRTIO_NET_F_MRG_RXBUF | VIRTIO_NET_F_CSUM | > + VIRTIO_F_RING_EVENT_IDX; > > - features = virtio_negotiate_features(vsc, features, > - virtio_net_feature_names); > - if (features & VIRTIO_NET_F_MAC) { > + virtio_negotiate_features(vsc, virtio_net_feature_names); > + if (virtio_has_feature(vsc, VIRTIO_NET_F_MAC)) { > vio_get_lladr(&sc->sc_ac, vsc); > } else { > ether_fakeaddr(ifp); > @@ -555,7 +544,7 @@ vio_attach(struct device *parent, struct device *self, > void *aux) > } > printf(": address %s\n", ether_sprintf(sc->sc_ac.ac_enaddr)); > > - if (features & VIRTIO_NET_F_MRG_RXBUF) { > + if (virtio_has_feature(vsc, VIRTIO_NET_F_MRG_RXBUF)) { > sc->sc_hdr_size = sizeof(struct virtio_net_hdr); > ifp->if_hardmtu = 16000; /* arbitrary limit */ > } else { > @@ -575,12 +564,12 @@ vio_attach(struct device *parent, struct device *self, > void *aux) > vsc->sc_nvqs = 2; > sc->sc_vq[VQTX].vq_done = vio_tx_intr; > virtio_start_vq_intr(vsc, &sc->sc_vq[VQRX]); > - if (features & VIRTIO_F_RING_EVENT_IDX) > + if (virtio_has_feature(vsc, VIRTIO_F_RING_EVENT_IDX)) > virtio_postpone_intr_far(&sc->sc_vq[VQTX]); > else > virtio_stop_vq_intr(vsc, &sc->sc_vq[VQTX]); > - if ((features & VIRTIO_NET_F_CTRL_VQ) > - && (features & VIRTIO_NET_F_CTRL_RX)) { > + if (virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_VQ) > + && virtio_has_feature(vsc, VIRTIO_NET_F_CTRL_RX)) { > if (virtio_alloc_vq(vsc, &sc->sc_vq[VQCTL], 2, NBPG, 1, > "control") == 0) { > sc->sc_vq[VQCTL].vq_done = vio_ctrleof; > @@ -598,7 +587,7 @@ vio_attach(struct device *parent, struct device *self, > void *aux) > ifp->if_start = vio_start; > ifp->if_ioctl = vio_ioctl; > ifp->if_capabilities = IFCAP_VLAN_MTU; > - if (features & VIRTIO_NET_F_CSUM) > + if (virtio_has_feature(vsc, VIRTIO_NET_F_CSUM)) > ifp->if_capabilities |= IFCAP_CSUM_TCPv4|IFCAP_CSUM_UDPv4; > IFQ_SET_MAXLEN(&ifp->if_snd, vsc->sc_vqs[1].vq_num - 1); > ifmedia_init(&sc->sc_media, 0, vio_media_change, vio_media_status); > @@ -629,7 +618,7 @@ vio_link_state(struct ifnet *ifp) > struct virtio_softc *vsc = sc->sc_virtio; > int link_state = LINK_STATE_FULL_DUPLEX; > > - if (vsc->sc_features & VIRTIO_NET_F_STATUS) { > + if (virtio_has_feature(vsc, VIRTIO_NET_F_STATUS)) { > int status = virtio_read_device_config_2(vsc, > VIRTIO_NET_CONFIG_STATUS); > if (!(status & VIRTIO_NET_S_LINK_UP)) > @@ -706,7 +695,6 @@ vio_stop(struct ifnet *ifp, int disable) > vio_rx_drain(sc); > > virtio_reinit_start(vsc); > - virtio_negotiate_features(vsc, vsc->sc_features, NULL); > virtio_start_vq_intr(vsc, &sc->sc_vq[VQRX]); > virtio_stop_vq_intr(vsc, &sc->sc_vq[VQTX]); > if (vsc->sc_nvqs >= 3) > @@ -815,7 +803,7 @@ again: > } > if (ifq_is_oactive(&ifp->if_snd)) { > int r; > - if (vsc->sc_features & VIRTIO_F_RING_EVENT_IDX) > + if (virtio_has_feature(vsc, VIRTIO_F_RING_EVENT_IDX)) > r = virtio_postpone_intr_smart(&sc->sc_vq[VQTX]); > else > r = virtio_start_vq_intr(vsc, &sc->sc_vq[VQTX]); > @@ -1069,7 +1057,7 @@ again: > if (r) { > vio_populate_rx_mbufs(sc); > /* set used event index to the next slot */ > - if (vsc->sc_features & VIRTIO_F_RING_EVENT_IDX) { > + if (virtio_has_feature(vsc, VIRTIO_F_RING_EVENT_IDX)) { > if (virtio_start_vq_intr(vq->vq_owner, vq)) > goto again; > } > diff --git a/sys/dev/pv/vioblk.c b/sys/dev/pv/vioblk.c > index 460c2dfa766..9fc6e82f89e 100644 > --- a/sys/dev/pv/vioblk.c > +++ b/sys/dev/pv/vioblk.c > @@ -171,7 +171,6 @@ vioblk_attach(struct device *parent, struct device *self, > void *aux) > struct vioblk_softc *sc = (struct vioblk_softc *)self; > struct virtio_softc *vsc = (struct virtio_softc *)parent; > struct scsibus_attach_args saa; > - uint64_t features; > int qsize; > > vsc->sc_vqs = &sc->sc_vq[0]; > @@ -182,15 +181,12 @@ vioblk_attach(struct device *parent, struct device > *self, void *aux) > vsc->sc_child = self; > vsc->sc_ipl = IPL_BIO; > sc->sc_virtio = vsc; > + vsc->sc_driver_features = VIRTIO_BLK_F_RO | VIRTIO_F_NOTIFY_ON_EMPTY | > + VIRTIO_BLK_F_SIZE_MAX | VIRTIO_BLK_F_SEG_MAX | VIRTIO_BLK_F_FLUSH; > > - features = virtio_negotiate_features(vsc, > - (VIRTIO_BLK_F_RO | VIRTIO_F_NOTIFY_ON_EMPTY | > - VIRTIO_BLK_F_SIZE_MAX | VIRTIO_BLK_F_SEG_MAX | > - VIRTIO_BLK_F_FLUSH), > - vioblk_feature_names); > + virtio_negotiate_features(vsc, vioblk_feature_names); > > - > - if (features & VIRTIO_BLK_F_SIZE_MAX) { > + if (virtio_has_feature(vsc, VIRTIO_BLK_F_SIZE_MAX)) { > uint32_t size_max = virtio_read_device_config_4(vsc, > VIRTIO_BLK_CONFIG_SIZE_MAX); > if (size_max < PAGE_SIZE) { > @@ -199,7 +195,7 @@ vioblk_attach(struct device *parent, struct device *self, > void *aux) > } > } > > - if (features & VIRTIO_BLK_F_SEG_MAX) { > + if (virtio_has_feature(vsc, VIRTIO_BLK_F_SEG_MAX)) { > uint32_t seg_max = virtio_read_device_config_4(vsc, > VIRTIO_BLK_CONFIG_SEG_MAX); > if (seg_max < SEG_MAX) { > @@ -220,7 +216,7 @@ vioblk_attach(struct device *parent, struct device *self, > void *aux) > qsize = sc->sc_vq[0].vq_num; > sc->sc_vq[0].vq_done = vioblk_vq_done; > > - if (features & VIRTIO_F_NOTIFY_ON_EMPTY) { > + if (virtio_has_feature(vsc, VIRTIO_F_NOTIFY_ON_EMPTY)) { > virtio_stop_vq_intr(vsc, &sc->sc_vq[0]); > sc->sc_notify_on_empty = 1; > } > @@ -252,7 +248,7 @@ vioblk_attach(struct device *parent, struct device *self, > void *aux) > sc->sc_link.luns = 1; > sc->sc_link.adapter_target = 2; > DNPRINTF(1, "%s: qsize: %d\n", __func__, qsize); > - if (features & VIRTIO_BLK_F_RO) > + if (virtio_has_feature(vsc, VIRTIO_BLK_F_RO)) > sc->sc_link.flags |= SDEV_READONLY; > > bzero(&saa, sizeof(saa)); > @@ -430,7 +426,7 @@ vioblk_scsi_cmd(struct scsi_xfer *xs) > break; > > case SYNCHRONIZE_CACHE: > - if ((vsc->sc_features & VIRTIO_BLK_F_FLUSH) == 0) { > + if (!virtio_has_feature(vsc, VIRTIO_BLK_F_FLUSH)) { > vioblk_scsi_done(xs, XS_NOERROR); > return; > } > @@ -553,13 +549,10 @@ vioblk_scsi_cmd(struct scsi_xfer *xs) > delay(1000); > } while(--timeout > 0); > if (timeout <= 0) { > - uint32_t features; > printf("%s: SCSI_POLL timed out\n", __func__); > vioblk_reset(sc); > virtio_reinit_start(vsc); > - features = virtio_negotiate_features(vsc, vsc->sc_features, > - NULL); > - KASSERT(features == vsc->sc_features); > + virtio_reinit_end(vsc); > } > splx(s); > return; > diff --git a/sys/dev/pv/viocon.c b/sys/dev/pv/viocon.c > index ed73152bbdd..a47eae33d39 100644 > --- a/sys/dev/pv/viocon.c > +++ b/sys/dev/pv/viocon.c > @@ -193,8 +193,8 @@ viocon_attach(struct device *parent, struct device *self, > void *aux) > goto err; > } > > - virtio_negotiate_features(vsc, VIRTIO_CONSOLE_F_SIZE, > - viocon_feature_names); > + vsc->sc_driver_features = VIRTIO_CONSOLE_F_SIZE; > + virtio_negotiate_features(vsc, viocon_feature_names); > > printf("\n"); > DPRINTF("%s: softc: %p\n", __func__, sc); > @@ -277,7 +277,7 @@ viocon_port_create(struct viocon_softc *sc, int portidx) > */ > vp->vp_tx_buf = vp->vp_rx_buf + vp->vp_rx->vq_num * BUFSIZE; > > - if (vsc->sc_features & VIRTIO_CONSOLE_F_SIZE) { > + if (virtio_has_feature(vsc, VIRTIO_CONSOLE_F_SIZE)) { > vp->vp_cols = virtio_read_device_config_2(vsc, > VIRTIO_CONSOLE_COLS); > vp->vp_rows = virtio_read_device_config_2(vsc, > diff --git a/sys/dev/pv/viomb.c b/sys/dev/pv/viomb.c > index 3be83eed562..71e92abf8a4 100644 > --- a/sys/dev/pv/viomb.c > +++ b/sys/dev/pv/viomb.c > @@ -158,8 +158,9 @@ viomb_attach(struct device *parent, struct device *self, > void *aux) > vsc->sc_ipl = IPL_BIO; > vsc->sc_config_change = viomb_config_change; > > - virtio_negotiate_features(vsc, VIRTIO_BALLOON_F_MUST_TELL_HOST, > - viomb_feature_names); > + vsc->sc_driver_features = VIRTIO_BALLOON_F_MUST_TELL_HOST; > + if (virtio_negotiate_features(vsc, viomb_feature_names) != 0) > + goto err; > > if ((virtio_alloc_vq(vsc, &sc->sc_vq[VQ_INFLATE], VQ_INFLATE, > sizeof(u_int32_t) * PGS_PER_REQ, 1, "inflate") != 0)) > @@ -365,7 +366,7 @@ viomb_deflate(struct viomb_softc *sc) > virtio_enqueue_p(vq, slot, b->bl_dmamap, 0, > sizeof(u_int32_t) * nvpages, VRING_READ); > > - if (!(vsc->sc_features & VIRTIO_BALLOON_F_MUST_TELL_HOST)) > + if (!virtio_has_feature(vsc, VIRTIO_BALLOON_F_MUST_TELL_HOST)) > uvm_pglistfree(&b->bl_pglist); > virtio_enqueue_commit(vsc, vq, slot, VRING_NOTIFY); > return; > @@ -463,7 +464,7 @@ viomb_deflate_intr(struct virtqueue *vq) > sizeof(u_int32_t) * nvpages, > BUS_DMASYNC_POSTWRITE); > > - if (vsc->sc_features & VIRTIO_BALLOON_F_MUST_TELL_HOST) > + if (virtio_has_feature(vsc, VIRTIO_BALLOON_F_MUST_TELL_HOST)) > uvm_pglistfree(&b->bl_pglist); > > VIOMBDEBUG(sc, "updating sc->sc_actual from %u to %llu\n", > diff --git a/sys/dev/pv/viornd.c b/sys/dev/pv/viornd.c > index 9d1e8c60938..0886d052310 100644 > --- a/sys/dev/pv/viornd.c > +++ b/sys/dev/pv/viornd.c > @@ -96,7 +96,7 @@ viornd_attach(struct device *parent, struct device *self, > void *aux) > vsc->sc_ipl = IPL_NET; > sc->sc_virtio = vsc; > > - virtio_negotiate_features(vsc, 0, NULL); > + virtio_negotiate_features(vsc, NULL); > > if (sc->sc_dev.dv_cfdata->cf_flags & VIORND_ONESHOT) { > sc->sc_interval = 0; > diff --git a/sys/dev/pv/vioscsi.c b/sys/dev/pv/vioscsi.c > index a7ccd8913b3..ad18ec151ec 100644 > --- a/sys/dev/pv/vioscsi.c > +++ b/sys/dev/pv/vioscsi.c > @@ -126,7 +126,7 @@ vioscsi_attach(struct device *parent, struct device > *self, void *aux) > vsc->sc_vqs = sc->sc_vqs; > vsc->sc_nvqs = nitems(sc->sc_vqs); > > - virtio_negotiate_features(vsc, 0, NULL); > + virtio_negotiate_features(vsc, NULL); > uint32_t cmd_per_lun = virtio_read_device_config_4(vsc, > VIRTIO_SCSI_CONFIG_CMD_PER_LUN); > uint32_t seg_max = virtio_read_device_config_4(vsc, > diff --git a/sys/dev/pv/virtio.c b/sys/dev/pv/virtio.c > index 40ea0b8a85e..904943420e0 100644 > --- a/sys/dev/pv/virtio.c > +++ b/sys/dev/pv/virtio.c > @@ -126,15 +126,15 @@ virtio_log_features(uint64_t host, uint64_t neg, > * <dequeue finished requests>; // virtio_dequeue() still can be called > * <revoke pending requests in the vqs if any>; > * virtio_reinit_start(sc); // dequeue prohibitted > - * newfeatures = virtio_negotiate_features(sc, requestedfeatures); > * <some other initialization>; > * virtio_reinit_end(sc); // device activated; enqueue allowed > - * Once attached, feature negotiation can only be allowed after virtio_reset. > + * Once attached, features are assumed to not change again. > */ > void > virtio_reset(struct virtio_softc *sc) > { > virtio_device_reset(sc); > + sc->sc_active_features = 0; > } > > void > @@ -144,6 +144,7 @@ virtio_reinit_start(struct virtio_softc *sc) > > virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_ACK); > virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER); > + virtio_negotiate_features(sc, NULL); > for (i = 0; i < sc->sc_nvqs; i++) { > int n; > struct virtqueue *vq = &sc->sc_vqs[i]; > @@ -300,7 +301,7 @@ virtio_alloc_vq(struct virtio_softc *sc, struct virtqueue > *vq, int index, > if (((vq_size - 1) & vq_size) != 0) > panic("vq_size not power of two: %d", vq_size); > > - hdrlen = (sc->sc_features & VIRTIO_F_RING_EVENT_IDX) ? 3 : 2; > + hdrlen = virtio_has_feature(sc, VIRTIO_F_RING_EVENT_IDX) ? 3 : 2; > > /* allocsize1: descriptor table + avail ring + pad */ > allocsize1 = VIRTQUEUE_ALIGN(sizeof(struct vring_desc) * vq_size > @@ -677,7 +678,7 @@ virtio_enqueue_commit(struct virtio_softc *sc, struct > virtqueue *vq, int slot, > > notify: > if (notifynow) { > - if (vq->vq_owner->sc_features & VIRTIO_F_RING_EVENT_IDX) { > + if (virtio_has_feature(vq->vq_owner, VIRTIO_F_RING_EVENT_IDX)) { > uint16_t o = vq->vq_avail->idx; > uint16_t n = vq->vq_avail_idx; > uint16_t t; > @@ -874,7 +875,7 @@ virtio_postpone_intr_far(struct virtqueue *vq) > void > virtio_stop_vq_intr(struct virtio_softc *sc, struct virtqueue *vq) > { > - if ((sc->sc_features & VIRTIO_F_RING_EVENT_IDX)) { > + if (virtio_has_feature(sc, VIRTIO_F_RING_EVENT_IDX)) { > /* > * No way to disable the interrupt completely with > * RingEventIdx. Instead advance used_event by half > @@ -898,7 +899,7 @@ virtio_start_vq_intr(struct virtio_softc *sc, struct > virtqueue *vq) > * interrupts is done through setting the latest > * consumed index in the used_event field > */ > - if (sc->sc_features & VIRTIO_F_RING_EVENT_IDX) > + if (virtio_has_feature(sc, VIRTIO_F_RING_EVENT_IDX)) > VQ_USED_EVENT(vq) = vq->vq_used_idx; > else > vq->vq_avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; > diff --git a/sys/dev/pv/virtiovar.h b/sys/dev/pv/virtiovar.h > index 4a52907a4a5..2b43086a4e9 100644 > --- a/sys/dev/pv/virtiovar.h > +++ b/sys/dev/pv/virtiovar.h > @@ -151,7 +151,7 @@ struct virtio_ops { > uint16_t (*read_queue_size)(struct virtio_softc *, uint16_t); > void (*setup_queue)(struct virtio_softc *, struct virtqueue > *, uint64_t); > void (*set_status)(struct virtio_softc *, int); > - uint64_t (*neg_features)(struct virtio_softc *, uint64_t, const > struct virtio_feature_name *); > + int (*neg_features)(struct virtio_softc *, const struct > virtio_feature_name *); > int (*poll_intr)(void *); > }; > > @@ -164,7 +164,8 @@ struct virtio_softc { > > int sc_ipl; /* set by child */ > > - uint64_t sc_features; > + uint64_t sc_driver_features; > + uint64_t sc_active_features; > int sc_indirect; > > int sc_nvqs; /* set by child */ > @@ -189,13 +190,21 @@ struct virtio_softc { > #define virtio_write_device_config_8(sc, o, v) > (sc)->sc_ops->write_dev_cfg_8(sc, o, v) > #define virtio_read_queue_size(sc, i) > (sc)->sc_ops->read_queue_size(sc, i) > #define virtio_setup_queue(sc, i, v) > (sc)->sc_ops->setup_queue(sc, i, v) > -#define virtio_negotiate_features(sc, f, n) > (sc)->sc_ops->neg_features(sc, f, n) > +#define virtio_negotiate_features(sc, n) > (sc)->sc_ops->neg_features(sc, n) > #define virtio_poll_intr(sc) > (sc)->sc_ops->poll_intr(sc) > > /* only for transport drivers */ > #define virtio_set_status(sc, i) > (sc)->sc_ops->set_status(sc, i) > #define virtio_device_reset(sc) virtio_set_status((sc), > 0) > > +static inline int > +virtio_has_feature(struct virtio_softc *sc, unsigned int fbit) > +{ > + if (sc->sc_active_features & fbit) > + return 1; > + return 0; > +} > + > int virtio_alloc_vq(struct virtio_softc*, struct virtqueue*, int, int, int, > const char*); > int virtio_free_vq(struct virtio_softc*, struct virtqueue*); > diff --git a/sys/dev/pv/vmmci.c b/sys/dev/pv/vmmci.c > index 80ba1224e3b..2313b11c71e 100644 > --- a/sys/dev/pv/vmmci.c > +++ b/sys/dev/pv/vmmci.c > @@ -94,7 +94,6 @@ vmmci_attach(struct device *parent, struct device *self, > void *aux) > { > struct vmmci_softc *sc = (struct vmmci_softc *)self; > struct virtio_softc *vsc = (struct virtio_softc *)parent; > - uint64_t features; > > if (vsc->sc_child != NULL) > panic("already attached to something else"); > @@ -105,10 +104,11 @@ vmmci_attach(struct device *parent, struct device > *self, void *aux) > vsc->sc_ipl = IPL_NET; > sc->sc_virtio = vsc; > > - features = VMMCI_F_TIMESYNC | VMMCI_F_ACK | VMMCI_F_SYNCRTC; > - features = virtio_negotiate_features(vsc, features, NULL); > + vsc->sc_driver_features = VMMCI_F_TIMESYNC | VMMCI_F_ACK | > + VMMCI_F_SYNCRTC; > + virtio_negotiate_features(vsc, NULL); > > - if (features & VMMCI_F_TIMESYNC) { > + if (virtio_has_feature(vsc, VMMCI_F_TIMESYNC)) { > strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, > sizeof(sc->sc_sensordev.xname)); > sc->sc_sensor.type = SENSOR_TIMEDELTA; > @@ -128,7 +128,7 @@ vmmci_activate(struct device *self, int act) > struct vmmci_softc *sc = (struct vmmci_softc *)self; > struct virtio_softc *vsc = sc->sc_virtio; > > - if ((vsc->sc_features & VMMCI_F_ACK) == 0) > + if (virtio_has_feature(vsc, VMMCI_F_ACK) == 0) > return (0); > > switch (act) { > @@ -183,8 +183,7 @@ vmmci_config_change(struct virtio_softc *vsc) > break; > } > > - if ((cmd != VMMCI_NONE) && > - (vsc->sc_features & VMMCI_F_ACK)) > + if ((cmd != VMMCI_NONE) && virtio_has_feature(vsc, VMMCI_F_ACK)) > virtio_write_device_config_4(vsc, VMMCI_CONFIG_COMMAND, cmd); > > return (1); > -- > 2.19.0 >