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