]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciLib.c
PCI Bus Driver Enhancement
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciLib.c
1 /**@file
2
3 PCI Bus Driver Lib file
4 It abstracts some functions that can be different
5 between light PCI bus driver and full PCI bus driver
6
7 Copyright (c) 2006, Intel Corporation
8 All rights reserved. This program and the accompanying materials
9 are licensed and made available under the terms and conditions of the BSD License
10 which accompanies this distribution. The full text of the license may be found at
11 http://opensource.org/licenses/bsd-license.php
12
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15
16 **/
17
18 #include "pcibus.h"
19
20 GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_HOTPLUG_REQUEST_PROTOCOL gPciHotPlugRequest = {
21 PciHotPlugRequestNotify
22 };
23
24
25 VOID
26 InstallHotPlugRequestProtocol (
27 IN EFI_STATUS *Status
28 )
29 /*++
30
31 Routine Description:
32
33 Arguments:
34 Status - A pointer to the status.
35
36 Returns:
37
38 None
39
40 --*/
41 {
42 EFI_HANDLE Handle;
43
44 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
45 return;
46 }
47
48 Handle = NULL;
49 *Status = gBS->InstallProtocolInterface (
50 &Handle,
51 &gEfiPciHotPlugRequestProtocolGuid,
52 EFI_NATIVE_INTERFACE,
53 &gPciHotPlugRequest
54 );
55 }
56
57 VOID
58 InstallPciHotplugGuid (
59 IN PCI_IO_DEVICE *PciIoDevice
60 )
61 /*++
62
63 Routine Description:
64
65 Arguments:
66
67 PciIoDevice - A pointer to the PCI_IO_DEVICE.
68
69 Returns:
70
71 None
72
73 --*/
74 {
75 EFI_STATUS Status;
76
77 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
78 return;
79 }
80
81 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Parent->Pci)) {
82
83 Status = gBS->InstallProtocolInterface (
84 &PciIoDevice->Handle,
85 &gEfiPciHotplugDeviceGuid,
86 EFI_NATIVE_INTERFACE,
87 NULL
88 );
89 ASSERT_EFI_ERROR (Status);
90 }
91 }
92
93 VOID
94 UninstallPciHotplugGuid (
95 IN PCI_IO_DEVICE *PciIoDevice
96 )
97 /*++
98
99 Routine Description:
100
101 Arguments:
102
103 PciIoDevice - A pointer to the PCI_IO_DEVICE.
104
105 Returns:
106
107 None
108
109 --*/
110 {
111 EFI_STATUS Status;
112
113 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
114 return;
115 }
116
117 Status = gBS->OpenProtocol (
118 PciIoDevice->Handle,
119 &gEfiPciHotplugDeviceGuid,
120 NULL,
121 NULL,
122 NULL,
123 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
124 );
125
126 if (Status == EFI_SUCCESS) {
127 //
128 // This may triger CardBus driver to stop for
129 // Pccard devices opened the GUID via BY_DRIVER
130 //
131 Status = gBS->UninstallProtocolInterface (
132 PciIoDevice->Handle,
133 &gEfiPciHotplugDeviceGuid,
134 NULL
135 );
136 }
137 }
138
139 VOID
140 GetBackPcCardBar (
141 IN PCI_IO_DEVICE *PciIoDevice
142 )
143 /*++
144
145 Routine Description:
146
147
148 Arguments:
149
150 PciIoDevice - A pointer to the PCI_IO_DEVICE.
151
152 Returns:
153
154 None
155
156 --*/
157 {
158 UINT32 Address;
159
160 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
161 return;
162 }
163
164 //
165 // Read PciBar information from the bar register
166 //
167 if (!gFullEnumeration) {
168
169 Address = 0;
170 PciIoRead (
171 &(PciIoDevice->PciIo),
172 EfiPciIoWidthUint32,
173 0x1c,
174 1,
175 &Address
176 );
177
178 (PciIoDevice->PciBar)[P2C_MEM_1].BaseAddress = (UINT64) (Address);
179 (PciIoDevice->PciBar)[P2C_MEM_1].Length = 0x2000000;
180 (PciIoDevice->PciBar)[P2C_MEM_1].BarType = PciBarTypeMem32;
181
182 Address = 0;
183 PciIoRead (
184 &(PciIoDevice->PciIo),
185 EfiPciIoWidthUint32,
186 0x20,
187 1,
188 &Address
189 );
190 (PciIoDevice->PciBar)[P2C_MEM_2].BaseAddress = (UINT64) (Address);
191 (PciIoDevice->PciBar)[P2C_MEM_2].Length = 0x2000000;
192 (PciIoDevice->PciBar)[P2C_MEM_2].BarType = PciBarTypePMem32;
193
194 Address = 0;
195 PciIoRead (
196 &(PciIoDevice->PciIo),
197 EfiPciIoWidthUint32,
198 0x2c,
199 1,
200 &Address
201 );
202 (PciIoDevice->PciBar)[P2C_IO_1].BaseAddress = (UINT64) (Address);
203 (PciIoDevice->PciBar)[P2C_IO_1].Length = 0x100;
204 (PciIoDevice->PciBar)[P2C_IO_1].BarType = PciBarTypeIo16;
205
206 Address = 0;
207 PciIoRead (
208 &(PciIoDevice->PciIo),
209 EfiPciIoWidthUint32,
210 0x34,
211 1,
212 &Address
213 );
214 (PciIoDevice->PciBar)[P2C_IO_2].BaseAddress = (UINT64) (Address);
215 (PciIoDevice->PciBar)[P2C_IO_2].Length = 0x100;
216 (PciIoDevice->PciBar)[P2C_IO_2].BarType = PciBarTypeIo16;
217
218 }
219
220 if (gPciHotPlugInit != NULL) {
221 GetResourcePaddingForHpb (PciIoDevice);
222 }
223 }
224
225 EFI_STATUS
226 RemoveRejectedPciDevices (
227 EFI_HANDLE RootBridgeHandle,
228 IN PCI_IO_DEVICE *Bridge
229 )
230 /*++
231
232 Routine Description:
233
234
235 Arguments:
236
237 RootBridgeHandle - An efi handle.
238 Bridge - An pointer to the PCI_IO_DEVICE.
239
240 Returns:
241
242 None
243
244 --*/
245 // TODO: EFI_SUCCESS - add return value to function comment
246 {
247 PCI_IO_DEVICE *Temp;
248 LIST_ENTRY *CurrentLink;
249 LIST_ENTRY *LastLink;
250
251 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
252 return EFI_SUCCESS;
253 }
254
255 CurrentLink = Bridge->ChildList.ForwardLink;
256
257 while (CurrentLink && CurrentLink != &Bridge->ChildList) {
258
259 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
260
261 if (IS_PCI_BRIDGE (&Temp->Pci)) {
262 //
263 // Remove rejected devices recusively
264 //
265 RemoveRejectedPciDevices (RootBridgeHandle, Temp);
266 } else {
267 //
268 // Skip rejection for all PPBs, while detect rejection for others
269 //
270 if (IsPciDeviceRejected (Temp)) {
271
272 //
273 // For P2C, remove all devices on it
274 //
275
276 if (!IsListEmpty (&Temp->ChildList)) {
277 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
278 }
279
280 //
281 // Finally remove itself
282 //
283
284 LastLink = CurrentLink->BackLink;
285 RemoveEntryList (CurrentLink);
286 FreePciDevice (Temp);
287
288 CurrentLink = LastLink;
289 }
290 }
291
292 CurrentLink = CurrentLink->ForwardLink;
293 }
294
295 return EFI_SUCCESS;
296 }
297
298 EFI_STATUS
299 PciHostBridgeResourceAllocator (
300 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
301 )
302 {
303 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
304 return PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport (
305 PciResAlloc
306 );
307 } else {
308 return PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (
309 PciResAlloc
310 );
311 }
312 }
313
314
315 EFI_STATUS
316 PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (
317 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
318 )
319 /*++
320
321 Routine Description:
322
323 Arguments:
324
325 Returns:
326
327 None
328
329 --*/
330 // TODO: PciResAlloc - add argument and description to function comment
331 // TODO: EFI_NOT_FOUND - add return value to function comment
332 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
333 // TODO: EFI_NOT_FOUND - add return value to function comment
334 // TODO: EFI_SUCCESS - add return value to function comment
335 {
336 PCI_IO_DEVICE *RootBridgeDev;
337 EFI_HANDLE RootBridgeHandle;
338 VOID *AcpiConfig;
339 EFI_STATUS Status;
340 UINT64 IoBase;
341 UINT64 Mem32Base;
342 UINT64 PMem32Base;
343 UINT64 Mem64Base;
344 UINT64 PMem64Base;
345 UINT64 MaxOptionRomSize;
346 PCI_RESOURCE_NODE *IoBridge;
347 PCI_RESOURCE_NODE *Mem32Bridge;
348 PCI_RESOURCE_NODE *PMem32Bridge;
349 PCI_RESOURCE_NODE *Mem64Bridge;
350 PCI_RESOURCE_NODE *PMem64Bridge;
351 PCI_RESOURCE_NODE IoPool;
352 PCI_RESOURCE_NODE Mem32Pool;
353 PCI_RESOURCE_NODE PMem32Pool;
354 PCI_RESOURCE_NODE Mem64Pool;
355 PCI_RESOURCE_NODE PMem64Pool;
356 EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD ExtendedData;
357
358 //
359 // Initialize resource pool
360 //
361
362 InitializeResourcePool (&IoPool, PciBarTypeIo16);
363 InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);
364 InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);
365 InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);
366 InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);
367
368 RootBridgeDev = NULL;
369 RootBridgeHandle = 0;
370
371 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
372 //
373 // Get RootBridg Device by handle
374 //
375 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
376
377 if (RootBridgeDev == NULL) {
378 return EFI_NOT_FOUND;
379 }
380
381 //
382 // Get host bridge handle for status report
383 //
384 ExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
385
386 //
387 // Create the entire system resource map from the information collected by
388 // enumerator. Several resource tree was created
389 //
390
391 IoBridge = CreateResourceNode (
392 RootBridgeDev,
393 0,
394 0xFFF,
395 0,
396 PciBarTypeIo16,
397 PciResUsageTypical
398 );
399
400 Mem32Bridge = CreateResourceNode (
401 RootBridgeDev,
402 0,
403 0xFFFFF,
404 0,
405 PciBarTypeMem32,
406 PciResUsageTypical
407 );
408
409 PMem32Bridge = CreateResourceNode (
410 RootBridgeDev,
411 0,
412 0xFFFFF,
413 0,
414 PciBarTypePMem32,
415 PciResUsageTypical
416 );
417
418 Mem64Bridge = CreateResourceNode (
419 RootBridgeDev,
420 0,
421 0xFFFFF,
422 0,
423 PciBarTypeMem64,
424 PciResUsageTypical
425 );
426
427 PMem64Bridge = CreateResourceNode (
428 RootBridgeDev,
429 0,
430 0xFFFFF,
431 0,
432 PciBarTypePMem64,
433 PciResUsageTypical
434 );
435
436 //
437 // Create resourcemap by going through all the devices subject to this root bridge
438 //
439 Status = CreateResourceMap (
440 RootBridgeDev,
441 IoBridge,
442 Mem32Bridge,
443 PMem32Bridge,
444 Mem64Bridge,
445 PMem64Bridge
446 );
447
448 //
449 // Get the max ROM size that the root bridge can process
450 //
451 RootBridgeDev->RomSize = Mem32Bridge->Length;
452
453 //
454 // Get Max Option Rom size for current root bridge
455 //
456 MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);
457
458 //
459 // Enlarger the mem32 resource to accomdate the option rom
460 // if the mem32 resource is not enough to hold the rom
461 //
462 if (MaxOptionRomSize > Mem32Bridge->Length) {
463
464 Mem32Bridge->Length = MaxOptionRomSize;
465 RootBridgeDev->RomSize = MaxOptionRomSize;
466
467 //
468 // Alignment should be adjusted as well
469 //
470 if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) {
471 Mem32Bridge->Alignment = MaxOptionRomSize - 1;
472 }
473 }
474
475 //
476 // Based on the all the resource tree, contruct ACPI resource node to
477 // submit the resource aperture to pci host bridge protocol
478 //
479 Status = ConstructAcpiResourceRequestor (
480 RootBridgeDev,
481 IoBridge,
482 Mem32Bridge,
483 PMem32Bridge,
484 Mem64Bridge,
485 PMem64Bridge,
486 &AcpiConfig
487 );
488
489 //
490 // Insert these resource nodes into the database
491 //
492 InsertResourceNode (&IoPool, IoBridge);
493 InsertResourceNode (&Mem32Pool, Mem32Bridge);
494 InsertResourceNode (&PMem32Pool, PMem32Bridge);
495 InsertResourceNode (&Mem64Pool, Mem64Bridge);
496 InsertResourceNode (&PMem64Pool, PMem64Bridge);
497
498 if (Status == EFI_SUCCESS) {
499 //
500 // Submit the resource requirement
501 //
502 Status = PciResAlloc->SubmitResources (
503 PciResAlloc,
504 RootBridgeDev->Handle,
505 AcpiConfig
506 );
507 }
508 //
509 // Free acpi resource node
510 //
511 if (AcpiConfig != NULL) {
512 FreePool (AcpiConfig);
513 }
514
515 if (EFI_ERROR (Status)) {
516 //
517 // Destroy all the resource tree
518 //
519 DestroyResourceTree (&IoPool);
520 DestroyResourceTree (&Mem32Pool);
521 DestroyResourceTree (&PMem32Pool);
522 DestroyResourceTree (&Mem64Pool);
523 DestroyResourceTree (&PMem64Pool);
524 return Status;
525 }
526 }
527 //
528 // End while
529 //
530
531 //
532 // Notify pci bus driver starts to program the resource
533 //
534 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);
535
536 if (EFI_ERROR (Status)) {
537 //
538 // Allocation failed, then return
539 //
540 return EFI_OUT_OF_RESOURCES;
541 }
542 //
543 // Raise the EFI_IOB_PCI_RES_ALLOC status code
544 //
545 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
546 EFI_PROGRESS_CODE,
547 EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_RES_ALLOC,
548 (VOID *) &ExtendedData,
549 sizeof (ExtendedData)
550 );
551
552 //
553 // Notify pci bus driver starts to program the resource
554 //
555 NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);
556
557 RootBridgeDev = NULL;
558
559 RootBridgeHandle = 0;
560
561 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
562 //
563 // Get RootBridg Device by handle
564 //
565 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
566
567 if (RootBridgeDev == NULL) {
568 return EFI_NOT_FOUND;
569 }
570
571 //
572 // Get acpi resource node for all the resource types
573 //
574 AcpiConfig = NULL;
575 Status = PciResAlloc->GetProposedResources (
576 PciResAlloc,
577 RootBridgeDev->Handle,
578 &AcpiConfig
579 );
580
581 if (EFI_ERROR (Status)) {
582 return Status;
583 }
584
585 //
586 // Get the resource base by interpreting acpi resource node
587 //
588 //
589 GetResourceBase (
590 AcpiConfig,
591 &IoBase,
592 &Mem32Base,
593 &PMem32Base,
594 &Mem64Base,
595 &PMem64Base
596 );
597
598 //
599 // Process option rom for this root bridge
600 //
601 Status = ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize);
602
603 //
604 // Create the entire system resource map from the information collected by
605 // enumerator. Several resource tree was created
606 //
607 Status = GetResourceMap (
608 RootBridgeDev,
609 &IoBridge,
610 &Mem32Bridge,
611 &PMem32Bridge,
612 &Mem64Bridge,
613 &PMem64Bridge,
614 &IoPool,
615 &Mem32Pool,
616 &PMem32Pool,
617 &Mem64Pool,
618 &PMem64Pool
619 );
620
621 if (EFI_ERROR (Status)) {
622 return Status;
623 }
624
625 //
626 // Program IO resources
627 //
628 ProgramResource (
629 IoBase,
630 IoBridge
631 );
632
633 //
634 // Program Mem32 resources
635 //
636 ProgramResource (
637 Mem32Base,
638 Mem32Bridge
639 );
640
641 //
642 // Program PMem32 resources
643 //
644 ProgramResource (
645 PMem32Base,
646 PMem32Bridge
647 );
648
649 //
650 // Program Mem64 resources
651 //
652 ProgramResource (
653 Mem64Base,
654 Mem64Bridge
655 );
656
657 //
658 // Program PMem64 resources
659 //
660 ProgramResource (
661 PMem64Base,
662 PMem64Bridge
663 );
664
665 if (AcpiConfig != NULL) {
666 FreePool (AcpiConfig);
667 }
668 }
669
670 //
671 // Destroy all the resource tree
672 //
673 DestroyResourceTree (&IoPool);
674 DestroyResourceTree (&Mem32Pool);
675 DestroyResourceTree (&PMem32Pool);
676 DestroyResourceTree (&Mem64Pool);
677 DestroyResourceTree (&PMem64Pool);
678
679 //
680 // Notify the resource allocation phase is to end
681 //
682 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);
683
684 return EFI_SUCCESS;
685 }
686
687
688 EFI_STATUS
689 PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport (
690 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
691 )
692 /*++
693
694 Routine Description:
695
696 Host brige resource allocator.
697
698 Arguments:
699
700 PciResAlloc - A pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
701
702 Returns:
703
704 EFI Status.
705
706 --*/
707 // TODO: EFI_NOT_FOUND - add return value to function comment
708 // TODO: EFI_NOT_FOUND - add return value to function comment
709 // TODO: EFI_NOT_FOUND - add return value to function comment
710 // TODO: EFI_SUCCESS - add return value to function comment
711 {
712 PCI_IO_DEVICE *RootBridgeDev;
713 EFI_HANDLE RootBridgeHandle;
714 VOID *AcpiConfig;
715 EFI_STATUS Status;
716 UINT64 IoBase;
717 UINT64 Mem32Base;
718 UINT64 PMem32Base;
719 UINT64 Mem64Base;
720 UINT64 PMem64Base;
721 UINT64 IoResStatus;
722 UINT64 Mem32ResStatus;
723 UINT64 PMem32ResStatus;
724 UINT64 Mem64ResStatus;
725 UINT64 PMem64ResStatus;
726 UINT64 MaxOptionRomSize;
727 PCI_RESOURCE_NODE *IoBridge;
728 PCI_RESOURCE_NODE *Mem32Bridge;
729 PCI_RESOURCE_NODE *PMem32Bridge;
730 PCI_RESOURCE_NODE *Mem64Bridge;
731 PCI_RESOURCE_NODE *PMem64Bridge;
732 PCI_RESOURCE_NODE IoPool;
733 PCI_RESOURCE_NODE Mem32Pool;
734 PCI_RESOURCE_NODE PMem32Pool;
735 PCI_RESOURCE_NODE Mem64Pool;
736 PCI_RESOURCE_NODE PMem64Pool;
737 BOOLEAN ReAllocate;
738 EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD HandleExtendedData;
739 EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;
740
741 //
742 // Reallocate flag
743 //
744 ReAllocate = FALSE;
745
746 //
747 // It will try several times if the resource allocation fails
748 //
749 while (TRUE) {
750
751 //
752 // Initialize resource pool
753 //
754 InitializeResourcePool (&IoPool, PciBarTypeIo16);
755 InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);
756 InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);
757 InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);
758 InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);
759
760 RootBridgeDev = NULL;
761 RootBridgeHandle = 0;
762
763 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
764
765 //
766 // Get RootBridg Device by handle
767 //
768 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
769
770 if (RootBridgeDev == NULL) {
771 return EFI_NOT_FOUND;
772 }
773
774 //
775 // Create the entire system resource map from the information collected by
776 // enumerator. Several resource tree was created
777 //
778
779 IoBridge = CreateResourceNode (
780 RootBridgeDev,
781 0,
782 0xFFF,
783 0,
784 PciBarTypeIo16,
785 PciResUsageTypical
786 );
787
788 Mem32Bridge = CreateResourceNode (
789 RootBridgeDev,
790 0,
791 0xFFFFF,
792 0,
793 PciBarTypeMem32,
794 PciResUsageTypical
795 );
796
797 PMem32Bridge = CreateResourceNode (
798 RootBridgeDev,
799 0,
800 0xFFFFF,
801 0,
802 PciBarTypePMem32,
803 PciResUsageTypical
804 );
805
806 Mem64Bridge = CreateResourceNode (
807 RootBridgeDev,
808 0,
809 0xFFFFF,
810 0,
811 PciBarTypeMem64,
812 PciResUsageTypical
813 );
814
815 PMem64Bridge = CreateResourceNode (
816 RootBridgeDev,
817 0,
818 0xFFFFF,
819 0,
820 PciBarTypePMem64,
821 PciResUsageTypical
822 );
823
824 //
825 // Create resourcemap by going through all the devices subject to this root bridge
826 //
827 Status = CreateResourceMap (
828 RootBridgeDev,
829 IoBridge,
830 Mem32Bridge,
831 PMem32Bridge,
832 Mem64Bridge,
833 PMem64Bridge
834 );
835
836 //
837 // Get the max ROM size that the root bridge can process
838 //
839 RootBridgeDev->RomSize = Mem32Bridge->Length;
840
841 //
842 // Skip to enlarge the resource request during realloction
843 //
844 if (!ReAllocate) {
845 //
846 // Get Max Option Rom size for current root bridge
847 //
848 MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);
849
850 //
851 // Enlarger the mem32 resource to accomdate the option rom
852 // if the mem32 resource is not enough to hold the rom
853 //
854 if (MaxOptionRomSize > Mem32Bridge->Length) {
855
856 Mem32Bridge->Length = MaxOptionRomSize;
857 RootBridgeDev->RomSize = MaxOptionRomSize;
858
859 //
860 // Alignment should be adjusted as well
861 //
862 if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) {
863 Mem32Bridge->Alignment = MaxOptionRomSize - 1;
864 }
865 }
866 }
867
868 //
869 // Based on the all the resource tree, contruct ACPI resource node to
870 // submit the resource aperture to pci host bridge protocol
871 //
872 Status = ConstructAcpiResourceRequestor (
873 RootBridgeDev,
874 IoBridge,
875 Mem32Bridge,
876 PMem32Bridge,
877 Mem64Bridge,
878 PMem64Bridge,
879 &AcpiConfig
880 );
881
882 //
883 // Insert these resource nodes into the database
884 //
885 InsertResourceNode (&IoPool, IoBridge);
886 InsertResourceNode (&Mem32Pool, Mem32Bridge);
887 InsertResourceNode (&PMem32Pool, PMem32Bridge);
888 InsertResourceNode (&Mem64Pool, Mem64Bridge);
889 InsertResourceNode (&PMem64Pool, PMem64Bridge);
890
891 if (Status == EFI_SUCCESS) {
892 //
893 // Submit the resource requirement
894 //
895 Status = PciResAlloc->SubmitResources (
896 PciResAlloc,
897 RootBridgeDev->Handle,
898 AcpiConfig
899 );
900 }
901
902 //
903 // Free acpi resource node
904 //
905 if (AcpiConfig != NULL) {
906 FreePool (AcpiConfig);
907 }
908
909 if (EFI_ERROR (Status)) {
910 //
911 // Destroy all the resource tree
912 //
913 DestroyResourceTree (&IoPool);
914 DestroyResourceTree (&Mem32Pool);
915 DestroyResourceTree (&PMem32Pool);
916 DestroyResourceTree (&Mem64Pool);
917 DestroyResourceTree (&PMem64Pool);
918 return Status;
919 }
920 }
921
922 //
923 // Notify pci bus driver starts to program the resource
924 //
925
926 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);
927
928 if (!EFI_ERROR (Status)) {
929 //
930 // Allocation succeed, then continue the following
931 //
932 break;
933 }
934
935 //
936 // If the resource allocation is unsuccessful, free resources on bridge
937 //
938
939 RootBridgeDev = NULL;
940 RootBridgeHandle = 0;
941
942 IoResStatus = EFI_RESOURCE_SATISFIED;
943 Mem32ResStatus = EFI_RESOURCE_SATISFIED;
944 PMem32ResStatus = EFI_RESOURCE_SATISFIED;
945 Mem64ResStatus = EFI_RESOURCE_SATISFIED;
946 PMem64ResStatus = EFI_RESOURCE_SATISFIED;
947
948 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
949 //
950 // Get RootBridg Device by handle
951 //
952 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
953 if (RootBridgeDev == NULL) {
954 return EFI_NOT_FOUND;
955 }
956
957 //
958 // Get host bridge handle for status report
959 //
960 HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
961
962 //
963 // Get acpi resource node for all the resource types
964 //
965 AcpiConfig = NULL;
966
967 Status = PciResAlloc->GetProposedResources (
968 PciResAlloc,
969 RootBridgeDev->Handle,
970 &AcpiConfig
971 );
972
973 if (EFI_ERROR (Status)) {
974 return Status;
975 }
976
977 if (AcpiConfig != NULL) {
978 //
979 // Adjust resource allocation policy for each RB
980 //
981 GetResourceAllocationStatus (
982 AcpiConfig,
983 &IoResStatus,
984 &Mem32ResStatus,
985 &PMem32ResStatus,
986 &Mem64ResStatus,
987 &PMem64ResStatus
988 );
989 FreePool (AcpiConfig);
990 }
991 }
992 //
993 // End while
994 //
995
996 //
997 // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
998 //
999 //
1000 // It is very difficult to follow the spec here
1001 // Device path , Bar index can not be get here
1002 //
1003 ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));
1004
1005 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
1006 EFI_PROGRESS_CODE,
1007 EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,
1008 (VOID *) &AllocFailExtendedData,
1009 sizeof (AllocFailExtendedData)
1010 );
1011
1012 Status = PciHostBridgeAdjustAllocation (
1013 &IoPool,
1014 &Mem32Pool,
1015 &PMem32Pool,
1016 &Mem64Pool,
1017 &PMem64Pool,
1018 IoResStatus,
1019 Mem32ResStatus,
1020 PMem32ResStatus,
1021 Mem64ResStatus,
1022 PMem64ResStatus
1023 );
1024
1025 //
1026 // Destroy all the resource tree
1027 //
1028 DestroyResourceTree (&IoPool);
1029 DestroyResourceTree (&Mem32Pool);
1030 DestroyResourceTree (&PMem32Pool);
1031 DestroyResourceTree (&Mem64Pool);
1032 DestroyResourceTree (&PMem64Pool);
1033
1034 NotifyPhase (PciResAlloc, EfiPciHostBridgeFreeResources);
1035
1036 if (EFI_ERROR (Status)) {
1037 return Status;
1038 }
1039
1040 ReAllocate = TRUE;
1041
1042 }
1043 //
1044 // End main while
1045 //
1046
1047 //
1048 // Raise the EFI_IOB_PCI_RES_ALLOC status code
1049 //
1050 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
1051 EFI_PROGRESS_CODE,
1052 EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_RES_ALLOC,
1053 (VOID *) &HandleExtendedData,
1054 sizeof (HandleExtendedData)
1055 );
1056
1057 //
1058 // Notify pci bus driver starts to program the resource
1059 //
1060 NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);
1061
1062 RootBridgeDev = NULL;
1063
1064 RootBridgeHandle = 0;
1065
1066 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1067
1068 //
1069 // Get RootBridg Device by handle
1070 //
1071 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
1072
1073 if (RootBridgeDev == NULL) {
1074 return EFI_NOT_FOUND;
1075 }
1076
1077 //
1078 // Get acpi resource node for all the resource types
1079 //
1080 AcpiConfig = NULL;
1081 Status = PciResAlloc->GetProposedResources (
1082 PciResAlloc,
1083 RootBridgeDev->Handle,
1084 &AcpiConfig
1085 );
1086
1087 if (EFI_ERROR (Status)) {
1088 return Status;
1089 }
1090
1091 //
1092 // Get the resource base by interpreting acpi resource node
1093 //
1094 //
1095 GetResourceBase (
1096 AcpiConfig,
1097 &IoBase,
1098 &Mem32Base,
1099 &PMem32Base,
1100 &Mem64Base,
1101 &PMem64Base
1102 );
1103
1104 //
1105 // Process option rom for this root bridge
1106 //
1107 Status = ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize);
1108
1109 //
1110 // Create the entire system resource map from the information collected by
1111 // enumerator. Several resource tree was created
1112 //
1113 Status = GetResourceMap (
1114 RootBridgeDev,
1115 &IoBridge,
1116 &Mem32Bridge,
1117 &PMem32Bridge,
1118 &Mem64Bridge,
1119 &PMem64Bridge,
1120 &IoPool,
1121 &Mem32Pool,
1122 &PMem32Pool,
1123 &Mem64Pool,
1124 &PMem64Pool
1125 );
1126
1127 if (EFI_ERROR (Status)) {
1128 return Status;
1129 }
1130
1131 //
1132 // Program IO resources
1133 //
1134 ProgramResource (
1135 IoBase,
1136 IoBridge
1137 );
1138
1139 //
1140 // Program Mem32 resources
1141 //
1142 ProgramResource (
1143 Mem32Base,
1144 Mem32Bridge
1145 );
1146
1147 //
1148 // Program PMem32 resources
1149 //
1150 ProgramResource (
1151 PMem32Base,
1152 PMem32Bridge
1153 );
1154
1155 //
1156 // Program Mem64 resources
1157 //
1158 ProgramResource (
1159 Mem64Base,
1160 Mem64Bridge
1161 );
1162
1163 //
1164 // Program PMem64 resources
1165 //
1166 ProgramResource (
1167 PMem64Base,
1168 PMem64Bridge
1169 );
1170
1171 if (AcpiConfig != NULL) {
1172 gBS->FreePool (AcpiConfig);
1173 }
1174 }
1175
1176 //
1177 // Destroy all the resource tree
1178 //
1179 DestroyResourceTree (&IoPool);
1180 DestroyResourceTree (&Mem32Pool);
1181 DestroyResourceTree (&PMem32Pool);
1182 DestroyResourceTree (&Mem64Pool);
1183 DestroyResourceTree (&PMem64Pool);
1184
1185 //
1186 // Notify the resource allocation phase is to end
1187 //
1188 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);
1189
1190 return EFI_SUCCESS;
1191 }
1192
1193
1194 EFI_STATUS
1195 PciScanBus (
1196 IN PCI_IO_DEVICE *Bridge,
1197 IN UINT8 StartBusNumber,
1198 OUT UINT8 *SubBusNumber,
1199 OUT UINT8 *PaddedBusRange
1200 )
1201 {
1202 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1203 return PciScanBus_WithHotPlugDeviceSupport (
1204 Bridge,
1205 StartBusNumber,
1206 SubBusNumber,
1207 PaddedBusRange
1208 );
1209 } else {
1210 return PciScanBus_WithoutHotPlugDeviceSupport (
1211 Bridge,
1212 StartBusNumber,
1213 SubBusNumber,
1214 PaddedBusRange
1215 );
1216 }
1217 }
1218
1219
1220 EFI_STATUS
1221 PciScanBus_WithoutHotPlugDeviceSupport (
1222 IN PCI_IO_DEVICE *Bridge,
1223 IN UINT8 StartBusNumber,
1224 OUT UINT8 *SubBusNumber,
1225 OUT UINT8 *PaddedBusRange
1226 )
1227 /*++
1228
1229 Routine Description:
1230
1231 This routine is used to assign bus number to the given PCI bus system
1232
1233 Arguments:
1234
1235 Returns:
1236
1237 None
1238
1239 --*/
1240 // TODO: Bridge - add argument and description to function comment
1241 // TODO: StartBusNumber - add argument and description to function comment
1242 // TODO: SubBusNumber - add argument and description to function comment
1243 // TODO: PaddedBusRange - add argument and description to function comment
1244 // TODO: EFI_DEVICE_ERROR - add return value to function comment
1245 // TODO: EFI_SUCCESS - add return value to function comment
1246 {
1247 EFI_STATUS Status;
1248 PCI_TYPE00 Pci;
1249 UINT8 Device;
1250 UINT8 Func;
1251 UINT64 Address;
1252 UINTN SecondBus;
1253 UINT16 Register;
1254 PCI_IO_DEVICE *PciDevice;
1255 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1256
1257 PciRootBridgeIo = Bridge->PciRootBridgeIo;
1258 SecondBus = 0;
1259 Register = 0;
1260
1261 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
1262 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
1263
1264 //
1265 // Check to see whether a pci device is present
1266 //
1267 Status = PciDevicePresent (
1268 PciRootBridgeIo,
1269 &Pci,
1270 StartBusNumber,
1271 Device,
1272 Func
1273 );
1274
1275 if (!EFI_ERROR (Status) &&
1276 (IS_PCI_BRIDGE (&Pci) ||
1277 IS_CARDBUS_BRIDGE (&Pci))) {
1278
1279 DEBUG((EFI_D_ERROR, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber, Device, Func ));
1280
1281 //
1282 // Get the bridge information
1283 //
1284 Status = PciSearchDevice (
1285 Bridge,
1286 &Pci,
1287 StartBusNumber,
1288 Device,
1289 Func,
1290 &PciDevice
1291 );
1292
1293 if (EFI_ERROR (Status)) {
1294 return Status;
1295 }
1296
1297 //
1298 // Add feature to support customized secondary bus number
1299 //
1300 if (*SubBusNumber == 0) {
1301 *SubBusNumber = *PaddedBusRange;
1302 *PaddedBusRange = 0;
1303 }
1304
1305 (*SubBusNumber)++;
1306
1307 SecondBus = (*SubBusNumber);
1308
1309 Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);
1310
1311 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
1312
1313 Status = PciRootBridgeIoWrite (
1314 PciRootBridgeIo,
1315 &Pci,
1316 EfiPciWidthUint16,
1317 Address,
1318 1,
1319 &Register
1320 );
1321
1322 //
1323 // Initialize SubBusNumber to SecondBus
1324 //
1325 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);
1326 Status = PciRootBridgeIoWrite (
1327 PciRootBridgeIo,
1328 &Pci,
1329 EfiPciWidthUint8,
1330 Address,
1331 1,
1332 SubBusNumber
1333 );
1334 //
1335 // If it is PPB, resursively search down this bridge
1336 //
1337 if (IS_PCI_BRIDGE (&Pci)) {
1338 //
1339 // Temporarily initialize SubBusNumber to maximum bus number to ensure the
1340 // PCI configuration transaction to go through any PPB
1341 //
1342 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);
1343 Register = 0xFF;
1344 Status = PciRootBridgeIoWrite (
1345 PciRootBridgeIo,
1346 &Pci,
1347 EfiPciWidthUint8,
1348 Address,
1349 1,
1350 &Register
1351 );
1352
1353 PreprocessController (
1354 PciDevice,
1355 PciDevice->BusNumber,
1356 PciDevice->DeviceNumber,
1357 PciDevice->FunctionNumber,
1358 EfiPciBeforeChildBusEnumeration
1359 );
1360
1361 DEBUG((EFI_D_ERROR, "Scan PPB(%02d,%02d,%02d)\n", PciDevice->BusNumber, PciDevice->DeviceNumber,PciDevice->FunctionNumber ));
1362 Status = PciScanBus (
1363 PciDevice,
1364 (UINT8) (SecondBus),
1365 SubBusNumber,
1366 PaddedBusRange
1367 );
1368
1369 if (EFI_ERROR (Status)) {
1370 return EFI_DEVICE_ERROR;
1371 }
1372 }
1373
1374 //
1375 // Set the current maximum bus number under the PPB
1376 //
1377
1378 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);
1379
1380 Status = PciRootBridgeIoWrite (
1381 PciRootBridgeIo,
1382 &Pci,
1383 EfiPciWidthUint8,
1384 Address,
1385 1,
1386 SubBusNumber
1387 );
1388
1389 }
1390
1391 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
1392
1393 //
1394 // Skip sub functions, this is not a multi function device
1395 //
1396
1397 Func = PCI_MAX_FUNC;
1398 }
1399 }
1400 }
1401
1402 return EFI_SUCCESS;
1403 }
1404
1405 EFI_STATUS
1406 PciScanBus_WithHotPlugDeviceSupport (
1407 IN PCI_IO_DEVICE *Bridge,
1408 IN UINT8 StartBusNumber,
1409 OUT UINT8 *SubBusNumber,
1410 OUT UINT8 *PaddedBusRange
1411 )
1412 /*++
1413
1414 Routine Description:
1415
1416 This routine is used to assign bus number to the given PCI bus system
1417
1418 Arguments:
1419
1420 Bridge - A pointer to the PCI_IO_DEVICE structure.
1421 StartBusNumber - The start bus number.
1422 SubBusNumber - A pointer to the sub bus number.
1423 PaddedBusRange - A pointer to the padded bus range.
1424
1425 Returns:
1426
1427 None
1428
1429 --*/
1430 // TODO: EFI_DEVICE_ERROR - add return value to function comment
1431 // TODO: EFI_SUCCESS - add return value to function comment
1432 {
1433 EFI_STATUS Status;
1434 PCI_TYPE00 Pci;
1435 UINT8 Device;
1436 UINT8 Func;
1437 UINT64 Address;
1438 UINTN SecondBus;
1439 UINT16 Register;
1440 UINTN HpIndex;
1441 PCI_IO_DEVICE *PciDevice;
1442 EFI_EVENT Event;
1443 EFI_HPC_STATE State;
1444 UINT64 PciAddress;
1445 EFI_HPC_PADDING_ATTRIBUTES Attributes;
1446 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
1447 UINT16 BusRange;
1448 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1449 BOOLEAN BusPadding;
1450
1451 PciRootBridgeIo = Bridge->PciRootBridgeIo;
1452 SecondBus = 0;
1453 Register = 0;
1454 State = 0;
1455 Attributes = (EFI_HPC_PADDING_ATTRIBUTES) 0;
1456 BusRange = 0;
1457
1458 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
1459 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
1460
1461 //
1462 // Check to see whether a pci device is present
1463 //
1464 Status = PciDevicePresent (
1465 PciRootBridgeIo,
1466 &Pci,
1467 StartBusNumber,
1468 Device,
1469 Func
1470 );
1471
1472 if (EFI_ERROR (Status)) {
1473 if (Func == 0) {
1474 //
1475 // Skip sub functions, this is not a multi function device
1476 //
1477 Func = PCI_MAX_FUNC;
1478 }
1479
1480 continue;
1481 }
1482
1483 DEBUG((EFI_D_ERROR, "Found DEV(%02d,%02d,%02d)\n", StartBusNumber, Device, Func ));
1484
1485 //
1486 // Get the PCI device information
1487 //
1488 Status = PciSearchDevice (
1489 Bridge,
1490 &Pci,
1491 StartBusNumber,
1492 Device,
1493 Func,
1494 &PciDevice
1495 );
1496
1497 ASSERT (!EFI_ERROR (Status));
1498
1499 PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);
1500
1501 if (!IS_PCI_BRIDGE (&Pci)) {
1502 //
1503 // PCI bridges will be called later
1504 // Here just need for PCI device or PCI to cardbus controller
1505 // EfiPciBeforeChildBusEnumeration for PCI Device Node
1506 //
1507 PreprocessController (
1508 PciDevice,
1509 PciDevice->BusNumber,
1510 PciDevice->DeviceNumber,
1511 PciDevice->FunctionNumber,
1512 EfiPciBeforeChildBusEnumeration
1513 );
1514 }
1515
1516 //
1517 // For Pci Hotplug controller devcie only
1518 //
1519 if (gPciHotPlugInit != NULL) {
1520 //
1521 // Check if it is a Hotplug PCI controller
1522 //
1523 if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {
1524
1525 if (!gPciRootHpcData[HpIndex].Initialized) {
1526
1527 Status = CreateEventForHpc (HpIndex, &Event);
1528
1529 ASSERT (!EFI_ERROR (Status));
1530
1531 Status = gPciHotPlugInit->InitializeRootHpc (
1532 gPciHotPlugInit,
1533 gPciRootHpcPool[HpIndex].HpcDevicePath,
1534 PciAddress,
1535 Event,
1536 &State
1537 );
1538
1539 PreprocessController (
1540 PciDevice,
1541 PciDevice->BusNumber,
1542 PciDevice->DeviceNumber,
1543 PciDevice->FunctionNumber,
1544 EfiPciBeforeChildBusEnumeration
1545 );
1546 }
1547 }
1548 }
1549
1550 if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) {
1551 //
1552 // For PPB
1553 // Get the bridge information
1554 //
1555 BusPadding = FALSE;
1556 if (gPciHotPlugInit != NULL) {
1557
1558 if (IsRootPciHotPlugBus (PciDevice->DevicePath, &HpIndex)) {
1559
1560 //
1561 // If it is initialized, get the padded bus range
1562 //
1563 Status = gPciHotPlugInit->GetResourcePadding (
1564 gPciHotPlugInit,
1565 gPciRootHpcPool[HpIndex].HpbDevicePath,
1566 PciAddress,
1567 &State,
1568 (VOID **) &Descriptors,
1569 &Attributes
1570 );
1571
1572 if (EFI_ERROR (Status)) {
1573 return Status;
1574 }
1575
1576 BusRange = 0;
1577 Status = PciGetBusRange (
1578 &Descriptors,
1579 NULL,
1580 NULL,
1581 &BusRange
1582 );
1583
1584 gBS->FreePool (Descriptors);
1585
1586 if (EFI_ERROR (Status)) {
1587 return Status;
1588 }
1589
1590 BusPadding = TRUE;
1591 }
1592 }
1593
1594 //
1595 // Add feature to support customized secondary bus number
1596 //
1597 if (*SubBusNumber == 0) {
1598 *SubBusNumber = *PaddedBusRange;
1599 *PaddedBusRange = 0;
1600 }
1601
1602 (*SubBusNumber)++;
1603 SecondBus = *SubBusNumber;
1604
1605 Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);
1606 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
1607
1608 Status = PciRootBridgeIoWrite (
1609 PciRootBridgeIo,
1610 &Pci,
1611 EfiPciWidthUint16,
1612 Address,
1613 1,
1614 &Register
1615 );
1616
1617
1618 //
1619 // If it is PPB, resursively search down this bridge
1620 //
1621 if (IS_PCI_BRIDGE (&Pci)) {
1622
1623 //
1624 // Initialize SubBusNumber to Maximum bus number
1625 //
1626 Register = 0xFF;
1627 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);
1628 Status = PciRootBridgeIoWrite (
1629 PciRootBridgeIo,
1630 &Pci,
1631 EfiPciWidthUint8,
1632 Address,
1633 1,
1634 &Register
1635 );
1636
1637 //
1638 // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige
1639 //
1640 PreprocessController (
1641 PciDevice,
1642 PciDevice->BusNumber,
1643 PciDevice->DeviceNumber,
1644 PciDevice->FunctionNumber,
1645 EfiPciBeforeChildBusEnumeration
1646 );
1647
1648 DEBUG((EFI_D_ERROR, "Scan PPB(%02d,%02d,%02d)\n", PciDevice->BusNumber, PciDevice->DeviceNumber,PciDevice->FunctionNumber ));
1649 Status = PciScanBus (
1650 PciDevice,
1651 (UINT8) (SecondBus),
1652 SubBusNumber,
1653 PaddedBusRange
1654 );
1655
1656 if (EFI_ERROR (Status)) {
1657 return EFI_DEVICE_ERROR;
1658 }
1659 }
1660
1661 if (BusPadding) {
1662 //
1663 // Ensure the device is enabled and initialized
1664 //
1665 if ((Attributes == EfiPaddingPciRootBridge) &&
1666 (State & EFI_HPC_STATE_ENABLED) &&
1667 (State & EFI_HPC_STATE_INITIALIZED) ) {
1668 *PaddedBusRange = (UINT8) ((UINT8) (BusRange) +*PaddedBusRange);
1669 } else {
1670 *SubBusNumber = (UINT8) ((UINT8) (BusRange) +*SubBusNumber);
1671 }
1672 }
1673
1674 //
1675 // Set the current maximum bus number under the PPB
1676 //
1677 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);
1678
1679 Status = PciRootBridgeIoWrite (
1680 PciRootBridgeIo,
1681 &Pci,
1682 EfiPciWidthUint8,
1683 Address,
1684 1,
1685 SubBusNumber
1686 );
1687 }
1688
1689 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
1690
1691 //
1692 // Skip sub functions, this is not a multi function device
1693 //
1694 Func = PCI_MAX_FUNC;
1695 }
1696
1697 }
1698 }
1699
1700 return EFI_SUCCESS;
1701 }
1702
1703 EFI_STATUS
1704 PciRootBridgeP2CProcess (
1705 IN PCI_IO_DEVICE *Bridge
1706 )
1707 /*++
1708
1709 Routine Description:
1710
1711 Process Option Rom on this host bridge
1712
1713 Arguments:
1714
1715 Returns:
1716
1717 None
1718
1719 --*/
1720 // TODO: Bridge - add argument and description to function comment
1721 // TODO: EFI_SUCCESS - add return value to function comment
1722 {
1723 LIST_ENTRY *CurrentLink;
1724 PCI_IO_DEVICE *Temp;
1725 EFI_HPC_STATE State;
1726 UINT64 PciAddress;
1727 EFI_STATUS Status;
1728
1729 CurrentLink = Bridge->ChildList.ForwardLink;
1730
1731 while (CurrentLink && CurrentLink != &Bridge->ChildList) {
1732
1733 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1734
1735 if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
1736
1737 if (gPciHotPlugInit && Temp->Allocated) {
1738
1739 //
1740 // Raise the EFI_IOB_PCI_HPC_INIT status code
1741 //
1742 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
1743 EFI_PROGRESS_CODE,
1744 EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_HPC_INIT,
1745 Temp->DevicePath
1746 );
1747
1748 PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
1749 Status = gPciHotPlugInit->InitializeRootHpc (
1750 gPciHotPlugInit,
1751 Temp->DevicePath,
1752 PciAddress,
1753 NULL,
1754 &State
1755 );
1756
1757 if (!EFI_ERROR (Status)) {
1758 Status = PciBridgeEnumerator (Temp);
1759
1760 if (EFI_ERROR (Status)) {
1761 return Status;
1762 }
1763 }
1764
1765 CurrentLink = CurrentLink->ForwardLink;
1766 continue;
1767
1768 }
1769 }
1770
1771 if (!IsListEmpty (&Temp->ChildList)) {
1772 Status = PciRootBridgeP2CProcess (Temp);
1773 }
1774
1775 CurrentLink = CurrentLink->ForwardLink;
1776 }
1777
1778 return EFI_SUCCESS;
1779 }
1780
1781 EFI_STATUS
1782 PciHostBridgeP2CProcess (
1783 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
1784 )
1785 /*++
1786
1787 Routine Description:
1788
1789 Arguments:
1790
1791 Returns:
1792
1793 None
1794
1795 --*/
1796 // TODO: PciResAlloc - add argument and description to function comment
1797 // TODO: EFI_NOT_FOUND - add return value to function comment
1798 // TODO: EFI_SUCCESS - add return value to function comment
1799 {
1800 EFI_HANDLE RootBridgeHandle;
1801 PCI_IO_DEVICE *RootBridgeDev;
1802 EFI_STATUS Status;
1803
1804 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1805 return EFI_SUCCESS;
1806 }
1807
1808 RootBridgeHandle = NULL;
1809
1810 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1811
1812 //
1813 // Get RootBridg Device by handle
1814 //
1815 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
1816
1817 if (RootBridgeDev == NULL) {
1818 return EFI_NOT_FOUND;
1819 }
1820
1821 Status = PciRootBridgeP2CProcess (RootBridgeDev);
1822
1823 if (EFI_ERROR (Status)) {
1824 return Status;
1825 }
1826
1827 }
1828
1829 return EFI_SUCCESS;
1830 }
1831
1832 EFI_STATUS
1833 PciHostBridgeEnumerator (
1834 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
1835 )
1836 /*++
1837
1838 Routine Description:
1839
1840 This function is used to enumerate the entire host bridge
1841 in a given platform
1842
1843 Arguments:
1844
1845 PciResAlloc - A pointer to the resource allocate protocol.
1846
1847 Returns:
1848
1849 None
1850
1851 --*/
1852 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1853 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1854 // TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
1855 // TODO: EFI_SUCCESS - add return value to function comment
1856 {
1857 EFI_HANDLE RootBridgeHandle;
1858 PCI_IO_DEVICE *RootBridgeDev;
1859 EFI_STATUS Status;
1860 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1861 UINT16 MinBus;
1862 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
1863
1864 InitializeHotPlugSupport ();
1865
1866 //
1867 // Notify the bus allocation phase is about to start
1868 //
1869 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
1870
1871 DEBUG((EFI_D_ERROR, "PCI Bus First Scanning\n"));
1872 RootBridgeHandle = NULL;
1873 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1874
1875 //
1876 // if a root bridge instance is found, create root bridge device for it
1877 //
1878
1879 RootBridgeDev = CreateRootBridge (RootBridgeHandle);
1880
1881 if (RootBridgeDev == NULL) {
1882 return EFI_OUT_OF_RESOURCES;
1883 }
1884
1885 //
1886 // Enumerate all the buses under this root bridge
1887 //
1888
1889 Status = PciRootBridgeEnumerator (
1890 PciResAlloc,
1891 RootBridgeDev
1892 );
1893
1894 DestroyRootBridge (RootBridgeDev);
1895 if (EFI_ERROR (Status)) {
1896 return Status;
1897 }
1898 }
1899
1900 //
1901 // Notify the bus allocation phase is finished for the first time
1902 //
1903 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
1904
1905 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
1906
1907 if (gPciHotPlugInit != NULL) {
1908 //
1909 // Wait for all HPC initialized
1910 //
1911 Status = AllRootHPCInitialized (STALL_1_SECOND * 15);
1912
1913 if (EFI_ERROR (Status)) {
1914 return Status;
1915 }
1916
1917 //
1918 // Notify the bus allocation phase is about to start for the 2nd time
1919 //
1920 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
1921
1922 DEBUG((EFI_D_ERROR, "PCI Bus Second Scanning\n"));
1923 RootBridgeHandle = NULL;
1924 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1925
1926 //
1927 // if a root bridge instance is found, create root bridge device for it
1928 //
1929
1930 RootBridgeDev = CreateRootBridge (RootBridgeHandle);
1931
1932 if (RootBridgeDev == NULL) {
1933 return EFI_OUT_OF_RESOURCES;
1934 }
1935
1936 //
1937 // Enumerate all the buses under this root bridge
1938 //
1939
1940 Status = PciRootBridgeEnumerator (
1941 PciResAlloc,
1942 RootBridgeDev
1943 );
1944
1945 DestroyRootBridge (RootBridgeDev);
1946 if (EFI_ERROR (Status)) {
1947 return Status;
1948 }
1949 }
1950
1951 //
1952 // Notify the bus allocation phase is to end for the 2nd time
1953 //
1954 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
1955 }
1956 }
1957
1958 //
1959 // Notify the resource allocation phase is to start
1960 //
1961 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation);
1962
1963 RootBridgeHandle = NULL;
1964 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
1965
1966 //
1967 // if a root bridge instance is found, create root bridge device for it
1968 //
1969
1970 RootBridgeDev = CreateRootBridge (RootBridgeHandle);
1971
1972 if (RootBridgeDev == NULL) {
1973 return EFI_OUT_OF_RESOURCES;
1974 }
1975
1976 Status = StartManagingRootBridge (RootBridgeDev);
1977
1978 if (EFI_ERROR (Status)) {
1979 return Status;
1980 }
1981
1982 PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;
1983 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
1984
1985 if (EFI_ERROR (Status)) {
1986 return Status;
1987 }
1988
1989 Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);
1990
1991 if (EFI_ERROR (Status)) {
1992 return Status;
1993 }
1994
1995 //
1996 // Determine root bridge attribute by calling interface of Pcihostbridge
1997 // protocol
1998 //
1999 DetermineRootBridgeAttributes (
2000 PciResAlloc,
2001 RootBridgeDev
2002 );
2003
2004 //
2005 // Collect all the resource information under this root bridge
2006 // A database that records all the information about pci device subject to this
2007 // root bridge will then be created
2008 //
2009 Status = PciPciDeviceInfoCollector (
2010 RootBridgeDev,
2011 (UINT8) MinBus
2012 );
2013
2014 if (EFI_ERROR (Status)) {
2015 return Status;
2016 }
2017
2018 InsertRootBridge (RootBridgeDev);
2019
2020 //
2021 // Record the hostbridge handle
2022 //
2023 AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle);
2024 }
2025
2026 return EFI_SUCCESS;
2027 }
2028
2029 /**
2030 Read PCI device configuration register by specified address.
2031
2032 This function check the incompatiblilites on PCI device. Return the register
2033 value.
2034
2035 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2036 @param PciIo A pointer to EFI_PCI_PROTOCOL.
2037 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2038 @param Width Signifies the width of the memory operations.
2039 @Param Address The address within the PCI configuration space for the PCI controller.
2040 @param Buffer For read operations, the destination buffer to store the results. For
2041 write operations, the source buffer to write data from.
2042
2043 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2044 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2045 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2046 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2047
2048 **/
2049 STATIC
2050 EFI_STATUS
2051 ReadConfigData (
2052 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
2053 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
2054 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
2055 IN UINT64 Width,
2056 IN UINT64 Address,
2057 IN OUT VOID *Buffer
2058 )
2059 {
2060 EFI_STATUS Status;
2061 UINT64 AccessWidth;
2062 EFI_PCI_REGISTER_ACCESS_DATA *PciRegisterAccessData;
2063 UINT64 AccessAddress;
2064 UINTN Stride;
2065 UINT64 TempBuffer;
2066 UINT8 *Pointer;
2067
2068 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
2069
2070 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) {
2071 //
2072 // check access compatibility at first time
2073 //
2074 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, Address & 0xff, Width, &PciRegisterAccessData);
2075
2076 if (Status == EFI_SUCCESS) {
2077 //
2078 // there exist incompatibility on this operation
2079 //
2080 AccessWidth = Width;
2081
2082 if (PciRegisterAccessData->Width != VALUE_NOCARE) {
2083 AccessWidth = PciRegisterAccessData->Width;
2084 }
2085
2086 AccessAddress = Address & ~((1 << AccessWidth) - 1);
2087
2088 TempBuffer = 0;
2089 Stride = 0;
2090 Pointer = (UINT8 *) &TempBuffer;
2091
2092 while (1) {
2093
2094 if (PciRootBridgeIo != NULL) {
2095 Status = PciRootBridgeIo->Pci.Read (
2096 PciRootBridgeIo,
2097 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,
2098 AccessAddress,
2099 1,
2100 Pointer
2101 );
2102 } else if (PciIo != NULL) {
2103 Status = PciIo->Pci.Read (
2104 PciIo,
2105 (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,
2106 (UINT32) AccessAddress,
2107 1,
2108 Pointer
2109 );
2110 }
2111
2112 if (Status != EFI_SUCCESS) {
2113 return Status;
2114 }
2115
2116 Stride = 1 << AccessWidth;
2117 AccessAddress += Stride;
2118 if (AccessAddress >= (Address + (1 << Width))) {
2119 //
2120 // if all datas have been read, exist
2121 //
2122 break;
2123 }
2124
2125 Pointer += Stride;
2126
2127 if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {
2128 //
2129 // if current offset doesn't reach the end
2130 //
2131 continue;
2132 }
2133
2134 FreePool (PciRegisterAccessData);
2135
2136 //
2137 // continue checking access incompatibility
2138 //
2139 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);
2140 if (Status == EFI_SUCCESS) {
2141 if (PciRegisterAccessData->Width != VALUE_NOCARE) {
2142 AccessWidth = PciRegisterAccessData->Width;
2143 }
2144 }
2145 }
2146
2147 FreePool (PciRegisterAccessData);
2148
2149 switch (Width) {
2150 case EfiPciWidthUint8:
2151 * (UINT8 *) Buffer = (UINT8) TempBuffer;
2152 break;
2153 case EfiPciWidthUint16:
2154 * (UINT16 *) Buffer = (UINT16) TempBuffer;
2155 break;
2156 case EfiPciWidthUint32:
2157 * (UINT32 *) Buffer = (UINT32) TempBuffer;
2158 break;
2159 default:
2160 return EFI_UNSUPPORTED;
2161 }
2162
2163 return Status;
2164 }
2165 }
2166 //
2167 // AccessWidth incompatible check not supportted
2168 // or, there doesn't exist incompatibility on this operation
2169 //
2170 if (PciRootBridgeIo != NULL) {
2171 Status = PciRootBridgeIo->Pci.Read (
2172 PciRootBridgeIo,
2173 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
2174 Address,
2175 1,
2176 Buffer
2177 );
2178
2179 } else {
2180 Status = PciIo->Pci.Read (
2181 PciIo,
2182 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
2183 (UINT32) Address,
2184 1,
2185 Buffer
2186 );
2187 }
2188
2189 return Status;
2190 }
2191
2192 /**
2193 Update register value by checking PCI device incompatibility.
2194
2195 This function check register value incompatibilites on PCI device. Return the register
2196 value.
2197
2198 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2199 @param AccessType Access type, READ or WRITE.
2200 @Param Address The address within the PCI configuration space.
2201 @param Buffer Store the register data.
2202
2203 @retval EFI_SUCCESS The data has been updated.
2204
2205 **/
2206 STATIC
2207 EFI_STATUS
2208 UpdateConfigData (
2209 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
2210 IN UINT64 AccessType,
2211 IN UINT64 Width,
2212 IN UINT64 Address,
2213 IN OUT VOID *Buffer
2214 )
2215 {
2216 EFI_STATUS Status;
2217 EFI_PCI_REGISTER_VALUE_DATA *PciRegisterData;
2218 UINT32 AndValue;
2219 UINT32 OrValue;
2220 UINT32 TempValue;
2221
2222 //
2223 // check register value incompatibility
2224 //
2225 Status = PciRegisterUpdateCheck (PciDeviceInfo, AccessType, Address & 0xff, &PciRegisterData);
2226
2227 if (Status == EFI_SUCCESS) {
2228
2229 AndValue = ((UINT32) PciRegisterData->AndValue) >> (((UINT8) Address & 0x3) * 8);
2230 OrValue = ((UINT32) PciRegisterData->OrValue) >> (((UINT8) Address & 0x3) * 8);
2231
2232 TempValue = * (UINT32 *) Buffer;
2233 if (PciRegisterData->AndValue != VALUE_NOCARE) {
2234 TempValue &= AndValue;
2235 }
2236 if (PciRegisterData->OrValue != VALUE_NOCARE) {
2237 TempValue |= OrValue;
2238 }
2239
2240 switch (Width) {
2241 case EfiPciWidthUint8:
2242 *(UINT8 *)Buffer = (UINT8) TempValue;
2243 break;
2244
2245 case EfiPciWidthUint16:
2246 *(UINT16 *)Buffer = (UINT16) TempValue;
2247 break;
2248 case EfiPciWidthUint32:
2249 *(UINT32 *)Buffer = TempValue;
2250 break;
2251
2252 default:
2253 return EFI_UNSUPPORTED;
2254 }
2255
2256 FreePool (PciRegisterData);
2257 }
2258
2259 return Status;
2260 }
2261
2262 /**
2263 Write PCI device configuration register by specified address.
2264
2265 This function check the incompatiblilites on PCI device, and write date
2266 into register.
2267
2268 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2269 @param PciIo A pointer to EFI_PCI_PROTOCOL.
2270 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2271 @param Width Signifies the width of the memory operations.
2272 @Param Address The address within the PCI configuration space for the PCI controller.
2273 @param Buffer For read operations, the destination buffer to store the results. For
2274 write operations, the source buffer to write data from.
2275
2276 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2277 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2278 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2279 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2280
2281 **/
2282 STATIC
2283 EFI_STATUS
2284 WriteConfigData (
2285 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
2286 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
2287 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,
2288 IN UINT64 Width,
2289 IN UINT64 Address,
2290 IN VOID *Buffer
2291 )
2292 {
2293 EFI_STATUS Status;
2294 UINT64 AccessWidth;
2295 EFI_PCI_REGISTER_ACCESS_DATA *PciRegisterAccessData;
2296 UINT64 AccessAddress;
2297 UINTN Stride;
2298 UINT8 *Pointer;
2299 UINT64 Data;
2300 UINTN Shift;
2301
2302 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
2303
2304 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) {
2305 //
2306 // check access compatibility at first time
2307 //
2308 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, Address & 0xff, Width, &PciRegisterAccessData);
2309
2310 if (Status == EFI_SUCCESS) {
2311 //
2312 // there exist incompatibility on this operation
2313 //
2314 AccessWidth = Width;
2315
2316 if (PciRegisterAccessData->Width != VALUE_NOCARE) {
2317 AccessWidth = PciRegisterAccessData->Width;
2318 }
2319
2320 AccessAddress = Address & ~((1 << AccessWidth) - 1);
2321
2322 Stride = 0;
2323 Pointer = (UINT8 *) &Buffer;
2324 Data = * (UINT64 *) Buffer;
2325
2326 while (1) {
2327
2328 if (AccessWidth > Width) {
2329 //
2330 // if actual access width is larger than orignal one, additional data need to be read back firstly
2331 //
2332 Status = ReadConfigData (PciRootBridgeIo, PciIo, PciDeviceInfo, AccessWidth, AccessAddress, &Data);
2333 if (Status != EFI_SUCCESS) {
2334 return Status;
2335 }
2336
2337 //
2338 // check data read incompatibility
2339 //
2340 UpdateConfigData (PciDeviceInfo, PCI_REGISTER_READ, AccessWidth, AccessAddress & 0xff, &Data);
2341
2342 Shift = (UINTN)(Address - AccessAddress) * 8;
2343 switch (Width) {
2344 case EfiPciWidthUint8:
2345 Data = (* (UINT8 *) Buffer) << Shift | (Data & ~(0xff << Shift));
2346 break;
2347
2348 case EfiPciWidthUint16:
2349 Data = (* (UINT16 *) Buffer) << Shift | (Data & ~(0xffff << Shift));
2350 break;
2351 }
2352
2353 //
2354 // check data write incompatibility
2355 //
2356 UpdateConfigData (PciDeviceInfo, PCI_REGISTER_WRITE, AccessWidth, MultU64x32 (AccessAddress, 0xff), &Data);
2357 }
2358
2359 if (PciRootBridgeIo != NULL) {
2360 Status = PciRootBridgeIo->Pci.Write (
2361 PciRootBridgeIo,
2362 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,
2363 AccessAddress,
2364 1,
2365 &Data
2366 );
2367 } else {
2368 Status = PciIo->Pci.Write (
2369 PciIo,
2370 (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,
2371 (UINT32) AccessAddress,
2372 1,
2373 &Data
2374 );
2375 }
2376
2377 if (Status != EFI_SUCCESS) {
2378 return Status;
2379 }
2380
2381 Data = RShiftU64 (Data, ((1 << AccessWidth) * 8));
2382
2383 Stride = 1 << AccessWidth;
2384 AccessAddress += Stride;
2385 if (AccessAddress >= (Address + (1 << Width))) {
2386 //
2387 // if all datas have been written, exist
2388 //
2389 break;
2390 }
2391
2392 Pointer += Stride;
2393
2394 if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {
2395 //
2396 // if current offset doesn't reach the end
2397 //
2398 continue;
2399 }
2400
2401 FreePool (PciRegisterAccessData);
2402
2403 //
2404 // continue checking access incompatibility
2405 //
2406 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);
2407 if (Status == EFI_SUCCESS) {
2408 if (PciRegisterAccessData->Width != VALUE_NOCARE) {
2409 AccessWidth = PciRegisterAccessData->Width;
2410 }
2411 }
2412 };
2413
2414 FreePool (PciRegisterAccessData);
2415
2416 return Status;
2417 }
2418
2419 }
2420 //
2421 // AccessWidth incompatible check not supportted
2422 // or, there doesn't exist incompatibility on this operation
2423 //
2424 if (PciRootBridgeIo != NULL) {
2425 Status = PciRootBridgeIo->Pci.Write (
2426 PciRootBridgeIo,
2427 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,
2428 Address,
2429 1,
2430 Buffer
2431 );
2432 } else {
2433 Status = PciIo->Pci.Write (
2434 PciIo,
2435 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
2436 (UINT32) Address,
2437 1,
2438 Buffer
2439 );
2440 }
2441
2442 return Status;
2443 }
2444
2445 /**
2446 Abstract PCI device device information.
2447
2448 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2449 @param PciIo A pointer to EFI_PCI_PROTOCOL.
2450 @param Pci A pointer to PCI_TYPE00.
2451 @Param Address The address within the PCI configuration space for the PCI controller.
2452 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.
2453
2454 @retval EFI_SUCCESS Pci device device information has been abstracted.
2455
2456 **/
2457 STATIC
2458 EFI_STATUS
2459 GetPciDeviceDeviceInfo (
2460 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
2461 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
2462 IN PCI_TYPE00 *Pci, OPTIONAL
2463 IN UINT64 Address, OPTIONAL
2464 OUT EFI_PCI_DEVICE_INFO *PciDeviceInfo
2465 )
2466 {
2467 EFI_STATUS Status;
2468 UINT64 PciAddress;
2469 UINT32 PciConfigData;
2470 PCI_IO_DEVICE *PciIoDevice;
2471
2472 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
2473
2474 if (PciIo != NULL) {
2475 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);
2476
2477 //
2478 // get pointer to PCI_TYPE00 from PciIoDevice
2479 //
2480 Pci = &PciIoDevice->Pci;
2481 }
2482
2483 if (Pci == NULL) {
2484 //
2485 // while PCI_TYPE00 hasn't been gotten, read PCI device device information directly
2486 //
2487 PciAddress = Address & 0xffffffffffffff00ULL;
2488 Status = PciRootBridgeIo->Pci.Read (
2489 PciRootBridgeIo,
2490 EfiPciWidthUint32,
2491 PciAddress,
2492 1,
2493 &PciConfigData
2494 );
2495
2496 if (EFI_ERROR (Status)) {
2497 return Status;
2498 }
2499
2500 if ((PciConfigData & 0xffff) == 0xffff) {
2501 return EFI_NOT_FOUND;
2502 }
2503
2504 PciDeviceInfo->VendorID = PciConfigData & 0xffff;
2505 PciDeviceInfo->DeviceID = PciConfigData >> 16;
2506
2507 Status = PciRootBridgeIo->Pci.Read (
2508 PciRootBridgeIo,
2509 EfiPciWidthUint32,
2510 PciAddress + 8,
2511 1,
2512 &PciConfigData
2513 );
2514 if (EFI_ERROR (Status)) {
2515 return Status;
2516 }
2517
2518 PciDeviceInfo->RevisionID = PciConfigData & 0xf;
2519
2520 Status = PciRootBridgeIo->Pci.Read (
2521 PciRootBridgeIo,
2522 EfiPciWidthUint32,
2523 PciAddress + 0x2c,
2524 1,
2525 &PciConfigData
2526 );
2527
2528 if (EFI_ERROR (Status)) {
2529 return Status;
2530 }
2531
2532 PciDeviceInfo->SubsystemVendorID = PciConfigData & 0xffff;
2533 PciDeviceInfo->SubsystemID = PciConfigData >> 16;
2534
2535 } else {
2536 PciDeviceInfo->VendorID = Pci->Hdr.VendorId;
2537 PciDeviceInfo->DeviceID = Pci->Hdr.DeviceId;
2538 PciDeviceInfo->RevisionID = Pci->Hdr.RevisionID;
2539 PciDeviceInfo->SubsystemVendorID = Pci->Device.SubsystemVendorID;
2540 PciDeviceInfo->SubsystemID = Pci->Device.SubsystemID;
2541 }
2542
2543 return EFI_SUCCESS;
2544 }
2545
2546 /**
2547 Read PCI configuration space with incompatibility check.
2548
2549 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2550 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.
2551 @param Pci A pointer to PCI_TYPE00.
2552 @param Width Signifies the width of the memory operations.
2553 @Param Address The address within the PCI configuration space for the PCI controller.
2554 @param Buffer For read operations, the destination buffer to store the results. For
2555 write operations, the source buffer to write data from.
2556
2557 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2558 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2559 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2560 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2561
2562 **/
2563 STATIC
2564 EFI_STATUS
2565 PciIncompatibilityCheckRead (
2566 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
2567 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
2568 IN PCI_TYPE00 *Pci, OPTIONAL
2569 IN UINTN Width,
2570 IN UINT64 Address,
2571 IN UINTN Count,
2572 IN OUT VOID *Buffer
2573 )
2574 {
2575 EFI_STATUS Status;
2576 EFI_PCI_DEVICE_INFO PciDeviceInfo;
2577 UINT32 Stride;
2578
2579 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
2580
2581 //
2582 // get PCI device device information
2583 //
2584 Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo);
2585 if (Status != EFI_SUCCESS) {
2586 return Status;
2587 }
2588
2589 Stride = 1 << Width;
2590
2591 for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *)Buffer + Stride) {
2592
2593 //
2594 // read configuration register
2595 //
2596 Status = ReadConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, (UINT64) Width, Address, Buffer);
2597
2598 if (Status != EFI_SUCCESS) {
2599 return Status;
2600 }
2601
2602 //
2603 // update the data read from configuration register
2604 //
2605 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) {
2606 UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_READ, Width, Address & 0xff, Buffer);
2607 }
2608 }
2609
2610 return EFI_SUCCESS;
2611 }
2612
2613 /**
2614 Write PCI configuration space with incompatibility check.
2615
2616 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2617 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.
2618 @param Pci A pointer to PCI_TYPE00.
2619 @param Width Signifies the width of the memory operations.
2620 @Param Address The address within the PCI configuration space for the PCI controller.
2621 @param Buffer For read operations, the destination buffer to store the results. For
2622 write operations, the source buffer to write data from.
2623
2624 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2625 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2626 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2627 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2628
2629 **/
2630 STATIC
2631 EFI_STATUS
2632 PciIncompatibilityCheckWrite (
2633 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL
2634 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL
2635 IN PCI_TYPE00 *Pci, OPTIONAL
2636 IN UINTN Width,
2637 IN UINT64 Address,
2638 IN UINTN Count,
2639 IN OUT VOID *Buffer
2640 )
2641 {
2642 EFI_STATUS Status;
2643 EFI_PCI_DEVICE_INFO PciDeviceInfo;
2644 UINT32 Stride;
2645 UINT64 Data;
2646
2647 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));
2648
2649 //
2650 // get PCI device device information
2651 //
2652 Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo);
2653 if (Status != EFI_SUCCESS) {
2654 return Status;
2655 }
2656
2657 Stride = 1 << Width;
2658
2659 for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *) Buffer + Stride) {
2660
2661 Data = 0;
2662
2663 switch (Width) {
2664 case EfiPciWidthUint8:
2665 Data = * (UINT8 *) Buffer;
2666 break;
2667 case EfiPciWidthUint16:
2668 Data = * (UINT16 *) Buffer;
2669 break;
2670
2671 case EfiPciWidthUint32:
2672 Data = * (UINT32 *) Buffer;
2673 break;
2674
2675 default:
2676 return EFI_UNSUPPORTED;
2677 }
2678
2679 //
2680 // update the data writen into configuration register
2681 //
2682 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) {
2683 UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_WRITE, Width, Address & 0xff, &Data);
2684 }
2685
2686 //
2687 // write configuration register
2688 //
2689 Status = WriteConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, Width, Address, &Data);
2690
2691 if (Status != EFI_SUCCESS) {
2692 return Status;
2693 }
2694 }
2695
2696 return EFI_SUCCESS;
2697 }
2698
2699 /**
2700 Read PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2701
2702 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2703 @param Pci A pointer to PCI_TYPE00.
2704 @param Width Signifies the width of the memory operations.
2705 @Param Address The address within the PCI configuration space for the PCI controller.
2706 @param Buffer For read operations, the destination buffer to store the results. For
2707 write operations, the source buffer to write data from.
2708
2709 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2710 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2711 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2712 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2713
2714 **/
2715 EFI_STATUS
2716 PciRootBridgeIoRead (
2717 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
2718 IN PCI_TYPE00 *Pci, OPTIONAL
2719 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
2720 IN UINT64 Address,
2721 IN UINTN Count,
2722 IN OUT VOID *Buffer
2723 )
2724 {
2725 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) {
2726 //
2727 // if PCI incompatibility check enabled
2728 //
2729 return PciIncompatibilityCheckRead (
2730 PciRootBridgeIo,
2731 NULL,
2732 Pci,
2733 (UINTN) Width,
2734 Address,
2735 Count,
2736 Buffer
2737 );
2738 } else {
2739 return PciRootBridgeIo->Pci.Read (
2740 PciRootBridgeIo,
2741 Width,
2742 Address,
2743 Count,
2744 Buffer
2745 );
2746 }
2747 }
2748
2749 /**
2750 Write PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2751
2752 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
2753 @param Pci A pointer to PCI_TYPE00.
2754 @param Width Signifies the width of the memory operations.
2755 @Param Address The address within the PCI configuration space for the PCI controller.
2756 @param Buffer For read operations, the destination buffer to store the results. For
2757 write operations, the source buffer to write data from.
2758
2759 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2760 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2761 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2762 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2763
2764 **/
2765 EFI_STATUS
2766 PciRootBridgeIoWrite (
2767 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
2768 IN PCI_TYPE00 *Pci,
2769 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
2770 IN UINT64 Address,
2771 IN UINTN Count,
2772 IN OUT VOID *Buffer
2773 )
2774 {
2775 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) {
2776 //
2777 // if PCI incompatibility check enabled
2778 //
2779 return PciIncompatibilityCheckWrite (
2780 PciRootBridgeIo,
2781 NULL,
2782 Pci,
2783 Width,
2784 Address,
2785 Count,
2786 Buffer
2787 );
2788
2789 } else {
2790 return PciRootBridgeIo->Pci.Write (
2791 PciRootBridgeIo,
2792 Width,
2793 Address,
2794 Count,
2795 Buffer
2796 );
2797 }
2798 }
2799
2800 /**
2801 Read PCI configuration space through EFI_PCI_IO_PROTOCOL.
2802
2803 @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.
2804 @param Width Signifies the width of the memory operations.
2805 @Param Address The address within the PCI configuration space for the PCI controller.
2806 @param Buffer For read operations, the destination buffer to store the results. For
2807 write operations, the source buffer to write data from.
2808
2809 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2810 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2811 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2812 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2813
2814 **/
2815 EFI_STATUS
2816 PciIoRead (
2817 IN EFI_PCI_IO_PROTOCOL *PciIo,
2818 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
2819 IN UINT32 Address,
2820 IN UINTN Count,
2821 IN OUT VOID *Buffer
2822 )
2823 {
2824 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) {
2825 //
2826 // if PCI incompatibility check enabled
2827 //
2828 return PciIncompatibilityCheckRead (
2829 NULL,
2830 PciIo,
2831 NULL,
2832 (UINTN) Width,
2833 Address,
2834 Count,
2835 Buffer
2836 );
2837 } else {
2838 return PciIo->Pci.Read (
2839 PciIo,
2840 Width,
2841 Address,
2842 Count,
2843 Buffer
2844 );
2845 }
2846 }
2847
2848 /**
2849 Write PCI configuration space through EFI_PCI_IO_PROTOCOL.
2850
2851 @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.
2852 @param Width Signifies the width of the memory operations.
2853 @Param Address The address within the PCI configuration space for the PCI controller.
2854 @param Buffer For read operations, the destination buffer to store the results. For
2855 write operations, the source buffer to write data from.
2856
2857 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.
2858 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
2859 @retval EFI_INVALID_PARAMETER Buffer is NULL.
2860 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
2861
2862 **/
2863 EFI_STATUS
2864 PciIoWrite (
2865 IN EFI_PCI_IO_PROTOCOL *PciIo,
2866 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,
2867 IN UINT32 Address,
2868 IN UINTN Count,
2869 IN OUT VOID *Buffer
2870 )
2871 {
2872 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) {
2873
2874 //
2875 // if PCI incompatibility check enabled
2876 //
2877 return PciIncompatibilityCheckWrite (
2878 NULL,
2879 PciIo,
2880 NULL,
2881 Width,
2882 Address,
2883 Count,
2884 Buffer
2885 );
2886
2887 } else {
2888 return PciIo->Pci.Write (
2889 PciIo,
2890 Width,
2891 Address,
2892 Count,
2893 Buffer
2894 );
2895 }
2896 }