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