NTSTATUS virtio_device_initialize(VirtIODevice *vdev, const VirtIOSystemOps *pSystemOps, PVOID DeviceContext, bool msix_used) { NTSTATUS status; RtlZeroMemory(vdev, sizeof(VirtIODevice)); vdev->DeviceContext = DeviceContext; vdev->system = pSystemOps; vdev->msix_used = msix_used; vdev->info = vdev->inline_info; vdev->maxQueues = ARRAYSIZE(vdev->inline_info); status = vio_modern_initialize(vdev); if (status == STATUS_DEVICE_NOT_CONNECTED) { /* fall back to legacy virtio device */ status = vio_legacy_initialize(vdev); } if (NT_SUCCESS(status)) { /* Always start by resetting the device */ virtio_device_reset(vdev); /* Acknowledge that we've seen the device. */ virtio_add_status(vdev, VIRTIO_CONFIG_S_ACKNOWLEDGE); /* If we are here, we must have found a driver for the device */ virtio_add_status(vdev, VIRTIO_CONFIG_S_DRIVER); } return status; }
VOID RhelShutDown( IN PVOID DeviceExtension ) { PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension; virtio_device_reset(&adaptExt->vdev); virtio_delete_queues(&adaptExt->vdev); virtio_device_shutdown(&adaptExt->vdev); adaptExt->vq = NULL; }
VOID RhelShutDown( IN PVOID DeviceExtension ) { ULONG index; PADAPTER_EXTENSION adaptExt = (PADAPTER_EXTENSION)DeviceExtension; virtio_device_reset(&adaptExt->vdev); virtio_delete_queues(&adaptExt->vdev); for (index = 0; index < adaptExt->num_queues; ++index) { adaptExt->vq[index] = NULL; } virtio_device_shutdown(&adaptExt->vdev); }
/* * To reset the device to a known state, do following: * virtio_reset(sc); // this will stop the device activity * <dequeue finished requests>; // virtio_dequeue() still can be called * <revoke pending requests in the vqs if any>; * virtio_reinit_begin(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. */ void virtio_reset(struct virtio_softc *sc) { virtio_device_reset(sc); }
static void virtio_attach(device_t parent, device_t self, void *aux) { struct virtio_softc *sc = device_private(self); struct pci_attach_args *pa = (struct pci_attach_args *)aux; pci_chipset_tag_t pc = pa->pa_pc; pcitag_t tag = pa->pa_tag; int revision; pcireg_t id; char const *intrstr; pci_intr_handle_t ih; revision = PCI_REVISION(pa->pa_class); if (revision != 0) { aprint_normal(": unknown revision 0x%02x; giving up\n", revision); return; } aprint_normal("\n"); aprint_naive("\n"); /* subsystem ID shows what I am */ id = pci_conf_read(pc, tag, PCI_SUBSYS_ID_REG); aprint_normal_dev(self, "%s Virtio %s Device (rev. 0x%02x)\n", pci_findvendor(id), (PCI_PRODUCT(id)<NDEVNAMES? virtio_device_name[PCI_PRODUCT(id)]:"Unknown"), revision); sc->sc_dev = self; sc->sc_pc = pc; sc->sc_tag = tag; sc->sc_iot = pa->pa_iot; sc->sc_dmat = pa->pa_dmat; sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI; if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_iosize)) { aprint_error_dev(self, "can't map i/o space\n"); return; } virtio_device_reset(sc); virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_ACK); virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER); /* XXX: use softc as aux... */ sc->sc_childdevid = PCI_PRODUCT(id); sc->sc_child = NULL; config_found(self, sc, NULL); if (sc->sc_child == NULL) { aprint_error_dev(self, "no matching child driver; not configured\n"); return; } if (sc->sc_child == (void*)1) { /* this shows error */ aprint_error_dev(self, "virtio configuration failed\n"); virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED); return; } if (pci_intr_map(pa, &ih)) { aprint_error_dev(self, "couldn't map interrupt\n"); virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED); return; } intrstr = pci_intr_string(pc, ih); sc->sc_ih = pci_intr_establish(pc, ih, sc->sc_ipl, virtio_intr, sc); if (sc->sc_ih == NULL) { aprint_error_dev(self, "couldn't establish interrupt"); if (intrstr != NULL) aprint_error(" at %s", intrstr); aprint_error("\n"); virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED); return; } aprint_normal_dev(self, "interrupting at %s\n", intrstr); virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK); return; }
void virtio_pci_attach(struct device *parent, struct device *self, void *aux) { struct virtio_pci_softc *sc = (struct virtio_pci_softc *)self; struct virtio_softc *vsc = &sc->sc_sc; struct pci_attach_args *pa = (struct pci_attach_args *)aux; pci_chipset_tag_t pc = pa->pa_pc; pcitag_t tag = pa->pa_tag; int revision; pcireg_t id; char const *intrstr; pci_intr_handle_t ih; revision = PCI_REVISION(pa->pa_class); if (revision != 0) { printf("unknown revision 0x%02x; giving up\n", revision); return; } /* subsystem ID shows what I am */ id = PCI_PRODUCT(pci_conf_read(pc, tag, PCI_SUBSYS_ID_REG)); printf(": Virtio %s Device", virtio_device_string(id)); #ifdef notyet if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, NULL)) printf(", msix capable"); #endif printf("\n"); vsc->sc_ops = &virtio_pci_ops; sc->sc_pc = pc; vsc->sc_dmat = pa->pa_dmat; sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI; if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0, &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_iosize, 0)) { printf("%s: can't map i/o space\n", vsc->sc_dev.dv_xname); return; } virtio_device_reset(vsc); virtio_pci_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_ACK); virtio_pci_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER); /* XXX: use softc as aux... */ vsc->sc_childdevid = id; vsc->sc_child = NULL; config_found(self, sc, NULL); if (vsc->sc_child == NULL) { printf("%s: no matching child driver; not configured\n", vsc->sc_dev.dv_xname); goto fail_1; } if (vsc->sc_child == VIRTIO_CHILD_ERROR) { printf("%s: virtio configuration failed\n", vsc->sc_dev.dv_xname); goto fail_1; } if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) { printf("%s: couldn't map interrupt\n", vsc->sc_dev.dv_xname); goto fail_2; } intrstr = pci_intr_string(pc, ih); /* * We always set the IPL_MPSAFE flag in order to do the relatively * expensive ISR read without lock, and then grab the kernel lock in * the interrupt handler. * For now, we don't support IPL_MPSAFE vq_done functions. */ KASSERT((vsc->sc_ipl & IPL_MPSAFE) == 0); sc->sc_ih = pci_intr_establish(pc, ih, vsc->sc_ipl | IPL_MPSAFE, virtio_pci_intr, sc, vsc->sc_dev.dv_xname); if (sc->sc_ih == NULL) { printf("%s: couldn't establish interrupt", vsc->sc_dev.dv_xname); if (intrstr != NULL) printf(" at %s", intrstr); printf("\n"); goto fail_2; } printf("%s: %s\n", vsc->sc_dev.dv_xname, intrstr); virtio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK); return; fail_2: config_detach(vsc->sc_child, 0); fail_1: /* no pci_mapreg_unmap() or pci_intr_unmap() */ virtio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED); }