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