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