df69078e77e4acc638072ba62a04c20e5d14d01e
[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   //\r
342   PciIo = &(PciIoDevice->PciIo);\r
343   Data8 = PCI_INT_LINE_UNKNOWN;\r
344   PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);\r
345 \r
346   //\r
347   // Process Platform OpRom\r
348   //\r
349   if (gPciPlatformProtocol != NULL && !PciIoDevice->AllOpRomProcessed) {\r
350     PciIoDevice->AllOpRomProcessed = TRUE;\r
351 \r
352     Status = gPciPlatformProtocol->GetPciRom (\r
353                                      gPciPlatformProtocol,\r
354                                      PciIoDevice->Handle,\r
355                                      &PlatformOpRomBuffer,\r
356                                      &PlatformOpRomSize\r
357                                      );\r
358 \r
359     if (!EFI_ERROR (Status)) {\r
360 \r
361       //\r
362       // Have Platform OpRom\r
363       //\r
364       PciIoDevice->RomSize        = PlatformOpRomSize;\r
365       PciIoDevice->PciIo.RomSize  = PlatformOpRomSize;\r
366       PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;\r
367 \r
368       //\r
369       // Process Image\r
370       //\r
371       ProcessOpRomImage (PciIoDevice);\r
372     }\r
373   }\r
374 \r
375   if (PciIoDevice->BusOverride) {\r
376     //\r
377     // Install BusSpecificDriverOverride Protocol\r
378     //\r
379     Status = gBS->InstallMultipleProtocolInterfaces (\r
380                     &PciIoDevice->Handle,\r
381                     &gEfiBusSpecificDriverOverrideProtocolGuid,\r
382                     &PciIoDevice->PciDriverOverride,\r
383                     NULL\r
384                     );\r
385     if (EFI_ERROR (Status)) {\r
386       gBS->UninstallMultipleProtocolInterfaces (\r
387              &PciIoDevice->Handle,\r
388              &gEfiDevicePathProtocolGuid,\r
389              PciIoDevice->DevicePath,\r
390              &gEfiPciIoProtocolGuid,\r
391              &PciIoDevice->PciIo,\r
392              NULL\r
393              );\r
394 \r
395       return Status;\r
396     }\r
397   }\r
398 \r
399   Status = gBS->OpenProtocol (\r
400                   Controller,\r
401                   &gEfiPciRootBridgeIoProtocolGuid,\r
402                   (VOID **) &(PciIoDevice->PciRootBridgeIo),\r
403                   gPciBusDriverBinding.DriverBindingHandle,\r
404                   PciIoDevice->Handle,\r
405                   EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
406                   );\r
407   if (EFI_ERROR (Status)) {\r
408     return Status;\r
409   }\r
410 \r
411   //\r
412   // Install Pccard Hotplug GUID for Pccard device so that\r
413   // to notify CardBus driver to stop the device when de-register happens\r
414   //\r
415   InstallPciHotplugGuid (PciIoDevice);\r
416 \r
417   if (Handle != NULL) {\r
418     *Handle = PciIoDevice->Handle;\r
419   }\r
420 \r
421   //\r
422   // Indicate the pci device is registered\r
423   //\r
424   PciIoDevice->Registered = TRUE;\r
425 \r
426   return EFI_SUCCESS;\r
427 }\r
428 \r
429 EFI_STATUS\r
430 RemoveAllPciDeviceOnBridge (\r
431   EFI_HANDLE               RootBridgeHandle,\r
432   PCI_IO_DEVICE            *Bridge\r
433   )\r
434 /*++\r
435 \r
436 Routine Description:\r
437 \r
438   This function is used to remove the whole PCI devices from the bridge.\r
439   \r
440 Arguments:\r
441 \r
442   RootBridgeHandle   - An efi handle.\r
443   Bridge             - A pointer to the PCI_IO_DEVICE.\r
444 \r
445 Returns:\r
446 \r
447   None\r
448 \r
449 --*/\r
450 // TODO:    EFI_SUCCESS - add return value to function comment\r
451 {\r
452 \r
453   LIST_ENTRY      *CurrentLink;\r
454   PCI_IO_DEVICE   *Temp;\r
455 \r
456   while (!IsListEmpty (&Bridge->ChildList)) {\r
457 \r
458     CurrentLink = Bridge->ChildList.ForwardLink;\r
459     Temp        = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
460 \r
461     //\r
462     // Check if the current node has been deregistered before\r
463     // If it is not, then deregister it\r
464     //\r
465     if (Temp->Registered) {\r
466       DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);\r
467     }\r
468     \r
469     //\r
470     // Remove this node from the linked list\r
471     //\r
472     RemoveEntryList (CurrentLink);\r
473 \r
474     if (!IsListEmpty (&Temp->ChildList)) {\r
475       RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);\r
476     }\r
477 \r
478     FreePciDevice (Temp);\r
479   }\r
480 \r
481   return EFI_SUCCESS;\r
482 }\r
483 \r
484 EFI_STATUS\r
485 DeRegisterPciDevice (\r
486   IN  EFI_HANDLE                     Controller,\r
487   IN  EFI_HANDLE                     Handle\r
488   )\r
489 /*++\r
490 \r
491 Routine Description:\r
492 \r
493   This function is used to de-register the PCI device from the EFI,\r
494   That includes un-installing PciIo protocol from the specified PCI \r
495   device handle.\r
496 \r
497 Arguments:\r
498 \r
499   Controller   - An efi handle.\r
500   Handle       - An efi handle.\r
501 \r
502 Returns:\r
503 \r
504   None\r
505 \r
506 --*/\r
507 // TODO:    EFI_SUCCESS - add return value to function comment\r
508 // TODO:    EFI_SUCCESS - add return value to function comment\r
509 // TODO:    EFI_SUCCESS - add return value to function comment\r
510 {\r
511   EFI_PCI_IO_PROTOCOL             *PciIo;\r
512   EFI_STATUS                      Status;\r
513   PCI_IO_DEVICE                   *PciIoDevice;\r
514   PCI_IO_DEVICE                   *Node;\r
515   LIST_ENTRY                      *CurrentLink;\r
516   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
517 \r
518   Status = gBS->OpenProtocol (\r
519                   Handle,\r
520                   &gEfiPciIoProtocolGuid,\r
521                   (VOID **) &PciIo,\r
522                   gPciBusDriverBinding.DriverBindingHandle,\r
523                   Controller,\r
524                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
525                   );\r
526   if (!EFI_ERROR (Status)) {\r
527     PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
528 \r
529     //\r
530     // If it is already de-registered\r
531     //\r
532     if (!PciIoDevice->Registered) {\r
533       return EFI_SUCCESS;\r
534     }\r
535 \r
536     //\r
537     // If it is PPB, first de-register its children\r
538     //\r
539 \r
540     if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
541 \r
542       CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
543 \r
544       while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {\r
545         Node    = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
546         Status  = DeRegisterPciDevice (Controller, Node->Handle);\r
547 \r
548         if (EFI_ERROR (Status)) {\r
549           return Status;\r
550         }\r
551 \r
552         CurrentLink = CurrentLink->ForwardLink;\r
553       }\r
554     }\r
555     //\r
556     // Uninstall Pccard Hotplug GUID for Pccard device\r
557     //\r
558     UninstallPciHotplugGuid (PciIoDevice);\r
559 \r
560     //\r
561     // Close the child handle\r
562     //\r
563     Status = gBS->CloseProtocol (\r
564                     Controller,\r
565                     &gEfiPciRootBridgeIoProtocolGuid,\r
566                     gPciBusDriverBinding.DriverBindingHandle,\r
567                     Handle\r
568                     );\r
569 \r
570     //\r
571     // Un-install the device path protocol and pci io protocol\r
572     //\r
573     if (PciIoDevice->BusOverride) {\r
574       Status = gBS->UninstallMultipleProtocolInterfaces (\r
575                       Handle,\r
576                       &gEfiDevicePathProtocolGuid,\r
577                       PciIoDevice->DevicePath,\r
578                       &gEfiPciIoProtocolGuid,\r
579                       &PciIoDevice->PciIo,\r
580                       &gEfiBusSpecificDriverOverrideProtocolGuid,\r
581                       &PciIoDevice->PciDriverOverride,\r
582                       NULL\r
583                       );\r
584     } else {\r
585       Status = gBS->UninstallMultipleProtocolInterfaces (\r
586                       Handle,\r
587                       &gEfiDevicePathProtocolGuid,\r
588                       PciIoDevice->DevicePath,\r
589                       &gEfiPciIoProtocolGuid,\r
590                       &PciIoDevice->PciIo,\r
591                       NULL\r
592                       );\r
593     }\r
594 \r
595     if (EFI_ERROR (Status)) {\r
596       gBS->OpenProtocol (\r
597             Controller,\r
598             &gEfiPciRootBridgeIoProtocolGuid,\r
599             (VOID **) &PciRootBridgeIo,\r
600             gPciBusDriverBinding.DriverBindingHandle,\r
601             Handle,\r
602             EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
603             );\r
604       return Status;\r
605     }\r
606     \r
607     //\r
608     // The Device Driver should disable this device after disconnect\r
609     // so the Pci Bus driver will not touch this device any more.\r
610     // Restore the register field to the original value\r
611     //\r
612     PciIoDevice->Registered = FALSE;\r
613     PciIoDevice->Handle     = NULL;\r
614   } else {\r
615 \r
616     //\r
617     // Handle may be closed before\r
618     //\r
619     return EFI_SUCCESS;\r
620   }\r
621 \r
622   return EFI_SUCCESS;\r
623 }\r
624 \r
625 EFI_STATUS\r
626 StartPciDevicesOnBridge (\r
627   IN EFI_HANDLE                          Controller,\r
628   IN PCI_IO_DEVICE                       *RootBridge,\r
629   IN EFI_DEVICE_PATH_PROTOCOL            *RemainingDevicePath,\r
630   IN OUT UINT8                           *NumberOfChildren,\r
631   IN OUT EFI_HANDLE                      *ChildHandleBuffer\r
632   )\r
633 /*++\r
634 \r
635 Routine Description:\r
636 \r
637   Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge\r
638 \r
639 Arguments:\r
640 \r
641   Controller          - An efi handle.\r
642   RootBridge          - A pointer to the PCI_IO_DEVICE.\r
643   RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
644   NumberOfChildren    - Children number.\r
645   ChildHandleBuffer   - A pointer to the child handle buffer.\r
646 \r
647 Returns:\r
648 \r
649   None\r
650 \r
651 --*/\r
652 // TODO:    EFI_NOT_READY - add return value to function comment\r
653 // TODO:    EFI_SUCCESS - add return value to function comment\r
654 // TODO:    EFI_UNSUPPORTED - add return value to function comment\r
655 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
656 {\r
657   PCI_IO_DEVICE             *Temp;\r
658   PCI_IO_DEVICE             *PciIoDevice;\r
659   EFI_DEV_PATH_PTR          Node;\r
660   EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;\r
661   EFI_STATUS                Status;\r
662   LIST_ENTRY                *CurrentLink;\r
663   UINT64                    Supports;\r
664 \r
665   CurrentLink = RootBridge->ChildList.ForwardLink;\r
666 \r
667   while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
668 \r
669     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
670     if (RemainingDevicePath != NULL) {\r
671 \r
672       Node.DevPath = RemainingDevicePath;\r
673 \r
674       if (Node.Pci->Device != Temp->DeviceNumber || \r
675           Node.Pci->Function != Temp->FunctionNumber) {\r
676         CurrentLink = CurrentLink->ForwardLink;\r
677         continue;\r
678       }\r
679 \r
680       //\r
681       // Check if the device has been assigned with required resource\r
682       //\r
683       if (!Temp->Allocated) {\r
684         return EFI_NOT_READY;\r
685       }\r
686       \r
687       //\r
688       // Check if the current node has been registered before\r
689       // If it is not, register it\r
690       //\r
691       if (!Temp->Registered) {\r
692         PciIoDevice = Temp;\r
693 \r
694         Status = RegisterPciDevice (\r
695                   Controller,\r
696                   PciIoDevice,\r
697                   NULL\r
698                   );\r
699 \r
700       }\r
701 \r
702       if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {\r
703         ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;\r
704         (*NumberOfChildren)++;\r
705       }\r
706       \r
707       //\r
708       // Get the next device path\r
709       //\r
710       CurrentDevicePath = EfiNextDevicePathNode (RemainingDevicePath);\r
711       if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
712         return EFI_SUCCESS;\r
713       }\r
714   \r
715       //\r
716       // If it is a PPB\r
717       //\r
718       if (!IsListEmpty (&Temp->ChildList)) {\r
719         Status = StartPciDevicesOnBridge (\r
720                   Controller,\r
721                   Temp,\r
722                   CurrentDevicePath,\r
723                   NumberOfChildren,\r
724                   ChildHandleBuffer\r
725                   );\r
726 \r
727         Temp->PciIo.Attributes (\r
728                       &(Temp->PciIo),\r
729                       EfiPciIoAttributeOperationSupported,\r
730                       0,\r
731                       &Supports\r
732                       );\r
733         Supports &= EFI_PCI_DEVICE_ENABLE;\r
734         Temp->PciIo.Attributes (\r
735                       &(Temp->PciIo),\r
736                       EfiPciIoAttributeOperationEnable,\r
737                       Supports,\r
738                       NULL\r
739                       );\r
740 \r
741         return Status;\r
742       } else {\r
743 \r
744         //\r
745         // Currently, the PCI bus driver only support PCI-PCI bridge\r
746         //\r
747         return EFI_UNSUPPORTED;\r
748       }\r
749 \r
750     } else {\r
751 \r
752       //\r
753       // If remaining device path is NULL,\r
754       // try to enable all the pci devices under this bridge\r
755       //\r
756 \r
757       if (!Temp->Registered && Temp->Allocated) {\r
758 \r
759         PciIoDevice = Temp;\r
760 \r
761         Status = RegisterPciDevice (\r
762                   Controller,\r
763                   PciIoDevice,\r
764                   NULL\r
765                   );\r
766 \r
767       }\r
768 \r
769       if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {\r
770         ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;\r
771         (*NumberOfChildren)++;\r
772       }\r
773 \r
774       if (!IsListEmpty (&Temp->ChildList)) {\r
775         Status = StartPciDevicesOnBridge (\r
776                   Controller,\r
777                   Temp,\r
778                   RemainingDevicePath,\r
779                   NumberOfChildren,\r
780                   ChildHandleBuffer\r
781                   );\r
782 \r
783         Temp->PciIo.Attributes (\r
784                       &(Temp->PciIo),\r
785                       EfiPciIoAttributeOperationSupported,\r
786                       0,\r
787                       &Supports\r
788                       );\r
789         Supports &= EFI_PCI_DEVICE_ENABLE;\r
790         Temp->PciIo.Attributes (\r
791                       &(Temp->PciIo),\r
792                       EfiPciIoAttributeOperationEnable,\r
793                       Supports,\r
794                       NULL\r
795                       );\r
796 \r
797       }\r
798 \r
799       CurrentLink = CurrentLink->ForwardLink;\r
800       continue;\r
801     }\r
802   }\r
803 \r
804   return EFI_NOT_FOUND;\r
805 }\r
806 \r
807 EFI_STATUS\r
808 StartPciDevices (\r
809   IN EFI_HANDLE                         Controller,\r
810   IN EFI_DEVICE_PATH_PROTOCOL           *RemainingDevicePath\r
811   )\r
812 /*++\r
813 \r
814 Routine Description:\r
815 \r
816   Start to manage the PCI device according to RemainingDevicePath\r
817   If RemainingDevicePath == NULL, the PCI bus driver will start \r
818   to manage all the PCI devices it found previously\r
819 \r
820 Arguments:\r
821   Controller          - An efi handle.\r
822   RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
823 \r
824 Returns:\r
825 \r
826   None\r
827 \r
828 --*/\r
829 // TODO:    EFI_UNSUPPORTED - add return value to function comment\r
830 // TODO:    EFI_SUCCESS - add return value to function comment\r
831 {\r
832   EFI_DEV_PATH_PTR  Node;\r
833   PCI_IO_DEVICE     *RootBridge;\r
834   LIST_ENTRY        *CurrentLink;\r
835 \r
836   if (RemainingDevicePath != NULL) {\r
837 \r
838     //\r
839     // Check if the RemainingDevicePath is valid\r
840     //\r
841     Node.DevPath = RemainingDevicePath;\r
842     if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||\r
843         ((Node.DevPath->SubType != HW_PCI_DP)         &&\r
844          (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))\r
845         ) {\r
846       return EFI_UNSUPPORTED;\r
847     }\r
848   }\r
849 \r
850   CurrentLink = gPciDevicePool.ForwardLink;\r
851 \r
852   while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
853 \r
854     RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
855     //\r
856     // Locate the right root bridge to start\r
857     //\r
858     if (RootBridge->Handle == Controller) {\r
859       StartPciDevicesOnBridge (\r
860         Controller,\r
861         RootBridge,\r
862         RemainingDevicePath,\r
863         NULL,\r
864         NULL\r
865         );\r
866     }\r
867 \r
868     CurrentLink = CurrentLink->ForwardLink;\r
869   }\r
870 \r
871   return EFI_SUCCESS;\r
872 }\r
873 \r
874 PCI_IO_DEVICE *\r
875 CreateRootBridge (\r
876   IN EFI_HANDLE RootBridgeHandle\r
877   )\r
878 /*++\r
879 \r
880 Routine Description:\r
881 \r
882 \r
883 Arguments:\r
884   RootBridgeHandle   - An efi handle.\r
885 \r
886 Returns:\r
887 \r
888   None\r
889 \r
890 --*/\r
891 {\r
892 \r
893   EFI_STATUS                      Status;\r
894   PCI_IO_DEVICE                   *Dev;\r
895   EFI_DEVICE_PATH_PROTOCOL        *ParentDevicePath;\r
896   EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
897 \r
898   Dev = NULL;\r
899   Status = gBS->AllocatePool (\r
900                   EfiBootServicesData,\r
901                   sizeof (PCI_IO_DEVICE),\r
902                   (VOID **) &Dev\r
903                   );\r
904 \r
905   if (EFI_ERROR (Status)) {\r
906     return NULL;\r
907   }\r
908 \r
909   ZeroMem (Dev, sizeof (PCI_IO_DEVICE));\r
910   Dev->Signature  = PCI_IO_DEVICE_SIGNATURE;\r
911   Dev->Handle     = RootBridgeHandle;\r
912   InitializeListHead (&Dev->ChildList);\r
913 \r
914   Status = gBS->OpenProtocol (\r
915                   RootBridgeHandle,\r
916                   &gEfiDevicePathProtocolGuid,\r
917                   (VOID **) &ParentDevicePath,\r
918                   gPciBusDriverBinding.DriverBindingHandle,\r
919                   RootBridgeHandle,\r
920                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
921                   );\r
922 \r
923   if (EFI_ERROR (Status)) {\r
924     gBS->FreePool (Dev);\r
925     return NULL;\r
926   }\r
927 \r
928   //\r
929   // Record the root bridge parent device path\r
930   //\r
931   Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);\r
932 \r
933   //\r
934   // Get the pci root bridge io protocol\r
935   //\r
936   Status = gBS->OpenProtocol (\r
937                   RootBridgeHandle,\r
938                   &gEfiPciRootBridgeIoProtocolGuid,\r
939                   (VOID **) &PciRootBridgeIo,\r
940                   gPciBusDriverBinding.DriverBindingHandle,\r
941                   RootBridgeHandle,\r
942                   EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
943                   );\r
944 \r
945   if (EFI_ERROR (Status)) {\r
946     FreePciDevice (Dev);\r
947     return NULL;\r
948   }\r
949 \r
950   Dev->PciRootBridgeIo = PciRootBridgeIo;\r
951 \r
952   //\r
953   // Initialize the PCI I/O instance structure\r
954   //\r
955   Status  = InitializePciIoInstance (Dev);\r
956   Status  = InitializePciDriverOverrideInstance (Dev);\r
957 \r
958   //\r
959   // Initialize reserved resource list and\r
960   // option rom driver list\r
961   //\r
962   InitializeListHead (&Dev->ReservedResourceList);\r
963   InitializeListHead (&Dev->OptionRomDriverList);\r
964 \r
965   return Dev;\r
966 }\r
967 \r
968 PCI_IO_DEVICE *\r
969 GetRootBridgeByHandle (\r
970   EFI_HANDLE RootBridgeHandle\r
971   )\r
972 /*++\r
973 \r
974 Routine Description:\r
975 \r
976 \r
977 Arguments:\r
978 \r
979   RootBridgeHandle    - An efi handle.\r
980 \r
981 Returns:\r
982 \r
983   None\r
984 \r
985 --*/\r
986 {\r
987   PCI_IO_DEVICE   *RootBridgeDev;\r
988   LIST_ENTRY      *CurrentLink;\r
989 \r
990   CurrentLink = gPciDevicePool.ForwardLink;\r
991 \r
992   while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
993 \r
994     RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
995     if (RootBridgeDev->Handle == RootBridgeHandle) {\r
996       return RootBridgeDev;\r
997     }\r
998 \r
999     CurrentLink = CurrentLink->ForwardLink;\r
1000   }\r
1001 \r
1002   return NULL;\r
1003 }\r
1004 \r
1005 BOOLEAN\r
1006 RootBridgeExisted (\r
1007   IN EFI_HANDLE RootBridgeHandle\r
1008   )\r
1009 /*++\r
1010 \r
1011 Routine Description:\r
1012 \r
1013   This function searches if RootBridgeHandle has already existed\r
1014   in current device pool.\r
1015 \r
1016   If so, it means the given root bridge has been already enumerated.\r
1017 \r
1018 Arguments:\r
1019 \r
1020   RootBridgeHandle   - An efi handle.\r
1021 \r
1022 Returns:\r
1023 \r
1024   None\r
1025 \r
1026 --*/\r
1027 {\r
1028   PCI_IO_DEVICE *Bridge;\r
1029 \r
1030   Bridge = GetRootBridgeByHandle (RootBridgeHandle);\r
1031 \r
1032   if (Bridge != NULL) {\r
1033     return TRUE;\r
1034   }\r
1035 \r
1036   return FALSE;\r
1037 }\r
1038 \r
1039 BOOLEAN\r
1040 PciDeviceExisted (\r
1041   IN PCI_IO_DEVICE    *Bridge,\r
1042   IN PCI_IO_DEVICE    *PciIoDevice\r
1043   )\r
1044 /*++\r
1045 \r
1046 Routine Description:\r
1047   \r
1048 Arguments:\r
1049 \r
1050   Bridge       - A pointer to the PCI_IO_DEVICE.\r
1051   PciIoDevice  - A pointer to the PCI_IO_DEVICE.\r
1052 \r
1053 Returns:\r
1054 \r
1055   None\r
1056 \r
1057 --*/\r
1058 {\r
1059 \r
1060   PCI_IO_DEVICE   *Temp;\r
1061   LIST_ENTRY      *CurrentLink;\r
1062 \r
1063   CurrentLink = Bridge->ChildList.ForwardLink;\r
1064 \r
1065   while (CurrentLink && CurrentLink != &Bridge->ChildList) {\r
1066 \r
1067     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1068 \r
1069     if (Temp == PciIoDevice) {\r
1070       return TRUE;\r
1071     }\r
1072 \r
1073     if (!IsListEmpty (&Temp->ChildList)) {\r
1074       if (PciDeviceExisted (Temp, PciIoDevice)) {\r
1075         return TRUE;\r
1076       }\r
1077     }\r
1078 \r
1079     CurrentLink = CurrentLink->ForwardLink;\r
1080   }\r
1081 \r
1082   return FALSE;\r
1083 }\r
1084 \r
1085 PCI_IO_DEVICE *\r
1086 ActiveVGADeviceOnTheSameSegment (\r
1087   IN PCI_IO_DEVICE        *VgaDevice\r
1088   )\r
1089 /*++\r
1090 \r
1091 Routine Description:\r
1092 \r
1093 Arguments:\r
1094 \r
1095   VgaDevice    - A pointer to the PCI_IO_DEVICE.\r
1096   \r
1097 Returns:\r
1098 \r
1099   None\r
1100 \r
1101 --*/\r
1102 {\r
1103   LIST_ENTRY      *CurrentLink;\r
1104   PCI_IO_DEVICE   *Temp;\r
1105 \r
1106   CurrentLink = gPciDevicePool.ForwardLink;\r
1107 \r
1108   while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
1109 \r
1110     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1111 \r
1112     if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {\r
1113 \r
1114       Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1115 \r
1116       if (Temp != NULL) {\r
1117         return Temp;\r
1118       }\r
1119     }\r
1120 \r
1121     CurrentLink = CurrentLink->ForwardLink;\r
1122   }\r
1123 \r
1124   return NULL;\r
1125 }\r
1126 \r
1127 PCI_IO_DEVICE *\r
1128 ActiveVGADeviceOnTheRootBridge (\r
1129   IN PCI_IO_DEVICE        *RootBridge\r
1130   )\r
1131 /*++\r
1132 \r
1133 Routine Description:\r
1134 \r
1135 Arguments:\r
1136 \r
1137   RootBridge    - A pointer to the PCI_IO_DEVICE.\r
1138 \r
1139 Returns:\r
1140 \r
1141   None\r
1142 \r
1143 --*/\r
1144 {\r
1145   LIST_ENTRY      *CurrentLink;\r
1146   PCI_IO_DEVICE   *Temp;\r
1147 \r
1148   CurrentLink = RootBridge->ChildList.ForwardLink;\r
1149 \r
1150   while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
1151 \r
1152     Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1153 \r
1154     if (IS_PCI_VGA(&Temp->Pci) && \r
1155         (Temp->Attributes &\r
1156          (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |\r
1157           EFI_PCI_IO_ATTRIBUTE_VGA_IO     |\r
1158           EFI_PCI_IO_ATTRIBUTE_VGA_IO_16))) {\r
1159       return Temp;\r
1160     }\r
1161 \r
1162     if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
1163 \r
1164       Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1165 \r
1166       if (Temp != NULL) {\r
1167         return Temp;\r
1168       }\r
1169     }\r
1170 \r
1171     CurrentLink = CurrentLink->ForwardLink;\r
1172   }\r
1173 \r
1174   return NULL;\r
1175 }\r
1176 \r
1177 EFI_STATUS\r
1178 GetHpcPciAddress (\r
1179   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *PciRootBridgeIo,\r
1180   IN  EFI_DEVICE_PATH_PROTOCOL         *HpcDevicePath,\r
1181   OUT UINT64                           *PciAddress\r
1182   )\r
1183 /*++\r
1184 \r
1185 Routine Description:\r
1186 \r
1187 Arguments:\r
1188 \r
1189   PciRootBridgeIo       - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1190   HpcDevicePath         - A pointer to the EFI_DEVICE_PATH_PROTOCL.\r
1191   PciAddress            - A pointer to the pci address.\r
1192   \r
1193 Returns:\r
1194 \r
1195   None\r
1196 \r
1197 --*/\r
1198 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
1199 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
1200 // TODO:    EFI_SUCCESS - add return value to function comment\r
1201 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
1202 {\r
1203   EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;\r
1204   EFI_DEV_PATH_PTR          Node;\r
1205   LIST_ENTRY                *CurrentLink;\r
1206   PCI_IO_DEVICE             *RootBridge;\r
1207   EFI_STATUS                Status;\r
1208 \r
1209   CurrentDevicePath = HpcDevicePath;\r
1210 \r
1211   //\r
1212   // Get the remaining device path for this PCI device, if it is a PCI device\r
1213   //\r
1214   while (!EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1215 \r
1216     Node.DevPath = CurrentDevicePath;\r
1217 \r
1218     //\r
1219     // Check if it is PCI device Path?\r
1220     //\r
1221     if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||\r
1222         ((Node.DevPath->SubType != HW_PCI_DP)         &&\r
1223          (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))) {\r
1224       CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
1225       continue;\r
1226     }\r
1227 \r
1228     break;\r
1229   }\r
1230 \r
1231   //\r
1232   // Check if it is not PCI device path\r
1233   //\r
1234   if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1235     return EFI_NOT_FOUND;\r
1236   }\r
1237 \r
1238   CurrentLink = gPciDevicePool.ForwardLink;\r
1239 \r
1240   while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
1241 \r
1242     RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1243     //\r
1244     // Locate the right root bridge to start\r
1245     //\r
1246     if (RootBridge->PciRootBridgeIo == PciRootBridgeIo) {\r
1247       Status = GetHpcPciAddressFromRootBridge (\r
1248                 RootBridge,\r
1249                 CurrentDevicePath,\r
1250                 PciAddress\r
1251                 );\r
1252       if (EFI_ERROR (Status)) {\r
1253         return EFI_NOT_FOUND;\r
1254       }\r
1255 \r
1256       return EFI_SUCCESS;\r
1257 \r
1258     }\r
1259 \r
1260     CurrentLink = CurrentLink->ForwardLink;\r
1261   }\r
1262 \r
1263   return EFI_NOT_FOUND;\r
1264 }\r
1265 \r
1266 EFI_STATUS\r
1267 GetHpcPciAddressFromRootBridge (\r
1268   IN  PCI_IO_DEVICE                    *RootBridge,\r
1269   IN  EFI_DEVICE_PATH_PROTOCOL         *RemainingDevicePath,\r
1270   OUT UINT64                           *PciAddress\r
1271   )\r
1272 /*++\r
1273 \r
1274 Routine Description:\r
1275 \r
1276 Arguments:\r
1277 \r
1278   PciRootBridgeIo       - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1279   HpcDevicePath         - A pointer to the EFI_DEVICE_PATH_PROTOCL.\r
1280   PciAddress            - A pointer to the pci address.\r
1281 \r
1282 Returns:\r
1283 \r
1284   None\r
1285 \r
1286 --*/\r
1287 // TODO:    RootBridge - add argument and description to function comment\r
1288 // TODO:    RemainingDevicePath - add argument and description to function comment\r
1289 // TODO:    EFI_SUCCESS - add return value to function comment\r
1290 // TODO:    EFI_NOT_FOUND - add return value to function comment\r
1291 // TODO:    EFI_SUCCESS - add return value to function comment\r
1292 {\r
1293   EFI_DEV_PATH_PTR          Node;\r
1294   PCI_IO_DEVICE             *Temp;\r
1295   EFI_DEVICE_PATH_PROTOCOL  *CurrentDevicePath;\r
1296   LIST_ENTRY                *CurrentLink;\r
1297   BOOLEAN                   MisMatch;\r
1298 \r
1299   MisMatch          = FALSE;\r
1300 \r
1301   CurrentDevicePath = RemainingDevicePath;\r
1302   Node.DevPath      = CurrentDevicePath;\r
1303   Temp              = NULL;\r
1304 \r
1305   while (!EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1306 \r
1307     CurrentLink   = RootBridge->ChildList.ForwardLink;\r
1308     Node.DevPath  = CurrentDevicePath;\r
1309 \r
1310     while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
1311       Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1312 \r
1313       if (Node.Pci->Device   == Temp->DeviceNumber &&\r
1314           Node.Pci->Function == Temp->FunctionNumber) {\r
1315         RootBridge = Temp;\r
1316         break;\r
1317       }\r
1318 \r
1319       CurrentLink = CurrentLink->ForwardLink;\r
1320     }\r
1321 \r
1322     //\r
1323     // Check if we find the bridge\r
1324     //\r
1325     if (CurrentLink == &RootBridge->ChildList) {\r
1326 \r
1327       MisMatch = TRUE;\r
1328       break;\r
1329 \r
1330     }\r
1331 \r
1332     CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
1333   }\r
1334 \r
1335   if (MisMatch) {\r
1336 \r
1337     CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
1338 \r
1339     if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1340       *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);\r
1341       return EFI_SUCCESS;\r
1342     }\r
1343 \r
1344     return EFI_NOT_FOUND;\r
1345   }\r
1346 \r
1347   *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1348 \r
1349   return EFI_SUCCESS;\r
1350 \r
1351 }\r