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