/*++\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
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
\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
}\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