]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
OvmfPkg/IncompatiblePciDeviceSupportDxe: Ignore OptionRom in Td guest
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / PciBusDxe / PciEnumeratorSupport.c
1 /** @file
2 PCI emumeration support functions implementation for PCI Bus module.
3
4 Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "PciBus.h"
11
12 extern CHAR16 *mBarTypeStr[];
13 extern EDKII_DEVICE_SECURITY_PROTOCOL *mDeviceSecurityProtocol;
14
15 #define OLD_ALIGN 0xFFFFFFFFFFFFFFFFULL
16 #define EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL
17 #define SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL
18 #define DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL
19
20 /**
21 This routine is used to check whether the pci device is present.
22
23 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
24 @param Pci Output buffer for PCI device configuration space.
25 @param Bus PCI bus NO.
26 @param Device PCI device NO.
27 @param Func PCI Func NO.
28
29 @retval EFI_NOT_FOUND PCI device not present.
30 @retval EFI_SUCCESS PCI device is found.
31
32 **/
33 EFI_STATUS
34 PciDevicePresent (
35 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
36 OUT PCI_TYPE00 *Pci,
37 IN UINT8 Bus,
38 IN UINT8 Device,
39 IN UINT8 Func
40 )
41 {
42 UINT64 Address;
43 EFI_STATUS Status;
44
45 //
46 // Create PCI address map in terms of Bus, Device and Func
47 //
48 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
49
50 //
51 // Read the Vendor ID register
52 //
53 Status = PciRootBridgeIo->Pci.Read (
54 PciRootBridgeIo,
55 EfiPciWidthUint32,
56 Address,
57 1,
58 Pci
59 );
60
61 if (!EFI_ERROR (Status) && ((Pci->Hdr).VendorId != 0xffff)) {
62 //
63 // Read the entire config header for the device
64 //
65 Status = PciRootBridgeIo->Pci.Read (
66 PciRootBridgeIo,
67 EfiPciWidthUint32,
68 Address,
69 sizeof (PCI_TYPE00) / sizeof (UINT32),
70 Pci
71 );
72
73 return EFI_SUCCESS;
74 }
75
76 return EFI_NOT_FOUND;
77 }
78
79 /**
80 Collect all the resource information under this root bridge.
81
82 A database that records all the information about pci device subject to this
83 root bridge will then be created.
84
85 @param Bridge Parent bridge instance.
86 @param StartBusNumber Bus number of beginning.
87
88 @retval EFI_SUCCESS PCI device is found.
89 @retval other Some error occurred when reading PCI bridge information.
90
91 **/
92 EFI_STATUS
93 PciPciDeviceInfoCollector (
94 IN PCI_IO_DEVICE *Bridge,
95 IN UINT8 StartBusNumber
96 )
97 {
98 EFI_STATUS Status;
99 PCI_TYPE00 Pci;
100 UINT8 Device;
101 UINT8 Func;
102 UINT8 SecBus;
103 PCI_IO_DEVICE *PciIoDevice;
104 EFI_PCI_IO_PROTOCOL *PciIo;
105
106 Status = EFI_SUCCESS;
107 SecBus = 0;
108
109 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
110 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
111 //
112 // Check to see whether PCI device is present
113 //
114 Status = PciDevicePresent (
115 Bridge->PciRootBridgeIo,
116 &Pci,
117 (UINT8)StartBusNumber,
118 (UINT8)Device,
119 (UINT8)Func
120 );
121
122 if (EFI_ERROR (Status) && (Func == 0)) {
123 //
124 // go to next device if there is no Function 0
125 //
126 break;
127 }
128
129 if (!EFI_ERROR (Status)) {
130 //
131 // Call back to host bridge function
132 //
133 PreprocessController (Bridge, (UINT8)StartBusNumber, Device, Func, EfiPciBeforeResourceCollection);
134
135 //
136 // Collect all the information about the PCI device discovered
137 //
138 Status = PciSearchDevice (
139 Bridge,
140 &Pci,
141 (UINT8)StartBusNumber,
142 Device,
143 Func,
144 &PciIoDevice
145 );
146
147 //
148 // Recursively scan PCI busses on the other side of PCI-PCI bridges
149 //
150 //
151 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {
152 //
153 // If it is PPB, we need to get the secondary bus to continue the enumeration
154 //
155 PciIo = &(PciIoDevice->PciIo);
156
157 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus);
158
159 if (EFI_ERROR (Status)) {
160 return Status;
161 }
162
163 //
164 // Ensure secondary bus number is greater than the primary bus number to avoid
165 // any potential dead loop when PcdPciDisableBusEnumeration is set to TRUE
166 //
167 if (SecBus <= StartBusNumber) {
168 break;
169 }
170
171 //
172 // Get resource padding for PPB
173 //
174 GetResourcePaddingPpb (PciIoDevice);
175
176 //
177 // Deep enumerate the next level bus
178 //
179 Status = PciPciDeviceInfoCollector (
180 PciIoDevice,
181 (UINT8)(SecBus)
182 );
183 }
184
185 if ((Func == 0) && !IS_PCI_MULTI_FUNC (&Pci)) {
186 //
187 // Skip sub functions, this is not a multi function device
188 //
189 Func = PCI_MAX_FUNC;
190 }
191 }
192 }
193 }
194
195 return EFI_SUCCESS;
196 }
197
198 /**
199 Search required device and create PCI device instance.
200
201 @param Bridge Parent bridge instance.
202 @param Pci Input PCI device information block.
203 @param Bus PCI bus NO.
204 @param Device PCI device NO.
205 @param Func PCI func NO.
206 @param PciDevice Output of searched PCI device instance.
207
208 @retval EFI_SUCCESS Successfully created PCI device instance.
209 @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.
210
211 **/
212 EFI_STATUS
213 PciSearchDevice (
214 IN PCI_IO_DEVICE *Bridge,
215 IN PCI_TYPE00 *Pci,
216 IN UINT8 Bus,
217 IN UINT8 Device,
218 IN UINT8 Func,
219 OUT PCI_IO_DEVICE **PciDevice
220 )
221 {
222 PCI_IO_DEVICE *PciIoDevice;
223
224 PciIoDevice = NULL;
225
226 DEBUG ((
227 DEBUG_INFO,
228 "PciBus: Discovered %s @ [%02x|%02x|%02x]\n",
229 IS_PCI_BRIDGE (Pci) ? L"PPB" :
230 IS_CARDBUS_BRIDGE (Pci) ? L"P2C" :
231 L"PCI",
232 Bus,
233 Device,
234 Func
235 ));
236
237 if (!IS_PCI_BRIDGE (Pci)) {
238 if (IS_CARDBUS_BRIDGE (Pci)) {
239 PciIoDevice = GatherP2CInfo (
240 Bridge,
241 Pci,
242 Bus,
243 Device,
244 Func
245 );
246 if ((PciIoDevice != NULL) && gFullEnumeration) {
247 InitializeP2C (PciIoDevice);
248 }
249 } else {
250 //
251 // Create private data for Pci Device
252 //
253 PciIoDevice = GatherDeviceInfo (
254 Bridge,
255 Pci,
256 Bus,
257 Device,
258 Func
259 );
260 }
261 } else {
262 //
263 // Create private data for PPB
264 //
265 PciIoDevice = GatherPpbInfo (
266 Bridge,
267 Pci,
268 Bus,
269 Device,
270 Func
271 );
272
273 //
274 // Special initialization for PPB including making the PPB quiet
275 //
276 if ((PciIoDevice != NULL) && gFullEnumeration) {
277 InitializePpb (PciIoDevice);
278 }
279 }
280
281 if (PciIoDevice == NULL) {
282 return EFI_OUT_OF_RESOURCES;
283 }
284
285 //
286 // Update the bar information for this PCI device so as to support some specific device
287 //
288 UpdatePciInfo (PciIoDevice);
289
290 if (PciIoDevice->DevicePath == NULL) {
291 return EFI_OUT_OF_RESOURCES;
292 }
293
294 //
295 // Detect this function has option rom
296 //
297 if (gFullEnumeration) {
298 if (!IS_CARDBUS_BRIDGE (Pci)) {
299 GetOpRomInfo (PciIoDevice);
300 }
301
302 ResetPowerManagementFeature (PciIoDevice);
303 }
304
305 //
306 // Insert it into a global tree for future reference
307 //
308 InsertPciDevice (Bridge, PciIoDevice);
309
310 //
311 // Determine PCI device attributes
312 //
313
314 if (PciDevice != NULL) {
315 *PciDevice = PciIoDevice;
316 }
317
318 return EFI_SUCCESS;
319 }
320
321 /**
322 Dump the PPB padding resource information.
323
324 @param PciIoDevice PCI IO instance.
325 @param ResourceType The desired resource type to dump.
326 PciBarTypeUnknown means to dump all types of resources.
327 **/
328 VOID
329 DumpPpbPaddingResource (
330 IN PCI_IO_DEVICE *PciIoDevice,
331 IN PCI_BAR_TYPE ResourceType
332 )
333 {
334 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
335 PCI_BAR_TYPE Type;
336
337 if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
338 return;
339 }
340
341 if ((ResourceType == PciBarTypeIo16) || (ResourceType == PciBarTypeIo32)) {
342 ResourceType = PciBarTypeIo;
343 }
344
345 for (Descriptor = PciIoDevice->ResourcePaddingDescriptors; Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR; Descriptor++) {
346 Type = PciBarTypeUnknown;
347 if ((Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) && (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO)) {
348 Type = PciBarTypeIo;
349 } else if ((Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) && (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM)) {
350 if (Descriptor->AddrSpaceGranularity == 32) {
351 //
352 // prefetchable
353 //
354 if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) {
355 Type = PciBarTypePMem32;
356 }
357
358 //
359 // Non-prefetchable
360 //
361 if (Descriptor->SpecificFlag == 0) {
362 Type = PciBarTypeMem32;
363 }
364 }
365
366 if (Descriptor->AddrSpaceGranularity == 64) {
367 //
368 // prefetchable
369 //
370 if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) {
371 Type = PciBarTypePMem64;
372 }
373
374 //
375 // Non-prefetchable
376 //
377 if (Descriptor->SpecificFlag == 0) {
378 Type = PciBarTypeMem64;
379 }
380 }
381 }
382
383 if ((Type != PciBarTypeUnknown) && ((ResourceType == PciBarTypeUnknown) || (ResourceType == Type))) {
384 DEBUG ((
385 DEBUG_INFO,
386 " Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n",
387 mBarTypeStr[Type],
388 Descriptor->AddrRangeMax,
389 Descriptor->AddrLen
390 ));
391 }
392 }
393 }
394
395 /**
396 Dump the PCI BAR information.
397
398 @param PciIoDevice PCI IO instance.
399 **/
400 VOID
401 DumpPciBars (
402 IN PCI_IO_DEVICE *PciIoDevice
403 )
404 {
405 UINTN Index;
406
407 for (Index = 0; Index < PCI_MAX_BAR; Index++) {
408 if (PciIoDevice->PciBar[Index].BarType == PciBarTypeUnknown) {
409 continue;
410 }
411
412 DEBUG ((
413 DEBUG_INFO,
414 " BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",
415 Index,
416 mBarTypeStr[MIN (PciIoDevice->PciBar[Index].BarType, PciBarTypeMaxType)],
417 PciIoDevice->PciBar[Index].Alignment,
418 PciIoDevice->PciBar[Index].Length,
419 PciIoDevice->PciBar[Index].Offset
420 ));
421 }
422
423 for (Index = 0; Index < PCI_MAX_BAR; Index++) {
424 if ((PciIoDevice->VfPciBar[Index].BarType == PciBarTypeUnknown) && (PciIoDevice->VfPciBar[Index].Length == 0)) {
425 continue;
426 }
427
428 DEBUG ((
429 DEBUG_INFO,
430 " VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n",
431 Index,
432 mBarTypeStr[MIN (PciIoDevice->VfPciBar[Index].BarType, PciBarTypeMaxType)],
433 PciIoDevice->VfPciBar[Index].Alignment,
434 PciIoDevice->VfPciBar[Index].Length,
435 PciIoDevice->VfPciBar[Index].Offset
436 ));
437 }
438
439 DEBUG ((DEBUG_INFO, "\n"));
440 }
441
442 /**
443 Create PCI device instance for PCI device.
444
445 @param Bridge Parent bridge instance.
446 @param Pci Input PCI device information block.
447 @param Bus PCI device Bus NO.
448 @param Device PCI device Device NO.
449 @param Func PCI device's func NO.
450
451 @return Created PCI device instance.
452
453 **/
454 PCI_IO_DEVICE *
455 GatherDeviceInfo (
456 IN PCI_IO_DEVICE *Bridge,
457 IN PCI_TYPE00 *Pci,
458 IN UINT8 Bus,
459 IN UINT8 Device,
460 IN UINT8 Func
461 )
462 {
463 UINTN Offset;
464 UINTN BarIndex;
465 PCI_IO_DEVICE *PciIoDevice;
466
467 PciIoDevice = CreatePciIoDevice (
468 Bridge,
469 Pci,
470 Bus,
471 Device,
472 Func
473 );
474
475 if (PciIoDevice == NULL) {
476 return NULL;
477 }
478
479 //
480 // If it is a full enumeration, disconnect the device in advance
481 //
482 if (gFullEnumeration) {
483 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
484 }
485
486 //
487 // Start to parse the bars
488 //
489 for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {
490 Offset = PciParseBar (PciIoDevice, Offset, BarIndex);
491 }
492
493 //
494 // Parse the SR-IOV VF bars
495 //
496 if (PcdGetBool (PcdSrIovSupport) && (PciIoDevice->SrIovCapabilityOffset != 0)) {
497 for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0;
498 Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5;
499 BarIndex++)
500 {
501 ASSERT (BarIndex < PCI_MAX_BAR);
502 Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex);
503 }
504 }
505
506 DEBUG_CODE (
507 DumpPciBars (PciIoDevice);
508 );
509 return PciIoDevice;
510 }
511
512 /**
513 Create PCI device instance for PCI-PCI bridge.
514
515 @param Bridge Parent bridge instance.
516 @param Pci Input PCI device information block.
517 @param Bus PCI device Bus NO.
518 @param Device PCI device Device NO.
519 @param Func PCI device's func NO.
520
521 @return Created PCI device instance.
522
523 **/
524 PCI_IO_DEVICE *
525 GatherPpbInfo (
526 IN PCI_IO_DEVICE *Bridge,
527 IN PCI_TYPE00 *Pci,
528 IN UINT8 Bus,
529 IN UINT8 Device,
530 IN UINT8 Func
531 )
532 {
533 PCI_IO_DEVICE *PciIoDevice;
534 EFI_STATUS Status;
535 UINT8 Value;
536 EFI_PCI_IO_PROTOCOL *PciIo;
537 UINT8 Temp;
538 UINT32 PMemBaseLimit;
539 UINT16 PrefetchableMemoryBase;
540 UINT16 PrefetchableMemoryLimit;
541
542 PciIoDevice = CreatePciIoDevice (
543 Bridge,
544 Pci,
545 Bus,
546 Device,
547 Func
548 );
549
550 if (PciIoDevice == NULL) {
551 return NULL;
552 }
553
554 if (gFullEnumeration) {
555 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
556
557 //
558 // Initialize the bridge control register
559 //
560 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);
561 }
562
563 //
564 // PPB can have two BARs
565 //
566 if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {
567 //
568 // Not 64-bit bar
569 //
570 PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);
571 }
572
573 PciIo = &PciIoDevice->PciIo;
574
575 //
576 // Test whether it support 32 decode or not
577 //
578 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
579 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
580 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
581 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
582
583 if (Value != 0) {
584 if ((Value & 0x01) != 0) {
585 PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;
586 } else {
587 PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
588 }
589 }
590
591 //
592 // if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes
593 // PCI bridge supporting non-standard I/O window alignment less than 4K.
594 //
595
596 PciIoDevice->BridgeIoAlignment = 0xFFF;
597 if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe)) {
598 //
599 // Check any bits of bit 3-1 of I/O Base Register are writable.
600 // if so, it is assumed non-standard I/O window alignment is supported by this bridge.
601 // Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content can't be assumed.
602 //
603 Value = (UINT8)(Temp ^ (BIT3 | BIT2 | BIT1));
604 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
605 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
606 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
607 Value = (UINT8)((Value ^ Temp) & (BIT3 | BIT2 | BIT1));
608 switch (Value) {
609 case BIT3:
610 PciIoDevice->BridgeIoAlignment = 0x7FF;
611 break;
612 case BIT3 | BIT2:
613 PciIoDevice->BridgeIoAlignment = 0x3FF;
614 break;
615 case BIT3 | BIT2 | BIT1:
616 PciIoDevice->BridgeIoAlignment = 0x1FF;
617 break;
618 }
619 }
620
621 Status = BarExisted (
622 PciIoDevice,
623 0x24,
624 NULL,
625 &PMemBaseLimit
626 );
627
628 //
629 // Test if it supports 64 memory or not
630 //
631 // The bottom 4 bits of both the Prefetchable Memory Base and Prefetchable Memory Limit
632 // registers:
633 // 0 - the bridge supports only 32 bit addresses.
634 // 1 - the bridge supports 64-bit addresses.
635 //
636 PrefetchableMemoryBase = (UINT16)(PMemBaseLimit & 0xffff);
637 PrefetchableMemoryLimit = (UINT16)(PMemBaseLimit >> 16);
638 if (!EFI_ERROR (Status) &&
639 ((PrefetchableMemoryBase & 0x000f) == 0x0001) &&
640 ((PrefetchableMemoryLimit & 0x000f) == 0x0001))
641 {
642 Status = BarExisted (
643 PciIoDevice,
644 0x28,
645 NULL,
646 NULL
647 );
648
649 if (!EFI_ERROR (Status)) {
650 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
651 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
652 } else {
653 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
654 }
655 }
656
657 //
658 // Memory 32 code is required for ppb
659 //
660 PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;
661
662 GetResourcePaddingPpb (PciIoDevice);
663
664 DEBUG_CODE (
665 DumpPpbPaddingResource (PciIoDevice, PciBarTypeUnknown);
666 DumpPciBars (PciIoDevice);
667 );
668
669 return PciIoDevice;
670 }
671
672 /**
673 Create PCI device instance for PCI Card bridge device.
674
675 @param Bridge Parent bridge instance.
676 @param Pci Input PCI device information block.
677 @param Bus PCI device Bus NO.
678 @param Device PCI device Device NO.
679 @param Func PCI device's func NO.
680
681 @return Created PCI device instance.
682
683 **/
684 PCI_IO_DEVICE *
685 GatherP2CInfo (
686 IN PCI_IO_DEVICE *Bridge,
687 IN PCI_TYPE00 *Pci,
688 IN UINT8 Bus,
689 IN UINT8 Device,
690 IN UINT8 Func
691 )
692 {
693 PCI_IO_DEVICE *PciIoDevice;
694
695 PciIoDevice = CreatePciIoDevice (
696 Bridge,
697 Pci,
698 Bus,
699 Device,
700 Func
701 );
702
703 if (PciIoDevice == NULL) {
704 return NULL;
705 }
706
707 if (gFullEnumeration) {
708 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
709
710 //
711 // Initialize the bridge control register
712 //
713 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);
714 }
715
716 //
717 // P2C only has one bar that is in 0x10
718 //
719 PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);
720
721 //
722 // Read PciBar information from the bar register
723 //
724 GetBackPcCardBar (PciIoDevice);
725 PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED |
726 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |
727 EFI_BRIDGE_IO32_DECODE_SUPPORTED;
728
729 DEBUG_CODE (
730 DumpPciBars (PciIoDevice);
731 );
732
733 return PciIoDevice;
734 }
735
736 /**
737 Create device path for pci device.
738
739 @param ParentDevicePath Parent bridge's path.
740 @param PciIoDevice Pci device instance.
741
742 @return Device path protocol instance for specific pci device.
743
744 **/
745 EFI_DEVICE_PATH_PROTOCOL *
746 CreatePciDevicePath (
747 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
748 IN PCI_IO_DEVICE *PciIoDevice
749 )
750 {
751 PCI_DEVICE_PATH PciNode;
752
753 //
754 // Create PCI device path
755 //
756 PciNode.Header.Type = HARDWARE_DEVICE_PATH;
757 PciNode.Header.SubType = HW_PCI_DP;
758 SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));
759
760 PciNode.Device = PciIoDevice->DeviceNumber;
761 PciNode.Function = PciIoDevice->FunctionNumber;
762 PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);
763
764 return PciIoDevice->DevicePath;
765 }
766
767 /**
768 Check whether the PCI IOV VF bar is existed or not.
769
770 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
771 @param Offset The offset.
772 @param BarLengthValue The bar length value returned.
773 @param OriginalBarValue The original bar value returned.
774
775 @retval EFI_NOT_FOUND The bar doesn't exist.
776 @retval EFI_SUCCESS The bar exist.
777
778 **/
779 EFI_STATUS
780 VfBarExisted (
781 IN PCI_IO_DEVICE *PciIoDevice,
782 IN UINTN Offset,
783 OUT UINT32 *BarLengthValue,
784 OUT UINT32 *OriginalBarValue
785 )
786 {
787 EFI_PCI_IO_PROTOCOL *PciIo;
788 UINT32 OriginalValue;
789 UINT32 Value;
790 EFI_TPL OldTpl;
791
792 //
793 // Ensure it is called properly
794 //
795 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
796 if (PciIoDevice->SrIovCapabilityOffset == 0) {
797 return EFI_NOT_FOUND;
798 }
799
800 PciIo = &PciIoDevice->PciIo;
801
802 //
803 // Preserve the original value
804 //
805
806 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);
807
808 //
809 // Raise TPL to high level to disable timer interrupt while the BAR is probed
810 //
811 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
812
813 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne);
814 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value);
815
816 //
817 // Write back the original value
818 //
819 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);
820
821 //
822 // Restore TPL to its original level
823 //
824 gBS->RestoreTPL (OldTpl);
825
826 if (BarLengthValue != NULL) {
827 *BarLengthValue = Value;
828 }
829
830 if (OriginalBarValue != NULL) {
831 *OriginalBarValue = OriginalValue;
832 }
833
834 if (Value == 0) {
835 return EFI_NOT_FOUND;
836 } else {
837 return EFI_SUCCESS;
838 }
839 }
840
841 /**
842 Check whether the bar is existed or not.
843
844 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
845 @param Offset The offset.
846 @param BarLengthValue The bar length value returned.
847 @param OriginalBarValue The original bar value returned.
848
849 @retval EFI_NOT_FOUND The bar doesn't exist.
850 @retval EFI_SUCCESS The bar exist.
851
852 **/
853 EFI_STATUS
854 BarExisted (
855 IN PCI_IO_DEVICE *PciIoDevice,
856 IN UINTN Offset,
857 OUT UINT32 *BarLengthValue,
858 OUT UINT32 *OriginalBarValue
859 )
860 {
861 EFI_PCI_IO_PROTOCOL *PciIo;
862 UINT32 OriginalValue;
863 UINT32 Value;
864 EFI_TPL OldTpl;
865
866 PciIo = &PciIoDevice->PciIo;
867
868 //
869 // Preserve the original value
870 //
871 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &OriginalValue);
872
873 //
874 // Raise TPL to high level to disable timer interrupt while the BAR is probed
875 //
876 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
877
878 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &gAllOne);
879 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &Value);
880
881 //
882 // Write back the original value
883 //
884 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &OriginalValue);
885
886 //
887 // Restore TPL to its original level
888 //
889 gBS->RestoreTPL (OldTpl);
890
891 if (BarLengthValue != NULL) {
892 *BarLengthValue = Value;
893 }
894
895 if (OriginalBarValue != NULL) {
896 *OriginalBarValue = OriginalValue;
897 }
898
899 if (Value == 0) {
900 return EFI_NOT_FOUND;
901 } else {
902 return EFI_SUCCESS;
903 }
904 }
905
906 /**
907 Test whether the device can support given attributes.
908
909 @param PciIoDevice Pci device instance.
910 @param Command Input command register value, and
911 returned supported register value.
912 @param BridgeControl Input bridge control value for PPB or P2C, and
913 returned supported bridge control value.
914 @param OldCommand Returned and stored old command register offset.
915 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
916
917 **/
918 VOID
919 PciTestSupportedAttribute (
920 IN PCI_IO_DEVICE *PciIoDevice,
921 IN OUT UINT16 *Command,
922 IN OUT UINT16 *BridgeControl,
923 OUT UINT16 *OldCommand,
924 OUT UINT16 *OldBridgeControl
925 )
926 {
927 EFI_TPL OldTpl;
928 UINT16 CommandValue;
929
930 //
931 // Preserve the original value
932 //
933 PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);
934
935 //
936 // Raise TPL to high level to disable timer interrupt while the BAR is probed
937 //
938 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
939 CommandValue = *Command | *OldCommand;
940
941 PCI_SET_COMMAND_REGISTER (PciIoDevice, CommandValue);
942 PCI_READ_COMMAND_REGISTER (PciIoDevice, &CommandValue);
943
944 *Command = *Command & CommandValue;
945 //
946 // Write back the original value
947 //
948 PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);
949
950 //
951 // Restore TPL to its original level
952 //
953 gBS->RestoreTPL (OldTpl);
954
955 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
956 //
957 // Preserve the original value
958 //
959 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);
960
961 //
962 // Raise TPL to high level to disable timer interrupt while the BAR is probed
963 //
964 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
965
966 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);
967 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
968
969 //
970 // Write back the original value
971 //
972 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);
973
974 //
975 // Restore TPL to its original level
976 //
977 gBS->RestoreTPL (OldTpl);
978 } else {
979 *OldBridgeControl = 0;
980 *BridgeControl = 0;
981 }
982 }
983
984 /**
985 Set the supported or current attributes of a PCI device.
986
987 @param PciIoDevice Structure pointer for PCI device.
988 @param Command Command register value.
989 @param BridgeControl Bridge control value for PPB or P2C.
990 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
991
992 **/
993 VOID
994 PciSetDeviceAttribute (
995 IN PCI_IO_DEVICE *PciIoDevice,
996 IN UINT16 Command,
997 IN UINT16 BridgeControl,
998 IN UINTN Option
999 )
1000 {
1001 UINT64 Attributes;
1002
1003 Attributes = 0;
1004
1005 if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {
1006 Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;
1007 }
1008
1009 if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {
1010 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;
1011 }
1012
1013 if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {
1014 Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;
1015 }
1016
1017 if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
1018 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
1019 }
1020
1021 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {
1022 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
1023 }
1024
1025 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {
1026 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
1027 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
1028 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
1029 }
1030
1031 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {
1032 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;
1033 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;
1034 }
1035
1036 if (Option == EFI_SET_SUPPORTS) {
1037 Attributes |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |
1038 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |
1039 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |
1040 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
1041 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
1042 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
1043
1044 if (IS_PCI_LPC (&PciIoDevice->Pci)) {
1045 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
1046 Attributes |= (mReserveIsaAliases ? (UINT64)EFI_PCI_IO_ATTRIBUTE_ISA_IO : \
1047 (UINT64)EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);
1048 }
1049
1050 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
1051 //
1052 // For bridge, it should support IDE attributes
1053 //
1054 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
1055 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
1056
1057 if (mReserveVgaAliases) {
1058 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \
1059 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16);
1060 } else {
1061 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | \
1062 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);
1063 }
1064 } else {
1065 if (IS_PCI_IDE (&PciIoDevice->Pci)) {
1066 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
1067 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
1068 }
1069
1070 if (IS_PCI_VGA (&PciIoDevice->Pci)) {
1071 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
1072 Attributes |= (mReserveVgaAliases ? (UINT64)EFI_PCI_IO_ATTRIBUTE_VGA_IO : \
1073 (UINT64)EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
1074 }
1075 }
1076
1077 PciIoDevice->Supports = Attributes;
1078 PciIoDevice->Supports &= ((PciIoDevice->Parent->Supports) | \
1079 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \
1080 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER);
1081 } else {
1082 //
1083 // When this attribute is clear, the RomImage and RomSize fields in the PCI IO were
1084 // initialized based on the PCI option ROM found through the ROM BAR of the PCI controller.
1085 // When this attribute is set, the PCI option ROM described by the RomImage and RomSize
1086 // fields is not from the the ROM BAR of the PCI controller.
1087 //
1088 if (!PciIoDevice->EmbeddedRom) {
1089 Attributes |= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM;
1090 }
1091
1092 PciIoDevice->Attributes = Attributes;
1093 }
1094 }
1095
1096 /**
1097 Determine if the device can support Fast Back to Back attribute.
1098
1099 @param PciIoDevice Pci device instance.
1100 @param StatusIndex Status register value.
1101
1102 @retval EFI_SUCCESS This device support Fast Back to Back attribute.
1103 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
1104
1105 **/
1106 EFI_STATUS
1107 GetFastBackToBackSupport (
1108 IN PCI_IO_DEVICE *PciIoDevice,
1109 IN UINT8 StatusIndex
1110 )
1111 {
1112 EFI_PCI_IO_PROTOCOL *PciIo;
1113 EFI_STATUS Status;
1114 UINT32 StatusRegister;
1115
1116 //
1117 // Read the status register
1118 //
1119 PciIo = &PciIoDevice->PciIo;
1120 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);
1121 if (EFI_ERROR (Status)) {
1122 return EFI_UNSUPPORTED;
1123 }
1124
1125 //
1126 // Check the Fast B2B bit
1127 //
1128 if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {
1129 return EFI_SUCCESS;
1130 } else {
1131 return EFI_UNSUPPORTED;
1132 }
1133 }
1134
1135 /**
1136 Process the option ROM for all the children of the specified parent PCI device.
1137 It can only be used after the first full Option ROM process.
1138
1139 @param PciIoDevice Pci device instance.
1140
1141 **/
1142 VOID
1143 ProcessOptionRomLight (
1144 IN PCI_IO_DEVICE *PciIoDevice
1145 )
1146 {
1147 PCI_IO_DEVICE *Temp;
1148 LIST_ENTRY *CurrentLink;
1149
1150 //
1151 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1152 //
1153 CurrentLink = PciIoDevice->ChildList.ForwardLink;
1154 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
1155 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1156
1157 if (!IsListEmpty (&Temp->ChildList)) {
1158 ProcessOptionRomLight (Temp);
1159 }
1160
1161 Temp->AllOpRomProcessed = PciRomGetImageMapping (Temp);
1162
1163 CurrentLink = CurrentLink->ForwardLink;
1164 }
1165 }
1166
1167 /**
1168 Determine the related attributes of all devices under a Root Bridge.
1169
1170 @param PciIoDevice PCI device instance.
1171
1172 **/
1173 EFI_STATUS
1174 DetermineDeviceAttribute (
1175 IN PCI_IO_DEVICE *PciIoDevice
1176 )
1177 {
1178 UINT16 Command;
1179 UINT16 BridgeControl;
1180 UINT16 OldCommand;
1181 UINT16 OldBridgeControl;
1182 BOOLEAN FastB2BSupport;
1183 PCI_IO_DEVICE *Temp;
1184 LIST_ENTRY *CurrentLink;
1185 EFI_STATUS Status;
1186
1187 //
1188 // For Root Bridge, just copy it by RootBridgeIo protocol
1189 // so as to keep consistent with the actual attribute
1190 //
1191 if (PciIoDevice->Parent == NULL) {
1192 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
1193 PciIoDevice->PciRootBridgeIo,
1194 &PciIoDevice->Supports,
1195 &PciIoDevice->Attributes
1196 );
1197 if (EFI_ERROR (Status)) {
1198 return Status;
1199 }
1200
1201 //
1202 // Assume the PCI Root Bridge supports DAC
1203 //
1204 PciIoDevice->Supports |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
1205 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
1206 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
1207 } else {
1208 //
1209 // Set the attributes to be checked for common PCI devices and PPB or P2C
1210 // Since some devices only support part of them, it is better to set the
1211 // attribute according to its command or bridge control register
1212 //
1213 Command = EFI_PCI_COMMAND_IO_SPACE |
1214 EFI_PCI_COMMAND_MEMORY_SPACE |
1215 EFI_PCI_COMMAND_BUS_MASTER |
1216 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1217
1218 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;
1219
1220 //
1221 // Test whether the device can support attributes above
1222 //
1223 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);
1224
1225 //
1226 // Set the supported attributes for specified PCI device
1227 //
1228 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);
1229
1230 //
1231 // Set the current attributes for specified PCI device
1232 //
1233 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);
1234
1235 //
1236 // Enable other PCI supported attributes but not defined in PCI_IO_PROTOCOL
1237 // For PCI Express devices, Memory Write and Invalidate is hardwired to 0b so only enable it for PCI devices.
1238 if (!PciIoDevice->IsPciExp) {
1239 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);
1240 }
1241 }
1242
1243 FastB2BSupport = TRUE;
1244
1245 //
1246 // P2C can not support FB2B on the secondary side
1247 //
1248 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
1249 FastB2BSupport = FALSE;
1250 }
1251
1252 //
1253 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1254 //
1255 CurrentLink = PciIoDevice->ChildList.ForwardLink;
1256 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
1257 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1258 Status = DetermineDeviceAttribute (Temp);
1259 if (EFI_ERROR (Status)) {
1260 return Status;
1261 }
1262
1263 //
1264 // Detect Fast Back to Back support for the device under the bridge
1265 //
1266 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);
1267 if (FastB2BSupport && EFI_ERROR (Status)) {
1268 FastB2BSupport = FALSE;
1269 }
1270
1271 CurrentLink = CurrentLink->ForwardLink;
1272 }
1273
1274 //
1275 // Set or clear Fast Back to Back bit for the whole bridge
1276 //
1277 if (!IsListEmpty (&PciIoDevice->ChildList)) {
1278 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
1279 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);
1280
1281 if (EFI_ERROR (Status) || (!FastB2BSupport)) {
1282 FastB2BSupport = FALSE;
1283 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
1284 } else {
1285 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
1286 }
1287 }
1288
1289 CurrentLink = PciIoDevice->ChildList.ForwardLink;
1290 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
1291 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1292 if (FastB2BSupport) {
1293 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
1294 } else {
1295 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
1296 }
1297
1298 CurrentLink = CurrentLink->ForwardLink;
1299 }
1300 }
1301
1302 //
1303 // End for IsListEmpty
1304 //
1305 return EFI_SUCCESS;
1306 }
1307
1308 /**
1309 This routine is used to update the bar information for those incompatible PCI device.
1310
1311 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
1312 Bar information.
1313
1314 @retval EFI_SUCCESS Successfully updated bar information.
1315 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
1316
1317 **/
1318 EFI_STATUS
1319 UpdatePciInfo (
1320 IN OUT PCI_IO_DEVICE *PciIoDevice
1321 )
1322 {
1323 EFI_STATUS Status;
1324 UINTN BarIndex;
1325 BOOLEAN SetFlag;
1326 VOID *Configuration;
1327 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
1328
1329 Configuration = NULL;
1330 Status = EFI_SUCCESS;
1331
1332 if (gIncompatiblePciDeviceSupport == NULL) {
1333 //
1334 // It can only be supported after the Incompatible PCI Device
1335 // Support Protocol has been installed
1336 //
1337 Status = gBS->LocateProtocol (
1338 &gEfiIncompatiblePciDeviceSupportProtocolGuid,
1339 NULL,
1340 (VOID **)&gIncompatiblePciDeviceSupport
1341 );
1342 }
1343
1344 if (Status == EFI_SUCCESS) {
1345 //
1346 // Check whether the device belongs to incompatible devices from protocol or not
1347 // If it is , then get its special requirement in the ACPI table
1348 //
1349 Status = gIncompatiblePciDeviceSupport->CheckDevice (
1350 gIncompatiblePciDeviceSupport,
1351 PciIoDevice->Pci.Hdr.VendorId,
1352 PciIoDevice->Pci.Hdr.DeviceId,
1353 PciIoDevice->Pci.Hdr.RevisionID,
1354 PciIoDevice->Pci.Device.SubsystemVendorID,
1355 PciIoDevice->Pci.Device.SubsystemID,
1356 &Configuration
1357 );
1358 }
1359
1360 if (EFI_ERROR (Status) || (Configuration == NULL)) {
1361 return EFI_UNSUPPORTED;
1362 }
1363
1364 //
1365 // Update PCI device information from the ACPI table
1366 //
1367 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration;
1368
1369 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {
1370 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
1371 //
1372 // The format is not support
1373 //
1374 break;
1375 }
1376
1377 for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
1378 if ((Ptr->AddrTranslationOffset != MAX_UINT64) &&
1379 (Ptr->AddrTranslationOffset != MAX_UINT8) &&
1380 (Ptr->AddrTranslationOffset != BarIndex)
1381 )
1382 {
1383 //
1384 // Skip updating when AddrTranslationOffset is not MAX_UINT64 or MAX_UINT8 (wide match).
1385 // Skip updating when current BarIndex doesn't equal to AddrTranslationOffset.
1386 // Comparing against MAX_UINT8 is to keep backward compatibility.
1387 //
1388 continue;
1389 }
1390
1391 SetFlag = FALSE;
1392 switch (Ptr->ResType) {
1393 case ACPI_ADDRESS_SPACE_TYPE_MEM:
1394
1395 //
1396 // Make sure the bar is memory type
1397 //
1398 if (CheckBarType (PciIoDevice, (UINT8)BarIndex, PciBarTypeMem)) {
1399 SetFlag = TRUE;
1400
1401 //
1402 // Ignored if granularity is 0.
1403 // Ignored if PCI BAR is I/O or 32-bit memory.
1404 // If PCI BAR is 64-bit memory and granularity is 32, then
1405 // the PCI BAR resource is allocated below 4GB.
1406 // If PCI BAR is 64-bit memory and granularity is 64, then
1407 // the PCI BAR resource is allocated above 4GB.
1408 //
1409 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeMem64) {
1410 switch (Ptr->AddrSpaceGranularity) {
1411 case 32:
1412 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
1413 case 64:
1414 PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;
1415 break;
1416 default:
1417 break;
1418 }
1419 }
1420
1421 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypePMem64) {
1422 switch (Ptr->AddrSpaceGranularity) {
1423 case 32:
1424 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
1425 case 64:
1426 PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;
1427 break;
1428 default:
1429 break;
1430 }
1431 }
1432 }
1433
1434 break;
1435
1436 case ACPI_ADDRESS_SPACE_TYPE_IO:
1437
1438 //
1439 // Make sure the bar is IO type
1440 //
1441 if (CheckBarType (PciIoDevice, (UINT8)BarIndex, PciBarTypeIo)) {
1442 SetFlag = TRUE;
1443 }
1444
1445 break;
1446 }
1447
1448 if (SetFlag) {
1449 //
1450 // Update the new alignment for the device
1451 //
1452 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);
1453
1454 //
1455 // Update the new length for the device
1456 //
1457 if (Ptr->AddrLen != 0) {
1458 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;
1459 }
1460 }
1461 }
1462
1463 Ptr++;
1464 }
1465
1466 FreePool (Configuration);
1467
1468 return EFI_SUCCESS;
1469 }
1470
1471 /**
1472 This routine will update the alignment with the new alignment.
1473 Compare with OLD_ALIGN/EVEN_ALIGN/SQUAD_ALIGN/DQUAD_ALIGN is to keep
1474 backward compatibility.
1475
1476 @param Alignment Input Old alignment. Output updated alignment.
1477 @param NewAlignment New alignment.
1478
1479 **/
1480 VOID
1481 SetNewAlign (
1482 IN OUT UINT64 *Alignment,
1483 IN UINT64 NewAlignment
1484 )
1485 {
1486 UINT64 OldAlignment;
1487 UINTN ShiftBit;
1488
1489 //
1490 // The new alignment is the same as the original,
1491 // so skip it
1492 //
1493 if ((NewAlignment == 0) || (NewAlignment == OLD_ALIGN)) {
1494 return;
1495 }
1496
1497 //
1498 // Check the validity of the parameter
1499 //
1500 if ((NewAlignment != EVEN_ALIGN) &&
1501 (NewAlignment != SQUAD_ALIGN) &&
1502 (NewAlignment != DQUAD_ALIGN))
1503 {
1504 *Alignment = NewAlignment;
1505 return;
1506 }
1507
1508 OldAlignment = (*Alignment) + 1;
1509 ShiftBit = 0;
1510
1511 //
1512 // Get the first non-zero hex value of the length
1513 //
1514 while ((OldAlignment & 0x0F) == 0x00) {
1515 OldAlignment = RShiftU64 (OldAlignment, 4);
1516 ShiftBit += 4;
1517 }
1518
1519 //
1520 // Adjust the alignment to even, quad or double quad boundary
1521 //
1522 if (NewAlignment == EVEN_ALIGN) {
1523 if ((OldAlignment & 0x01) != 0) {
1524 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);
1525 }
1526 } else if (NewAlignment == SQUAD_ALIGN) {
1527 if ((OldAlignment & 0x03) != 0) {
1528 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);
1529 }
1530 } else if (NewAlignment == DQUAD_ALIGN) {
1531 if ((OldAlignment & 0x07) != 0) {
1532 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);
1533 }
1534 }
1535
1536 //
1537 // Update the old value
1538 //
1539 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;
1540 *Alignment = NewAlignment;
1541
1542 return;
1543 }
1544
1545 /**
1546 Parse PCI IOV VF bar information and fill them into PCI device instance.
1547
1548 @param PciIoDevice Pci device instance.
1549 @param Offset Bar offset.
1550 @param BarIndex Bar index.
1551
1552 @return Next bar offset.
1553
1554 **/
1555 UINTN
1556 PciIovParseVfBar (
1557 IN PCI_IO_DEVICE *PciIoDevice,
1558 IN UINTN Offset,
1559 IN UINTN BarIndex
1560 )
1561 {
1562 UINT32 Value;
1563 UINT32 OriginalValue;
1564 UINT32 Mask;
1565 EFI_STATUS Status;
1566
1567 //
1568 // Ensure it is called properly
1569 //
1570 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
1571 if (PciIoDevice->SrIovCapabilityOffset == 0) {
1572 return 0;
1573 }
1574
1575 OriginalValue = 0;
1576 Value = 0;
1577
1578 Status = VfBarExisted (
1579 PciIoDevice,
1580 Offset,
1581 &Value,
1582 &OriginalValue
1583 );
1584
1585 if (EFI_ERROR (Status)) {
1586 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
1587 PciIoDevice->VfPciBar[BarIndex].Length = 0;
1588 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;
1589
1590 //
1591 // Scan all the BARs anyway
1592 //
1593 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16)Offset;
1594 return Offset + 4;
1595 }
1596
1597 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16)Offset;
1598 if ((Value & 0x01) != 0) {
1599 //
1600 // Device I/Os. Impossible
1601 //
1602 ASSERT (FALSE);
1603 return Offset + 4;
1604 } else {
1605 Mask = 0xfffffff0;
1606
1607 PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1608
1609 switch (Value & 0x07) {
1610 //
1611 // memory space; anywhere in 32 bit address space
1612 //
1613 case 0x00:
1614 if ((Value & 0x08) != 0) {
1615 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;
1616 } else {
1617 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;
1618 }
1619
1620 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1621 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
1622
1623 //
1624 // Adjust Length
1625 //
1626 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
1627 //
1628 // Adjust Alignment
1629 //
1630 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
1631 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
1632 }
1633
1634 break;
1635
1636 //
1637 // memory space; anywhere in 64 bit address space
1638 //
1639 case 0x04:
1640 if ((Value & 0x08) != 0) {
1641 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;
1642 } else {
1643 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;
1644 }
1645
1646 //
1647 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1648 // is regarded as an extension for the first bar. As a result
1649 // the sizing will be conducted on combined 64 bit value
1650 // Here just store the masked first 32bit value for future size
1651 // calculation
1652 //
1653 PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;
1654 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
1655
1656 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
1657 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
1658 }
1659
1660 //
1661 // Increment the offset to point to next DWORD
1662 //
1663 Offset += 4;
1664
1665 Status = VfBarExisted (
1666 PciIoDevice,
1667 Offset,
1668 &Value,
1669 &OriginalValue
1670 );
1671
1672 if (EFI_ERROR (Status)) {
1673 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
1674 return Offset + 4;
1675 }
1676
1677 //
1678 // Fix the length to support some special 64 bit BAR
1679 //
1680 Value |= ((UINT32)-1 << HighBitSet32 (Value));
1681
1682 //
1683 // Calculate the size of 64bit bar
1684 //
1685 PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64)OriginalValue, 32);
1686
1687 PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64)Value, 32);
1688 PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;
1689 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
1690
1691 //
1692 // Adjust Length
1693 //
1694 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
1695 //
1696 // Adjust Alignment
1697 //
1698 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
1699 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
1700 }
1701
1702 break;
1703
1704 //
1705 // reserved
1706 //
1707 default:
1708 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
1709 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1710 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
1711
1712 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
1713 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
1714 }
1715
1716 break;
1717 }
1718 }
1719
1720 //
1721 // Check the length again so as to keep compatible with some special bars
1722 //
1723 if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {
1724 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
1725 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
1726 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;
1727 }
1728
1729 //
1730 // Increment number of bar
1731 //
1732 return Offset + 4;
1733 }
1734
1735 /**
1736 Parse PCI bar information and fill them into PCI device instance.
1737
1738 @param PciIoDevice Pci device instance.
1739 @param Offset Bar offset.
1740 @param BarIndex Bar index.
1741
1742 @return Next bar offset.
1743
1744 **/
1745 UINTN
1746 PciParseBar (
1747 IN PCI_IO_DEVICE *PciIoDevice,
1748 IN UINTN Offset,
1749 IN UINTN BarIndex
1750 )
1751 {
1752 UINT32 Value;
1753 UINT32 OriginalValue;
1754 UINT32 Mask;
1755 EFI_STATUS Status;
1756
1757 OriginalValue = 0;
1758 Value = 0;
1759
1760 Status = BarExisted (
1761 PciIoDevice,
1762 Offset,
1763 &Value,
1764 &OriginalValue
1765 );
1766
1767 if (EFI_ERROR (Status)) {
1768 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1769 PciIoDevice->PciBar[BarIndex].Length = 0;
1770 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1771
1772 //
1773 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
1774 //
1775 PciIoDevice->PciBar[BarIndex].Offset = (UINT8)Offset;
1776 return Offset + 4;
1777 }
1778
1779 PciIoDevice->PciBar[BarIndex].BarTypeFixed = FALSE;
1780 PciIoDevice->PciBar[BarIndex].Offset = (UINT8)Offset;
1781 if ((Value & 0x01) != 0) {
1782 //
1783 // Device I/Os
1784 //
1785 Mask = 0xfffffffc;
1786
1787 if ((Value & 0xFFFF0000) != 0) {
1788 //
1789 // It is a IO32 bar
1790 //
1791 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;
1792 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);
1793 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1794 } else {
1795 //
1796 // It is a IO16 bar
1797 //
1798 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;
1799 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);
1800 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1801 }
1802
1803 //
1804 // Workaround. Some platforms implement IO bar with 0 length
1805 // Need to treat it as no-bar
1806 //
1807 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1808 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE)0;
1809 }
1810
1811 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1812 } else {
1813 Mask = 0xfffffff0;
1814
1815 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1816
1817 switch (Value & 0x07) {
1818 //
1819 // memory space; anywhere in 32 bit address space
1820 //
1821 case 0x00:
1822 if ((Value & 0x08) != 0) {
1823 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
1824 } else {
1825 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
1826 }
1827
1828 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1829 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
1830 //
1831 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1832 //
1833 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
1834 } else {
1835 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1836 }
1837
1838 break;
1839
1840 //
1841 // memory space; anywhere in 64 bit address space
1842 //
1843 case 0x04:
1844 if ((Value & 0x08) != 0) {
1845 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;
1846 } else {
1847 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;
1848 }
1849
1850 //
1851 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1852 // is regarded as an extension for the first bar. As a result
1853 // the sizing will be conducted on combined 64 bit value
1854 // Here just store the masked first 32bit value for future size
1855 // calculation
1856 //
1857 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;
1858 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1859
1860 //
1861 // Increment the offset to point to next DWORD
1862 //
1863 Offset += 4;
1864
1865 Status = BarExisted (
1866 PciIoDevice,
1867 Offset,
1868 &Value,
1869 &OriginalValue
1870 );
1871
1872 if (EFI_ERROR (Status)) {
1873 //
1874 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again
1875 //
1876 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1877 //
1878 // some device implement MMIO bar with 0 length, need to treat it as no-bar
1879 //
1880 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1881 return Offset + 4;
1882 }
1883 }
1884
1885 //
1886 // Fix the length to support some special 64 bit BAR
1887 //
1888 if (Value == 0) {
1889 DEBUG ((DEBUG_INFO, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n"));
1890 Value = (UINT32)-1;
1891 } else {
1892 Value |= ((UINT32)(-1) << HighBitSet32 (Value));
1893 }
1894
1895 //
1896 // Calculate the size of 64bit bar
1897 //
1898 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64)OriginalValue, 32);
1899
1900 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64)Value, 32);
1901 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;
1902 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
1903 //
1904 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1905 //
1906 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
1907 } else {
1908 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1909 }
1910
1911 break;
1912
1913 //
1914 // reserved
1915 //
1916 default:
1917 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1918 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1919 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
1920 //
1921 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1922 //
1923 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
1924 } else {
1925 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1926 }
1927
1928 break;
1929 }
1930 }
1931
1932 //
1933 // Check the length again so as to keep compatible with some special bars
1934 //
1935 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1936 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1937 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1938 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1939 }
1940
1941 //
1942 // Increment number of bar
1943 //
1944 return Offset + 4;
1945 }
1946
1947 /**
1948 This routine is used to initialize the bar of a PCI device.
1949
1950 @param PciIoDevice Pci device instance.
1951
1952 @note It can be called typically when a device is going to be rejected.
1953
1954 **/
1955 VOID
1956 InitializePciDevice (
1957 IN PCI_IO_DEVICE *PciIoDevice
1958 )
1959 {
1960 EFI_PCI_IO_PROTOCOL *PciIo;
1961 UINT8 Offset;
1962
1963 PciIo = &(PciIoDevice->PciIo);
1964
1965 //
1966 // Put all the resource apertures
1967 // Resource base is set to all ones so as to indicate its resource
1968 // has not been allocated
1969 //
1970 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
1971 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);
1972 }
1973 }
1974
1975 /**
1976 This routine is used to initialize the bar of a PCI-PCI Bridge device.
1977
1978 @param PciIoDevice PCI-PCI bridge device instance.
1979
1980 **/
1981 VOID
1982 InitializePpb (
1983 IN PCI_IO_DEVICE *PciIoDevice
1984 )
1985 {
1986 EFI_PCI_IO_PROTOCOL *PciIo;
1987
1988 PciIo = &(PciIoDevice->PciIo);
1989
1990 //
1991 // Put all the resource apertures including IO16
1992 // Io32, pMem32, pMem64 to quiescent state
1993 // Resource base all ones, Resource limit all zeros
1994 //
1995 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
1996 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);
1997
1998 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);
1999 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);
2000
2001 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);
2002 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);
2003
2004 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);
2005 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);
2006
2007 //
2008 // Don't support use io32 as for now
2009 //
2010 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);
2011 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);
2012
2013 //
2014 // Force Interrupt line to zero for cards that come up randomly
2015 //
2016 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
2017 }
2018
2019 /**
2020 This routine is used to initialize the bar of a PCI Card Bridge device.
2021
2022 @param PciIoDevice PCI Card bridge device.
2023
2024 **/
2025 VOID
2026 InitializeP2C (
2027 IN PCI_IO_DEVICE *PciIoDevice
2028 )
2029 {
2030 EFI_PCI_IO_PROTOCOL *PciIo;
2031
2032 PciIo = &(PciIoDevice->PciIo);
2033
2034 //
2035 // Put all the resource apertures including IO16
2036 // Io32, pMem32, pMem64 to quiescent state(
2037 // Resource base all ones, Resource limit all zeros
2038 //
2039 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);
2040 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);
2041
2042 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);
2043 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);
2044
2045 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);
2046 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);
2047
2048 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);
2049 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);
2050
2051 //
2052 // Force Interrupt line to zero for cards that come up randomly
2053 //
2054 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
2055 }
2056
2057 /**
2058 Authenticate the PCI device by using DeviceSecurityProtocol.
2059
2060 @param PciIoDevice PCI device.
2061
2062 @retval EFI_SUCCESS The device passes the authentication.
2063 @return not EFI_SUCCESS The device failes the authentication or
2064 unexpected error happen during authentication.
2065 **/
2066 EFI_STATUS
2067 AuthenticatePciDevice (
2068 IN PCI_IO_DEVICE *PciIoDevice
2069 )
2070 {
2071 EDKII_DEVICE_IDENTIFIER DeviceIdentifier;
2072 EFI_STATUS Status;
2073
2074 if (mDeviceSecurityProtocol != NULL) {
2075 //
2076 // Prepare the parameter
2077 //
2078 DeviceIdentifier.Version = EDKII_DEVICE_IDENTIFIER_REVISION;
2079 CopyGuid (&DeviceIdentifier.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid);
2080 DeviceIdentifier.DeviceHandle = NULL;
2081 Status = gBS->InstallMultipleProtocolInterfaces (
2082 &DeviceIdentifier.DeviceHandle,
2083 &gEfiDevicePathProtocolGuid,
2084 PciIoDevice->DevicePath,
2085 &gEdkiiDeviceIdentifierTypePciGuid,
2086 &PciIoDevice->PciIo,
2087 NULL
2088 );
2089 if (EFI_ERROR (Status)) {
2090 return Status;
2091 }
2092
2093 //
2094 // Do DeviceAuthentication
2095 //
2096 Status = mDeviceSecurityProtocol->DeviceAuthenticate (mDeviceSecurityProtocol, &DeviceIdentifier);
2097 //
2098 // Always uninstall, because they are only for Authentication.
2099 // No need to check return Status.
2100 //
2101 gBS->UninstallMultipleProtocolInterfaces (
2102 DeviceIdentifier.DeviceHandle,
2103 &gEfiDevicePathProtocolGuid,
2104 PciIoDevice->DevicePath,
2105 &gEdkiiDeviceIdentifierTypePciGuid,
2106 &PciIoDevice->PciIo,
2107 NULL
2108 );
2109 return Status;
2110 }
2111
2112 //
2113 // Device Security Protocol is not found, just return success
2114 //
2115 return EFI_SUCCESS;
2116 }
2117
2118 /**
2119 Checks if PCI device is Root Bridge.
2120
2121 @param PciIoDevice Instance of PCI device
2122
2123 @retval TRUE Device is Root Bridge
2124 @retval FALSE Device is not Root Bridge
2125
2126 **/
2127 BOOLEAN
2128 IsRootBridge (
2129 IN PCI_IO_DEVICE *PciIoDevice
2130 )
2131 {
2132 if (PciIoDevice->Parent == NULL) {
2133 return TRUE;
2134 } else {
2135 return FALSE;
2136 }
2137 }
2138
2139 /**
2140 Create and initialize general PCI I/O device instance for
2141 PCI device/bridge device/hotplug bridge device.
2142
2143 @param Bridge Parent bridge instance.
2144 @param Pci Input Pci information block.
2145 @param Bus Device Bus NO.
2146 @param Device Device device NO.
2147 @param Func Device func NO.
2148
2149 @return Instance of PCI device. NULL means no instance created.
2150
2151 **/
2152 PCI_IO_DEVICE *
2153 CreatePciIoDevice (
2154 IN PCI_IO_DEVICE *Bridge,
2155 IN PCI_TYPE00 *Pci,
2156 IN UINT8 Bus,
2157 IN UINT8 Device,
2158 IN UINT8 Func
2159 )
2160 {
2161 PCI_IO_DEVICE *PciIoDevice;
2162 EFI_PCI_IO_PROTOCOL *PciIo;
2163 EFI_STATUS Status;
2164
2165 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
2166 if (PciIoDevice == NULL) {
2167 return NULL;
2168 }
2169
2170 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;
2171 PciIoDevice->Handle = NULL;
2172 PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;
2173 PciIoDevice->DevicePath = NULL;
2174 PciIoDevice->BusNumber = Bus;
2175 PciIoDevice->DeviceNumber = Device;
2176 PciIoDevice->FunctionNumber = Func;
2177 PciIoDevice->Decodes = 0;
2178
2179 if (gFullEnumeration) {
2180 PciIoDevice->Allocated = FALSE;
2181 } else {
2182 PciIoDevice->Allocated = TRUE;
2183 }
2184
2185 PciIoDevice->Registered = FALSE;
2186 PciIoDevice->Attributes = 0;
2187 PciIoDevice->Supports = 0;
2188 PciIoDevice->BusOverride = FALSE;
2189 PciIoDevice->AllOpRomProcessed = FALSE;
2190
2191 PciIoDevice->IsPciExp = FALSE;
2192
2193 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));
2194
2195 //
2196 // Initialize the PCI I/O instance structure
2197 //
2198 InitializePciIoInstance (PciIoDevice);
2199 InitializePciDriverOverrideInstance (PciIoDevice);
2200 InitializePciLoadFile2 (PciIoDevice);
2201 PciIo = &PciIoDevice->PciIo;
2202
2203 //
2204 // Create a device path for this PCI device and store it into its private data
2205 //
2206 CreatePciDevicePath (
2207 Bridge->DevicePath,
2208 PciIoDevice
2209 );
2210
2211 //
2212 // Detect if PCI Express Device
2213 //
2214 PciIoDevice->PciExpressCapabilityOffset = 0;
2215 Status = LocateCapabilityRegBlock (
2216 PciIoDevice,
2217 EFI_PCI_CAPABILITY_ID_PCIEXP,
2218 &PciIoDevice->PciExpressCapabilityOffset,
2219 NULL
2220 );
2221 if (!EFI_ERROR (Status)) {
2222 PciIoDevice->IsPciExp = TRUE;
2223 }
2224
2225 //
2226 // Now we can do the authentication check for the device.
2227 //
2228 Status = AuthenticatePciDevice (PciIoDevice);
2229 //
2230 // If authentication fails, skip this device.
2231 //
2232 if (EFI_ERROR (Status)) {
2233 if (PciIoDevice->DevicePath != NULL) {
2234 FreePool (PciIoDevice->DevicePath);
2235 }
2236
2237 FreePool (PciIoDevice);
2238 return NULL;
2239 }
2240
2241 //
2242 // Check if device's parent is not Root Bridge
2243 //
2244 if (PcdGetBool (PcdAriSupport) && !IsRootBridge (Bridge)) {
2245 //
2246 // Check if the device is an ARI device.
2247 //
2248 Status = LocatePciExpressCapabilityRegBlock (
2249 PciIoDevice,
2250 EFI_PCIE_CAPABILITY_ID_ARI,
2251 &PciIoDevice->AriCapabilityOffset,
2252 NULL
2253 );
2254 if (!EFI_ERROR (Status)) {
2255 //
2256 // We need to enable ARI feature before calculate BusReservation,
2257 // because FirstVFOffset and VFStride may change after that.
2258 //
2259 EFI_PCI_IO_PROTOCOL *ParentPciIo;
2260 UINT32 Data32;
2261
2262 //
2263 // Check if its parent supports ARI forwarding.
2264 //
2265 ParentPciIo = &Bridge->PciIo;
2266 ParentPciIo->Pci.Read (
2267 ParentPciIo,
2268 EfiPciIoWidthUint32,
2269 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,
2270 1,
2271 &Data32
2272 );
2273 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {
2274 //
2275 // ARI forward support in bridge, so enable it.
2276 //
2277 ParentPciIo->Pci.Read (
2278 ParentPciIo,
2279 EfiPciIoWidthUint32,
2280 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
2281 1,
2282 &Data32
2283 );
2284 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {
2285 Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;
2286 ParentPciIo->Pci.Write (
2287 ParentPciIo,
2288 EfiPciIoWidthUint32,
2289 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
2290 1,
2291 &Data32
2292 );
2293 DEBUG ((
2294 DEBUG_INFO,
2295 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",
2296 Bridge->BusNumber,
2297 Bridge->DeviceNumber,
2298 Bridge->FunctionNumber
2299 ));
2300 }
2301 }
2302
2303 DEBUG ((DEBUG_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset));
2304 }
2305 }
2306
2307 //
2308 // Initialization for SR-IOV
2309 //
2310
2311 if (PcdGetBool (PcdSrIovSupport)) {
2312 Status = LocatePciExpressCapabilityRegBlock (
2313 PciIoDevice,
2314 EFI_PCIE_CAPABILITY_ID_SRIOV,
2315 &PciIoDevice->SrIovCapabilityOffset,
2316 NULL
2317 );
2318 if (!EFI_ERROR (Status)) {
2319 UINT32 SupportedPageSize;
2320 UINT16 VFStride;
2321 UINT16 FirstVFOffset;
2322 UINT16 Data16;
2323 UINT32 PFRid;
2324 UINT32 LastVF;
2325
2326 //
2327 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.
2328 //
2329 if (PcdGetBool (PcdAriSupport) && (PciIoDevice->AriCapabilityOffset != 0)) {
2330 PciIo->Pci.Read (
2331 PciIo,
2332 EfiPciIoWidthUint16,
2333 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,
2334 1,
2335 &Data16
2336 );
2337 Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;
2338 PciIo->Pci.Write (
2339 PciIo,
2340 EfiPciIoWidthUint16,
2341 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,
2342 1,
2343 &Data16
2344 );
2345 }
2346
2347 //
2348 // Calculate SystemPageSize
2349 //
2350
2351 PciIo->Pci.Read (
2352 PciIo,
2353 EfiPciIoWidthUint32,
2354 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,
2355 1,
2356 &SupportedPageSize
2357 );
2358 PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize);
2359 ASSERT (PciIoDevice->SystemPageSize != 0);
2360
2361 PciIo->Pci.Write (
2362 PciIo,
2363 EfiPciIoWidthUint32,
2364 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,
2365 1,
2366 &PciIoDevice->SystemPageSize
2367 );
2368 //
2369 // Adjust SystemPageSize for Alignment usage later
2370 //
2371 PciIoDevice->SystemPageSize <<= 12;
2372
2373 //
2374 // Calculate BusReservation for PCI IOV
2375 //
2376
2377 //
2378 // Read First FirstVFOffset, InitialVFs, and VFStride
2379 //
2380 PciIo->Pci.Read (
2381 PciIo,
2382 EfiPciIoWidthUint16,
2383 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,
2384 1,
2385 &FirstVFOffset
2386 );
2387 PciIo->Pci.Read (
2388 PciIo,
2389 EfiPciIoWidthUint16,
2390 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,
2391 1,
2392 &PciIoDevice->InitialVFs
2393 );
2394 PciIo->Pci.Read (
2395 PciIo,
2396 EfiPciIoWidthUint16,
2397 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,
2398 1,
2399 &VFStride
2400 );
2401 //
2402 // Calculate LastVF
2403 //
2404 PFRid = EFI_PCI_RID (Bus, Device, Func);
2405 LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;
2406
2407 //
2408 // Calculate ReservedBusNum for this PF
2409 //
2410 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);
2411
2412 DEBUG ((
2413 DEBUG_INFO,
2414 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",
2415 SupportedPageSize,
2416 PciIoDevice->SystemPageSize >> 12,
2417 FirstVFOffset
2418 ));
2419 DEBUG ((
2420 DEBUG_INFO,
2421 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",
2422 PciIoDevice->InitialVFs,
2423 PciIoDevice->ReservedBusNum,
2424 PciIoDevice->SrIovCapabilityOffset
2425 ));
2426 }
2427 }
2428
2429 if (PcdGetBool (PcdMrIovSupport)) {
2430 Status = LocatePciExpressCapabilityRegBlock (
2431 PciIoDevice,
2432 EFI_PCIE_CAPABILITY_ID_MRIOV,
2433 &PciIoDevice->MrIovCapabilityOffset,
2434 NULL
2435 );
2436 if (!EFI_ERROR (Status)) {
2437 DEBUG ((DEBUG_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset));
2438 }
2439 }
2440
2441 PciIoDevice->ResizableBarOffset = 0;
2442 if (PcdGetBool (PcdPcieResizableBarSupport)) {
2443 Status = LocatePciExpressCapabilityRegBlock (
2444 PciIoDevice,
2445 PCI_EXPRESS_EXTENDED_CAPABILITY_RESIZABLE_BAR_ID,
2446 &PciIoDevice->ResizableBarOffset,
2447 NULL
2448 );
2449 if (!EFI_ERROR (Status)) {
2450 PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL ResizableBarControl;
2451 UINT32 Offset;
2452 Offset = PciIoDevice->ResizableBarOffset + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER)
2453 + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CAPABILITY),
2454 PciIo->Pci.Read (
2455 PciIo,
2456 EfiPciIoWidthUint8,
2457 Offset,
2458 sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL),
2459 &ResizableBarControl
2460 );
2461 PciIoDevice->ResizableBarNumber = ResizableBarControl.Bits.ResizableBarNumber;
2462 PciProgramResizableBar (PciIoDevice, PciResizableBarMax);
2463 }
2464 }
2465
2466 //
2467 // Initialize the reserved resource list
2468 //
2469 InitializeListHead (&PciIoDevice->ReservedResourceList);
2470
2471 //
2472 // Initialize the driver list
2473 //
2474 InitializeListHead (&PciIoDevice->OptionRomDriverList);
2475
2476 //
2477 // Initialize the child list
2478 //
2479 InitializeListHead (&PciIoDevice->ChildList);
2480
2481 return PciIoDevice;
2482 }
2483
2484 /**
2485 This routine is used to enumerate entire pci bus system
2486 in a given platform.
2487
2488 It is only called on the second start on the same Root Bridge.
2489
2490 @param Controller Parent bridge handler.
2491
2492 @retval EFI_SUCCESS PCI enumeration finished successfully.
2493 @retval other Some error occurred when enumerating the pci bus system.
2494
2495 **/
2496 EFI_STATUS
2497 PciEnumeratorLight (
2498 IN EFI_HANDLE Controller
2499 )
2500 {
2501 EFI_STATUS Status;
2502 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2503 PCI_IO_DEVICE *RootBridgeDev;
2504 UINT16 MinBus;
2505 UINT16 MaxBus;
2506 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
2507
2508 MinBus = 0;
2509 MaxBus = PCI_MAX_BUS;
2510 Descriptors = NULL;
2511
2512 //
2513 // If this root bridge has been already enumerated, then return successfully
2514 //
2515 if (GetRootBridgeByHandle (Controller) != NULL) {
2516 return EFI_SUCCESS;
2517 }
2518
2519 //
2520 // Open pci root bridge io protocol
2521 //
2522 Status = gBS->OpenProtocol (
2523 Controller,
2524 &gEfiPciRootBridgeIoProtocolGuid,
2525 (VOID **)&PciRootBridgeIo,
2526 gPciBusDriverBinding.DriverBindingHandle,
2527 Controller,
2528 EFI_OPEN_PROTOCOL_BY_DRIVER
2529 );
2530 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
2531 return Status;
2532 }
2533
2534 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **)&Descriptors);
2535
2536 if (EFI_ERROR (Status)) {
2537 return Status;
2538 }
2539
2540 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {
2541 //
2542 // Create a device node for root bridge device with a NULL host bridge controller handle
2543 //
2544 RootBridgeDev = CreateRootBridge (Controller);
2545
2546 if (RootBridgeDev == NULL) {
2547 Descriptors++;
2548 continue;
2549 }
2550
2551 //
2552 // Record the root bridge-io protocol
2553 //
2554 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
2555
2556 Status = PciPciDeviceInfoCollector (
2557 RootBridgeDev,
2558 (UINT8)MinBus
2559 );
2560
2561 if (!EFI_ERROR (Status)) {
2562 //
2563 // Remove those PCI devices which are rejected when full enumeration
2564 //
2565 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);
2566
2567 //
2568 // Process option rom light
2569 //
2570 ProcessOptionRomLight (RootBridgeDev);
2571
2572 //
2573 // Determine attributes for all devices under this root bridge
2574 //
2575 DetermineDeviceAttribute (RootBridgeDev);
2576
2577 //
2578 // If successfully, insert the node into device pool
2579 //
2580 InsertRootBridge (RootBridgeDev);
2581 } else {
2582 //
2583 // If unsuccessfully, destroy the entire node
2584 //
2585 DestroyRootBridge (RootBridgeDev);
2586 }
2587
2588 Descriptors++;
2589 }
2590
2591 return EFI_SUCCESS;
2592 }
2593
2594 /**
2595 Get bus range from PCI resource descriptor list.
2596
2597 @param Descriptors A pointer to the address space descriptor.
2598 @param MinBus The min bus returned.
2599 @param MaxBus The max bus returned.
2600 @param BusRange The bus range returned.
2601
2602 @retval EFI_SUCCESS Successfully got bus range.
2603 @retval EFI_NOT_FOUND Can not find the specific bus.
2604
2605 **/
2606 EFI_STATUS
2607 PciGetBusRange (
2608 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,
2609 OUT UINT16 *MinBus,
2610 OUT UINT16 *MaxBus,
2611 OUT UINT16 *BusRange
2612 )
2613 {
2614 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {
2615 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
2616 if (MinBus != NULL) {
2617 *MinBus = (UINT16)(*Descriptors)->AddrRangeMin;
2618 }
2619
2620 if (MaxBus != NULL) {
2621 *MaxBus = (UINT16)(*Descriptors)->AddrRangeMax;
2622 }
2623
2624 if (BusRange != NULL) {
2625 *BusRange = (UINT16)(*Descriptors)->AddrLen;
2626 }
2627
2628 return EFI_SUCCESS;
2629 }
2630
2631 (*Descriptors)++;
2632 }
2633
2634 return EFI_NOT_FOUND;
2635 }
2636
2637 /**
2638 This routine can be used to start the root bridge.
2639
2640 @param RootBridgeDev Pci device instance.
2641
2642 @retval EFI_SUCCESS This device started.
2643 @retval other Failed to get PCI Root Bridge I/O protocol.
2644
2645 **/
2646 EFI_STATUS
2647 StartManagingRootBridge (
2648 IN PCI_IO_DEVICE *RootBridgeDev
2649 )
2650 {
2651 EFI_HANDLE RootBridgeHandle;
2652 EFI_STATUS Status;
2653 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2654
2655 //
2656 // Get the root bridge handle
2657 //
2658 RootBridgeHandle = RootBridgeDev->Handle;
2659 PciRootBridgeIo = NULL;
2660
2661 //
2662 // Get the pci root bridge io protocol
2663 //
2664 Status = gBS->OpenProtocol (
2665 RootBridgeHandle,
2666 &gEfiPciRootBridgeIoProtocolGuid,
2667 (VOID **)&PciRootBridgeIo,
2668 gPciBusDriverBinding.DriverBindingHandle,
2669 RootBridgeHandle,
2670 EFI_OPEN_PROTOCOL_BY_DRIVER
2671 );
2672
2673 if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
2674 return Status;
2675 }
2676
2677 //
2678 // Store the PciRootBridgeIo protocol into root bridge private data
2679 //
2680 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
2681
2682 return EFI_SUCCESS;
2683 }
2684
2685 /**
2686 This routine can be used to check whether a PCI device should be rejected when light enumeration.
2687
2688 @param PciIoDevice Pci device instance.
2689
2690 @retval TRUE This device should be rejected.
2691 @retval FALSE This device shouldn't be rejected.
2692
2693 **/
2694 BOOLEAN
2695 IsPciDeviceRejected (
2696 IN PCI_IO_DEVICE *PciIoDevice
2697 )
2698 {
2699 EFI_STATUS Status;
2700 UINT32 TestValue;
2701 UINT32 OldValue;
2702 UINT32 Mask;
2703 UINT8 BarOffset;
2704
2705 //
2706 // PPB should be skip!
2707 //
2708 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
2709 return FALSE;
2710 }
2711
2712 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
2713 //
2714 // Only test base registers for P2C
2715 //
2716 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {
2717 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
2718 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2719 if (EFI_ERROR (Status)) {
2720 continue;
2721 }
2722
2723 TestValue = TestValue & Mask;
2724 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2725 //
2726 // The bar isn't programed, so it should be rejected
2727 //
2728 return TRUE;
2729 }
2730 }
2731
2732 return FALSE;
2733 }
2734
2735 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {
2736 //
2737 // Test PCI devices
2738 //
2739 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2740 if (EFI_ERROR (Status)) {
2741 continue;
2742 }
2743
2744 if ((TestValue & 0x01) != 0) {
2745 //
2746 // IO Bar
2747 //
2748 Mask = 0xFFFFFFFC;
2749 TestValue = TestValue & Mask;
2750 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2751 return TRUE;
2752 }
2753 } else {
2754 //
2755 // Mem Bar
2756 //
2757 Mask = 0xFFFFFFF0;
2758 TestValue = TestValue & Mask;
2759
2760 if ((TestValue & 0x07) == 0x04) {
2761 //
2762 // Mem64 or PMem64
2763 //
2764 BarOffset += sizeof (UINT32);
2765 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2766 //
2767 // Test its high 32-Bit BAR
2768 //
2769 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2770 if (TestValue == OldValue) {
2771 return TRUE;
2772 }
2773 }
2774 } else {
2775 //
2776 // Mem32 or PMem32
2777 //
2778 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2779 return TRUE;
2780 }
2781 }
2782 }
2783 }
2784
2785 return FALSE;
2786 }
2787
2788 /**
2789 Reset all bus number from specific bridge.
2790
2791 @param Bridge Parent specific bridge.
2792 @param StartBusNumber Start bus number.
2793
2794 **/
2795 VOID
2796 ResetAllPpbBusNumber (
2797 IN PCI_IO_DEVICE *Bridge,
2798 IN UINT8 StartBusNumber
2799 )
2800 {
2801 EFI_STATUS Status;
2802 PCI_TYPE00 Pci;
2803 UINT8 Device;
2804 UINT32 Register;
2805 UINT8 Func;
2806 UINT64 Address;
2807 UINT8 SecondaryBus;
2808 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2809
2810 PciRootBridgeIo = Bridge->PciRootBridgeIo;
2811
2812 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
2813 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
2814 //
2815 // Check to see whether a pci device is present
2816 //
2817 Status = PciDevicePresent (
2818 PciRootBridgeIo,
2819 &Pci,
2820 StartBusNumber,
2821 Device,
2822 Func
2823 );
2824
2825 if (EFI_ERROR (Status) && (Func == 0)) {
2826 //
2827 // go to next device if there is no Function 0
2828 //
2829 break;
2830 }
2831
2832 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {
2833 Register = 0;
2834 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
2835 Status = PciRootBridgeIo->Pci.Read (
2836 PciRootBridgeIo,
2837 EfiPciWidthUint32,
2838 Address,
2839 1,
2840 &Register
2841 );
2842 SecondaryBus = (UINT8)(Register >> 8);
2843
2844 if (SecondaryBus != 0) {
2845 ResetAllPpbBusNumber (Bridge, SecondaryBus);
2846 }
2847
2848 //
2849 // Reset register 18h, 19h, 1Ah on PCI Bridge
2850 //
2851 Register &= 0xFF000000;
2852 Status = PciRootBridgeIo->Pci.Write (
2853 PciRootBridgeIo,
2854 EfiPciWidthUint32,
2855 Address,
2856 1,
2857 &Register
2858 );
2859 }
2860
2861 if ((Func == 0) && !IS_PCI_MULTI_FUNC (&Pci)) {
2862 //
2863 // Skip sub functions, this is not a multi function device
2864 //
2865 Func = PCI_MAX_FUNC;
2866 }
2867 }
2868 }
2869 }