1 /*++
2 
3 Copyright (c) 2005 - 2006, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13 
14   PciDeviceSupport.c
15 
16 Abstract:
17 
18   This file provides routine to support Pci device node manipulation
19 
20 Revision History
21 
22 --*/
23 
24 #include "PciBus.h"
25 
26 //
27 // This device structure is serviced as a header.
28 // Its Next field points to the first root bridge device node
29 //
30 LIST_ENTRY  gPciDevicePool;
31 
32 EFI_STATUS
InitializePciDevicePool(VOID)33 InitializePciDevicePool (
34   VOID
35   )
36 /*++
37 
38 Routine Description:
39 
40   Initialize the gPciDevicePool
41 
42 Arguments:
43 
44 Returns:
45 
46   None
47 
48 --*/
49 {
50   InitializeListHead (&gPciDevicePool);
51 
52   return EFI_SUCCESS;
53 }
54 
55 EFI_STATUS
InsertRootBridge(IN PCI_IO_DEVICE * RootBridge)56 InsertRootBridge (
57   IN PCI_IO_DEVICE *RootBridge
58   )
59 /*++
60 
61 Routine Description:
62 
63   Insert a root bridge into PCI device pool
64 
65 Arguments:
66 
67   RootBridge    - A pointer to the PCI_IO_DEVICE.
68 
69 Returns:
70 
71   None
72 
73 --*/
74 {
75   InsertTailList (&gPciDevicePool, &(RootBridge->Link));
76 
77   return EFI_SUCCESS;
78 }
79 
80 EFI_STATUS
InsertPciDevice(PCI_IO_DEVICE * Bridge,PCI_IO_DEVICE * PciDeviceNode)81 InsertPciDevice (
82   PCI_IO_DEVICE *Bridge,
83   PCI_IO_DEVICE *PciDeviceNode
84   )
85 /*++
86 
87 Routine Description:
88 
89   This function is used to insert a PCI device node under
90   a bridge
91 
92 Arguments:
93   Bridge        - A pointer to the PCI_IO_DEVICE.
94   PciDeviceNode - A pointer to the PCI_IO_DEVICE.
95 
96 Returns:
97 
98   None
99 
100 --*/
101 
102 {
103 
104   InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));
105   PciDeviceNode->Parent = Bridge;
106 
107   return EFI_SUCCESS;
108 }
109 
110 EFI_STATUS
DestroyRootBridge(IN PCI_IO_DEVICE * RootBridge)111 DestroyRootBridge (
112   IN PCI_IO_DEVICE *RootBridge
113   )
114 /*++
115 
116 Routine Description:
117 
118 
119 Arguments:
120 
121   RootBridge   - A pointer to the PCI_IO_DEVICE.
122 
123 Returns:
124 
125   None
126 
127 --*/
128 {
129   DestroyPciDeviceTree (RootBridge);
130 
131   gBS->FreePool (RootBridge);
132 
133   return EFI_SUCCESS;
134 }
135 
136 EFI_STATUS
DestroyPciDeviceTree(IN PCI_IO_DEVICE * Bridge)137 DestroyPciDeviceTree (
138   IN PCI_IO_DEVICE *Bridge
139   )
140 /*++
141 
142 Routine Description:
143 
144   Destroy all the pci device node under the bridge.
145   Bridge itself is not included.
146 
147 Arguments:
148 
149   Bridge   - A pointer to the PCI_IO_DEVICE.
150 
151 Returns:
152 
153   None
154 
155 --*/
156 {
157   LIST_ENTRY  *CurrentLink;
158   PCI_IO_DEVICE   *Temp;
159 
160   while (!IsListEmpty (&Bridge->ChildList)) {
161 
162     CurrentLink = Bridge->ChildList.ForwardLink;
163 
164     //
165     // Remove this node from the linked list
166     //
167     RemoveEntryList (CurrentLink);
168 
169     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
170 
171     if (IS_PCI_BRIDGE (&(Temp->Pci))) {
172       DestroyPciDeviceTree (Temp);
173     }
174     gBS->FreePool (Temp);
175   }
176 
177   return EFI_SUCCESS;
178 }
179 
180 EFI_STATUS
DestroyRootBridgeByHandle(EFI_HANDLE Controller)181 DestroyRootBridgeByHandle (
182   EFI_HANDLE Controller
183   )
184 /*++
185 
186 Routine Description:
187 
188   Destroy all device nodes under the root bridge
189   specified by Controller.
190   The root bridge itself is also included.
191 
192 Arguments:
193 
194   Controller   - An efi handle.
195 
196 Returns:
197 
198   None
199 
200 --*/
201 {
202 
203   LIST_ENTRY  *CurrentLink;
204   PCI_IO_DEVICE   *Temp;
205 
206   CurrentLink = gPciDevicePool.ForwardLink;
207 
208   while (CurrentLink && CurrentLink != &gPciDevicePool) {
209     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
210 
211     if (Temp->Handle == Controller) {
212 
213       RemoveEntryList (CurrentLink);
214 
215       DestroyPciDeviceTree (Temp);
216 
217       gBS->FreePool(Temp);
218 
219       return EFI_SUCCESS;
220     }
221 
222     CurrentLink = CurrentLink->ForwardLink;
223   }
224 
225   return EFI_NOT_FOUND;
226 }
227 
228 EFI_STATUS
RegisterPciDevice(IN EFI_HANDLE Controller,IN PCI_IO_DEVICE * PciIoDevice,OUT EFI_HANDLE * Handle OPTIONAL)229 RegisterPciDevice (
230   IN  EFI_HANDLE                     Controller,
231   IN  PCI_IO_DEVICE                  *PciIoDevice,
232   OUT EFI_HANDLE                     *Handle OPTIONAL
233   )
234 /*++
235 
236 Routine Description:
237 
238   This function registers the PCI IO device. It creates a handle for this PCI IO device
239   (if the handle does not exist), attaches appropriate protocols onto the handle, does
240   necessary initialization, and sets up parent/child relationship with its bus controller.
241 
242 Arguments:
243 
244   Controller    - An EFI handle for the PCI bus controller.
245   PciIoDevice   - A PCI_IO_DEVICE pointer to the PCI IO device to be registered.
246   Handle        - A pointer to hold the EFI handle for the PCI IO device.
247 
248 Returns:
249 
250   EFI_SUCCESS   - The PCI device is successfully registered.
251   Others        - An error occurred when registering the PCI device.
252 
253 --*/
254 {
255   EFI_STATUS          Status;
256   UINT8               PciExpressCapRegOffset;
257 
258   //
259   // Install the pciio protocol, device path protocol and
260   // Bus Specific Driver Override Protocol
261   //
262 
263   if (PciIoDevice->BusOverride) {
264     Status = gBS->InstallMultipleProtocolInterfaces (
265                   &PciIoDevice->Handle,
266                   &gEfiDevicePathProtocolGuid,
267                   PciIoDevice->DevicePath,
268                   &gEfiPciIoProtocolGuid,
269                   &PciIoDevice->PciIo,
270                   &gEfiBusSpecificDriverOverrideProtocolGuid,
271                   &PciIoDevice->PciDriverOverride,
272                   NULL
273                   );
274   } else {
275     Status = gBS->InstallMultipleProtocolInterfaces (
276                   &PciIoDevice->Handle,
277                   &gEfiDevicePathProtocolGuid,
278                   PciIoDevice->DevicePath,
279                   &gEfiPciIoProtocolGuid,
280                   &PciIoDevice->PciIo,
281                   NULL
282                   );
283   }
284 
285   if (EFI_ERROR (Status)) {
286     return Status;
287   } else {
288     Status = gBS->OpenProtocol (
289                     Controller,
290                     &gEfiPciRootBridgeIoProtocolGuid,
291                     (VOID **)&(PciIoDevice->PciRootBridgeIo),
292                     gPciBusDriverBinding.DriverBindingHandle,
293                     PciIoDevice->Handle,
294                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
295                     );
296     if (EFI_ERROR (Status)) {
297       return Status;
298     }
299   }
300 
301   if (Handle != NULL) {
302     *Handle = PciIoDevice->Handle;
303   }
304 
305   //
306   // Detect if PCI Express Device
307   //
308   PciExpressCapRegOffset = 0;
309   Status = LocateCapabilityRegBlock (
310              PciIoDevice,
311              EFI_PCI_CAPABILITY_ID_PCIEXP,
312              &PciExpressCapRegOffset,
313              NULL
314              );
315   if (!EFI_ERROR (Status)) {
316     PciIoDevice->IsPciExp = TRUE;
317     DEBUG ((EFI_D_ERROR, "PciExp - %x (B-%x, D-%x, F-%x)\n", PciIoDevice->IsPciExp, PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber));
318   }
319 
320   //
321   // Indicate the pci device is registered
322   //
323   PciIoDevice->Registered = TRUE;
324 
325   return EFI_SUCCESS;
326 }
327 
328 
329 EFI_STATUS
DeRegisterPciDevice(IN EFI_HANDLE Controller,IN EFI_HANDLE Handle)330 DeRegisterPciDevice (
331   IN  EFI_HANDLE                     Controller,
332   IN  EFI_HANDLE                     Handle
333   )
334 /*++
335 
336 Routine Description:
337 
338   This function is used to de-register the PCI device from the EFI,
339   That includes un-installing PciIo protocol from the specified PCI
340   device handle.
341 
342 Arguments:
343 
344   Controller   - An efi handle.
345   Handle       - An efi handle.
346 
347 Returns:
348 
349   None
350 
351 --*/
352 {
353   EFI_PCI_IO_PROTOCOL             *PciIo;
354   EFI_STATUS                      Status;
355   PCI_IO_DEVICE                   *PciIoDevice;
356   PCI_IO_DEVICE                   *Node;
357   LIST_ENTRY                  *CurrentLink;
358   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
359 
360   Status = gBS->OpenProtocol (
361                   Handle,
362                   &gEfiPciIoProtocolGuid,
363                   (VOID **) &PciIo,
364                   gPciBusDriverBinding.DriverBindingHandle,
365                   Controller,
366                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
367                   );
368   if (!EFI_ERROR (Status)) {
369     PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
370 
371     //
372     // If it is already de-registered
373     //
374     if (!PciIoDevice->Registered) {
375       return EFI_SUCCESS;
376     }
377 
378     //
379     // If it is PPB, first de-register its children
380     //
381 
382     if (IS_PCI_BRIDGE (&(PciIoDevice->Pci))) {
383 
384       CurrentLink = PciIoDevice->ChildList.ForwardLink;
385 
386       while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {
387         Node    = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
388         Status  = DeRegisterPciDevice (Controller, Node->Handle);
389 
390         if (EFI_ERROR (Status)) {
391           return Status;
392         }
393 
394         CurrentLink = CurrentLink->ForwardLink;
395       }
396     }
397 
398     //
399     // First disconnect this device
400     //
401 //    PciIoDevice->PciIo.Attributes(&(PciIoDevice->PciIo),
402 //                                    EfiPciIoAttributeOperationDisable,
403 //                                    EFI_PCI_DEVICE_ENABLE,
404 //                                    NULL
405 //                                    );
406 
407     //
408     // Close the child handle
409     //
410     Status = gBS->CloseProtocol (
411                     Controller,
412                     &gEfiPciRootBridgeIoProtocolGuid,
413                     gPciBusDriverBinding.DriverBindingHandle,
414                     Handle
415                     );
416 
417     //
418     // Un-install the device path protocol and pci io protocol
419     //
420     if (PciIoDevice->BusOverride) {
421       Status = gBS->UninstallMultipleProtocolInterfaces (
422                       Handle,
423                       &gEfiDevicePathProtocolGuid,
424                       PciIoDevice->DevicePath,
425                       &gEfiPciIoProtocolGuid,
426                       &PciIoDevice->PciIo,
427                       &gEfiBusSpecificDriverOverrideProtocolGuid,
428                       &PciIoDevice->PciDriverOverride,
429                       NULL
430                       );
431     } else {
432       Status = gBS->UninstallMultipleProtocolInterfaces (
433                       Handle,
434                       &gEfiDevicePathProtocolGuid,
435                       PciIoDevice->DevicePath,
436                       &gEfiPciIoProtocolGuid,
437                       &PciIoDevice->PciIo,
438                       NULL
439                       );
440     }
441 
442     if (EFI_ERROR (Status)) {
443       gBS->OpenProtocol (
444             Controller,
445             &gEfiPciRootBridgeIoProtocolGuid,
446             (VOID **) &PciRootBridgeIo,
447             gPciBusDriverBinding.DriverBindingHandle,
448             Handle,
449             EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
450             );
451       return Status;
452     }
453 
454     //
455     // The Device Driver should disable this device after disconnect
456     // so the Pci Bus driver will not touch this device any more.
457     // Restore the register field to the original value
458     //
459     PciIoDevice->Registered = FALSE;
460     PciIoDevice->Handle     = NULL;
461   } else {
462 
463     //
464     // Handle may be closed before
465     //
466     return EFI_SUCCESS;
467   }
468 
469   return EFI_SUCCESS;
470 }
471 
472 EFI_STATUS
EnableBridgeAttributes(IN PCI_IO_DEVICE * PciIoDevice)473 EnableBridgeAttributes (
474   IN PCI_IO_DEVICE                       *PciIoDevice
475   )
476 {
477   PCI_TYPE01                PciData;
478 
479   //
480   // NOTE: We should not set EFI_PCI_DEVICE_ENABLE for a bridge
481   //       directly, because some legacy BIOS will NOT assign
482   //       IO or Memory resource for a bridge who has no child
483   //       device. So we add check IO or Memory here.
484   //
485 
486   PciIoDevice->PciIo.Pci.Read (
487                            &PciIoDevice->PciIo,
488                            EfiPciIoWidthUint8,
489                            0,
490                            sizeof (PciData),
491                            &PciData
492                            );
493 
494   if ((((PciData.Bridge.IoBase & 0xF) == 0) &&
495         (PciData.Bridge.IoBase != 0 || PciData.Bridge.IoLimit != 0)) ||
496       (((PciData.Bridge.IoBase & 0xF) == 1) &&
497         ((PciData.Bridge.IoBase & 0xF0) != 0 || (PciData.Bridge.IoLimit & 0xF0) != 0 || PciData.Bridge.IoBaseUpper16 != 0 || PciData.Bridge.IoLimitUpper16 != 0))) {
498     PciIoDevice->PciIo.Attributes(
499                          &(PciIoDevice->PciIo),
500                          EfiPciIoAttributeOperationEnable,
501                          (EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
502                          NULL
503                          );
504   }
505   if ((PciData.Bridge.MemoryBase & 0xFFF0) != 0 || (PciData.Bridge.MemoryLimit & 0xFFF0) != 0) {
506     PciIoDevice->PciIo.Attributes(
507                          &(PciIoDevice->PciIo),
508                          EfiPciIoAttributeOperationEnable,
509                          (EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
510                          NULL
511                          );
512   }
513   if ((((PciData.Bridge.PrefetchableMemoryBase & 0xF) == 0) &&
514         (PciData.Bridge.PrefetchableMemoryBase != 0 || PciData.Bridge.PrefetchableMemoryLimit != 0)) ||
515       (((PciData.Bridge.PrefetchableMemoryBase & 0xF) == 1) &&
516         ((PciData.Bridge.PrefetchableMemoryBase & 0xFFF0) != 0 || (PciData.Bridge.PrefetchableMemoryLimit & 0xFFF0) != 0 || PciData.Bridge.PrefetchableBaseUpper32 != 0 || PciData.Bridge.PrefetchableLimitUpper32 != 0))) {
517     PciIoDevice->PciIo.Attributes(
518                          &(PciIoDevice->PciIo),
519                          EfiPciIoAttributeOperationEnable,
520                          (EFI_PCI_IO_ATTRIBUTE_MEMORY | EFI_PCI_IO_ATTRIBUTE_BUS_MASTER),
521                          NULL
522                          );
523   }
524 
525   return EFI_SUCCESS;
526 }
527 
528 EFI_STATUS
StartPciDevicesOnBridge(IN EFI_HANDLE Controller,IN PCI_IO_DEVICE * RootBridge,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)529 StartPciDevicesOnBridge (
530   IN EFI_HANDLE                          Controller,
531   IN PCI_IO_DEVICE                       *RootBridge,
532   IN EFI_DEVICE_PATH_PROTOCOL            *RemainingDevicePath
533   )
534 /*++
535 
536 Routine Description:
537 
538   Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge
539 
540 Arguments:
541 
542   Controller          - An efi handle.
543   RootBridge          - A pointer to the PCI_IO_DEVICE.
544   RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.
545   NumberOfChildren    - Children number.
546   ChildHandleBuffer   - A pointer to the child handle buffer.
547 
548 Returns:
549 
550   None
551 
552 --*/
553 {
554   PCI_IO_DEVICE             *Temp;
555   PCI_IO_DEVICE             *PciIoDevice;
556   EFI_DEV_PATH_PTR          Node;
557   EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;
558   EFI_STATUS                Status;
559   LIST_ENTRY            *CurrentLink;
560 
561   CurrentLink = RootBridge->ChildList.ForwardLink;
562 
563   while (CurrentLink && CurrentLink != &RootBridge->ChildList) {
564 
565     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
566     if (RemainingDevicePath != NULL) {
567 
568       Node.DevPath = RemainingDevicePath;
569 
570       if (Node.Pci->Device != Temp->DeviceNumber ||
571           Node.Pci->Function != Temp->FunctionNumber) {
572         CurrentLink = CurrentLink->ForwardLink;
573         continue;
574       }
575 
576       //
577       // Check if the device has been assigned with required resource
578       //
579       if (!Temp->Allocated) {
580         return EFI_NOT_READY;
581       }
582 
583       //
584       // Check if the current node has been registered before
585       // If it is not, register it
586       //
587       if (!Temp->Registered) {
588         PciIoDevice = Temp;
589 
590         Status = RegisterPciDevice (
591                   Controller,
592                   PciIoDevice,
593                   NULL
594                   );
595 
596       }
597 
598       //
599       // Get the next device path
600       //
601       CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);
602       if (IsDevicePathEnd (CurrentDevicePath)) {
603         return EFI_SUCCESS;
604       }
605 
606       //
607       // If it is a PPB
608       //
609       if (IS_PCI_BRIDGE (&(Temp->Pci))) {
610         Status = StartPciDevicesOnBridge (
611                   Controller,
612                   Temp,
613                   CurrentDevicePath
614                   );
615         EnableBridgeAttributes (Temp);
616 
617         return Status;
618       } else {
619 
620         //
621         // Currently, the PCI bus driver only support PCI-PCI bridge
622         //
623         return EFI_UNSUPPORTED;
624       }
625 
626     } else {
627 
628       //
629       // If remaining device path is NULL,
630       // try to enable all the pci devices under this bridge
631       //
632 
633       if (!Temp->Registered && Temp->Allocated) {
634 
635         PciIoDevice = Temp;
636 
637         Status = RegisterPciDevice (
638                   Controller,
639                   PciIoDevice,
640                   NULL
641                   );
642 
643       }
644 
645       if (IS_PCI_BRIDGE (&(Temp->Pci))) {
646         Status = StartPciDevicesOnBridge (
647                    Controller,
648                    Temp,
649                    RemainingDevicePath
650                    );
651         EnableBridgeAttributes (Temp);
652       }
653 
654       CurrentLink = CurrentLink->ForwardLink;
655       continue;
656     }
657   }
658 
659   return EFI_NOT_FOUND;
660 }
661 
662 EFI_STATUS
StartPciDevices(IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)663 StartPciDevices (
664   IN EFI_HANDLE                         Controller,
665   IN EFI_DEVICE_PATH_PROTOCOL           *RemainingDevicePath
666   )
667 /*++
668 
669 Routine Description:
670 
671   Start to manage the PCI device according to RemainingDevicePath
672   If RemainingDevicePath == NULL, the PCI bus driver will start
673   to manage all the PCI devices it found previously
674 
675 Arguments:
676   Controller          - An efi handle.
677   RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.
678 
679 Returns:
680 
681   None
682 
683 --*/
684 {
685   EFI_DEV_PATH_PTR  Node;
686   PCI_IO_DEVICE     *RootBridge;
687   LIST_ENTRY    *CurrentLink;
688 
689   if (RemainingDevicePath != NULL) {
690 
691     //
692     // Check if the RemainingDevicePath is valid
693     //
694     Node.DevPath = RemainingDevicePath;
695     if (Node.DevPath->Type != HARDWARE_DEVICE_PATH ||
696         Node.DevPath->SubType != HW_PCI_DP         ||
697         DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)
698         ) {
699       return EFI_UNSUPPORTED;
700     }
701   }
702 
703   CurrentLink = gPciDevicePool.ForwardLink;
704 
705   while (CurrentLink && CurrentLink != &gPciDevicePool) {
706 
707     RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
708     //
709     // Locate the right root bridge to start
710     //
711     if (RootBridge->Handle == Controller) {
712       StartPciDevicesOnBridge (
713         Controller,
714         RootBridge,
715         RemainingDevicePath
716         );
717     }
718 
719     CurrentLink = CurrentLink->ForwardLink;
720   }
721 
722   return EFI_SUCCESS;
723 }
724 
725 PCI_IO_DEVICE *
CreateRootBridge(IN EFI_HANDLE RootBridgeHandle)726 CreateRootBridge (
727   IN EFI_HANDLE RootBridgeHandle
728   )
729 /*++
730 
731 Routine Description:
732 
733 
734 Arguments:
735   RootBridgeHandle   - An efi handle.
736 
737 Returns:
738 
739   None
740 
741 --*/
742 {
743 
744   EFI_STATUS                      Status;
745   PCI_IO_DEVICE                   *Dev;
746 
747   Dev = NULL;
748   Status = gBS->AllocatePool (
749                   EfiBootServicesData,
750                   sizeof (PCI_IO_DEVICE),
751                   (VOID **) &Dev
752                   );
753 
754   if (EFI_ERROR (Status)) {
755     return NULL;
756   }
757 
758   ZeroMem (Dev, sizeof (PCI_IO_DEVICE));
759   Dev->Signature  = PCI_IO_DEVICE_SIGNATURE;
760   Dev->Handle     = RootBridgeHandle;
761   InitializeListHead (&Dev->ChildList);
762 
763   return Dev;
764 }
765 
766 PCI_IO_DEVICE *
GetRootBridgeByHandle(EFI_HANDLE RootBridgeHandle)767 GetRootBridgeByHandle (
768   EFI_HANDLE RootBridgeHandle
769   )
770 /*++
771 
772 Routine Description:
773 
774 
775 Arguments:
776 
777   RootBridgeHandle    - An efi handle.
778 
779 Returns:
780 
781   None
782 
783 --*/
784 {
785   PCI_IO_DEVICE   *RootBridgeDev;
786   LIST_ENTRY  *CurrentLink;
787 
788   CurrentLink = gPciDevicePool.ForwardLink;
789 
790   while (CurrentLink && CurrentLink != &gPciDevicePool) {
791 
792     RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
793     if (RootBridgeDev->Handle == RootBridgeHandle) {
794       return RootBridgeDev;
795     }
796 
797     CurrentLink = CurrentLink->ForwardLink;
798   }
799 
800   return NULL;
801 }
802 
803 BOOLEAN
RootBridgeExisted(IN EFI_HANDLE RootBridgeHandle)804 RootBridgeExisted (
805   IN EFI_HANDLE RootBridgeHandle
806   )
807 /*++
808 
809 Routine Description:
810 
811   This function searches if RootBridgeHandle has already existed
812   in current device pool.
813 
814   If so, it means the given root bridge has been already enumerated.
815 
816 Arguments:
817 
818   RootBridgeHandle   - An efi handle.
819 
820 Returns:
821 
822   None
823 
824 --*/
825 {
826   PCI_IO_DEVICE *Bridge;
827 
828   Bridge = GetRootBridgeByHandle (RootBridgeHandle);
829 
830   if (Bridge != NULL) {
831     return TRUE;
832   }
833 
834   return FALSE;
835 }
836 
837 BOOLEAN
PciDeviceExisted(IN PCI_IO_DEVICE * Bridge,IN PCI_IO_DEVICE * PciIoDevice)838 PciDeviceExisted (
839   IN PCI_IO_DEVICE    *Bridge,
840   IN PCI_IO_DEVICE    *PciIoDevice
841   )
842 /*++
843 
844 Routine Description:
845 
846 Arguments:
847 
848   Bridge       - A pointer to the PCI_IO_DEVICE.
849   PciIoDevice  - A pointer to the PCI_IO_DEVICE.
850 
851 Returns:
852 
853   None
854 
855 --*/
856 {
857 
858   PCI_IO_DEVICE   *Temp;
859   LIST_ENTRY  *CurrentLink;
860 
861   CurrentLink = Bridge->ChildList.ForwardLink;
862 
863   while (CurrentLink && CurrentLink != &Bridge->ChildList) {
864 
865     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
866 
867     if (Temp == PciIoDevice) {
868       return TRUE;
869     }
870 
871     if (!IsListEmpty (&Temp->ChildList)) {
872       if (PciDeviceExisted (Temp, PciIoDevice)) {
873         return TRUE;
874       }
875     }
876 
877     CurrentLink = CurrentLink->ForwardLink;
878   }
879 
880   return FALSE;
881 }
882 
883 PCI_IO_DEVICE *
ActiveVGADeviceOnTheSameSegment(IN PCI_IO_DEVICE * VgaDevice)884 ActiveVGADeviceOnTheSameSegment (
885   IN PCI_IO_DEVICE        *VgaDevice
886   )
887 /*++
888 
889 Routine Description:
890 
891 Arguments:
892 
893   VgaDevice    - A pointer to the PCI_IO_DEVICE.
894 
895 Returns:
896 
897   None
898 
899 --*/
900 {
901   LIST_ENTRY  *CurrentLink;
902   PCI_IO_DEVICE   *Temp;
903 
904   CurrentLink = gPciDevicePool.ForwardLink;
905 
906   while (CurrentLink && CurrentLink != &gPciDevicePool) {
907 
908     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
909 
910     if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {
911 
912       Temp = ActiveVGADeviceOnTheRootBridge (Temp);
913 
914       if (Temp != NULL) {
915         return Temp;
916       }
917     }
918 
919     CurrentLink = CurrentLink->ForwardLink;
920   }
921 
922   return NULL;
923 }
924 
925 PCI_IO_DEVICE *
ActiveVGADeviceOnTheRootBridge(IN PCI_IO_DEVICE * RootBridge)926 ActiveVGADeviceOnTheRootBridge (
927   IN PCI_IO_DEVICE        *RootBridge
928   )
929 /*++
930 
931 Routine Description:
932 
933 Arguments:
934 
935   RootBridge    - A pointer to the PCI_IO_DEVICE.
936 
937 Returns:
938 
939   None
940 
941 --*/
942 {
943   LIST_ENTRY  *CurrentLink;
944   PCI_IO_DEVICE   *Temp;
945 
946   CurrentLink = RootBridge->ChildList.ForwardLink;
947 
948   while (CurrentLink && CurrentLink != &RootBridge->ChildList) {
949 
950     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
951 
952     if (IS_PCI_VGA(&Temp->Pci) &&
953         (Temp->Attributes &
954          (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
955           EFI_PCI_IO_ATTRIBUTE_VGA_IO     |
956           EFI_PCI_IO_ATTRIBUTE_VGA_IO_16))) {
957       return Temp;
958     }
959 
960     if (IS_PCI_BRIDGE (&Temp->Pci)) {
961 
962       Temp = ActiveVGADeviceOnTheRootBridge (Temp);
963 
964       if (Temp != NULL) {
965         return Temp;
966       }
967     }
968 
969     CurrentLink = CurrentLink->ForwardLink;
970   }
971 
972   return NULL;
973 }
974