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