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