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