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