• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
GetNumberPirqs(IN EFI_LEGACY_INTERRUPT_PROTOCOL * This,OUT UINT8 * NumberPirqs)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
GetLocation(IN EFI_LEGACY_INTERRUPT_PROTOCOL * This,OUT UINT8 * Bus,OUT UINT8 * Device,OUT UINT8 * Function)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
GetAddress(UINT8 PirqNumber)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
ReadPirq(IN EFI_LEGACY_INTERRUPT_PROTOCOL * This,IN UINT8 PirqNumber,OUT UINT8 * PirqData)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
WritePirq(IN EFI_LEGACY_INTERRUPT_PROTOCOL * This,IN UINT8 PirqNumber,IN UINT8 PirqData)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
LegacyInterruptInstall(VOID)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