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