]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
5ace222e602886df5eb8f3fceec17038ad9c1704
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciDeviceSupport.c
1 /** @file
2 Supporting functions implementaion for PCI devices management.
3
4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
5 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
218 //
219 // Install the pciio protocol, device path protocol
220 //
221 Status = gBS->InstallMultipleProtocolInterfaces (
222 &PciIoDevice->Handle,
223 &gEfiDevicePathProtocolGuid,
224 PciIoDevice->DevicePath,
225 &gEfiPciIoProtocolGuid,
226 &PciIoDevice->PciIo,
227 NULL
228 );
229 if (EFI_ERROR (Status)) {
230 return Status;
231 }
232
233 //
234 // Detect if PCI Express Device
235 //
236 PciExpressCapRegOffset = 0;
237 Status = LocateCapabilityRegBlock (
238 PciIoDevice,
239 EFI_PCI_CAPABILITY_ID_PCIEXP,
240 &PciExpressCapRegOffset,
241 NULL
242 );
243 if (!EFI_ERROR (Status)) {
244 PciIoDevice->IsPciExp = TRUE;
245 }
246
247 //
248 // Force Interrupt line to "Unknown" or "No Connection"
249 //
250 PciIo = &(PciIoDevice->PciIo);
251 Data8 = PCI_INT_LINE_UNKNOWN;
252 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);
253
254 //
255 // Process OpRom
256 //
257 if (!PciIoDevice->AllOpRomProcessed) {
258
259 //
260 // Get the OpRom provided by platform
261 //
262 if (gPciPlatformProtocol != NULL) {
263 Status = gPciPlatformProtocol->GetPciRom (
264 gPciPlatformProtocol,
265 PciIoDevice->Handle,
266 &PlatformOpRomBuffer,
267 &PlatformOpRomSize
268 );
269 if (!EFI_ERROR (Status)) {
270 PciIoDevice->EmbeddedRom = FALSE;
271 PciIoDevice->RomSize = PlatformOpRomSize;
272 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;
273 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
274 //
275 // For OpROM read from gPciPlatformProtocol:
276 // Add the Rom Image to internal database for later PCI light enumeration
277 //
278 PciRomAddImageMapping (
279 NULL,
280 PciIoDevice->PciRootBridgeIo->SegmentNumber,
281 PciIoDevice->BusNumber,
282 PciIoDevice->DeviceNumber,
283 PciIoDevice->FunctionNumber,
284 (UINT64) (UINTN) PciIoDevice->PciIo.RomImage,
285 PciIoDevice->PciIo.RomSize
286 );
287 }
288 } else if (gPciOverrideProtocol != NULL) {
289 Status = gPciOverrideProtocol->GetPciRom (
290 gPciOverrideProtocol,
291 PciIoDevice->Handle,
292 &PlatformOpRomBuffer,
293 &PlatformOpRomSize
294 );
295 if (!EFI_ERROR (Status)) {
296 PciIoDevice->EmbeddedRom = FALSE;
297 PciIoDevice->RomSize = PlatformOpRomSize;
298 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;
299 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
300 //
301 // For OpROM read from gPciOverrideProtocol:
302 // Add the Rom Image to internal database for later PCI light enumeration
303 //
304 PciRomAddImageMapping (
305 NULL,
306 PciIoDevice->PciRootBridgeIo->SegmentNumber,
307 PciIoDevice->BusNumber,
308 PciIoDevice->DeviceNumber,
309 PciIoDevice->FunctionNumber,
310 (UINT64) (UINTN) PciIoDevice->PciIo.RomImage,
311 PciIoDevice->PciIo.RomSize
312 );
313 }
314 }
315 }
316
317 if (PciIoDevice->HasEfiOpRom) {
318 Status = gBS->InstallMultipleProtocolInterfaces (
319 &PciIoDevice->Handle,
320 &gEfiLoadFile2ProtocolGuid,
321 &PciIoDevice->LoadFile2,
322 NULL
323 );
324 if (EFI_ERROR (Status)) {
325 gBS->UninstallMultipleProtocolInterfaces (
326 &PciIoDevice->Handle,
327 &gEfiDevicePathProtocolGuid,
328 PciIoDevice->DevicePath,
329 &gEfiPciIoProtocolGuid,
330 &PciIoDevice->PciIo,
331 NULL
332 );
333 return Status;
334 }
335 }
336
337
338 if (!PciIoDevice->AllOpRomProcessed) {
339
340 PciIoDevice->AllOpRomProcessed = TRUE;
341
342 //
343 // Dispatch the EFI OpRom for the PCI device.
344 // The OpRom is got from platform in the above code
345 // or loaded from device in the previous round of bus enumeration
346 //
347 if (PciIoDevice->HasEfiOpRom) {
348 ProcessOpRomImage (PciIoDevice);
349 }
350 }
351
352 if (PciIoDevice->BusOverride) {
353 //
354 // Install Bus Specific Driver Override Protocol
355 //
356 Status = gBS->InstallMultipleProtocolInterfaces (
357 &PciIoDevice->Handle,
358 &gEfiBusSpecificDriverOverrideProtocolGuid,
359 &PciIoDevice->PciDriverOverride,
360 NULL
361 );
362 if (EFI_ERROR (Status)) {
363 gBS->UninstallMultipleProtocolInterfaces (
364 &PciIoDevice->Handle,
365 &gEfiDevicePathProtocolGuid,
366 PciIoDevice->DevicePath,
367 &gEfiPciIoProtocolGuid,
368 &PciIoDevice->PciIo,
369 NULL
370 );
371 if (PciIoDevice->HasEfiOpRom) {
372 gBS->UninstallMultipleProtocolInterfaces (
373 &PciIoDevice->Handle,
374 &gEfiLoadFile2ProtocolGuid,
375 &PciIoDevice->LoadFile2,
376 NULL
377 );
378 }
379
380 return Status;
381 }
382 }
383
384 Status = gBS->OpenProtocol (
385 Controller,
386 &gEfiPciRootBridgeIoProtocolGuid,
387 (VOID **) &(PciIoDevice->PciRootBridgeIo),
388 gPciBusDriverBinding.DriverBindingHandle,
389 PciIoDevice->Handle,
390 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
391 );
392 if (EFI_ERROR (Status)) {
393 return Status;
394 }
395
396 if (Handle != NULL) {
397 *Handle = PciIoDevice->Handle;
398 }
399
400 //
401 // Indicate the pci device is registered
402 //
403 PciIoDevice->Registered = TRUE;
404
405 return EFI_SUCCESS;
406 }
407
408 /**
409 This function is used to remove the whole PCI devices on the specified bridge from
410 the root bridge.
411
412 @param RootBridgeHandle The root bridge device handle.
413 @param Bridge The bridge device to be removed.
414
415 **/
416 VOID
417 RemoveAllPciDeviceOnBridge (
418 EFI_HANDLE RootBridgeHandle,
419 PCI_IO_DEVICE *Bridge
420 )
421 {
422 LIST_ENTRY *CurrentLink;
423 PCI_IO_DEVICE *Temp;
424
425 while (!IsListEmpty (&Bridge->ChildList)) {
426
427 CurrentLink = Bridge->ChildList.ForwardLink;
428 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
429
430 //
431 // Check if the current node has been deregistered before
432 // If it is not, then deregister it
433 //
434 if (Temp->Registered) {
435 DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);
436 }
437
438 //
439 // Remove this node from the linked list
440 //
441 RemoveEntryList (CurrentLink);
442
443 if (!IsListEmpty (&Temp->ChildList)) {
444 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
445 }
446
447 FreePciDevice (Temp);
448 }
449 }
450
451 /**
452 This function is used to de-register the PCI IO device.
453
454 That includes un-installing PciIo protocol from the specified PCI
455 device handle.
456
457 @param Controller An EFI handle for the PCI bus controller.
458 @param Handle PCI device handle.
459
460 @retval EFI_SUCCESS The PCI device is successfully de-registered.
461 @retval other An error occurred when de-registering the PCI device.
462
463 **/
464 EFI_STATUS
465 DeRegisterPciDevice (
466 IN EFI_HANDLE Controller,
467 IN EFI_HANDLE Handle
468 )
469
470 {
471 EFI_PCI_IO_PROTOCOL *PciIo;
472 EFI_STATUS Status;
473 PCI_IO_DEVICE *PciIoDevice;
474 PCI_IO_DEVICE *Node;
475 LIST_ENTRY *CurrentLink;
476 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
477
478 Status = gBS->OpenProtocol (
479 Handle,
480 &gEfiPciIoProtocolGuid,
481 (VOID **) &PciIo,
482 gPciBusDriverBinding.DriverBindingHandle,
483 Controller,
484 EFI_OPEN_PROTOCOL_GET_PROTOCOL
485 );
486 if (!EFI_ERROR (Status)) {
487 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
488
489 //
490 // If it is already de-registered
491 //
492 if (!PciIoDevice->Registered) {
493 return EFI_SUCCESS;
494 }
495
496 //
497 // If it is PPB, first de-register its children
498 //
499
500 if (!IsListEmpty (&PciIoDevice->ChildList)) {
501
502 CurrentLink = PciIoDevice->ChildList.ForwardLink;
503
504 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
505 Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
506 Status = DeRegisterPciDevice (Controller, Node->Handle);
507
508 if (EFI_ERROR (Status)) {
509 return Status;
510 }
511
512 CurrentLink = CurrentLink->ForwardLink;
513 }
514 }
515
516 //
517 // Close the child handle
518 //
519 Status = gBS->CloseProtocol (
520 Controller,
521 &gEfiPciRootBridgeIoProtocolGuid,
522 gPciBusDriverBinding.DriverBindingHandle,
523 Handle
524 );
525
526 //
527 // Un-install the Device Path protocol and PCI I/O protocol
528 // and Bus Specific Driver Override protocol if needed.
529 //
530 if (PciIoDevice->BusOverride) {
531 Status = gBS->UninstallMultipleProtocolInterfaces (
532 Handle,
533 &gEfiDevicePathProtocolGuid,
534 PciIoDevice->DevicePath,
535 &gEfiPciIoProtocolGuid,
536 &PciIoDevice->PciIo,
537 &gEfiBusSpecificDriverOverrideProtocolGuid,
538 &PciIoDevice->PciDriverOverride,
539 NULL
540 );
541 } else {
542 Status = gBS->UninstallMultipleProtocolInterfaces (
543 Handle,
544 &gEfiDevicePathProtocolGuid,
545 PciIoDevice->DevicePath,
546 &gEfiPciIoProtocolGuid,
547 &PciIoDevice->PciIo,
548 NULL
549 );
550 }
551
552 if (!EFI_ERROR (Status)) {
553 //
554 // Try to uninstall LoadFile2 protocol if exists
555 //
556 Status = gBS->OpenProtocol (
557 Handle,
558 &gEfiLoadFile2ProtocolGuid,
559 NULL,
560 gPciBusDriverBinding.DriverBindingHandle,
561 Controller,
562 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
563 );
564 if (!EFI_ERROR (Status)) {
565 Status = gBS->UninstallMultipleProtocolInterfaces (
566 Handle,
567 &gEfiLoadFile2ProtocolGuid,
568 &PciIoDevice->LoadFile2,
569 NULL
570 );
571 }
572 //
573 // Restore Status
574 //
575 Status = EFI_SUCCESS;
576 }
577
578
579 if (EFI_ERROR (Status)) {
580 gBS->OpenProtocol (
581 Controller,
582 &gEfiPciRootBridgeIoProtocolGuid,
583 (VOID **) &PciRootBridgeIo,
584 gPciBusDriverBinding.DriverBindingHandle,
585 Handle,
586 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
587 );
588 return Status;
589 }
590
591 //
592 // The Device Driver should disable this device after disconnect
593 // so the Pci Bus driver will not touch this device any more.
594 // Restore the register field to the original value
595 //
596 PciIoDevice->Registered = FALSE;
597 PciIoDevice->Handle = NULL;
598 } else {
599
600 //
601 // Handle may be closed before
602 //
603 return EFI_SUCCESS;
604 }
605
606 return EFI_SUCCESS;
607 }
608
609 /**
610 Start to manage the PCI device on the specified root bridge or PCI-PCI Bridge.
611
612 @param Controller The root bridge handle.
613 @param RootBridge A pointer to the PCI_IO_DEVICE.
614 @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.
615 @param NumberOfChildren Children number.
616 @param ChildHandleBuffer A pointer to the child handle buffer.
617
618 @retval EFI_NOT_READY Device is not allocated.
619 @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.
620 @retval EFI_NOT_FOUND Can not find the specific device.
621 @retval EFI_SUCCESS Success to start Pci devices on bridge.
622
623 **/
624 EFI_STATUS
625 StartPciDevicesOnBridge (
626 IN EFI_HANDLE Controller,
627 IN PCI_IO_DEVICE *RootBridge,
628 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
629 IN OUT UINT8 *NumberOfChildren,
630 IN OUT EFI_HANDLE *ChildHandleBuffer
631 )
632
633 {
634 PCI_IO_DEVICE *PciIoDevice;
635 EFI_DEV_PATH_PTR Node;
636 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
637 EFI_STATUS Status;
638 LIST_ENTRY *CurrentLink;
639 UINT64 Supports;
640
641 PciIoDevice = NULL;
642 CurrentLink = RootBridge->ChildList.ForwardLink;
643
644 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
645
646 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
647 if (RemainingDevicePath != NULL) {
648
649 Node.DevPath = RemainingDevicePath;
650
651 if (Node.Pci->Device != PciIoDevice->DeviceNumber ||
652 Node.Pci->Function != PciIoDevice->FunctionNumber) {
653 CurrentLink = CurrentLink->ForwardLink;
654 continue;
655 }
656
657 //
658 // Check if the device has been assigned with required resource
659 //
660 if (!PciIoDevice->Allocated) {
661 return EFI_NOT_READY;
662 }
663
664 //
665 // Check if the current node has been registered before
666 // If it is not, register it
667 //
668 if (!PciIoDevice->Registered) {
669 Status = RegisterPciDevice (
670 Controller,
671 PciIoDevice,
672 NULL
673 );
674
675 }
676
677 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
678 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
679 (*NumberOfChildren)++;
680 }
681
682 //
683 // Get the next device path
684 //
685 CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);
686 if (IsDevicePathEnd (CurrentDevicePath)) {
687 return EFI_SUCCESS;
688 }
689
690 //
691 // If it is a PPB
692 //
693 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
694 Status = StartPciDevicesOnBridge (
695 Controller,
696 PciIoDevice,
697 CurrentDevicePath,
698 NumberOfChildren,
699 ChildHandleBuffer
700 );
701
702 PciIoDevice->PciIo.Attributes (
703 &(PciIoDevice->PciIo),
704 EfiPciIoAttributeOperationSupported,
705 0,
706 &Supports
707 );
708 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
709 PciIoDevice->PciIo.Attributes (
710 &(PciIoDevice->PciIo),
711 EfiPciIoAttributeOperationEnable,
712 Supports,
713 NULL
714 );
715
716 return Status;
717 } else {
718
719 //
720 // Currently, the PCI bus driver only support PCI-PCI bridge
721 //
722 return EFI_UNSUPPORTED;
723 }
724
725 } else {
726
727 //
728 // If remaining device path is NULL,
729 // try to enable all the pci devices under this bridge
730 //
731 if (!PciIoDevice->Registered && PciIoDevice->Allocated) {
732 Status = RegisterPciDevice (
733 Controller,
734 PciIoDevice,
735 NULL
736 );
737
738 }
739
740 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {
741 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;
742 (*NumberOfChildren)++;
743 }
744
745 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
746 Status = StartPciDevicesOnBridge (
747 Controller,
748 PciIoDevice,
749 RemainingDevicePath,
750 NumberOfChildren,
751 ChildHandleBuffer
752 );
753
754 PciIoDevice->PciIo.Attributes (
755 &(PciIoDevice->PciIo),
756 EfiPciIoAttributeOperationSupported,
757 0,
758 &Supports
759 );
760 Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
761 PciIoDevice->PciIo.Attributes (
762 &(PciIoDevice->PciIo),
763 EfiPciIoAttributeOperationEnable,
764 Supports,
765 NULL
766 );
767
768 }
769
770 CurrentLink = CurrentLink->ForwardLink;
771 }
772 }
773
774 if (PciIoDevice == NULL) {
775 return EFI_NOT_FOUND;
776 } else {
777 return EFI_SUCCESS;
778 }
779 }
780
781 /**
782 Start to manage all the PCI devices it found previously under
783 the entire host bridge.
784
785 @param Controller The root bridge handle.
786
787 @retval EFI_NOT_READY Device is not allocated.
788 @retval EFI_SUCCESS Success to start Pci device on host bridge.
789
790 **/
791 EFI_STATUS
792 StartPciDevices (
793 IN EFI_HANDLE Controller
794 )
795 {
796 PCI_IO_DEVICE *RootBridge;
797 EFI_HANDLE ThisHostBridge;
798 LIST_ENTRY *CurrentLink;
799
800 RootBridge = GetRootBridgeByHandle (Controller);
801 ASSERT (RootBridge != NULL);
802 ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;
803
804 CurrentLink = mPciDevicePool.ForwardLink;
805
806 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
807
808 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
809 //
810 // Locate the right root bridge to start
811 //
812 if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {
813 StartPciDevicesOnBridge (
814 RootBridge->Handle,
815 RootBridge,
816 NULL,
817 NULL,
818 NULL
819 );
820 }
821
822 CurrentLink = CurrentLink->ForwardLink;
823 }
824
825 return EFI_SUCCESS;
826 }
827
828 /**
829 Create root bridge device.
830
831 @param RootBridgeHandle Specified root bridge hanle.
832
833 @return The crated root bridge device instance, NULL means no
834 root bridge device instance created.
835
836 **/
837 PCI_IO_DEVICE *
838 CreateRootBridge (
839 IN EFI_HANDLE RootBridgeHandle
840 )
841 {
842 EFI_STATUS Status;
843 PCI_IO_DEVICE *Dev;
844 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
845 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
846
847 Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
848 if (Dev == NULL) {
849 return NULL;
850 }
851
852 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;
853 Dev->Handle = RootBridgeHandle;
854 InitializeListHead (&Dev->ChildList);
855
856 Status = gBS->OpenProtocol (
857 RootBridgeHandle,
858 &gEfiDevicePathProtocolGuid,
859 (VOID **) &ParentDevicePath,
860 gPciBusDriverBinding.DriverBindingHandle,
861 RootBridgeHandle,
862 EFI_OPEN_PROTOCOL_GET_PROTOCOL
863 );
864
865 if (EFI_ERROR (Status)) {
866 FreePool (Dev);
867 return NULL;
868 }
869
870 //
871 // Record the root bridge parent device path
872 //
873 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);
874
875 //
876 // Get the pci root bridge io protocol
877 //
878 Status = gBS->OpenProtocol (
879 RootBridgeHandle,
880 &gEfiPciRootBridgeIoProtocolGuid,
881 (VOID **) &PciRootBridgeIo,
882 gPciBusDriverBinding.DriverBindingHandle,
883 RootBridgeHandle,
884 EFI_OPEN_PROTOCOL_GET_PROTOCOL
885 );
886
887 if (EFI_ERROR (Status)) {
888 FreePciDevice (Dev);
889 return NULL;
890 }
891
892 Dev->PciRootBridgeIo = PciRootBridgeIo;
893
894 //
895 // Initialize the PCI I/O instance structure
896 //
897 InitializePciIoInstance (Dev);
898 InitializePciDriverOverrideInstance (Dev);
899 InitializePciLoadFile2 (Dev);
900
901 //
902 // Initialize reserved resource list and
903 // option rom driver list
904 //
905 InitializeListHead (&Dev->ReservedResourceList);
906 InitializeListHead (&Dev->OptionRomDriverList);
907
908 return Dev;
909 }
910
911 /**
912 Get root bridge device instance by specific root bridge handle.
913
914 @param RootBridgeHandle Given root bridge handle.
915
916 @return The root bridge device instance, NULL means no root bridge
917 device instance found.
918
919 **/
920 PCI_IO_DEVICE *
921 GetRootBridgeByHandle (
922 EFI_HANDLE RootBridgeHandle
923 )
924 {
925 PCI_IO_DEVICE *RootBridgeDev;
926 LIST_ENTRY *CurrentLink;
927
928 CurrentLink = mPciDevicePool.ForwardLink;
929
930 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
931
932 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
933 if (RootBridgeDev->Handle == RootBridgeHandle) {
934 return RootBridgeDev;
935 }
936
937 CurrentLink = CurrentLink->ForwardLink;
938 }
939
940 return NULL;
941 }
942
943 /**
944 Judege whether Pci device existed.
945
946 @param Bridge Parent bridege instance.
947 @param PciIoDevice Device instance.
948
949 @retval TRUE Pci device existed.
950 @retval FALSE Pci device did not exist.
951
952 **/
953 BOOLEAN
954 PciDeviceExisted (
955 IN PCI_IO_DEVICE *Bridge,
956 IN PCI_IO_DEVICE *PciIoDevice
957 )
958 {
959
960 PCI_IO_DEVICE *Temp;
961 LIST_ENTRY *CurrentLink;
962
963 CurrentLink = Bridge->ChildList.ForwardLink;
964
965 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
966
967 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
968
969 if (Temp == PciIoDevice) {
970 return TRUE;
971 }
972
973 if (!IsListEmpty (&Temp->ChildList)) {
974 if (PciDeviceExisted (Temp, PciIoDevice)) {
975 return TRUE;
976 }
977 }
978
979 CurrentLink = CurrentLink->ForwardLink;
980 }
981
982 return FALSE;
983 }
984
985 /**
986 Get the active VGA device on the same segment.
987
988 @param VgaDevice PCI IO instance for the VGA device.
989
990 @return The active VGA device on the same segment.
991
992 **/
993 PCI_IO_DEVICE *
994 ActiveVGADeviceOnTheSameSegment (
995 IN PCI_IO_DEVICE *VgaDevice
996 )
997 {
998 LIST_ENTRY *CurrentLink;
999 PCI_IO_DEVICE *Temp;
1000
1001 CurrentLink = mPciDevicePool.ForwardLink;
1002
1003 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {
1004
1005 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1006
1007 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {
1008
1009 Temp = ActiveVGADeviceOnTheRootBridge (Temp);
1010
1011 if (Temp != NULL) {
1012 return Temp;
1013 }
1014 }
1015
1016 CurrentLink = CurrentLink->ForwardLink;
1017 }
1018
1019 return NULL;
1020 }
1021
1022 /**
1023 Get the active VGA device on the root bridge.
1024
1025 @param RootBridge PCI IO instance for the root bridge.
1026
1027 @return The active VGA device.
1028
1029 **/
1030 PCI_IO_DEVICE *
1031 ActiveVGADeviceOnTheRootBridge (
1032 IN PCI_IO_DEVICE *RootBridge
1033 )
1034 {
1035 LIST_ENTRY *CurrentLink;
1036 PCI_IO_DEVICE *Temp;
1037
1038 CurrentLink = RootBridge->ChildList.ForwardLink;
1039
1040 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
1041
1042 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1043
1044 if (IS_PCI_VGA(&Temp->Pci) &&
1045 (Temp->Attributes &
1046 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
1047 EFI_PCI_IO_ATTRIBUTE_VGA_IO |
1048 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {
1049 return Temp;
1050 }
1051
1052 if (IS_PCI_BRIDGE (&Temp->Pci)) {
1053
1054 Temp = ActiveVGADeviceOnTheRootBridge (Temp);
1055
1056 if (Temp != NULL) {
1057 return Temp;
1058 }
1059 }
1060
1061 CurrentLink = CurrentLink->ForwardLink;
1062 }
1063
1064 return NULL;
1065 }
1066
1067
1068 /**
1069 Get HPC PCI address according to its device path.
1070
1071 @param RootBridge Root bridege Io instance.
1072 @param RemainingDevicePath Given searching device path.
1073 @param PciAddress Buffer holding searched result.
1074
1075 @retval EFI_SUCCESS PCI address was stored in PciAddress
1076 @retval EFI_NOT_FOUND Can not find the specific device path.
1077
1078 **/
1079 EFI_STATUS
1080 GetHpcPciAddressFromRootBridge (
1081 IN PCI_IO_DEVICE *RootBridge,
1082 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
1083 OUT UINT64 *PciAddress
1084 )
1085 {
1086 EFI_DEV_PATH_PTR Node;
1087 PCI_IO_DEVICE *Temp;
1088 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
1089 LIST_ENTRY *CurrentLink;
1090 BOOLEAN MisMatch;
1091
1092 MisMatch = FALSE;
1093
1094 CurrentDevicePath = RemainingDevicePath;
1095 Node.DevPath = CurrentDevicePath;
1096 Temp = NULL;
1097
1098 while (!IsDevicePathEnd (CurrentDevicePath)) {
1099
1100 CurrentLink = RootBridge->ChildList.ForwardLink;
1101 Node.DevPath = CurrentDevicePath;
1102
1103 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {
1104 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1105
1106 if (Node.Pci->Device == Temp->DeviceNumber &&
1107 Node.Pci->Function == Temp->FunctionNumber) {
1108 RootBridge = Temp;
1109 break;
1110 }
1111
1112 CurrentLink = CurrentLink->ForwardLink;
1113 }
1114
1115 //
1116 // Check if we find the bridge
1117 //
1118 if (CurrentLink == &RootBridge->ChildList) {
1119
1120 MisMatch = TRUE;
1121 break;
1122
1123 }
1124
1125 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
1126 }
1127
1128 if (MisMatch) {
1129
1130 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);
1131
1132 if (IsDevicePathEnd (CurrentDevicePath)) {
1133 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);
1134 return EFI_SUCCESS;
1135 }
1136
1137 return EFI_NOT_FOUND;
1138 }
1139
1140 if (Temp != NULL) {
1141 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
1142 } else {
1143 return EFI_NOT_FOUND;
1144 }
1145
1146 return EFI_SUCCESS;
1147
1148 }
1149