]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciLib.c
615bbaa4dc909c7b9c51e2e8d90eaaa28f400053
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciLib.c
1 /** @file
2 Internal library implementation for PCI Bus module.
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 /**
19 Retrieve the PCI Card device BAR information via PciIo interface.
20
21 @param PciIoDevice PCI Card device instance.
22
23 **/
24 VOID
25 GetBackPcCardBar (
26 IN PCI_IO_DEVICE *PciIoDevice
27 )
28 {
29 UINT32 Address;
30
31 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
32 return;
33 }
34
35 //
36 // Read PciBar information from the bar register
37 //
38 if (!gFullEnumeration) {
39 Address = 0;
40 PciIoRead (
41 &(PciIoDevice->PciIo),
42 EfiPciIoWidthUint32,
43 PCI_CARD_MEMORY_BASE_0,
44 1,
45 &Address
46 );
47
48 (PciIoDevice->PciBar)[P2C_MEM_1].BaseAddress = (UINT64) (Address);
49 (PciIoDevice->PciBar)[P2C_MEM_1].Length = 0x2000000;
50 (PciIoDevice->PciBar)[P2C_MEM_1].BarType = PciBarTypeMem32;
51
52 Address = 0;
53 PciIoRead (
54 &(PciIoDevice->PciIo),
55 EfiPciIoWidthUint32,
56 PCI_CARD_MEMORY_BASE_1,
57 1,
58 &Address
59 );
60 (PciIoDevice->PciBar)[P2C_MEM_2].BaseAddress = (UINT64) (Address);
61 (PciIoDevice->PciBar)[P2C_MEM_2].Length = 0x2000000;
62 (PciIoDevice->PciBar)[P2C_MEM_2].BarType = PciBarTypePMem32;
63
64 Address = 0;
65 PciIoRead (
66 &(PciIoDevice->PciIo),
67 EfiPciIoWidthUint32,
68 PCI_CARD_IO_BASE_0_LOWER,
69 1,
70 &Address
71 );
72 (PciIoDevice->PciBar)[P2C_IO_1].BaseAddress = (UINT64) (Address);
73 (PciIoDevice->PciBar)[P2C_IO_1].Length = 0x100;
74 (PciIoDevice->PciBar)[P2C_IO_1].BarType = PciBarTypeIo16;
75
76 Address = 0;
77 PciIoRead (
78 &(PciIoDevice->PciIo),
79 EfiPciIoWidthUint32,
80 PCI_CARD_IO_BASE_1_LOWER,
81 1,
82 &Address
83 );
84 (PciIoDevice->PciBar)[P2C_IO_2].BaseAddress = (UINT64) (Address);
85 (PciIoDevice->PciBar)[P2C_IO_2].Length = 0x100;
86 (PciIoDevice->PciBar)[P2C_IO_2].BarType = PciBarTypeIo16;
87
88 }
89
90 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
91 GetResourcePaddingForHpb (PciIoDevice);
92 }
93 }
94
95 /**
96 Remove rejected pci device from specific root bridge
97 handle.
98
99 @param RootBridgeHandle Specific parent root bridge handle.
100 @param Bridge Bridge device instance.
101
102 **/
103 VOID
104 RemoveRejectedPciDevices (
105 IN EFI_HANDLE RootBridgeHandle,
106 IN PCI_IO_DEVICE *Bridge
107 )
108 {
109 PCI_IO_DEVICE *Temp;
110 LIST_ENTRY *CurrentLink;
111 LIST_ENTRY *LastLink;
112
113 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
114 return;
115 }
116
117 CurrentLink = Bridge->ChildList.ForwardLink;
118
119 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
120
121 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
122
123 if (IS_PCI_BRIDGE (&Temp->Pci)) {
124 //
125 // Remove rejected devices recusively
126 //
127 RemoveRejectedPciDevices (RootBridgeHandle, Temp);
128 } else {
129 //
130 // Skip rejection for all PPBs, while detect rejection for others
131 //
132 if (IsPciDeviceRejected (Temp)) {
133
134 //
135 // For P2C, remove all devices on it
136 //
137 if (!IsListEmpty (&Temp->ChildList)) {
138 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
139 }
140
141 //
142 // Finally remove itself
143 //
144 LastLink = CurrentLink->BackLink;
145 RemoveEntryList (CurrentLink);
146 FreePciDevice (Temp);
147
148 CurrentLink = LastLink;
149 }
150 }
151
152 CurrentLink = CurrentLink->ForwardLink;
153 }
154 }
155
156 /**
157 Submits the I/O and memory resource requirements for the specified PCI Host Bridge.
158
159 @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
160
161 @retval EFI_SUCCESS Successfully finished resource allocation.
162 @retval EFI_NOT_FOUND Cannot get root bridge instance.
163 @retval EFI_OUT_OF_RESOURCES Platform failed to program the resources if no hot plug supported.
164 @retval other Some error occurred when allocating resources for the PCI Host Bridge.
165
166 @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
167
168 **/
169 EFI_STATUS
170 PciHostBridgeResourceAllocator (
171 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
172 )
173 {
174 PCI_IO_DEVICE *RootBridgeDev;
175 EFI_HANDLE RootBridgeHandle;
176 VOID *AcpiConfig;
177 EFI_STATUS Status;
178 UINT64 IoBase;
179 UINT64 Mem32Base;
180 UINT64 PMem32Base;
181 UINT64 Mem64Base;
182 UINT64 PMem64Base;
183 UINT64 IoResStatus;
184 UINT64 Mem32ResStatus;
185 UINT64 PMem32ResStatus;
186 UINT64 Mem64ResStatus;
187 UINT64 PMem64ResStatus;
188 UINT64 MaxOptionRomSize;
189 PCI_RESOURCE_NODE *IoBridge;
190 PCI_RESOURCE_NODE *Mem32Bridge;
191 PCI_RESOURCE_NODE *PMem32Bridge;
192 PCI_RESOURCE_NODE *Mem64Bridge;
193 PCI_RESOURCE_NODE *PMem64Bridge;
194 PCI_RESOURCE_NODE IoPool;
195 PCI_RESOURCE_NODE Mem32Pool;
196 PCI_RESOURCE_NODE PMem32Pool;
197 PCI_RESOURCE_NODE Mem64Pool;
198 PCI_RESOURCE_NODE PMem64Pool;
199 BOOLEAN ReAllocate;
200 EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD HandleExtendedData;
201 EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;
202
203 //
204 // Reallocate flag
205 //
206 ReAllocate = FALSE;
207
208 //
209 // It may try several times if the resource allocation fails
210 //
211 while (TRUE) {
212 //
213 // Initialize resource pool
214 //
215 InitializeResourcePool (&IoPool, PciBarTypeIo16);
216 InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);
217 InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);
218 InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);
219 InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);
220
221 RootBridgeDev = NULL;
222 RootBridgeHandle = 0;
223
224 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
225 //
226 // Get Root Bridge Device by handle
227 //
228 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
229
230 if (RootBridgeDev == NULL) {
231 return EFI_NOT_FOUND;
232 }
233
234 //
235 // Create the entire system resource map from the information collected by
236 // enumerator. Several resource tree was created
237 //
238
239 IoBridge = CreateResourceNode (
240 RootBridgeDev,
241 0,
242 0xFFF,
243 0,
244 PciBarTypeIo16,
245 PciResUsageTypical
246 );
247
248 Mem32Bridge = CreateResourceNode (
249 RootBridgeDev,
250 0,
251 0xFFFFF,
252 0,
253 PciBarTypeMem32,
254 PciResUsageTypical
255 );
256
257 PMem32Bridge = CreateResourceNode (
258 RootBridgeDev,
259 0,
260 0xFFFFF,
261 0,
262 PciBarTypePMem32,
263 PciResUsageTypical
264 );
265
266 Mem64Bridge = CreateResourceNode (
267 RootBridgeDev,
268 0,
269 0xFFFFF,
270 0,
271 PciBarTypeMem64,
272 PciResUsageTypical
273 );
274
275 PMem64Bridge = CreateResourceNode (
276 RootBridgeDev,
277 0,
278 0xFFFFF,
279 0,
280 PciBarTypePMem64,
281 PciResUsageTypical
282 );
283
284 //
285 // Create resourcemap by going through all the devices subject to this root bridge
286 //
287 CreateResourceMap (
288 RootBridgeDev,
289 IoBridge,
290 Mem32Bridge,
291 PMem32Bridge,
292 Mem64Bridge,
293 PMem64Bridge
294 );
295
296 //
297 // Get the max ROM size that the root bridge can process
298 //
299 RootBridgeDev->RomSize = Mem32Bridge->Length;
300
301 //
302 // Skip to enlarge the resource request during realloction
303 //
304 if (!ReAllocate) {
305 //
306 // Get Max Option Rom size for current root bridge
307 //
308 MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);
309
310 //
311 // Enlarger the mem32 resource to accomdate the option rom
312 // if the mem32 resource is not enough to hold the rom
313 //
314 if (MaxOptionRomSize > Mem32Bridge->Length) {
315
316 Mem32Bridge->Length = MaxOptionRomSize;
317 RootBridgeDev->RomSize = MaxOptionRomSize;
318
319 //
320 // Alignment should be adjusted as well
321 //
322 if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) {
323 Mem32Bridge->Alignment = MaxOptionRomSize - 1;
324 }
325 }
326 }
327
328 //
329 // Based on the all the resource tree, contruct ACPI resource node to
330 // submit the resource aperture to pci host bridge protocol
331 //
332 Status = ConstructAcpiResourceRequestor (
333 RootBridgeDev,
334 IoBridge,
335 Mem32Bridge,
336 PMem32Bridge,
337 Mem64Bridge,
338 PMem64Bridge,
339 &AcpiConfig
340 );
341
342 //
343 // Insert these resource nodes into the database
344 //
345 InsertResourceNode (&IoPool, IoBridge);
346 InsertResourceNode (&Mem32Pool, Mem32Bridge);
347 InsertResourceNode (&PMem32Pool, PMem32Bridge);
348 InsertResourceNode (&Mem64Pool, Mem64Bridge);
349 InsertResourceNode (&PMem64Pool, PMem64Bridge);
350
351 if (Status == EFI_SUCCESS) {
352 //
353 // Submit the resource requirement
354 //
355 Status = PciResAlloc->SubmitResources (
356 PciResAlloc,
357 RootBridgeDev->Handle,
358 AcpiConfig
359 );
360 }
361
362 //
363 // Free acpi resource node
364 //
365 if (AcpiConfig != NULL) {
366 FreePool (AcpiConfig);
367 }
368
369 if (EFI_ERROR (Status)) {
370 //
371 // Destroy all the resource tree
372 //
373 DestroyResourceTree (&IoPool);
374 DestroyResourceTree (&Mem32Pool);
375 DestroyResourceTree (&PMem32Pool);
376 DestroyResourceTree (&Mem64Pool);
377 DestroyResourceTree (&PMem64Pool);
378 return Status;
379 }
380 }
381 //
382 // End while, at least one Root Bridge should be found.
383 //
384 ASSERT (RootBridgeDev != NULL);
385
386 //
387 // Notify platform to start to program the resource
388 //
389 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);
390 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
391 //
392 // If Hot Plug is not supported
393 //
394 if (EFI_ERROR (Status)) {
395 //
396 // Allocation failed, then return
397 //
398 return EFI_OUT_OF_RESOURCES;
399 }
400 //
401 // Allocation succeed.
402 // Get host bridge handle for status report, and then skip the main while
403 //
404 HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
405
406 break;
407
408 } else {
409 //
410 // If Hot Plug is supported
411 //
412 if (!EFI_ERROR (Status)) {
413 //
414 // Allocation succeed, then continue the following
415 //
416 break;
417 }
418
419 //
420 // If the resource allocation is unsuccessful, free resources on bridge
421 //
422
423 RootBridgeDev = NULL;
424 RootBridgeHandle = 0;
425
426 IoResStatus = EFI_RESOURCE_SATISFIED;
427 Mem32ResStatus = EFI_RESOURCE_SATISFIED;
428 PMem32ResStatus = EFI_RESOURCE_SATISFIED;
429 Mem64ResStatus = EFI_RESOURCE_SATISFIED;
430 PMem64ResStatus = EFI_RESOURCE_SATISFIED;
431
432 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
433 //
434 // Get RootBridg Device by handle
435 //
436 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
437 if (RootBridgeDev == NULL) {
438 return EFI_NOT_FOUND;
439 }
440
441 //
442 // Get host bridge handle for status report
443 //
444 HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
445
446 //
447 // Get acpi resource node for all the resource types
448 //
449 AcpiConfig = NULL;
450
451 Status = PciResAlloc->GetProposedResources (
452 PciResAlloc,
453 RootBridgeDev->Handle,
454 &AcpiConfig
455 );
456
457 if (EFI_ERROR (Status)) {
458 return Status;
459 }
460
461 if (AcpiConfig != NULL) {
462 //
463 // Adjust resource allocation policy for each RB
464 //
465 GetResourceAllocationStatus (
466 AcpiConfig,
467 &IoResStatus,
468 &Mem32ResStatus,
469 &PMem32ResStatus,
470 &Mem64ResStatus,
471 &PMem64ResStatus
472 );
473 FreePool (AcpiConfig);
474 }
475 }
476 //
477 // End while
478 //
479
480 //
481 // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
482 //
483 //
484 // It is very difficult to follow the spec here
485 // Device path , Bar index can not be get here
486 //
487 ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));
488
489 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
490 EFI_PROGRESS_CODE,
491 EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,
492 (VOID *) &AllocFailExtendedData,
493 sizeof (AllocFailExtendedData)
494 );
495
496 Status = PciHostBridgeAdjustAllocation (
497 &IoPool,
498 &Mem32Pool,
499 &PMem32Pool,
500 &Mem64Pool,
501 &PMem64Pool,
502 IoResStatus,
503 Mem32ResStatus,
504 PMem32ResStatus,
505 Mem64ResStatus,
506 PMem64ResStatus
507 );
508
509 //
510 // Destroy all the resource tree
511 //
512 DestroyResourceTree (&IoPool);
513 DestroyResourceTree (&Mem32Pool);
514 DestroyResourceTree (&PMem32Pool);
515 DestroyResourceTree (&Mem64Pool);
516 DestroyResourceTree (&PMem64Pool);
517
518 NotifyPhase (PciResAlloc, EfiPciHostBridgeFreeResources);
519
520 if (EFI_ERROR (Status)) {
521 return Status;
522 }
523
524 ReAllocate = TRUE;
525 }
526 }
527 //
528 // End main while
529 //
530
531 //
532 // Raise the EFI_IOB_PCI_RES_ALLOC status code
533 //
534 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
535 EFI_PROGRESS_CODE,
536 EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_RES_ALLOC,
537 (VOID *) &HandleExtendedData,
538 sizeof (HandleExtendedData)
539 );
540
541 //
542 // Notify pci bus driver starts to program the resource
543 //
544 NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);
545
546 RootBridgeDev = NULL;
547
548 RootBridgeHandle = 0;
549
550 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
551 //
552 // Get RootBridg Device by handle
553 //
554 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
555
556 if (RootBridgeDev == NULL) {
557 return EFI_NOT_FOUND;
558 }
559
560 //
561 // Get acpi resource node for all the resource types
562 //
563 AcpiConfig = NULL;
564 Status = PciResAlloc->GetProposedResources (
565 PciResAlloc,
566 RootBridgeDev->Handle,
567 &AcpiConfig
568 );
569
570 if (EFI_ERROR (Status)) {
571 return Status;
572 }
573
574 //
575 // Get the resource base by interpreting acpi resource node
576 //
577 //
578 GetResourceBase (
579 AcpiConfig,
580 &IoBase,
581 &Mem32Base,
582 &PMem32Base,
583 &Mem64Base,
584 &PMem64Base
585 );
586
587 //
588 // Process option rom for this root bridge
589 //
590 ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize);
591
592 //
593 // Create the entire system resource map from the information collected by
594 // enumerator. Several resource tree was created
595 //
596 GetResourceMap (
597 RootBridgeDev,
598 &IoBridge,
599 &Mem32Bridge,
600 &PMem32Bridge,
601 &Mem64Bridge,
602 &PMem64Bridge,
603 &IoPool,
604 &Mem32Pool,
605 &PMem32Pool,
606 &Mem64Pool,
607 &PMem64Pool
608 );
609
610 //
611 // Program IO resources
612 //
613 ProgramResource (
614 IoBase,
615 IoBridge
616 );
617
618 //
619 // Program Mem32 resources
620 //
621 ProgramResource (
622 Mem32Base,
623 Mem32Bridge
624 );
625
626 //
627 // Program PMem32 resources
628 //
629 ProgramResource (
630 PMem32Base,
631 PMem32Bridge
632 );
633
634 //
635 // Program Mem64 resources
636 //
637 ProgramResource (
638 Mem64Base,
639 Mem64Bridge
640 );
641
642 //
643 // Program PMem64 resources
644 //
645 ProgramResource (
646 PMem64Base,
647 PMem64Bridge
648 );
649
650 FreePool (AcpiConfig);
651 }
652
653 //
654 // Destroy all the resource tree
655 //
656 DestroyResourceTree (&IoPool);
657 DestroyResourceTree (&Mem32Pool);
658 DestroyResourceTree (&PMem32Pool);
659 DestroyResourceTree (&Mem64Pool);
660 DestroyResourceTree (&PMem64Pool);
661
662 //
663 // Notify the resource allocation phase is to end
664 //
665 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);
666
667 return EFI_SUCCESS;
668 }
669
670 /**
671 Scan pci bus and assign bus number to the given PCI bus system.
672
673 @param Bridge Bridge device instance.
674 @param StartBusNumber start point.
675 @param SubBusNumber Point to sub bus number.
676 @param PaddedBusRange Customized bus number.
677
678 @retval EFI_SUCCESS Successfully scanned and assigned bus number.
679 @retval other Some error occurred when scanning pci bus.
680
681 @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
682
683 **/
684 EFI_STATUS
685 PciScanBus (
686 IN PCI_IO_DEVICE *Bridge,
687 IN UINT8 StartBusNumber,
688 OUT UINT8 *SubBusNumber,
689 OUT UINT8 *PaddedBusRange
690 )
691 {
692 EFI_STATUS Status;
693 PCI_TYPE00 Pci;
694 UINT8 Device;
695 UINT8 Func;
696 UINT64 Address;
697 UINTN SecondBus;
698 UINT16 Register;
699 UINTN HpIndex;
700 PCI_IO_DEVICE *PciDevice;
701 EFI_EVENT Event;
702 EFI_HPC_STATE State;
703 UINT64 PciAddress;
704 EFI_HPC_PADDING_ATTRIBUTES Attributes;
705 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
706 UINT16 BusRange;
707 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
708 BOOLEAN BusPadding;
709
710 PciRootBridgeIo = Bridge->PciRootBridgeIo;
711 SecondBus = 0;
712 Register = 0;
713 State = 0;
714 Attributes = (EFI_HPC_PADDING_ATTRIBUTES) 0;
715 BusRange = 0;
716 BusPadding = FALSE;
717 PciDevice = NULL;
718 PciAddress = 0;
719
720 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
721 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
722
723 //
724 // Check to see whether a pci device is present
725 //
726 Status = PciDevicePresent (
727 PciRootBridgeIo,
728 &Pci,
729 StartBusNumber,
730 Device,
731 Func
732 );
733
734 if (EFI_ERROR (Status)) {
735 if (Func == 0) {
736 //
737 // Skip sub functions, this is not a multi function device
738 //
739 Func = PCI_MAX_FUNC;
740 }
741
742 continue;
743 }
744
745 DEBUG((EFI_D_ERROR, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber, Device, Func ));
746
747 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
748 //
749 // Get the PCI device information
750 //
751 Status = PciSearchDevice (
752 Bridge,
753 &Pci,
754 StartBusNumber,
755 Device,
756 Func,
757 &PciDevice
758 );
759
760 ASSERT (!EFI_ERROR (Status));
761
762 PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);
763
764 if (!IS_PCI_BRIDGE (&Pci)) {
765 //
766 // PCI bridges will be called later
767 // Here just need for PCI device or PCI to cardbus controller
768 // EfiPciBeforeChildBusEnumeration for PCI Device Node
769 //
770 PreprocessController (
771 PciDevice,
772 PciDevice->BusNumber,
773 PciDevice->DeviceNumber,
774 PciDevice->FunctionNumber,
775 EfiPciBeforeChildBusEnumeration
776 );
777 }
778
779 //
780 // For Pci Hotplug controller devcie only
781 //
782 if (gPciHotPlugInit != NULL) {
783 //
784 // Check if it is a Hotplug PCI controller
785 //
786 if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {
787
788 if (!gPciRootHpcData[HpIndex].Initialized) {
789
790 Status = CreateEventForHpc (HpIndex, &Event);
791
792 ASSERT (!EFI_ERROR (Status));
793
794 Status = gPciHotPlugInit->InitializeRootHpc (
795 gPciHotPlugInit,
796 gPciRootHpcPool[HpIndex].HpcDevicePath,
797 PciAddress,
798 Event,
799 &State
800 );
801
802 PreprocessController (
803 PciDevice,
804 PciDevice->BusNumber,
805 PciDevice->DeviceNumber,
806 PciDevice->FunctionNumber,
807 EfiPciBeforeChildBusEnumeration
808 );
809 }
810 }
811 }
812 }
813
814 if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) {
815 //
816 // For PPB
817 //
818 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
819 //
820 // If Hot Plug is not supported,
821 // get the bridge information
822 //
823 Status = PciSearchDevice (
824 Bridge,
825 &Pci,
826 StartBusNumber,
827 Device,
828 Func,
829 &PciDevice
830 );
831
832 if (EFI_ERROR (Status)) {
833 return Status;
834 }
835 } else {
836 //
837 // If Hot Plug is supported,
838 // Get the bridge information
839 //
840 BusPadding = FALSE;
841 if (gPciHotPlugInit != NULL) {
842
843 if (IsRootPciHotPlugBus (PciDevice->DevicePath, &HpIndex)) {
844
845 //
846 // If it is initialized, get the padded bus range
847 //
848 Status = gPciHotPlugInit->GetResourcePadding (
849 gPciHotPlugInit,
850 gPciRootHpcPool[HpIndex].HpbDevicePath,
851 PciAddress,
852 &State,
853 (VOID **) &Descriptors,
854 &Attributes
855 );
856
857 if (EFI_ERROR (Status)) {
858 return Status;
859 }
860
861 BusRange = 0;
862 Status = PciGetBusRange (
863 &Descriptors,
864 NULL,
865 NULL,
866 &BusRange
867 );
868
869 FreePool (Descriptors);
870
871 if (EFI_ERROR (Status)) {
872 return Status;
873 }
874
875 BusPadding = TRUE;
876 }
877 }
878 }
879
880 //
881 // Add feature to support customized secondary bus number
882 //
883 if (*SubBusNumber == 0) {
884 *SubBusNumber = *PaddedBusRange;
885 *PaddedBusRange = 0;
886 }
887
888 (*SubBusNumber)++;
889 SecondBus = *SubBusNumber;
890
891 Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);
892 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);
893
894 Status = PciRootBridgeIoWrite (
895 PciRootBridgeIo,
896 &Pci,
897 EfiPciWidthUint16,
898 Address,
899 1,
900 &Register
901 );
902
903
904 //
905 // If it is PPB, resursively search down this bridge
906 //
907 if (IS_PCI_BRIDGE (&Pci)) {
908
909 //
910 // Temporarily initialize SubBusNumber to maximum bus number to ensure the
911 // PCI configuration transaction to go through any PPB
912 //
913 Register = 0xFF;
914 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
915 Status = PciRootBridgeIoWrite (
916 PciRootBridgeIo,
917 &Pci,
918 EfiPciWidthUint8,
919 Address,
920 1,
921 &Register
922 );
923
924 //
925 // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige
926 //
927 PreprocessController (
928 PciDevice,
929 PciDevice->BusNumber,
930 PciDevice->DeviceNumber,
931 PciDevice->FunctionNumber,
932 EfiPciBeforeChildBusEnumeration
933 );
934
935 DEBUG((EFI_D_ERROR, "Scan PPB(%02d,%02d,%02d)\n", PciDevice->BusNumber, PciDevice->DeviceNumber,PciDevice->FunctionNumber));
936 Status = PciScanBus (
937 PciDevice,
938 (UINT8) (SecondBus),
939 SubBusNumber,
940 PaddedBusRange
941 );
942 if (EFI_ERROR (Status)) {
943 return Status;
944 }
945 }
946
947 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport) && BusPadding) {
948 //
949 // Ensure the device is enabled and initialized
950 //
951 if ((Attributes == EfiPaddingPciRootBridge) &&
952 (State & EFI_HPC_STATE_ENABLED) != 0 &&
953 (State & EFI_HPC_STATE_INITIALIZED) != 0) {
954 *PaddedBusRange = (UINT8) ((UINT8) (BusRange) +*PaddedBusRange);
955 } else {
956 *SubBusNumber = (UINT8) ((UINT8) (BusRange) +*SubBusNumber);
957 }
958 }
959
960 //
961 // Set the current maximum bus number under the PPB
962 //
963 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
964
965 Status = PciRootBridgeIoWrite (
966 PciRootBridgeIo,
967 &Pci,
968 EfiPciWidthUint8,
969 Address,
970 1,
971 SubBusNumber
972 );
973 }
974
975 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
976
977 //
978 // Skip sub functions, this is not a multi function device
979 //
980
981 Func = PCI_MAX_FUNC;
982 }
983 }
984 }
985
986 return EFI_SUCCESS;
987 }
988
989 /**
990 Process Option Rom on the specified root bridge.
991
992 @param Bridge Pci root bridge device instance.
993
994 @retval EFI_SUCCESS Success process.
995 @retval other Some error occurred when processing Option Rom on the root bridge.
996
997 **/
998 EFI_STATUS
999 PciRootBridgeP2CProcess (
1000 IN PCI_IO_DEVICE *Bridge
1001 )
1002 {
1003 LIST_ENTRY *CurrentLink;
1004 PCI_IO_DEVICE *Temp;
1005 EFI_HPC_STATE State;
1006 UINT64 PciAddress;
1007 EFI_STATUS Status;
1008
1009 CurrentLink = Bridge->ChildList.ForwardLink;
1010
1011 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
1012
1013 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1014
1015 if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
1016
1017 if (gPciHotPlugInit != NULL && Temp->Allocated && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1018
1019 //
1020 // Raise the EFI_IOB_PCI_HPC_INIT status code
1021 //
1022 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1023 EFI_PROGRESS_CODE,
1024 EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_HPC_INIT,
1025 Temp->DevicePath
1026 );
1027
1028 PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
1029 Status = gPciHotPlugInit->InitializeRootHpc (
1030 gPciHotPlugInit,
1031 Temp->DevicePath,
1032 PciAddress,
1033 NULL,
1034 &State
1035 );
1036
1037 if (!EFI_ERROR (Status)) {
1038 Status = PciBridgeEnumerator (Temp);
1039
1040 if (EFI_ERROR (Status)) {
1041 return Status;
1042 }
1043 }
1044
1045 CurrentLink = CurrentLink->ForwardLink;
1046 continue;
1047
1048 }
1049 }
1050
1051 if (!IsListEmpty (&Temp->ChildList)) {
1052 Status = PciRootBridgeP2CProcess (Temp);
1053 }
1054
1055 CurrentLink = CurrentLink->ForwardLink;
1056 }
1057
1058 return EFI_SUCCESS;
1059 }
1060
1061 /**
1062 Process Option Rom on the specified host bridge.
1063
1064 @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
1065
1066 @retval EFI_SUCCESS Success process.
1067 @retval EFI_NOT_FOUND Can not find the root bridge instance.
1068 @retval other Some error occurred when processing Option Rom on the host bridge.
1069
1070 **/
1071 EFI_STATUS
1072 PciHostBridgeP2CProcess (
1073 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
1074 )
1075 {
1076 EFI_HANDLE RootBridgeHandle;
1077 PCI_IO_DEVICE *RootBridgeDev;
1078 EFI_STATUS Status;
1079
1080 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1081 return EFI_SUCCESS;
1082 }
1083
1084 RootBridgeHandle = NULL;
1085
1086 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1087
1088 //
1089 // Get RootBridg Device by handle
1090 //
1091 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
1092
1093 if (RootBridgeDev == NULL) {
1094 return EFI_NOT_FOUND;
1095 }
1096
1097 Status = PciRootBridgeP2CProcess (RootBridgeDev);
1098 if (EFI_ERROR (Status)) {
1099 return Status;
1100 }
1101
1102 }
1103
1104 return EFI_SUCCESS;
1105 }
1106
1107 /**
1108 This function is used to enumerate the entire host bridge
1109 in a given platform.
1110
1111 @param PciResAlloc A pointer to the PCI Host Resource Allocation protocol.
1112
1113 @retval EFI_SUCCESS Successfully enumerated the host bridge.
1114 @retval EFI_OUT_OF_RESOURCES No enough memory available.
1115 @retval other Some error occurred when enumerating the host bridge.
1116
1117 **/
1118 EFI_STATUS
1119 PciHostBridgeEnumerator (
1120 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
1121 )
1122 {
1123 EFI_HANDLE RootBridgeHandle;
1124 PCI_IO_DEVICE *RootBridgeDev;
1125 EFI_STATUS Status;
1126 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1127 UINT16 MinBus;
1128 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
1129 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
1130 UINT8 StartBusNumber;
1131 LIST_ENTRY RootBridgeList;
1132 LIST_ENTRY *Link;
1133
1134 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1135 InitializeHotPlugSupport ();
1136 }
1137
1138 InitializeListHead (&RootBridgeList);
1139
1140 //
1141 // Notify the bus allocation phase is about to start
1142 //
1143 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
1144
1145 DEBUG((EFI_D_ERROR, "PCI Bus First Scanning\n"));
1146 RootBridgeHandle = NULL;
1147 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1148
1149 //
1150 // if a root bridge instance is found, create root bridge device for it
1151 //
1152
1153 RootBridgeDev = CreateRootBridge (RootBridgeHandle);
1154
1155 if (RootBridgeDev == NULL) {
1156 return EFI_OUT_OF_RESOURCES;
1157 }
1158
1159 //
1160 // Enumerate all the buses under this root bridge
1161 //
1162 Status = PciRootBridgeEnumerator (
1163 PciResAlloc,
1164 RootBridgeDev
1165 );
1166
1167 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1168 InsertTailList (&RootBridgeList, &(RootBridgeDev->Link));
1169 } else {
1170 DestroyRootBridge (RootBridgeDev);
1171 }
1172 if (EFI_ERROR (Status)) {
1173 return Status;
1174 }
1175 }
1176
1177 //
1178 // Notify the bus allocation phase is finished for the first time
1179 //
1180 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
1181
1182 if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1183 //
1184 // Reset all assigned PCI bus number in all PPB
1185 //
1186 RootBridgeHandle = NULL;
1187 Link = GetFirstNode (&RootBridgeList);
1188 while ((PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) &&
1189 (!IsNull (&RootBridgeList, Link))) {
1190 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (Link);
1191 //
1192 // Get the Bus information
1193 //
1194 Status = PciResAlloc->StartBusEnumeration (
1195 PciResAlloc,
1196 RootBridgeHandle,
1197 (VOID **) &Configuration
1198 );
1199 if (EFI_ERROR (Status)) {
1200 return Status;
1201 }
1202
1203 //
1204 // Get the bus number to start with
1205 //
1206 StartBusNumber = (UINT8) (Configuration->AddrRangeMin);
1207
1208 ResetAllPpbBusNumber (
1209 RootBridgeDev,
1210 StartBusNumber
1211 );
1212
1213 FreePool (Configuration);
1214 Link = GetNextNode (&RootBridgeList, Link);
1215 DestroyRootBridge (RootBridgeDev);
1216 }
1217
1218 //
1219 // Wait for all HPC initialized
1220 //
1221 Status = AllRootHPCInitialized (STALL_1_SECOND * 15);
1222
1223 if (EFI_ERROR (Status)) {
1224 return Status;
1225 }
1226
1227 //
1228 // Notify the bus allocation phase is about to start for the 2nd time
1229 //
1230 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
1231
1232 DEBUG((EFI_D_ERROR, "PCI Bus Second Scanning\n"));
1233 RootBridgeHandle = NULL;
1234 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1235
1236 //
1237 // if a root bridge instance is found, create root bridge device for it
1238 //
1239 RootBridgeDev = CreateRootBridge (RootBridgeHandle);
1240
1241 if (RootBridgeDev == NULL) {
1242 return EFI_OUT_OF_RESOURCES;
1243 }
1244
1245 //
1246 // Enumerate all the buses under this root bridge
1247 //
1248 Status = PciRootBridgeEnumerator (
1249 PciResAlloc,
1250 RootBridgeDev
1251 );
1252
1253 DestroyRootBridge (RootBridgeDev);
1254 if (EFI_ERROR (Status)) {
1255 return Status;
1256 }
1257 }
1258
1259 //
1260 // Notify the bus allocation phase is to end for the 2nd time
1261 //
1262 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
1263 }
1264
1265 //
1266 // Notify the resource allocation phase is to start
1267 //
1268 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation);
1269
1270 RootBridgeHandle = NULL;
1271 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1272
1273 //
1274 // if a root bridge instance is found, create root bridge device for it
1275 //
1276 RootBridgeDev = CreateRootBridge (RootBridgeHandle);
1277
1278 if (RootBridgeDev == NULL) {
1279 return EFI_OUT_OF_RESOURCES;
1280 }
1281
1282 Status = StartManagingRootBridge (RootBridgeDev);
1283
1284 if (EFI_ERROR (Status)) {
1285 return Status;
1286 }
1287
1288 PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;
1289 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
1290
1291 if (EFI_ERROR (Status)) {
1292 return Status;
1293 }
1294
1295 Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);
1296
1297 if (EFI_ERROR (Status)) {
1298 return Status;
1299 }
1300
1301 //
1302 // Determine root bridge attribute by calling interface of Pcihostbridge
1303 // protocol
1304 //
1305 DetermineRootBridgeAttributes (
1306 PciResAlloc,
1307 RootBridgeDev
1308 );
1309
1310 //
1311 // Collect all the resource information under this root bridge
1312 // A database that records all the information about pci device subject to this
1313 // root bridge will then be created
1314 //
1315 Status = PciPciDeviceInfoCollector (
1316 RootBridgeDev,
1317 (UINT8) MinBus
1318 );
1319
1320 if (EFI_ERROR (Status)) {
1321 return Status;
1322 }
1323
1324 InsertRootBridge (RootBridgeDev);
1325
1326 //
1327 // Record the hostbridge handle
1328 //
1329 AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle);
1330 }
1331
1332 return EFI_SUCCESS;
1333 }
1334
1335 /**
1336 Read PCI device configuration register by specified address.
1337
1338 This function check the incompatiblilites on PCI device. Return the register
1339 value.
1340
1341 @param PciRootBridgeIo PCI root bridge io protocol instance.
1342 @param PciIo PCI IO protocol instance.
1343 @param PciDeviceInfo PCI device information.
1344 @param Width Signifies the width of the memory operations.
1345 @param Offset The offset within the PCI configuration space for the PCI controller.
1346 @param Buffer For read operations, the destination buffer to store the results. For
1347 write operations, the source buffer to write data from.
1348
1349 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
1350 @retval EFI_UNSUPPORTED Width is invalid for this PCI root bridge.
1351 @retval other Some error occurred when reading PCI device configuration space
1352 or checking incompatibility.
1353
1354 **/
1355 EFI_STATUS
1356 ReadConfigData (
1357 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
1358 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
1359 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
1360 IN UINT64 Width,
1361 IN UINT64 Offset,
1362 IN OUT VOID *Buffer
1363 )
1364 {
1365 EFI_STATUS Status;
1366 UINT64 AccessWidth;
1367 EFI_PCI_REGISTER_ACCESS_DATA *PciRegisterAccessData;
1368 UINT64 AccessAddress;
1369 UINTN Stride;
1370 UINT64 TempBuffer;
1371 UINT8 *Pointer;
1372
1373 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
1374 ASSERT (Buffer != NULL);
1375
1376 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) != 0) {
1377 //
1378 // Check access compatibility at first time
1379 //
1380 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, Offset & 0xff, Width, &PciRegisterAccessData);
1381
1382 if (Status == EFI_SUCCESS) {
1383 //
1384 // There exists incompatibility on this operation
1385 //
1386 AccessWidth = Width;
1387
1388 if (PciRegisterAccessData->Width != VALUE_NOCARE) {
1389 AccessWidth = PciRegisterAccessData->Width;
1390 }
1391
1392 AccessAddress = Offset & ~((1 << AccessWidth) - 1);
1393
1394 TempBuffer = 0;
1395 Stride = 0;
1396 Pointer = (UINT8 *) &TempBuffer;
1397
1398 while (TRUE) {
1399
1400 if (PciRootBridgeIo != NULL) {
1401 Status = PciRootBridgeIo->Pci.Read (
1402 PciRootBridgeIo,
1403 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,
1404 AccessAddress,
1405 1,
1406 Pointer
1407 );
1408 } else if (PciIo != NULL) {
1409 Status = PciIo->Pci.Read (
1410 PciIo,
1411 (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,
1412 (UINT32) AccessAddress,
1413 1,
1414 Pointer
1415 );
1416 }
1417
1418 if (Status != EFI_SUCCESS) {
1419 return Status;
1420 }
1421
1422 Stride = (UINTN)1 << AccessWidth;
1423 AccessAddress += Stride;
1424 if (AccessAddress >= (Offset + LShiftU64 (1ULL, (UINTN)Width))) {
1425 //
1426 // If all datas have been read, exit
1427 //
1428 break;
1429 }
1430
1431 Pointer += Stride;
1432
1433 if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {
1434 //
1435 // If current offset doesn't reach the end
1436 //
1437 continue;
1438 }
1439
1440 //
1441 // Continue checking access incompatibility
1442 //
1443 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);
1444 if (Status == EFI_SUCCESS) {
1445 if (PciRegisterAccessData->Width != VALUE_NOCARE) {
1446 AccessWidth = PciRegisterAccessData->Width;
1447 }
1448 }
1449 }
1450
1451 switch (Width) {
1452 case EfiPciWidthUint8:
1453 * (UINT8 *) Buffer = (UINT8) TempBuffer;
1454 break;
1455 case EfiPciWidthUint16:
1456 * (UINT16 *) Buffer = (UINT16) TempBuffer;
1457 break;
1458 case EfiPciWidthUint32:
1459 * (UINT32 *) Buffer = (UINT32) TempBuffer;
1460 break;
1461 default:
1462 return EFI_UNSUPPORTED;
1463 }
1464
1465 return Status;
1466 }
1467 }
1468 //
1469 // AccessWidth incompatible check not supportted
1470 // or, there doesn't exist incompatibility on this operation
1471 //
1472 if (PciRootBridgeIo != NULL) {
1473 Status = PciRootBridgeIo->Pci.Read (
1474 PciRootBridgeIo,
1475 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
1476 Offset,
1477 1,
1478 Buffer
1479 );
1480
1481 } else {
1482 Status = PciIo->Pci.Read (
1483 PciIo,
1484 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
1485 (UINT32) Offset,
1486 1,
1487 Buffer
1488 );
1489 }
1490
1491 return Status;
1492 }
1493
1494 /**
1495 Update register value by checking PCI device incompatibility.
1496
1497 This function check register value incompatibilites on PCI device. Return the register
1498 value.
1499
1500 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
1501 @param AccessType Access type, READ or WRITE.
1502 @param Width Signifies the width of the memory operations.
1503 @param Offset The offset within the PCI configuration space.
1504 @param Buffer Store the register data.
1505
1506 @retval EFI_SUCCESS The data has been updated.
1507 @retval EFI_UNSUPPORTED Width is invalid for this PCI root bridge.
1508 @retval other Some error occurred when checking incompatibility.
1509
1510 **/
1511 EFI_STATUS
1512 UpdateConfigData (
1513 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
1514 IN UINT64 AccessType,
1515 IN UINT64 Width,
1516 IN UINT64 Offset,
1517 IN OUT VOID *Buffer
1518 )
1519 {
1520 EFI_STATUS Status;
1521 EFI_PCI_REGISTER_VALUE_DATA *PciRegisterData;
1522 UINT32 AndValue;
1523 UINT32 OrValue;
1524 UINT32 TempValue;
1525
1526 ASSERT (Buffer != NULL);
1527
1528 //
1529 // Check register value incompatibility
1530 //
1531 Status = PciRegisterUpdateCheck (PciDeviceInfo, AccessType, Offset & 0xff, &PciRegisterData);
1532 if (Status == EFI_SUCCESS) {
1533
1534 AndValue = ((UINT32) PciRegisterData->AndValue) >> (((UINT8) Offset & 0x3) * 8);
1535 OrValue = ((UINT32) PciRegisterData->OrValue) >> (((UINT8) Offset & 0x3) * 8);
1536
1537 TempValue = * (UINT32 *) Buffer;
1538 if (PciRegisterData->AndValue != VALUE_NOCARE) {
1539 TempValue &= AndValue;
1540 }
1541 if (PciRegisterData->OrValue != VALUE_NOCARE) {
1542 TempValue |= OrValue;
1543 }
1544
1545 switch (Width) {
1546 case EfiPciWidthUint8:
1547 *(UINT8 *)Buffer = (UINT8) TempValue;
1548 break;
1549
1550 case EfiPciWidthUint16:
1551 *(UINT16 *)Buffer = (UINT16) TempValue;
1552 break;
1553 case EfiPciWidthUint32:
1554 *(UINT32 *)Buffer = TempValue;
1555 break;
1556
1557 default:
1558 return EFI_UNSUPPORTED;
1559 }
1560 }
1561
1562 return Status;
1563 }
1564
1565 /**
1566 Write PCI device configuration register by specified address.
1567
1568 This function check the incompatiblilites on PCI device, and write date
1569 into register.
1570
1571 @param PciRootBridgeIo PCI root bridge io instance.
1572 @param PciIo PCI IO protocol instance.
1573 @param PciDeviceInfo PCI device information.
1574 @param Width Signifies the width of the memory operations.
1575 @param Offset The offset within the PCI configuration space for the PCI controller.
1576 @param Buffer For read operations, the destination buffer to store the results. For
1577 write operations, the source buffer to write data from.
1578
1579 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
1580 @retval other Some error occurred when writing PCI device information
1581 or checking incompatibility.
1582
1583 **/
1584 EFI_STATUS
1585 WriteConfigData (
1586 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
1587 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
1588 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
1589 IN UINT64 Width,
1590 IN UINT64 Offset,
1591 IN VOID *Buffer
1592 )
1593 {
1594 EFI_STATUS Status;
1595 UINT64 AccessWidth;
1596 EFI_PCI_REGISTER_ACCESS_DATA *PciRegisterAccessData;
1597 UINT64 AccessAddress;
1598 UINTN Stride;
1599 UINT8 *Pointer;
1600 UINT64 Data;
1601 UINTN Shift;
1602
1603 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
1604 ASSERT (Buffer != NULL);
1605
1606 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) != 0) {
1607 //
1608 // Check access compatibility at first time
1609 //
1610 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, Offset & 0xff, Width, &PciRegisterAccessData);
1611
1612 if (Status == EFI_SUCCESS) {
1613 //
1614 // There exists incompatibility on this operation
1615 //
1616 AccessWidth = Width;
1617
1618 if (PciRegisterAccessData->Width != VALUE_NOCARE) {
1619 AccessWidth = PciRegisterAccessData->Width;
1620 }
1621
1622 AccessAddress = Offset & ~((1 << AccessWidth) - 1);
1623
1624 Stride = 0;
1625 Pointer = (UINT8 *) &Buffer;
1626 Data = * (UINT64 *) Buffer;
1627
1628 while (TRUE) {
1629
1630 if (AccessWidth > Width) {
1631 //
1632 // If actual access width is larger than orignal one, additional data need to be read back firstly
1633 //
1634 Status = ReadConfigData (PciRootBridgeIo, PciIo, PciDeviceInfo, AccessWidth, AccessAddress, &Data);
1635 if (Status != EFI_SUCCESS) {
1636 return Status;
1637 }
1638
1639 //
1640 // Check data read incompatibility
1641 //
1642 UpdateConfigData (PciDeviceInfo, PCI_REGISTER_READ, AccessWidth, AccessAddress & 0xff, &Data);
1643
1644 Shift = (UINTN)(Offset - AccessAddress) * 8;
1645 switch (Width) {
1646 case EfiPciWidthUint8:
1647 Data = (* (UINT8 *) Buffer) << Shift | (Data & ~(0xff << Shift));
1648 break;
1649
1650 case EfiPciWidthUint16:
1651 Data = (* (UINT16 *) Buffer) << Shift | (Data & ~(0xffff << Shift));
1652 break;
1653 }
1654
1655 //
1656 // Check data write incompatibility
1657 //
1658 UpdateConfigData (PciDeviceInfo, PCI_REGISTER_WRITE, AccessWidth, MultU64x32 (AccessAddress, 0xff), &Data);
1659 }
1660
1661 if (PciRootBridgeIo != NULL) {
1662 Status = PciRootBridgeIo->Pci.Write (
1663 PciRootBridgeIo,
1664 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,
1665 AccessAddress,
1666 1,
1667 &Data
1668 );
1669 } else {
1670 Status = PciIo->Pci.Write (
1671 PciIo,
1672 (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,
1673 (UINT32) AccessAddress,
1674 1,
1675 &Data
1676 );
1677 }
1678
1679 if (Status != EFI_SUCCESS) {
1680 return Status;
1681 }
1682
1683 Data = RShiftU64 (Data, ((1 << AccessWidth) * 8));
1684
1685 Stride = (UINTN)1 << AccessWidth;
1686 AccessAddress += Stride;
1687 if (AccessAddress >= (Offset + LShiftU64 (1ULL, (UINTN)Width))) {
1688 //
1689 // If all datas have been written, exit
1690 //
1691 break;
1692 }
1693
1694 Pointer += Stride;
1695
1696 if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {
1697 //
1698 // If current offset doesn't reach the end
1699 //
1700 continue;
1701 }
1702
1703 //
1704 // Continue checking access incompatibility
1705 //
1706 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);
1707 if (Status == EFI_SUCCESS) {
1708 if (PciRegisterAccessData->Width != VALUE_NOCARE) {
1709 AccessWidth = PciRegisterAccessData->Width;
1710 }
1711 }
1712 };
1713
1714 return Status;
1715 }
1716
1717 }
1718 //
1719 // AccessWidth incompatible check not supportted
1720 // or, there doesn't exist incompatibility on this operation
1721 //
1722 if (PciRootBridgeIo != NULL) {
1723 Status = PciRootBridgeIo->Pci.Write (
1724 PciRootBridgeIo,
1725 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
1726 Offset,
1727 1,
1728 Buffer
1729 );
1730 } else {
1731 Status = PciIo->Pci.Write (
1732 PciIo,
1733 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
1734 (UINT32) Offset,
1735 1,
1736 Buffer
1737 );
1738 }
1739
1740 return Status;
1741 }
1742
1743 /**
1744 Abstract PCI device device information.
1745
1746 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1747 @param PciIo A pointer to EFI_PCI_PROTOCOL.
1748 @param Pci PCI device configuration space.
1749 @param Offset The offset within the PCI configuration space for the PCI controller.
1750 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
1751
1752 @retval EFI_SUCCESS Pci device device information has been abstracted.
1753 @retval EFI_NOT_FOUND Cannot found the specified PCI device.
1754 @retval other Some error occurred when reading PCI device information.
1755
1756 **/
1757 EFI_STATUS
1758 GetPciDeviceDeviceInfo (
1759 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
1760 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
1761 IN PCI_TYPE00 *Pci, OPTIONAL
1762 IN UINT64 Offset, OPTIONAL
1763 OUT EFI_PCI_DEVICE_INFO *PciDeviceInfo
1764 )
1765 {
1766 EFI_STATUS Status;
1767 UINT64 PciAddress;
1768 UINT32 PciConfigData;
1769 PCI_IO_DEVICE *PciIoDevice;
1770
1771 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
1772 ASSERT (PciDeviceInfo != NULL);
1773
1774 if (PciIo != NULL) {
1775 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
1776
1777 //
1778 // Get pointer to PCI_TYPE00 from PciIoDevice
1779 //
1780 Pci = &PciIoDevice->Pci;
1781 }
1782
1783 if (Pci == NULL) {
1784 //
1785 // While PCI_TYPE00 hasn't been gotten, read PCI device device information directly
1786 //
1787 PciAddress = Offset & 0xffffffffffffff00ULL;
1788 Status = PciRootBridgeIo->Pci.Read (
1789 PciRootBridgeIo,
1790 EfiPciWidthUint32,
1791 PciAddress,
1792 1,
1793 &PciConfigData
1794 );
1795
1796 if (EFI_ERROR (Status)) {
1797 return Status;
1798 }
1799
1800 if ((PciConfigData & 0xffff) == 0xffff) {
1801 return EFI_NOT_FOUND;
1802 }
1803
1804 PciDeviceInfo->VendorID = PciConfigData & 0xffff;
1805 PciDeviceInfo->DeviceID = PciConfigData >> 16;
1806
1807 Status = PciRootBridgeIo->Pci.Read (
1808 PciRootBridgeIo,
1809 EfiPciWidthUint32,
1810 PciAddress + 8,
1811 1,
1812 &PciConfigData
1813 );
1814 if (EFI_ERROR (Status)) {
1815 return Status;
1816 }
1817
1818 PciDeviceInfo->RevisionID = PciConfigData & 0xf;
1819
1820 Status = PciRootBridgeIo->Pci.Read (
1821 PciRootBridgeIo,
1822 EfiPciWidthUint32,
1823 PciAddress + 0x2c,
1824 1,
1825 &PciConfigData
1826 );
1827
1828 if (EFI_ERROR (Status)) {
1829 return Status;
1830 }
1831
1832 PciDeviceInfo->SubsystemVendorID = PciConfigData & 0xffff;
1833 PciDeviceInfo->SubsystemID = PciConfigData >> 16;
1834
1835 } else {
1836 PciDeviceInfo->VendorID = Pci->Hdr.VendorId;
1837 PciDeviceInfo->DeviceID = Pci->Hdr.DeviceId;
1838 PciDeviceInfo->RevisionID = Pci->Hdr.RevisionID;
1839 PciDeviceInfo->SubsystemVendorID = Pci->Device.SubsystemVendorID;
1840 PciDeviceInfo->SubsystemID = Pci->Device.SubsystemID;
1841 }
1842
1843 return EFI_SUCCESS;
1844 }
1845
1846 /**
1847 Read PCI configuration space with incompatibility check.
1848
1849 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1850 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.
1851 @param Pci A pointer to PCI_TYPE00.
1852 @param Width Signifies the width of the memory operations.
1853 @param Offset The offset within the PCI configuration space for the PCI controller.
1854 @param Count The number of unit to be read.
1855 @param Buffer For read operations, the destination buffer to store the results. For
1856 write operations, the source buffer to write data from.
1857
1858 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
1859 @retval EFI_UNSUPPORTED Buffer is NULL.
1860 @retval other Some error occurred when reading PCI configuration space.
1861
1862 **/
1863 EFI_STATUS
1864 PciIncompatibilityCheckRead (
1865 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
1866 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
1867 IN PCI_TYPE00 *Pci, OPTIONAL
1868 IN UINTN Width,
1869 IN UINT64 Offset,
1870 IN UINTN Count,
1871 IN OUT VOID *Buffer
1872 )
1873 {
1874 EFI_STATUS Status;
1875 EFI_PCI_DEVICE_INFO PciDeviceInfo;
1876 UINT32 Stride;
1877
1878 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
1879 if (Buffer == NULL) {
1880 return EFI_UNSUPPORTED;
1881 }
1882
1883 //
1884 // get PCI device device information
1885 //
1886 Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Offset, &PciDeviceInfo);
1887 if (Status != EFI_SUCCESS) {
1888 return Status;
1889 }
1890
1891 Stride = 1 << Width;
1892
1893 for (; Count > 0; Count--, Offset += Stride, Buffer = (UINT8 *)Buffer + Stride) {
1894
1895 //
1896 // read configuration register
1897 //
1898 Status = ReadConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, (UINT64) Width, Offset, Buffer);
1899
1900 if (Status != EFI_SUCCESS) {
1901 return Status;
1902 }
1903
1904 //
1905 // update the data read from configuration register
1906 //
1907 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) != 0) {
1908 UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_READ, Width, Offset & 0xff, Buffer);
1909 }
1910 }
1911
1912 return EFI_SUCCESS;
1913 }
1914
1915 /**
1916 Write PCI configuration space with incompatibility check.
1917
1918 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1919 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.
1920 @param Pci A pointer to PCI_TYPE00.
1921 @param Width Signifies the width of the memory operations.
1922 @param Offset The offset within the PCI configuration space for the PCI controller.
1923 @param Count The number of unit to be write.
1924 @param Buffer For read operations, the destination buffer to store the results. For
1925 write operations, the source buffer to write data from.
1926
1927 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
1928 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
1929 valid for the PCI configuration header of the PCI controller.
1930 Buffer is NULL.
1931 @retval other Some error occurred when writing PCI configuration space.
1932
1933 **/
1934 EFI_STATUS
1935 PciIncompatibilityCheckWrite (
1936 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
1937 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
1938 IN PCI_TYPE00 *Pci, OPTIONAL
1939 IN UINTN Width,
1940 IN UINT64 Offset,
1941 IN UINTN Count,
1942 IN OUT VOID *Buffer
1943 )
1944 {
1945 EFI_STATUS Status;
1946 EFI_PCI_DEVICE_INFO PciDeviceInfo;
1947 UINT32 Stride;
1948 UINT64 Data;
1949
1950 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
1951 if (Buffer == NULL) {
1952 return EFI_UNSUPPORTED;
1953 }
1954
1955 //
1956 // Get PCI device device information
1957 //
1958 Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Offset, &PciDeviceInfo);
1959 if (Status != EFI_SUCCESS) {
1960 return Status;
1961 }
1962
1963 Stride = 1 << Width;
1964
1965 for (; Count > 0; Count--, Offset += Stride, Buffer = (UINT8 *) Buffer + Stride) {
1966
1967 Data = 0;
1968
1969 switch (Width) {
1970 case EfiPciWidthUint8:
1971 Data = * (UINT8 *) Buffer;
1972 break;
1973 case EfiPciWidthUint16:
1974 Data = * (UINT16 *) Buffer;
1975 break;
1976
1977 case EfiPciWidthUint32:
1978 Data = * (UINT32 *) Buffer;
1979 break;
1980
1981 default:
1982 return EFI_UNSUPPORTED;
1983 }
1984
1985 //
1986 // Update the data writen into configuration register
1987 //
1988 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) != 0) {
1989 UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_WRITE, Width, Offset & 0xff, &Data);
1990 }
1991
1992 //
1993 // Write configuration register
1994 //
1995 Status = WriteConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, Width, Offset, &Data);
1996
1997 if (Status != EFI_SUCCESS) {
1998 return Status;
1999 }
2000 }
2001
2002 return EFI_SUCCESS;
2003 }
2004
2005 /**
2006 Read PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2007
2008 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2009 @param Pci A pointer to PCI_TYPE00.
2010 @param Width Signifies the width of the memory operations.
2011 @param Offset The offset within the PCI configuration space for the PCI controller.
2012 @param Count The number of unit to be read.
2013 @param Buffer For read operations, the destination buffer to store the results. For
2014 write operations, the source buffer to write data from.
2015
2016 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2017 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2018 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
2019
2020 **/
2021 EFI_STATUS
2022 PciRootBridgeIoRead (
2023 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
2024 IN PCI_TYPE00 *Pci, OPTIONAL
2025 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
2026 IN UINT64 Offset,
2027 IN UINTN Count,
2028 IN OUT VOID *Buffer
2029 )
2030 {
2031 EFI_STATUS Status;
2032
2033 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) != 0) {
2034 //
2035 // If PCI incompatibility check enabled
2036 //
2037 Status = PciIncompatibilityCheckRead (
2038 PciRootBridgeIo,
2039 NULL,
2040 Pci,
2041 (UINTN) Width,
2042 Offset,
2043 Count,
2044 Buffer
2045 );
2046 if (Status == EFI_UNSUPPORTED) {
2047 return EFI_INVALID_PARAMETER;
2048 } else {
2049 return Status;
2050 }
2051 } else {
2052 return PciRootBridgeIo->Pci.Read (
2053 PciRootBridgeIo,
2054 Width,
2055 Offset,
2056 Count,
2057 Buffer
2058 );
2059 }
2060 }
2061
2062 /**
2063 Write PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2064
2065 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2066 @param Pci A pointer to PCI_TYPE00.
2067 @param Width Signifies the width of the memory operations.
2068 @param Offset The offset within the PCI configuration space for the PCI controller.
2069 @param Count The number of unit to be read.
2070 @param Buffer For read operations, the destination buffer to store the results. For
2071 write operations, the source buffer to write data from.
2072
2073 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2074 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2075 @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
2076
2077 **/
2078 EFI_STATUS
2079 PciRootBridgeIoWrite (
2080 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
2081 IN PCI_TYPE00 *Pci,
2082 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
2083 IN UINT64 Offset,
2084 IN UINTN Count,
2085 IN OUT VOID *Buffer
2086 )
2087 {
2088 EFI_STATUS Status;
2089
2090 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) != 0) {
2091 //
2092 // If PCI incompatibility check enabled
2093 //
2094 Status = PciIncompatibilityCheckWrite (
2095 PciRootBridgeIo,
2096 NULL,
2097 Pci,
2098 Width,
2099 Offset,
2100 Count,
2101 Buffer
2102 );
2103 if (Status == EFI_UNSUPPORTED) {
2104 return EFI_INVALID_PARAMETER;
2105 } else {
2106 return Status;
2107 }
2108
2109 } else {
2110 return PciRootBridgeIo->Pci.Write (
2111 PciRootBridgeIo,
2112 Width,
2113 Offset,
2114 Count,
2115 Buffer
2116 );
2117 }
2118 }
2119
2120 /**
2121 Read PCI configuration space through EFI_PCI_IO_PROTOCOL.
2122
2123 @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.
2124 @param Width Signifies the width of the memory operations.
2125 @param Offset The offset within the PCI configuration space for the PCI controller.
2126 @param Count The number of unit to be read.
2127 @param Buffer For read operations, the destination buffer to store the results. For
2128 write operations, the source buffer to write data from.
2129
2130 @retval EFI_SUCCESS The data was read from or written to the PCI controller.
2131 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
2132 valid for the PCI configuration header of the PCI controller.
2133 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2134 @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
2135
2136 **/
2137 EFI_STATUS
2138 PciIoRead (
2139 IN EFI_PCI_IO_PROTOCOL *PciIo,
2140 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
2141 IN UINT32 Offset,
2142 IN UINTN Count,
2143 IN OUT VOID *Buffer
2144 )
2145 {
2146 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) != 0) {
2147 //
2148 // If PCI incompatibility check enabled
2149 //
2150 return PciIncompatibilityCheckRead (
2151 NULL,
2152 PciIo,
2153 NULL,
2154 (UINTN) Width,
2155 Offset,
2156 Count,
2157 Buffer
2158 );
2159 } else {
2160 return PciIo->Pci.Read (
2161 PciIo,
2162 Width,
2163 Offset,
2164 Count,
2165 Buffer
2166 );
2167 }
2168 }
2169
2170 /**
2171 Write PCI configuration space through EFI_PCI_IO_PROTOCOL.
2172
2173 If PCI incompatibility check is enabled, do incompatibility check.
2174
2175 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL instance.
2176 @param Width Signifies the width of the memory operations.
2177 @param Offset The offset within the PCI configuration space for the PCI controller.
2178 @param Count The number of PCI configuration operations to perform.
2179 @param Buffer For read operations, the destination buffer to store the results. For write
2180 operations, the source buffer to write data from.
2181
2182 @retval EFI_SUCCESS The data was read from or written to the PCI controller.
2183 @retval EFI_UNSUPPORTED The address range specified by Offset, Width, and Count is not
2184 valid for the PCI configuration header of the PCI controller.
2185 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2186 @retval EFI_INVALID_PARAMETER Buffer is NULL or Width is invalid.
2187
2188 **/
2189 EFI_STATUS
2190 PciIoWrite (
2191 IN EFI_PCI_IO_PROTOCOL *PciIo,
2192 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
2193 IN UINT32 Offset,
2194 IN UINTN Count,
2195 IN OUT VOID *Buffer
2196 )
2197 {
2198 if ((PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) != 0) {
2199 //
2200 // If PCI incompatibility check enabled
2201 //
2202 return PciIncompatibilityCheckWrite (
2203 NULL,
2204 PciIo,
2205 NULL,
2206 Width,
2207 Offset,
2208 Count,
2209 Buffer
2210 );
2211
2212 } else {
2213 return PciIo->Pci.Write (
2214 PciIo,
2215 Width,
2216 Offset,
2217 Count,
2218 Buffer
2219 );
2220 }
2221 }
2222