Home | History | Annotate | Download | only in CsmSupportLib
      1 /** @file
      2   Legacy Interrupt Support
      3 
      4   Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
      5 
      6   This program and the accompanying materials are
      7   licensed and made available under the terms and conditions of the BSD License
      8   which accompanies this distribution.  The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.php
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "LegacyInterrupt.h"
     17 
     18 //
     19 // Handle for the Legacy Interrupt Protocol instance produced by this driver
     20 //
     21 STATIC EFI_HANDLE mLegacyInterruptHandle = NULL;
     22 
     23 //
     24 // Legacy Interrupt Device number (0x01 on piix4, 0x1f on q35/mch)
     25 //
     26 STATIC UINT8      mLegacyInterruptDevice;
     27 
     28 //
     29 // The Legacy Interrupt Protocol instance produced by this driver
     30 //
     31 STATIC EFI_LEGACY_INTERRUPT_PROTOCOL mLegacyInterrupt = {
     32   GetNumberPirqs,
     33   GetLocation,
     34   ReadPirq,
     35   WritePirq
     36 };
     37 
     38 STATIC UINT8 PirqReg[MAX_PIRQ_NUMBER] = { PIRQA, PIRQB, PIRQC, PIRQD, PIRQE, PIRQF, PIRQG, PIRQH };
     39 
     40 
     41 /**
     42   Return the number of PIRQs supported by this chipset.
     43 
     44   @param[in]  This         Pointer to LegacyInterrupt Protocol
     45   @param[out] NumberPirqs  The pointer to return the max IRQ number supported
     46 
     47   @retval EFI_SUCCESS   Max PIRQs successfully returned
     48 
     49 **/
     50 EFI_STATUS
     51 EFIAPI
     52 GetNumberPirqs (
     53   IN  EFI_LEGACY_INTERRUPT_PROTOCOL  *This,
     54   OUT UINT8                          *NumberPirqs
     55   )
     56 {
     57   *NumberPirqs = MAX_PIRQ_NUMBER;
     58 
     59   return EFI_SUCCESS;
     60 }
     61 
     62 
     63 /**
     64   Return PCI location of this device.
     65   $PIR table requires this info.
     66 
     67   @param[in]   This                - Protocol instance pointer.
     68   @param[out]  Bus                 - PCI Bus
     69   @param[out]  Device              - PCI Device
     70   @param[out]  Function            - PCI Function
     71 
     72   @retval  EFI_SUCCESS   Bus/Device/Function returned
     73 
     74 **/
     75 EFI_STATUS
     76 EFIAPI
     77 GetLocation (
     78   IN  EFI_LEGACY_INTERRUPT_PROTOCOL  *This,
     79   OUT UINT8                          *Bus,
     80   OUT UINT8                          *Device,
     81   OUT UINT8                          *Function
     82   )
     83 {
     84   *Bus      = LEGACY_INT_BUS;
     85   *Device   = mLegacyInterruptDevice;
     86   *Function = LEGACY_INT_FUNC;
     87 
     88   return EFI_SUCCESS;
     89 }
     90 
     91 
     92 /**
     93   Builds the PCI configuration address for the register specified by PirqNumber
     94 
     95   @param[in]  PirqNumber - The PIRQ number to build the PCI configuration address for
     96 
     97   @return  The PCI Configuration address for the PIRQ
     98 **/
     99 UINTN
    100 GetAddress (
    101   UINT8  PirqNumber
    102   )
    103 {
    104   return PCI_LIB_ADDRESS(
    105           LEGACY_INT_BUS,
    106           mLegacyInterruptDevice,
    107           LEGACY_INT_FUNC,
    108           PirqReg[PirqNumber]
    109           );
    110 }
    111 
    112 /**
    113   Read the given PIRQ register
    114 
    115   @param[in]  This        Protocol instance pointer
    116   @param[in]  PirqNumber  The Pirq register 0 = A, 1 = B etc
    117   @param[out] PirqData    Value read
    118 
    119   @retval EFI_SUCCESS   Decoding change affected.
    120   @retval EFI_INVALID_PARAMETER   Invalid PIRQ number
    121 
    122 **/
    123 EFI_STATUS
    124 EFIAPI
    125 ReadPirq (
    126   IN  EFI_LEGACY_INTERRUPT_PROTOCOL  *This,
    127   IN  UINT8                          PirqNumber,
    128   OUT UINT8                          *PirqData
    129   )
    130 {
    131   if (PirqNumber >= MAX_PIRQ_NUMBER) {
    132     return EFI_INVALID_PARAMETER;
    133   }
    134 
    135   *PirqData = PciRead8 (GetAddress (PirqNumber));
    136   *PirqData = (UINT8) (*PirqData & 0x7f);
    137 
    138   return EFI_SUCCESS;
    139 }
    140 
    141 
    142 /**
    143   Write the given PIRQ register
    144 
    145   @param[in]  This        Protocol instance pointer
    146   @param[in]  PirqNumber  The Pirq register 0 = A, 1 = B etc
    147   @param[out] PirqData    Value to write
    148 
    149   @retval EFI_SUCCESS   Decoding change affected.
    150   @retval EFI_INVALID_PARAMETER   Invalid PIRQ number
    151 
    152 **/
    153 EFI_STATUS
    154 EFIAPI
    155 WritePirq (
    156   IN  EFI_LEGACY_INTERRUPT_PROTOCOL  *This,
    157   IN  UINT8                          PirqNumber,
    158   IN  UINT8                          PirqData
    159   )
    160 {
    161   if (PirqNumber >= MAX_PIRQ_NUMBER) {
    162     return EFI_INVALID_PARAMETER;
    163   }
    164 
    165   PciWrite8 (GetAddress (PirqNumber), PirqData);
    166   return EFI_SUCCESS;
    167 }
    168 
    169 
    170 /**
    171   Initialize Legacy Interrupt support
    172 
    173   @retval EFI_SUCCESS   Successfully initialized
    174 
    175 **/
    176 EFI_STATUS
    177 LegacyInterruptInstall (
    178   VOID
    179   )
    180 {
    181   UINT16      HostBridgeDevId;
    182   EFI_STATUS  Status;
    183 
    184   //
    185   // Make sure the Legacy Interrupt Protocol is not already installed in the system
    186   //
    187   ASSERT_PROTOCOL_ALREADY_INSTALLED(NULL, &gEfiLegacyInterruptProtocolGuid);
    188 
    189   //
    190   // Query Host Bridge DID to determine platform type, then set device number
    191   //
    192   HostBridgeDevId = PcdGet16 (PcdOvmfHostBridgePciDevId);
    193   switch (HostBridgeDevId) {
    194     case INTEL_82441_DEVICE_ID:
    195       mLegacyInterruptDevice = LEGACY_INT_DEV_PIIX4;
    196       break;
    197     case INTEL_Q35_MCH_DEVICE_ID:
    198       mLegacyInterruptDevice = LEGACY_INT_DEV_Q35;
    199       break;
    200     default:
    201       DEBUG ((EFI_D_ERROR, "%a: Unknown Host Bridge Device ID: 0x%04x\n",
    202         __FUNCTION__, HostBridgeDevId));
    203       ASSERT (FALSE);
    204       return EFI_UNSUPPORTED;
    205   }
    206 
    207   //
    208   // Make a new handle and install the protocol
    209   //
    210   Status = gBS->InstallMultipleProtocolInterfaces (
    211                   &mLegacyInterruptHandle,
    212                   &gEfiLegacyInterruptProtocolGuid,
    213                   &mLegacyInterrupt,
    214                   NULL
    215                   );
    216   ASSERT_EFI_ERROR(Status);
    217 
    218   return Status;
    219 }
    220 
    221