]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
MdeModulePkg/PciBusDxe: Handle BAR sizing fail in high 32bit of MEM64.
[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
937 //
938 // Preserve the original value
939 //
940 PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);
941
942 //
943 // Raise TPL to high level to disable timer interrupt while the BAR is probed
944 //
945 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
946
947 PCI_SET_COMMAND_REGISTER (PciIoDevice, *Command);
948 PCI_READ_COMMAND_REGISTER (PciIoDevice, Command);
949
950 //
951 // Write back the original value
952 //
953 PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);
954
955 //
956 // Restore TPL to its original level
957 //
958 gBS->RestoreTPL (OldTpl);
959
960 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
961
962 //
963 // Preserve the original value
964 //
965 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);
966
967 //
968 // Raise TPL to high level to disable timer interrupt while the BAR is probed
969 //
970 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
971
972 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);
973 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
974
975 //
976 // Write back the original value
977 //
978 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);
979
980 //
981 // Restore TPL to its original level
982 //
983 gBS->RestoreTPL (OldTpl);
984
985 } else {
986 *OldBridgeControl = 0;
987 *BridgeControl = 0;
988 }
989 }
990
991 /**
992 Set the supported or current attributes of a PCI device.
993
994 @param PciIoDevice Structure pointer for PCI device.
995 @param Command Command register value.
996 @param BridgeControl Bridge control value for PPB or P2C.
997 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
998
999 **/
1000 VOID
1001 PciSetDeviceAttribute (
1002 IN PCI_IO_DEVICE *PciIoDevice,
1003 IN UINT16 Command,
1004 IN UINT16 BridgeControl,
1005 IN UINTN Option
1006 )
1007 {
1008 UINT64 Attributes;
1009
1010 Attributes = 0;
1011
1012 if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {
1013 Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;
1014 }
1015
1016 if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {
1017 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;
1018 }
1019
1020 if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {
1021 Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;
1022 }
1023
1024 if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
1025 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
1026 }
1027
1028 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {
1029 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
1030 }
1031
1032 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {
1033 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
1034 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
1035 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
1036 }
1037
1038 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {
1039 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;
1040 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;
1041 }
1042
1043 if (Option == EFI_SET_SUPPORTS) {
1044
1045 Attributes |= (UINT64) (EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |
1046 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |
1047 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |
1048 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
1049 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
1050 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
1051
1052 if (IS_PCI_LPC (&PciIoDevice->Pci)) {
1053 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
1054 Attributes |= (mReserveIsaAliases ? (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO : \
1055 (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);
1056 }
1057
1058 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
1059 //
1060 // For bridge, it should support IDE attributes
1061 //
1062 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
1063 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
1064
1065 if (mReserveVgaAliases) {
1066 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \
1067 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16);
1068 } else {
1069 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | \
1070 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO);
1071 }
1072 } else {
1073
1074 if (IS_PCI_IDE (&PciIoDevice->Pci)) {
1075 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
1076 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
1077 }
1078
1079 if (IS_PCI_VGA (&PciIoDevice->Pci)) {
1080 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
1081 Attributes |= (mReserveVgaAliases ? (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO : \
1082 (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
1083 }
1084 }
1085
1086 PciIoDevice->Supports = Attributes;
1087 PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \
1088 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \
1089 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );
1090
1091 } else {
1092 //
1093 // When this attribute is clear, the RomImage and RomSize fields in the PCI IO were
1094 // initialized based on the PCI option ROM found through the ROM BAR of the PCI controller.
1095 // When this attribute is set, the PCI option ROM described by the RomImage and RomSize
1096 // fields is not from the the ROM BAR of the PCI controller.
1097 //
1098 if (!PciIoDevice->EmbeddedRom) {
1099 Attributes |= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM;
1100 }
1101 PciIoDevice->Attributes = Attributes;
1102 }
1103 }
1104
1105 /**
1106 Determine if the device can support Fast Back to Back attribute.
1107
1108 @param PciIoDevice Pci device instance.
1109 @param StatusIndex Status register value.
1110
1111 @retval EFI_SUCCESS This device support Fast Back to Back attribute.
1112 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
1113
1114 **/
1115 EFI_STATUS
1116 GetFastBackToBackSupport (
1117 IN PCI_IO_DEVICE *PciIoDevice,
1118 IN UINT8 StatusIndex
1119 )
1120 {
1121 EFI_PCI_IO_PROTOCOL *PciIo;
1122 EFI_STATUS Status;
1123 UINT32 StatusRegister;
1124
1125 //
1126 // Read the status register
1127 //
1128 PciIo = &PciIoDevice->PciIo;
1129 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);
1130 if (EFI_ERROR (Status)) {
1131 return EFI_UNSUPPORTED;
1132 }
1133
1134 //
1135 // Check the Fast B2B bit
1136 //
1137 if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {
1138 return EFI_SUCCESS;
1139 } else {
1140 return EFI_UNSUPPORTED;
1141 }
1142 }
1143
1144 /**
1145 Process the option ROM for all the children of the specified parent PCI device.
1146 It can only be used after the first full Option ROM process.
1147
1148 @param PciIoDevice Pci device instance.
1149
1150 **/
1151 VOID
1152 ProcessOptionRomLight (
1153 IN PCI_IO_DEVICE *PciIoDevice
1154 )
1155 {
1156 PCI_IO_DEVICE *Temp;
1157 LIST_ENTRY *CurrentLink;
1158
1159 //
1160 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1161 //
1162 CurrentLink = PciIoDevice->ChildList.ForwardLink;
1163 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
1164
1165 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1166
1167 if (!IsListEmpty (&Temp->ChildList)) {
1168 ProcessOptionRomLight (Temp);
1169 }
1170
1171 PciRomGetImageMapping (Temp);
1172
1173 //
1174 // The OpRom has already been processed in the first round
1175 //
1176 Temp->AllOpRomProcessed = TRUE;
1177
1178 CurrentLink = CurrentLink->ForwardLink;
1179 }
1180 }
1181
1182 /**
1183 Determine the related attributes of all devices under a Root Bridge.
1184
1185 @param PciIoDevice PCI device instance.
1186
1187 **/
1188 EFI_STATUS
1189 DetermineDeviceAttribute (
1190 IN PCI_IO_DEVICE *PciIoDevice
1191 )
1192 {
1193 UINT16 Command;
1194 UINT16 BridgeControl;
1195 UINT16 OldCommand;
1196 UINT16 OldBridgeControl;
1197 BOOLEAN FastB2BSupport;
1198 PCI_IO_DEVICE *Temp;
1199 LIST_ENTRY *CurrentLink;
1200 EFI_STATUS Status;
1201
1202 //
1203 // For Root Bridge, just copy it by RootBridgeIo protocol
1204 // so as to keep consistent with the actual attribute
1205 //
1206 if (PciIoDevice->Parent == NULL) {
1207 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
1208 PciIoDevice->PciRootBridgeIo,
1209 &PciIoDevice->Supports,
1210 &PciIoDevice->Attributes
1211 );
1212 if (EFI_ERROR (Status)) {
1213 return Status;
1214 }
1215 //
1216 // Assume the PCI Root Bridge supports DAC
1217 //
1218 PciIoDevice->Supports |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
1219 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
1220 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
1221
1222 } else {
1223
1224 //
1225 // Set the attributes to be checked for common PCI devices and PPB or P2C
1226 // Since some devices only support part of them, it is better to set the
1227 // attribute according to its command or bridge control register
1228 //
1229 Command = EFI_PCI_COMMAND_IO_SPACE |
1230 EFI_PCI_COMMAND_MEMORY_SPACE |
1231 EFI_PCI_COMMAND_BUS_MASTER |
1232 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1233
1234 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;
1235
1236 //
1237 // Test whether the device can support attributes above
1238 //
1239 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);
1240
1241 //
1242 // Set the supported attributes for specified PCI device
1243 //
1244 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);
1245
1246 //
1247 // Set the current attributes for specified PCI device
1248 //
1249 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);
1250
1251 //
1252 // Enable other PCI supported attributes but not defined in PCI_IO_PROTOCOL
1253 // For PCI Express devices, Memory Write and Invalidate is hardwired to 0b so only enable it for PCI devices.
1254 if (!PciIoDevice->IsPciExp) {
1255 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);
1256 }
1257 }
1258
1259 FastB2BSupport = TRUE;
1260
1261 //
1262 // P2C can not support FB2B on the secondary side
1263 //
1264 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
1265 FastB2BSupport = FALSE;
1266 }
1267
1268 //
1269 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1270 //
1271 CurrentLink = PciIoDevice->ChildList.ForwardLink;
1272 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
1273
1274 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1275 Status = DetermineDeviceAttribute (Temp);
1276 if (EFI_ERROR (Status)) {
1277 return Status;
1278 }
1279 //
1280 // Detect Fast Back to Back support for the device under the bridge
1281 //
1282 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);
1283 if (FastB2BSupport && EFI_ERROR (Status)) {
1284 FastB2BSupport = FALSE;
1285 }
1286
1287 CurrentLink = CurrentLink->ForwardLink;
1288 }
1289 //
1290 // Set or clear Fast Back to Back bit for the whole bridge
1291 //
1292 if (!IsListEmpty (&PciIoDevice->ChildList)) {
1293
1294 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
1295
1296 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);
1297
1298 if (EFI_ERROR (Status) || (!FastB2BSupport)) {
1299 FastB2BSupport = FALSE;
1300 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
1301 } else {
1302 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
1303 }
1304 }
1305
1306 CurrentLink = PciIoDevice->ChildList.ForwardLink;
1307 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
1308 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1309 if (FastB2BSupport) {
1310 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
1311 } else {
1312 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
1313 }
1314
1315 CurrentLink = CurrentLink->ForwardLink;
1316 }
1317 }
1318 //
1319 // End for IsListEmpty
1320 //
1321 return EFI_SUCCESS;
1322 }
1323
1324 /**
1325 This routine is used to update the bar information for those incompatible PCI device.
1326
1327 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
1328 Bar information.
1329
1330 @retval EFI_SUCCESS Successfully updated bar information.
1331 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
1332
1333 **/
1334 EFI_STATUS
1335 UpdatePciInfo (
1336 IN OUT PCI_IO_DEVICE *PciIoDevice
1337 )
1338 {
1339 EFI_STATUS Status;
1340 UINTN BarIndex;
1341 BOOLEAN SetFlag;
1342 VOID *Configuration;
1343 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
1344
1345 Configuration = NULL;
1346 Status = EFI_SUCCESS;
1347
1348 if (gIncompatiblePciDeviceSupport == NULL) {
1349 //
1350 // It can only be supported after the Incompatible PCI Device
1351 // Support Protocol has been installed
1352 //
1353 Status = gBS->LocateProtocol (
1354 &gEfiIncompatiblePciDeviceSupportProtocolGuid,
1355 NULL,
1356 (VOID **) &gIncompatiblePciDeviceSupport
1357 );
1358 }
1359 if (Status == EFI_SUCCESS) {
1360 //
1361 // Check whether the device belongs to incompatible devices from protocol or not
1362 // If it is , then get its special requirement in the ACPI table
1363 //
1364 Status = gIncompatiblePciDeviceSupport->CheckDevice (
1365 gIncompatiblePciDeviceSupport,
1366 PciIoDevice->Pci.Hdr.VendorId,
1367 PciIoDevice->Pci.Hdr.DeviceId,
1368 PciIoDevice->Pci.Hdr.RevisionID,
1369 PciIoDevice->Pci.Device.SubsystemVendorID,
1370 PciIoDevice->Pci.Device.SubsystemID,
1371 &Configuration
1372 );
1373
1374 }
1375
1376 if (EFI_ERROR (Status) || Configuration == NULL ) {
1377 return EFI_UNSUPPORTED;
1378 }
1379
1380 //
1381 // Update PCI device information from the ACPI table
1382 //
1383 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
1384
1385 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {
1386
1387 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
1388 //
1389 // The format is not support
1390 //
1391 break;
1392 }
1393
1394 for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
1395 if ((Ptr->AddrTranslationOffset != MAX_UINT64) &&
1396 (Ptr->AddrTranslationOffset != MAX_UINT8) &&
1397 (Ptr->AddrTranslationOffset != BarIndex)
1398 ) {
1399 //
1400 // Skip updating when AddrTranslationOffset is not MAX_UINT64 or MAX_UINT8 (wide match).
1401 // Skip updating when current BarIndex doesn't equal to AddrTranslationOffset.
1402 // Comparing against MAX_UINT8 is to keep backward compatibility.
1403 //
1404 continue;
1405 }
1406
1407 SetFlag = FALSE;
1408 switch (Ptr->ResType) {
1409 case ACPI_ADDRESS_SPACE_TYPE_MEM:
1410
1411 //
1412 // Make sure the bar is memory type
1413 //
1414 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {
1415 SetFlag = TRUE;
1416
1417 //
1418 // Ignored if granularity is 0.
1419 // Ignored if PCI BAR is I/O or 32-bit memory.
1420 // If PCI BAR is 64-bit memory and granularity is 32, then
1421 // the PCI BAR resource is allocated below 4GB.
1422 // If PCI BAR is 64-bit memory and granularity is 64, then
1423 // the PCI BAR resource is allocated above 4GB.
1424 //
1425 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeMem64) {
1426 switch (Ptr->AddrSpaceGranularity) {
1427 case 32:
1428 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
1429 case 64:
1430 PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;
1431 break;
1432 default:
1433 break;
1434 }
1435 }
1436
1437 if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypePMem64) {
1438 switch (Ptr->AddrSpaceGranularity) {
1439 case 32:
1440 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
1441 case 64:
1442 PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE;
1443 break;
1444 default:
1445 break;
1446 }
1447 }
1448 }
1449 break;
1450
1451 case ACPI_ADDRESS_SPACE_TYPE_IO:
1452
1453 //
1454 // Make sure the bar is IO type
1455 //
1456 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {
1457 SetFlag = TRUE;
1458 }
1459 break;
1460 }
1461
1462 if (SetFlag) {
1463
1464 //
1465 // Update the new alignment for the device
1466 //
1467 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);
1468
1469 //
1470 // Update the new length for the device
1471 //
1472 if (Ptr->AddrLen != 0) {
1473 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;
1474 }
1475 }
1476 }
1477
1478 Ptr++;
1479 }
1480
1481 FreePool (Configuration);
1482
1483 return EFI_SUCCESS;
1484 }
1485
1486 /**
1487 This routine will update the alignment with the new alignment.
1488 Compare with OLD_ALIGN/EVEN_ALIGN/SQUAD_ALIGN/DQUAD_ALIGN is to keep
1489 backward compatibility.
1490
1491 @param Alignment Input Old alignment. Output updated alignment.
1492 @param NewAlignment New alignment.
1493
1494 **/
1495 VOID
1496 SetNewAlign (
1497 IN OUT UINT64 *Alignment,
1498 IN UINT64 NewAlignment
1499 )
1500 {
1501 UINT64 OldAlignment;
1502 UINTN ShiftBit;
1503
1504 //
1505 // The new alignment is the same as the original,
1506 // so skip it
1507 //
1508 if ((NewAlignment == 0) || (NewAlignment == OLD_ALIGN)) {
1509 return ;
1510 }
1511 //
1512 // Check the validity of the parameter
1513 //
1514 if (NewAlignment != EVEN_ALIGN &&
1515 NewAlignment != SQUAD_ALIGN &&
1516 NewAlignment != DQUAD_ALIGN ) {
1517 *Alignment = NewAlignment;
1518 return ;
1519 }
1520
1521 OldAlignment = (*Alignment) + 1;
1522 ShiftBit = 0;
1523
1524 //
1525 // Get the first non-zero hex value of the length
1526 //
1527 while ((OldAlignment & 0x0F) == 0x00) {
1528 OldAlignment = RShiftU64 (OldAlignment, 4);
1529 ShiftBit += 4;
1530 }
1531
1532 //
1533 // Adjust the alignment to even, quad or double quad boundary
1534 //
1535 if (NewAlignment == EVEN_ALIGN) {
1536 if ((OldAlignment & 0x01) != 0) {
1537 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);
1538 }
1539 } else if (NewAlignment == SQUAD_ALIGN) {
1540 if ((OldAlignment & 0x03) != 0) {
1541 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);
1542 }
1543 } else if (NewAlignment == DQUAD_ALIGN) {
1544 if ((OldAlignment & 0x07) != 0) {
1545 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);
1546 }
1547 }
1548
1549 //
1550 // Update the old value
1551 //
1552 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;
1553 *Alignment = NewAlignment;
1554
1555 return ;
1556 }
1557
1558 /**
1559 Parse PCI IOV VF bar information and fill them into PCI device instance.
1560
1561 @param PciIoDevice Pci device instance.
1562 @param Offset Bar offset.
1563 @param BarIndex Bar index.
1564
1565 @return Next bar offset.
1566
1567 **/
1568 UINTN
1569 PciIovParseVfBar (
1570 IN PCI_IO_DEVICE *PciIoDevice,
1571 IN UINTN Offset,
1572 IN UINTN BarIndex
1573 )
1574 {
1575 UINT32 Value;
1576 UINT32 OriginalValue;
1577 UINT32 Mask;
1578 EFI_STATUS Status;
1579
1580 //
1581 // Ensure it is called properly
1582 //
1583 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
1584 if (PciIoDevice->SrIovCapabilityOffset == 0) {
1585 return 0;
1586 }
1587
1588 OriginalValue = 0;
1589 Value = 0;
1590
1591 Status = VfBarExisted (
1592 PciIoDevice,
1593 Offset,
1594 &Value,
1595 &OriginalValue
1596 );
1597
1598 if (EFI_ERROR (Status)) {
1599 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
1600 PciIoDevice->VfPciBar[BarIndex].Length = 0;
1601 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;
1602
1603 //
1604 // Scan all the BARs anyway
1605 //
1606 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;
1607 return Offset + 4;
1608 }
1609
1610 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;
1611 if ((Value & 0x01) != 0) {
1612 //
1613 // Device I/Os. Impossible
1614 //
1615 ASSERT (FALSE);
1616 return Offset + 4;
1617
1618 } else {
1619
1620 Mask = 0xfffffff0;
1621
1622 PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1623
1624 switch (Value & 0x07) {
1625
1626 //
1627 //memory space; anywhere in 32 bit address space
1628 //
1629 case 0x00:
1630 if ((Value & 0x08) != 0) {
1631 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;
1632 } else {
1633 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;
1634 }
1635
1636 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1637 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
1638
1639 //
1640 // Adjust Length
1641 //
1642 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
1643 //
1644 // Adjust Alignment
1645 //
1646 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
1647 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
1648 }
1649
1650 break;
1651
1652 //
1653 // memory space; anywhere in 64 bit address space
1654 //
1655 case 0x04:
1656 if ((Value & 0x08) != 0) {
1657 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;
1658 } else {
1659 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;
1660 }
1661
1662 //
1663 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1664 // is regarded as an extension for the first bar. As a result
1665 // the sizing will be conducted on combined 64 bit value
1666 // Here just store the masked first 32bit value for future size
1667 // calculation
1668 //
1669 PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;
1670 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
1671
1672 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
1673 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
1674 }
1675
1676 //
1677 // Increment the offset to point to next DWORD
1678 //
1679 Offset += 4;
1680
1681 Status = VfBarExisted (
1682 PciIoDevice,
1683 Offset,
1684 &Value,
1685 &OriginalValue
1686 );
1687
1688 if (EFI_ERROR (Status)) {
1689 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
1690 return Offset + 4;
1691 }
1692
1693 //
1694 // Fix the length to support some special 64 bit BAR
1695 //
1696 Value |= ((UINT32) -1 << HighBitSet32 (Value));
1697
1698 //
1699 // Calculate the size of 64bit bar
1700 //
1701 PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);
1702
1703 PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
1704 PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;
1705 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
1706
1707 //
1708 // Adjust Length
1709 //
1710 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
1711 //
1712 // Adjust Alignment
1713 //
1714 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
1715 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
1716 }
1717
1718 break;
1719
1720 //
1721 // reserved
1722 //
1723 default:
1724 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
1725 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1726 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
1727
1728 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
1729 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
1730 }
1731
1732 break;
1733 }
1734 }
1735
1736 //
1737 // Check the length again so as to keep compatible with some special bars
1738 //
1739 if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {
1740 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
1741 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
1742 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;
1743 }
1744
1745 //
1746 // Increment number of bar
1747 //
1748 return Offset + 4;
1749 }
1750
1751 /**
1752 Parse PCI bar information and fill them into PCI device instance.
1753
1754 @param PciIoDevice Pci device instance.
1755 @param Offset Bar offset.
1756 @param BarIndex Bar index.
1757
1758 @return Next bar offset.
1759
1760 **/
1761 UINTN
1762 PciParseBar (
1763 IN PCI_IO_DEVICE *PciIoDevice,
1764 IN UINTN Offset,
1765 IN UINTN BarIndex
1766 )
1767 {
1768 UINT32 Value;
1769 UINT32 OriginalValue;
1770 UINT32 Mask;
1771 EFI_STATUS Status;
1772
1773 OriginalValue = 0;
1774 Value = 0;
1775
1776 Status = BarExisted (
1777 PciIoDevice,
1778 Offset,
1779 &Value,
1780 &OriginalValue
1781 );
1782
1783 if (EFI_ERROR (Status)) {
1784 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1785 PciIoDevice->PciBar[BarIndex].Length = 0;
1786 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1787
1788 //
1789 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
1790 //
1791 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
1792 return Offset + 4;
1793 }
1794
1795 PciIoDevice->PciBar[BarIndex].BarTypeFixed = FALSE;
1796 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
1797 if ((Value & 0x01) != 0) {
1798 //
1799 // Device I/Os
1800 //
1801 Mask = 0xfffffffc;
1802
1803 if ((Value & 0xFFFF0000) != 0) {
1804 //
1805 // It is a IO32 bar
1806 //
1807 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;
1808 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);
1809 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1810
1811 } else {
1812 //
1813 // It is a IO16 bar
1814 //
1815 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;
1816 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);
1817 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1818
1819 }
1820 //
1821 // Workaround. Some platforms implement IO bar with 0 length
1822 // Need to treat it as no-bar
1823 //
1824 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1825 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;
1826 }
1827
1828 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1829
1830 } else {
1831
1832 Mask = 0xfffffff0;
1833
1834 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1835
1836 switch (Value & 0x07) {
1837
1838 //
1839 //memory space; anywhere in 32 bit address space
1840 //
1841 case 0x00:
1842 if ((Value & 0x08) != 0) {
1843 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
1844 } else {
1845 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
1846 }
1847
1848 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1849 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
1850 //
1851 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1852 //
1853 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
1854 } else {
1855 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1856 }
1857 break;
1858
1859 //
1860 // memory space; anywhere in 64 bit address space
1861 //
1862 case 0x04:
1863 if ((Value & 0x08) != 0) {
1864 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;
1865 } else {
1866 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;
1867 }
1868
1869 //
1870 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1871 // is regarded as an extension for the first bar. As a result
1872 // the sizing will be conducted on combined 64 bit value
1873 // Here just store the masked first 32bit value for future size
1874 // calculation
1875 //
1876 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;
1877 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1878
1879 //
1880 // Increment the offset to point to next DWORD
1881 //
1882 Offset += 4;
1883
1884 Status = BarExisted (
1885 PciIoDevice,
1886 Offset,
1887 &Value,
1888 &OriginalValue
1889 );
1890
1891 if (EFI_ERROR (Status)) {
1892 //
1893 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again
1894 //
1895 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1896 //
1897 // some device implement MMIO bar with 0 length, need to treat it as no-bar
1898 //
1899 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1900 return Offset + 4;
1901 }
1902 }
1903
1904 //
1905 // Fix the length to support some special 64 bit BAR
1906 //
1907 if (Value == 0) {
1908 DEBUG ((EFI_D_INFO, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n"));
1909 Value = (UINT32) -1;
1910 } else {
1911 Value |= ((UINT32)(-1) << HighBitSet32 (Value));
1912 }
1913
1914 //
1915 // Calculate the size of 64bit bar
1916 //
1917 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);
1918
1919 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
1920 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;
1921 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
1922 //
1923 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1924 //
1925 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
1926 } else {
1927 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1928 }
1929
1930 break;
1931
1932 //
1933 // reserved
1934 //
1935 default:
1936 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1937 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1938 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
1939 //
1940 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1941 //
1942 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
1943 } else {
1944 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1945 }
1946 break;
1947 }
1948 }
1949
1950 //
1951 // Check the length again so as to keep compatible with some special bars
1952 //
1953 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1954 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1955 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1956 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1957 }
1958
1959 //
1960 // Increment number of bar
1961 //
1962 return Offset + 4;
1963 }
1964
1965 /**
1966 This routine is used to initialize the bar of a PCI device.
1967
1968 @param PciIoDevice Pci device instance.
1969
1970 @note It can be called typically when a device is going to be rejected.
1971
1972 **/
1973 VOID
1974 InitializePciDevice (
1975 IN PCI_IO_DEVICE *PciIoDevice
1976 )
1977 {
1978 EFI_PCI_IO_PROTOCOL *PciIo;
1979 UINT8 Offset;
1980
1981 PciIo = &(PciIoDevice->PciIo);
1982
1983 //
1984 // Put all the resource apertures
1985 // Resource base is set to all ones so as to indicate its resource
1986 // has not been allocated
1987 //
1988 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
1989 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);
1990 }
1991 }
1992
1993 /**
1994 This routine is used to initialize the bar of a PCI-PCI Bridge device.
1995
1996 @param PciIoDevice PCI-PCI bridge device instance.
1997
1998 **/
1999 VOID
2000 InitializePpb (
2001 IN PCI_IO_DEVICE *PciIoDevice
2002 )
2003 {
2004 EFI_PCI_IO_PROTOCOL *PciIo;
2005
2006 PciIo = &(PciIoDevice->PciIo);
2007
2008 //
2009 // Put all the resource apertures including IO16
2010 // Io32, pMem32, pMem64 to quiescent state
2011 // Resource base all ones, Resource limit all zeros
2012 //
2013 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
2014 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);
2015
2016 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);
2017 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);
2018
2019 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);
2020 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);
2021
2022 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);
2023 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);
2024
2025 //
2026 // Don't support use io32 as for now
2027 //
2028 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);
2029 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);
2030
2031 //
2032 // Force Interrupt line to zero for cards that come up randomly
2033 //
2034 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
2035 }
2036
2037 /**
2038 This routine is used to initialize the bar of a PCI Card Bridge device.
2039
2040 @param PciIoDevice PCI Card bridge device.
2041
2042 **/
2043 VOID
2044 InitializeP2C (
2045 IN PCI_IO_DEVICE *PciIoDevice
2046 )
2047 {
2048 EFI_PCI_IO_PROTOCOL *PciIo;
2049
2050 PciIo = &(PciIoDevice->PciIo);
2051
2052 //
2053 // Put all the resource apertures including IO16
2054 // Io32, pMem32, pMem64 to quiescent state(
2055 // Resource base all ones, Resource limit all zeros
2056 //
2057 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);
2058 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);
2059
2060 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);
2061 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);
2062
2063 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);
2064 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);
2065
2066 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);
2067 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);
2068
2069 //
2070 // Force Interrupt line to zero for cards that come up randomly
2071 //
2072 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
2073 }
2074
2075 /**
2076 Authenticate the PCI device by using DeviceSecurityProtocol.
2077
2078 @param PciIoDevice PCI device.
2079
2080 @retval EFI_SUCCESS The device passes the authentication.
2081 @return not EFI_SUCCESS The device failes the authentication or
2082 unexpected error happen during authentication.
2083 **/
2084 EFI_STATUS
2085 AuthenticatePciDevice (
2086 IN PCI_IO_DEVICE *PciIoDevice
2087 )
2088 {
2089 EDKII_DEVICE_IDENTIFIER DeviceIdentifier;
2090 EFI_STATUS Status;
2091
2092 if (mDeviceSecurityProtocol != NULL) {
2093 //
2094 // Prepare the parameter
2095 //
2096 DeviceIdentifier.Version = EDKII_DEVICE_IDENTIFIER_REVISION;
2097 CopyGuid (&DeviceIdentifier.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid);
2098 DeviceIdentifier.DeviceHandle = NULL;
2099 Status = gBS->InstallMultipleProtocolInterfaces (
2100 &DeviceIdentifier.DeviceHandle,
2101 &gEfiDevicePathProtocolGuid,
2102 PciIoDevice->DevicePath,
2103 &gEdkiiDeviceIdentifierTypePciGuid,
2104 &PciIoDevice->PciIo,
2105 NULL
2106 );
2107 if (EFI_ERROR(Status)) {
2108 return Status;
2109 }
2110
2111 //
2112 // Do DeviceAuthentication
2113 //
2114 Status = mDeviceSecurityProtocol->DeviceAuthenticate (mDeviceSecurityProtocol, &DeviceIdentifier);
2115 //
2116 // Always uninstall, because they are only for Authentication.
2117 // No need to check return Status.
2118 //
2119 gBS->UninstallMultipleProtocolInterfaces (
2120 DeviceIdentifier.DeviceHandle,
2121 &gEfiDevicePathProtocolGuid,
2122 PciIoDevice->DevicePath,
2123 &gEdkiiDeviceIdentifierTypePciGuid,
2124 &PciIoDevice->PciIo,
2125 NULL
2126 );
2127 return Status;
2128 }
2129
2130 //
2131 // Device Security Protocol is not found, just return success
2132 //
2133 return EFI_SUCCESS;
2134 }
2135
2136 /**
2137 Create and initialize general PCI I/O device instance for
2138 PCI device/bridge device/hotplug bridge device.
2139
2140 @param Bridge Parent bridge instance.
2141 @param Pci Input Pci information block.
2142 @param Bus Device Bus NO.
2143 @param Device Device device NO.
2144 @param Func Device func NO.
2145
2146 @return Instance of PCI device. NULL means no instance created.
2147
2148 **/
2149 PCI_IO_DEVICE *
2150 CreatePciIoDevice (
2151 IN PCI_IO_DEVICE *Bridge,
2152 IN PCI_TYPE00 *Pci,
2153 IN UINT8 Bus,
2154 IN UINT8 Device,
2155 IN UINT8 Func
2156 )
2157 {
2158 PCI_IO_DEVICE *PciIoDevice;
2159 EFI_PCI_IO_PROTOCOL *PciIo;
2160 EFI_STATUS Status;
2161
2162 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
2163 if (PciIoDevice == NULL) {
2164 return NULL;
2165 }
2166
2167 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;
2168 PciIoDevice->Handle = NULL;
2169 PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;
2170 PciIoDevice->DevicePath = NULL;
2171 PciIoDevice->BusNumber = Bus;
2172 PciIoDevice->DeviceNumber = Device;
2173 PciIoDevice->FunctionNumber = Func;
2174 PciIoDevice->Decodes = 0;
2175
2176 if (gFullEnumeration) {
2177 PciIoDevice->Allocated = FALSE;
2178 } else {
2179 PciIoDevice->Allocated = TRUE;
2180 }
2181
2182 PciIoDevice->Registered = FALSE;
2183 PciIoDevice->Attributes = 0;
2184 PciIoDevice->Supports = 0;
2185 PciIoDevice->BusOverride = FALSE;
2186 PciIoDevice->AllOpRomProcessed = FALSE;
2187
2188 PciIoDevice->IsPciExp = FALSE;
2189
2190 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));
2191
2192 //
2193 // Initialize the PCI I/O instance structure
2194 //
2195 InitializePciIoInstance (PciIoDevice);
2196 InitializePciDriverOverrideInstance (PciIoDevice);
2197 InitializePciLoadFile2 (PciIoDevice);
2198 PciIo = &PciIoDevice->PciIo;
2199
2200 //
2201 // Create a device path for this PCI device and store it into its private data
2202 //
2203 CreatePciDevicePath (
2204 Bridge->DevicePath,
2205 PciIoDevice
2206 );
2207
2208 //
2209 // Detect if PCI Express Device
2210 //
2211 PciIoDevice->PciExpressCapabilityOffset = 0;
2212 Status = LocateCapabilityRegBlock (
2213 PciIoDevice,
2214 EFI_PCI_CAPABILITY_ID_PCIEXP,
2215 &PciIoDevice->PciExpressCapabilityOffset,
2216 NULL
2217 );
2218 if (!EFI_ERROR (Status)) {
2219 PciIoDevice->IsPciExp = TRUE;
2220 }
2221
2222 //
2223 // Now we can do the authentication check for the device.
2224 //
2225 Status = AuthenticatePciDevice (PciIoDevice);
2226 //
2227 // If authentication fails, skip this device.
2228 //
2229 if (EFI_ERROR(Status)) {
2230 if (PciIoDevice->DevicePath != NULL) {
2231 FreePool (PciIoDevice->DevicePath);
2232 }
2233 FreePool (PciIoDevice);
2234 return NULL;
2235 }
2236
2237 if (PcdGetBool (PcdAriSupport)) {
2238 //
2239 // Check if the device is an ARI device.
2240 //
2241 Status = LocatePciExpressCapabilityRegBlock (
2242 PciIoDevice,
2243 EFI_PCIE_CAPABILITY_ID_ARI,
2244 &PciIoDevice->AriCapabilityOffset,
2245 NULL
2246 );
2247 if (!EFI_ERROR (Status)) {
2248 //
2249 // We need to enable ARI feature before calculate BusReservation,
2250 // because FirstVFOffset and VFStride may change after that.
2251 //
2252 EFI_PCI_IO_PROTOCOL *ParentPciIo;
2253 UINT32 Data32;
2254
2255 //
2256 // Check if its parent supports ARI forwarding.
2257 //
2258 ParentPciIo = &Bridge->PciIo;
2259 ParentPciIo->Pci.Read (
2260 ParentPciIo,
2261 EfiPciIoWidthUint32,
2262 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,
2263 1,
2264 &Data32
2265 );
2266 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {
2267 //
2268 // ARI forward support in bridge, so enable it.
2269 //
2270 ParentPciIo->Pci.Read (
2271 ParentPciIo,
2272 EfiPciIoWidthUint32,
2273 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
2274 1,
2275 &Data32
2276 );
2277 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {
2278 Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;
2279 ParentPciIo->Pci.Write (
2280 ParentPciIo,
2281 EfiPciIoWidthUint32,
2282 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
2283 1,
2284 &Data32
2285 );
2286 DEBUG ((
2287 EFI_D_INFO,
2288 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",
2289 Bridge->BusNumber,
2290 Bridge->DeviceNumber,
2291 Bridge->FunctionNumber
2292 ));
2293 }
2294 }
2295
2296 DEBUG ((EFI_D_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset));
2297 }
2298 }
2299
2300 //
2301 // Initialization for SR-IOV
2302 //
2303
2304 if (PcdGetBool (PcdSrIovSupport)) {
2305 Status = LocatePciExpressCapabilityRegBlock (
2306 PciIoDevice,
2307 EFI_PCIE_CAPABILITY_ID_SRIOV,
2308 &PciIoDevice->SrIovCapabilityOffset,
2309 NULL
2310 );
2311 if (!EFI_ERROR (Status)) {
2312 UINT32 SupportedPageSize;
2313 UINT16 VFStride;
2314 UINT16 FirstVFOffset;
2315 UINT16 Data16;
2316 UINT32 PFRid;
2317 UINT32 LastVF;
2318
2319 //
2320 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.
2321 //
2322 if (PcdGetBool (PcdAriSupport) && PciIoDevice->AriCapabilityOffset != 0) {
2323 PciIo->Pci.Read (
2324 PciIo,
2325 EfiPciIoWidthUint16,
2326 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,
2327 1,
2328 &Data16
2329 );
2330 Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;
2331 PciIo->Pci.Write (
2332 PciIo,
2333 EfiPciIoWidthUint16,
2334 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,
2335 1,
2336 &Data16
2337 );
2338 }
2339
2340 //
2341 // Calculate SystemPageSize
2342 //
2343
2344 PciIo->Pci.Read (
2345 PciIo,
2346 EfiPciIoWidthUint32,
2347 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,
2348 1,
2349 &SupportedPageSize
2350 );
2351 PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize);
2352 ASSERT (PciIoDevice->SystemPageSize != 0);
2353
2354 PciIo->Pci.Write (
2355 PciIo,
2356 EfiPciIoWidthUint32,
2357 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,
2358 1,
2359 &PciIoDevice->SystemPageSize
2360 );
2361 //
2362 // Adjust SystemPageSize for Alignment usage later
2363 //
2364 PciIoDevice->SystemPageSize <<= 12;
2365
2366 //
2367 // Calculate BusReservation for PCI IOV
2368 //
2369
2370 //
2371 // Read First FirstVFOffset, InitialVFs, and VFStride
2372 //
2373 PciIo->Pci.Read (
2374 PciIo,
2375 EfiPciIoWidthUint16,
2376 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,
2377 1,
2378 &FirstVFOffset
2379 );
2380 PciIo->Pci.Read (
2381 PciIo,
2382 EfiPciIoWidthUint16,
2383 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,
2384 1,
2385 &PciIoDevice->InitialVFs
2386 );
2387 PciIo->Pci.Read (
2388 PciIo,
2389 EfiPciIoWidthUint16,
2390 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,
2391 1,
2392 &VFStride
2393 );
2394 //
2395 // Calculate LastVF
2396 //
2397 PFRid = EFI_PCI_RID(Bus, Device, Func);
2398 LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;
2399
2400 //
2401 // Calculate ReservedBusNum for this PF
2402 //
2403 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);
2404
2405 DEBUG ((
2406 EFI_D_INFO,
2407 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",
2408 SupportedPageSize, PciIoDevice->SystemPageSize >> 12, FirstVFOffset
2409 ));
2410 DEBUG ((
2411 EFI_D_INFO,
2412 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",
2413 PciIoDevice->InitialVFs, PciIoDevice->ReservedBusNum, PciIoDevice->SrIovCapabilityOffset
2414 ));
2415 }
2416 }
2417
2418 if (PcdGetBool (PcdMrIovSupport)) {
2419 Status = LocatePciExpressCapabilityRegBlock (
2420 PciIoDevice,
2421 EFI_PCIE_CAPABILITY_ID_MRIOV,
2422 &PciIoDevice->MrIovCapabilityOffset,
2423 NULL
2424 );
2425 if (!EFI_ERROR (Status)) {
2426 DEBUG ((EFI_D_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset));
2427 }
2428 }
2429
2430 PciIoDevice->ResizableBarOffset = 0;
2431 if (PcdGetBool (PcdPcieResizableBarSupport)) {
2432 Status = LocatePciExpressCapabilityRegBlock (
2433 PciIoDevice,
2434 PCI_EXPRESS_EXTENDED_CAPABILITY_RESIZABLE_BAR_ID,
2435 &PciIoDevice->ResizableBarOffset,
2436 NULL
2437 );
2438 if (!EFI_ERROR (Status)) {
2439 PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL ResizableBarControl;
2440 UINT32 Offset;
2441 Offset = PciIoDevice->ResizableBarOffset + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER)
2442 + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CAPABILITY),
2443 PciIo->Pci.Read (
2444 PciIo,
2445 EfiPciIoWidthUint8,
2446 Offset,
2447 sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL),
2448 &ResizableBarControl
2449 );
2450 PciIoDevice->ResizableBarNumber = ResizableBarControl.Bits.ResizableBarNumber;
2451 PciProgramResizableBar (PciIoDevice, PciResizableBarMax);
2452 }
2453 }
2454
2455 //
2456 // Initialize the reserved resource list
2457 //
2458 InitializeListHead (&PciIoDevice->ReservedResourceList);
2459
2460 //
2461 // Initialize the driver list
2462 //
2463 InitializeListHead (&PciIoDevice->OptionRomDriverList);
2464
2465 //
2466 // Initialize the child list
2467 //
2468 InitializeListHead (&PciIoDevice->ChildList);
2469
2470 return PciIoDevice;
2471 }
2472
2473 /**
2474 This routine is used to enumerate entire pci bus system
2475 in a given platform.
2476
2477 It is only called on the second start on the same Root Bridge.
2478
2479 @param Controller Parent bridge handler.
2480
2481 @retval EFI_SUCCESS PCI enumeration finished successfully.
2482 @retval other Some error occurred when enumerating the pci bus system.
2483
2484 **/
2485 EFI_STATUS
2486 PciEnumeratorLight (
2487 IN EFI_HANDLE Controller
2488 )
2489 {
2490
2491 EFI_STATUS Status;
2492 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2493 PCI_IO_DEVICE *RootBridgeDev;
2494 UINT16 MinBus;
2495 UINT16 MaxBus;
2496 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
2497
2498 MinBus = 0;
2499 MaxBus = PCI_MAX_BUS;
2500 Descriptors = NULL;
2501
2502 //
2503 // If this root bridge has been already enumerated, then return successfully
2504 //
2505 if (GetRootBridgeByHandle (Controller) != NULL) {
2506 return EFI_SUCCESS;
2507 }
2508
2509 //
2510 // Open pci root bridge io protocol
2511 //
2512 Status = gBS->OpenProtocol (
2513 Controller,
2514 &gEfiPciRootBridgeIoProtocolGuid,
2515 (VOID **) &PciRootBridgeIo,
2516 gPciBusDriverBinding.DriverBindingHandle,
2517 Controller,
2518 EFI_OPEN_PROTOCOL_BY_DRIVER
2519 );
2520 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
2521 return Status;
2522 }
2523
2524 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
2525
2526 if (EFI_ERROR (Status)) {
2527 return Status;
2528 }
2529
2530 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {
2531
2532 //
2533 // Create a device node for root bridge device with a NULL host bridge controller handle
2534 //
2535 RootBridgeDev = CreateRootBridge (Controller);
2536
2537 if (RootBridgeDev == NULL) {
2538 Descriptors++;
2539 continue;
2540 }
2541
2542 //
2543 // Record the root bridge-io protocol
2544 //
2545 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
2546
2547 Status = PciPciDeviceInfoCollector (
2548 RootBridgeDev,
2549 (UINT8) MinBus
2550 );
2551
2552 if (!EFI_ERROR (Status)) {
2553
2554 //
2555 // Remove those PCI devices which are rejected when full enumeration
2556 //
2557 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);
2558
2559 //
2560 // Process option rom light
2561 //
2562 ProcessOptionRomLight (RootBridgeDev);
2563
2564 //
2565 // Determine attributes for all devices under this root bridge
2566 //
2567 DetermineDeviceAttribute (RootBridgeDev);
2568
2569 //
2570 // If successfully, insert the node into device pool
2571 //
2572 InsertRootBridge (RootBridgeDev);
2573 } else {
2574
2575 //
2576 // If unsuccessfully, destroy the entire node
2577 //
2578 DestroyRootBridge (RootBridgeDev);
2579 }
2580
2581 Descriptors++;
2582 }
2583
2584 return EFI_SUCCESS;
2585 }
2586
2587 /**
2588 Get bus range from PCI resource descriptor list.
2589
2590 @param Descriptors A pointer to the address space descriptor.
2591 @param MinBus The min bus returned.
2592 @param MaxBus The max bus returned.
2593 @param BusRange The bus range returned.
2594
2595 @retval EFI_SUCCESS Successfully got bus range.
2596 @retval EFI_NOT_FOUND Can not find the specific bus.
2597
2598 **/
2599 EFI_STATUS
2600 PciGetBusRange (
2601 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,
2602 OUT UINT16 *MinBus,
2603 OUT UINT16 *MaxBus,
2604 OUT UINT16 *BusRange
2605 )
2606 {
2607 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {
2608 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
2609 if (MinBus != NULL) {
2610 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;
2611 }
2612
2613 if (MaxBus != NULL) {
2614 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;
2615 }
2616
2617 if (BusRange != NULL) {
2618 *BusRange = (UINT16) (*Descriptors)->AddrLen;
2619 }
2620
2621 return EFI_SUCCESS;
2622 }
2623
2624 (*Descriptors)++;
2625 }
2626
2627 return EFI_NOT_FOUND;
2628 }
2629
2630 /**
2631 This routine can be used to start the root bridge.
2632
2633 @param RootBridgeDev Pci device instance.
2634
2635 @retval EFI_SUCCESS This device started.
2636 @retval other Failed to get PCI Root Bridge I/O protocol.
2637
2638 **/
2639 EFI_STATUS
2640 StartManagingRootBridge (
2641 IN PCI_IO_DEVICE *RootBridgeDev
2642 )
2643 {
2644 EFI_HANDLE RootBridgeHandle;
2645 EFI_STATUS Status;
2646 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2647
2648 //
2649 // Get the root bridge handle
2650 //
2651 RootBridgeHandle = RootBridgeDev->Handle;
2652 PciRootBridgeIo = NULL;
2653
2654 //
2655 // Get the pci root bridge io protocol
2656 //
2657 Status = gBS->OpenProtocol (
2658 RootBridgeHandle,
2659 &gEfiPciRootBridgeIoProtocolGuid,
2660 (VOID **) &PciRootBridgeIo,
2661 gPciBusDriverBinding.DriverBindingHandle,
2662 RootBridgeHandle,
2663 EFI_OPEN_PROTOCOL_BY_DRIVER
2664 );
2665
2666 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
2667 return Status;
2668 }
2669
2670 //
2671 // Store the PciRootBridgeIo protocol into root bridge private data
2672 //
2673 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
2674
2675 return EFI_SUCCESS;
2676
2677 }
2678
2679 /**
2680 This routine can be used to check whether a PCI device should be rejected when light enumeration.
2681
2682 @param PciIoDevice Pci device instance.
2683
2684 @retval TRUE This device should be rejected.
2685 @retval FALSE This device shouldn't be rejected.
2686
2687 **/
2688 BOOLEAN
2689 IsPciDeviceRejected (
2690 IN PCI_IO_DEVICE *PciIoDevice
2691 )
2692 {
2693 EFI_STATUS Status;
2694 UINT32 TestValue;
2695 UINT32 OldValue;
2696 UINT32 Mask;
2697 UINT8 BarOffset;
2698
2699 //
2700 // PPB should be skip!
2701 //
2702 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
2703 return FALSE;
2704 }
2705
2706 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
2707 //
2708 // Only test base registers for P2C
2709 //
2710 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {
2711
2712 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
2713 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2714 if (EFI_ERROR (Status)) {
2715 continue;
2716 }
2717
2718 TestValue = TestValue & Mask;
2719 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2720 //
2721 // The bar isn't programed, so it should be rejected
2722 //
2723 return TRUE;
2724 }
2725 }
2726
2727 return FALSE;
2728 }
2729
2730 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {
2731 //
2732 // Test PCI devices
2733 //
2734 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2735 if (EFI_ERROR (Status)) {
2736 continue;
2737 }
2738
2739 if ((TestValue & 0x01) != 0) {
2740
2741 //
2742 // IO Bar
2743 //
2744 Mask = 0xFFFFFFFC;
2745 TestValue = TestValue & Mask;
2746 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2747 return TRUE;
2748 }
2749
2750 } else {
2751
2752 //
2753 // Mem Bar
2754 //
2755 Mask = 0xFFFFFFF0;
2756 TestValue = TestValue & Mask;
2757
2758 if ((TestValue & 0x07) == 0x04) {
2759
2760 //
2761 // Mem64 or PMem64
2762 //
2763 BarOffset += sizeof (UINT32);
2764 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2765
2766 //
2767 // Test its high 32-Bit BAR
2768 //
2769 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2770 if (TestValue == OldValue) {
2771 return TRUE;
2772 }
2773 }
2774
2775 } else {
2776
2777 //
2778 // Mem32 or PMem32
2779 //
2780 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2781 return TRUE;
2782 }
2783 }
2784 }
2785 }
2786
2787 return FALSE;
2788 }
2789
2790 /**
2791 Reset all bus number from specific bridge.
2792
2793 @param Bridge Parent specific bridge.
2794 @param StartBusNumber Start bus number.
2795
2796 **/
2797 VOID
2798 ResetAllPpbBusNumber (
2799 IN PCI_IO_DEVICE *Bridge,
2800 IN UINT8 StartBusNumber
2801 )
2802 {
2803 EFI_STATUS Status;
2804 PCI_TYPE00 Pci;
2805 UINT8 Device;
2806 UINT32 Register;
2807 UINT8 Func;
2808 UINT64 Address;
2809 UINT8 SecondaryBus;
2810 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2811
2812 PciRootBridgeIo = Bridge->PciRootBridgeIo;
2813
2814 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
2815 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
2816
2817 //
2818 // Check to see whether a pci device is present
2819 //
2820 Status = PciDevicePresent (
2821 PciRootBridgeIo,
2822 &Pci,
2823 StartBusNumber,
2824 Device,
2825 Func
2826 );
2827
2828 if (EFI_ERROR (Status) && Func == 0) {
2829 //
2830 // go to next device if there is no Function 0
2831 //
2832 break;
2833 }
2834
2835 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {
2836
2837 Register = 0;
2838 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
2839 Status = PciRootBridgeIo->Pci.Read (
2840 PciRootBridgeIo,
2841 EfiPciWidthUint32,
2842 Address,
2843 1,
2844 &Register
2845 );
2846 SecondaryBus = (UINT8)(Register >> 8);
2847
2848 if (SecondaryBus != 0) {
2849 ResetAllPpbBusNumber (Bridge, SecondaryBus);
2850 }
2851
2852 //
2853 // Reset register 18h, 19h, 1Ah on PCI Bridge
2854 //
2855 Register &= 0xFF000000;
2856 Status = PciRootBridgeIo->Pci.Write (
2857 PciRootBridgeIo,
2858 EfiPciWidthUint32,
2859 Address,
2860 1,
2861 &Register
2862 );
2863 }
2864
2865 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
2866 //
2867 // Skip sub functions, this is not a multi function device
2868 //
2869 Func = PCI_MAX_FUNC;
2870 }
2871 }
2872 }
2873 }
2874