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