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