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