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