Use a PCD set from PEI to determine the legacy interrupt device number appropriate for the underlying platform type during protocol initialization. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Gabriel Somlo <somlo@cmu.edu> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Jordan Justen <jordan.l.justen@intel.com> Reviewed-by: Gerd Hoffmann <kraxel@redhat.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16375 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			221 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Legacy Interrupt Support
 | |
| 
 | |
|   Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   This program and the accompanying materials are
 | |
|   licensed and made available under the terms and conditions of the BSD License
 | |
|   which accompanies this distribution.  The full text of the license may be found at
 | |
|   http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
|   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
|   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "LegacyInterrupt.h"
 | |
| 
 | |
| //
 | |
| // Handle for the Legacy Interrupt Protocol instance produced by this driver
 | |
| //
 | |
| STATIC EFI_HANDLE mLegacyInterruptHandle = NULL;
 | |
| 
 | |
| //
 | |
| // Legacy Interrupt Device number (0x01 on piix4, 0x1f on q35/mch)
 | |
| //
 | |
| STATIC UINT8      mLegacyInterruptDevice;
 | |
| 
 | |
| //
 | |
| // The Legacy Interrupt Protocol instance produced by this driver
 | |
| //
 | |
| STATIC EFI_LEGACY_INTERRUPT_PROTOCOL mLegacyInterrupt = {
 | |
|   GetNumberPirqs,
 | |
|   GetLocation,
 | |
|   ReadPirq,
 | |
|   WritePirq
 | |
| };
 | |
| 
 | |
| STATIC UINT8 PirqReg[MAX_PIRQ_NUMBER] = { PIRQA, PIRQB, PIRQC, PIRQD, PIRQE, PIRQF, PIRQG, PIRQH };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Return the number of PIRQs supported by this chipset.
 | |
| 
 | |
|   @param[in]  This         Pointer to LegacyInterrupt Protocol
 | |
|   @param[out] NumberPirqs  The pointer to return the max IRQ number supported
 | |
| 
 | |
|   @retval EFI_SUCCESS   Max PIRQs successfully returned
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| GetNumberPirqs (
 | |
|   IN  EFI_LEGACY_INTERRUPT_PROTOCOL  *This,
 | |
|   OUT UINT8                          *NumberPirqs
 | |
|   )
 | |
| {
 | |
|   *NumberPirqs = MAX_PIRQ_NUMBER;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Return PCI location of this device.
 | |
|   $PIR table requires this info.
 | |
| 
 | |
|   @param[in]   This                - Protocol instance pointer.
 | |
|   @param[out]  Bus                 - PCI Bus
 | |
|   @param[out]  Device              - PCI Device
 | |
|   @param[out]  Function            - PCI Function
 | |
| 
 | |
|   @retval  EFI_SUCCESS   Bus/Device/Function returned
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| GetLocation (
 | |
|   IN  EFI_LEGACY_INTERRUPT_PROTOCOL  *This,
 | |
|   OUT UINT8                          *Bus,
 | |
|   OUT UINT8                          *Device,
 | |
|   OUT UINT8                          *Function
 | |
|   )
 | |
| {
 | |
|   *Bus      = LEGACY_INT_BUS;
 | |
|   *Device   = mLegacyInterruptDevice;
 | |
|   *Function = LEGACY_INT_FUNC;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Builds the PCI configuration address for the register specified by PirqNumber
 | |
| 
 | |
|   @param[in]  PirqNumber - The PIRQ number to build the PCI configuration address for
 | |
| 
 | |
|   @return  The PCI Configuration address for the PIRQ
 | |
| **/
 | |
| UINTN
 | |
| GetAddress (
 | |
|   UINT8  PirqNumber
 | |
|   )
 | |
| {
 | |
|   return PCI_LIB_ADDRESS(
 | |
|           LEGACY_INT_BUS,
 | |
|           mLegacyInterruptDevice,
 | |
|           LEGACY_INT_FUNC,
 | |
|           PirqReg[PirqNumber]
 | |
|           );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Read the given PIRQ register
 | |
| 
 | |
|   @param[in]  This        Protocol instance pointer
 | |
|   @param[in]  PirqNumber  The Pirq register 0 = A, 1 = B etc
 | |
|   @param[out] PirqData    Value read
 | |
| 
 | |
|   @retval EFI_SUCCESS   Decoding change affected.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid PIRQ number
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| ReadPirq (
 | |
|   IN  EFI_LEGACY_INTERRUPT_PROTOCOL  *This,
 | |
|   IN  UINT8                          PirqNumber,
 | |
|   OUT UINT8                          *PirqData
 | |
|   )
 | |
| {
 | |
|   if (PirqNumber >= MAX_PIRQ_NUMBER) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *PirqData = PciRead8 (GetAddress (PirqNumber));
 | |
|   *PirqData = (UINT8) (*PirqData & 0x7f);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Write the given PIRQ register
 | |
| 
 | |
|   @param[in]  This        Protocol instance pointer
 | |
|   @param[in]  PirqNumber  The Pirq register 0 = A, 1 = B etc
 | |
|   @param[out] PirqData    Value to write
 | |
| 
 | |
|   @retval EFI_SUCCESS   Decoding change affected.
 | |
|   @retval EFI_INVALID_PARAMETER   Invalid PIRQ number
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| WritePirq (
 | |
|   IN  EFI_LEGACY_INTERRUPT_PROTOCOL  *This,
 | |
|   IN  UINT8                          PirqNumber,
 | |
|   IN  UINT8                          PirqData
 | |
|   )
 | |
| {
 | |
|   if (PirqNumber >= MAX_PIRQ_NUMBER) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   PciWrite8 (GetAddress (PirqNumber), PirqData);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Initialize Legacy Interrupt support
 | |
| 
 | |
|   @retval EFI_SUCCESS   Successfully initialized
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| LegacyInterruptInstall (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT16      HostBridgeDevId;
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   //
 | |
|   // Make sure the Legacy Interrupt Protocol is not already installed in the system
 | |
|   //
 | |
|   ASSERT_PROTOCOL_ALREADY_INSTALLED(NULL, &gEfiLegacyInterruptProtocolGuid);
 | |
| 
 | |
|   //
 | |
|   // Query Host Bridge DID to determine platform type, then set device number
 | |
|   //
 | |
|   HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
 | |
|   switch (HostBridgeDevId) {
 | |
|     case INTEL_82441_DEVICE_ID:
 | |
|       mLegacyInterruptDevice = LEGACY_INT_DEV_PIIX4;
 | |
|       break;
 | |
|     case INTEL_Q35_MCH_DEVICE_ID:
 | |
|       mLegacyInterruptDevice = LEGACY_INT_DEV_Q35;
 | |
|       break;
 | |
|     default:
 | |
|       DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
 | |
|         __FUNCTION__, HostBridgeDevId));
 | |
|       ASSERT (FALSE);
 | |
|       return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Make a new handle and install the protocol
 | |
|   //
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &mLegacyInterruptHandle,
 | |
|                   &gEfiLegacyInterruptProtocolGuid,
 | |
|                   &mLegacyInterrupt,
 | |
|                   NULL
 | |
|                   );
 | |
|   ASSERT_EFI_ERROR(Status);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 |