From 56f65ed838e8d73e91d54a8ed984d777c936843c Mon Sep 17 00:00:00 2001 From: Olivier Martin Date: Wed, 11 Dec 2013 16:58:22 +0000 Subject: OvmfPkg: Make the VirtIo devices use the new VIRTIO_DEVICE_PROTOCOL This change replaces the accesses to the PCI bus from the Block, Scsi and Net drivers by the use of the new VIRTIO_DEVICE_PROTOCOL protocol that abstracts the transport layer. It means these drivers can be used on PCI and MMIO transport layer. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Olivier Martin v5: - VirtioFlush(): update comment block in VirtioLib.[hc]; error code is propagated from VirtIo->SetQueueNotify(). - VirtioBlkInit(): jump to Failed label if SetPageSize() fails - VirtioBlkInit(): fixup comment, and add error handling, near SetQueueNum() call - VirtioBlkDriverBindingStart(): remove redundant (always false) check for a subsystem device ID different from VIRTIO_SUBSYSTEM_BLOCK_DEVICE; VirtioBlkDriverBindingSupported() handles it already - VirtioNetGetFeatures(): update stale comment block - VirtioNetGetFeatures(): retrieve MAC address byte for byte (open-coded loop) - VirtioNetDriverBindingStart(): remove redundant (always false) check for a subsystem device ID different from VIRTIO_SUBSYSTEM_NETWORK_CARD; VirtioNetDriverBindingSupported() handles it already - VirtioNetInitRing(): call SetQueueNum() and SetQueueAlign() for proper MMIO operation - VirtioNetInitialize(): fix destination error label for when SetPageSize() fails - VirtioScsi.c: fix comment block of VIRTIO_CFG_WRITE()/VIRTIO_CFG_READ() - VirtioScsiInit(): fix destination error label for when SetPageSize() fails - VirtioScsiInit(): call SetQueueNum() and SetQueueAlign() for proper MMIO operation Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Laszlo Ersek Reviewed-by: Jordan Justen git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@14966 6f19259b-4bc3-4df7-8a09-765794883524 --- OvmfPkg/VirtioBlkDxe/VirtioBlk.c | 180 +++++++++++++++---------------------- OvmfPkg/VirtioBlkDxe/VirtioBlk.h | 32 +++---- OvmfPkg/VirtioBlkDxe/VirtioBlk.inf | 4 +- 3 files changed, 87 insertions(+), 129 deletions(-) (limited to 'OvmfPkg/VirtioBlkDxe') diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c index 17b9f71d63..f09b0d1118 100644 --- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.c +++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.c @@ -23,7 +23,6 @@ **/ -#include #include #include #include @@ -37,14 +36,14 @@ /** Convenience macros to read and write region 0 IO space elements of the - virtio-blk PCI device, for configuration purposes. + virtio-blk device, for configuration purposes. The following macros make it possible to specify only the "core parameters" for such accesses and to derive the rest. By the time VIRTIO_CFG_WRITE() returns, the transaction will have been completed. - @param[in] Dev Pointer to the VBLK_DEV structure whose PCI IO space - we're accessing. Dev->PciIo must be valid. + @param[in] Dev Pointer to the VBLK_DEV structure whose VirtIo space + we're accessing. Dev->VirtIo must be valid. @param[in] Field A field name from VBLK_HDR, identifying the virtio-blk configuration item to access. @@ -57,19 +56,19 @@ one of UINT8, UINT16, UINT32, UINT64. - @return Status code returned by VirtioWrite() / VirtioRead(). + @return Status code returned by VirtioWriteDevice() / VirtioReadDevice(). **/ -#define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWrite ( \ - (Dev)->PciIo, \ +#define VIRTIO_CFG_WRITE(Dev, Field, Value) (VirtioWriteDevice ( \ + (Dev)->VirtIo, \ OFFSET_OF_VBLK (Field), \ SIZE_OF_VBLK (Field), \ (Value) \ )) -#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioRead ( \ - (Dev)->PciIo, \ +#define VIRTIO_CFG_READ(Dev, Field, Pointer) (VirtioReadDevice ( \ + (Dev)->VirtIo, \ OFFSET_OF_VBLK (Field), \ SIZE_OF_VBLK (Field), \ sizeof *(Pointer), \ @@ -229,7 +228,7 @@ VerifyReadWriteRequest ( @retval EFI_SUCCESS Transfer complete. - @retval EFI_DEVICE_ERROR Failed to notify host side via PCI write, or + @retval EFI_DEVICE_ERROR Failed to notify host side via VirtIo write, or unable to parse host response, or host response is not VIRTIO_BLK_S_OK. @@ -324,7 +323,7 @@ SynchronousRequest ( // // virtio-blk's only virtqueue is #0, called "requestq" (see Appendix D). // - if (VirtioFlush (Dev->PciIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS && + if (VirtioFlush (Dev->VirtIo, 0, &Dev->Ring, &Indices) == EFI_SUCCESS && HostStatus == VIRTIO_BLK_S_OK) { return EFI_SUCCESS; } @@ -500,11 +499,6 @@ VirtioBlkFlushBlocks ( underlying device - 9 Driver Binding Protocol -- for exporting ourselves - Specs relevant in the specific sense: - - UEFI Spec 2.3.1 + Errata C, 13.4 EFI PCI I/O Protocol - - Driver Writer's Guide for UEFI 2.3.1 v1.01, 18 PCI Driver Design - Guidelines, 18.3 PCI drivers. - @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object incorporating this driver (independently of any device). @@ -516,11 +510,11 @@ VirtioBlkFlushBlocks ( @retval EFI_SUCCESS The driver supports the device being probed. - @retval EFI_UNSUPPORTED Based on virtio-blk PCI discovery, we do not support + @retval EFI_UNSUPPORTED Based on virtio-blk discovery, we do not support the device. @return Error codes from the OpenProtocol() boot service or - the PciIo protocol. + the VirtIo protocol. **/ @@ -533,56 +527,36 @@ VirtioBlkDriverBindingSupported ( ) { EFI_STATUS Status; - EFI_PCI_IO_PROTOCOL *PciIo; - PCI_TYPE00 Pci; + VIRTIO_DEVICE_PROTOCOL *VirtIo; // - // Attempt to open the device with the PciIo set of interfaces. On success, - // the protocol is "instantiated" for the PCI device. Covers duplicate open + // Attempt to open the device with the VirtIo set of interfaces. On success, + // the protocol is "instantiated" for the VirtIo device. Covers duplicate open // attempts (EFI_ALREADY_STARTED). // Status = gBS->OpenProtocol ( DeviceHandle, // candidate device - &gEfiPciIoProtocolGuid, // for generic PCI access - (VOID **)&PciIo, // handle to instantiate + &gVirtioDeviceProtocolGuid, // for generic VirtIo access + (VOID **)&VirtIo, // handle to instantiate This->DriverBindingHandle, // requestor driver identity DeviceHandle, // ControllerHandle, according to // the UEFI Driver Model - EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive PciIo access to + EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to // the device; to be released ); if (EFI_ERROR (Status)) { return Status; } - // - // Read entire PCI configuration header for more extensive check ahead. - // - Status = PciIo->Pci.Read ( - PciIo, // (protocol, device) - // handle - EfiPciIoWidthUint32, // access width & copy - // mode - 0, // Offset - sizeof Pci / sizeof (UINT32), // Count - &Pci // target buffer - ); - - if (Status == EFI_SUCCESS) { - // - // virtio-0.9.5, 2.1 PCI Discovery - // - Status = (Pci.Hdr.VendorId == 0x1AF4 && - Pci.Hdr.DeviceId >= 0x1000 && Pci.Hdr.DeviceId <= 0x103F && - Pci.Hdr.RevisionID == 0x00 && - Pci.Device.SubsystemID == VIRTIO_SUBSYSTEM_BLOCK_DEVICE) ? EFI_SUCCESS : EFI_UNSUPPORTED; + if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_BLOCK_DEVICE) { + Status = EFI_UNSUPPORTED; } // - // We needed PCI IO access only transitorily, to see whether we support the + // We needed VirtIo access only transitorily, to see whether we support the // device or not. // - gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, + gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle); return Status; } @@ -594,8 +568,8 @@ VirtioBlkDriverBindingSupported ( device. @param[in out] Dev The driver instance to configure. The caller is - responsible for Dev->PciIo's validity (ie. working IO - access to the underlying virtio-blk PCI device). + responsible for Dev->VirtIo's validity (ie. working IO + access to the underlying virtio-blk device). @retval EFI_SUCCESS Setup complete. @@ -626,19 +600,27 @@ VirtioBlkInit ( // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence. // NextDevStat = 0; // step 1 -- reset device - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat); + Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) { goto Failed; } NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat); + Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) { goto Failed; } NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat); + Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); + if (EFI_ERROR (Status)) { + goto Failed; + } + + // + // Set Page Size - MMIO VirtIo Specific + // + Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE); if (EFI_ERROR (Status)) { goto Failed; } @@ -646,11 +628,12 @@ VirtioBlkInit ( // // step 4a -- retrieve and validate features // - Status = VIRTIO_CFG_READ (Dev, Generic.VhdrDeviceFeatureBits, &Features); + Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features); if (EFI_ERROR (Status)) { goto Failed; } - Status = VIRTIO_CFG_READ (Dev, VhdrCapacity, &NumSectors); + + Status = VIRTIO_CFG_READ (Dev, Capacity, &NumSectors); if (EFI_ERROR (Status)) { goto Failed; } @@ -660,7 +643,7 @@ VirtioBlkInit ( } if (Features & VIRTIO_BLK_F_BLK_SIZE) { - Status = VIRTIO_CFG_READ (Dev, VhdrBlkSize, &BlockSize); + Status = VIRTIO_CFG_READ (Dev, BlkSize, &BlockSize); if (EFI_ERROR (Status)) { goto Failed; } @@ -681,11 +664,11 @@ VirtioBlkInit ( // // step 4b -- allocate virtqueue // - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueSelect, 0); + Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, 0); if (EFI_ERROR (Status)) { goto Failed; } - Status = VIRTIO_CFG_READ (Dev, Generic.VhdrQueueSize, &QueueSize); + Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize); if (EFI_ERROR (Status)) { goto Failed; } @@ -700,22 +683,36 @@ VirtioBlkInit ( } // - // step 4c -- Report GPFN (guest-physical frame number) of queue. If anything - // fails from here on, we must release the ring resources. + // Additional steps for MMIO: align the queue appropriately, and set the + // size. If anything fails from here on, we must release the ring resources. + // + Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize); + if (EFI_ERROR (Status)) { + goto ReleaseQueue; + } + + Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE); + if (EFI_ERROR (Status)) { + goto ReleaseQueue; + } + + // + // step 4c -- Report GPFN (guest-physical frame number) of queue. // - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrQueueAddress, - (UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT); + Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, + (UINT32)(UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT); if (EFI_ERROR (Status)) { goto ReleaseQueue; } + // // step 5 -- Report understood features. There are no virtio-blk specific // features to negotiate in virtio-0.9.5, plus we do not want any of the // device-independent (known or unknown) VIRTIO_F_* capabilities (see // Appendix B). // - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrGuestFeatureBits, 0); + Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, 0); if (EFI_ERROR (Status)) { goto ReleaseQueue; } @@ -724,7 +721,7 @@ VirtioBlkInit ( // step 6 -- initialization complete // NextDevStat |= VSTAT_DRIVER_OK; - Status = VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat); + Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); if (EFI_ERROR (Status)) { goto ReleaseQueue; } @@ -758,10 +755,10 @@ ReleaseQueue: Failed: // // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device - // Status. PCI IO access failure here should not mask the original error. + // Status. VirtIo access failure here should not mask the original error. // NextDevStat |= VSTAT_FAILED; - VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, NextDevStat); + Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat); return Status; // reached only via Failed above } @@ -788,7 +785,7 @@ VirtioBlkUninit ( // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from // the old comms area. // - VIRTIO_CFG_WRITE (Dev, Generic.VhdrDeviceStatus, 0); + Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0); VirtioRingUninit (&Dev->Ring); @@ -815,13 +812,13 @@ VirtioBlkUninit ( @retval EFI_SUCCESS Driver instance has been created and - initialized for the virtio-blk PCI device, it + initialized for the virtio-blk device, it is now accessibla via EFI_BLOCK_IO_PROTOCOL. @retval EFI_OUT_OF_RESOURCES Memory allocation failed. @return Error codes from the OpenProtocol() boot - service, the PciIo protocol, VirtioBlkInit(), + service, the VirtIo protocol, VirtioBlkInit(), or the InstallProtocolInterface() boot service. **/ @@ -842,43 +839,19 @@ VirtioBlkDriverBindingStart ( return EFI_OUT_OF_RESOURCES; } - Status = gBS->OpenProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, - (VOID **)&Dev->PciIo, This->DriverBindingHandle, + Status = gBS->OpenProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, + (VOID **)&Dev->VirtIo, This->DriverBindingHandle, DeviceHandle, EFI_OPEN_PROTOCOL_BY_DRIVER); if (EFI_ERROR (Status)) { goto FreeVirtioBlk; } // - // We must retain and ultimately restore the original PCI attributes of the - // device. See Driver Writer's Guide for UEFI 2.3.1 v1.01, 18.3 PCI drivers / - // 18.3.2 Start() and Stop(). - // - // The third parameter ("Attributes", input) is ignored by the Get operation. - // The fourth parameter ("Result", output) is ignored by the Enable and Set - // operations. - // - // For virtio-blk we only need IO space access. - // - Status = Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationGet, - 0, &Dev->OriginalPciAttributes); - if (EFI_ERROR (Status)) { - goto ClosePciIo; - } - - Status = Dev->PciIo->Attributes (Dev->PciIo, - EfiPciIoAttributeOperationEnable, - EFI_PCI_IO_ATTRIBUTE_IO, NULL); - if (EFI_ERROR (Status)) { - goto ClosePciIo; - } - - // - // PCI IO access granted, configure virtio-blk device. + // VirtIo access granted, configure virtio-blk device. // Status = VirtioBlkInit (Dev); if (EFI_ERROR (Status)) { - goto RestorePciAttributes; + goto CloseVirtIo; } // @@ -897,12 +870,8 @@ VirtioBlkDriverBindingStart ( UninitDev: VirtioBlkUninit (Dev); -RestorePciAttributes: - Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet, - Dev->OriginalPciAttributes, NULL); - -ClosePciIo: - gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, +CloseVirtIo: + gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle); FreeVirtioBlk: @@ -973,10 +942,7 @@ VirtioBlkDriverBindingStop ( VirtioBlkUninit (Dev); - Dev->PciIo->Attributes (Dev->PciIo, EfiPciIoAttributeOperationSet, - Dev->OriginalPciAttributes, NULL); - - gBS->CloseProtocol (DeviceHandle, &gEfiPciIoProtocolGuid, + gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid, This->DriverBindingHandle, DeviceHandle); FreePool (Dev); diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.h b/OvmfPkg/VirtioBlkDxe/VirtioBlk.h index d22570def9..789caf9a37 100644 --- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.h +++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.h @@ -21,7 +21,6 @@ #include #include #include -#include #include @@ -34,14 +33,13 @@ typedef struct { // at various call depths. The table to the right should make it easier to // track them. // - // field init function init dpth - // ---------------------- ------------------ --------- - UINT32 Signature; // DriverBindingStart 0 - EFI_PCI_IO_PROTOCOL *PciIo; // DriverBindingStart 0 - UINT64 OriginalPciAttributes; // DriverBindingStart 0 - VRING Ring; // VirtioRingInit 2 - EFI_BLOCK_IO_PROTOCOL BlockIo; // VirtioBlkInit 1 - EFI_BLOCK_IO_MEDIA BlockIoMedia; // VirtioBlkInit 1 + // field init function init dpth + // --------------------- ------------------ --------- + UINT32 Signature; // DriverBindingStart 0 + VIRTIO_DEVICE_PROTOCOL *VirtIo; // DriverBindingStart 0 + VRING Ring; // VirtioRingInit 2 + EFI_BLOCK_IO_PROTOCOL BlockIo; // VirtioBlkInit 1 + EFI_BLOCK_IO_MEDIA BlockIoMedia; // VirtioBlkInit 1 } VBLK_DEV; #define VIRTIO_BLK_FROM_BLOCK_IO(BlockIoPointer) \ @@ -66,11 +64,6 @@ typedef struct { underlying device - 9 Driver Binding Protocol -- for exporting ourselves - Specs relevant in the specific sense: - - UEFI Spec 2.3.1 + Errata C, 13.4 EFI PCI I/O Protocol - - Driver Writer's Guide for UEFI 2.3.1 v1.01, 18 PCI Driver Design - Guidelines, 18.3 PCI drivers. - @param[in] This The EFI_DRIVER_BINDING_PROTOCOL object incorporating this driver (independently of any device). @@ -82,11 +75,10 @@ typedef struct { @retval EFI_SUCCESS The driver supports the device being probed. - @retval EFI_UNSUPPORTED Based on virtio-blk PCI discovery, we do not support + @retval EFI_UNSUPPORTED Based on virtio-blk discovery, we do not support the device. - @return Error codes from the OpenProtocol() boot service or - the PciIo protocol. + @return Error codes from the OpenProtocol() boot service. **/ @@ -117,14 +109,14 @@ VirtioBlkDriverBindingSupported ( @retval EFI_SUCCESS Driver instance has been created and - initialized for the virtio-blk PCI device, it + initialized for the virtio-blk device, it is now accessibla via EFI_BLOCK_IO_PROTOCOL. @retval EFI_OUT_OF_RESOURCES Memory allocation failed. @return Error codes from the OpenProtocol() boot - service, the PciIo protocol, VirtioBlkInit(), - or the InstallProtocolInterface() boot service. + service, VirtioBlkInit(), or the + InstallProtocolInterface() boot service. **/ diff --git a/OvmfPkg/VirtioBlkDxe/VirtioBlk.inf b/OvmfPkg/VirtioBlkDxe/VirtioBlk.inf index 6dffc3a22a..d5975b74eb 100644 --- a/OvmfPkg/VirtioBlkDxe/VirtioBlk.inf +++ b/OvmfPkg/VirtioBlkDxe/VirtioBlk.inf @@ -38,5 +38,5 @@ VirtioLib [Protocols] - gEfiBlockIoProtocolGuid ## BY_START - gEfiPciIoProtocolGuid ## TO_START + gEfiBlockIoProtocolGuid ## BY_START + gVirtioDeviceProtocolGuid ## TO_START -- cgit v1.2.3