]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Bus/Pci/PciBus/Dxe/PciEnumeratorSupport.c
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1459 6f19259b...
[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 PciSetCommandRegister (PciIoDevice, 0);
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 PciSetCommandRegister (PciIoDevice, 0);
466
467 //
468 // Initalize the bridge control register
469 //
470 PciSetBridgeControlRegister (PciIoDevice, 0);
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 PciSetCommandRegister (PciIoDevice, 0);
590
591 //
592 // Initalize the bridge control register
593 //
594 PciSetBridgeControlRegister (PciIoDevice, 0);
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 (Option == EFI_SET_SUPPORTS) {
875
876 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |
877 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |
878 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |
879 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
880 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
881 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
882
883 if (Attributes & EFI_PCI_IO_ATTRIBUTE_IO) {
884 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
885 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
886 }
887
888 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
889 //
890 // For bridge, it should support IDE attributes
891 //
892 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
893 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
894 } else {
895
896 if (IS_PCI_IDE (&PciIoDevice->Pci)) {
897 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
898 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
899 }
900
901 if (IS_PCI_VGA (&PciIoDevice->Pci)) {
902 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
903 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
904 }
905 }
906
907 PciIoDevice->Supports = Attributes;
908 PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \
909 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \
910 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );
911
912 } else {
913 PciIoDevice->Attributes = Attributes;
914 }
915
916 return EFI_SUCCESS;
917 }
918
919 EFI_STATUS
920 GetFastBackToBackSupport (
921 IN PCI_IO_DEVICE *PciIoDevice,
922 IN UINT8 StatusIndex
923 )
924 /*++
925
926 Routine Description:
927
928 Determine if the device can support Fast Back to Back attribute
929
930 Arguments:
931
932 Returns:
933
934 None
935
936 --*/
937 // TODO: PciIoDevice - add argument and description to function comment
938 // TODO: StatusIndex - add argument and description to function comment
939 // TODO: EFI_UNSUPPORTED - add return value to function comment
940 // TODO: EFI_SUCCESS - add return value to function comment
941 // TODO: EFI_UNSUPPORTED - add return value to function comment
942 {
943 EFI_PCI_IO_PROTOCOL *PciIo;
944 EFI_STATUS Status;
945 UINT32 StatusRegister;
946
947 //
948 // Read the status register
949 //
950 PciIo = &PciIoDevice->PciIo;
951 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);
952 if (EFI_ERROR (Status)) {
953 return EFI_UNSUPPORTED;
954 }
955
956 //
957 // Check the Fast B2B bit
958 //
959 if (StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) {
960 return EFI_SUCCESS;
961 } else {
962 return EFI_UNSUPPORTED;
963 }
964
965 }
966
967 EFI_STATUS
968 ProcessOptionRomLight (
969 IN PCI_IO_DEVICE *PciIoDevice
970 )
971 /*++
972
973 Routine Description:
974
975 Process the option ROM for all the children of the specified parent PCI device.
976 It can only be used after the first full Option ROM process.
977
978 Arguments:
979
980 Returns:
981
982 None
983
984 --*/
985 // TODO: PciIoDevice - add argument and description to function comment
986 // TODO: EFI_SUCCESS - add return value to function comment
987 {
988 PCI_IO_DEVICE *Temp;
989 LIST_ENTRY *CurrentLink;
990
991 //
992 // For RootBridge, PPB , P2C, go recursively to traverse all its children
993 //
994 CurrentLink = PciIoDevice->ChildList.ForwardLink;
995 while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {
996
997 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
998
999 if (!IsListEmpty (&Temp->ChildList)) {
1000 ProcessOptionRomLight (Temp);
1001 }
1002
1003 PciRomGetImageMapping (Temp);
1004 CurrentLink = CurrentLink->ForwardLink;
1005 }
1006
1007 return EFI_SUCCESS;
1008 }
1009
1010 EFI_STATUS
1011 DetermineDeviceAttribute (
1012 IN PCI_IO_DEVICE *PciIoDevice
1013 )
1014 /*++
1015
1016 Routine Description:
1017
1018 Determine the related attributes of all devices under a Root Bridge
1019
1020 Arguments:
1021
1022 Returns:
1023
1024 None
1025
1026 --*/
1027 // TODO: PciIoDevice - add argument and description to function comment
1028 // TODO: EFI_SUCCESS - add return value to function comment
1029 {
1030 UINT16 Command;
1031 UINT16 BridgeControl;
1032 UINT16 OldCommand;
1033 UINT16 OldBridgeControl;
1034 BOOLEAN FastB2BSupport;
1035
1036 /*
1037 UINT8 IdePI;
1038 EFI_PCI_IO_PROTOCOL *PciIo;
1039 */
1040 PCI_IO_DEVICE *Temp;
1041 LIST_ENTRY *CurrentLink;
1042 EFI_STATUS Status;
1043
1044 //
1045 // For Root Bridge, just copy it by RootBridgeIo proctocol
1046 // so as to keep consistent with the actual attribute
1047 //
1048 if (!PciIoDevice->Parent) {
1049 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
1050 PciIoDevice->PciRootBridgeIo,
1051 &PciIoDevice->Supports,
1052 &PciIoDevice->Attributes
1053 );
1054 if (EFI_ERROR (Status)) {
1055 return Status;
1056 }
1057 } else {
1058
1059 //
1060 // Set the attributes to be checked for common PCI devices and PPB or P2C
1061 // Since some devices only support part of them, it is better to set the
1062 // attribute according to its command or bridge control register
1063 //
1064 Command = EFI_PCI_COMMAND_IO_SPACE |
1065 EFI_PCI_COMMAND_MEMORY_SPACE |
1066 EFI_PCI_COMMAND_BUS_MASTER |
1067 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1068
1069 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA;
1070
1071 //
1072 // Test whether the device can support attributes above
1073 //
1074 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);
1075
1076 //
1077 // Set the supported attributes for specified PCI device
1078 //
1079 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);
1080
1081 //
1082 // Set the current attributes for specified PCI device
1083 //
1084 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);
1085
1086 //
1087 // Enable other supported attributes but not defined in PCI_IO_PROTOCOL
1088 //
1089 PciEnableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);
1090
1091 //
1092 // Enable IDE native mode
1093 //
1094 /*
1095 if (IS_PCI_IDE(&PciIoDevice->Pci)) {
1096
1097 PciIo = &PciIoDevice->PciIo;
1098
1099 PciIo->Pci.Read (
1100 PciIo,
1101 EfiPciIoWidthUint8,
1102 0x09,
1103 1,
1104 &IdePI
1105 );
1106
1107 //
1108 // Set native mode if it can be supported
1109 //
1110 IdePI |= (((IdePI & 0x0F) >> 1) & 0x05);
1111
1112 PciIo->Pci.Write (
1113 PciIo,
1114 EfiPciIoWidthUint8,
1115 0x09,
1116 1,
1117 &IdePI
1118 );
1119
1120 }
1121 */
1122 }
1123
1124 FastB2BSupport = TRUE;
1125
1126 //
1127 // P2C can not support FB2B on the secondary side
1128 //
1129 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
1130 FastB2BSupport = FALSE;
1131 }
1132
1133 //
1134 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1135 //
1136 CurrentLink = PciIoDevice->ChildList.ForwardLink;
1137 while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {
1138
1139 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1140 Status = DetermineDeviceAttribute (Temp);
1141 if (EFI_ERROR (Status)) {
1142 return Status;
1143 }
1144 //
1145 // Detect Fast Bact to Bact support for the device under the bridge
1146 //
1147 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);
1148 if (FastB2BSupport && EFI_ERROR (Status)) {
1149 FastB2BSupport = FALSE;
1150 }
1151
1152 CurrentLink = CurrentLink->ForwardLink;
1153 }
1154 //
1155 // Set or clear Fast Back to Back bit for the whole bridge
1156 //
1157 if (!IsListEmpty (&PciIoDevice->ChildList)) {
1158
1159 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
1160
1161 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);
1162
1163 if (EFI_ERROR (Status) || (!FastB2BSupport)) {
1164 FastB2BSupport = FALSE;
1165 PciDisableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
1166 } else {
1167 PciEnableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
1168 }
1169 }
1170
1171 CurrentLink = PciIoDevice->ChildList.ForwardLink;
1172 while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {
1173 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1174 if (FastB2BSupport) {
1175 PciEnableCommandRegister (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
1176 } else {
1177 PciDisableCommandRegister (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
1178 }
1179
1180 CurrentLink = CurrentLink->ForwardLink;
1181 }
1182 }
1183 //
1184 // End for IsListEmpty
1185 //
1186 return EFI_SUCCESS;
1187 }
1188
1189 EFI_STATUS
1190 UpdatePciInfo (
1191 IN PCI_IO_DEVICE *PciIoDevice
1192 )
1193 /*++
1194
1195 Routine Description:
1196
1197 This routine is used to update the bar information for those incompatible PCI device
1198
1199 Arguments:
1200
1201 Returns:
1202
1203 None
1204
1205 --*/
1206 // TODO: PciIoDevice - add argument and description to function comment
1207 // TODO: EFI_UNSUPPORTED - add return value to function comment
1208 {
1209 EFI_STATUS Status;
1210 UINTN BarIndex;
1211 UINTN BarEndIndex;
1212 BOOLEAN SetFlag;
1213 VOID *Configuration;
1214 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
1215
1216 Configuration = NULL;
1217
1218 //
1219 // It can only be supported after the Incompatible PCI Device
1220 // Support Protocol has been installed
1221 //
1222 if (gEfiIncompatiblePciDeviceSupport == NULL) {
1223
1224 Status = gBS->LocateProtocol (
1225 &gEfiIncompatiblePciDeviceSupportProtocolGuid,
1226 NULL,
1227 (VOID **) &gEfiIncompatiblePciDeviceSupport
1228 );
1229 if (EFI_ERROR (Status)) {
1230 return EFI_UNSUPPORTED;
1231 }
1232 }
1233
1234 //
1235 // Check whether the device belongs to incompatible devices or not
1236 // If it is , then get its special requirement in the ACPI table
1237 //
1238 Status = gEfiIncompatiblePciDeviceSupport->CheckDevice (
1239 gEfiIncompatiblePciDeviceSupport,
1240 PciIoDevice->Pci.Hdr.VendorId,
1241 PciIoDevice->Pci.Hdr.DeviceId,
1242 PciIoDevice->Pci.Hdr.RevisionID,
1243 PciIoDevice->Pci.Device.SubsystemVendorID,
1244 PciIoDevice->Pci.Device.SubsystemID,
1245 &Configuration
1246 );
1247
1248 if (EFI_ERROR (Status)) {
1249 return Status;
1250 }
1251
1252 //
1253 // Update PCI device information from the ACPI table
1254 //
1255 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
1256
1257 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {
1258
1259 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
1260 //
1261 // The format is not support
1262 //
1263 break;
1264 }
1265
1266 BarIndex = (UINTN) Ptr->AddrTranslationOffset;
1267 BarEndIndex = BarIndex;
1268
1269 //
1270 // Update all the bars in the device
1271 //
1272 if (BarIndex == PCI_BAR_ALL) {
1273 BarIndex = 0;
1274 BarEndIndex = PCI_MAX_BAR - 1;
1275 }
1276
1277 if (BarIndex >= PCI_MAX_BAR) {
1278 Ptr++;
1279 continue;
1280 }
1281
1282 for (; BarIndex <= BarEndIndex; BarIndex++) {
1283 SetFlag = FALSE;
1284 switch (Ptr->ResType) {
1285 case ACPI_ADDRESS_SPACE_TYPE_MEM:
1286
1287 //
1288 // Make sure the bar is memory type
1289 //
1290 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {
1291 SetFlag = TRUE;
1292 }
1293 break;
1294
1295 case ACPI_ADDRESS_SPACE_TYPE_IO:
1296
1297 //
1298 // Make sure the bar is IO type
1299 //
1300 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {
1301 SetFlag = TRUE;
1302 }
1303 break;
1304 }
1305
1306 if (SetFlag) {
1307
1308 //
1309 // Update the new alignment for the device
1310 //
1311 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);
1312
1313 //
1314 // Update the new length for the device
1315 //
1316 if (Ptr->AddrLen != PCI_BAR_NOCHANGE) {
1317 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;
1318 }
1319 }
1320 }
1321
1322 Ptr++;
1323 }
1324
1325 gBS->FreePool (Configuration);
1326 return Status;
1327
1328 }
1329
1330 VOID
1331 SetNewAlign (
1332 IN UINT64 *Alignment,
1333 IN UINT64 NewAlignment
1334 )
1335 /*++
1336
1337 Routine Description:
1338
1339 This routine will update the alignment with the new alignment
1340
1341 Arguments:
1342
1343 Returns:
1344
1345 None
1346
1347 --*/
1348 // TODO: Alignment - add argument and description to function comment
1349 // TODO: NewAlignment - add argument and description to function comment
1350 {
1351 UINT64 OldAlignment;
1352 UINTN ShiftBit;
1353
1354 //
1355 // The new alignment is the same as the original,
1356 // so skip it
1357 //
1358 if (NewAlignment == PCI_BAR_OLD_ALIGN) {
1359 return ;
1360 }
1361 //
1362 // Check the validity of the parameter
1363 //
1364 if (NewAlignment != PCI_BAR_EVEN_ALIGN &&
1365 NewAlignment != PCI_BAR_SQUAD_ALIGN &&
1366 NewAlignment != PCI_BAR_DQUAD_ALIGN ) {
1367 *Alignment = NewAlignment;
1368 return ;
1369 }
1370
1371 OldAlignment = (*Alignment) + 1;
1372 ShiftBit = 0;
1373
1374 //
1375 // Get the first non-zero hex value of the length
1376 //
1377 while ((OldAlignment & 0x0F) == 0x00) {
1378 OldAlignment = RShiftU64 (OldAlignment, 4);
1379 ShiftBit += 4;
1380 }
1381
1382 //
1383 // Adjust the alignment to even, quad or double quad boundary
1384 //
1385 if (NewAlignment == PCI_BAR_EVEN_ALIGN) {
1386 if (OldAlignment & 0x01) {
1387 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);
1388 }
1389 } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {
1390 if (OldAlignment & 0x03) {
1391 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);
1392 }
1393 } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {
1394 if (OldAlignment & 0x07) {
1395 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);
1396 }
1397 }
1398
1399 //
1400 // Update the old value
1401 //
1402 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;
1403 *Alignment = NewAlignment;
1404
1405 return ;
1406 }
1407
1408 UINTN
1409 PciParseBar (
1410 IN PCI_IO_DEVICE *PciIoDevice,
1411 IN UINTN Offset,
1412 IN UINTN BarIndex
1413 )
1414 /*++
1415
1416 Routine Description:
1417
1418 Arguments:
1419
1420 Returns:
1421
1422 None
1423
1424 --*/
1425 // TODO: PciIoDevice - add argument and description to function comment
1426 // TODO: Offset - add argument and description to function comment
1427 // TODO: BarIndex - add argument and description to function comment
1428 {
1429 UINT32 Value;
1430 UINT64 BarValue64;
1431 UINT32 OriginalValue;
1432 UINT32 Mask;
1433 UINT32 Data;
1434 UINT8 Index;
1435 EFI_STATUS Status;
1436
1437 OriginalValue = 0;
1438 Value = 0;
1439 BarValue64 = 0;
1440
1441 Status = BarExisted (
1442 PciIoDevice,
1443 Offset,
1444 &Value,
1445 &OriginalValue
1446 );
1447
1448 if (EFI_ERROR (Status)) {
1449 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1450 PciIoDevice->PciBar[BarIndex].Length = 0;
1451 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1452
1453 //
1454 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
1455 //
1456 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
1457 return Offset + 4;
1458 }
1459
1460 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
1461 if (Value & 0x01) {
1462 //
1463 // Device I/Os
1464 //
1465 Mask = 0xfffffffc;
1466
1467 if (Value & 0xFFFF0000) {
1468 //
1469 // It is a IO32 bar
1470 //
1471 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;
1472 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);
1473 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1474
1475 } else {
1476 //
1477 // It is a IO16 bar
1478 //
1479 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;
1480 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);
1481 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1482
1483 }
1484 //
1485 // Workaround. Some platforms inplement IO bar with 0 length
1486 // Need to treat it as no-bar
1487 //
1488 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1489 PciIoDevice->PciBar[BarIndex].BarType = 0;
1490 }
1491
1492 PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;
1493 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1494
1495 } else {
1496
1497 Mask = 0xfffffff0;
1498
1499 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1500
1501 switch (Value & 0x07) {
1502
1503 //
1504 //memory space; anywhere in 32 bit address space
1505 //
1506 case 0x00:
1507 if (Value & 0x08) {
1508 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
1509 } else {
1510 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
1511 }
1512
1513 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1514 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1515
1516 break;
1517
1518 //
1519 // memory space; anywhere in 64 bit address space
1520 //
1521 case 0x04:
1522 if (Value & 0x08) {
1523 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;
1524 } else {
1525 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;
1526 }
1527
1528 //
1529 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1530 // is regarded as an extension for the first bar. As a result
1531 // the sizing will be conducted on combined 64 bit value
1532 // Here just store the masked first 32bit value for future size
1533 // calculation
1534 //
1535 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;
1536 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1537
1538 //
1539 // Increment the offset to point to next DWORD
1540 //
1541 Offset += 4;
1542
1543 Status = BarExisted (
1544 PciIoDevice,
1545 Offset,
1546 &Value,
1547 &OriginalValue
1548 );
1549
1550 if (EFI_ERROR (Status)) {
1551 return Offset + 4;
1552 }
1553
1554 //
1555 // Fix the length to support some spefic 64 bit BAR
1556 //
1557 Data = Value;
1558 Index = 0;
1559 for (Data = Value; Data != 0; Data >>= 1) {
1560 Index ++;
1561 }
1562 Value |= ((UINT32)(-1) << Index);
1563
1564 //
1565 // Calculate the size of 64bit bar
1566 //
1567 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);
1568
1569 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
1570 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;
1571 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1572
1573 break;
1574
1575 //
1576 // reserved
1577 //
1578 default:
1579 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1580 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1581 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1582
1583 break;
1584 }
1585 }
1586
1587 //
1588 // Check the length again so as to keep compatible with some special bars
1589 //
1590 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1591 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1592 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1593 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1594 }
1595
1596 //
1597 // Increment number of bar
1598 //
1599 return Offset + 4;
1600 }
1601
1602 EFI_STATUS
1603 InitializePciDevice (
1604 IN PCI_IO_DEVICE *PciIoDevice
1605 )
1606 /*++
1607
1608 Routine Description:
1609
1610 This routine is used to initialize the bar of a PCI device
1611 It can be called typically when a device is going to be rejected
1612
1613 Arguments:
1614
1615 Returns:
1616
1617 None
1618
1619 --*/
1620 // TODO: PciIoDevice - add argument and description to function comment
1621 // TODO: EFI_SUCCESS - add return value to function comment
1622 {
1623 EFI_PCI_IO_PROTOCOL *PciIo;
1624 UINT8 Offset;
1625
1626 PciIo = &(PciIoDevice->PciIo);
1627
1628 //
1629 // Put all the resource apertures
1630 // Resource base is set to all ones so as to indicate its resource
1631 // has not been alloacted
1632 //
1633 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
1634 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);
1635 }
1636
1637 return EFI_SUCCESS;
1638 }
1639
1640 EFI_STATUS
1641 InitializePpb (
1642 IN PCI_IO_DEVICE *PciIoDevice
1643 )
1644 /*++
1645
1646 Routine Description:
1647
1648 Arguments:
1649
1650 Returns:
1651
1652 None
1653
1654 --*/
1655 // TODO: PciIoDevice - add argument and description to function comment
1656 // TODO: EFI_SUCCESS - add return value to function comment
1657 {
1658 EFI_PCI_IO_PROTOCOL *PciIo;
1659
1660 PciIo = &(PciIoDevice->PciIo);
1661
1662 //
1663 // Put all the resource apertures including IO16
1664 // Io32, pMem32, pMem64 to quiescent state
1665 // Resource base all ones, Resource limit all zeros
1666 //
1667 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
1668 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);
1669
1670 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);
1671 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);
1672
1673 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);
1674 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);
1675
1676 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);
1677 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);
1678
1679 //
1680 // don't support use io32 as for now
1681 //
1682 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);
1683 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);
1684
1685 //
1686 // Force Interrupt line to zero for cards that come up randomly
1687 //
1688 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
1689
1690 return EFI_SUCCESS;
1691 }
1692
1693 EFI_STATUS
1694 InitializeP2C (
1695 IN PCI_IO_DEVICE *PciIoDevice
1696 )
1697 /*++
1698
1699 Routine Description:
1700
1701 Arguments:
1702
1703 Returns:
1704
1705 None
1706
1707 --*/
1708 // TODO: PciIoDevice - add argument and description to function comment
1709 // TODO: EFI_SUCCESS - add return value to function comment
1710 {
1711 EFI_PCI_IO_PROTOCOL *PciIo;
1712
1713 PciIo = &(PciIoDevice->PciIo);
1714
1715 //
1716 // Put all the resource apertures including IO16
1717 // Io32, pMem32, pMem64 to quiescent state(
1718 // Resource base all ones, Resource limit all zeros
1719 //
1720 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);
1721 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);
1722
1723 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);
1724 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);
1725
1726 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);
1727 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);
1728
1729 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);
1730 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);
1731
1732 //
1733 // Force Interrupt line to zero for cards that come up randomly
1734 //
1735 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
1736 return EFI_SUCCESS;
1737 }
1738
1739 PCI_IO_DEVICE *
1740 CreatePciIoDevice (
1741 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
1742 IN PCI_TYPE00 *Pci,
1743 UINT8 Bus,
1744 UINT8 Device,
1745 UINT8 Func
1746 )
1747 /*++
1748
1749 Routine Description:
1750
1751 Arguments:
1752
1753 Returns:
1754
1755 None
1756
1757 --*/
1758 // TODO: PciRootBridgeIo - add argument and description to function comment
1759 // TODO: Pci - add argument and description to function comment
1760 // TODO: Bus - add argument and description to function comment
1761 // TODO: Device - add argument and description to function comment
1762 // TODO: Func - add argument and description to function comment
1763 {
1764
1765 EFI_STATUS Status;
1766 PCI_IO_DEVICE *PciIoDevice;
1767
1768 PciIoDevice = NULL;
1769
1770 Status = gBS->AllocatePool (
1771 EfiBootServicesData,
1772 sizeof (PCI_IO_DEVICE),
1773 (VOID **) &PciIoDevice
1774 );
1775
1776 if (EFI_ERROR (Status)) {
1777 return NULL;
1778 }
1779
1780 ZeroMem (PciIoDevice, sizeof (PCI_IO_DEVICE));
1781
1782 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;
1783 PciIoDevice->Handle = NULL;
1784 PciIoDevice->PciRootBridgeIo = PciRootBridgeIo;
1785 PciIoDevice->DevicePath = NULL;
1786 PciIoDevice->BusNumber = Bus;
1787 PciIoDevice->DeviceNumber = Device;
1788 PciIoDevice->FunctionNumber = Func;
1789 PciIoDevice->Decodes = 0;
1790 if (gFullEnumeration) {
1791 PciIoDevice->Allocated = FALSE;
1792 } else {
1793 PciIoDevice->Allocated = TRUE;
1794 }
1795
1796 PciIoDevice->Registered = FALSE;
1797 PciIoDevice->Attributes = 0;
1798 PciIoDevice->Supports = 0;
1799 PciIoDevice->BusOverride = FALSE;
1800 PciIoDevice->AllOpRomProcessed = FALSE;
1801
1802 PciIoDevice->IsPciExp = FALSE;
1803
1804 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));
1805
1806 //
1807 // Initialize the PCI I/O instance structure
1808 //
1809
1810 Status = InitializePciIoInstance (PciIoDevice);
1811 Status = InitializePciDriverOverrideInstance (PciIoDevice);
1812
1813 if (EFI_ERROR (Status)) {
1814 gBS->FreePool (PciIoDevice);
1815 return NULL;
1816 }
1817
1818 //
1819 // Initialize the reserved resource list
1820 //
1821 InitializeListHead (&PciIoDevice->ReservedResourceList);
1822
1823 //
1824 // Initialize the driver list
1825 //
1826 InitializeListHead (&PciIoDevice->OptionRomDriverList);
1827
1828 //
1829 // Initialize the child list
1830 //
1831 InitializeListHead (&PciIoDevice->ChildList);
1832
1833 return PciIoDevice;
1834 }
1835
1836 EFI_STATUS
1837 PciEnumeratorLight (
1838 IN EFI_HANDLE Controller
1839 )
1840 /*++
1841
1842 Routine Description:
1843
1844 This routine is used to enumerate entire pci bus system
1845 in a given platform
1846
1847 Arguments:
1848
1849 Returns:
1850
1851 None
1852
1853 --*/
1854 // TODO: Controller - add argument and description to function comment
1855 // TODO: EFI_SUCCESS - add return value to function comment
1856 // TODO: EFI_SUCCESS - add return value to function comment
1857 {
1858
1859 EFI_STATUS Status;
1860 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1861 PCI_IO_DEVICE *RootBridgeDev;
1862 UINT16 MinBus;
1863 UINT16 MaxBus;
1864 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
1865
1866 MinBus = 0;
1867 MaxBus = PCI_MAX_BUS;
1868 Descriptors = NULL;
1869
1870 //
1871 // If this host bridge has been already enumerated, then return successfully
1872 //
1873 if (RootBridgeExisted (Controller)) {
1874 return EFI_SUCCESS;
1875 }
1876
1877 //
1878 // Open pci root bridge io protocol
1879 //
1880 Status = gBS->OpenProtocol (
1881 Controller,
1882 &gEfiPciRootBridgeIoProtocolGuid,
1883 (VOID **) &PciRootBridgeIo,
1884 gPciBusDriverBinding.DriverBindingHandle,
1885 Controller,
1886 EFI_OPEN_PROTOCOL_BY_DRIVER
1887 );
1888 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
1889 return Status;
1890 }
1891
1892 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
1893
1894 if (EFI_ERROR (Status)) {
1895 return Status;
1896 }
1897
1898 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {
1899
1900 //
1901 // Create a device node for root bridge device with a NULL host bridge controller handle
1902 //
1903 RootBridgeDev = CreateRootBridge (Controller);
1904
1905 if (!RootBridgeDev) {
1906 Descriptors++;
1907 continue;
1908 }
1909
1910 //
1911 // Record the root bridge io protocol
1912 //
1913 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
1914
1915 Status = PciPciDeviceInfoCollector (
1916 RootBridgeDev,
1917 (UINT8) MinBus
1918 );
1919
1920 if (!EFI_ERROR (Status)) {
1921
1922 //
1923 // Remove those PCI devices which are rejected when full enumeration
1924 //
1925 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);
1926
1927 //
1928 // Process option rom light
1929 //
1930 ProcessOptionRomLight (RootBridgeDev);
1931
1932 //
1933 // Determine attributes for all devices under this root bridge
1934 //
1935 DetermineDeviceAttribute (RootBridgeDev);
1936
1937 //
1938 // If successfully, insert the node into device pool
1939 //
1940 InsertRootBridge (RootBridgeDev);
1941 } else {
1942
1943 //
1944 // If unsuccessly, destroy the entire node
1945 //
1946 DestroyRootBridge (RootBridgeDev);
1947 }
1948
1949 Descriptors++;
1950 }
1951
1952 return EFI_SUCCESS;
1953 }
1954
1955 EFI_STATUS
1956 PciGetBusRange (
1957 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,
1958 OUT UINT16 *MinBus,
1959 OUT UINT16 *MaxBus,
1960 OUT UINT16 *BusRange
1961 )
1962 /*++
1963
1964 Routine Description:
1965
1966 Get the bus range.
1967
1968 Arguments:
1969
1970 Descriptors - A pointer to the address space descriptor.
1971 MinBus - The min bus.
1972 MaxBus - The max bus.
1973 BusRange - The bus range.
1974
1975 Returns:
1976
1977 Status Code.
1978
1979 --*/
1980 // TODO: EFI_SUCCESS - add return value to function comment
1981 // TODO: EFI_NOT_FOUND - add return value to function comment
1982 {
1983
1984 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {
1985 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
1986 if (MinBus != NULL) {
1987 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;
1988 }
1989
1990 if (MaxBus != NULL) {
1991 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;
1992 }
1993
1994 if (BusRange != NULL) {
1995 *BusRange = (UINT16) (*Descriptors)->AddrLen;
1996 }
1997
1998 return EFI_SUCCESS;
1999 }
2000
2001 (*Descriptors)++;
2002 }
2003
2004 return EFI_NOT_FOUND;
2005 }
2006
2007 EFI_STATUS
2008 StartManagingRootBridge (
2009 IN PCI_IO_DEVICE *RootBridgeDev
2010 )
2011 /*++
2012
2013 Routine Description:
2014
2015
2016 Arguments:
2017
2018 Returns:
2019
2020 None
2021
2022 --*/
2023 // TODO: RootBridgeDev - add argument and description to function comment
2024 // TODO: EFI_SUCCESS - add return value to function comment
2025 {
2026 EFI_HANDLE RootBridgeHandle;
2027 EFI_STATUS Status;
2028 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2029
2030 //
2031 // Get the root bridge handle
2032 //
2033 RootBridgeHandle = RootBridgeDev->Handle;
2034 PciRootBridgeIo = NULL;
2035
2036 //
2037 // Get the pci root bridge io protocol
2038 //
2039 Status = gBS->OpenProtocol (
2040 RootBridgeHandle,
2041 &gEfiPciRootBridgeIoProtocolGuid,
2042 (VOID **) &PciRootBridgeIo,
2043 gPciBusDriverBinding.DriverBindingHandle,
2044 RootBridgeHandle,
2045 EFI_OPEN_PROTOCOL_BY_DRIVER
2046 );
2047
2048 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
2049 return Status;
2050 }
2051
2052 //
2053 // Store the PciRootBridgeIo protocol into root bridge private data
2054 //
2055 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
2056
2057 return EFI_SUCCESS;
2058
2059 }
2060
2061 BOOLEAN
2062 IsPciDeviceRejected (
2063 IN PCI_IO_DEVICE *PciIoDevice
2064 )
2065 /*++
2066
2067 Routine Description:
2068
2069 This routine can be used to check whether a PCI device should be rejected when light enumeration
2070
2071 Arguments:
2072
2073 Returns:
2074
2075 TRUE This device should be rejected
2076 FALSE This device shouldn't be rejected
2077
2078 --*/
2079 // TODO: PciIoDevice - add argument and description to function comment
2080 {
2081 EFI_STATUS Status;
2082 UINT32 TestValue;
2083 UINT32 OldValue;
2084 UINT32 Mask;
2085 UINT8 BarOffset;
2086
2087 //
2088 // PPB should be skip!
2089 //
2090 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
2091 return FALSE;
2092 }
2093
2094 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
2095 //
2096 // Only test base registers for P2C
2097 //
2098 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {
2099
2100 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
2101 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2102 if (EFI_ERROR (Status)) {
2103 continue;
2104 }
2105
2106 TestValue = TestValue & Mask;
2107 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2108 //
2109 // The bar isn't programed, so it should be rejected
2110 //
2111 return TRUE;
2112 }
2113 }
2114
2115 return FALSE;
2116 }
2117
2118 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {
2119 //
2120 // Test PCI devices
2121 //
2122 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2123 if (EFI_ERROR (Status)) {
2124 continue;
2125 }
2126
2127 if (TestValue & 0x01) {
2128
2129 //
2130 // IO Bar
2131 //
2132
2133 Mask = 0xFFFFFFFC;
2134 TestValue = TestValue & Mask;
2135 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2136 return TRUE;
2137 }
2138
2139 } else {
2140
2141 //
2142 // Mem Bar
2143 //
2144
2145 Mask = 0xFFFFFFF0;
2146 TestValue = TestValue & Mask;
2147
2148 if ((TestValue & 0x07) == 0x04) {
2149
2150 //
2151 // Mem64 or PMem64
2152 //
2153 BarOffset += sizeof (UINT32);
2154 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2155
2156 //
2157 // Test its high 32-Bit BAR
2158 //
2159
2160 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2161 if (TestValue == OldValue) {
2162 return TRUE;
2163 }
2164 }
2165
2166 } else {
2167
2168 //
2169 // Mem32 or PMem32
2170 //
2171 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2172 return TRUE;
2173 }
2174 }
2175 }
2176 }
2177
2178 return FALSE;
2179 }
2180
2181 EFI_STATUS
2182 ResetAllPpbBusReg (
2183 IN PCI_IO_DEVICE *Bridge,
2184 IN UINT8 StartBusNumber
2185 )
2186 /*++
2187
2188 Routine Description:
2189
2190 TODO: Add function description
2191
2192 Arguments:
2193
2194 Bridge - TODO: add argument description
2195 StartBusNumber - TODO: add argument description
2196
2197 Returns:
2198
2199 EFI_SUCCESS - TODO: Add description for return value
2200
2201 --*/
2202 {
2203 EFI_STATUS Status;
2204 PCI_TYPE00 Pci;
2205 UINT8 Device;
2206 UINT32 Register;
2207 UINT8 Func;
2208 UINT64 Address;
2209 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2210
2211 PciRootBridgeIo = Bridge->PciRootBridgeIo;
2212
2213 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
2214 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
2215
2216 //
2217 // Check to see whether a pci device is present
2218 //
2219 Status = PciDevicePresent (
2220 PciRootBridgeIo,
2221 &Pci,
2222 StartBusNumber,
2223 Device,
2224 Func
2225 );
2226
2227 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {
2228 Register = 0;
2229 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
2230 Status = PciRootBridgeIo->Pci.Read (
2231 PciRootBridgeIo,
2232 EfiPciWidthUint32,
2233 Address,
2234 1,
2235 &Register
2236 );
2237 //
2238 // Reset register 18h, 19h, 1Ah on PCI Bridge
2239 //
2240 Register &= 0xFF000000;
2241 Status = PciRootBridgeIo->Pci.Write (
2242 PciRootBridgeIo,
2243 EfiPciWidthUint32,
2244 Address,
2245 1,
2246 &Register
2247 );
2248 }
2249
2250 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
2251 //
2252 // Skip sub functions, this is not a multi function device
2253 //
2254 Func = PCI_MAX_FUNC;
2255 }
2256 }
2257 }
2258
2259 return EFI_SUCCESS;
2260 }
2261