The AtaAtapiPassThru() driver maps three system memory regions for Bus
Master Common Buffer operation on the following call path, if the
controller being bound has PCI_CLASS_MASS_STORAGE_SATADPA class code:
AtaAtapiPassThruStart()
EnumerateAttachedDevice()
AhciModeInitialization()
AhciCreateTransferDescriptor()
The regions are unmapped when the controller is unbound, in
AtaAtapiPassThruStop().
The common buffers should also be de-programmed when we exit the boot
services and the OS gains ownership of the system memory. Introduce an
ExitBootServices() notification function that
- resets the controller so that it forgets the device addresses for the
common buffers,
- unmaps the common buffers so that device-to-RAM address translations (in
a potential IOMMU or another translator) are torn down.
ExitBootServices() notification functions must not alter the UEFI memory
map, thus call only PciIo->Unmap(), and not PciIo->FreeBuffer(). (Unlike
AtaAtapiPassThruStop() does.)
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h | 18 ++++++
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h | 5 ++
MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c | 67 +++++++++++++++++++-
3 files changed, 89 insertions(+), 1 deletion(-)
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
index 809bcc307fc4..d085597fbdfe 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AhciMode.h
@@ -367,5 +367,23 @@ AhciStopCommand (
IN UINT64 Timeout
);
+/**
+ Do AHCI HBA reset.
+
+ @param PciIo The PCI IO protocol instance.
+ @param Timeout The timeout value of reset, uses 100ns as a unit.
+
+ @retval EFI_DEVICE_ERROR AHCI controller is failed to complete hardware
+ reset.
+ @retval EFI_TIMEOUT The reset operation is time out.
+ @retval EFI_SUCCESS AHCI controller is reset successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+AhciReset (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT64 Timeout
+ );
#endif
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h
index 4f327dc30b60..e51c66f392d2 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.h
@@ -120,6 +120,11 @@ typedef struct {
//
EFI_EVENT TimerEvent;
LIST_ENTRY NonBlockingTaskList;
+
+ //
+ // For resetting AHCI and unmapping CommonBuffer DMA at ExitBootServices().
+ //
+ EFI_EVENT ExitBootEvent;
} ATA_ATAPI_PASS_THRU_INSTANCE;
//
diff --git a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
index 795443ef74f6..6972349b2b8f 100644
--- a/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
+++ b/MdeModulePkg/Bus/Ata/AtaAtapiPassThru/AtaAtapiPassThru.c
@@ -103,7 +103,8 @@ ATA_ATAPI_PASS_THRU_INSTANCE gAtaAtapiPassThruInstanceTemplate = {
{ // NonBlocking TaskList
NULL,
NULL
- }
+ },
+ NULL, // ExitBootEvent
};
ATAPI_DEVICE_PATH mAtapiDevicePathTemplate = {
@@ -477,6 +478,50 @@ InitializeAtaAtapiPassThru (
return Status;
}
+/**
+ If operating in AHCI mode, then reset the HBA and unmap CommonBuffer Bus
+ Master DMA when exiting the boot services.
+
+ @param[in] Event Event for which this notification function is being
+ called.
+ @param[in] Context Pointer to the ATA_ATAPI_PASS_THRU_INSTANCE that
+ represents the HBA.
+**/
+VOID
+EFIAPI
+AtaPassThruExitBootServices (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ ATA_ATAPI_PASS_THRU_INSTANCE *Instance;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_AHCI_REGISTERS *AhciRegisters;
+
+ Instance = Context;
+
+ if (Instance->Mode == EfiAtaAhciMode) {
+ PciIo = Instance->PciIo;
+ AhciRegisters = &Instance->AhciRegisters;
+ //
+ // De-program common buffer references from the HBA by resetting the HBA.
+ //
+ AhciReset (PciIo, EFI_AHCI_BUS_RESET_TIMEOUT);
+ //
+ // Unmap long-lived common buffers.
+ //
+ if (AhciRegisters->AhciRFis != NULL) {
+ PciIo->Unmap (PciIo, AhciRegisters->MapRFis);
+ }
+ if (AhciRegisters->AhciCmdList != NULL) {
+ PciIo->Unmap (PciIo, AhciRegisters->MapCmdList);
+ }
+ if (AhciRegisters->AhciCommandTable != NULL) {
+ PciIo->Unmap (PciIo, AhciRegisters->MapCommandTable);
+ }
+ }
+}
+
/**
Tests to see if this driver supports a given controller. If a child device is provided,
it further tests to see if this driver supports creating a handle for the specified child device.
@@ -755,6 +800,17 @@ AtaAtapiPassThruStart (
InitializeListHead(&Instance->DeviceList);
InitializeListHead(&Instance->NonBlockingTaskList);
+ Status = gBS->CreateEvent (
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ TPL_CALLBACK,
+ AtaPassThruExitBootServices,
+ Instance,
+ &Instance->ExitBootEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
Instance->TimerEvent = NULL;
Status = gBS->CreateEvent (
@@ -808,6 +864,10 @@ ErrorExit:
gBS->CloseEvent (Instance->TimerEvent);
}
+ if ((Instance != NULL) && (Instance->ExitBootEvent != NULL)) {
+ gBS->CloseEvent (Instance->ExitBootEvent);
+ }
+
//
// Remove all inserted ATA devices.
//
@@ -912,6 +972,11 @@ AtaAtapiPassThruStop (
//
DestroyDeviceInfoList (Instance);
+ if (Instance->ExitBootEvent != NULL) {
+ gBS->CloseEvent (Instance->ExitBootEvent);
+ Instance->ExitBootEvent = NULL;
+ }
+
//
// If the current working mode is AHCI mode, then pre-allocated resource
// for AHCI initialization should be released.
--
2.14.1.3.gb7cf6e02401b
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel
© 2016 - 2024 Red Hat, Inc.