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