]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
Retired PciIncompatibleDeviceSupportLib from IntelFrameworkModulePkg.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciEnumeratorSupport.c
1 /** @file
2 PCI emumeration support functions implementation for PCI Bus module.
3
4 Copyright (c) 2006 - 2009, Intel Corporation
5 All rights reserved. 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 return PciIoDevice;
371 }
372
373 /**
374 Create PCI device instance for PCI-PCI bridge.
375
376 @param Bridge Parent bridge instance.
377 @param Pci Input PCI device information block.
378 @param Bus PCI device Bus NO.
379 @param Device PCI device Device NO.
380 @param Func PCI device's func NO.
381
382 @return Created PCI device instance.
383
384 **/
385 PCI_IO_DEVICE *
386 GatherPpbInfo (
387 IN PCI_IO_DEVICE *Bridge,
388 IN PCI_TYPE00 *Pci,
389 IN UINT8 Bus,
390 IN UINT8 Device,
391 IN UINT8 Func
392 )
393 {
394 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
395 PCI_IO_DEVICE *PciIoDevice;
396 EFI_STATUS Status;
397 UINT8 Value;
398 EFI_PCI_IO_PROTOCOL *PciIo;
399 UINT8 Temp;
400
401 PciRootBridgeIo = Bridge->PciRootBridgeIo;
402 PciIoDevice = CreatePciIoDevice (
403 PciRootBridgeIo,
404 Pci,
405 Bus,
406 Device,
407 Func
408 );
409
410 if (PciIoDevice == NULL) {
411 return NULL;
412 }
413
414 //
415 // Create a device path for this PCI device and store it into its private data
416 //
417 CreatePciDevicePath (
418 Bridge->DevicePath,
419 PciIoDevice
420 );
421
422 if (gFullEnumeration) {
423 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
424
425 //
426 // Initalize the bridge control register
427 //
428 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);
429
430 }
431
432 //
433 // PPB can have two BARs
434 //
435 if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {
436 //
437 // Not 64-bit bar
438 //
439 PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);
440 }
441
442 PciIo = &PciIoDevice->PciIo;
443
444 //
445 // Test whether it support 32 decode or not
446 //
447 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
448 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
449 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
450 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
451
452 if (Value != 0) {
453 if ((Value & 0x01) != 0) {
454 PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;
455 } else {
456 PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
457 }
458 }
459
460 Status = BarExisted (
461 PciIoDevice,
462 0x24,
463 NULL,
464 NULL
465 );
466
467 //
468 // Test if it supports 64 memory or not
469 //
470 if (!EFI_ERROR (Status)) {
471
472 Status = BarExisted (
473 PciIoDevice,
474 0x28,
475 NULL,
476 NULL
477 );
478
479 if (!EFI_ERROR (Status)) {
480 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
481 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
482 } else {
483 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
484 }
485 }
486
487 //
488 // Memory 32 code is required for ppb
489 //
490 PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;
491
492 GetResourcePaddingPpb (PciIoDevice);
493
494 return PciIoDevice;
495 }
496
497
498 /**
499 Create PCI device instance for PCI Card bridge device.
500
501 @param Bridge Parent bridge instance.
502 @param Pci Input PCI device information block.
503 @param Bus PCI device Bus NO.
504 @param Device PCI device Device NO.
505 @param Func PCI device's func NO.
506
507 @return Created PCI device instance.
508
509 **/
510 PCI_IO_DEVICE *
511 GatherP2CInfo (
512 IN PCI_IO_DEVICE *Bridge,
513 IN PCI_TYPE00 *Pci,
514 IN UINT8 Bus,
515 IN UINT8 Device,
516 IN UINT8 Func
517 )
518 {
519 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
520 PCI_IO_DEVICE *PciIoDevice;
521
522 PciRootBridgeIo = Bridge->PciRootBridgeIo;
523 PciIoDevice = CreatePciIoDevice (
524 PciRootBridgeIo,
525 Pci,
526 Bus,
527 Device,
528 Func
529 );
530
531 if (PciIoDevice == NULL) {
532 return NULL;
533 }
534
535 //
536 // Create a device path for this PCI device and store it into its private data
537 //
538 CreatePciDevicePath (
539 Bridge->DevicePath,
540 PciIoDevice
541 );
542
543 if (gFullEnumeration) {
544 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
545
546 //
547 // Initalize the bridge control register
548 //
549 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);
550 }
551
552 //
553 // P2C only has one bar that is in 0x10
554 //
555 PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);
556
557 //
558 // Read PciBar information from the bar register
559 //
560 GetBackPcCardBar (PciIoDevice);
561 PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED |
562 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |
563 EFI_BRIDGE_IO32_DECODE_SUPPORTED;
564
565 return PciIoDevice;
566 }
567
568 /**
569 Create device path for pci deivce.
570
571 @param ParentDevicePath Parent bridge's path.
572 @param PciIoDevice Pci device instance.
573
574 @return Device path protocol instance for specific pci device.
575
576 **/
577 EFI_DEVICE_PATH_PROTOCOL *
578 CreatePciDevicePath (
579 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
580 IN PCI_IO_DEVICE *PciIoDevice
581 )
582 {
583
584 PCI_DEVICE_PATH PciNode;
585
586 //
587 // Create PCI device path
588 //
589 PciNode.Header.Type = HARDWARE_DEVICE_PATH;
590 PciNode.Header.SubType = HW_PCI_DP;
591 SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));
592
593 PciNode.Device = PciIoDevice->DeviceNumber;
594 PciNode.Function = PciIoDevice->FunctionNumber;
595 PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);
596
597 return PciIoDevice->DevicePath;
598 }
599
600 /**
601 Check whether the bar is existed or not.
602
603 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
604 @param Offset The offset.
605 @param BarLengthValue The bar length value returned.
606 @param OriginalBarValue The original bar value returned.
607
608 @retval EFI_NOT_FOUND The bar doesn't exist.
609 @retval EFI_SUCCESS The bar exist.
610
611 **/
612 EFI_STATUS
613 BarExisted (
614 IN PCI_IO_DEVICE *PciIoDevice,
615 IN UINTN Offset,
616 OUT UINT32 *BarLengthValue,
617 OUT UINT32 *OriginalBarValue
618 )
619 {
620 EFI_PCI_IO_PROTOCOL *PciIo;
621 UINT32 OriginalValue;
622 UINT32 Value;
623 EFI_TPL OldTpl;
624
625 PciIo = &PciIoDevice->PciIo;
626
627 //
628 // Preserve the original value
629 //
630 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);
631
632 //
633 // Raise TPL to high level to disable timer interrupt while the BAR is probed
634 //
635 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
636
637 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne);
638 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value);
639
640 //
641 // Write back the original value
642 //
643 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);
644
645 //
646 // Restore TPL to its original level
647 //
648 gBS->RestoreTPL (OldTpl);
649
650 if (BarLengthValue != NULL) {
651 *BarLengthValue = Value;
652 }
653
654 if (OriginalBarValue != NULL) {
655 *OriginalBarValue = OriginalValue;
656 }
657
658 if (Value == 0) {
659 return EFI_NOT_FOUND;
660 } else {
661 return EFI_SUCCESS;
662 }
663 }
664
665 /**
666 Test whether the device can support given attributes.
667
668 @param PciIoDevice Pci device instance.
669 @param Command Input command register value, and
670 returned supported register value.
671 @param BridgeControl Inout bridge control value for PPB or P2C, and
672 returned supported bridge control value.
673 @param OldCommand Returned and stored old command register offset.
674 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
675
676 **/
677 VOID
678 PciTestSupportedAttribute (
679 IN PCI_IO_DEVICE *PciIoDevice,
680 IN OUT UINT16 *Command,
681 IN OUT UINT16 *BridgeControl,
682 OUT UINT16 *OldCommand,
683 OUT UINT16 *OldBridgeControl
684 )
685 {
686 EFI_TPL OldTpl;
687
688 //
689 // Preserve the original value
690 //
691 PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);
692
693 //
694 // Raise TPL to high level to disable timer interrupt while the BAR is probed
695 //
696 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
697
698 PCI_SET_COMMAND_REGISTER (PciIoDevice, *Command);
699 PCI_READ_COMMAND_REGISTER (PciIoDevice, Command);
700
701 //
702 // Write back the original value
703 //
704 PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);
705
706 //
707 // Restore TPL to its original level
708 //
709 gBS->RestoreTPL (OldTpl);
710
711 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
712
713 //
714 // Preserve the original value
715 //
716 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);
717
718 //
719 // Raise TPL to high level to disable timer interrupt while the BAR is probed
720 //
721 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
722
723 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);
724 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
725
726 //
727 // Write back the original value
728 //
729 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);
730
731 //
732 // Restore TPL to its original level
733 //
734 gBS->RestoreTPL (OldTpl);
735
736 } else {
737 *OldBridgeControl = 0;
738 *BridgeControl = 0;
739 }
740 }
741
742 /**
743 Set the supported or current attributes of a PCI device.
744
745 @param PciIoDevice Structure pointer for PCI device.
746 @param Command Command register value.
747 @param BridgeControl Bridge control value for PPB or P2C.
748 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
749
750 **/
751 VOID
752 PciSetDeviceAttribute (
753 IN PCI_IO_DEVICE *PciIoDevice,
754 IN UINT16 Command,
755 IN UINT16 BridgeControl,
756 IN UINTN Option
757 )
758 {
759 UINT64 Attributes;
760
761 Attributes = 0;
762
763 if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {
764 Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;
765 }
766
767 if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {
768 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;
769 }
770
771 if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {
772 Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;
773 }
774
775 if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
776 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
777 }
778
779 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {
780 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
781 }
782
783 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {
784 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
785 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
786 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
787 }
788
789 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {
790 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;
791 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;
792 }
793
794 if (Option == EFI_SET_SUPPORTS) {
795
796 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |
797 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |
798 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |
799 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
800 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
801 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
802
803 if ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) != 0) {
804 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
805 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
806 }
807
808 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
809 //
810 // For bridge, it should support IDE attributes
811 //
812 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
813 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
814 } else {
815
816 if (IS_PCI_IDE (&PciIoDevice->Pci)) {
817 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
818 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
819 }
820
821 if (IS_PCI_VGA (&PciIoDevice->Pci)) {
822 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
823 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
824 }
825 }
826
827 PciIoDevice->Supports = Attributes;
828 PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \
829 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \
830 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );
831
832 } else {
833 PciIoDevice->Attributes = Attributes;
834 }
835 }
836
837 /**
838 Determine if the device can support Fast Back to Back attribute.
839
840 @param PciIoDevice Pci device instance.
841 @param StatusIndex Status register value.
842
843 @retval EFI_SUCCESS This device support Fast Back to Back attribute.
844 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
845
846 **/
847 EFI_STATUS
848 GetFastBackToBackSupport (
849 IN PCI_IO_DEVICE *PciIoDevice,
850 IN UINT8 StatusIndex
851 )
852 {
853 EFI_PCI_IO_PROTOCOL *PciIo;
854 EFI_STATUS Status;
855 UINT32 StatusRegister;
856
857 //
858 // Read the status register
859 //
860 PciIo = &PciIoDevice->PciIo;
861 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);
862 if (EFI_ERROR (Status)) {
863 return EFI_UNSUPPORTED;
864 }
865
866 //
867 // Check the Fast B2B bit
868 //
869 if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {
870 return EFI_SUCCESS;
871 } else {
872 return EFI_UNSUPPORTED;
873 }
874 }
875
876 /**
877 Process the option ROM for all the children of the specified parent PCI device.
878 It can only be used after the first full Option ROM process.
879
880 @param PciIoDevice Pci device instance.
881
882 **/
883 VOID
884 ProcessOptionRomLight (
885 IN PCI_IO_DEVICE *PciIoDevice
886 )
887 {
888 PCI_IO_DEVICE *Temp;
889 LIST_ENTRY *CurrentLink;
890
891 //
892 // For RootBridge, PPB , P2C, go recursively to traverse all its children
893 //
894 CurrentLink = PciIoDevice->ChildList.ForwardLink;
895 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
896
897 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
898
899 if (!IsListEmpty (&Temp->ChildList)) {
900 ProcessOptionRomLight (Temp);
901 }
902
903 PciRomGetImageMapping (Temp);
904
905 //
906 // The OpRom has already been processed in the first round
907 //
908 Temp->AllOpRomProcessed = TRUE;
909
910 CurrentLink = CurrentLink->ForwardLink;
911 }
912 }
913
914 /**
915 Determine the related attributes of all devices under a Root Bridge.
916
917 @param PciIoDevice PCI device instance.
918
919 **/
920 EFI_STATUS
921 DetermineDeviceAttribute (
922 IN PCI_IO_DEVICE *PciIoDevice
923 )
924 {
925 UINT16 Command;
926 UINT16 BridgeControl;
927 UINT16 OldCommand;
928 UINT16 OldBridgeControl;
929 BOOLEAN FastB2BSupport;
930 PCI_IO_DEVICE *Temp;
931 LIST_ENTRY *CurrentLink;
932 EFI_STATUS Status;
933
934 //
935 // For Root Bridge, just copy it by RootBridgeIo proctocol
936 // so as to keep consistent with the actual attribute
937 //
938 if (PciIoDevice->Parent == NULL) {
939 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
940 PciIoDevice->PciRootBridgeIo,
941 &PciIoDevice->Supports,
942 &PciIoDevice->Attributes
943 );
944 if (EFI_ERROR (Status)) {
945 return Status;
946 }
947 } else {
948
949 //
950 // Set the attributes to be checked for common PCI devices and PPB or P2C
951 // Since some devices only support part of them, it is better to set the
952 // attribute according to its command or bridge control register
953 //
954 Command = EFI_PCI_COMMAND_IO_SPACE |
955 EFI_PCI_COMMAND_MEMORY_SPACE |
956 EFI_PCI_COMMAND_BUS_MASTER |
957 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
958
959 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;
960
961 //
962 // Test whether the device can support attributes above
963 //
964 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);
965
966 //
967 // Set the supported attributes for specified PCI device
968 //
969 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);
970
971 //
972 // Set the current attributes for specified PCI device
973 //
974 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);
975
976 //
977 // Enable other supported attributes but not defined in PCI_IO_PROTOCOL
978 //
979 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);
980 }
981
982 FastB2BSupport = TRUE;
983
984 //
985 // P2C can not support FB2B on the secondary side
986 //
987 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
988 FastB2BSupport = FALSE;
989 }
990
991 //
992 // For RootBridge, PPB , P2C, go recursively to traverse all its children
993 //
994 CurrentLink = PciIoDevice->ChildList.ForwardLink;
995 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
996
997 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
998 Status = DetermineDeviceAttribute (Temp);
999 if (EFI_ERROR (Status)) {
1000 return Status;
1001 }
1002 //
1003 // Detect Fast Bact to Bact support for the device under the bridge
1004 //
1005 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);
1006 if (FastB2BSupport && EFI_ERROR (Status)) {
1007 FastB2BSupport = FALSE;
1008 }
1009
1010 CurrentLink = CurrentLink->ForwardLink;
1011 }
1012 //
1013 // Set or clear Fast Back to Back bit for the whole bridge
1014 //
1015 if (!IsListEmpty (&PciIoDevice->ChildList)) {
1016
1017 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
1018
1019 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);
1020
1021 if (EFI_ERROR (Status) || (!FastB2BSupport)) {
1022 FastB2BSupport = FALSE;
1023 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
1024 } else {
1025 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
1026 }
1027 }
1028
1029 CurrentLink = PciIoDevice->ChildList.ForwardLink;
1030 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
1031 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1032 if (FastB2BSupport) {
1033 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
1034 } else {
1035 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
1036 }
1037
1038 CurrentLink = CurrentLink->ForwardLink;
1039 }
1040 }
1041 //
1042 // End for IsListEmpty
1043 //
1044 return EFI_SUCCESS;
1045 }
1046
1047 /**
1048 This routine is used to update the bar information for those incompatible PCI device.
1049
1050 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
1051 Bar information.
1052
1053 @retval EFI_SUCCESS Successfully updated bar information.
1054 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
1055
1056 **/
1057 EFI_STATUS
1058 UpdatePciInfo (
1059 IN OUT PCI_IO_DEVICE *PciIoDevice
1060 )
1061 {
1062 EFI_STATUS Status;
1063 UINTN BarIndex;
1064 UINTN BarEndIndex;
1065 BOOLEAN SetFlag;
1066 VOID *Configuration;
1067 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
1068
1069 Configuration = NULL;
1070 Status = EFI_SUCCESS;
1071
1072 if (gEfiIncompatiblePciDeviceSupport == NULL) {
1073 //
1074 // It can only be supported after the Incompatible PCI Device
1075 // Support Protocol has been installed
1076 //
1077 Status = gBS->LocateProtocol (
1078 &gEfiIncompatiblePciDeviceSupportProtocolGuid,
1079 NULL,
1080 (VOID **) &gEfiIncompatiblePciDeviceSupport
1081 );
1082 }
1083 if (Status == EFI_SUCCESS) {
1084 //
1085 // Check whether the device belongs to incompatible devices from protocol or not
1086 // If it is , then get its special requirement in the ACPI table
1087 //
1088 Status = gEfiIncompatiblePciDeviceSupport->CheckDevice (
1089 gEfiIncompatiblePciDeviceSupport,
1090 PciIoDevice->Pci.Hdr.VendorId,
1091 PciIoDevice->Pci.Hdr.DeviceId,
1092 PciIoDevice->Pci.Hdr.RevisionID,
1093 PciIoDevice->Pci.Device.SubsystemVendorID,
1094 PciIoDevice->Pci.Device.SubsystemID,
1095 &Configuration
1096 );
1097
1098 }
1099
1100 if (EFI_ERROR (Status) || Configuration == NULL ) {
1101 return EFI_UNSUPPORTED;
1102 }
1103
1104 //
1105 // Update PCI device information from the ACPI table
1106 //
1107 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
1108
1109 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {
1110
1111 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
1112 //
1113 // The format is not support
1114 //
1115 break;
1116 }
1117
1118 BarIndex = (UINTN) Ptr->AddrTranslationOffset;
1119 BarEndIndex = BarIndex;
1120
1121 //
1122 // Update all the bars in the device
1123 //
1124 if (BarIndex == PCI_BAR_ALL) {
1125 BarIndex = 0;
1126 BarEndIndex = PCI_MAX_BAR - 1;
1127 }
1128
1129 if (BarIndex >= PCI_MAX_BAR) {
1130 Ptr++;
1131 continue;
1132 }
1133
1134 for (; BarIndex <= BarEndIndex; BarIndex++) {
1135 SetFlag = FALSE;
1136 switch (Ptr->ResType) {
1137 case ACPI_ADDRESS_SPACE_TYPE_MEM:
1138
1139 //
1140 // Make sure the bar is memory type
1141 //
1142 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {
1143 SetFlag = TRUE;
1144 }
1145 break;
1146
1147 case ACPI_ADDRESS_SPACE_TYPE_IO:
1148
1149 //
1150 // Make sure the bar is IO type
1151 //
1152 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {
1153 SetFlag = TRUE;
1154 }
1155 break;
1156 }
1157
1158 if (SetFlag) {
1159
1160 //
1161 // Update the new alignment for the device
1162 //
1163 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);
1164
1165 //
1166 // Update the new length for the device
1167 //
1168 if (Ptr->AddrLen != PCI_BAR_NOCHANGE) {
1169 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;
1170 }
1171 }
1172 }
1173
1174 Ptr++;
1175 }
1176
1177 FreePool (Configuration);
1178
1179 return EFI_SUCCESS;
1180 }
1181
1182 /**
1183 This routine will update the alignment with the new alignment.
1184
1185 @param Alignment Input Old alignment. Output updated alignment.
1186 @param NewAlignment New alignment.
1187
1188 **/
1189 VOID
1190 SetNewAlign (
1191 IN OUT UINT64 *Alignment,
1192 IN UINT64 NewAlignment
1193 )
1194 {
1195 UINT64 OldAlignment;
1196 UINTN ShiftBit;
1197
1198 //
1199 // The new alignment is the same as the original,
1200 // so skip it
1201 //
1202 if (NewAlignment == PCI_BAR_OLD_ALIGN) {
1203 return ;
1204 }
1205 //
1206 // Check the validity of the parameter
1207 //
1208 if (NewAlignment != PCI_BAR_EVEN_ALIGN &&
1209 NewAlignment != PCI_BAR_SQUAD_ALIGN &&
1210 NewAlignment != PCI_BAR_DQUAD_ALIGN ) {
1211 *Alignment = NewAlignment;
1212 return ;
1213 }
1214
1215 OldAlignment = (*Alignment) + 1;
1216 ShiftBit = 0;
1217
1218 //
1219 // Get the first non-zero hex value of the length
1220 //
1221 while ((OldAlignment & 0x0F) == 0x00) {
1222 OldAlignment = RShiftU64 (OldAlignment, 4);
1223 ShiftBit += 4;
1224 }
1225
1226 //
1227 // Adjust the alignment to even, quad or double quad boundary
1228 //
1229 if (NewAlignment == PCI_BAR_EVEN_ALIGN) {
1230 if ((OldAlignment & 0x01) != 0) {
1231 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);
1232 }
1233 } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {
1234 if ((OldAlignment & 0x03) != 0) {
1235 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);
1236 }
1237 } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {
1238 if ((OldAlignment & 0x07) != 0) {
1239 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);
1240 }
1241 }
1242
1243 //
1244 // Update the old value
1245 //
1246 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;
1247 *Alignment = NewAlignment;
1248
1249 return ;
1250 }
1251
1252 /**
1253 Parse PCI bar information and fill them into PCI device instance.
1254
1255 @param PciIoDevice Pci device instance.
1256 @param Offset Bar offset.
1257 @param BarIndex Bar index.
1258
1259 @return Next bar offset.
1260
1261 **/
1262 UINTN
1263 PciParseBar (
1264 IN PCI_IO_DEVICE *PciIoDevice,
1265 IN UINTN Offset,
1266 IN UINTN BarIndex
1267 )
1268 {
1269 UINT32 Value;
1270 UINT32 OriginalValue;
1271 UINT32 Mask;
1272 UINT32 Data;
1273 UINT8 Index;
1274 EFI_STATUS Status;
1275
1276 OriginalValue = 0;
1277 Value = 0;
1278
1279 Status = BarExisted (
1280 PciIoDevice,
1281 Offset,
1282 &Value,
1283 &OriginalValue
1284 );
1285
1286 if (EFI_ERROR (Status)) {
1287 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1288 PciIoDevice->PciBar[BarIndex].Length = 0;
1289 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1290
1291 //
1292 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
1293 //
1294 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
1295 return Offset + 4;
1296 }
1297
1298 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
1299 if ((Value & 0x01) != 0) {
1300 //
1301 // Device I/Os
1302 //
1303 Mask = 0xfffffffc;
1304
1305 if ((Value & 0xFFFF0000) != 0) {
1306 //
1307 // It is a IO32 bar
1308 //
1309 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;
1310 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);
1311 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1312
1313 } else {
1314 //
1315 // It is a IO16 bar
1316 //
1317 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;
1318 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);
1319 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1320
1321 }
1322 //
1323 // Workaround. Some platforms inplement IO bar with 0 length
1324 // Need to treat it as no-bar
1325 //
1326 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1327 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;
1328 }
1329
1330 PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;
1331 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1332
1333 } else {
1334
1335 Mask = 0xfffffff0;
1336
1337 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1338
1339 switch (Value & 0x07) {
1340
1341 //
1342 //memory space; anywhere in 32 bit address space
1343 //
1344 case 0x00:
1345 if ((Value & 0x08) != 0) {
1346 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
1347 } else {
1348 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
1349 }
1350
1351 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1352 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1353
1354 break;
1355
1356 //
1357 // memory space; anywhere in 64 bit address space
1358 //
1359 case 0x04:
1360 if ((Value & 0x08) != 0) {
1361 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;
1362 } else {
1363 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;
1364 }
1365
1366 //
1367 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1368 // is regarded as an extension for the first bar. As a result
1369 // the sizing will be conducted on combined 64 bit value
1370 // Here just store the masked first 32bit value for future size
1371 // calculation
1372 //
1373 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;
1374 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1375
1376 //
1377 // Increment the offset to point to next DWORD
1378 //
1379 Offset += 4;
1380
1381 Status = BarExisted (
1382 PciIoDevice,
1383 Offset,
1384 &Value,
1385 &OriginalValue
1386 );
1387
1388 if (EFI_ERROR (Status)) {
1389 return Offset + 4;
1390 }
1391
1392 //
1393 // Fix the length to support some spefic 64 bit BAR
1394 //
1395 Data = Value;
1396 Index = 0;
1397 for (Data = Value; Data != 0; Data >>= 1) {
1398 Index ++;
1399 }
1400 Value |= ((UINT32)(-1) << Index);
1401
1402 //
1403 // Calculate the size of 64bit bar
1404 //
1405 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);
1406
1407 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
1408 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;
1409 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1410
1411 break;
1412
1413 //
1414 // reserved
1415 //
1416 default:
1417 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1418 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1419 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1420
1421 break;
1422 }
1423 }
1424
1425 //
1426 // Check the length again so as to keep compatible with some special bars
1427 //
1428 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1429 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1430 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1431 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1432 }
1433
1434 //
1435 // Increment number of bar
1436 //
1437 return Offset + 4;
1438 }
1439
1440 /**
1441 This routine is used to initialize the bar of a PCI device.
1442
1443 @param PciIoDevice Pci device instance.
1444
1445 @note It can be called typically when a device is going to be rejected.
1446
1447 **/
1448 VOID
1449 InitializePciDevice (
1450 IN PCI_IO_DEVICE *PciIoDevice
1451 )
1452 {
1453 EFI_PCI_IO_PROTOCOL *PciIo;
1454 UINT8 Offset;
1455
1456 PciIo = &(PciIoDevice->PciIo);
1457
1458 //
1459 // Put all the resource apertures
1460 // Resource base is set to all ones so as to indicate its resource
1461 // has not been alloacted
1462 //
1463 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
1464 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);
1465 }
1466 }
1467
1468 /**
1469 This routine is used to initialize the bar of a PCI-PCI Bridge device.
1470
1471 @param PciIoDevice PCI-PCI bridge device instance.
1472
1473 **/
1474 VOID
1475 InitializePpb (
1476 IN PCI_IO_DEVICE *PciIoDevice
1477 )
1478 {
1479 EFI_PCI_IO_PROTOCOL *PciIo;
1480
1481 PciIo = &(PciIoDevice->PciIo);
1482
1483 //
1484 // Put all the resource apertures including IO16
1485 // Io32, pMem32, pMem64 to quiescent state
1486 // Resource base all ones, Resource limit all zeros
1487 //
1488 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
1489 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);
1490
1491 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);
1492 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);
1493
1494 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);
1495 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);
1496
1497 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);
1498 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);
1499
1500 //
1501 // Don't support use io32 as for now
1502 //
1503 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);
1504 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);
1505
1506 //
1507 // Force Interrupt line to zero for cards that come up randomly
1508 //
1509 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
1510 }
1511
1512 /**
1513 This routine is used to initialize the bar of a PCI Card Bridge device.
1514
1515 @param PciIoDevice PCI Card bridge device.
1516
1517 **/
1518 VOID
1519 InitializeP2C (
1520 IN PCI_IO_DEVICE *PciIoDevice
1521 )
1522 {
1523 EFI_PCI_IO_PROTOCOL *PciIo;
1524
1525 PciIo = &(PciIoDevice->PciIo);
1526
1527 //
1528 // Put all the resource apertures including IO16
1529 // Io32, pMem32, pMem64 to quiescent state(
1530 // Resource base all ones, Resource limit all zeros
1531 //
1532 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);
1533 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);
1534
1535 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);
1536 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);
1537
1538 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);
1539 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);
1540
1541 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);
1542 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);
1543
1544 //
1545 // Force Interrupt line to zero for cards that come up randomly
1546 //
1547 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
1548 }
1549
1550 /**
1551 Create and initiliaze general PCI I/O device instance for
1552 PCI device/bridge device/hotplug bridge device.
1553
1554 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1555 @param Pci Input Pci information block.
1556 @param Bus Device Bus NO.
1557 @param Device Device device NO.
1558 @param Func Device func NO.
1559
1560 @return Instance of PCI device. NULL means no instance created.
1561
1562 **/
1563 PCI_IO_DEVICE *
1564 CreatePciIoDevice (
1565 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
1566 IN PCI_TYPE00 *Pci,
1567 IN UINT8 Bus,
1568 IN UINT8 Device,
1569 IN UINT8 Func
1570 )
1571 {
1572 PCI_IO_DEVICE *PciIoDevice;
1573
1574 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
1575 if (PciIoDevice == NULL) {
1576 return NULL;
1577 }
1578
1579 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;
1580 PciIoDevice->Handle = NULL;
1581 PciIoDevice->PciRootBridgeIo = PciRootBridgeIo;
1582 PciIoDevice->DevicePath = NULL;
1583 PciIoDevice->BusNumber = Bus;
1584 PciIoDevice->DeviceNumber = Device;
1585 PciIoDevice->FunctionNumber = Func;
1586 PciIoDevice->Decodes = 0;
1587
1588 if (gFullEnumeration) {
1589 PciIoDevice->Allocated = FALSE;
1590 } else {
1591 PciIoDevice->Allocated = TRUE;
1592 }
1593
1594 PciIoDevice->Registered = FALSE;
1595 PciIoDevice->Attributes = 0;
1596 PciIoDevice->Supports = 0;
1597 PciIoDevice->BusOverride = FALSE;
1598 PciIoDevice->AllOpRomProcessed = FALSE;
1599
1600 PciIoDevice->IsPciExp = FALSE;
1601
1602 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));
1603
1604 //
1605 // Initialize the PCI I/O instance structure
1606 //
1607 InitializePciIoInstance (PciIoDevice);
1608 InitializePciDriverOverrideInstance (PciIoDevice);
1609 InitializePciLoadFile2 (PciIoDevice);
1610
1611 //
1612 // Initialize the reserved resource list
1613 //
1614 InitializeListHead (&PciIoDevice->ReservedResourceList);
1615
1616 //
1617 // Initialize the driver list
1618 //
1619 InitializeListHead (&PciIoDevice->OptionRomDriverList);
1620
1621 //
1622 // Initialize the child list
1623 //
1624 InitializeListHead (&PciIoDevice->ChildList);
1625
1626 return PciIoDevice;
1627 }
1628
1629 /**
1630 This routine is used to enumerate entire pci bus system
1631 in a given platform.
1632
1633 It is only called on the second start on the same Root Bridge.
1634
1635 @param Controller Parent bridge handler.
1636
1637 @retval EFI_SUCCESS PCI enumeration finished successfully.
1638 @retval other Some error occurred when enumerating the pci bus system.
1639
1640 **/
1641 EFI_STATUS
1642 PciEnumeratorLight (
1643 IN EFI_HANDLE Controller
1644 )
1645 {
1646
1647 EFI_STATUS Status;
1648 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1649 PCI_IO_DEVICE *RootBridgeDev;
1650 UINT16 MinBus;
1651 UINT16 MaxBus;
1652 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
1653
1654 MinBus = 0;
1655 MaxBus = PCI_MAX_BUS;
1656 Descriptors = NULL;
1657
1658 //
1659 // If this root bridge has been already enumerated, then return successfully
1660 //
1661 if (GetRootBridgeByHandle (Controller) != NULL) {
1662 return EFI_SUCCESS;
1663 }
1664
1665 //
1666 // Open pci root bridge io protocol
1667 //
1668 Status = gBS->OpenProtocol (
1669 Controller,
1670 &gEfiPciRootBridgeIoProtocolGuid,
1671 (VOID **) &PciRootBridgeIo,
1672 gPciBusDriverBinding.DriverBindingHandle,
1673 Controller,
1674 EFI_OPEN_PROTOCOL_BY_DRIVER
1675 );
1676 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
1677 return Status;
1678 }
1679
1680 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
1681
1682 if (EFI_ERROR (Status)) {
1683 return Status;
1684 }
1685
1686 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {
1687
1688 //
1689 // Create a device node for root bridge device with a NULL host bridge controller handle
1690 //
1691 RootBridgeDev = CreateRootBridge (Controller);
1692
1693 if (RootBridgeDev == NULL) {
1694 Descriptors++;
1695 continue;
1696 }
1697
1698 //
1699 // Record the root bridgeio protocol
1700 //
1701 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
1702
1703 Status = PciPciDeviceInfoCollector (
1704 RootBridgeDev,
1705 (UINT8) MinBus
1706 );
1707
1708 if (!EFI_ERROR (Status)) {
1709
1710 //
1711 // Remove those PCI devices which are rejected when full enumeration
1712 //
1713 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);
1714
1715 //
1716 // Process option rom light
1717 //
1718 ProcessOptionRomLight (RootBridgeDev);
1719
1720 //
1721 // Determine attributes for all devices under this root bridge
1722 //
1723 DetermineDeviceAttribute (RootBridgeDev);
1724
1725 //
1726 // If successfully, insert the node into device pool
1727 //
1728 InsertRootBridge (RootBridgeDev);
1729 } else {
1730
1731 //
1732 // If unsuccessly, destroy the entire node
1733 //
1734 DestroyRootBridge (RootBridgeDev);
1735 }
1736
1737 Descriptors++;
1738 }
1739
1740 return EFI_SUCCESS;
1741 }
1742
1743 /**
1744 Get bus range from PCI resource descriptor list.
1745
1746 @param Descriptors A pointer to the address space descriptor.
1747 @param MinBus The min bus returned.
1748 @param MaxBus The max bus returned.
1749 @param BusRange The bus range returned.
1750
1751 @retval EFI_SUCCESS Successfully got bus range.
1752 @retval EFI_NOT_FOUND Can not find the specific bus.
1753
1754 **/
1755 EFI_STATUS
1756 PciGetBusRange (
1757 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,
1758 OUT UINT16 *MinBus,
1759 OUT UINT16 *MaxBus,
1760 OUT UINT16 *BusRange
1761 )
1762 {
1763 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {
1764 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
1765 if (MinBus != NULL) {
1766 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;
1767 }
1768
1769 if (MaxBus != NULL) {
1770 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;
1771 }
1772
1773 if (BusRange != NULL) {
1774 *BusRange = (UINT16) (*Descriptors)->AddrLen;
1775 }
1776
1777 return EFI_SUCCESS;
1778 }
1779
1780 (*Descriptors)++;
1781 }
1782
1783 return EFI_NOT_FOUND;
1784 }
1785
1786 /**
1787 This routine can be used to start the root bridge.
1788
1789 @param RootBridgeDev Pci device instance.
1790
1791 @retval EFI_SUCCESS This device started.
1792 @retval other Failed to get PCI Root Bridge I/O protocol.
1793
1794 **/
1795 EFI_STATUS
1796 StartManagingRootBridge (
1797 IN PCI_IO_DEVICE *RootBridgeDev
1798 )
1799 {
1800 EFI_HANDLE RootBridgeHandle;
1801 EFI_STATUS Status;
1802 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1803
1804 //
1805 // Get the root bridge handle
1806 //
1807 RootBridgeHandle = RootBridgeDev->Handle;
1808 PciRootBridgeIo = NULL;
1809
1810 //
1811 // Get the pci root bridge io protocol
1812 //
1813 Status = gBS->OpenProtocol (
1814 RootBridgeHandle,
1815 &gEfiPciRootBridgeIoProtocolGuid,
1816 (VOID **) &PciRootBridgeIo,
1817 gPciBusDriverBinding.DriverBindingHandle,
1818 RootBridgeHandle,
1819 EFI_OPEN_PROTOCOL_BY_DRIVER
1820 );
1821
1822 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
1823 return Status;
1824 }
1825
1826 //
1827 // Store the PciRootBridgeIo protocol into root bridge private data
1828 //
1829 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
1830
1831 return EFI_SUCCESS;
1832
1833 }
1834
1835 /**
1836 This routine can be used to check whether a PCI device should be rejected when light enumeration.
1837
1838 @param PciIoDevice Pci device instance.
1839
1840 @retval TRUE This device should be rejected.
1841 @retval FALSE This device shouldn't be rejected.
1842
1843 **/
1844 BOOLEAN
1845 IsPciDeviceRejected (
1846 IN PCI_IO_DEVICE *PciIoDevice
1847 )
1848 {
1849 EFI_STATUS Status;
1850 UINT32 TestValue;
1851 UINT32 OldValue;
1852 UINT32 Mask;
1853 UINT8 BarOffset;
1854
1855 //
1856 // PPB should be skip!
1857 //
1858 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
1859 return FALSE;
1860 }
1861
1862 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
1863 //
1864 // Only test base registers for P2C
1865 //
1866 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {
1867
1868 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
1869 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
1870 if (EFI_ERROR (Status)) {
1871 continue;
1872 }
1873
1874 TestValue = TestValue & Mask;
1875 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
1876 //
1877 // The bar isn't programed, so it should be rejected
1878 //
1879 return TRUE;
1880 }
1881 }
1882
1883 return FALSE;
1884 }
1885
1886 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {
1887 //
1888 // Test PCI devices
1889 //
1890 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
1891 if (EFI_ERROR (Status)) {
1892 continue;
1893 }
1894
1895 if ((TestValue & 0x01) != 0) {
1896
1897 //
1898 // IO Bar
1899 //
1900 Mask = 0xFFFFFFFC;
1901 TestValue = TestValue & Mask;
1902 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
1903 return TRUE;
1904 }
1905
1906 } else {
1907
1908 //
1909 // Mem Bar
1910 //
1911 Mask = 0xFFFFFFF0;
1912 TestValue = TestValue & Mask;
1913
1914 if ((TestValue & 0x07) == 0x04) {
1915
1916 //
1917 // Mem64 or PMem64
1918 //
1919 BarOffset += sizeof (UINT32);
1920 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
1921
1922 //
1923 // Test its high 32-Bit BAR
1924 //
1925 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
1926 if (TestValue == OldValue) {
1927 return TRUE;
1928 }
1929 }
1930
1931 } else {
1932
1933 //
1934 // Mem32 or PMem32
1935 //
1936 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
1937 return TRUE;
1938 }
1939 }
1940 }
1941 }
1942
1943 return FALSE;
1944 }
1945
1946 /**
1947 Reset all bus number from specific bridge.
1948
1949 @param Bridge Parent specific bridge.
1950 @param StartBusNumber Start bus number.
1951
1952 **/
1953 VOID
1954 ResetAllPpbBusNumber (
1955 IN PCI_IO_DEVICE *Bridge,
1956 IN UINT8 StartBusNumber
1957 )
1958 {
1959 EFI_STATUS Status;
1960 PCI_TYPE00 Pci;
1961 UINT8 Device;
1962 UINT32 Register;
1963 UINT8 Func;
1964 UINT64 Address;
1965 UINT8 SecondaryBus;
1966 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1967
1968 PciRootBridgeIo = Bridge->PciRootBridgeIo;
1969
1970 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
1971 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
1972
1973 //
1974 // Check to see whether a pci device is present
1975 //
1976 Status = PciDevicePresent (
1977 PciRootBridgeIo,
1978 &Pci,
1979 StartBusNumber,
1980 Device,
1981 Func
1982 );
1983
1984 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {
1985
1986 Register = 0;
1987 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
1988 Status = PciRootBridgeIo->Pci.Read (
1989 PciRootBridgeIo,
1990 EfiPciWidthUint32,
1991 Address,
1992 1,
1993 &Register
1994 );
1995 SecondaryBus = (UINT8)(Register >> 8);
1996
1997 if (SecondaryBus != 0) {
1998 ResetAllPpbBusNumber (Bridge, SecondaryBus);
1999 }
2000
2001 //
2002 // Reset register 18h, 19h, 1Ah on PCI Bridge
2003 //
2004 Register &= 0xFF000000;
2005 Status = PciRootBridgeIo->Pci.Write (
2006 PciRootBridgeIo,
2007 EfiPciWidthUint32,
2008 Address,
2009 1,
2010 &Register
2011 );
2012 }
2013
2014 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
2015 //
2016 // Skip sub functions, this is not a multi function device
2017 //
2018 Func = PCI_MAX_FUNC;
2019 }
2020 }
2021 }
2022 }
2023