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