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