]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
9e7ac74eb70c331f56c57f035953435fce8b877f
[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 - 2014, 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 }
1774 return Offset + 4;
1775 }
1776
1777 //
1778 // Fix the length to support some spefic 64 bit BAR
1779 //
1780 Value |= ((UINT32)(-1) << HighBitSet32 (Value));
1781
1782 //
1783 // Calculate the size of 64bit bar
1784 //
1785 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);
1786
1787 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
1788 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;
1789 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
1790 //
1791 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1792 //
1793 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
1794 } else {
1795 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1796 }
1797
1798 break;
1799
1800 //
1801 // reserved
1802 //
1803 default:
1804 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1805 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1806 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
1807 //
1808 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1809 //
1810 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
1811 } else {
1812 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1813 }
1814 break;
1815 }
1816 }
1817
1818 //
1819 // Check the length again so as to keep compatible with some special bars
1820 //
1821 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1822 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1823 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1824 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1825 }
1826
1827 //
1828 // Increment number of bar
1829 //
1830 return Offset + 4;
1831 }
1832
1833 /**
1834 This routine is used to initialize the bar of a PCI device.
1835
1836 @param PciIoDevice Pci device instance.
1837
1838 @note It can be called typically when a device is going to be rejected.
1839
1840 **/
1841 VOID
1842 InitializePciDevice (
1843 IN PCI_IO_DEVICE *PciIoDevice
1844 )
1845 {
1846 EFI_PCI_IO_PROTOCOL *PciIo;
1847 UINT8 Offset;
1848
1849 PciIo = &(PciIoDevice->PciIo);
1850
1851 //
1852 // Put all the resource apertures
1853 // Resource base is set to all ones so as to indicate its resource
1854 // has not been alloacted
1855 //
1856 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
1857 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);
1858 }
1859 }
1860
1861 /**
1862 This routine is used to initialize the bar of a PCI-PCI Bridge device.
1863
1864 @param PciIoDevice PCI-PCI bridge device instance.
1865
1866 **/
1867 VOID
1868 InitializePpb (
1869 IN PCI_IO_DEVICE *PciIoDevice
1870 )
1871 {
1872 EFI_PCI_IO_PROTOCOL *PciIo;
1873
1874 PciIo = &(PciIoDevice->PciIo);
1875
1876 //
1877 // Put all the resource apertures including IO16
1878 // Io32, pMem32, pMem64 to quiescent state
1879 // Resource base all ones, Resource limit all zeros
1880 //
1881 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
1882 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);
1883
1884 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);
1885 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);
1886
1887 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);
1888 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);
1889
1890 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);
1891 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);
1892
1893 //
1894 // Don't support use io32 as for now
1895 //
1896 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);
1897 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);
1898
1899 //
1900 // Force Interrupt line to zero for cards that come up randomly
1901 //
1902 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
1903 }
1904
1905 /**
1906 This routine is used to initialize the bar of a PCI Card Bridge device.
1907
1908 @param PciIoDevice PCI Card bridge device.
1909
1910 **/
1911 VOID
1912 InitializeP2C (
1913 IN PCI_IO_DEVICE *PciIoDevice
1914 )
1915 {
1916 EFI_PCI_IO_PROTOCOL *PciIo;
1917
1918 PciIo = &(PciIoDevice->PciIo);
1919
1920 //
1921 // Put all the resource apertures including IO16
1922 // Io32, pMem32, pMem64 to quiescent state(
1923 // Resource base all ones, Resource limit all zeros
1924 //
1925 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);
1926 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);
1927
1928 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);
1929 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);
1930
1931 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);
1932 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);
1933
1934 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);
1935 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);
1936
1937 //
1938 // Force Interrupt line to zero for cards that come up randomly
1939 //
1940 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
1941 }
1942
1943 /**
1944 Create and initiliaze general PCI I/O device instance for
1945 PCI device/bridge device/hotplug bridge device.
1946
1947 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1948 @param Pci Input Pci information block.
1949 @param Bus Device Bus NO.
1950 @param Device Device device NO.
1951 @param Func Device func NO.
1952
1953 @return Instance of PCI device. NULL means no instance created.
1954
1955 **/
1956 PCI_IO_DEVICE *
1957 CreatePciIoDevice (
1958 IN PCI_IO_DEVICE *Bridge,
1959 IN PCI_TYPE00 *Pci,
1960 IN UINT8 Bus,
1961 IN UINT8 Device,
1962 IN UINT8 Func
1963 )
1964 {
1965 PCI_IO_DEVICE *PciIoDevice;
1966 EFI_PCI_IO_PROTOCOL *PciIo;
1967 EFI_STATUS Status;
1968
1969 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
1970 if (PciIoDevice == NULL) {
1971 return NULL;
1972 }
1973
1974 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;
1975 PciIoDevice->Handle = NULL;
1976 PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;
1977 PciIoDevice->DevicePath = NULL;
1978 PciIoDevice->BusNumber = Bus;
1979 PciIoDevice->DeviceNumber = Device;
1980 PciIoDevice->FunctionNumber = Func;
1981 PciIoDevice->Decodes = 0;
1982
1983 if (gFullEnumeration) {
1984 PciIoDevice->Allocated = FALSE;
1985 } else {
1986 PciIoDevice->Allocated = TRUE;
1987 }
1988
1989 PciIoDevice->Registered = FALSE;
1990 PciIoDevice->Attributes = 0;
1991 PciIoDevice->Supports = 0;
1992 PciIoDevice->BusOverride = FALSE;
1993 PciIoDevice->AllOpRomProcessed = FALSE;
1994
1995 PciIoDevice->IsPciExp = FALSE;
1996
1997 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));
1998
1999 //
2000 // Initialize the PCI I/O instance structure
2001 //
2002 InitializePciIoInstance (PciIoDevice);
2003 InitializePciDriverOverrideInstance (PciIoDevice);
2004 InitializePciLoadFile2 (PciIoDevice);
2005 PciIo = &PciIoDevice->PciIo;
2006
2007 //
2008 // Create a device path for this PCI device and store it into its private data
2009 //
2010 CreatePciDevicePath (
2011 Bridge->DevicePath,
2012 PciIoDevice
2013 );
2014
2015 //
2016 // Detect if PCI Express Device
2017 //
2018 PciIoDevice->PciExpressCapabilityOffset = 0;
2019 Status = LocateCapabilityRegBlock (
2020 PciIoDevice,
2021 EFI_PCI_CAPABILITY_ID_PCIEXP,
2022 &PciIoDevice->PciExpressCapabilityOffset,
2023 NULL
2024 );
2025 if (!EFI_ERROR (Status)) {
2026 PciIoDevice->IsPciExp = TRUE;
2027 }
2028
2029 if (PcdGetBool (PcdAriSupport)) {
2030 //
2031 // Check if the device is an ARI device.
2032 //
2033 Status = LocatePciExpressCapabilityRegBlock (
2034 PciIoDevice,
2035 EFI_PCIE_CAPABILITY_ID_ARI,
2036 &PciIoDevice->AriCapabilityOffset,
2037 NULL
2038 );
2039 if (!EFI_ERROR (Status)) {
2040 //
2041 // We need to enable ARI feature before calculate BusReservation,
2042 // because FirstVFOffset and VFStride may change after that.
2043 //
2044 EFI_PCI_IO_PROTOCOL *ParentPciIo;
2045 UINT32 Data32;
2046
2047 //
2048 // Check if its parent supports ARI forwarding.
2049 //
2050 ParentPciIo = &Bridge->PciIo;
2051 ParentPciIo->Pci.Read (
2052 ParentPciIo,
2053 EfiPciIoWidthUint32,
2054 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,
2055 1,
2056 &Data32
2057 );
2058 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {
2059 //
2060 // ARI forward support in bridge, so enable it.
2061 //
2062 ParentPciIo->Pci.Read (
2063 ParentPciIo,
2064 EfiPciIoWidthUint32,
2065 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
2066 1,
2067 &Data32
2068 );
2069 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {
2070 Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;
2071 ParentPciIo->Pci.Write (
2072 ParentPciIo,
2073 EfiPciIoWidthUint32,
2074 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,
2075 1,
2076 &Data32
2077 );
2078 DEBUG ((
2079 EFI_D_INFO,
2080 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n",
2081 Bridge->BusNumber,
2082 Bridge->DeviceNumber,
2083 Bridge->FunctionNumber
2084 ));
2085 }
2086 }
2087
2088 DEBUG ((EFI_D_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset));
2089 }
2090 }
2091
2092 //
2093 // Initialization for SR-IOV
2094 //
2095
2096 if (PcdGetBool (PcdSrIovSupport)) {
2097 Status = LocatePciExpressCapabilityRegBlock (
2098 PciIoDevice,
2099 EFI_PCIE_CAPABILITY_ID_SRIOV,
2100 &PciIoDevice->SrIovCapabilityOffset,
2101 NULL
2102 );
2103 if (!EFI_ERROR (Status)) {
2104 UINT32 SupportedPageSize;
2105 UINT16 VFStride;
2106 UINT16 FirstVFOffset;
2107 UINT16 Data16;
2108 UINT32 PFRid;
2109 UINT32 LastVF;
2110
2111 //
2112 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.
2113 //
2114 if (PcdGetBool (PcdAriSupport) && PciIoDevice->AriCapabilityOffset != 0) {
2115 PciIo->Pci.Read (
2116 PciIo,
2117 EfiPciIoWidthUint16,
2118 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,
2119 1,
2120 &Data16
2121 );
2122 Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;
2123 PciIo->Pci.Write (
2124 PciIo,
2125 EfiPciIoWidthUint16,
2126 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,
2127 1,
2128 &Data16
2129 );
2130 }
2131
2132 //
2133 // Calculate SystemPageSize
2134 //
2135
2136 PciIo->Pci.Read (
2137 PciIo,
2138 EfiPciIoWidthUint32,
2139 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,
2140 1,
2141 &SupportedPageSize
2142 );
2143 PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize);
2144 ASSERT (PciIoDevice->SystemPageSize != 0);
2145
2146 PciIo->Pci.Write (
2147 PciIo,
2148 EfiPciIoWidthUint32,
2149 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,
2150 1,
2151 &PciIoDevice->SystemPageSize
2152 );
2153 //
2154 // Adjust SystemPageSize for Alignment usage later
2155 //
2156 PciIoDevice->SystemPageSize <<= 12;
2157
2158 //
2159 // Calculate BusReservation for PCI IOV
2160 //
2161
2162 //
2163 // Read First FirstVFOffset, InitialVFs, and VFStride
2164 //
2165 PciIo->Pci.Read (
2166 PciIo,
2167 EfiPciIoWidthUint16,
2168 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,
2169 1,
2170 &FirstVFOffset
2171 );
2172 PciIo->Pci.Read (
2173 PciIo,
2174 EfiPciIoWidthUint16,
2175 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,
2176 1,
2177 &PciIoDevice->InitialVFs
2178 );
2179 PciIo->Pci.Read (
2180 PciIo,
2181 EfiPciIoWidthUint16,
2182 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,
2183 1,
2184 &VFStride
2185 );
2186 //
2187 // Calculate LastVF
2188 //
2189 PFRid = EFI_PCI_RID(Bus, Device, Func);
2190 LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;
2191
2192 //
2193 // Calculate ReservedBusNum for this PF
2194 //
2195 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);
2196
2197 DEBUG ((
2198 EFI_D_INFO,
2199 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n",
2200 SupportedPageSize, PciIoDevice->SystemPageSize >> 12, FirstVFOffset
2201 ));
2202 DEBUG ((
2203 EFI_D_INFO,
2204 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n",
2205 PciIoDevice->InitialVFs, PciIoDevice->ReservedBusNum, PciIoDevice->SrIovCapabilityOffset
2206 ));
2207 }
2208 }
2209
2210 if (PcdGetBool (PcdMrIovSupport)) {
2211 Status = LocatePciExpressCapabilityRegBlock (
2212 PciIoDevice,
2213 EFI_PCIE_CAPABILITY_ID_MRIOV,
2214 &PciIoDevice->MrIovCapabilityOffset,
2215 NULL
2216 );
2217 if (!EFI_ERROR (Status)) {
2218 DEBUG ((EFI_D_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset));
2219 }
2220 }
2221
2222 //
2223 // Initialize the reserved resource list
2224 //
2225 InitializeListHead (&PciIoDevice->ReservedResourceList);
2226
2227 //
2228 // Initialize the driver list
2229 //
2230 InitializeListHead (&PciIoDevice->OptionRomDriverList);
2231
2232 //
2233 // Initialize the child list
2234 //
2235 InitializeListHead (&PciIoDevice->ChildList);
2236
2237 return PciIoDevice;
2238 }
2239
2240 /**
2241 This routine is used to enumerate entire pci bus system
2242 in a given platform.
2243
2244 It is only called on the second start on the same Root Bridge.
2245
2246 @param Controller Parent bridge handler.
2247
2248 @retval EFI_SUCCESS PCI enumeration finished successfully.
2249 @retval other Some error occurred when enumerating the pci bus system.
2250
2251 **/
2252 EFI_STATUS
2253 PciEnumeratorLight (
2254 IN EFI_HANDLE Controller
2255 )
2256 {
2257
2258 EFI_STATUS Status;
2259 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2260 PCI_IO_DEVICE *RootBridgeDev;
2261 UINT16 MinBus;
2262 UINT16 MaxBus;
2263 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
2264
2265 MinBus = 0;
2266 MaxBus = PCI_MAX_BUS;
2267 Descriptors = NULL;
2268
2269 //
2270 // If this root bridge has been already enumerated, then return successfully
2271 //
2272 if (GetRootBridgeByHandle (Controller) != NULL) {
2273 return EFI_SUCCESS;
2274 }
2275
2276 //
2277 // Open pci root bridge io protocol
2278 //
2279 Status = gBS->OpenProtocol (
2280 Controller,
2281 &gEfiPciRootBridgeIoProtocolGuid,
2282 (VOID **) &PciRootBridgeIo,
2283 gPciBusDriverBinding.DriverBindingHandle,
2284 Controller,
2285 EFI_OPEN_PROTOCOL_BY_DRIVER
2286 );
2287 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
2288 return Status;
2289 }
2290
2291 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
2292
2293 if (EFI_ERROR (Status)) {
2294 return Status;
2295 }
2296
2297 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {
2298
2299 //
2300 // Create a device node for root bridge device with a NULL host bridge controller handle
2301 //
2302 RootBridgeDev = CreateRootBridge (Controller);
2303
2304 if (RootBridgeDev == NULL) {
2305 Descriptors++;
2306 continue;
2307 }
2308
2309 //
2310 // Record the root bridgeio protocol
2311 //
2312 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
2313
2314 Status = PciPciDeviceInfoCollector (
2315 RootBridgeDev,
2316 (UINT8) MinBus
2317 );
2318
2319 if (!EFI_ERROR (Status)) {
2320
2321 //
2322 // Remove those PCI devices which are rejected when full enumeration
2323 //
2324 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);
2325
2326 //
2327 // Process option rom light
2328 //
2329 ProcessOptionRomLight (RootBridgeDev);
2330
2331 //
2332 // Determine attributes for all devices under this root bridge
2333 //
2334 DetermineDeviceAttribute (RootBridgeDev);
2335
2336 //
2337 // If successfully, insert the node into device pool
2338 //
2339 InsertRootBridge (RootBridgeDev);
2340 } else {
2341
2342 //
2343 // If unsuccessly, destroy the entire node
2344 //
2345 DestroyRootBridge (RootBridgeDev);
2346 }
2347
2348 Descriptors++;
2349 }
2350
2351 return EFI_SUCCESS;
2352 }
2353
2354 /**
2355 Get bus range from PCI resource descriptor list.
2356
2357 @param Descriptors A pointer to the address space descriptor.
2358 @param MinBus The min bus returned.
2359 @param MaxBus The max bus returned.
2360 @param BusRange The bus range returned.
2361
2362 @retval EFI_SUCCESS Successfully got bus range.
2363 @retval EFI_NOT_FOUND Can not find the specific bus.
2364
2365 **/
2366 EFI_STATUS
2367 PciGetBusRange (
2368 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,
2369 OUT UINT16 *MinBus,
2370 OUT UINT16 *MaxBus,
2371 OUT UINT16 *BusRange
2372 )
2373 {
2374 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {
2375 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
2376 if (MinBus != NULL) {
2377 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;
2378 }
2379
2380 if (MaxBus != NULL) {
2381 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;
2382 }
2383
2384 if (BusRange != NULL) {
2385 *BusRange = (UINT16) (*Descriptors)->AddrLen;
2386 }
2387
2388 return EFI_SUCCESS;
2389 }
2390
2391 (*Descriptors)++;
2392 }
2393
2394 return EFI_NOT_FOUND;
2395 }
2396
2397 /**
2398 This routine can be used to start the root bridge.
2399
2400 @param RootBridgeDev Pci device instance.
2401
2402 @retval EFI_SUCCESS This device started.
2403 @retval other Failed to get PCI Root Bridge I/O protocol.
2404
2405 **/
2406 EFI_STATUS
2407 StartManagingRootBridge (
2408 IN PCI_IO_DEVICE *RootBridgeDev
2409 )
2410 {
2411 EFI_HANDLE RootBridgeHandle;
2412 EFI_STATUS Status;
2413 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2414
2415 //
2416 // Get the root bridge handle
2417 //
2418 RootBridgeHandle = RootBridgeDev->Handle;
2419 PciRootBridgeIo = NULL;
2420
2421 //
2422 // Get the pci root bridge io protocol
2423 //
2424 Status = gBS->OpenProtocol (
2425 RootBridgeHandle,
2426 &gEfiPciRootBridgeIoProtocolGuid,
2427 (VOID **) &PciRootBridgeIo,
2428 gPciBusDriverBinding.DriverBindingHandle,
2429 RootBridgeHandle,
2430 EFI_OPEN_PROTOCOL_BY_DRIVER
2431 );
2432
2433 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
2434 return Status;
2435 }
2436
2437 //
2438 // Store the PciRootBridgeIo protocol into root bridge private data
2439 //
2440 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
2441
2442 return EFI_SUCCESS;
2443
2444 }
2445
2446 /**
2447 This routine can be used to check whether a PCI device should be rejected when light enumeration.
2448
2449 @param PciIoDevice Pci device instance.
2450
2451 @retval TRUE This device should be rejected.
2452 @retval FALSE This device shouldn't be rejected.
2453
2454 **/
2455 BOOLEAN
2456 IsPciDeviceRejected (
2457 IN PCI_IO_DEVICE *PciIoDevice
2458 )
2459 {
2460 EFI_STATUS Status;
2461 UINT32 TestValue;
2462 UINT32 OldValue;
2463 UINT32 Mask;
2464 UINT8 BarOffset;
2465
2466 //
2467 // PPB should be skip!
2468 //
2469 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
2470 return FALSE;
2471 }
2472
2473 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
2474 //
2475 // Only test base registers for P2C
2476 //
2477 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {
2478
2479 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
2480 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2481 if (EFI_ERROR (Status)) {
2482 continue;
2483 }
2484
2485 TestValue = TestValue & Mask;
2486 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2487 //
2488 // The bar isn't programed, so it should be rejected
2489 //
2490 return TRUE;
2491 }
2492 }
2493
2494 return FALSE;
2495 }
2496
2497 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {
2498 //
2499 // Test PCI devices
2500 //
2501 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2502 if (EFI_ERROR (Status)) {
2503 continue;
2504 }
2505
2506 if ((TestValue & 0x01) != 0) {
2507
2508 //
2509 // IO Bar
2510 //
2511 Mask = 0xFFFFFFFC;
2512 TestValue = TestValue & Mask;
2513 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2514 return TRUE;
2515 }
2516
2517 } else {
2518
2519 //
2520 // Mem Bar
2521 //
2522 Mask = 0xFFFFFFF0;
2523 TestValue = TestValue & Mask;
2524
2525 if ((TestValue & 0x07) == 0x04) {
2526
2527 //
2528 // Mem64 or PMem64
2529 //
2530 BarOffset += sizeof (UINT32);
2531 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2532
2533 //
2534 // Test its high 32-Bit BAR
2535 //
2536 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2537 if (TestValue == OldValue) {
2538 return TRUE;
2539 }
2540 }
2541
2542 } else {
2543
2544 //
2545 // Mem32 or PMem32
2546 //
2547 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2548 return TRUE;
2549 }
2550 }
2551 }
2552 }
2553
2554 return FALSE;
2555 }
2556
2557 /**
2558 Reset all bus number from specific bridge.
2559
2560 @param Bridge Parent specific bridge.
2561 @param StartBusNumber Start bus number.
2562
2563 **/
2564 VOID
2565 ResetAllPpbBusNumber (
2566 IN PCI_IO_DEVICE *Bridge,
2567 IN UINT8 StartBusNumber
2568 )
2569 {
2570 EFI_STATUS Status;
2571 PCI_TYPE00 Pci;
2572 UINT8 Device;
2573 UINT32 Register;
2574 UINT8 Func;
2575 UINT64 Address;
2576 UINT8 SecondaryBus;
2577 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2578
2579 PciRootBridgeIo = Bridge->PciRootBridgeIo;
2580
2581 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
2582 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
2583
2584 //
2585 // Check to see whether a pci device is present
2586 //
2587 Status = PciDevicePresent (
2588 PciRootBridgeIo,
2589 &Pci,
2590 StartBusNumber,
2591 Device,
2592 Func
2593 );
2594
2595 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {
2596
2597 Register = 0;
2598 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
2599 Status = PciRootBridgeIo->Pci.Read (
2600 PciRootBridgeIo,
2601 EfiPciWidthUint32,
2602 Address,
2603 1,
2604 &Register
2605 );
2606 SecondaryBus = (UINT8)(Register >> 8);
2607
2608 if (SecondaryBus != 0) {
2609 ResetAllPpbBusNumber (Bridge, SecondaryBus);
2610 }
2611
2612 //
2613 // Reset register 18h, 19h, 1Ah on PCI Bridge
2614 //
2615 Register &= 0xFF000000;
2616 Status = PciRootBridgeIo->Pci.Write (
2617 PciRootBridgeIo,
2618 EfiPciWidthUint32,
2619 Address,
2620 1,
2621 &Register
2622 );
2623 }
2624
2625 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
2626 //
2627 // Skip sub functions, this is not a multi function device
2628 //
2629 Func = PCI_MAX_FUNC;
2630 }
2631 }
2632 }
2633 }
2634