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