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