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