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