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