]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciDeviceSupport.c
CommitLineData
9060e3ec 1/** @file\r
fcdfcdbf 2 Supporting functions implementation for PCI devices management.\r
9060e3ec 3\r
1f6785c4 4Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
07eba706 5(C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR>\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
9060e3ec 7\r
8**/\r
9\r
10#include "PciBus.h"\r
11\r
12//\r
13// This device structure is serviced as a header.\r
14// Its next field points to the first root bridge device node.\r
15//\r
16LIST_ENTRY mPciDevicePool;\r
17\r
18/**\r
19 Initialize the PCI devices pool.\r
20\r
21**/\r
22VOID\r
23InitializePciDevicePool (\r
24 VOID\r
25 )\r
26{\r
27 InitializeListHead (&mPciDevicePool);\r
28}\r
29\r
30/**\r
31 Insert a root bridge into PCI device pool.\r
32\r
33 @param RootBridge A pointer to the PCI_IO_DEVICE.\r
34\r
35**/\r
36VOID\r
37InsertRootBridge (\r
1436aea4 38 IN PCI_IO_DEVICE *RootBridge\r
9060e3ec 39 )\r
40{\r
41 InsertTailList (&mPciDevicePool, &(RootBridge->Link));\r
42}\r
43\r
44/**\r
45 This function is used to insert a PCI device node under\r
46 a bridge.\r
47\r
48 @param Bridge The PCI bridge.\r
49 @param PciDeviceNode The PCI device needs inserting.\r
50\r
51**/\r
52VOID\r
53InsertPciDevice (\r
1436aea4
MK
54 IN PCI_IO_DEVICE *Bridge,\r
55 IN PCI_IO_DEVICE *PciDeviceNode\r
9060e3ec 56 )\r
57{\r
58 InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));\r
59 PciDeviceNode->Parent = Bridge;\r
60}\r
61\r
62/**\r
fcdfcdbf 63 Destroy root bridge and remove it from device tree.\r
9060e3ec 64\r
65 @param RootBridge The bridge want to be removed.\r
66\r
67**/\r
68VOID\r
69DestroyRootBridge (\r
1436aea4 70 IN PCI_IO_DEVICE *RootBridge\r
9060e3ec 71 )\r
72{\r
73 DestroyPciDeviceTree (RootBridge);\r
74\r
75 FreePciDevice (RootBridge);\r
76}\r
77\r
78/**\r
79 Destroy a pci device node.\r
80\r
81 All direct or indirect allocated resource for this node will be freed.\r
82\r
fcdfcdbf 83 @param PciIoDevice A pointer to the PCI_IO_DEVICE to be destroyed.\r
9060e3ec 84\r
85**/\r
86VOID\r
87FreePciDevice (\r
1436aea4 88 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 89 )\r
90{\r
91 ASSERT (PciIoDevice != NULL);\r
92 //\r
93 // Assume all children have been removed underneath this device\r
94 //\r
95 if (PciIoDevice->ResourcePaddingDescriptors != NULL) {\r
96 FreePool (PciIoDevice->ResourcePaddingDescriptors);\r
97 }\r
98\r
99 if (PciIoDevice->DevicePath != NULL) {\r
100 FreePool (PciIoDevice->DevicePath);\r
101 }\r
102\r
07eba706
TP
103 if (PciIoDevice->BusNumberRanges != NULL) {\r
104 FreePool (PciIoDevice->BusNumberRanges);\r
105 }\r
106\r
9060e3ec 107 FreePool (PciIoDevice);\r
108}\r
109\r
110/**\r
111 Destroy all the pci device node under the bridge.\r
112 Bridge itself is not included.\r
113\r
114 @param Bridge A pointer to the PCI_IO_DEVICE.\r
115\r
116**/\r
117VOID\r
118DestroyPciDeviceTree (\r
1436aea4 119 IN PCI_IO_DEVICE *Bridge\r
9060e3ec 120 )\r
121{\r
1436aea4
MK
122 LIST_ENTRY *CurrentLink;\r
123 PCI_IO_DEVICE *Temp;\r
9060e3ec 124\r
125 while (!IsListEmpty (&Bridge->ChildList)) {\r
9060e3ec 126 CurrentLink = Bridge->ChildList.ForwardLink;\r
127\r
128 //\r
129 // Remove this node from the linked list\r
130 //\r
131 RemoveEntryList (CurrentLink);\r
132\r
133 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
134\r
135 if (!IsListEmpty (&Temp->ChildList)) {\r
136 DestroyPciDeviceTree (Temp);\r
137 }\r
138\r
139 FreePciDevice (Temp);\r
140 }\r
141}\r
142\r
143/**\r
144 Destroy all device nodes under the root bridge\r
145 specified by Controller.\r
146\r
147 The root bridge itself is also included.\r
148\r
149 @param Controller Root bridge handle.\r
150\r
fcdfcdbf 151 @retval EFI_SUCCESS Destroy all device nodes successfully.\r
9060e3ec 152 @retval EFI_NOT_FOUND Cannot find any PCI device under specified\r
153 root bridge.\r
154\r
155**/\r
156EFI_STATUS\r
157DestroyRootBridgeByHandle (\r
1436aea4 158 IN EFI_HANDLE Controller\r
9060e3ec 159 )\r
160{\r
1436aea4
MK
161 LIST_ENTRY *CurrentLink;\r
162 PCI_IO_DEVICE *Temp;\r
9060e3ec 163\r
164 CurrentLink = mPciDevicePool.ForwardLink;\r
165\r
166 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
167 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
168\r
169 if (Temp->Handle == Controller) {\r
9060e3ec 170 RemoveEntryList (CurrentLink);\r
171\r
172 DestroyPciDeviceTree (Temp);\r
173\r
174 FreePciDevice (Temp);\r
175\r
176 return EFI_SUCCESS;\r
177 }\r
178\r
179 CurrentLink = CurrentLink->ForwardLink;\r
180 }\r
181\r
182 return EFI_NOT_FOUND;\r
183}\r
184\r
185/**\r
186 This function registers the PCI IO device.\r
187\r
188 It creates a handle for this PCI IO device (if the handle does not exist), attaches\r
189 appropriate protocols onto the handle, does necessary initialization, and sets up\r
190 parent/child relationship with its bus controller.\r
191\r
192 @param Controller An EFI handle for the PCI bus controller.\r
193 @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered.\r
194 @param Handle A pointer to hold the returned EFI handle for the PCI IO device.\r
195\r
196 @retval EFI_SUCCESS The PCI device is successfully registered.\r
197 @retval other An error occurred when registering the PCI device.\r
198\r
199**/\r
200EFI_STATUS\r
201RegisterPciDevice (\r
1436aea4
MK
202 IN EFI_HANDLE Controller,\r
203 IN PCI_IO_DEVICE *PciIoDevice,\r
204 OUT EFI_HANDLE *Handle OPTIONAL\r
9060e3ec 205 )\r
206{\r
1436aea4
MK
207 EFI_STATUS Status;\r
208 VOID *PlatformOpRomBuffer;\r
209 UINTN PlatformOpRomSize;\r
210 EFI_PCI_IO_PROTOCOL *PciIo;\r
211 UINT8 Data8;\r
212 BOOLEAN HasEfiImage;\r
9060e3ec 213\r
214 //\r
215 // Install the pciio protocol, device path protocol\r
216 //\r
217 Status = gBS->InstallMultipleProtocolInterfaces (\r
218 &PciIoDevice->Handle,\r
219 &gEfiDevicePathProtocolGuid,\r
220 PciIoDevice->DevicePath,\r
221 &gEfiPciIoProtocolGuid,\r
222 &PciIoDevice->PciIo,\r
223 NULL\r
224 );\r
225 if (EFI_ERROR (Status)) {\r
226 return Status;\r
227 }\r
228\r
9060e3ec 229 //\r
230 // Force Interrupt line to "Unknown" or "No Connection"\r
231 //\r
232 PciIo = &(PciIoDevice->PciIo);\r
233 Data8 = PCI_INT_LINE_UNKNOWN;\r
234 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);\r
d1102dba 235\r
9060e3ec 236 //\r
237 // Process OpRom\r
238 //\r
239 if (!PciIoDevice->AllOpRomProcessed) {\r
9060e3ec 240 //\r
241 // Get the OpRom provided by platform\r
242 //\r
243 if (gPciPlatformProtocol != NULL) {\r
244 Status = gPciPlatformProtocol->GetPciRom (\r
245 gPciPlatformProtocol,\r
246 PciIoDevice->Handle,\r
247 &PlatformOpRomBuffer,\r
248 &PlatformOpRomSize\r
249 );\r
250 if (!EFI_ERROR (Status)) {\r
4ed4e19c 251 PciIoDevice->EmbeddedRom = FALSE;\r
1436aea4 252 PciIoDevice->RomSize = (UINT32)PlatformOpRomSize;\r
9060e3ec 253 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;\r
254 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;\r
255 //\r
256 // For OpROM read from gPciPlatformProtocol:\r
257 // Add the Rom Image to internal database for later PCI light enumeration\r
258 //\r
259 PciRomAddImageMapping (\r
260 NULL,\r
261 PciIoDevice->PciRootBridgeIo->SegmentNumber,\r
262 PciIoDevice->BusNumber,\r
263 PciIoDevice->DeviceNumber,\r
264 PciIoDevice->FunctionNumber,\r
221c8fd5 265 PciIoDevice->PciIo.RomImage,\r
9060e3ec 266 PciIoDevice->PciIo.RomSize\r
267 );\r
268 }\r
269 } else if (gPciOverrideProtocol != NULL) {\r
270 Status = gPciOverrideProtocol->GetPciRom (\r
271 gPciOverrideProtocol,\r
272 PciIoDevice->Handle,\r
273 &PlatformOpRomBuffer,\r
274 &PlatformOpRomSize\r
275 );\r
276 if (!EFI_ERROR (Status)) {\r
4ed4e19c 277 PciIoDevice->EmbeddedRom = FALSE;\r
1436aea4 278 PciIoDevice->RomSize = (UINT32)PlatformOpRomSize;\r
9060e3ec 279 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;\r
280 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;\r
281 //\r
282 // For OpROM read from gPciOverrideProtocol:\r
283 // Add the Rom Image to internal database for later PCI light enumeration\r
284 //\r
285 PciRomAddImageMapping (\r
286 NULL,\r
287 PciIoDevice->PciRootBridgeIo->SegmentNumber,\r
288 PciIoDevice->BusNumber,\r
289 PciIoDevice->DeviceNumber,\r
290 PciIoDevice->FunctionNumber,\r
221c8fd5 291 PciIoDevice->PciIo.RomImage,\r
9060e3ec 292 PciIoDevice->PciIo.RomSize\r
293 );\r
d1102dba 294 }\r
9060e3ec 295 }\r
296 }\r
297\r
483d0d85
RN
298 //\r
299 // Determine if there are EFI images in the option rom\r
300 //\r
301 HasEfiImage = ContainEfiImage (PciIoDevice->PciIo.RomImage, PciIoDevice->PciIo.RomSize);\r
302\r
303 if (HasEfiImage) {\r
9060e3ec 304 Status = gBS->InstallMultipleProtocolInterfaces (\r
305 &PciIoDevice->Handle,\r
306 &gEfiLoadFile2ProtocolGuid,\r
307 &PciIoDevice->LoadFile2,\r
308 NULL\r
309 );\r
310 if (EFI_ERROR (Status)) {\r
311 gBS->UninstallMultipleProtocolInterfaces (\r
9388c6b1 312 PciIoDevice->Handle,\r
9060e3ec 313 &gEfiDevicePathProtocolGuid,\r
314 PciIoDevice->DevicePath,\r
315 &gEfiPciIoProtocolGuid,\r
316 &PciIoDevice->PciIo,\r
317 NULL\r
318 );\r
319 return Status;\r
320 }\r
321 }\r
322\r
9060e3ec 323 if (!PciIoDevice->AllOpRomProcessed) {\r
9060e3ec 324 PciIoDevice->AllOpRomProcessed = TRUE;\r
325\r
326 //\r
327 // Dispatch the EFI OpRom for the PCI device.\r
328 // The OpRom is got from platform in the above code\r
329 // or loaded from device in the previous round of bus enumeration\r
330 //\r
483d0d85 331 if (HasEfiImage) {\r
9060e3ec 332 ProcessOpRomImage (PciIoDevice);\r
333 }\r
334 }\r
335\r
336 if (PciIoDevice->BusOverride) {\r
337 //\r
338 // Install Bus Specific Driver Override Protocol\r
339 //\r
340 Status = gBS->InstallMultipleProtocolInterfaces (\r
341 &PciIoDevice->Handle,\r
342 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
343 &PciIoDevice->PciDriverOverride,\r
344 NULL\r
345 );\r
346 if (EFI_ERROR (Status)) {\r
347 gBS->UninstallMultipleProtocolInterfaces (\r
9388c6b1 348 PciIoDevice->Handle,\r
9060e3ec 349 &gEfiDevicePathProtocolGuid,\r
350 PciIoDevice->DevicePath,\r
351 &gEfiPciIoProtocolGuid,\r
352 &PciIoDevice->PciIo,\r
353 NULL\r
354 );\r
483d0d85 355 if (HasEfiImage) {\r
9060e3ec 356 gBS->UninstallMultipleProtocolInterfaces (\r
9388c6b1 357 PciIoDevice->Handle,\r
9060e3ec 358 &gEfiLoadFile2ProtocolGuid,\r
359 &PciIoDevice->LoadFile2,\r
360 NULL\r
361 );\r
362 }\r
363\r
364 return Status;\r
365 }\r
366 }\r
367\r
368 Status = gBS->OpenProtocol (\r
369 Controller,\r
370 &gEfiPciRootBridgeIoProtocolGuid,\r
1436aea4 371 (VOID **)&(PciIoDevice->PciRootBridgeIo),\r
9060e3ec 372 gPciBusDriverBinding.DriverBindingHandle,\r
373 PciIoDevice->Handle,\r
374 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
375 );\r
376 if (EFI_ERROR (Status)) {\r
377 return Status;\r
378 }\r
379\r
380 if (Handle != NULL) {\r
381 *Handle = PciIoDevice->Handle;\r
382 }\r
383\r
384 //\r
385 // Indicate the pci device is registered\r
386 //\r
387 PciIoDevice->Registered = TRUE;\r
388\r
389 return EFI_SUCCESS;\r
390}\r
391\r
392/**\r
393 This function is used to remove the whole PCI devices on the specified bridge from\r
394 the root bridge.\r
395\r
396 @param RootBridgeHandle The root bridge device handle.\r
397 @param Bridge The bridge device to be removed.\r
398\r
399**/\r
400VOID\r
401RemoveAllPciDeviceOnBridge (\r
1436aea4
MK
402 EFI_HANDLE RootBridgeHandle,\r
403 PCI_IO_DEVICE *Bridge\r
9060e3ec 404 )\r
405{\r
1436aea4
MK
406 LIST_ENTRY *CurrentLink;\r
407 PCI_IO_DEVICE *Temp;\r
9060e3ec 408\r
409 while (!IsListEmpty (&Bridge->ChildList)) {\r
9060e3ec 410 CurrentLink = Bridge->ChildList.ForwardLink;\r
411 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
412\r
413 //\r
414 // Check if the current node has been deregistered before\r
415 // If it is not, then deregister it\r
416 //\r
417 if (Temp->Registered) {\r
418 DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);\r
419 }\r
420\r
421 //\r
422 // Remove this node from the linked list\r
423 //\r
424 RemoveEntryList (CurrentLink);\r
425\r
426 if (!IsListEmpty (&Temp->ChildList)) {\r
427 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);\r
428 }\r
429\r
430 FreePciDevice (Temp);\r
431 }\r
432}\r
433\r
434/**\r
435 This function is used to de-register the PCI IO device.\r
436\r
437 That includes un-installing PciIo protocol from the specified PCI\r
438 device handle.\r
439\r
440 @param Controller An EFI handle for the PCI bus controller.\r
441 @param Handle PCI device handle.\r
442\r
443 @retval EFI_SUCCESS The PCI device is successfully de-registered.\r
444 @retval other An error occurred when de-registering the PCI device.\r
445\r
446**/\r
447EFI_STATUS\r
448DeRegisterPciDevice (\r
1436aea4
MK
449 IN EFI_HANDLE Controller,\r
450 IN EFI_HANDLE Handle\r
9060e3ec 451 )\r
452\r
453{\r
1436aea4
MK
454 EFI_PCI_IO_PROTOCOL *PciIo;\r
455 EFI_STATUS Status;\r
456 PCI_IO_DEVICE *PciIoDevice;\r
457 PCI_IO_DEVICE *Node;\r
458 LIST_ENTRY *CurrentLink;\r
459 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
9060e3ec 460\r
461 Status = gBS->OpenProtocol (\r
462 Handle,\r
463 &gEfiPciIoProtocolGuid,\r
1436aea4 464 (VOID **)&PciIo,\r
9060e3ec 465 gPciBusDriverBinding.DriverBindingHandle,\r
466 Controller,\r
467 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
468 );\r
469 if (!EFI_ERROR (Status)) {\r
470 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
471\r
472 //\r
473 // If it is already de-registered\r
474 //\r
475 if (!PciIoDevice->Registered) {\r
476 return EFI_SUCCESS;\r
477 }\r
478\r
479 //\r
480 // If it is PPB, first de-register its children\r
481 //\r
482\r
483 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
9060e3ec 484 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
485\r
486 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1436aea4
MK
487 Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
488 Status = DeRegisterPciDevice (Controller, Node->Handle);\r
9060e3ec 489\r
490 if (EFI_ERROR (Status)) {\r
491 return Status;\r
492 }\r
493\r
494 CurrentLink = CurrentLink->ForwardLink;\r
495 }\r
496 }\r
497\r
498 //\r
499 // Close the child handle\r
500 //\r
501 Status = gBS->CloseProtocol (\r
502 Controller,\r
503 &gEfiPciRootBridgeIoProtocolGuid,\r
504 gPciBusDriverBinding.DriverBindingHandle,\r
505 Handle\r
506 );\r
507\r
508 //\r
509 // Un-install the Device Path protocol and PCI I/O protocol\r
510 // and Bus Specific Driver Override protocol if needed.\r
511 //\r
512 if (PciIoDevice->BusOverride) {\r
513 Status = gBS->UninstallMultipleProtocolInterfaces (\r
514 Handle,\r
515 &gEfiDevicePathProtocolGuid,\r
516 PciIoDevice->DevicePath,\r
517 &gEfiPciIoProtocolGuid,\r
518 &PciIoDevice->PciIo,\r
519 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
520 &PciIoDevice->PciDriverOverride,\r
521 NULL\r
522 );\r
523 } else {\r
524 Status = gBS->UninstallMultipleProtocolInterfaces (\r
525 Handle,\r
526 &gEfiDevicePathProtocolGuid,\r
527 PciIoDevice->DevicePath,\r
528 &gEfiPciIoProtocolGuid,\r
529 &PciIoDevice->PciIo,\r
530 NULL\r
531 );\r
532 }\r
533\r
534 if (!EFI_ERROR (Status)) {\r
535 //\r
536 // Try to uninstall LoadFile2 protocol if exists\r
537 //\r
538 Status = gBS->OpenProtocol (\r
539 Handle,\r
540 &gEfiLoadFile2ProtocolGuid,\r
541 NULL,\r
542 gPciBusDriverBinding.DriverBindingHandle,\r
543 Controller,\r
544 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
545 );\r
546 if (!EFI_ERROR (Status)) {\r
547 Status = gBS->UninstallMultipleProtocolInterfaces (\r
548 Handle,\r
549 &gEfiLoadFile2ProtocolGuid,\r
550 &PciIoDevice->LoadFile2,\r
551 NULL\r
552 );\r
553 }\r
1436aea4 554\r
9060e3ec 555 //\r
556 // Restore Status\r
557 //\r
558 Status = EFI_SUCCESS;\r
559 }\r
560\r
9060e3ec 561 if (EFI_ERROR (Status)) {\r
562 gBS->OpenProtocol (\r
1436aea4
MK
563 Controller,\r
564 &gEfiPciRootBridgeIoProtocolGuid,\r
565 (VOID **)&PciRootBridgeIo,\r
566 gPciBusDriverBinding.DriverBindingHandle,\r
567 Handle,\r
568 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
569 );\r
9060e3ec 570 return Status;\r
571 }\r
572\r
573 //\r
574 // The Device Driver should disable this device after disconnect\r
575 // so the Pci Bus driver will not touch this device any more.\r
576 // Restore the register field to the original value\r
577 //\r
578 PciIoDevice->Registered = FALSE;\r
579 PciIoDevice->Handle = NULL;\r
580 } else {\r
9060e3ec 581 //\r
582 // Handle may be closed before\r
583 //\r
584 return EFI_SUCCESS;\r
585 }\r
586\r
587 return EFI_SUCCESS;\r
588}\r
589\r
590/**\r
591 Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge.\r
592\r
593 @param Controller The root bridge handle.\r
594 @param RootBridge A pointer to the PCI_IO_DEVICE.\r
595 @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
596 @param NumberOfChildren Children number.\r
597 @param ChildHandleBuffer A pointer to the child handle buffer.\r
598\r
599 @retval EFI_NOT_READY Device is not allocated.\r
600 @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.\r
601 @retval EFI_NOT_FOUND Can not find the specific device.\r
602 @retval EFI_SUCCESS Success to start Pci devices on bridge.\r
603\r
604**/\r
605EFI_STATUS\r
606StartPciDevicesOnBridge (\r
1436aea4
MK
607 IN EFI_HANDLE Controller,\r
608 IN PCI_IO_DEVICE *RootBridge,\r
609 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
610 IN OUT UINT8 *NumberOfChildren,\r
611 IN OUT EFI_HANDLE *ChildHandleBuffer\r
9060e3ec 612 )\r
613\r
614{\r
615 PCI_IO_DEVICE *PciIoDevice;\r
616 EFI_DEV_PATH_PTR Node;\r
617 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
618 EFI_STATUS Status;\r
619 LIST_ENTRY *CurrentLink;\r
620 UINT64 Supports;\r
621\r
622 PciIoDevice = NULL;\r
623 CurrentLink = RootBridge->ChildList.ForwardLink;\r
624\r
625 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
9060e3ec 626 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
627 if (RemainingDevicePath != NULL) {\r
9060e3ec 628 Node.DevPath = RemainingDevicePath;\r
629\r
1436aea4
MK
630 if ((Node.Pci->Device != PciIoDevice->DeviceNumber) ||\r
631 (Node.Pci->Function != PciIoDevice->FunctionNumber))\r
632 {\r
9060e3ec 633 CurrentLink = CurrentLink->ForwardLink;\r
634 continue;\r
635 }\r
636\r
637 //\r
638 // Check if the device has been assigned with required resource\r
639 //\r
640 if (!PciIoDevice->Allocated) {\r
641 return EFI_NOT_READY;\r
642 }\r
643\r
644 //\r
645 // Check if the current node has been registered before\r
646 // If it is not, register it\r
647 //\r
648 if (!PciIoDevice->Registered) {\r
649 Status = RegisterPciDevice (\r
650 Controller,\r
651 PciIoDevice,\r
652 NULL\r
653 );\r
9060e3ec 654 }\r
655\r
1436aea4 656 if ((NumberOfChildren != NULL) && (ChildHandleBuffer != NULL) && PciIoDevice->Registered) {\r
9060e3ec 657 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
658 (*NumberOfChildren)++;\r
659 }\r
660\r
661 //\r
662 // Get the next device path\r
663 //\r
664 CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);\r
665 if (IsDevicePathEnd (CurrentDevicePath)) {\r
666 return EFI_SUCCESS;\r
667 }\r
668\r
669 //\r
670 // If it is a PPB\r
671 //\r
13fd0d50 672 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
9060e3ec 673 Status = StartPciDevicesOnBridge (\r
674 Controller,\r
675 PciIoDevice,\r
676 CurrentDevicePath,\r
677 NumberOfChildren,\r
678 ChildHandleBuffer\r
679 );\r
680\r
681 PciIoDevice->PciIo.Attributes (\r
682 &(PciIoDevice->PciIo),\r
683 EfiPciIoAttributeOperationSupported,\r
684 0,\r
685 &Supports\r
686 );\r
a8035b90 687 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
9060e3ec 688 PciIoDevice->PciIo.Attributes (\r
689 &(PciIoDevice->PciIo),\r
690 EfiPciIoAttributeOperationEnable,\r
691 Supports,\r
692 NULL\r
693 );\r
694\r
695 return Status;\r
696 } else {\r
9060e3ec 697 //\r
698 // Currently, the PCI bus driver only support PCI-PCI bridge\r
699 //\r
700 return EFI_UNSUPPORTED;\r
701 }\r
9060e3ec 702 } else {\r
9060e3ec 703 //\r
704 // If remaining device path is NULL,\r
705 // try to enable all the pci devices under this bridge\r
706 //\r
707 if (!PciIoDevice->Registered && PciIoDevice->Allocated) {\r
708 Status = RegisterPciDevice (\r
709 Controller,\r
710 PciIoDevice,\r
711 NULL\r
712 );\r
9060e3ec 713 }\r
714\r
1436aea4 715 if ((NumberOfChildren != NULL) && (ChildHandleBuffer != NULL) && PciIoDevice->Registered) {\r
9060e3ec 716 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
717 (*NumberOfChildren)++;\r
718 }\r
719\r
13fd0d50 720 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
9060e3ec 721 Status = StartPciDevicesOnBridge (\r
722 Controller,\r
723 PciIoDevice,\r
724 RemainingDevicePath,\r
725 NumberOfChildren,\r
726 ChildHandleBuffer\r
727 );\r
728\r
729 PciIoDevice->PciIo.Attributes (\r
730 &(PciIoDevice->PciIo),\r
731 EfiPciIoAttributeOperationSupported,\r
732 0,\r
733 &Supports\r
734 );\r
a8035b90 735 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;\r
9060e3ec 736 PciIoDevice->PciIo.Attributes (\r
737 &(PciIoDevice->PciIo),\r
738 EfiPciIoAttributeOperationEnable,\r
739 Supports,\r
740 NULL\r
741 );\r
9060e3ec 742 }\r
743\r
744 CurrentLink = CurrentLink->ForwardLink;\r
745 }\r
746 }\r
747\r
748 if (PciIoDevice == NULL) {\r
749 return EFI_NOT_FOUND;\r
750 } else {\r
751 return EFI_SUCCESS;\r
752 }\r
753}\r
754\r
755/**\r
756 Start to manage all the PCI devices it found previously under\r
757 the entire host bridge.\r
758\r
759 @param Controller The root bridge handle.\r
760\r
761 @retval EFI_NOT_READY Device is not allocated.\r
762 @retval EFI_SUCCESS Success to start Pci device on host bridge.\r
763\r
764**/\r
765EFI_STATUS\r
766StartPciDevices (\r
1436aea4 767 IN EFI_HANDLE Controller\r
9060e3ec 768 )\r
769{\r
1436aea4
MK
770 PCI_IO_DEVICE *RootBridge;\r
771 EFI_HANDLE ThisHostBridge;\r
772 LIST_ENTRY *CurrentLink;\r
9060e3ec 773\r
774 RootBridge = GetRootBridgeByHandle (Controller);\r
775 ASSERT (RootBridge != NULL);\r
776 ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;\r
777\r
778 CurrentLink = mPciDevicePool.ForwardLink;\r
779\r
780 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
9060e3ec 781 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
782 //\r
783 // Locate the right root bridge to start\r
784 //\r
785 if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {\r
786 StartPciDevicesOnBridge (\r
1436aea4
MK
787 RootBridge->Handle,\r
788 RootBridge,\r
789 NULL,\r
790 NULL,\r
791 NULL\r
792 );\r
9060e3ec 793 }\r
794\r
795 CurrentLink = CurrentLink->ForwardLink;\r
796 }\r
797\r
798 return EFI_SUCCESS;\r
799}\r
800\r
801/**\r
802 Create root bridge device.\r
803\r
fcdfcdbf 804 @param RootBridgeHandle Specified root bridge handle.\r
9060e3ec 805\r
806 @return The crated root bridge device instance, NULL means no\r
807 root bridge device instance created.\r
808\r
809**/\r
810PCI_IO_DEVICE *\r
811CreateRootBridge (\r
1436aea4 812 IN EFI_HANDLE RootBridgeHandle\r
9060e3ec 813 )\r
814{\r
1436aea4
MK
815 EFI_STATUS Status;\r
816 PCI_IO_DEVICE *Dev;\r
817 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
818 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
9060e3ec 819\r
820 Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
821 if (Dev == NULL) {\r
822 return NULL;\r
823 }\r
824\r
1436aea4
MK
825 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;\r
826 Dev->Handle = RootBridgeHandle;\r
9060e3ec 827 InitializeListHead (&Dev->ChildList);\r
828\r
829 Status = gBS->OpenProtocol (\r
830 RootBridgeHandle,\r
831 &gEfiDevicePathProtocolGuid,\r
1436aea4 832 (VOID **)&ParentDevicePath,\r
9060e3ec 833 gPciBusDriverBinding.DriverBindingHandle,\r
834 RootBridgeHandle,\r
835 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
836 );\r
837\r
838 if (EFI_ERROR (Status)) {\r
839 FreePool (Dev);\r
840 return NULL;\r
841 }\r
842\r
843 //\r
844 // Record the root bridge parent device path\r
845 //\r
846 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);\r
847\r
848 //\r
849 // Get the pci root bridge io protocol\r
850 //\r
851 Status = gBS->OpenProtocol (\r
852 RootBridgeHandle,\r
853 &gEfiPciRootBridgeIoProtocolGuid,\r
1436aea4 854 (VOID **)&PciRootBridgeIo,\r
9060e3ec 855 gPciBusDriverBinding.DriverBindingHandle,\r
856 RootBridgeHandle,\r
857 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
858 );\r
859\r
860 if (EFI_ERROR (Status)) {\r
861 FreePciDevice (Dev);\r
862 return NULL;\r
863 }\r
864\r
865 Dev->PciRootBridgeIo = PciRootBridgeIo;\r
866\r
867 //\r
868 // Initialize the PCI I/O instance structure\r
869 //\r
870 InitializePciIoInstance (Dev);\r
871 InitializePciDriverOverrideInstance (Dev);\r
872 InitializePciLoadFile2 (Dev);\r
873\r
874 //\r
875 // Initialize reserved resource list and\r
876 // option rom driver list\r
877 //\r
878 InitializeListHead (&Dev->ReservedResourceList);\r
879 InitializeListHead (&Dev->OptionRomDriverList);\r
880\r
881 return Dev;\r
882}\r
883\r
884/**\r
885 Get root bridge device instance by specific root bridge handle.\r
886\r
887 @param RootBridgeHandle Given root bridge handle.\r
888\r
889 @return The root bridge device instance, NULL means no root bridge\r
890 device instance found.\r
891\r
892**/\r
893PCI_IO_DEVICE *\r
894GetRootBridgeByHandle (\r
1436aea4 895 EFI_HANDLE RootBridgeHandle\r
9060e3ec 896 )\r
897{\r
1436aea4
MK
898 PCI_IO_DEVICE *RootBridgeDev;\r
899 LIST_ENTRY *CurrentLink;\r
9060e3ec 900\r
901 CurrentLink = mPciDevicePool.ForwardLink;\r
902\r
903 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
9060e3ec 904 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
905 if (RootBridgeDev->Handle == RootBridgeHandle) {\r
906 return RootBridgeDev;\r
907 }\r
908\r
909 CurrentLink = CurrentLink->ForwardLink;\r
910 }\r
911\r
912 return NULL;\r
913}\r
914\r
915/**\r
fcdfcdbf 916 Judge whether Pci device existed.\r
9060e3ec 917\r
fcdfcdbf 918 @param Bridge Parent bridge instance.\r
9060e3ec 919 @param PciIoDevice Device instance.\r
920\r
921 @retval TRUE Pci device existed.\r
922 @retval FALSE Pci device did not exist.\r
923\r
924**/\r
925BOOLEAN\r
926PciDeviceExisted (\r
1436aea4
MK
927 IN PCI_IO_DEVICE *Bridge,\r
928 IN PCI_IO_DEVICE *PciIoDevice\r
9060e3ec 929 )\r
930{\r
1436aea4
MK
931 PCI_IO_DEVICE *Temp;\r
932 LIST_ENTRY *CurrentLink;\r
9060e3ec 933\r
934 CurrentLink = Bridge->ChildList.ForwardLink;\r
935\r
936 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
9060e3ec 937 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
938\r
939 if (Temp == PciIoDevice) {\r
940 return TRUE;\r
941 }\r
942\r
943 if (!IsListEmpty (&Temp->ChildList)) {\r
944 if (PciDeviceExisted (Temp, PciIoDevice)) {\r
945 return TRUE;\r
946 }\r
947 }\r
948\r
949 CurrentLink = CurrentLink->ForwardLink;\r
950 }\r
951\r
952 return FALSE;\r
953}\r
954\r
955/**\r
983f5abb 956 Get the active VGA device on the specified Host Bridge.\r
9060e3ec 957\r
983f5abb 958 @param HostBridgeHandle Host Bridge handle.\r
9060e3ec 959\r
983f5abb 960 @return The active VGA device on the specified Host Bridge.\r
9060e3ec 961\r
962**/\r
963PCI_IO_DEVICE *\r
983f5abb 964LocateVgaDeviceOnHostBridge (\r
1436aea4 965 IN EFI_HANDLE HostBridgeHandle\r
9060e3ec 966 )\r
967{\r
1436aea4
MK
968 LIST_ENTRY *CurrentLink;\r
969 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 970\r
971 CurrentLink = mPciDevicePool.ForwardLink;\r
972\r
973 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
983f5abb 974 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
9060e3ec 975\r
1436aea4 976 if (PciIoDevice->PciRootBridgeIo->ParentHandle == HostBridgeHandle) {\r
983f5abb 977 PciIoDevice = LocateVgaDevice (PciIoDevice);\r
9060e3ec 978\r
983f5abb
RN
979 if (PciIoDevice != NULL) {\r
980 return PciIoDevice;\r
9060e3ec 981 }\r
982 }\r
983\r
984 CurrentLink = CurrentLink->ForwardLink;\r
985 }\r
986\r
987 return NULL;\r
988}\r
989\r
990/**\r
06da1e31 991 Locate the active VGA device under the bridge.\r
9060e3ec 992\r
06da1e31 993 @param Bridge PCI IO instance for the bridge.\r
9060e3ec 994\r
995 @return The active VGA device.\r
996\r
997**/\r
998PCI_IO_DEVICE *\r
06da1e31 999LocateVgaDevice (\r
1436aea4 1000 IN PCI_IO_DEVICE *Bridge\r
9060e3ec 1001 )\r
1002{\r
1436aea4
MK
1003 LIST_ENTRY *CurrentLink;\r
1004 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 1005\r
06da1e31 1006 CurrentLink = Bridge->ChildList.ForwardLink;\r
9060e3ec 1007\r
06da1e31 1008 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
06da1e31 1009 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
9060e3ec 1010\r
1436aea4
MK
1011 if (IS_PCI_VGA (&PciIoDevice->Pci) &&\r
1012 ((PciIoDevice->Attributes &\r
1013 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |\r
1014 EFI_PCI_IO_ATTRIBUTE_VGA_IO |\r
1015 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0))\r
1016 {\r
06da1e31 1017 return PciIoDevice;\r
9060e3ec 1018 }\r
1019\r
06da1e31 1020 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
06da1e31 1021 PciIoDevice = LocateVgaDevice (PciIoDevice);\r
9060e3ec 1022\r
06da1e31
RN
1023 if (PciIoDevice != NULL) {\r
1024 return PciIoDevice;\r
9060e3ec 1025 }\r
1026 }\r
1027\r
1028 CurrentLink = CurrentLink->ForwardLink;\r
1029 }\r
1030\r
1031 return NULL;\r
1032}\r