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