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