]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Bus/Pci/PciBus/Dxe/PciDeviceSupport.c
The reasons for the changes made are:
[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 is used to register the PCI device to the EFI,
287 create a handle for this PCI device,then attach apporpriate protocols
288 onto the handle.
289
290 Arguments:
291
292 Controller - An efi handle.
293 PciIoDevice - A pointer to the PCI_IO_DEVICE.
294 Handle - A pointer to a efi handle.
295
296 Returns:
297
298 None
299
300 --*/
301 // TODO: EFI_SUCCESS - add return value to function comment
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 zero for cards that come up randomly
341 //
342 PciIo = &(PciIoDevice->PciIo);
343 Data8 = 0xFF;
344 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);
345 //
346 // Process Platform OpRom
347 //
348 if (gPciPlatformProtocol != NULL && !PciIoDevice->AllOpRomProcessed) {
349 PciIoDevice->AllOpRomProcessed = TRUE;
350
351 Status = gPciPlatformProtocol->GetPciRom (
352 gPciPlatformProtocol,
353 PciIoDevice->Handle,
354 &PlatformOpRomBuffer,
355 &PlatformOpRomSize
356 );
357
358 if (!EFI_ERROR (Status)) {
359
360 //
361 // Have Platform OpRom
362 //
363 PciIoDevice->RomSize = PlatformOpRomSize;
364 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;
365 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;
366
367 //
368 // Process Image
369 //
370 ProcessOpRomImage (PciIoDevice);
371 }
372 }
373
374 if (PciIoDevice->BusOverride) {
375 //
376 // Install BusSpecificDriverOverride Protocol
377 //
378 Status = gBS->InstallMultipleProtocolInterfaces (
379 &PciIoDevice->Handle,
380 &gEfiBusSpecificDriverOverrideProtocolGuid,
381 &PciIoDevice->PciDriverOverride,
382 NULL
383 );
384 if (EFI_ERROR (Status)) {
385 gBS->UninstallMultipleProtocolInterfaces (
386 &PciIoDevice->Handle,
387 &gEfiDevicePathProtocolGuid,
388 PciIoDevice->DevicePath,
389 &gEfiPciIoProtocolGuid,
390 &PciIoDevice->PciIo,
391 NULL
392 );
393
394 return Status;
395 }
396 }
397
398 Status = gBS->OpenProtocol (
399 Controller,
400 &gEfiPciRootBridgeIoProtocolGuid,
401 (VOID **) &(PciIoDevice->PciRootBridgeIo),
402 gPciBusDriverBinding.DriverBindingHandle,
403 PciIoDevice->Handle,
404 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
405 );
406 if (EFI_ERROR (Status)) {
407 return Status;
408 }
409
410 //
411 // Install Pccard Hotplug GUID for Pccard device so that
412 // to notify CardBus driver to stop the device when de-register happens
413 //
414 InstallPciHotplugGuid (PciIoDevice);
415
416 if (Handle != NULL) {
417 *Handle = PciIoDevice->Handle;
418 }
419
420 //
421 // Indicate the pci device is registered
422 //
423 PciIoDevice->Registered = TRUE;
424
425 return EFI_SUCCESS;
426 }
427
428 EFI_STATUS
429 RemoveAllPciDeviceOnBridge (
430 EFI_HANDLE RootBridgeHandle,
431 PCI_IO_DEVICE *Bridge
432 )
433 /*++
434
435 Routine Description:
436
437 This function is used to remove the whole PCI devices from the bridge.
438
439 Arguments:
440
441 RootBridgeHandle - An efi handle.
442 Bridge - A pointer to the PCI_IO_DEVICE.
443
444 Returns:
445
446 None
447
448 --*/
449 // TODO: EFI_SUCCESS - add return value to function comment
450 {
451
452 LIST_ENTRY *CurrentLink;
453 PCI_IO_DEVICE *Temp;
454
455 while (!IsListEmpty (&Bridge->ChildList)) {
456
457 CurrentLink = Bridge->ChildList.ForwardLink;
458 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
459
460 //
461 // Check if the current node has been deregistered before
462 // If it is not, then deregister it
463 //
464 if (Temp->Registered) {
465 DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);
466 }
467
468 //
469 // Remove this node from the linked list
470 //
471 RemoveEntryList (CurrentLink);
472
473 if (!IsListEmpty (&Temp->ChildList)) {
474 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
475 }
476
477 FreePciDevice (Temp);
478 }
479
480 return EFI_SUCCESS;
481 }
482
483 EFI_STATUS
484 DeRegisterPciDevice (
485 IN EFI_HANDLE Controller,
486 IN EFI_HANDLE Handle
487 )
488 /*++
489
490 Routine Description:
491
492 This function is used to de-register the PCI device from the EFI,
493 That includes un-installing PciIo protocol from the specified PCI
494 device handle.
495
496 Arguments:
497
498 Controller - An efi handle.
499 Handle - An efi handle.
500
501 Returns:
502
503 None
504
505 --*/
506 // TODO: EFI_SUCCESS - add return value to function comment
507 // TODO: EFI_SUCCESS - add return value to function comment
508 // TODO: EFI_SUCCESS - add return value to function comment
509 {
510 EFI_PCI_IO_PROTOCOL *PciIo;
511 EFI_STATUS Status;
512 PCI_IO_DEVICE *PciIoDevice;
513 PCI_IO_DEVICE *Node;
514 LIST_ENTRY *CurrentLink;
515 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
516
517 Status = gBS->OpenProtocol (
518 Handle,
519 &gEfiPciIoProtocolGuid,
520 (VOID **) &PciIo,
521 gPciBusDriverBinding.DriverBindingHandle,
522 Controller,
523 EFI_OPEN_PROTOCOL_GET_PROTOCOL
524 );
525 if (!EFI_ERROR (Status)) {
526 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
527
528 //
529 // If it is already de-registered
530 //
531 if (!PciIoDevice->Registered) {
532 return EFI_SUCCESS;
533 }
534
535 //
536 // If it is PPB, first de-register its children
537 //
538
539 if (!IsListEmpty (&PciIoDevice->ChildList)) {
540
541 CurrentLink = PciIoDevice->ChildList.ForwardLink;
542
543 while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {
544 Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
545 Status = DeRegisterPciDevice (Controller, Node->Handle);
546
547 if (EFI_ERROR (Status)) {
548 return Status;
549 }
550
551 CurrentLink = CurrentLink->ForwardLink;
552 }
553 }
554 //
555 // Uninstall Pccard Hotplug GUID for Pccard device
556 //
557 UninstallPciHotplugGuid (PciIoDevice);
558
559 //
560 // Close the child handle
561 //
562 Status = gBS->CloseProtocol (
563 Controller,
564 &gEfiPciRootBridgeIoProtocolGuid,
565 gPciBusDriverBinding.DriverBindingHandle,
566 Handle
567 );
568
569 //
570 // Un-install the device path protocol and pci io protocol
571 //
572 if (PciIoDevice->BusOverride) {
573 Status = gBS->UninstallMultipleProtocolInterfaces (
574 Handle,
575 &gEfiDevicePathProtocolGuid,
576 PciIoDevice->DevicePath,
577 &gEfiPciIoProtocolGuid,
578 &PciIoDevice->PciIo,
579 &gEfiBusSpecificDriverOverrideProtocolGuid,
580 &PciIoDevice->PciDriverOverride,
581 NULL
582 );
583 } else {
584 Status = gBS->UninstallMultipleProtocolInterfaces (
585 Handle,
586 &gEfiDevicePathProtocolGuid,
587 PciIoDevice->DevicePath,
588 &gEfiPciIoProtocolGuid,
589 &PciIoDevice->PciIo,
590 NULL
591 );
592 }
593
594 if (EFI_ERROR (Status)) {
595 gBS->OpenProtocol (
596 Controller,
597 &gEfiPciRootBridgeIoProtocolGuid,
598 (VOID **) &PciRootBridgeIo,
599 gPciBusDriverBinding.DriverBindingHandle,
600 Handle,
601 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
602 );
603 return Status;
604 }
605
606 //
607 // The Device Driver should disable this device after disconnect
608 // so the Pci Bus driver will not touch this device any more.
609 // Restore the register field to the original value
610 //
611 PciIoDevice->Registered = FALSE;
612 PciIoDevice->Handle = NULL;
613 } else {
614
615 //
616 // Handle may be closed before
617 //
618 return EFI_SUCCESS;
619 }
620
621 return EFI_SUCCESS;
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 Routine Description:
635
636 Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge
637
638 Arguments:
639
640 Controller - An efi handle.
641 RootBridge - A pointer to the PCI_IO_DEVICE.
642 RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.
643 NumberOfChildren - Children number.
644 ChildHandleBuffer - A pointer to the child handle buffer.
645
646 Returns:
647
648 None
649
650 --*/
651 // TODO: EFI_NOT_READY - add return value to function comment
652 // TODO: EFI_SUCCESS - add return value to function comment
653 // TODO: EFI_UNSUPPORTED - add return value to function comment
654 // TODO: EFI_NOT_FOUND - add return value to function comment
655 {
656 PCI_IO_DEVICE *Temp;
657 PCI_IO_DEVICE *PciIoDevice;
658 EFI_DEV_PATH_PTR Node;
659 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
660 EFI_STATUS Status;
661 LIST_ENTRY *CurrentLink;
662 UINT64 Supports;
663
664 CurrentLink = RootBridge->ChildList.ForwardLink;
665
666 while (CurrentLink && CurrentLink != &RootBridge->ChildList) {
667
668 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
669 if (RemainingDevicePath != NULL) {
670
671 Node.DevPath = RemainingDevicePath;
672
673 if (Node.Pci->Device != Temp->DeviceNumber ||
674 Node.Pci->Function != Temp->FunctionNumber) {
675 CurrentLink = CurrentLink->ForwardLink;
676 continue;
677 }
678
679 //
680 // Check if the device has been assigned with required resource
681 //
682 if (!Temp->Allocated) {
683 return EFI_NOT_READY;
684 }
685
686 //
687 // Check if the current node has been registered before
688 // If it is not, register it
689 //
690 if (!Temp->Registered) {
691 PciIoDevice = Temp;
692
693 Status = RegisterPciDevice (
694 Controller,
695 PciIoDevice,
696 NULL
697 );
698
699 }
700
701 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {
702 ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;
703 (*NumberOfChildren)++;
704 }
705
706 //
707 // Get the next device path
708 //
709 CurrentDevicePath = EfiNextDevicePathNode (RemainingDevicePath);
710 if (EfiIsDevicePathEnd (CurrentDevicePath)) {
711 return EFI_SUCCESS;
712 }
713
714 //
715 // If it is a PPB
716 //
717 if (!IsListEmpty (&Temp->ChildList)) {
718 Status = StartPciDevicesOnBridge (
719 Controller,
720 Temp,
721 CurrentDevicePath,
722 NumberOfChildren,
723 ChildHandleBuffer
724 );
725
726 Temp->PciIo.Attributes (
727 &(Temp->PciIo),
728 EfiPciIoAttributeOperationSupported,
729 0,
730 &Supports
731 );
732 Supports &= EFI_PCI_DEVICE_ENABLE;
733 Temp->PciIo.Attributes (
734 &(Temp->PciIo),
735 EfiPciIoAttributeOperationEnable,
736 Supports,
737 NULL
738 );
739
740 return Status;
741 } else {
742
743 //
744 // Currently, the PCI bus driver only support PCI-PCI bridge
745 //
746 return EFI_UNSUPPORTED;
747 }
748
749 } else {
750
751 //
752 // If remaining device path is NULL,
753 // try to enable all the pci devices under this bridge
754 //
755
756 if (!Temp->Registered && Temp->Allocated) {
757
758 PciIoDevice = Temp;
759
760 Status = RegisterPciDevice (
761 Controller,
762 PciIoDevice,
763 NULL
764 );
765
766 }
767
768 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && Temp->Registered) {
769 ChildHandleBuffer[*NumberOfChildren] = Temp->Handle;
770 (*NumberOfChildren)++;
771 }
772
773 if (!IsListEmpty (&Temp->ChildList)) {
774 Status = StartPciDevicesOnBridge (
775 Controller,
776 Temp,
777 RemainingDevicePath,
778 NumberOfChildren,
779 ChildHandleBuffer
780 );
781
782 Temp->PciIo.Attributes (
783 &(Temp->PciIo),
784 EfiPciIoAttributeOperationSupported,
785 0,
786 &Supports
787 );
788 Supports &= EFI_PCI_DEVICE_ENABLE;
789 Temp->PciIo.Attributes (
790 &(Temp->PciIo),
791 EfiPciIoAttributeOperationEnable,
792 Supports,
793 NULL
794 );
795
796 }
797
798 CurrentLink = CurrentLink->ForwardLink;
799 continue;
800 }
801 }
802
803 return EFI_NOT_FOUND;
804 }
805
806 EFI_STATUS
807 StartPciDevices (
808 IN EFI_HANDLE Controller,
809 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
810 )
811 /*++
812
813 Routine Description:
814
815 Start to manage the PCI device according to RemainingDevicePath
816 If RemainingDevicePath == NULL, the PCI bus driver will start
817 to manage all the PCI devices it found previously
818
819 Arguments:
820 Controller - An efi handle.
821 RemainingDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCOL.
822
823 Returns:
824
825 None
826
827 --*/
828 // TODO: EFI_UNSUPPORTED - add return value to function comment
829 // TODO: EFI_SUCCESS - add return value to function comment
830 {
831 EFI_DEV_PATH_PTR Node;
832 PCI_IO_DEVICE *RootBridge;
833 LIST_ENTRY *CurrentLink;
834
835 if (RemainingDevicePath != NULL) {
836
837 //
838 // Check if the RemainingDevicePath is valid
839 //
840 Node.DevPath = RemainingDevicePath;
841 if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||
842 ((Node.DevPath->SubType != HW_PCI_DP) &&
843 (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))
844 ) {
845 return EFI_UNSUPPORTED;
846 }
847 }
848
849 CurrentLink = gPciDevicePool.ForwardLink;
850
851 while (CurrentLink && CurrentLink != &gPciDevicePool) {
852
853 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
854 //
855 // Locate the right root bridge to start
856 //
857 if (RootBridge->Handle == Controller) {
858 StartPciDevicesOnBridge (
859 Controller,
860 RootBridge,
861 RemainingDevicePath,
862 NULL,
863 NULL
864 );
865 }
866
867 CurrentLink = CurrentLink->ForwardLink;
868 }
869
870 return EFI_SUCCESS;
871 }
872
873 PCI_IO_DEVICE *
874 CreateRootBridge (
875 IN EFI_HANDLE RootBridgeHandle
876 )
877 /*++
878
879 Routine Description:
880
881
882 Arguments:
883 RootBridgeHandle - An efi handle.
884
885 Returns:
886
887 None
888
889 --*/
890 {
891
892 EFI_STATUS Status;
893 PCI_IO_DEVICE *Dev;
894 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
895 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
896
897 Dev = NULL;
898 Status = gBS->AllocatePool (
899 EfiBootServicesData,
900 sizeof (PCI_IO_DEVICE),
901 (VOID **) &Dev
902 );
903
904 if (EFI_ERROR (Status)) {
905 return NULL;
906 }
907
908 ZeroMem (Dev, sizeof (PCI_IO_DEVICE));
909 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;
910 Dev->Handle = RootBridgeHandle;
911 InitializeListHead (&Dev->ChildList);
912
913 Status = gBS->OpenProtocol (
914 RootBridgeHandle,
915 &gEfiDevicePathProtocolGuid,
916 (VOID **) &ParentDevicePath,
917 gPciBusDriverBinding.DriverBindingHandle,
918 RootBridgeHandle,
919 EFI_OPEN_PROTOCOL_GET_PROTOCOL
920 );
921
922 if (EFI_ERROR (Status)) {
923 gBS->FreePool (Dev);
924 return NULL;
925 }
926
927 //
928 // Record the root bridge parent device path
929 //
930 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);
931
932 //
933 // Get the pci root bridge io protocol
934 //
935 Status = gBS->OpenProtocol (
936 RootBridgeHandle,
937 &gEfiPciRootBridgeIoProtocolGuid,
938 (VOID **) &PciRootBridgeIo,
939 gPciBusDriverBinding.DriverBindingHandle,
940 RootBridgeHandle,
941 EFI_OPEN_PROTOCOL_GET_PROTOCOL
942 );
943
944 if (EFI_ERROR (Status)) {
945 FreePciDevice (Dev);
946 return NULL;
947 }
948
949 Dev->PciRootBridgeIo = PciRootBridgeIo;
950
951 //
952 // Initialize the PCI I/O instance structure
953 //
954 Status = InitializePciIoInstance (Dev);
955 Status = InitializePciDriverOverrideInstance (Dev);
956
957 //
958 // Initialize reserved resource list and
959 // option rom driver list
960 //
961 InitializeListHead (&Dev->ReservedResourceList);
962 InitializeListHead (&Dev->OptionRomDriverList);
963
964 return Dev;
965 }
966
967 PCI_IO_DEVICE *
968 GetRootBridgeByHandle (
969 EFI_HANDLE RootBridgeHandle
970 )
971 /*++
972
973 Routine Description:
974
975
976 Arguments:
977
978 RootBridgeHandle - An efi handle.
979
980 Returns:
981
982 None
983
984 --*/
985 {
986 PCI_IO_DEVICE *RootBridgeDev;
987 LIST_ENTRY *CurrentLink;
988
989 CurrentLink = gPciDevicePool.ForwardLink;
990
991 while (CurrentLink && CurrentLink != &gPciDevicePool) {
992
993 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
994 if (RootBridgeDev->Handle == RootBridgeHandle) {
995 return RootBridgeDev;
996 }
997
998 CurrentLink = CurrentLink->ForwardLink;
999 }
1000
1001 return NULL;
1002 }
1003
1004 BOOLEAN
1005 RootBridgeExisted (
1006 IN EFI_HANDLE RootBridgeHandle
1007 )
1008 /*++
1009
1010 Routine Description:
1011
1012 This function searches if RootBridgeHandle has already existed
1013 in current device pool.
1014
1015 If so, it means the given root bridge has been already enumerated.
1016
1017 Arguments:
1018
1019 RootBridgeHandle - An efi handle.
1020
1021 Returns:
1022
1023 None
1024
1025 --*/
1026 {
1027 PCI_IO_DEVICE *Bridge;
1028
1029 Bridge = GetRootBridgeByHandle (RootBridgeHandle);
1030
1031 if (Bridge != NULL) {
1032 return TRUE;
1033 }
1034
1035 return FALSE;
1036 }
1037
1038 BOOLEAN
1039 PciDeviceExisted (
1040 IN PCI_IO_DEVICE *Bridge,
1041 IN PCI_IO_DEVICE *PciIoDevice
1042 )
1043 /*++
1044
1045 Routine Description:
1046
1047 Arguments:
1048
1049 Bridge - A pointer to the PCI_IO_DEVICE.
1050 PciIoDevice - A pointer to the PCI_IO_DEVICE.
1051
1052 Returns:
1053
1054 None
1055
1056 --*/
1057 {
1058
1059 PCI_IO_DEVICE *Temp;
1060 LIST_ENTRY *CurrentLink;
1061
1062 CurrentLink = Bridge->ChildList.ForwardLink;
1063
1064 while (CurrentLink && CurrentLink != &Bridge->ChildList) {
1065
1066 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1067
1068 if (Temp == PciIoDevice) {
1069 return TRUE;
1070 }
1071
1072 if (!IsListEmpty (&Temp->ChildList)) {
1073 if (PciDeviceExisted (Temp, PciIoDevice)) {
1074 return TRUE;
1075 }
1076 }
1077
1078 CurrentLink = CurrentLink->ForwardLink;
1079 }
1080
1081 return FALSE;
1082 }
1083
1084 PCI_IO_DEVICE *
1085 ActiveVGADeviceOnTheSameSegment (
1086 IN PCI_IO_DEVICE *VgaDevice
1087 )
1088 /*++
1089
1090 Routine Description:
1091
1092 Arguments:
1093
1094 VgaDevice - A pointer to the PCI_IO_DEVICE.
1095
1096 Returns:
1097
1098 None
1099
1100 --*/
1101 {
1102 LIST_ENTRY *CurrentLink;
1103 PCI_IO_DEVICE *Temp;
1104
1105 CurrentLink = gPciDevicePool.ForwardLink;
1106
1107 while (CurrentLink && CurrentLink != &gPciDevicePool) {
1108
1109 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1110
1111 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {
1112
1113 Temp = ActiveVGADeviceOnTheRootBridge (Temp);
1114
1115 if (Temp != NULL) {
1116 return Temp;
1117 }
1118 }
1119
1120 CurrentLink = CurrentLink->ForwardLink;
1121 }
1122
1123 return NULL;
1124 }
1125
1126 PCI_IO_DEVICE *
1127 ActiveVGADeviceOnTheRootBridge (
1128 IN PCI_IO_DEVICE *RootBridge
1129 )
1130 /*++
1131
1132 Routine Description:
1133
1134 Arguments:
1135
1136 RootBridge - A pointer to the PCI_IO_DEVICE.
1137
1138 Returns:
1139
1140 None
1141
1142 --*/
1143 {
1144 LIST_ENTRY *CurrentLink;
1145 PCI_IO_DEVICE *Temp;
1146
1147 CurrentLink = RootBridge->ChildList.ForwardLink;
1148
1149 while (CurrentLink && CurrentLink != &RootBridge->ChildList) {
1150
1151 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1152
1153 if (IS_PCI_VGA(&Temp->Pci) &&
1154 (Temp->Attributes &
1155 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |
1156 EFI_PCI_IO_ATTRIBUTE_VGA_IO |
1157 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16))) {
1158 return Temp;
1159 }
1160
1161 if (IS_PCI_BRIDGE (&Temp->Pci)) {
1162
1163 Temp = ActiveVGADeviceOnTheRootBridge (Temp);
1164
1165 if (Temp != NULL) {
1166 return Temp;
1167 }
1168 }
1169
1170 CurrentLink = CurrentLink->ForwardLink;
1171 }
1172
1173 return NULL;
1174 }
1175
1176 EFI_STATUS
1177 GetHpcPciAddress (
1178 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
1179 IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,
1180 OUT UINT64 *PciAddress
1181 )
1182 /*++
1183
1184 Routine Description:
1185
1186 Arguments:
1187
1188 PciRootBridgeIo - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1189 HpcDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCL.
1190 PciAddress - A pointer to the pci address.
1191
1192 Returns:
1193
1194 None
1195
1196 --*/
1197 // TODO: EFI_NOT_FOUND - add return value to function comment
1198 // TODO: EFI_NOT_FOUND - add return value to function comment
1199 // TODO: EFI_SUCCESS - add return value to function comment
1200 // TODO: EFI_NOT_FOUND - add return value to function comment
1201 {
1202 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
1203 EFI_DEV_PATH_PTR Node;
1204 LIST_ENTRY *CurrentLink;
1205 PCI_IO_DEVICE *RootBridge;
1206 EFI_STATUS Status;
1207
1208 CurrentDevicePath = HpcDevicePath;
1209
1210 //
1211 // Get the remaining device path for this PCI device, if it is a PCI device
1212 //
1213 while (!EfiIsDevicePathEnd (CurrentDevicePath)) {
1214
1215 Node.DevPath = CurrentDevicePath;
1216
1217 //
1218 // Check if it is PCI device Path?
1219 //
1220 if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||
1221 ((Node.DevPath->SubType != HW_PCI_DP) &&
1222 (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))) {
1223 CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);
1224 continue;
1225 }
1226
1227 break;
1228 }
1229
1230 //
1231 // Check if it is not PCI device path
1232 //
1233 if (EfiIsDevicePathEnd (CurrentDevicePath)) {
1234 return EFI_NOT_FOUND;
1235 }
1236
1237 CurrentLink = gPciDevicePool.ForwardLink;
1238
1239 while (CurrentLink && CurrentLink != &gPciDevicePool) {
1240
1241 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1242 //
1243 // Locate the right root bridge to start
1244 //
1245 if (RootBridge->PciRootBridgeIo == PciRootBridgeIo) {
1246 Status = GetHpcPciAddressFromRootBridge (
1247 RootBridge,
1248 CurrentDevicePath,
1249 PciAddress
1250 );
1251 if (EFI_ERROR (Status)) {
1252 return EFI_NOT_FOUND;
1253 }
1254
1255 return EFI_SUCCESS;
1256
1257 }
1258
1259 CurrentLink = CurrentLink->ForwardLink;
1260 }
1261
1262 return EFI_NOT_FOUND;
1263 }
1264
1265 EFI_STATUS
1266 GetHpcPciAddressFromRootBridge (
1267 IN PCI_IO_DEVICE *RootBridge,
1268 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,
1269 OUT UINT64 *PciAddress
1270 )
1271 /*++
1272
1273 Routine Description:
1274
1275 Arguments:
1276
1277 PciRootBridgeIo - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1278 HpcDevicePath - A pointer to the EFI_DEVICE_PATH_PROTOCL.
1279 PciAddress - A pointer to the pci address.
1280
1281 Returns:
1282
1283 None
1284
1285 --*/
1286 // TODO: RootBridge - add argument and description to function comment
1287 // TODO: RemainingDevicePath - add argument and description to function comment
1288 // TODO: EFI_SUCCESS - add return value to function comment
1289 // TODO: EFI_NOT_FOUND - add return value to function comment
1290 // TODO: EFI_SUCCESS - add return value to function comment
1291 {
1292 EFI_DEV_PATH_PTR Node;
1293 PCI_IO_DEVICE *Temp;
1294 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;
1295 LIST_ENTRY *CurrentLink;
1296 BOOLEAN MisMatch;
1297
1298 MisMatch = FALSE;
1299
1300 CurrentDevicePath = RemainingDevicePath;
1301 Node.DevPath = CurrentDevicePath;
1302 Temp = NULL;
1303
1304 while (!EfiIsDevicePathEnd (CurrentDevicePath)) {
1305
1306 CurrentLink = RootBridge->ChildList.ForwardLink;
1307 Node.DevPath = CurrentDevicePath;
1308
1309 while (CurrentLink && CurrentLink != &RootBridge->ChildList) {
1310 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1311
1312 if (Node.Pci->Device == Temp->DeviceNumber &&
1313 Node.Pci->Function == Temp->FunctionNumber) {
1314 RootBridge = Temp;
1315 break;
1316 }
1317
1318 CurrentLink = CurrentLink->ForwardLink;
1319 }
1320
1321 //
1322 // Check if we find the bridge
1323 //
1324 if (CurrentLink == &RootBridge->ChildList) {
1325
1326 MisMatch = TRUE;
1327 break;
1328
1329 }
1330
1331 CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);
1332 }
1333
1334 if (MisMatch) {
1335
1336 CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);
1337
1338 if (EfiIsDevicePathEnd (CurrentDevicePath)) {
1339 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);
1340 return EFI_SUCCESS;
1341 }
1342
1343 return EFI_NOT_FOUND;
1344 }
1345
1346 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
1347
1348 return EFI_SUCCESS;
1349
1350 }