Drivers/DwUfsHcDxe: open PciIo protocol

Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
diff --git a/Drivers/Block/DwUfsHcDxe/ComponentName.c b/Drivers/Block/DwUfsHcDxe/ComponentName.c
index 89c3f14..03c690c 100644
--- a/Drivers/Block/DwUfsHcDxe/ComponentName.c
+++ b/Drivers/Block/DwUfsHcDxe/ComponentName.c
@@ -191,6 +191,8 @@
   OUT CHAR16                                          **ControllerName

   )

 {

+  EFI_STATUS                    Status;

+

   if (Language == NULL || ControllerName == NULL) {

     return EFI_INVALID_PARAMETER;

   }

@@ -202,6 +204,18 @@
     return EFI_UNSUPPORTED;

   }

 

+  //

+  // Make sure this driver is currently managing Controller Handle

+  //

+  Status = EfiTestManagedDevice (

+             ControllerHandle,

+             gUfsHcDriverBinding.DriverBindingHandle,

+             &gEfiPciIoProtocolGuid

+             );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+

   return LookupUnicodeString2 (

            Language,

            This->SupportedLanguages,

diff --git a/Drivers/Block/DwUfsHcDxe/DwUfsHcDxe.c b/Drivers/Block/DwUfsHcDxe/DwUfsHcDxe.c
index 901f508..669f9b0 100644
--- a/Drivers/Block/DwUfsHcDxe/DwUfsHcDxe.c
+++ b/Drivers/Block/DwUfsHcDxe/DwUfsHcDxe.c
@@ -17,6 +17,10 @@
 

 #include "DwUfsHcDxe.h"

 

+#include <IndustryStandard/Pci.h>

+

+#include <Protocol/PciIo.h>

+

 //

 // Ufs Host Controller Driver Binding Protocol Instance

 //

@@ -551,9 +555,13 @@
   )

 {

   EFI_STATUS                Status;

-  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;

+  BOOLEAN                   UfsHcFound;

+  EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath = NULL;

+  EFI_PCI_IO_PROTOCOL       *PciIo = NULL;

+  PCI_TYPE00                PciData;

 

   ParentDevicePath = NULL;

+  UfsHcFound       = FALSE;

 

   //

   // UfsHcDxe is a device driver, and should ingore the

@@ -583,6 +591,64 @@
         Controller

         );

 

+  //

+  // Now test the EfiPciIoProtocol

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiPciIoProtocolGuid,

+                  (VOID **) &PciIo,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  if (EFI_ERROR (Status)) {

+    return Status;

+  }

+  //

+  // Now further check the PCI header: Base class (offset 0x0B) and

+  // Sub Class (offset 0x0A). This controller should be an UFS controller

+  //

+  Status = PciIo->Pci.Read (

+                        PciIo,

+                        EfiPciIoWidthUint8,

+                        0,

+                        sizeof (PciData),

+                        &PciData

+                        );

+  if (EFI_ERROR (Status)) {

+    gBS->CloseProtocol (

+          Controller,

+          &gEfiPciIoProtocolGuid,

+          This->DriverBindingHandle,

+          Controller

+          );

+    return EFI_UNSUPPORTED;

+  }

+

+  //

+  // Since we already got the PciData, we can close protocol to avoid to carry it on for multiple exit points.

+  //

+  gBS->CloseProtocol (

+        Controller,

+        &gEfiPciIoProtocolGuid,

+        This->DriverBindingHandle,

+        Controller

+        );

+

+  //

+  // Examine UFS Host Controller PCI Configuration table fields

+  //

+  if (PciData.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE) {

+    if (PciData.Hdr.ClassCode[1] == 0x09 ) { //UFS Controller Subclass

+      UfsHcFound = TRUE;

+    }

+  }

+

+  if (!UfsHcFound) {

+    return EFI_UNSUPPORTED;

+  }

+

   return Status;

 }

 

@@ -630,16 +696,106 @@
   )

 {

   EFI_STATUS                        Status;

+  EFI_PCI_IO_PROTOCOL               *PciIo;

   UFS_HOST_CONTROLLER_PRIVATE_DATA  *Private;

+  UINT64                            Supports;

+  UINT8                             BarIndex;

+  EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;

   UINT32                            BaseAddress;

 

+  PciIo    = NULL;

+  Private  = NULL;

+  Supports = 0;

+  BarDesc  = NULL;

   BaseAddress = PcdGet32 (PcdDwUfsHcDxeBaseAddress);

+

+  //

+  // Now test and open the EfiPciIoProtocol

+  //

+  Status = gBS->OpenProtocol (

+                  Controller,

+                  &gEfiPciIoProtocolGuid,

+                  (VOID **) &PciIo,

+                  This->DriverBindingHandle,

+                  Controller,

+                  EFI_OPEN_PROTOCOL_BY_DRIVER

+                  );

+  //

+  // Status == 0 - A normal execution flow, SUCCESS and the program proceeds.

+  // Status == ALREADY_STARTED - A non-zero Status code returned. It indicates

+  //           that the protocol has been opened and should be treated as a

+  //           normal condition and the program proceeds. The Protocol will not

+  //           opened 'again' by this call.

+  // Status != ALREADY_STARTED - Error status, terminate program execution

+  //

+  if (EFI_ERROR (Status)) {

+    //

+    // EFI_ALREADY_STARTED is also an error

+    //

+    return Status;

+  }

+

+  //BaseAddress = PcdGet32 (PcdDwUfsHcDxeBaseAddress);

   Private = AllocateCopyPool (sizeof (UFS_HOST_CONTROLLER_PRIVATE_DATA), &gUfsHcTemplate);

   if (Private == NULL) {

     Status = EFI_OUT_OF_RESOURCES;

     goto Done;

   }

+

   Private->RegBase = (UINTN)BaseAddress;

+  Private->PciIo = PciIo;

+

+  for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {

+    Status = PciIo->GetBarAttributes (

+                      PciIo,

+                      BarIndex,

+                      NULL,

+                      (VOID**) &BarDesc

+                      );

+    if (Status == EFI_UNSUPPORTED) {

+      continue;

+    } else if (EFI_ERROR (Status)) {

+      goto Done;

+    }

+

+    if (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {

+      Private->BarIndex = BarIndex;

+      FreePool (BarDesc);

+      break;

+    }

+

+    FreePool (BarDesc);

+  }

+

+  Status = PciIo->Attributes (

+                    PciIo,

+                    EfiPciIoAttributeOperationGet,

+                    0,

+                    &Private->PciAttributes

+                    );

+

+  if (EFI_ERROR (Status)) {

+    goto Done;

+  }

+

+  Status = PciIo->Attributes (

+                    PciIo,

+                    EfiPciIoAttributeOperationSupported,

+                    0,

+                    &Supports

+                    );

+

+  if (!EFI_ERROR (Status)) {

+    Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;

+    Status    = PciIo->Attributes (

+                         PciIo,

+                         EfiPciIoAttributeOperationEnable,

+                         Supports,

+                         NULL

+                         );

+  } else {

+    goto Done;

+  }

 

   ///

   /// Install UFS_HOST_CONTROLLER protocol

@@ -653,6 +809,24 @@
 

 Done:

   if (EFI_ERROR (Status)) {

+    if ((Private != NULL) && (Private->PciAttributes != 0)) {

+      //

+      // Restore original PCI attributes

+      //

+      Status = PciIo->Attributes (

+                        PciIo,

+                        EfiPciIoAttributeOperationSet,

+                        Private->PciAttributes,

+                        NULL

+                        );

+      ASSERT_EFI_ERROR (Status);

+    }

+    gBS->CloseProtocol (

+          Controller,

+          &gEfiPciIoProtocolGuid,

+          This->DriverBindingHandle,

+          Controller

+          );

     if (Private != NULL) {

       FreePool (Private);

     }

@@ -724,6 +898,27 @@
                   &(Private->UfsHc)

                   );

   if (!EFI_ERROR (Status)) {

+    //

+    // Restore original PCI attributes

+    //

+    Status = Private->PciIo->Attributes (

+                               Private->PciIo,

+                               EfiPciIoAttributeOperationSet,

+                               Private->PciAttributes,

+                               NULL

+                               );

+    ASSERT_EFI_ERROR (Status);

+

+    //

+    // Close protocols opened by UFS host controller driver

+    //

+    gBS->CloseProtocol (

+           Controller,

+           &gEfiPciIoProtocolGuid,

+           This->DriverBindingHandle,

+           Controller

+           );

+

     FreePool (Private);

   }

 

diff --git a/Drivers/Block/DwUfsHcDxe/DwUfsHcDxe.h b/Drivers/Block/DwUfsHcDxe/DwUfsHcDxe.h
index 1448e08..a5d90ea 100644
--- a/Drivers/Block/DwUfsHcDxe/DwUfsHcDxe.h
+++ b/Drivers/Block/DwUfsHcDxe/DwUfsHcDxe.h
@@ -23,6 +23,7 @@
 #include <Protocol/DevicePath.h>

 #include <Protocol/DriverBinding.h>

 #include <Protocol/LoadedImage.h>

+#include <Protocol/PciIo.h>

 #include <Protocol/UfsHostController.h>

 

 #include <Library/ArmLib.h>

@@ -122,6 +123,10 @@
   EFI_HANDLE                         Handle;

 

   EDKII_UFS_HOST_CONTROLLER_PROTOCOL UfsHc;

+  EFI_PCI_IO_PROTOCOL                *PciIo;

+  UINT8                              BarIndex;

+  UINT64                             PciAttributes;

+

   UINTN                              RegBase;

 };

 

diff --git a/Drivers/Block/DwUfsHcDxe/DwUfsHcDxe.inf b/Drivers/Block/DwUfsHcDxe/DwUfsHcDxe.inf
index b36b0a4..10c2d26 100644
--- a/Drivers/Block/DwUfsHcDxe/DwUfsHcDxe.inf
+++ b/Drivers/Block/DwUfsHcDxe/DwUfsHcDxe.inf
@@ -52,8 +52,9 @@
   UefiLib

 

 [Protocols]

-  gEfiDevicePathProtocolGuid                  ## TO_START

   gEdkiiUfsHostControllerProtocolGuid         ## BY_START

+  gEfiDevicePathProtocolGuid                  ## TO_START

+  gEfiPciIoProtocolGuid

 

 [Pcd]

   gDwUfsHcDxeTokenSpaceGuid.PcdDwUfsHcDxeBaseAddress