Index: usr.sbin/bhyve/pci_nvme.c =================================================================== --- usr.sbin/bhyve/pci_nvme.c +++ usr.sbin/bhyve/pci_nvme.c @@ -356,6 +356,10 @@ struct nvme_feature_obj *, struct nvme_command *, struct nvme_completion *); +static void nvme_feature_iv_config(struct pci_nvme_softc *, + struct nvme_feature_obj *, + struct nvme_command *, + struct nvme_completion *); static __inline void cpywithpad(char *dst, size_t dst_size, const char *src, char pad) @@ -612,6 +616,8 @@ sc->feat[NVME_FEAT_LBA_RANGE_TYPE].namespace_specific = true; sc->feat[NVME_FEAT_ERROR_RECOVERY].namespace_specific = true; sc->feat[NVME_FEAT_NUMBER_OF_QUEUES].set = nvme_feature_num_queues; + sc->feat[NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION].set = + nvme_feature_iv_config; } static void @@ -1276,6 +1282,39 @@ } static void +nvme_feature_iv_config(struct pci_nvme_softc *sc, + struct nvme_feature_obj *feat, + struct nvme_command *command, + struct nvme_completion *compl) +{ + uint32_t i; + uint32_t cdw11 = command->cdw11; + uint16_t iv; + bool cd; + + pci_nvme_status_genc(&compl->status, NVME_SC_INVALID_FIELD); + + iv = cdw11 & 0xffff; + cd = cdw11 & (1 << 16); + + if (iv > (sc->max_queues + 1)) { + return; + } + + /* No Interrupt Coalescing (i.e. not Coalescing Disable) for Admin Q */ + if ((iv == 0) && !cd) + return; + + /* Requested Interrupt Vector must be used by a CQ */ + for (i = 0; i < sc->num_cqueues + 1; i++) { + if (sc->compl_queues[i].intr_vec == iv) { + pci_nvme_status_genc(&compl->status, NVME_SC_SUCCESS); + } + } + +} + +static void nvme_feature_num_queues(struct pci_nvme_softc *sc, struct nvme_feature_obj *feat, struct nvme_command *command,