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