]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciHotPlugSupport.c
Fixup for review
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciHotPlugSupport.c
1 /**@ file
2 This module provide support function for hot plug device.
3
4 Copyright (c) 2006, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15
16 #include "PciBus.h"
17 #include "PciHotPlugSupport.h"
18
19 EFI_PCI_HOT_PLUG_INIT_PROTOCOL *gPciHotPlugInit;
20 EFI_HPC_LOCATION *gPciRootHpcPool;
21 UINTN gPciRootHpcCount;
22 ROOT_HPC_DATA *gPciRootHpcData;
23
24 /**
25 Init HPC private data.
26
27 @param Event event object
28 @param Context HPC private data.
29 **/
30 VOID
31 EFIAPI
32 PciHPCInitialized (
33 IN EFI_EVENT Event,
34 IN VOID *Context
35 )
36 {
37 ROOT_HPC_DATA *HpcData;
38
39 HpcData = (ROOT_HPC_DATA *) Context;
40 HpcData->Initialized = TRUE;
41
42 }
43
44 /**
45 Compare two device path
46
47 @param DevicePath1 the first device path want to be compared.
48 @param DevicePath2 the first device path want to be compared.
49
50 @retval TRUE equal.
51 @retval FALSE different.
52 **/
53 BOOLEAN
54 EfiCompareDevicePath (
55 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath1,
56 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath2
57 )
58 {
59 UINTN Size1;
60 UINTN Size2;
61
62 Size1 = GetDevicePathSize (DevicePath1);
63 Size2 = GetDevicePathSize (DevicePath2);
64
65 if (Size1 != Size2) {
66 return FALSE;
67 }
68
69 if (CompareMem (DevicePath1, DevicePath2, Size1)) {
70 return FALSE;
71 }
72
73 return TRUE;
74 }
75
76 /**
77 Init hot plug support and root hot plug private data.
78
79 **/
80 EFI_STATUS
81 InitializeHotPlugSupport (
82 VOID
83 )
84 {
85 EFI_STATUS Status;
86 EFI_HPC_LOCATION *HpcList;
87 UINTN HpcCount;
88
89 //
90 // Locate the PciHotPlugInit Protocol
91 // If it doesn't exist, that means there is no
92 // hot plug controller supported on the platform
93 // the PCI Bus driver is running on. HotPlug Support
94 // is an optional feature, so absence of the protocol
95 // won't incur the penalty
96 //
97 gPciHotPlugInit = NULL;
98 gPciRootHpcPool = NULL;
99 gPciRootHpcCount = 0;
100 gPciRootHpcData = NULL;
101
102 Status = gBS->LocateProtocol (
103 &gEfiPciHotPlugInitProtocolGuid,
104 NULL,
105 (VOID **) &gPciHotPlugInit
106 );
107
108 if (EFI_ERROR (Status)) {
109 return EFI_UNSUPPORTED;
110 }
111
112 Status = gPciHotPlugInit->GetRootHpcList (
113 gPciHotPlugInit,
114 &HpcCount,
115 &HpcList
116 );
117
118 if (!EFI_ERROR (Status)) {
119
120 gPciRootHpcPool = HpcList;
121 gPciRootHpcCount = HpcCount;
122 gPciRootHpcData = AllocateZeroPool (sizeof (ROOT_HPC_DATA) * gPciRootHpcCount);
123 if (gPciRootHpcData == NULL) {
124 return EFI_OUT_OF_RESOURCES;
125 }
126 }
127
128 return EFI_SUCCESS;
129 }
130
131 /**
132 Test whether device path is for root pci hot plug bus
133
134 @param HpbdevicePath tested device path.
135 @param HpIndex Return the index of root hot plug in global array.
136
137 @retval TRUE device path is for root pci hot plug.
138 @retval FALSE device path is not for root pci hot plug.
139 **/
140 BOOLEAN
141 IsRootPciHotPlugBus (
142 IN EFI_DEVICE_PATH_PROTOCOL *HpbDevicePath,
143 OUT UINTN *HpIndex
144 )
145 {
146 UINTN Index;
147
148 for (Index = 0; Index < gPciRootHpcCount; Index++) {
149
150 if (EfiCompareDevicePath (gPciRootHpcPool[Index].HpbDevicePath, HpbDevicePath)) {
151
152 if (HpIndex != NULL) {
153 *HpIndex = Index;
154 }
155
156 return TRUE;
157 }
158 }
159
160 return FALSE;
161 }
162
163 /**
164 Test whether device path is for root pci hot plug controller
165
166 @param HpbdevicePath tested device path.
167 @param HpIndex Return the index of root hot plug in global array.
168
169 @retval TRUE device path is for root pci hot plug controller.
170 @retval FALSE device path is not for root pci hot plug controller.
171 **/
172 BOOLEAN
173 IsRootPciHotPlugController (
174 IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
175 OUT UINTN *HpIndex
176 )
177 {
178 UINTN Index;
179
180 for (Index = 0; Index < gPciRootHpcCount; Index++) {
181
182 if (EfiCompareDevicePath (gPciRootHpcPool[Index].HpcDevicePath, HpcDevicePath)) {
183
184 if (HpIndex != NULL) {
185 *HpIndex = Index;
186 }
187
188 return TRUE;
189 }
190 }
191
192 return FALSE;
193 }
194
195 /**
196 Wrapper for creating event object for HPC
197
198 @param HpIndex index of hot plug device in global array.
199 @param Event event object.
200
201 @return status of create event invoken.
202 **/
203 EFI_STATUS
204 CreateEventForHpc (
205 IN UINTN HpIndex,
206 OUT EFI_EVENT *Event
207 )
208 {
209 EFI_STATUS Status;
210
211 Status = gBS->CreateEvent (
212 EVT_NOTIFY_SIGNAL,
213 TPL_CALLBACK,
214 PciHPCInitialized,
215 gPciRootHpcData + HpIndex,
216 &((gPciRootHpcData + HpIndex)->Event)
217 );
218
219 if (!EFI_ERROR (Status)) {
220 *Event = (gPciRootHpcData + HpIndex)->Event;
221 }
222
223 return Status;
224 }
225
226 /**
227 Wait for all root HPC initialized.
228
229 @param TimeoutInMicroSeconds microseconds to wait for all root hpc's initialization.
230 **/
231 EFI_STATUS
232 AllRootHPCInitialized (
233 IN UINTN TimeoutInMicroSeconds
234 )
235 {
236 UINT32 Delay;
237 UINTN Index;
238
239 Delay = (UINT32) ((TimeoutInMicroSeconds / 30) + 1);
240 do {
241
242 for (Index = 0; Index < gPciRootHpcCount; Index++) {
243
244 if (!gPciRootHpcData[Index].Initialized) {
245 break;
246 }
247 }
248
249 if (Index == gPciRootHpcCount) {
250 return EFI_SUCCESS;
251 }
252
253 //
254 // Stall for 30 us
255 //
256 gBS->Stall (30);
257
258 Delay--;
259
260 } while (Delay > 0);
261
262 return EFI_TIMEOUT;
263 }
264
265 /**
266 Check HPC capability register block
267
268 @param PciIoDevice PCI device instance.
269
270 @retval EFI_SUCCESS PCI device is HPC.
271 @retval EFI_NOT_FOUND PCI device is not HPC.
272 **/
273 EFI_STATUS
274 IsSHPC (
275 PCI_IO_DEVICE *PciIoDevice
276 )
277 {
278
279 EFI_STATUS Status;
280 UINT8 Offset;
281
282 if (PciIoDevice == NULL) {
283 return EFI_NOT_FOUND;
284 }
285
286 Offset = 0;
287 Status = LocateCapabilityRegBlock (
288 PciIoDevice,
289 EFI_PCI_CAPABILITY_ID_HOTPLUG,
290 &Offset,
291 NULL
292 );
293
294 //
295 // If the PPB has the hot plug controller build-in,
296 // then return TRUE;
297 //
298 if (!EFI_ERROR (Status)) {
299 return EFI_SUCCESS;
300 }
301
302 return EFI_NOT_FOUND;
303 }
304
305 /**
306 Get resource padding for hot plug bus
307
308 @param PciIoDevice PCI device instance
309
310 @retval EFI_SUCCESS success get padding and set it into PCI device instance
311 @retval EFI_NOT_FOUND PCI device is not a hot plug bus.
312 **/
313 EFI_STATUS
314 GetResourcePaddingForHpb (
315 IN PCI_IO_DEVICE *PciIoDevice
316 )
317 /**
318
319 Routine Description:
320
321 Arguments:
322
323 Returns:
324
325 None
326
327 **/
328 // TODO: PciIoDevice - add argument and description to function comment
329 // TODO: EFI_SUCCESS - add return value to function comment
330 // TODO: EFI_NOT_FOUND - add return value to function comment
331 {
332 EFI_STATUS Status;
333 EFI_HPC_STATE State;
334 UINT64 PciAddress;
335 EFI_HPC_PADDING_ATTRIBUTES Attributes;
336 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
337
338 Status = IsPciHotPlugBus (PciIoDevice);
339
340 if (!EFI_ERROR (Status)) {
341 PciAddress = EFI_PCI_ADDRESS (PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber, 0);
342 Status = gPciHotPlugInit->GetResourcePadding (
343 gPciHotPlugInit,
344 PciIoDevice->DevicePath,
345 PciAddress,
346 &State,
347 (VOID **) &Descriptors,
348 &Attributes
349 );
350
351 if (EFI_ERROR (Status)) {
352 return Status;
353 }
354
355 if ((State & EFI_HPC_STATE_ENABLED) != 0 && (State & EFI_HPC_STATE_INITIALIZED) != 0) {
356 PciIoDevice->ResourcePaddingDescriptors = Descriptors;
357 PciIoDevice->PaddingAttributes = Attributes;
358 }
359
360 return EFI_SUCCESS;
361 }
362
363 return EFI_NOT_FOUND;
364 }
365
366 /**
367 Test whether PCI device is hot plug bus.
368
369 @param PciIoDevice PCI device instance.
370
371 @retval EFI_SUCCESS PCI device is hot plug bus.
372 @retval EFI_NOT_FOUND PCI device is not hot plug bus.
373 **/
374 EFI_STATUS
375 IsPciHotPlugBus (
376 PCI_IO_DEVICE *PciIoDevice
377 )
378 {
379 BOOLEAN Result;
380 EFI_STATUS Status;
381
382 Status = IsSHPC (PciIoDevice);
383
384 //
385 // If the PPB has the hot plug controller build-in,
386 // then return TRUE;
387 //
388 if (!EFI_ERROR (Status)) {
389 return EFI_SUCCESS;
390 }
391
392 //
393 // Otherwise, see if it is a Root HPC
394 //
395 Result = IsRootPciHotPlugBus (PciIoDevice->DevicePath, NULL);
396
397 if (Result) {
398 return EFI_SUCCESS;
399 }
400
401 return EFI_NOT_FOUND;
402 }
403