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