]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
Fix bug: The lower 2 bits of Width and stripped, Count will always be multiplied...
[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
913 if ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) != 0) {\r
914 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;\r
915 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;\r
916 }\r
917\r
918 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
919 //\r
920 // For bridge, it should support IDE attributes\r
921 //\r
922 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
923 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
924 } else {\r
925\r
926 if (IS_PCI_IDE (&PciIoDevice->Pci)) {\r
927 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
928 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
929 }\r
930\r
931 if (IS_PCI_VGA (&PciIoDevice->Pci)) {\r
932 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
933 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;\r
934 }\r
935 }\r
936\r
937 PciIoDevice->Supports = Attributes;\r
938 PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \\r
939 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \\r
940 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );\r
941\r
942 } else {\r
943 PciIoDevice->Attributes = Attributes;\r
944 }\r
945}\r
946\r
947/**\r
948 Determine if the device can support Fast Back to Back attribute.\r
949\r
950 @param PciIoDevice Pci device instance.\r
951 @param StatusIndex Status register value.\r
952\r
953 @retval EFI_SUCCESS This device support Fast Back to Back attribute.\r
954 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.\r
955\r
956**/\r
957EFI_STATUS\r
958GetFastBackToBackSupport (\r
959 IN PCI_IO_DEVICE *PciIoDevice,\r
960 IN UINT8 StatusIndex\r
961 )\r
962{\r
963 EFI_PCI_IO_PROTOCOL *PciIo;\r
964 EFI_STATUS Status;\r
965 UINT32 StatusRegister;\r
966\r
967 //\r
968 // Read the status register\r
969 //\r
970 PciIo = &PciIoDevice->PciIo;\r
971 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);\r
972 if (EFI_ERROR (Status)) {\r
973 return EFI_UNSUPPORTED;\r
974 }\r
975\r
976 //\r
977 // Check the Fast B2B bit\r
978 //\r
979 if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {\r
980 return EFI_SUCCESS;\r
981 } else {\r
982 return EFI_UNSUPPORTED;\r
983 }\r
984}\r
985\r
986/**\r
987 Process the option ROM for all the children of the specified parent PCI device.\r
988 It can only be used after the first full Option ROM process.\r
989\r
990 @param PciIoDevice Pci device instance.\r
991\r
992**/\r
993VOID\r
994ProcessOptionRomLight (\r
995 IN PCI_IO_DEVICE *PciIoDevice\r
996 )\r
997{\r
998 PCI_IO_DEVICE *Temp;\r
999 LIST_ENTRY *CurrentLink;\r
1000\r
1001 //\r
1002 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
1003 //\r
1004 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1005 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1006\r
1007 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1008\r
1009 if (!IsListEmpty (&Temp->ChildList)) {\r
1010 ProcessOptionRomLight (Temp);\r
1011 }\r
1012\r
1013 PciRomGetImageMapping (Temp);\r
1014\r
1015 //\r
1016 // The OpRom has already been processed in the first round\r
1017 //\r
1018 Temp->AllOpRomProcessed = TRUE;\r
1019\r
1020 CurrentLink = CurrentLink->ForwardLink;\r
1021 }\r
1022}\r
1023\r
1024/**\r
1025 Determine the related attributes of all devices under a Root Bridge.\r
1026\r
1027 @param PciIoDevice PCI device instance.\r
1028\r
1029**/\r
1030EFI_STATUS\r
1031DetermineDeviceAttribute (\r
1032 IN PCI_IO_DEVICE *PciIoDevice\r
1033 )\r
1034{\r
1035 UINT16 Command;\r
1036 UINT16 BridgeControl;\r
1037 UINT16 OldCommand;\r
1038 UINT16 OldBridgeControl;\r
1039 BOOLEAN FastB2BSupport;\r
1040 PCI_IO_DEVICE *Temp;\r
1041 LIST_ENTRY *CurrentLink;\r
1042 EFI_STATUS Status;\r
1043\r
1044 //\r
1045 // For Root Bridge, just copy it by RootBridgeIo proctocol\r
1046 // so as to keep consistent with the actual attribute\r
1047 //\r
1048 if (PciIoDevice->Parent == NULL) {\r
1049 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (\r
1050 PciIoDevice->PciRootBridgeIo,\r
1051 &PciIoDevice->Supports,\r
1052 &PciIoDevice->Attributes\r
1053 );\r
1054 if (EFI_ERROR (Status)) {\r
1055 return Status;\r
1056 }\r
1057 } else {\r
1058\r
1059 //\r
1060 // Set the attributes to be checked for common PCI devices and PPB or P2C\r
1061 // Since some devices only support part of them, it is better to set the\r
1062 // attribute according to its command or bridge control register\r
1063 //\r
1064 Command = EFI_PCI_COMMAND_IO_SPACE |\r
1065 EFI_PCI_COMMAND_MEMORY_SPACE |\r
1066 EFI_PCI_COMMAND_BUS_MASTER |\r
1067 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;\r
1068\r
1069 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;\r
1070\r
1071 //\r
1072 // Test whether the device can support attributes above\r
1073 //\r
1074 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);\r
1075\r
1076 //\r
1077 // Set the supported attributes for specified PCI device\r
1078 //\r
1079 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);\r
1080\r
1081 //\r
1082 // Set the current attributes for specified PCI device\r
1083 //\r
1084 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);\r
1085\r
1086 //\r
1087 // Enable other supported attributes but not defined in PCI_IO_PROTOCOL\r
1088 //\r
1089 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);\r
1090 }\r
1091\r
1092 FastB2BSupport = TRUE;\r
1093\r
1094 //\r
1095 // P2C can not support FB2B on the secondary side\r
1096 //\r
1097 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1098 FastB2BSupport = FALSE;\r
1099 }\r
1100\r
1101 //\r
1102 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
1103 //\r
1104 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1105 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1106\r
1107 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1108 Status = DetermineDeviceAttribute (Temp);\r
1109 if (EFI_ERROR (Status)) {\r
1110 return Status;\r
1111 }\r
1112 //\r
1113 // Detect Fast Bact to Bact support for the device under the bridge\r
1114 //\r
1115 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);\r
1116 if (FastB2BSupport && EFI_ERROR (Status)) {\r
1117 FastB2BSupport = FALSE;\r
1118 }\r
1119\r
1120 CurrentLink = CurrentLink->ForwardLink;\r
1121 }\r
1122 //\r
1123 // Set or clear Fast Back to Back bit for the whole bridge\r
1124 //\r
1125 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
1126\r
1127 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
1128\r
1129 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);\r
1130\r
1131 if (EFI_ERROR (Status) || (!FastB2BSupport)) {\r
1132 FastB2BSupport = FALSE;\r
1133 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1134 } else {\r
1135 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1136 }\r
1137 }\r
1138\r
1139 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1140 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
1141 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1142 if (FastB2BSupport) {\r
1143 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1144 } else {\r
1145 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1146 }\r
1147\r
1148 CurrentLink = CurrentLink->ForwardLink;\r
1149 }\r
1150 }\r
1151 //\r
1152 // End for IsListEmpty\r
1153 //\r
1154 return EFI_SUCCESS;\r
1155}\r
1156\r
1157/**\r
1158 This routine is used to update the bar information for those incompatible PCI device.\r
1159\r
1160 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated\r
1161 Bar information.\r
1162\r
1163 @retval EFI_SUCCESS Successfully updated bar information.\r
1164 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.\r
1165\r
1166**/\r
1167EFI_STATUS\r
1168UpdatePciInfo (\r
1169 IN OUT PCI_IO_DEVICE *PciIoDevice\r
1170 )\r
1171{\r
1172 EFI_STATUS Status;\r
1173 UINTN BarIndex;\r
1174 UINTN BarEndIndex;\r
1175 BOOLEAN SetFlag;\r
1176 VOID *Configuration;\r
1177 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
1178\r
1179 Configuration = NULL;\r
1180 Status = EFI_SUCCESS;\r
1181\r
1182 if (gEfiIncompatiblePciDeviceSupport == NULL) {\r
1183 //\r
1184 // It can only be supported after the Incompatible PCI Device\r
1185 // Support Protocol has been installed\r
1186 //\r
1187 Status = gBS->LocateProtocol (\r
1188 &gEfiIncompatiblePciDeviceSupportProtocolGuid,\r
1189 NULL,\r
1190 (VOID **) &gEfiIncompatiblePciDeviceSupport\r
1191 );\r
1192 }\r
1193 if (Status == EFI_SUCCESS) {\r
1194 //\r
1195 // Check whether the device belongs to incompatible devices from protocol or not\r
1196 // If it is , then get its special requirement in the ACPI table\r
1197 //\r
1198 Status = gEfiIncompatiblePciDeviceSupport->CheckDevice (\r
1199 gEfiIncompatiblePciDeviceSupport,\r
1200 PciIoDevice->Pci.Hdr.VendorId,\r
1201 PciIoDevice->Pci.Hdr.DeviceId,\r
1202 PciIoDevice->Pci.Hdr.RevisionID,\r
1203 PciIoDevice->Pci.Device.SubsystemVendorID,\r
1204 PciIoDevice->Pci.Device.SubsystemID,\r
1205 &Configuration\r
1206 );\r
1207\r
1208 }\r
1209\r
1210 if (EFI_ERROR (Status) || Configuration == NULL ) {\r
1211 return EFI_UNSUPPORTED;\r
1212 }\r
1213\r
1214 //\r
1215 // Update PCI device information from the ACPI table\r
1216 //\r
1217 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;\r
1218\r
1219 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1220\r
1221 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
1222 //\r
1223 // The format is not support\r
1224 //\r
1225 break;\r
1226 }\r
1227\r
1228 BarIndex = (UINTN) Ptr->AddrTranslationOffset;\r
1229 BarEndIndex = BarIndex;\r
1230\r
1231 //\r
1232 // Update all the bars in the device\r
1233 //\r
1234 if (BarIndex == PCI_BAR_ALL) {\r
1235 BarIndex = 0;\r
1236 BarEndIndex = PCI_MAX_BAR - 1;\r
1237 }\r
1238\r
1239 if (BarIndex > PCI_MAX_BAR) {\r
1240 Ptr++;\r
1241 continue;\r
1242 }\r
1243\r
1244 for (; BarIndex <= BarEndIndex; BarIndex++) {\r
1245 SetFlag = FALSE;\r
1246 switch (Ptr->ResType) {\r
1247 case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
1248\r
1249 //\r
1250 // Make sure the bar is memory type\r
1251 //\r
1252 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {\r
1253 SetFlag = TRUE;\r
1254 }\r
1255 break;\r
1256\r
1257 case ACPI_ADDRESS_SPACE_TYPE_IO:\r
1258\r
1259 //\r
1260 // Make sure the bar is IO type\r
1261 //\r
1262 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {\r
1263 SetFlag = TRUE;\r
1264 }\r
1265 break;\r
1266 }\r
1267\r
1268 if (SetFlag) {\r
1269\r
1270 //\r
1271 // Update the new alignment for the device\r
1272 //\r
1273 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);\r
1274\r
1275 //\r
1276 // Update the new length for the device\r
1277 //\r
1278 if (Ptr->AddrLen != PCI_BAR_NOCHANGE) {\r
1279 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;\r
1280 }\r
1281 }\r
1282 }\r
1283\r
1284 Ptr++;\r
1285 }\r
1286\r
1287 FreePool (Configuration);\r
1288\r
1289 return EFI_SUCCESS;\r
1290}\r
1291\r
1292/**\r
1293 This routine will update the alignment with the new alignment.\r
1294\r
1295 @param Alignment Input Old alignment. Output updated alignment.\r
1296 @param NewAlignment New alignment.\r
1297\r
1298**/\r
1299VOID\r
1300SetNewAlign (\r
1301 IN OUT UINT64 *Alignment,\r
1302 IN UINT64 NewAlignment\r
1303 )\r
1304{\r
1305 UINT64 OldAlignment;\r
1306 UINTN ShiftBit;\r
1307\r
1308 //\r
1309 // The new alignment is the same as the original,\r
1310 // so skip it\r
1311 //\r
1312 if (NewAlignment == PCI_BAR_OLD_ALIGN) {\r
1313 return ;\r
1314 }\r
1315 //\r
1316 // Check the validity of the parameter\r
1317 //\r
1318 if (NewAlignment != PCI_BAR_EVEN_ALIGN &&\r
1319 NewAlignment != PCI_BAR_SQUAD_ALIGN &&\r
1320 NewAlignment != PCI_BAR_DQUAD_ALIGN ) {\r
1321 *Alignment = NewAlignment;\r
1322 return ;\r
1323 }\r
1324\r
1325 OldAlignment = (*Alignment) + 1;\r
1326 ShiftBit = 0;\r
1327\r
1328 //\r
1329 // Get the first non-zero hex value of the length\r
1330 //\r
1331 while ((OldAlignment & 0x0F) == 0x00) {\r
1332 OldAlignment = RShiftU64 (OldAlignment, 4);\r
1333 ShiftBit += 4;\r
1334 }\r
1335\r
1336 //\r
1337 // Adjust the alignment to even, quad or double quad boundary\r
1338 //\r
1339 if (NewAlignment == PCI_BAR_EVEN_ALIGN) {\r
1340 if ((OldAlignment & 0x01) != 0) {\r
1341 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);\r
1342 }\r
1343 } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {\r
1344 if ((OldAlignment & 0x03) != 0) {\r
1345 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);\r
1346 }\r
1347 } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {\r
1348 if ((OldAlignment & 0x07) != 0) {\r
1349 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);\r
1350 }\r
1351 }\r
1352\r
1353 //\r
1354 // Update the old value\r
1355 //\r
1356 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;\r
1357 *Alignment = NewAlignment;\r
1358\r
1359 return ;\r
1360}\r
1361\r
1362/**\r
1363 Parse PCI IOV VF bar information and fill them into PCI device instance.\r
1364\r
1365 @param PciIoDevice Pci device instance.\r
1366 @param Offset Bar offset.\r
1367 @param BarIndex Bar index.\r
1368\r
1369 @return Next bar offset.\r
1370\r
1371**/\r
1372UINTN\r
1373PciIovParseVfBar (\r
1374 IN PCI_IO_DEVICE *PciIoDevice,\r
1375 IN UINTN Offset,\r
1376 IN UINTN BarIndex\r
1377 )\r
1378{\r
1379 UINT32 Value;\r
1380 UINT32 OriginalValue;\r
1381 UINT32 Mask;\r
1382 UINT32 Data;\r
1383 UINT8 Index;\r
1384 EFI_STATUS Status;\r
1385\r
1386 //\r
1387 // Ensure it is called properly\r
1388 //\r
1389 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
1390 if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
1391 return 0;\r
1392 }\r
1393\r
1394 OriginalValue = 0;\r
1395 Value = 0;\r
1396\r
1397 Status = VfBarExisted (\r
1398 PciIoDevice,\r
1399 Offset,\r
1400 &Value,\r
1401 &OriginalValue\r
1402 );\r
1403\r
1404 if (EFI_ERROR (Status)) {\r
1405 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1406 PciIoDevice->VfPciBar[BarIndex].Length = 0;\r
1407 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1408\r
1409 //\r
1410 // Scan all the BARs anyway\r
1411 //\r
d4048391 1412 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;\r
9060e3ec 1413 return Offset + 4;\r
1414 }\r
1415\r
d4048391 1416 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset;\r
aa75dfec 1417 if ((Value & 0x01) != 0) {\r
9060e3ec 1418 //\r
1419 // Device I/Os. Impossible\r
1420 //\r
1421 ASSERT (FALSE);\r
1422 return Offset + 4;\r
1423\r
1424 } else {\r
1425\r
1426 Mask = 0xfffffff0;\r
1427\r
1428 PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1429\r
1430 switch (Value & 0x07) {\r
1431\r
1432 //\r
1433 //memory space; anywhere in 32 bit address space\r
1434 //\r
1435 case 0x00:\r
aa75dfec 1436 if ((Value & 0x08) != 0) {\r
9060e3ec 1437 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;\r
1438 } else {\r
1439 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;\r
1440 }\r
1441\r
1442 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1443 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1444\r
1445 //\r
1446 // Adjust Length\r
1447 //\r
1448 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1449 //\r
1450 // Adjust Alignment\r
1451 //\r
1452 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1453 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1454 }\r
1455\r
1456 break;\r
1457\r
1458 //\r
1459 // memory space; anywhere in 64 bit address space\r
1460 //\r
1461 case 0x04:\r
aa75dfec 1462 if ((Value & 0x08) != 0) {\r
9060e3ec 1463 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;\r
1464 } else {\r
1465 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;\r
1466 }\r
1467\r
1468 //\r
1469 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1470 // is regarded as an extension for the first bar. As a result\r
1471 // the sizing will be conducted on combined 64 bit value\r
1472 // Here just store the masked first 32bit value for future size\r
1473 // calculation\r
1474 //\r
1475 PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;\r
1476 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1477\r
1478 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1479 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1480 }\r
1481\r
1482 //\r
1483 // Increment the offset to point to next DWORD\r
1484 //\r
1485 Offset += 4;\r
1486\r
1487 Status = VfBarExisted (\r
1488 PciIoDevice,\r
1489 Offset,\r
1490 &Value,\r
1491 &OriginalValue\r
1492 );\r
1493\r
1494 if (EFI_ERROR (Status)) {\r
1495 return Offset + 4;\r
1496 }\r
1497\r
1498 //\r
1499 // Fix the length to support some spefic 64 bit BAR\r
1500 //\r
1501 Data = Value;\r
1502 Index = 0;\r
1503 for (Data = Value; Data != 0; Data >>= 1) {\r
1504 Index ++;\r
1505 }\r
1506 Value |= ((UINT32)(-1) << Index); \r
1507\r
1508 //\r
1509 // Calculate the size of 64bit bar\r
1510 //\r
1511 PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1512\r
1513 PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1514 PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;\r
1515 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1516\r
1517 //\r
1518 // Adjust Length\r
1519 //\r
1520 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
1521 //\r
1522 // Adjust Alignment\r
1523 //\r
1524 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1525 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1526 }\r
1527\r
1528 break;\r
1529\r
1530 //\r
1531 // reserved\r
1532 //\r
1533 default:\r
1534 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1535 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1536 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
1537\r
1538 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
1539 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
1540 }\r
1541\r
1542 break;\r
1543 }\r
1544 }\r
1545 \r
1546 //\r
1547 // Check the length again so as to keep compatible with some special bars\r
1548 //\r
1549 if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {\r
1550 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1551 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
1552 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
1553 }\r
1554 \r
1555 //\r
1556 // Increment number of bar\r
1557 //\r
1558 return Offset + 4;\r
1559}\r
1560\r
1561/**\r
1562 Parse PCI bar information and fill them into PCI device instance.\r
1563\r
1564 @param PciIoDevice Pci device instance.\r
1565 @param Offset Bar offset.\r
1566 @param BarIndex Bar index.\r
1567\r
1568 @return Next bar offset.\r
1569\r
1570**/\r
1571UINTN\r
1572PciParseBar (\r
1573 IN PCI_IO_DEVICE *PciIoDevice,\r
1574 IN UINTN Offset,\r
1575 IN UINTN BarIndex\r
1576 )\r
1577{\r
1578 UINT32 Value;\r
1579 UINT32 OriginalValue;\r
1580 UINT32 Mask;\r
1581 UINT32 Data;\r
1582 UINT8 Index;\r
1583 EFI_STATUS Status;\r
1584\r
1585 OriginalValue = 0;\r
1586 Value = 0;\r
1587\r
1588 Status = BarExisted (\r
1589 PciIoDevice,\r
1590 Offset,\r
1591 &Value,\r
1592 &OriginalValue\r
1593 );\r
1594\r
1595 if (EFI_ERROR (Status)) {\r
1596 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1597 PciIoDevice->PciBar[BarIndex].Length = 0;\r
1598 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1599\r
1600 //\r
1601 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway\r
1602 //\r
1603 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1604 return Offset + 4;\r
1605 }\r
1606\r
1607 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1608 if ((Value & 0x01) != 0) {\r
1609 //\r
1610 // Device I/Os\r
1611 //\r
1612 Mask = 0xfffffffc;\r
1613\r
1614 if ((Value & 0xFFFF0000) != 0) {\r
1615 //\r
1616 // It is a IO32 bar\r
1617 //\r
1618 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;\r
1619 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);\r
1620 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1621\r
1622 } else {\r
1623 //\r
1624 // It is a IO16 bar\r
1625 //\r
1626 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;\r
1627 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);\r
1628 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1629\r
1630 }\r
1631 //\r
1632 // Workaround. Some platforms inplement IO bar with 0 length\r
1633 // Need to treat it as no-bar\r
1634 //\r
1635 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1636 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;\r
1637 }\r
1638\r
1639 PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;\r
1640 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1641\r
1642 } else {\r
1643\r
1644 Mask = 0xfffffff0;\r
1645\r
1646 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1647\r
1648 switch (Value & 0x07) {\r
1649\r
1650 //\r
1651 //memory space; anywhere in 32 bit address space\r
1652 //\r
1653 case 0x00:\r
1654 if ((Value & 0x08) != 0) {\r
1655 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1656 } else {\r
1657 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1658 }\r
1659\r
1660 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1661 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1662 //\r
1663 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1664 //\r
1665 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1666 } else {\r
1667 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1668 }\r
1669 break;\r
1670\r
1671 //\r
1672 // memory space; anywhere in 64 bit address space\r
1673 //\r
1674 case 0x04:\r
1675 if ((Value & 0x08) != 0) {\r
1676 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;\r
1677 } else {\r
1678 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;\r
1679 }\r
1680\r
1681 //\r
1682 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1683 // is regarded as an extension for the first bar. As a result\r
1684 // the sizing will be conducted on combined 64 bit value\r
1685 // Here just store the masked first 32bit value for future size\r
1686 // calculation\r
1687 //\r
1688 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;\r
1689 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1690\r
1691 //\r
1692 // Increment the offset to point to next DWORD\r
1693 //\r
1694 Offset += 4;\r
1695\r
1696 Status = BarExisted (\r
1697 PciIoDevice,\r
1698 Offset,\r
1699 &Value,\r
1700 &OriginalValue\r
1701 );\r
1702\r
1703 if (EFI_ERROR (Status)) {\r
1704 //\r
1705 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again\r
1706 //\r
1707 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1708 //\r
1709 // some device implement MMIO bar with 0 length, need to treat it as no-bar\r
1710 //\r
1711 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1712 }\r
1713 return Offset + 4;\r
1714 }\r
1715\r
1716 //\r
1717 // Fix the length to support some spefic 64 bit BAR\r
1718 //\r
1719 Data = Value;\r
1720 Index = 0;\r
1721 for (Data = Value; Data != 0; Data >>= 1) {\r
1722 Index ++;\r
1723 }\r
1724 Value |= ((UINT32)(-1) << Index);\r
1725\r
1726 //\r
1727 // Calculate the size of 64bit bar\r
1728 //\r
1729 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1730\r
1731 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1732 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
1733 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1734 //\r
1735 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1736 //\r
1737 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1738 } else {\r
1739 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1740 }\r
1741\r
1742 break;\r
1743\r
1744 //\r
1745 // reserved\r
1746 //\r
1747 default:\r
1748 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1749 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1750 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
1751 //\r
1752 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
1753 //\r
1754 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
1755 } else {\r
1756 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1757 }\r
1758 break;\r
1759 }\r
1760 }\r
1761\r
1762 //\r
1763 // Check the length again so as to keep compatible with some special bars\r
1764 //\r
1765 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1766 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1767 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1768 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1769 }\r
1770\r
1771 //\r
1772 // Increment number of bar\r
1773 //\r
1774 return Offset + 4;\r
1775}\r
1776\r
1777/**\r
1778 This routine is used to initialize the bar of a PCI device.\r
1779\r
1780 @param PciIoDevice Pci device instance.\r
1781\r
1782 @note It can be called typically when a device is going to be rejected.\r
1783\r
1784**/\r
1785VOID\r
1786InitializePciDevice (\r
1787 IN PCI_IO_DEVICE *PciIoDevice\r
1788 )\r
1789{\r
1790 EFI_PCI_IO_PROTOCOL *PciIo;\r
1791 UINT8 Offset;\r
1792\r
1793 PciIo = &(PciIoDevice->PciIo);\r
1794\r
1795 //\r
1796 // Put all the resource apertures\r
1797 // Resource base is set to all ones so as to indicate its resource\r
1798 // has not been alloacted\r
1799 //\r
1800 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
1801 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
1802 }\r
1803}\r
1804\r
1805/**\r
1806 This routine is used to initialize the bar of a PCI-PCI Bridge device.\r
1807\r
1808 @param PciIoDevice PCI-PCI bridge device instance.\r
1809\r
1810**/\r
1811VOID\r
1812InitializePpb (\r
1813 IN PCI_IO_DEVICE *PciIoDevice\r
1814 )\r
1815{\r
1816 EFI_PCI_IO_PROTOCOL *PciIo;\r
1817\r
1818 PciIo = &(PciIoDevice->PciIo);\r
1819\r
1820 //\r
1821 // Put all the resource apertures including IO16\r
1822 // Io32, pMem32, pMem64 to quiescent state\r
1823 // Resource base all ones, Resource limit all zeros\r
1824 //\r
1825 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
1826 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
1827\r
1828 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
1829 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
1830\r
1831 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
1832 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
1833\r
1834 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
1835 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
1836\r
1837 //\r
1838 // Don't support use io32 as for now\r
1839 //\r
1840 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
1841 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
1842\r
1843 //\r
1844 // Force Interrupt line to zero for cards that come up randomly\r
1845 //\r
1846 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
1847}\r
1848\r
1849/**\r
1850 This routine is used to initialize the bar of a PCI Card Bridge device.\r
1851\r
1852 @param PciIoDevice PCI Card bridge device.\r
1853\r
1854**/\r
1855VOID\r
1856InitializeP2C (\r
1857 IN PCI_IO_DEVICE *PciIoDevice\r
1858 )\r
1859{\r
1860 EFI_PCI_IO_PROTOCOL *PciIo;\r
1861\r
1862 PciIo = &(PciIoDevice->PciIo);\r
1863\r
1864 //\r
1865 // Put all the resource apertures including IO16\r
1866 // Io32, pMem32, pMem64 to quiescent state(\r
1867 // Resource base all ones, Resource limit all zeros\r
1868 //\r
1869 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
1870 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
1871\r
1872 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
1873 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
1874\r
1875 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
1876 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
1877\r
1878 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
1879 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
1880\r
1881 //\r
1882 // Force Interrupt line to zero for cards that come up randomly\r
1883 //\r
1884 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
1885}\r
1886\r
1887/**\r
1888 Create and initiliaze general PCI I/O device instance for\r
1889 PCI device/bridge device/hotplug bridge device.\r
1890\r
1891 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1892 @param Pci Input Pci information block.\r
1893 @param Bus Device Bus NO.\r
1894 @param Device Device device NO.\r
1895 @param Func Device func NO.\r
1896\r
1897 @return Instance of PCI device. NULL means no instance created.\r
1898\r
1899**/\r
1900PCI_IO_DEVICE *\r
1901CreatePciIoDevice (\r
d4048391 1902 IN PCI_IO_DEVICE *Bridge,\r
9060e3ec 1903 IN PCI_TYPE00 *Pci,\r
1904 IN UINT8 Bus,\r
1905 IN UINT8 Device,\r
1906 IN UINT8 Func\r
1907 )\r
1908{\r
d4048391 1909 PCI_IO_DEVICE *PciIoDevice;\r
9060e3ec 1910 EFI_PCI_IO_PROTOCOL *PciIo;\r
1911 EFI_STATUS Status;\r
1912\r
1913 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
1914 if (PciIoDevice == NULL) {\r
1915 return NULL;\r
1916 }\r
1917\r
1918 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;\r
1919 PciIoDevice->Handle = NULL;\r
d4048391 1920 PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
9060e3ec 1921 PciIoDevice->DevicePath = NULL;\r
1922 PciIoDevice->BusNumber = Bus;\r
1923 PciIoDevice->DeviceNumber = Device;\r
1924 PciIoDevice->FunctionNumber = Func;\r
1925 PciIoDevice->Decodes = 0;\r
1926\r
1927 if (gFullEnumeration) {\r
1928 PciIoDevice->Allocated = FALSE;\r
1929 } else {\r
1930 PciIoDevice->Allocated = TRUE;\r
1931 }\r
1932\r
1933 PciIoDevice->Registered = FALSE;\r
1934 PciIoDevice->Attributes = 0;\r
1935 PciIoDevice->Supports = 0;\r
1936 PciIoDevice->BusOverride = FALSE;\r
1937 PciIoDevice->AllOpRomProcessed = FALSE;\r
1938\r
1939 PciIoDevice->IsPciExp = FALSE;\r
1940\r
1941 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
1942\r
1943 //\r
1944 // Initialize the PCI I/O instance structure\r
1945 //\r
1946 InitializePciIoInstance (PciIoDevice);\r
1947 InitializePciDriverOverrideInstance (PciIoDevice);\r
1948 InitializePciLoadFile2 (PciIoDevice);\r
1949 PciIo = &PciIoDevice->PciIo;\r
1950\r
1951 //\r
1952 // Detect if PCI Express Device\r
1953 //\r
1954 PciIoDevice->PciExpressCapabilityOffset = 0;\r
1955 Status = LocateCapabilityRegBlock (\r
1956 PciIoDevice,\r
1957 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
1958 &PciIoDevice->PciExpressCapabilityOffset,\r
1959 NULL\r
1960 );\r
1961 if (!EFI_ERROR (Status)) {\r
1962 PciIoDevice->IsPciExp = TRUE;\r
1963 }\r
1964\r
d4048391 1965 if (PcdGetBool (PcdAriSupport)) {\r
1966 //\r
1967 // Check if the device is an ARI device.\r
1968 //\r
1969 Status = LocatePciExpressCapabilityRegBlock (\r
1970 PciIoDevice,\r
1971 EFI_PCIE_CAPABILITY_ID_ARI,\r
1972 &PciIoDevice->AriCapabilityOffset,\r
1973 NULL\r
1974 );\r
1975 if (!EFI_ERROR (Status)) {\r
1976 //\r
1977 // We need to enable ARI feature before calculate BusReservation,\r
1978 // because FirstVFOffset and VFStride may change after that.\r
1979 //\r
1980 EFI_PCI_IO_PROTOCOL *ParentPciIo;\r
1981 UINT32 Data32;\r
9060e3ec 1982\r
d4048391 1983 //\r
1984 // Check if its parent supports ARI forwarding.\r
1985 //\r
1986 ParentPciIo = &Bridge->PciIo;\r
1987 ParentPciIo->Pci.Read (\r
1988 ParentPciIo, \r
1989 EfiPciIoWidthUint32,\r
1990 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET,\r
1991 1,\r
1992 &Data32\r
1993 );\r
1994 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) {\r
1995 //\r
1996 // ARI forward support in bridge, so enable it.\r
1997 //\r
1998 ParentPciIo->Pci.Read (\r
1999 ParentPciIo,\r
2000 EfiPciIoWidthUint32,\r
2001 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2002 1,\r
2003 &Data32\r
2004 );\r
2005 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) {\r
2006 Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING;\r
2007 ParentPciIo->Pci.Write (\r
2008 ParentPciIo,\r
2009 EfiPciIoWidthUint32,\r
2010 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET,\r
2011 1,\r
2012 &Data32\r
2013 );\r
2014 DEBUG ((\r
2015 EFI_D_INFO,\r
2016 "PCI B%x.D%x.F%x - ARI forwarding enabled\n",\r
2017 (UINTN)Bridge->BusNumber,\r
2018 (UINTN)Bridge->DeviceNumber,\r
2019 (UINTN)Bridge->FunctionNumber\r
2020 ));\r
2021 }\r
2022 }\r
9060e3ec 2023\r
d4048391 2024 DEBUG ((\r
2025 EFI_D_INFO,\r
2026 "PCI ARI B%x.D%x.F%x - ARI Cap offset - 0x%x\n",\r
2027 (UINTN)Bus,\r
2028 (UINTN)Device,\r
2029 (UINTN)Func,\r
2030 (UINTN)PciIoDevice->AriCapabilityOffset\r
2031 ));\r
2032 }\r
9060e3ec 2033 }\r
2034\r
2035 //\r
d4048391 2036 // Initialization for SR-IOV\r
9060e3ec 2037 //\r
9060e3ec 2038\r
d4048391 2039 if (PcdGetBool (PcdSrIovSupport)) {\r
2040 Status = LocatePciExpressCapabilityRegBlock (\r
2041 PciIoDevice,\r
2042 EFI_PCIE_CAPABILITY_ID_SRIOV,\r
2043 &PciIoDevice->SrIovCapabilityOffset,\r
2044 NULL\r
2045 );\r
2046 if (!EFI_ERROR (Status)) {\r
2047 UINT16 VFStride;\r
2048 UINT16 FirstVFOffset;\r
2049 UINT16 Data16;\r
2050 UINT32 PFRid;\r
2051 UINT32 LastVF;\r
2052\r
2053 //\r
2054 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device.\r
2055 //\r
2056 if (PcdGetBool (PcdAriSupport) && PciIoDevice->AriCapabilityOffset != 0) {\r
2057 PciIo->Pci.Read (\r
2058 PciIo,\r
2059 EfiPciIoWidthUint16,\r
2060 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2061 1,\r
2062 &Data16\r
2063 );\r
2064 Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY;\r
2065 PciIo->Pci.Write (\r
2066 PciIo,\r
2067 EfiPciIoWidthUint16,\r
2068 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL,\r
2069 1,\r
2070 &Data16\r
2071 );\r
2072 }\r
9060e3ec 2073\r
d4048391 2074 //\r
2075 // Calculate SystemPageSize\r
2076 //\r
9060e3ec 2077\r
d4048391 2078 PciIo->Pci.Read (\r
2079 PciIo,\r
2080 EfiPciIoWidthUint32,\r
2081 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,\r
2082 1,\r
2083 &PciIoDevice->SystemPageSize\r
2084 );\r
2085 DEBUG ((\r
2086 EFI_D_INFO,\r
2087 "PCI SR-IOV B%x.D%x.F%x - SupportedPageSize - 0x%x\n",\r
2088 (UINTN)Bus,\r
2089 (UINTN)Device,\r
2090 (UINTN)Func,\r
2091 PciIoDevice->SystemPageSize\r
2092 ));\r
2093\r
2094 PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & PciIoDevice->SystemPageSize);\r
2095 ASSERT (PciIoDevice->SystemPageSize != 0);\r
2096\r
2097 PciIo->Pci.Write (\r
2098 PciIo,\r
2099 EfiPciIoWidthUint32,\r
2100 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,\r
2101 1,\r
2102 &PciIoDevice->SystemPageSize\r
2103 );\r
2104 DEBUG ((\r
2105 EFI_D_INFO,\r
2106 "PCI SR-IOV B%x.D%x.F%x - SystemPageSize - 0x%x\n",\r
2107 (UINTN)Bus,\r
2108 (UINTN)Device,\r
2109 (UINTN)Func,\r
2110 PciIoDevice->SystemPageSize\r
2111 ));\r
2112 //\r
2113 // Adjust SystemPageSize for Alignment usage later\r
2114 //\r
2115 PciIoDevice->SystemPageSize <<= 12;\r
9060e3ec 2116\r
d4048391 2117 //\r
2118 // Calculate BusReservation for PCI IOV\r
2119 //\r
9060e3ec 2120\r
d4048391 2121 //\r
2122 // Read First FirstVFOffset, InitialVFs, and VFStride\r
2123 //\r
2124 PciIo->Pci.Read (\r
2125 PciIo,\r
2126 EfiPciIoWidthUint16,\r
2127 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,\r
2128 1,\r
2129 &FirstVFOffset\r
2130 );\r
2131 DEBUG ((\r
2132 EFI_D_INFO,\r
2133 "PCI SR-IOV B%x.D%x.F%x - FirstVFOffset - 0x%x\n",\r
2134 (UINTN)Bus,\r
2135 (UINTN)Device,\r
2136 (UINTN)Func,\r
2137 (UINTN)FirstVFOffset\r
2138 ));\r
2139\r
2140 PciIo->Pci.Read (\r
2141 PciIo,\r
2142 EfiPciIoWidthUint16,\r
2143 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,\r
2144 1,\r
2145 &PciIoDevice->InitialVFs\r
2146 );\r
2147 DEBUG ((\r
2148 EFI_D_INFO,\r
2149 "PCI SR-IOV B%x.D%x.F%x - InitialVFs - 0x%x\n",\r
2150 (UINTN)Bus,\r
2151 (UINTN)Device,\r
2152 (UINTN)Func,\r
2153 (UINTN)PciIoDevice->InitialVFs\r
2154 ));\r
2155\r
2156 PciIo->Pci.Read (\r
2157 PciIo,\r
2158 EfiPciIoWidthUint16,\r
2159 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,\r
2160 1,\r
2161 &VFStride\r
2162 );\r
2163 DEBUG ((\r
2164 EFI_D_INFO,\r
2165 "PCI SR-IOV B%x.D%x.F%x - VFStride - 0x%x\n",\r
2166 (UINTN)Bus,\r
2167 (UINTN)Device,\r
2168 (UINTN)Func,\r
2169 (UINTN)VFStride\r
2170 ));\r
9060e3ec 2171\r
d4048391 2172 //\r
2173 // Calculate LastVF\r
2174 //\r
2175 PFRid = EFI_PCI_RID(Bus, Device, Func);\r
2176 LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;\r
9060e3ec 2177\r
d4048391 2178 //\r
2179 // Calculate ReservedBusNum for this PF\r
2180 //\r
2181 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);\r
2182 DEBUG ((\r
2183 EFI_D_INFO,\r
2184 "PCI SR-IOV B%x.D%x.F%x - reserved bus number - 0x%x\n",\r
2185 (UINTN)Bus,\r
2186 (UINTN)Device,\r
2187 (UINTN)Func,\r
2188 (UINTN)PciIoDevice->ReservedBusNum\r
2189 ));\r
2190\r
2191 DEBUG ((\r
2192 EFI_D_INFO,\r
2193 "PCI SR-IOV B%x.D%x.F%x - SRIOV Cap offset - 0x%x\n",\r
2194 (UINTN)Bus,\r
2195 (UINTN)Device,\r
2196 (UINTN)Func,\r
2197 (UINTN)PciIoDevice->SrIovCapabilityOffset\r
2198 ));\r
2199 }\r
9060e3ec 2200 }\r
2201\r
d4048391 2202 if (PcdGetBool (PcdMrIovSupport)) {\r
2203 Status = LocatePciExpressCapabilityRegBlock (\r
2204 PciIoDevice,\r
2205 EFI_PCIE_CAPABILITY_ID_MRIOV,\r
2206 &PciIoDevice->MrIovCapabilityOffset,\r
2207 NULL\r
2208 );\r
2209 if (!EFI_ERROR (Status)) {\r
2210 DEBUG ((\r
2211 EFI_D_INFO,\r
2212 "PCI MR-IOV B%x.D%x.F%x - MRIOV Cap offset - 0x%x\n",\r
2213 (UINTN)Bus,\r
2214 (UINTN)Device,\r
2215 (UINTN)Func,\r
2216 (UINTN)PciIoDevice->MrIovCapabilityOffset\r
2217 ));\r
2218 }\r
2219 }\r
9060e3ec 2220\r
2221 //\r
2222 // Initialize the reserved resource list\r
2223 //\r
2224 InitializeListHead (&PciIoDevice->ReservedResourceList);\r
2225\r
2226 //\r
2227 // Initialize the driver list\r
2228 //\r
2229 InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
2230\r
2231 //\r
2232 // Initialize the child list\r
2233 //\r
2234 InitializeListHead (&PciIoDevice->ChildList);\r
2235\r
2236 return PciIoDevice;\r
2237}\r
2238\r
2239/**\r
2240 This routine is used to enumerate entire pci bus system\r
2241 in a given platform.\r
2242\r
2243 It is only called on the second start on the same Root Bridge.\r
2244\r
2245 @param Controller Parent bridge handler.\r
2246\r
2247 @retval EFI_SUCCESS PCI enumeration finished successfully.\r
2248 @retval other Some error occurred when enumerating the pci bus system.\r
2249\r
2250**/\r
2251EFI_STATUS\r
2252PciEnumeratorLight (\r
2253 IN EFI_HANDLE Controller\r
2254 )\r
2255{\r
2256\r
2257 EFI_STATUS Status;\r
2258 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2259 PCI_IO_DEVICE *RootBridgeDev;\r
2260 UINT16 MinBus;\r
2261 UINT16 MaxBus;\r
2262 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
2263\r
2264 MinBus = 0;\r
2265 MaxBus = PCI_MAX_BUS;\r
2266 Descriptors = NULL;\r
2267\r
2268 //\r
2269 // If this root bridge has been already enumerated, then return successfully\r
2270 //\r
2271 if (GetRootBridgeByHandle (Controller) != NULL) {\r
2272 return EFI_SUCCESS;\r
2273 }\r
2274\r
2275 //\r
2276 // Open pci root bridge io protocol\r
2277 //\r
2278 Status = gBS->OpenProtocol (\r
2279 Controller,\r
2280 &gEfiPciRootBridgeIoProtocolGuid,\r
2281 (VOID **) &PciRootBridgeIo,\r
2282 gPciBusDriverBinding.DriverBindingHandle,\r
2283 Controller,\r
2284 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2285 );\r
2286 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2287 return Status;\r
2288 }\r
2289\r
2290 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
2291\r
2292 if (EFI_ERROR (Status)) {\r
2293 return Status;\r
2294 }\r
2295\r
2296 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
2297\r
2298 //\r
2299 // Create a device node for root bridge device with a NULL host bridge controller handle\r
2300 //\r
2301 RootBridgeDev = CreateRootBridge (Controller);\r
2302\r
2303 if (RootBridgeDev == NULL) {\r
2304 Descriptors++;\r
2305 continue;\r
2306 }\r
2307\r
2308 //\r
2309 // Record the root bridgeio protocol\r
2310 //\r
2311 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2312\r
2313 Status = PciPciDeviceInfoCollector (\r
2314 RootBridgeDev,\r
2315 (UINT8) MinBus\r
2316 );\r
2317\r
2318 if (!EFI_ERROR (Status)) {\r
2319\r
2320 //\r
2321 // Remove those PCI devices which are rejected when full enumeration\r
2322 //\r
2323 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
2324\r
2325 //\r
2326 // Process option rom light\r
2327 //\r
2328 ProcessOptionRomLight (RootBridgeDev);\r
2329\r
2330 //\r
2331 // Determine attributes for all devices under this root bridge\r
2332 //\r
2333 DetermineDeviceAttribute (RootBridgeDev);\r
2334\r
2335 //\r
2336 // If successfully, insert the node into device pool\r
2337 //\r
2338 InsertRootBridge (RootBridgeDev);\r
2339 } else {\r
2340\r
2341 //\r
2342 // If unsuccessly, destroy the entire node\r
2343 //\r
2344 DestroyRootBridge (RootBridgeDev);\r
2345 }\r
2346\r
2347 Descriptors++;\r
2348 }\r
2349\r
2350 return EFI_SUCCESS;\r
2351}\r
2352\r
2353/**\r
2354 Get bus range from PCI resource descriptor list.\r
2355\r
2356 @param Descriptors A pointer to the address space descriptor.\r
2357 @param MinBus The min bus returned.\r
2358 @param MaxBus The max bus returned.\r
2359 @param BusRange The bus range returned.\r
2360\r
2361 @retval EFI_SUCCESS Successfully got bus range.\r
2362 @retval EFI_NOT_FOUND Can not find the specific bus.\r
2363\r
2364**/\r
2365EFI_STATUS\r
2366PciGetBusRange (\r
2367 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
2368 OUT UINT16 *MinBus,\r
2369 OUT UINT16 *MaxBus,\r
2370 OUT UINT16 *BusRange\r
2371 )\r
2372{\r
2373 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
2374 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
2375 if (MinBus != NULL) {\r
2376 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;\r
2377 }\r
2378\r
2379 if (MaxBus != NULL) {\r
2380 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;\r
2381 }\r
2382\r
2383 if (BusRange != NULL) {\r
2384 *BusRange = (UINT16) (*Descriptors)->AddrLen;\r
2385 }\r
2386\r
2387 return EFI_SUCCESS;\r
2388 }\r
2389\r
2390 (*Descriptors)++;\r
2391 }\r
2392\r
2393 return EFI_NOT_FOUND;\r
2394}\r
2395\r
2396/**\r
2397 This routine can be used to start the root bridge.\r
2398\r
2399 @param RootBridgeDev Pci device instance.\r
2400\r
2401 @retval EFI_SUCCESS This device started.\r
2402 @retval other Failed to get PCI Root Bridge I/O protocol.\r
2403\r
2404**/\r
2405EFI_STATUS\r
2406StartManagingRootBridge (\r
2407 IN PCI_IO_DEVICE *RootBridgeDev\r
2408 )\r
2409{\r
2410 EFI_HANDLE RootBridgeHandle;\r
2411 EFI_STATUS Status;\r
2412 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2413\r
2414 //\r
2415 // Get the root bridge handle\r
2416 //\r
2417 RootBridgeHandle = RootBridgeDev->Handle;\r
2418 PciRootBridgeIo = NULL;\r
2419\r
2420 //\r
2421 // Get the pci root bridge io protocol\r
2422 //\r
2423 Status = gBS->OpenProtocol (\r
2424 RootBridgeHandle,\r
2425 &gEfiPciRootBridgeIoProtocolGuid,\r
2426 (VOID **) &PciRootBridgeIo,\r
2427 gPciBusDriverBinding.DriverBindingHandle,\r
2428 RootBridgeHandle,\r
2429 EFI_OPEN_PROTOCOL_BY_DRIVER\r
2430 );\r
2431\r
2432 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
2433 return Status;\r
2434 }\r
2435\r
2436 //\r
2437 // Store the PciRootBridgeIo protocol into root bridge private data\r
2438 //\r
2439 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
2440\r
2441 return EFI_SUCCESS;\r
2442\r
2443}\r
2444\r
2445/**\r
2446 This routine can be used to check whether a PCI device should be rejected when light enumeration.\r
2447\r
2448 @param PciIoDevice Pci device instance.\r
2449\r
2450 @retval TRUE This device should be rejected.\r
2451 @retval FALSE This device shouldn't be rejected.\r
2452\r
2453**/\r
2454BOOLEAN\r
2455IsPciDeviceRejected (\r
2456 IN PCI_IO_DEVICE *PciIoDevice\r
2457 )\r
2458{\r
2459 EFI_STATUS Status;\r
2460 UINT32 TestValue;\r
2461 UINT32 OldValue;\r
2462 UINT32 Mask;\r
2463 UINT8 BarOffset;\r
2464\r
2465 //\r
2466 // PPB should be skip!\r
2467 //\r
2468 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
2469 return FALSE;\r
2470 }\r
2471\r
2472 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
2473 //\r
2474 // Only test base registers for P2C\r
2475 //\r
2476 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
2477\r
2478 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
2479 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2480 if (EFI_ERROR (Status)) {\r
2481 continue;\r
2482 }\r
2483\r
2484 TestValue = TestValue & Mask;\r
2485 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2486 //\r
2487 // The bar isn't programed, so it should be rejected\r
2488 //\r
2489 return TRUE;\r
2490 }\r
2491 }\r
2492\r
2493 return FALSE;\r
2494 }\r
2495\r
2496 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
2497 //\r
2498 // Test PCI devices\r
2499 //\r
2500 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2501 if (EFI_ERROR (Status)) {\r
2502 continue;\r
2503 }\r
2504\r
2505 if ((TestValue & 0x01) != 0) {\r
2506\r
2507 //\r
2508 // IO Bar\r
2509 //\r
2510 Mask = 0xFFFFFFFC;\r
2511 TestValue = TestValue & Mask;\r
2512 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2513 return TRUE;\r
2514 }\r
2515\r
2516 } else {\r
2517\r
2518 //\r
2519 // Mem Bar\r
2520 //\r
2521 Mask = 0xFFFFFFF0;\r
2522 TestValue = TestValue & Mask;\r
2523\r
2524 if ((TestValue & 0x07) == 0x04) {\r
2525\r
2526 //\r
2527 // Mem64 or PMem64\r
2528 //\r
2529 BarOffset += sizeof (UINT32);\r
2530 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2531\r
2532 //\r
2533 // Test its high 32-Bit BAR\r
2534 //\r
2535 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
2536 if (TestValue == OldValue) {\r
2537 return TRUE;\r
2538 }\r
2539 }\r
2540\r
2541 } else {\r
2542\r
2543 //\r
2544 // Mem32 or PMem32\r
2545 //\r
2546 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
2547 return TRUE;\r
2548 }\r
2549 }\r
2550 }\r
2551 }\r
2552\r
2553 return FALSE;\r
2554}\r
2555\r
2556/**\r
2557 Reset all bus number from specific bridge.\r
2558\r
2559 @param Bridge Parent specific bridge.\r
2560 @param StartBusNumber Start bus number.\r
2561\r
2562**/\r
2563VOID\r
2564ResetAllPpbBusNumber (\r
2565 IN PCI_IO_DEVICE *Bridge,\r
2566 IN UINT8 StartBusNumber\r
2567 )\r
2568{\r
2569 EFI_STATUS Status;\r
2570 PCI_TYPE00 Pci;\r
2571 UINT8 Device;\r
2572 UINT32 Register;\r
2573 UINT8 Func;\r
2574 UINT64 Address;\r
2575 UINT8 SecondaryBus;\r
2576 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2577\r
2578 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2579\r
2580 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
2581 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
2582\r
2583 //\r
2584 // Check to see whether a pci device is present\r
2585 //\r
2586 Status = PciDevicePresent (\r
2587 PciRootBridgeIo,\r
2588 &Pci,\r
2589 StartBusNumber,\r
2590 Device,\r
2591 Func\r
2592 );\r
2593\r
2594 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
2595\r
2596 Register = 0;\r
2597 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
2598 Status = PciRootBridgeIo->Pci.Read (\r
2599 PciRootBridgeIo,\r
2600 EfiPciWidthUint32,\r
2601 Address,\r
2602 1,\r
2603 &Register\r
2604 );\r
2605 SecondaryBus = (UINT8)(Register >> 8);\r
2606\r
2607 if (SecondaryBus != 0) {\r
2608 ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
2609 }\r
2610\r
2611 //\r
2612 // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2613 //\r
2614 Register &= 0xFF000000;\r
2615 Status = PciRootBridgeIo->Pci.Write (\r
2616 PciRootBridgeIo,\r
2617 EfiPciWidthUint32,\r
2618 Address,\r
2619 1,\r
2620 &Register\r
2621 );\r
2622 }\r
2623\r
2624 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
2625 //\r
2626 // Skip sub functions, this is not a multi function device\r
2627 //\r
2628 Func = PCI_MAX_FUNC;\r
2629 }\r
2630 }\r
2631 }\r
2632}\r
2633\r