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