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