]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ArmPkg/Drivers/ArmGic/ArmGicCommonDxe.c
ArmPkg/Gic: force GIC driver to run before CPU arch protocol driver
[mirror_edk2.git] / ArmPkg / Drivers / ArmGic / ArmGicCommonDxe.c
index 346d0bc7c95aec0812d049f62af1deadb886de5f..e1adcd3bc6d37b15bf385878fa7a714d3822fe78 100644 (file)
@@ -1,6 +1,6 @@
 /*++\r
 \r
-Copyright (c) 2013-2014, ARM Ltd. All rights reserved.<BR>\r
+Copyright (c) 2013-2017, ARM Ltd. All rights reserved.<BR>\r
 \r
 This program and the accompanying materials\r
 are licensed and made available under the terms and conditions of the BSD License\r
@@ -28,14 +28,10 @@ ExitBootServicesEvent (
   IN VOID       *Context\r
   );\r
 \r
-//\r
 // Making this global saves a few bytes in image size\r
-//\r
 EFI_HANDLE  gHardwareInterruptHandle = NULL;\r
 \r
-//\r
 // Notifications\r
-//\r
 EFI_EVENT EfiExitBootServicesEvent      = (EFI_EVENT)NULL;\r
 \r
 // Maximum Number of Interrupts\r
@@ -43,25 +39,150 @@ UINTN mGicNumInterrupts                 = 0;
 \r
 HARDWARE_INTERRUPT_HANDLER  *gRegisteredInterruptHandlers = NULL;\r
 \r
+\r
+/**\r
+  Calculate GICD_ICFGRn base address and corresponding bit\r
+  field Int_config[1] of the GIC distributor register.\r
+\r
+  @param Source       Hardware source of the interrupt.\r
+  @param RegAddress   Corresponding GICD_ICFGRn base address.\r
+  @param Config1Bit   Bit number of F Int_config[1] bit in the register.\r
+\r
+  @retval EFI_SUCCESS       Source interrupt supported.\r
+  @retval EFI_UNSUPPORTED   Source interrupt is not supported.\r
+**/\r
+EFI_STATUS\r
+GicGetDistributorIcfgBaseAndBit (\r
+  IN HARDWARE_INTERRUPT_SOURCE             Source,\r
+  OUT UINTN                               *RegAddress,\r
+  OUT UINTN                               *Config1Bit\r
+  )\r
+{\r
+  UINTN                  RegIndex;\r
+  UINTN                  Field;\r
+\r
+  if (Source >= mGicNumInterrupts) {\r
+    ASSERT(Source < mGicNumInterrupts);\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  RegIndex = Source / ARM_GIC_ICDICFR_F_STRIDE;  // NOTE: truncation is significant\r
+  Field = Source % ARM_GIC_ICDICFR_F_STRIDE;\r
+  *RegAddress = PcdGet64 (PcdGicDistributorBase)\r
+                + ARM_GIC_ICDICFR\r
+                + (ARM_GIC_ICDICFR_BYTES * RegIndex);\r
+  *Config1Bit = ((Field * ARM_GIC_ICDICFR_F_WIDTH)\r
+                 + ARM_GIC_ICDICFR_F_CONFIG1_BIT);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Register Handler for the specified interrupt source.\r
+\r
+  @param This     Instance pointer for this protocol\r
+  @param Source   Hardware source of the interrupt\r
+  @param Handler  Callback for interrupt. NULL to unregister\r
+\r
+  @retval EFI_SUCCESS Source was updated to support Handler.\r
+  @retval EFI_DEVICE_ERROR  Hardware could not be programmed.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterInterruptSource (\r
+  IN EFI_HARDWARE_INTERRUPT_PROTOCOL    *This,\r
+  IN HARDWARE_INTERRUPT_SOURCE          Source,\r
+  IN HARDWARE_INTERRUPT_HANDLER         Handler\r
+  )\r
+{\r
+  if (Source >= mGicNumInterrupts) {\r
+    ASSERT(FALSE);\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if ((Handler == NULL) && (gRegisteredInterruptHandlers[Source] == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ((Handler != NULL) && (gRegisteredInterruptHandlers[Source] != NULL)) {\r
+    return EFI_ALREADY_STARTED;\r
+  }\r
+\r
+  gRegisteredInterruptHandlers[Source] = Handler;\r
+\r
+  // If the interrupt handler is unregistered then disable the interrupt\r
+  if (NULL == Handler){\r
+    return This->DisableInterruptSource (This, Source);\r
+  } else {\r
+    return This->EnableInterruptSource (This, Source);\r
+  }\r
+}\r
+\r
+STATIC VOID *mCpuArchProtocolNotifyEventRegistration;\r
+\r
+STATIC\r
+VOID\r
+EFIAPI\r
+CpuArchEventProtocolNotify (\r
+  IN  EFI_EVENT       Event,\r
+  IN  VOID            *Context\r
+  )\r
+{\r
+  EFI_CPU_ARCH_PROTOCOL   *Cpu;\r
+  EFI_STATUS              Status;\r
+\r
+  // Get the CPU protocol that this driver requires.\r
+  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);\r
+  if (EFI_ERROR (Status)) {\r
+    return;\r
+  }\r
+\r
+  // Unregister the default exception handler.\r
+  Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n",\r
+      __FUNCTION__, Status));\r
+    return;\r
+  }\r
+\r
+  // Register to receive interrupts\r
+  Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ,\r
+                  Context);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "%a: Cpu->RegisterInterruptHandler() - %r\n",\r
+      __FUNCTION__, Status));\r
+  }\r
+\r
+  gBS->CloseEvent (Event);\r
+}\r
+\r
 EFI_STATUS\r
 InstallAndRegisterInterruptService (\r
   IN EFI_HARDWARE_INTERRUPT_PROTOCOL   *InterruptProtocol,\r
+  IN EFI_HARDWARE_INTERRUPT2_PROTOCOL  *Interrupt2Protocol,\r
   IN EFI_CPU_INTERRUPT_HANDLER          InterruptHandler,\r
   IN EFI_EVENT_NOTIFY                   ExitBootServicesEvent\r
   )\r
 {\r
   EFI_STATUS               Status;\r
-  EFI_CPU_ARCH_PROTOCOL   *Cpu;\r
+  CONST UINTN              RihArraySize =\r
+    (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);\r
 \r
   // Initialize the array for the Interrupt Handlers\r
-  gRegisteredInterruptHandlers = (HARDWARE_INTERRUPT_HANDLER*)AllocateZeroPool (sizeof(HARDWARE_INTERRUPT_HANDLER) * mGicNumInterrupts);\r
+  gRegisteredInterruptHandlers = AllocateZeroPool (RihArraySize);\r
   if (gRegisteredInterruptHandlers == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
                   &gHardwareInterruptHandle,\r
-                  &gHardwareInterruptProtocolGuid, InterruptProtocol,\r
+                  &gHardwareInterruptProtocolGuid,\r
+                  InterruptProtocol,\r
+                  &gHardwareInterrupt2ProtocolGuid,\r
+                  Interrupt2Protocol,\r
                   NULL\r
                   );\r
   if (EFI_ERROR (Status)) {\r
@@ -69,31 +190,23 @@ InstallAndRegisterInterruptService (
   }\r
 \r
   //\r
-  // Get the CPU protocol that this driver requires.\r
-  //\r
-  Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Cpu);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
-  //\r
-  // Unregister the default exception handler.\r
+  // Install the interrupt handler as soon as the CPU arch protocol appears.\r
   //\r
-  Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ, NULL);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
-\r
-  //\r
-  // Register to receive interrupts\r
-  //\r
-  Status = Cpu->RegisterInterruptHandler (Cpu, ARM_ARCH_EXCEPTION_IRQ, InterruptHandler);\r
-  if (EFI_ERROR (Status)) {\r
-    return Status;\r
-  }\r
+  EfiCreateProtocolNotifyEvent (\r
+    &gEfiCpuArchProtocolGuid,\r
+    TPL_CALLBACK,\r
+    CpuArchEventProtocolNotify,\r
+    InterruptHandler,\r
+    &mCpuArchProtocolNotifyEventRegistration);\r
 \r
   // Register for an ExitBootServicesEvent\r
-  Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_NOTIFY, ExitBootServicesEvent, NULL, &EfiExitBootServicesEvent);\r
+  Status = gBS->CreateEvent (\r
+                  EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
+                  TPL_NOTIFY,\r
+                  ExitBootServicesEvent,\r
+                  NULL,\r
+                  &EfiExitBootServicesEvent\r
+                  );\r
 \r
   return Status;\r
 }\r