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