]> git.proxmox.com Git - mirror_edk2.git/blobdiff - OvmfPkg/VirtioScsiDxe/VirtioScsi.c
OvmfPkg/Virtio: take RingBaseShift in SetQueueAddress()
[mirror_edk2.git] / OvmfPkg / VirtioScsiDxe / VirtioScsi.c
index 2cb3f43bb01c25c29297f0e7027d11dcd5391b8d..a983b3df7b9caf2d1490af8ec6b0dee7cfc45129 100644 (file)
@@ -27,6 +27,7 @@
 \r
   Copyright (C) 2012, Red Hat, Inc.\r
   Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>\r
 \r
   Copyright (C) 2012, Red Hat, Inc.\r
   Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2017, AMD Inc, All rights reserved.<BR>\r
 \r
   This program and the accompanying materials are licensed and made available\r
   under the terms and conditions of the BSD License which accompanies this\r
 \r
   This program and the accompanying materials are licensed and made available\r
   under the terms and conditions of the BSD License which accompanies this\r
@@ -470,7 +471,7 @@ VirtioScsiPassThru (
   // caller retry.\r
   //\r
   if (VirtioFlush (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE, &Dev->Ring,\r
   // caller retry.\r
   //\r
   if (VirtioFlush (Dev->VirtIo, VIRTIO_SCSI_REQUEST_QUEUE, &Dev->Ring,\r
-        &Indices) != EFI_SUCCESS) {\r
+        &Indices, NULL) != EFI_SUCCESS) {\r
     Packet->InTransferLength  = 0;\r
     Packet->OutTransferLength = 0;\r
     Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;\r
     Packet->InTransferLength  = 0;\r
     Packet->OutTransferLength = 0;\r
     Packet->HostAdapterStatus = EFI_EXT_SCSI_STATUS_HOST_ADAPTER_OTHER;\r
@@ -707,7 +708,7 @@ VirtioScsiInit (
   UINT8      NextDevStat;\r
   EFI_STATUS Status;\r
 \r
   UINT8      NextDevStat;\r
   EFI_STATUS Status;\r
 \r
-  UINT32     Features;\r
+  UINT64     Features;\r
   UINT16     MaxChannel; // for validation only\r
   UINT32     NumQueues;  // for validation only\r
   UINT16     QueueSize;\r
   UINT16     MaxChannel; // for validation only\r
   UINT32     NumQueues;  // for validation only\r
   UINT16     QueueSize;\r
@@ -800,6 +801,19 @@ VirtioScsiInit (
     goto Failed;\r
   }\r
 \r
     goto Failed;\r
   }\r
 \r
+  Features &= VIRTIO_SCSI_F_INOUT | VIRTIO_F_VERSION_1;\r
+\r
+  //\r
+  // In virtio-1.0, feature negotiation is expected to complete before queue\r
+  // discovery, and the device can also reject the selected set of features.\r
+  //\r
+  if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
+    Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Failed;\r
+    }\r
+  }\r
+\r
   //\r
   // step 4b -- allocate request virtqueue\r
   //\r
   //\r
   // step 4b -- allocate request virtqueue\r
   //\r
@@ -819,7 +833,7 @@ VirtioScsiInit (
     goto Failed;\r
   }\r
 \r
     goto Failed;\r
   }\r
 \r
-  Status = VirtioRingInit (QueueSize, &Dev->Ring);\r
+  Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Dev->Ring);\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
   if (EFI_ERROR (Status)) {\r
     goto Failed;\r
   }\r
@@ -841,21 +855,20 @@ VirtioScsiInit (
   //\r
   // step 4c -- Report GPFN (guest-physical frame number) of queue.\r
   //\r
   //\r
   // step 4c -- Report GPFN (guest-physical frame number) of queue.\r
   //\r
-  Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo,\r
-      (UINT32) ((UINTN) Dev->Ring.Base >> EFI_PAGE_SHIFT));\r
+  Status = Dev->VirtIo->SetQueueAddress (Dev->VirtIo, &Dev->Ring, 0);\r
   if (EFI_ERROR (Status)) {\r
     goto ReleaseQueue;\r
   }\r
 \r
   //\r
   if (EFI_ERROR (Status)) {\r
     goto ReleaseQueue;\r
   }\r
 \r
   //\r
-  // step 5 -- Report understood features and guest-tuneables. We want none of\r
-  // the known (or unknown) VIRTIO_SCSI_F_* or VIRTIO_F_* capabilities (see\r
-  // virtio-0.9.5, Appendices B and I), except bidirectional transfers.\r
+  // step 5 -- Report understood features and guest-tuneables.\r
   //\r
   //\r
-  Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo,\r
-      Features & VIRTIO_SCSI_F_INOUT);\r
-  if (EFI_ERROR (Status)) {\r
-    goto ReleaseQueue;\r
+  if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {\r
+    Features &= ~(UINT64)VIRTIO_F_VERSION_1;\r
+    Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ReleaseQueue;\r
+    }\r
   }\r
 \r
   //\r
   }\r
 \r
   //\r
@@ -914,7 +927,7 @@ VirtioScsiInit (
   return EFI_SUCCESS;\r
 \r
 ReleaseQueue:\r
   return EFI_SUCCESS;\r
 \r
 ReleaseQueue:\r
-  VirtioRingUninit (&Dev->Ring);\r
+  VirtioRingUninit (Dev->VirtIo, &Dev->Ring);\r
 \r
 Failed:\r
   //\r
 \r
 Failed:\r
   //\r
@@ -933,7 +946,6 @@ Failed:
 }\r
 \r
 \r
 }\r
 \r
 \r
-\r
 STATIC\r
 VOID\r
 EFIAPI\r
 STATIC\r
 VOID\r
 EFIAPI\r
@@ -953,13 +965,39 @@ VirtioScsiUninit (
   Dev->MaxLun         = 0;\r
   Dev->MaxSectors     = 0;\r
 \r
   Dev->MaxLun         = 0;\r
   Dev->MaxSectors     = 0;\r
 \r
-  VirtioRingUninit (&Dev->Ring);\r
+  VirtioRingUninit (Dev->VirtIo, &Dev->Ring);\r
 \r
   SetMem (&Dev->PassThru,     sizeof Dev->PassThru,     0x00);\r
   SetMem (&Dev->PassThruMode, sizeof Dev->PassThruMode, 0x00);\r
 }\r
 \r
 \r
 \r
   SetMem (&Dev->PassThru,     sizeof Dev->PassThru,     0x00);\r
   SetMem (&Dev->PassThruMode, sizeof Dev->PassThruMode, 0x00);\r
 }\r
 \r
 \r
+//\r
+// Event notification function enqueued by ExitBootServices().\r
+//\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+VirtioScsiExitBoot (\r
+  IN  EFI_EVENT Event,\r
+  IN  VOID      *Context\r
+  )\r
+{\r
+  VSCSI_DEV *Dev;\r
+\r
+  //\r
+  // Reset the device. This causes the hypervisor to forget about the virtio\r
+  // ring.\r
+  //\r
+  // We allocated said ring in EfiBootServicesData type memory, and code\r
+  // executing after ExitBootServices() is permitted to overwrite it.\r
+  //\r
+  Dev = Context;\r
+  Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);\r
+}\r
+\r
+\r
 //\r
 // Probe, start and stop functions of this driver, called by the DXE core for\r
 // specific devices.\r
 //\r
 // Probe, start and stop functions of this driver, called by the DXE core for\r
 // specific devices.\r
@@ -1050,6 +1088,12 @@ VirtioScsiDriverBindingStart (
     goto CloseVirtIo;\r
   }\r
 \r
     goto CloseVirtIo;\r
   }\r
 \r
+  Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,\r
+                  &VirtioScsiExitBoot, Dev, &Dev->ExitBoot);\r
+  if (EFI_ERROR (Status)) {\r
+    goto UninitDev;\r
+  }\r
+\r
   //\r
   // Setup complete, attempt to export the driver instance's PassThru\r
   // interface.\r
   //\r
   // Setup complete, attempt to export the driver instance's PassThru\r
   // interface.\r
@@ -1059,11 +1103,14 @@ VirtioScsiDriverBindingStart (
                   &gEfiExtScsiPassThruProtocolGuid, EFI_NATIVE_INTERFACE,\r
                   &Dev->PassThru);\r
   if (EFI_ERROR (Status)) {\r
                   &gEfiExtScsiPassThruProtocolGuid, EFI_NATIVE_INTERFACE,\r
                   &Dev->PassThru);\r
   if (EFI_ERROR (Status)) {\r
-    goto UninitDev;\r
+    goto CloseExitBoot;\r
   }\r
 \r
   return EFI_SUCCESS;\r
 \r
   }\r
 \r
   return EFI_SUCCESS;\r
 \r
+CloseExitBoot:\r
+  gBS->CloseEvent (Dev->ExitBoot);\r
+\r
 UninitDev:\r
   VirtioScsiUninit (Dev);\r
 \r
 UninitDev:\r
   VirtioScsiUninit (Dev);\r
 \r
@@ -1114,6 +1161,8 @@ VirtioScsiDriverBindingStop (
     return Status;\r
   }\r
 \r
     return Status;\r
   }\r
 \r
+  gBS->CloseEvent (Dev->ExitBoot);\r
+\r
   VirtioScsiUninit (Dev);\r
 \r
   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,\r
   VirtioScsiUninit (Dev);\r
 \r
   gBS->CloseProtocol (DeviceHandle, &gVirtioDeviceProtocolGuid,\r