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