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