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