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