]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
Retired PciIncompatibleDeviceSupportLib from IntelFrameworkModulePkg.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciEnumeratorSupport.c
CommitLineData
eeefcb9d 1/** @file\r
8e8227d1 2 PCI emumeration support functions implementation for PCI Bus module.\r
ead42efc 3\r
8e6b0dcb 4Copyright (c) 2006 - 2009, Intel Corporation\r
ea5632e5 5All rights reserved. This program and the accompanying materials\r
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
ead42efc 12\r
3db51098 13**/\r
ead42efc 14\r
03417d8d 15#include "PciBus.h"\r
ead42efc 16\r
a3b8e257 17/**\r
18 This routine is used to check whether the pci device is present.\r
8e8227d1 19\r
97404058 20 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
8e8227d1 21 @param Pci Output buffer for PCI device configuration space.\r
97404058 22 @param Bus PCI bus NO.\r
23 @param Device PCI device NO.\r
24 @param Func PCI Func NO.\r
8e8227d1 25\r
26 @retval EFI_NOT_FOUND PCI device not present.\r
27 @retval EFI_SUCCESS PCI device is found.\r
28\r
a3b8e257 29**/\r
ead42efc 30EFI_STATUS\r
31PciDevicePresent (\r
8e8227d1 32 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
33 OUT PCI_TYPE00 *Pci,\r
34 IN UINT8 Bus,\r
35 IN UINT8 Device,\r
36 IN UINT8 Func\r
ead42efc 37 )\r
ead42efc 38{\r
39 UINT64 Address;\r
40 EFI_STATUS Status;\r
41\r
42 //\r
43 // Create PCI address map in terms of Bus, Device and Func\r
44 //\r
45 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);\r
46\r
47 //\r
8e8227d1 48 // Read the Vendor ID register\r
ead42efc 49 //\r
9eb130ff 50 Status = PciRootBridgeIo->Pci.Read (\r
51 PciRootBridgeIo,\r
52 EfiPciWidthUint32,\r
53 Address,\r
54 1,\r
55 Pci\r
56 );\r
ead42efc 57\r
58 if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff) {\r
ead42efc 59 //\r
60 // Read the entire config header for the device\r
61 //\r
9eb130ff 62 Status = PciRootBridgeIo->Pci.Read (\r
63 PciRootBridgeIo,\r
64 EfiPciWidthUint32,\r
65 Address,\r
66 sizeof (PCI_TYPE00) / sizeof (UINT32),\r
67 Pci\r
68 );\r
ead42efc 69\r
70 return EFI_SUCCESS;\r
71 }\r
72\r
73 return EFI_NOT_FOUND;\r
74}\r
75\r
a3b8e257 76/**\r
8e8227d1 77 Collect all the resource information under this root bridge.\r
78\r
a3b8e257 79 A database that records all the information about pci device subject to this\r
80 root bridge will then be created.\r
8e8227d1 81\r
97404058 82 @param Bridge Parent bridge instance.\r
8e8227d1 83 @param StartBusNumber Bus number of begining.\r
84\r
85 @retval EFI_SUCCESS PCI device is found.\r
86 @retval other Some error occurred when reading PCI bridge information.\r
87\r
a3b8e257 88**/\r
ead42efc 89EFI_STATUS\r
90PciPciDeviceInfoCollector (\r
91 IN PCI_IO_DEVICE *Bridge,\r
8e8227d1 92 IN UINT8 StartBusNumber\r
ead42efc 93 )\r
ead42efc 94{\r
95 EFI_STATUS Status;\r
96 PCI_TYPE00 Pci;\r
97 UINT8 Device;\r
98 UINT8 Func;\r
99 UINT8 SecBus;\r
100 PCI_IO_DEVICE *PciIoDevice;\r
101 EFI_PCI_IO_PROTOCOL *PciIo;\r
102\r
103 Status = EFI_SUCCESS;\r
104 SecBus = 0;\r
105\r
106 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
107\r
108 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
109\r
110 //\r
111 // Check to see whether PCI device is present\r
112 //\r
ead42efc 113 Status = PciDevicePresent (\r
8e8227d1 114 Bridge->PciRootBridgeIo,\r
115 &Pci,\r
116 (UINT8) StartBusNumber,\r
117 (UINT8) Device,\r
118 (UINT8) Func\r
119 );\r
ead42efc 120 if (!EFI_ERROR (Status)) {\r
121\r
122 //\r
123 // Call back to host bridge function\r
124 //\r
125 PreprocessController (Bridge, (UINT8) StartBusNumber, Device, Func, EfiPciBeforeResourceCollection);\r
126\r
127 //\r
128 // Collect all the information about the PCI device discovered\r
129 //\r
130 Status = PciSearchDevice (\r
8e8227d1 131 Bridge,\r
132 &Pci,\r
133 (UINT8) StartBusNumber,\r
134 Device,\r
135 Func,\r
136 &PciIoDevice\r
137 );\r
ead42efc 138\r
139 //\r
140 // Recursively scan PCI busses on the other side of PCI-PCI bridges\r
141 //\r
142 //\r
ead42efc 143 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {\r
144\r
145 //\r
146 // If it is PPB, we need to get the secondary bus to continue the enumeration\r
147 //\r
148 PciIo = &(PciIoDevice->PciIo);\r
149\r
9eb130ff 150 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus);\r
ead42efc 151\r
152 if (EFI_ERROR (Status)) {\r
153 return Status;\r
154 }\r
155\r
156 //\r
157 // Get resource padding for PPB\r
158 //\r
159 GetResourcePaddingPpb (PciIoDevice);\r
160\r
161 //\r
162 // Deep enumerate the next level bus\r
163 //\r
164 Status = PciPciDeviceInfoCollector (\r
8e8227d1 165 PciIoDevice,\r
166 (UINT8) (SecBus)\r
167 );\r
ead42efc 168\r
169 }\r
170\r
171 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
172\r
173 //\r
174 // Skip sub functions, this is not a multi function device\r
175 //\r
176 Func = PCI_MAX_FUNC;\r
177 }\r
178 }\r
179\r
180 }\r
181 }\r
182\r
183 return EFI_SUCCESS;\r
184}\r
185\r
a3b8e257 186/**\r
8e8227d1 187 Seach required device and create PCI device instance.\r
188\r
97404058 189 @param Bridge Parent bridge instance.\r
8e8227d1 190 @param Pci Input PCI device information block.\r
a3b8e257 191 @param Bus PCI bus NO.\r
192 @param Device PCI device NO.\r
193 @param Func PCI func NO.\r
8e8227d1 194 @param PciDevice Output of searched PCI device instance.\r
195\r
196 @retval EFI_SUCCESS Successfully created PCI device instance.\r
197 @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.\r
198\r
a3b8e257 199**/\r
ead42efc 200EFI_STATUS\r
201PciSearchDevice (\r
202 IN PCI_IO_DEVICE *Bridge,\r
203 IN PCI_TYPE00 *Pci,\r
204 IN UINT8 Bus,\r
205 IN UINT8 Device,\r
206 IN UINT8 Func,\r
207 OUT PCI_IO_DEVICE **PciDevice\r
208 )\r
ead42efc 209{\r
210 PCI_IO_DEVICE *PciIoDevice;\r
211\r
212 PciIoDevice = NULL;\r
213\r
214 if (!IS_PCI_BRIDGE (Pci)) {\r
215\r
216 if (IS_CARDBUS_BRIDGE (Pci)) {\r
217 PciIoDevice = GatherP2CInfo (\r
218 Bridge,\r
219 Pci,\r
220 Bus,\r
221 Device,\r
222 Func\r
223 );\r
224 if ((PciIoDevice != NULL) && gFullEnumeration) {\r
225 InitializeP2C (PciIoDevice);\r
226 }\r
227 } else {\r
228\r
229 //\r
230 // Create private data for Pci Device\r
231 //\r
232 PciIoDevice = GatherDeviceInfo (\r
233 Bridge,\r
234 Pci,\r
235 Bus,\r
236 Device,\r
237 Func\r
238 );\r
239\r
240 }\r
241\r
242 } else {\r
243\r
244 //\r
245 // Create private data for PPB\r
246 //\r
247 PciIoDevice = GatherPpbInfo (\r
248 Bridge,\r
249 Pci,\r
250 Bus,\r
251 Device,\r
252 Func\r
253 );\r
254\r
255 //\r
256 // Special initialization for PPB including making the PPB quiet\r
257 //\r
258 if ((PciIoDevice != NULL) && gFullEnumeration) {\r
259 InitializePpb (PciIoDevice);\r
260 }\r
261 }\r
262\r
97404058 263 if (PciIoDevice == NULL) {\r
ead42efc 264 return EFI_OUT_OF_RESOURCES;\r
265 }\r
266\r
267 //\r
268 // Update the bar information for this PCI device so as to support some specific device\r
269 //\r
ea5632e5 270 UpdatePciInfo (PciIoDevice);\r
ead42efc 271\r
272 if (PciIoDevice->DevicePath == NULL) {\r
273 return EFI_OUT_OF_RESOURCES;\r
274 }\r
275\r
276 //\r
277 // Detect this function has option rom\r
278 //\r
279 if (gFullEnumeration) {\r
280\r
281 if (!IS_CARDBUS_BRIDGE (Pci)) {\r
282\r
283 GetOpRomInfo (PciIoDevice);\r
284\r
285 }\r
286\r
287 ResetPowerManagementFeature (PciIoDevice);\r
288\r
289 }\r
290\r
291 //\r
292 // Insert it into a global tree for future reference\r
293 //\r
294 InsertPciDevice (Bridge, PciIoDevice);\r
295\r
296 //\r
297 // Determine PCI device attributes\r
298 //\r
299\r
300 if (PciDevice != NULL) {\r
301 *PciDevice = PciIoDevice;\r
302 }\r
303\r
304 return EFI_SUCCESS;\r
305}\r
306\r
a3b8e257 307/**\r
8e8227d1 308 Create PCI device instance for PCI device.\r
309\r
310 @param Bridge Parent bridge instance.\r
311 @param Pci Input PCI device information block.\r
312 @param Bus PCI device Bus NO.\r
313 @param Device PCI device Device NO.\r
314 @param Func PCI device's func NO.\r
315\r
316 @return Created PCI device instance.\r
317\r
a3b8e257 318**/\r
ead42efc 319PCI_IO_DEVICE *\r
320GatherDeviceInfo (\r
321 IN PCI_IO_DEVICE *Bridge,\r
322 IN PCI_TYPE00 *Pci,\r
8e8227d1 323 IN UINT8 Bus,\r
324 IN UINT8 Device,\r
325 IN UINT8 Func\r
ead42efc 326 )\r
ead42efc 327{\r
328 UINTN Offset;\r
329 UINTN BarIndex;\r
330 PCI_IO_DEVICE *PciIoDevice;\r
331 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
332\r
333 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
334 PciIoDevice = CreatePciIoDevice (\r
335 PciRootBridgeIo,\r
336 Pci,\r
337 Bus,\r
338 Device,\r
339 Func\r
340 );\r
341\r
97404058 342 if (PciIoDevice == NULL) {\r
ead42efc 343 return NULL;\r
344 }\r
345\r
346 //\r
347 // Create a device path for this PCI device and store it into its private data\r
348 //\r
349 CreatePciDevicePath (\r
350 Bridge->DevicePath,\r
351 PciIoDevice\r
352 );\r
353\r
354 //\r
355 // If it is a full enumeration, disconnect the device in advance\r
356 //\r
357 if (gFullEnumeration) {\r
358\r
94b9d5c6 359 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
ead42efc 360\r
361 }\r
362\r
363 //\r
364 // Start to parse the bars\r
365 //\r
c72216a6 366 for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {\r
ead42efc 367 Offset = PciParseBar (PciIoDevice, Offset, BarIndex);\r
368 }\r
369\r
370 return PciIoDevice;\r
371}\r
372\r
a3b8e257 373/**\r
8e8227d1 374 Create PCI device instance for PCI-PCI bridge.\r
375\r
376 @param Bridge Parent bridge instance.\r
377 @param Pci Input PCI device information block.\r
378 @param Bus PCI device Bus NO.\r
379 @param Device PCI device Device NO.\r
380 @param Func PCI device's func NO.\r
381\r
382 @return Created PCI device instance.\r
383\r
a3b8e257 384**/\r
ead42efc 385PCI_IO_DEVICE *\r
386GatherPpbInfo (\r
387 IN PCI_IO_DEVICE *Bridge,\r
388 IN PCI_TYPE00 *Pci,\r
8e8227d1 389 IN UINT8 Bus,\r
390 IN UINT8 Device,\r
391 IN UINT8 Func\r
ead42efc 392 )\r
ead42efc 393{\r
394 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
395 PCI_IO_DEVICE *PciIoDevice;\r
396 EFI_STATUS Status;\r
fc9efbee 397 UINT8 Value;\r
ead42efc 398 EFI_PCI_IO_PROTOCOL *PciIo;\r
399 UINT8 Temp;\r
400\r
401 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
402 PciIoDevice = CreatePciIoDevice (\r
403 PciRootBridgeIo,\r
404 Pci,\r
405 Bus,\r
406 Device,\r
407 Func\r
408 );\r
409\r
97404058 410 if (PciIoDevice == NULL) {\r
ead42efc 411 return NULL;\r
412 }\r
413\r
414 //\r
415 // Create a device path for this PCI device and store it into its private data\r
416 //\r
417 CreatePciDevicePath (\r
418 Bridge->DevicePath,\r
419 PciIoDevice\r
420 );\r
421\r
422 if (gFullEnumeration) {\r
94b9d5c6 423 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
ead42efc 424\r
425 //\r
426 // Initalize the bridge control register\r
427 //\r
94b9d5c6 428 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);\r
ead42efc 429\r
430 }\r
431\r
432 //\r
433 // PPB can have two BARs\r
434 //\r
435 if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {\r
436 //\r
437 // Not 64-bit bar\r
438 //\r
439 PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);\r
440 }\r
441\r
442 PciIo = &PciIoDevice->PciIo;\r
443\r
444 //\r
445 // Test whether it support 32 decode or not\r
446 //\r
9eb130ff 447 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
448 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
449 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);\r
450 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
ead42efc 451\r
97404058 452 if (Value != 0) {\r
453 if ((Value & 0x01) != 0) {\r
ead42efc 454 PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;\r
455 } else {\r
456 PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;\r
457 }\r
458 }\r
459\r
460 Status = BarExisted (\r
461 PciIoDevice,\r
462 0x24,\r
463 NULL,\r
464 NULL\r
465 );\r
466\r
467 //\r
8e8227d1 468 // Test if it supports 64 memory or not\r
ead42efc 469 //\r
470 if (!EFI_ERROR (Status)) {\r
471\r
472 Status = BarExisted (\r
473 PciIoDevice,\r
474 0x28,\r
475 NULL,\r
476 NULL\r
477 );\r
478\r
479 if (!EFI_ERROR (Status)) {\r
480 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
481 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;\r
482 } else {\r
483 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
484 }\r
485 }\r
486\r
487 //\r
488 // Memory 32 code is required for ppb\r
489 //\r
490 PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;\r
491\r
492 GetResourcePaddingPpb (PciIoDevice);\r
493\r
494 return PciIoDevice;\r
495}\r
496\r
8e8227d1 497\r
a3b8e257 498/**\r
8e8227d1 499 Create PCI device instance for PCI Card bridge device.\r
500\r
501 @param Bridge Parent bridge instance.\r
502 @param Pci Input PCI device information block.\r
503 @param Bus PCI device Bus NO.\r
504 @param Device PCI device Device NO.\r
505 @param Func PCI device's func NO.\r
506\r
507 @return Created PCI device instance.\r
508\r
a3b8e257 509**/\r
ead42efc 510PCI_IO_DEVICE *\r
511GatherP2CInfo (\r
512 IN PCI_IO_DEVICE *Bridge,\r
513 IN PCI_TYPE00 *Pci,\r
8e8227d1 514 IN UINT8 Bus,\r
515 IN UINT8 Device,\r
516 IN UINT8 Func\r
ead42efc 517 )\r
ead42efc 518{\r
519 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
520 PCI_IO_DEVICE *PciIoDevice;\r
521\r
522 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
523 PciIoDevice = CreatePciIoDevice (\r
524 PciRootBridgeIo,\r
525 Pci,\r
526 Bus,\r
527 Device,\r
528 Func\r
529 );\r
530\r
97404058 531 if (PciIoDevice == NULL) {\r
ead42efc 532 return NULL;\r
533 }\r
534\r
535 //\r
536 // Create a device path for this PCI device and store it into its private data\r
537 //\r
538 CreatePciDevicePath (\r
539 Bridge->DevicePath,\r
540 PciIoDevice\r
541 );\r
542\r
543 if (gFullEnumeration) {\r
94b9d5c6 544 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
ead42efc 545\r
546 //\r
547 // Initalize the bridge control register\r
548 //\r
94b9d5c6 549 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);\r
ead42efc 550 }\r
8e8227d1 551\r
ead42efc 552 //\r
553 // P2C only has one bar that is in 0x10\r
554 //\r
555 PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);\r
556\r
557 //\r
558 // Read PciBar information from the bar register\r
559 //\r
560 GetBackPcCardBar (PciIoDevice);\r
561 PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED |\r
562 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |\r
563 EFI_BRIDGE_IO32_DECODE_SUPPORTED;\r
564\r
565 return PciIoDevice;\r
566}\r
567\r
a3b8e257 568/**\r
8e8227d1 569 Create device path for pci deivce.\r
570\r
97404058 571 @param ParentDevicePath Parent bridge's path.\r
572 @param PciIoDevice Pci device instance.\r
8e8227d1 573\r
574 @return Device path protocol instance for specific pci device.\r
575\r
a3b8e257 576**/\r
ead42efc 577EFI_DEVICE_PATH_PROTOCOL *\r
578CreatePciDevicePath (\r
579 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
580 IN PCI_IO_DEVICE *PciIoDevice\r
581 )\r
ead42efc 582{\r
583\r
584 PCI_DEVICE_PATH PciNode;\r
585\r
586 //\r
587 // Create PCI device path\r
588 //\r
589 PciNode.Header.Type = HARDWARE_DEVICE_PATH;\r
590 PciNode.Header.SubType = HW_PCI_DP;\r
591 SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));\r
592\r
593 PciNode.Device = PciIoDevice->DeviceNumber;\r
594 PciNode.Function = PciIoDevice->FunctionNumber;\r
595 PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);\r
596\r
597 return PciIoDevice->DevicePath;\r
598}\r
599\r
a3b8e257 600/**\r
8e8227d1 601 Check whether the bar is existed or not.\r
a3b8e257 602\r
8e8227d1 603 @param PciIoDevice A pointer to the PCI_IO_DEVICE.\r
604 @param Offset The offset.\r
605 @param BarLengthValue The bar length value returned.\r
606 @param OriginalBarValue The original bar value returned.\r
a3b8e257 607\r
8e8227d1 608 @retval EFI_NOT_FOUND The bar doesn't exist.\r
609 @retval EFI_SUCCESS The bar exist.\r
a3b8e257 610\r
611**/\r
ead42efc 612EFI_STATUS\r
613BarExisted (\r
8e8227d1 614 IN PCI_IO_DEVICE *PciIoDevice,\r
615 IN UINTN Offset,\r
616 OUT UINT32 *BarLengthValue,\r
617 OUT UINT32 *OriginalBarValue\r
ead42efc 618 )\r
ead42efc 619{\r
620 EFI_PCI_IO_PROTOCOL *PciIo;\r
621 UINT32 OriginalValue;\r
622 UINT32 Value;\r
623 EFI_TPL OldTpl;\r
624\r
625 PciIo = &PciIoDevice->PciIo;\r
626\r
627 //\r
628 // Preserve the original value\r
629 //\r
9eb130ff 630 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);\r
ead42efc 631\r
632 //\r
633 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
634 //\r
635 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
636\r
9eb130ff 637 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne);\r
638 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value);\r
ead42efc 639\r
640 //\r
641 // Write back the original value\r
642 //\r
9eb130ff 643 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);\r
ead42efc 644\r
645 //\r
646 // Restore TPL to its original level\r
647 //\r
648 gBS->RestoreTPL (OldTpl);\r
649\r
650 if (BarLengthValue != NULL) {\r
651 *BarLengthValue = Value;\r
652 }\r
653\r
654 if (OriginalBarValue != NULL) {\r
655 *OriginalBarValue = OriginalValue;\r
656 }\r
657\r
658 if (Value == 0) {\r
659 return EFI_NOT_FOUND;\r
660 } else {\r
661 return EFI_SUCCESS;\r
662 }\r
663}\r
664\r
a3b8e257 665/**\r
8e8227d1 666 Test whether the device can support given attributes.\r
667\r
668 @param PciIoDevice Pci device instance.\r
669 @param Command Input command register value, and\r
670 returned supported register value.\r
671 @param BridgeControl Inout bridge control value for PPB or P2C, and\r
672 returned supported bridge control value.\r
673 @param OldCommand Returned and stored old command register offset.\r
674 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.\r
675\r
a3b8e257 676**/\r
8e8227d1 677VOID\r
ead42efc 678PciTestSupportedAttribute (\r
8e8227d1 679 IN PCI_IO_DEVICE *PciIoDevice,\r
680 IN OUT UINT16 *Command,\r
681 IN OUT UINT16 *BridgeControl,\r
682 OUT UINT16 *OldCommand,\r
683 OUT UINT16 *OldBridgeControl\r
ead42efc 684 )\r
ead42efc 685{\r
686 EFI_TPL OldTpl;\r
687\r
688 //\r
689 // Preserve the original value\r
690 //\r
94b9d5c6 691 PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);\r
ead42efc 692\r
693 //\r
694 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
695 //\r
696 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
697\r
94b9d5c6 698 PCI_SET_COMMAND_REGISTER (PciIoDevice, *Command);\r
699 PCI_READ_COMMAND_REGISTER (PciIoDevice, Command);\r
ead42efc 700\r
701 //\r
702 // Write back the original value\r
703 //\r
94b9d5c6 704 PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);\r
ead42efc 705\r
706 //\r
707 // Restore TPL to its original level\r
708 //\r
709 gBS->RestoreTPL (OldTpl);\r
710\r
711 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
712\r
713 //\r
714 // Preserve the original value\r
715 //\r
94b9d5c6 716 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);\r
ead42efc 717\r
718 //\r
719 // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
720 //\r
721 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
722\r
94b9d5c6 723 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);\r
724 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);\r
ead42efc 725\r
726 //\r
727 // Write back the original value\r
728 //\r
94b9d5c6 729 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);\r
ead42efc 730\r
731 //\r
732 // Restore TPL to its original level\r
733 //\r
734 gBS->RestoreTPL (OldTpl);\r
735\r
736 } else {\r
737 *OldBridgeControl = 0;\r
738 *BridgeControl = 0;\r
739 }\r
ead42efc 740}\r
741\r
a3b8e257 742/**\r
8e8227d1 743 Set the supported or current attributes of a PCI device.\r
744\r
745 @param PciIoDevice Structure pointer for PCI device.\r
746 @param Command Command register value.\r
747 @param BridgeControl Bridge control value for PPB or P2C.\r
748 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.\r
749\r
a3b8e257 750**/\r
8e8227d1 751VOID\r
ead42efc 752PciSetDeviceAttribute (\r
753 IN PCI_IO_DEVICE *PciIoDevice,\r
754 IN UINT16 Command,\r
755 IN UINT16 BridgeControl,\r
756 IN UINTN Option\r
757 )\r
ead42efc 758{\r
759 UINT64 Attributes;\r
760\r
761 Attributes = 0;\r
762\r
97404058 763 if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {\r
ead42efc 764 Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;\r
765 }\r
766\r
97404058 767 if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {\r
ead42efc 768 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;\r
769 }\r
770\r
97404058 771 if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {\r
ead42efc 772 Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;\r
773 }\r
774\r
97404058 775 if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {\r
ead42efc 776 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
777 }\r
778\r
97404058 779 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {\r
ead42efc 780 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;\r
781 }\r
782\r
97404058 783 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {\r
ead42efc 784 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;\r
785 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
786 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
787 }\r
788\r
97404058 789 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {\r
ead42efc 790 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;\r
791 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;\r
792 }\r
793\r
794 if (Option == EFI_SET_SUPPORTS) {\r
795\r
796 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |\r
797 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |\r
798 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |\r
799 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |\r
800 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |\r
801 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;\r
802\r
97404058 803 if ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) != 0) {\r
ead42efc 804 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;\r
805 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;\r
806 }\r
807\r
808 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
809 //\r
810 // For bridge, it should support IDE attributes\r
811 //\r
812 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
813 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
814 } else {\r
815\r
816 if (IS_PCI_IDE (&PciIoDevice->Pci)) {\r
817 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
818 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
819 }\r
820\r
821 if (IS_PCI_VGA (&PciIoDevice->Pci)) {\r
822 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
823 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;\r
824 }\r
825 }\r
826\r
827 PciIoDevice->Supports = Attributes;\r
828 PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \\r
829 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \\r
830 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );\r
831\r
832 } else {\r
833 PciIoDevice->Attributes = Attributes;\r
834 }\r
ead42efc 835}\r
836\r
a3b8e257 837/**\r
97404058 838 Determine if the device can support Fast Back to Back attribute.\r
8e8227d1 839\r
97404058 840 @param PciIoDevice Pci device instance.\r
841 @param StatusIndex Status register value.\r
8e8227d1 842\r
843 @retval EFI_SUCCESS This device support Fast Back to Back attribute.\r
844 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.\r
845\r
a3b8e257 846**/\r
ead42efc 847EFI_STATUS\r
848GetFastBackToBackSupport (\r
849 IN PCI_IO_DEVICE *PciIoDevice,\r
850 IN UINT8 StatusIndex\r
851 )\r
ead42efc 852{\r
853 EFI_PCI_IO_PROTOCOL *PciIo;\r
854 EFI_STATUS Status;\r
855 UINT32 StatusRegister;\r
856\r
857 //\r
858 // Read the status register\r
859 //\r
860 PciIo = &PciIoDevice->PciIo;\r
9eb130ff 861 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);\r
ead42efc 862 if (EFI_ERROR (Status)) {\r
863 return EFI_UNSUPPORTED;\r
864 }\r
865\r
866 //\r
867 // Check the Fast B2B bit\r
868 //\r
97404058 869 if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {\r
ead42efc 870 return EFI_SUCCESS;\r
871 } else {\r
872 return EFI_UNSUPPORTED;\r
873 }\r
ead42efc 874}\r
875\r
bcd70414 876/**\r
ead42efc 877 Process the option ROM for all the children of the specified parent PCI device.\r
878 It can only be used after the first full Option ROM process.\r
879\r
97404058 880 @param PciIoDevice Pci device instance.\r
8e8227d1 881\r
bcd70414 882**/\r
8e8227d1 883VOID\r
a3b8e257 884ProcessOptionRomLight (\r
885 IN PCI_IO_DEVICE *PciIoDevice\r
886 )\r
ead42efc 887{\r
888 PCI_IO_DEVICE *Temp;\r
889 LIST_ENTRY *CurrentLink;\r
890\r
891 //\r
892 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
893 //\r
894 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
97404058 895 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
ead42efc 896\r
897 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
898\r
899 if (!IsListEmpty (&Temp->ChildList)) {\r
900 ProcessOptionRomLight (Temp);\r
901 }\r
902\r
903 PciRomGetImageMapping (Temp);\r
eb9a9a5e 904\r
905 //\r
906 // The OpRom has already been processed in the first round\r
907 //\r
908 Temp->AllOpRomProcessed = TRUE;\r
909\r
ead42efc 910 CurrentLink = CurrentLink->ForwardLink;\r
911 }\r
ead42efc 912}\r
913\r
a3b8e257 914/**\r
8e8227d1 915 Determine the related attributes of all devices under a Root Bridge.\r
916\r
917 @param PciIoDevice PCI device instance.\r
918\r
a3b8e257 919**/\r
ead42efc 920EFI_STATUS\r
921DetermineDeviceAttribute (\r
922 IN PCI_IO_DEVICE *PciIoDevice\r
923 )\r
ead42efc 924{\r
925 UINT16 Command;\r
926 UINT16 BridgeControl;\r
927 UINT16 OldCommand;\r
928 UINT16 OldBridgeControl;\r
929 BOOLEAN FastB2BSupport;\r
ead42efc 930 PCI_IO_DEVICE *Temp;\r
931 LIST_ENTRY *CurrentLink;\r
932 EFI_STATUS Status;\r
933\r
934 //\r
935 // For Root Bridge, just copy it by RootBridgeIo proctocol\r
936 // so as to keep consistent with the actual attribute\r
937 //\r
97404058 938 if (PciIoDevice->Parent == NULL) {\r
ead42efc 939 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (\r
940 PciIoDevice->PciRootBridgeIo,\r
941 &PciIoDevice->Supports,\r
942 &PciIoDevice->Attributes\r
943 );\r
944 if (EFI_ERROR (Status)) {\r
945 return Status;\r
946 }\r
947 } else {\r
948\r
949 //\r
950 // Set the attributes to be checked for common PCI devices and PPB or P2C\r
951 // Since some devices only support part of them, it is better to set the\r
952 // attribute according to its command or bridge control register\r
953 //\r
954 Command = EFI_PCI_COMMAND_IO_SPACE |\r
955 EFI_PCI_COMMAND_MEMORY_SPACE |\r
956 EFI_PCI_COMMAND_BUS_MASTER |\r
957 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;\r
958\r
959 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;\r
960\r
961 //\r
962 // Test whether the device can support attributes above\r
963 //\r
964 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);\r
965\r
966 //\r
967 // Set the supported attributes for specified PCI device\r
968 //\r
969 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);\r
970\r
971 //\r
972 // Set the current attributes for specified PCI device\r
973 //\r
974 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);\r
975\r
976 //\r
977 // Enable other supported attributes but not defined in PCI_IO_PROTOCOL\r
978 //\r
94b9d5c6 979 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);\r
ead42efc 980 }\r
981\r
982 FastB2BSupport = TRUE;\r
983\r
984 //\r
985 // P2C can not support FB2B on the secondary side\r
986 //\r
987 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
988 FastB2BSupport = FALSE;\r
989 }\r
990\r
991 //\r
992 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
993 //\r
994 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
97404058 995 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
ead42efc 996\r
997 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
998 Status = DetermineDeviceAttribute (Temp);\r
999 if (EFI_ERROR (Status)) {\r
1000 return Status;\r
1001 }\r
1002 //\r
1003 // Detect Fast Bact to Bact support for the device under the bridge\r
1004 //\r
1005 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);\r
1006 if (FastB2BSupport && EFI_ERROR (Status)) {\r
1007 FastB2BSupport = FALSE;\r
1008 }\r
1009\r
1010 CurrentLink = CurrentLink->ForwardLink;\r
1011 }\r
1012 //\r
1013 // Set or clear Fast Back to Back bit for the whole bridge\r
1014 //\r
1015 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
1016\r
1017 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
1018\r
1019 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);\r
1020\r
1021 if (EFI_ERROR (Status) || (!FastB2BSupport)) {\r
1022 FastB2BSupport = FALSE;\r
94b9d5c6 1023 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
ead42efc 1024 } else {\r
94b9d5c6 1025 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
ead42efc 1026 }\r
1027 }\r
1028\r
1029 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
97404058 1030 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
ead42efc 1031 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1032 if (FastB2BSupport) {\r
94b9d5c6 1033 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
ead42efc 1034 } else {\r
94b9d5c6 1035 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
ead42efc 1036 }\r
1037\r
1038 CurrentLink = CurrentLink->ForwardLink;\r
1039 }\r
1040 }\r
1041 //\r
1042 // End for IsListEmpty\r
1043 //\r
1044 return EFI_SUCCESS;\r
1045}\r
1046\r
a3b8e257 1047/**\r
8e8227d1 1048 This routine is used to update the bar information for those incompatible PCI device.\r
1049\r
9eb130ff 1050 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated\r
1051 Bar information.\r
8e8227d1 1052\r
1053 @retval EFI_SUCCESS Successfully updated bar information.\r
1054 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.\r
8e8227d1 1055\r
a3b8e257 1056**/\r
ead42efc 1057EFI_STATUS\r
1058UpdatePciInfo (\r
9eb130ff 1059 IN OUT PCI_IO_DEVICE *PciIoDevice\r
ead42efc 1060 )\r
ead42efc 1061{\r
1062 EFI_STATUS Status;\r
1063 UINTN BarIndex;\r
1064 UINTN BarEndIndex;\r
1065 BOOLEAN SetFlag;\r
ead42efc 1066 VOID *Configuration;\r
1067 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
1068\r
1069 Configuration = NULL;\r
ea5632e5 1070 Status = EFI_SUCCESS;\r
ead42efc 1071\r
ea5632e5 1072 if (gEfiIncompatiblePciDeviceSupport == NULL) {\r
1073 //\r
1074 // It can only be supported after the Incompatible PCI Device\r
1075 // Support Protocol has been installed\r
1076 //\r
1077 Status = gBS->LocateProtocol (\r
1078 &gEfiIncompatiblePciDeviceSupportProtocolGuid,\r
1079 NULL,\r
1080 (VOID **) &gEfiIncompatiblePciDeviceSupport\r
1081 );\r
1082 }\r
1083 if (Status == EFI_SUCCESS) {\r
1084 //\r
1085 // Check whether the device belongs to incompatible devices from protocol or not\r
1086 // If it is , then get its special requirement in the ACPI table\r
1087 //\r
1088 Status = gEfiIncompatiblePciDeviceSupport->CheckDevice (\r
1089 gEfiIncompatiblePciDeviceSupport,\r
1090 PciIoDevice->Pci.Hdr.VendorId,\r
1091 PciIoDevice->Pci.Hdr.DeviceId,\r
1092 PciIoDevice->Pci.Hdr.RevisionID,\r
1093 PciIoDevice->Pci.Device.SubsystemVendorID,\r
1094 PciIoDevice->Pci.Device.SubsystemID,\r
1095 &Configuration\r
1096 );\r
ead42efc 1097\r
ea5632e5 1098 }\r
ead42efc 1099\r
c72216a6 1100 if (EFI_ERROR (Status) || Configuration == NULL ) {\r
ea5632e5 1101 return EFI_UNSUPPORTED;\r
ead42efc 1102 }\r
1103\r
1104 //\r
1105 // Update PCI device information from the ACPI table\r
1106 //\r
1107 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;\r
1108\r
1109 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1110\r
1111 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
1112 //\r
1113 // The format is not support\r
1114 //\r
1115 break;\r
1116 }\r
1117\r
1118 BarIndex = (UINTN) Ptr->AddrTranslationOffset;\r
1119 BarEndIndex = BarIndex;\r
1120\r
1121 //\r
1122 // Update all the bars in the device\r
1123 //\r
1124 if (BarIndex == PCI_BAR_ALL) {\r
1125 BarIndex = 0;\r
1126 BarEndIndex = PCI_MAX_BAR - 1;\r
1127 }\r
1128\r
1129 if (BarIndex >= PCI_MAX_BAR) {\r
1130 Ptr++;\r
1131 continue;\r
1132 }\r
1133\r
1134 for (; BarIndex <= BarEndIndex; BarIndex++) {\r
1135 SetFlag = FALSE;\r
1136 switch (Ptr->ResType) {\r
1137 case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
1138\r
1139 //\r
1140 // Make sure the bar is memory type\r
1141 //\r
1142 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {\r
1143 SetFlag = TRUE;\r
1144 }\r
1145 break;\r
1146\r
1147 case ACPI_ADDRESS_SPACE_TYPE_IO:\r
1148\r
1149 //\r
1150 // Make sure the bar is IO type\r
1151 //\r
1152 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {\r
1153 SetFlag = TRUE;\r
1154 }\r
1155 break;\r
1156 }\r
1157\r
1158 if (SetFlag) {\r
1159\r
1160 //\r
1161 // Update the new alignment for the device\r
1162 //\r
1163 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);\r
1164\r
1165 //\r
1166 // Update the new length for the device\r
1167 //\r
1168 if (Ptr->AddrLen != PCI_BAR_NOCHANGE) {\r
1169 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;\r
1170 }\r
1171 }\r
1172 }\r
1173\r
1174 Ptr++;\r
1175 }\r
1176\r
9eb130ff 1177 FreePool (Configuration);\r
ead42efc 1178\r
8e8227d1 1179 return EFI_SUCCESS;\r
ead42efc 1180}\r
1181\r
a3b8e257 1182/**\r
8e8227d1 1183 This routine will update the alignment with the new alignment.\r
1184\r
9eb130ff 1185 @param Alignment Input Old alignment. Output updated alignment.\r
8e8227d1 1186 @param NewAlignment New alignment.\r
1187\r
a3b8e257 1188**/\r
ead42efc 1189VOID\r
1190SetNewAlign (\r
9eb130ff 1191 IN OUT UINT64 *Alignment,\r
1192 IN UINT64 NewAlignment\r
ead42efc 1193 )\r
ead42efc 1194{\r
1195 UINT64 OldAlignment;\r
1196 UINTN ShiftBit;\r
1197\r
1198 //\r
1199 // The new alignment is the same as the original,\r
1200 // so skip it\r
1201 //\r
1202 if (NewAlignment == PCI_BAR_OLD_ALIGN) {\r
1203 return ;\r
1204 }\r
1205 //\r
1206 // Check the validity of the parameter\r
1207 //\r
1208 if (NewAlignment != PCI_BAR_EVEN_ALIGN &&\r
1209 NewAlignment != PCI_BAR_SQUAD_ALIGN &&\r
1210 NewAlignment != PCI_BAR_DQUAD_ALIGN ) {\r
1211 *Alignment = NewAlignment;\r
1212 return ;\r
1213 }\r
1214\r
1215 OldAlignment = (*Alignment) + 1;\r
1216 ShiftBit = 0;\r
1217\r
1218 //\r
1219 // Get the first non-zero hex value of the length\r
1220 //\r
1221 while ((OldAlignment & 0x0F) == 0x00) {\r
1222 OldAlignment = RShiftU64 (OldAlignment, 4);\r
1223 ShiftBit += 4;\r
1224 }\r
1225\r
1226 //\r
1227 // Adjust the alignment to even, quad or double quad boundary\r
1228 //\r
1229 if (NewAlignment == PCI_BAR_EVEN_ALIGN) {\r
97404058 1230 if ((OldAlignment & 0x01) != 0) {\r
ead42efc 1231 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);\r
1232 }\r
1233 } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {\r
97404058 1234 if ((OldAlignment & 0x03) != 0) {\r
ead42efc 1235 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);\r
1236 }\r
1237 } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {\r
97404058 1238 if ((OldAlignment & 0x07) != 0) {\r
ead42efc 1239 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);\r
1240 }\r
1241 }\r
1242\r
1243 //\r
1244 // Update the old value\r
1245 //\r
1246 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;\r
1247 *Alignment = NewAlignment;\r
1248\r
1249 return ;\r
1250}\r
1251\r
a3b8e257 1252/**\r
8e8227d1 1253 Parse PCI bar information and fill them into PCI device instance.\r
1254\r
97404058 1255 @param PciIoDevice Pci device instance.\r
8e8227d1 1256 @param Offset Bar offset.\r
1257 @param BarIndex Bar index.\r
1258\r
1259 @return Next bar offset.\r
1260\r
a3b8e257 1261**/\r
ead42efc 1262UINTN\r
1263PciParseBar (\r
1264 IN PCI_IO_DEVICE *PciIoDevice,\r
1265 IN UINTN Offset,\r
1266 IN UINTN BarIndex\r
1267 )\r
ead42efc 1268{\r
1269 UINT32 Value;\r
1270 UINT32 OriginalValue;\r
1271 UINT32 Mask;\r
1272 UINT32 Data;\r
1273 UINT8 Index;\r
1274 EFI_STATUS Status;\r
1275\r
1276 OriginalValue = 0;\r
1277 Value = 0;\r
1278\r
1279 Status = BarExisted (\r
9eb130ff 1280 PciIoDevice,\r
1281 Offset,\r
1282 &Value,\r
1283 &OriginalValue\r
1284 );\r
ead42efc 1285\r
1286 if (EFI_ERROR (Status)) {\r
1287 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1288 PciIoDevice->PciBar[BarIndex].Length = 0;\r
1289 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1290\r
1291 //\r
1292 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway\r
1293 //\r
1294 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1295 return Offset + 4;\r
1296 }\r
1297\r
1298 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
97404058 1299 if ((Value & 0x01) != 0) {\r
ead42efc 1300 //\r
1301 // Device I/Os\r
1302 //\r
1303 Mask = 0xfffffffc;\r
1304\r
97404058 1305 if ((Value & 0xFFFF0000) != 0) {\r
ead42efc 1306 //\r
1307 // It is a IO32 bar\r
1308 //\r
1309 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;\r
1310 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);\r
1311 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1312\r
1313 } else {\r
1314 //\r
1315 // It is a IO16 bar\r
1316 //\r
1317 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;\r
1318 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);\r
1319 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1320\r
1321 }\r
1322 //\r
1323 // Workaround. Some platforms inplement IO bar with 0 length\r
1324 // Need to treat it as no-bar\r
1325 //\r
1326 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1327 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;\r
1328 }\r
1329\r
1330 PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;\r
1331 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1332\r
1333 } else {\r
1334\r
1335 Mask = 0xfffffff0;\r
1336\r
1337 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1338\r
1339 switch (Value & 0x07) {\r
1340\r
1341 //\r
1342 //memory space; anywhere in 32 bit address space\r
1343 //\r
1344 case 0x00:\r
97404058 1345 if ((Value & 0x08) != 0) {\r
ead42efc 1346 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1347 } else {\r
1348 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1349 }\r
1350\r
1351 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1352 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1353\r
1354 break;\r
1355\r
1356 //\r
1357 // memory space; anywhere in 64 bit address space\r
1358 //\r
1359 case 0x04:\r
97404058 1360 if ((Value & 0x08) != 0) {\r
ead42efc 1361 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;\r
1362 } else {\r
1363 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;\r
1364 }\r
1365\r
1366 //\r
1367 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1368 // is regarded as an extension for the first bar. As a result\r
1369 // the sizing will be conducted on combined 64 bit value\r
1370 // Here just store the masked first 32bit value for future size\r
1371 // calculation\r
1372 //\r
1373 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;\r
1374 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1375\r
1376 //\r
1377 // Increment the offset to point to next DWORD\r
1378 //\r
1379 Offset += 4;\r
1380\r
1381 Status = BarExisted (\r
9eb130ff 1382 PciIoDevice,\r
1383 Offset,\r
1384 &Value,\r
1385 &OriginalValue\r
1386 );\r
ead42efc 1387\r
1388 if (EFI_ERROR (Status)) {\r
1389 return Offset + 4;\r
1390 }\r
1391\r
1392 //\r
1393 // Fix the length to support some spefic 64 bit BAR\r
1394 //\r
1395 Data = Value;\r
1396 Index = 0;\r
1397 for (Data = Value; Data != 0; Data >>= 1) {\r
a3b8e257 1398 Index ++;\r
ead42efc 1399 }\r
1400 Value |= ((UINT32)(-1) << Index);\r
1401\r
1402 //\r
1403 // Calculate the size of 64bit bar\r
1404 //\r
1405 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1406\r
1407 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1408 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
1409 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1410\r
1411 break;\r
1412\r
1413 //\r
1414 // reserved\r
1415 //\r
1416 default:\r
1417 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1418 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1419 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1420\r
1421 break;\r
1422 }\r
1423 }\r
1424\r
1425 //\r
1426 // Check the length again so as to keep compatible with some special bars\r
1427 //\r
1428 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1429 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1430 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1431 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1432 }\r
1433\r
1434 //\r
1435 // Increment number of bar\r
1436 //\r
1437 return Offset + 4;\r
1438}\r
1439\r
bcd70414 1440/**\r
97404058 1441 This routine is used to initialize the bar of a PCI device.\r
ead42efc 1442\r
97404058 1443 @param PciIoDevice Pci device instance.\r
8e8227d1 1444\r
1445 @note It can be called typically when a device is going to be rejected.\r
1446\r
bcd70414 1447**/\r
8e8227d1 1448VOID\r
a3b8e257 1449InitializePciDevice (\r
8e8227d1 1450 IN PCI_IO_DEVICE *PciIoDevice\r
a3b8e257 1451 )\r
ead42efc 1452{\r
1453 EFI_PCI_IO_PROTOCOL *PciIo;\r
1454 UINT8 Offset;\r
1455\r
1456 PciIo = &(PciIoDevice->PciIo);\r
1457\r
1458 //\r
1459 // Put all the resource apertures\r
1460 // Resource base is set to all ones so as to indicate its resource\r
1461 // has not been alloacted\r
1462 //\r
1463 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
9eb130ff 1464 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
ead42efc 1465 }\r
ead42efc 1466}\r
1467\r
a3b8e257 1468/**\r
8e8227d1 1469 This routine is used to initialize the bar of a PCI-PCI Bridge device.\r
1470\r
1471 @param PciIoDevice PCI-PCI bridge device instance.\r
1472\r
a3b8e257 1473**/\r
8e8227d1 1474VOID\r
ead42efc 1475InitializePpb (\r
8e8227d1 1476 IN PCI_IO_DEVICE *PciIoDevice\r
ead42efc 1477 )\r
ead42efc 1478{\r
1479 EFI_PCI_IO_PROTOCOL *PciIo;\r
1480\r
1481 PciIo = &(PciIoDevice->PciIo);\r
1482\r
1483 //\r
1484 // Put all the resource apertures including IO16\r
1485 // Io32, pMem32, pMem64 to quiescent state\r
1486 // Resource base all ones, Resource limit all zeros\r
1487 //\r
9eb130ff 1488 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
1489 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
ead42efc 1490\r
9eb130ff 1491 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
1492 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
ead42efc 1493\r
9eb130ff 1494 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
1495 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
ead42efc 1496\r
9eb130ff 1497 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
1498 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
ead42efc 1499\r
1500 //\r
9eb130ff 1501 // Don't support use io32 as for now\r
ead42efc 1502 //\r
9eb130ff 1503 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
1504 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
ead42efc 1505\r
1506 //\r
1507 // Force Interrupt line to zero for cards that come up randomly\r
1508 //\r
9eb130ff 1509 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
ead42efc 1510}\r
1511\r
a3b8e257 1512/**\r
8e8227d1 1513 This routine is used to initialize the bar of a PCI Card Bridge device.\r
1514\r
1515 @param PciIoDevice PCI Card bridge device.\r
1516\r
a3b8e257 1517**/\r
8e8227d1 1518VOID\r
ead42efc 1519InitializeP2C (\r
8e8227d1 1520 IN PCI_IO_DEVICE *PciIoDevice\r
ead42efc 1521 )\r
ead42efc 1522{\r
1523 EFI_PCI_IO_PROTOCOL *PciIo;\r
1524\r
1525 PciIo = &(PciIoDevice->PciIo);\r
1526\r
1527 //\r
1528 // Put all the resource apertures including IO16\r
1529 // Io32, pMem32, pMem64 to quiescent state(\r
1530 // Resource base all ones, Resource limit all zeros\r
1531 //\r
9eb130ff 1532 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
1533 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
ead42efc 1534\r
9eb130ff 1535 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
1536 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
ead42efc 1537\r
9eb130ff 1538 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
1539 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
ead42efc 1540\r
9eb130ff 1541 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
1542 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
ead42efc 1543\r
1544 //\r
1545 // Force Interrupt line to zero for cards that come up randomly\r
1546 //\r
9eb130ff 1547 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
ead42efc 1548}\r
1549\r
a3b8e257 1550/**\r
1551 Create and initiliaze general PCI I/O device instance for\r
1552 PCI device/bridge device/hotplug bridge device.\r
8e8227d1 1553\r
97404058 1554 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
8e8227d1 1555 @param Pci Input Pci information block.\r
1556 @param Bus Device Bus NO.\r
1557 @param Device Device device NO.\r
1558 @param Func Device func NO.\r
1559\r
1560 @return Instance of PCI device. NULL means no instance created.\r
1561\r
a3b8e257 1562**/\r
ead42efc 1563PCI_IO_DEVICE *\r
1564CreatePciIoDevice (\r
1565 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
1566 IN PCI_TYPE00 *Pci,\r
8e8227d1 1567 IN UINT8 Bus,\r
1568 IN UINT8 Device,\r
1569 IN UINT8 Func\r
ead42efc 1570 )\r
ead42efc 1571{\r
ead42efc 1572 PCI_IO_DEVICE *PciIoDevice;\r
1573\r
48a9ea7b 1574 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
1575 if (PciIoDevice == NULL) {\r
ead42efc 1576 return NULL;\r
1577 }\r
1578\r
ead42efc 1579 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;\r
1580 PciIoDevice->Handle = NULL;\r
1581 PciIoDevice->PciRootBridgeIo = PciRootBridgeIo;\r
1582 PciIoDevice->DevicePath = NULL;\r
1583 PciIoDevice->BusNumber = Bus;\r
1584 PciIoDevice->DeviceNumber = Device;\r
1585 PciIoDevice->FunctionNumber = Func;\r
1586 PciIoDevice->Decodes = 0;\r
48a9ea7b 1587\r
ead42efc 1588 if (gFullEnumeration) {\r
1589 PciIoDevice->Allocated = FALSE;\r
1590 } else {\r
1591 PciIoDevice->Allocated = TRUE;\r
1592 }\r
1593\r
1594 PciIoDevice->Registered = FALSE;\r
1595 PciIoDevice->Attributes = 0;\r
1596 PciIoDevice->Supports = 0;\r
1597 PciIoDevice->BusOverride = FALSE;\r
1598 PciIoDevice->AllOpRomProcessed = FALSE;\r
1599\r
1600 PciIoDevice->IsPciExp = FALSE;\r
1601\r
1602 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
1603\r
1604 //\r
1605 // Initialize the PCI I/O instance structure\r
1606 //\r
8e6b0dcb 1607 InitializePciIoInstance (PciIoDevice);\r
1608 InitializePciDriverOverrideInstance (PciIoDevice);\r
1609 InitializePciLoadFile2 (PciIoDevice);\r
ead42efc 1610\r
ead42efc 1611 //\r
1612 // Initialize the reserved resource list\r
1613 //\r
1614 InitializeListHead (&PciIoDevice->ReservedResourceList);\r
1615\r
1616 //\r
1617 // Initialize the driver list\r
1618 //\r
1619 InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
1620\r
1621 //\r
1622 // Initialize the child list\r
1623 //\r
1624 InitializeListHead (&PciIoDevice->ChildList);\r
1625\r
1626 return PciIoDevice;\r
1627}\r
1628\r
bcd70414 1629/**\r
ead42efc 1630 This routine is used to enumerate entire pci bus system\r
8e8227d1 1631 in a given platform.\r
1632\r
eb9a9a5e 1633 It is only called on the second start on the same Root Bridge.\r
ead42efc 1634\r
8e8227d1 1635 @param Controller Parent bridge handler.\r
1636\r
1637 @retval EFI_SUCCESS PCI enumeration finished successfully.\r
1638 @retval other Some error occurred when enumerating the pci bus system.\r
1639\r
bcd70414 1640**/\r
a3b8e257 1641EFI_STATUS\r
1642PciEnumeratorLight (\r
1643 IN EFI_HANDLE Controller\r
1644 )\r
ead42efc 1645{\r
1646\r
1647 EFI_STATUS Status;\r
1648 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1649 PCI_IO_DEVICE *RootBridgeDev;\r
1650 UINT16 MinBus;\r
1651 UINT16 MaxBus;\r
1652 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
1653\r
1654 MinBus = 0;\r
1655 MaxBus = PCI_MAX_BUS;\r
1656 Descriptors = NULL;\r
1657\r
1658 //\r
eb9a9a5e 1659 // If this root bridge has been already enumerated, then return successfully\r
ead42efc 1660 //\r
eb9a9a5e 1661 if (GetRootBridgeByHandle (Controller) != NULL) {\r
ead42efc 1662 return EFI_SUCCESS;\r
1663 }\r
1664\r
1665 //\r
1666 // Open pci root bridge io protocol\r
1667 //\r
1668 Status = gBS->OpenProtocol (\r
1669 Controller,\r
1670 &gEfiPciRootBridgeIoProtocolGuid,\r
1671 (VOID **) &PciRootBridgeIo,\r
1672 gPciBusDriverBinding.DriverBindingHandle,\r
1673 Controller,\r
1674 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1675 );\r
1676 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
1677 return Status;\r
1678 }\r
1679\r
1680 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
1681\r
1682 if (EFI_ERROR (Status)) {\r
1683 return Status;\r
1684 }\r
1685\r
1686 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
1687\r
1688 //\r
1689 // Create a device node for root bridge device with a NULL host bridge controller handle\r
1690 //\r
1691 RootBridgeDev = CreateRootBridge (Controller);\r
1692\r
97404058 1693 if (RootBridgeDev == NULL) {\r
ead42efc 1694 Descriptors++;\r
1695 continue;\r
1696 }\r
1697\r
1698 //\r
8e8227d1 1699 // Record the root bridgeio protocol\r
ead42efc 1700 //\r
1701 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
1702\r
1703 Status = PciPciDeviceInfoCollector (\r
9eb130ff 1704 RootBridgeDev,\r
1705 (UINT8) MinBus\r
1706 );\r
ead42efc 1707\r
1708 if (!EFI_ERROR (Status)) {\r
1709\r
1710 //\r
1711 // Remove those PCI devices which are rejected when full enumeration\r
1712 //\r
1713 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
1714\r
1715 //\r
1716 // Process option rom light\r
1717 //\r
1718 ProcessOptionRomLight (RootBridgeDev);\r
1719\r
1720 //\r
1721 // Determine attributes for all devices under this root bridge\r
1722 //\r
1723 DetermineDeviceAttribute (RootBridgeDev);\r
1724\r
1725 //\r
1726 // If successfully, insert the node into device pool\r
1727 //\r
1728 InsertRootBridge (RootBridgeDev);\r
1729 } else {\r
1730\r
1731 //\r
1732 // If unsuccessly, destroy the entire node\r
1733 //\r
1734 DestroyRootBridge (RootBridgeDev);\r
1735 }\r
1736\r
1737 Descriptors++;\r
1738 }\r
1739\r
1740 return EFI_SUCCESS;\r
1741}\r
1742\r
a3b8e257 1743/**\r
8e8227d1 1744 Get bus range from PCI resource descriptor list.\r
1745\r
a3b8e257 1746 @param Descriptors A pointer to the address space descriptor.\r
8e8227d1 1747 @param MinBus The min bus returned.\r
1748 @param MaxBus The max bus returned.\r
1749 @param BusRange The bus range returned.\r
1750\r
1751 @retval EFI_SUCCESS Successfully got bus range.\r
1752 @retval EFI_NOT_FOUND Can not find the specific bus.\r
1753\r
a3b8e257 1754**/\r
ead42efc 1755EFI_STATUS\r
1756PciGetBusRange (\r
1757 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
1758 OUT UINT16 *MinBus,\r
1759 OUT UINT16 *MaxBus,\r
1760 OUT UINT16 *BusRange\r
1761 )\r
ead42efc 1762{\r
ead42efc 1763 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1764 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
1765 if (MinBus != NULL) {\r
1766 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;\r
1767 }\r
1768\r
1769 if (MaxBus != NULL) {\r
1770 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;\r
1771 }\r
1772\r
1773 if (BusRange != NULL) {\r
1774 *BusRange = (UINT16) (*Descriptors)->AddrLen;\r
1775 }\r
1776\r
1777 return EFI_SUCCESS;\r
1778 }\r
1779\r
1780 (*Descriptors)++;\r
1781 }\r
1782\r
1783 return EFI_NOT_FOUND;\r
1784}\r
1785\r
eeefcb9d 1786/**\r
1787 This routine can be used to start the root bridge.\r
1788\r
1789 @param RootBridgeDev Pci device instance.\r
1790\r
1791 @retval EFI_SUCCESS This device started.\r
8e8227d1 1792 @retval other Failed to get PCI Root Bridge I/O protocol.\r
1793\r
eeefcb9d 1794**/\r
ead42efc 1795EFI_STATUS\r
1796StartManagingRootBridge (\r
1797 IN PCI_IO_DEVICE *RootBridgeDev\r
1798 )\r
ead42efc 1799{\r
1800 EFI_HANDLE RootBridgeHandle;\r
1801 EFI_STATUS Status;\r
1802 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1803\r
1804 //\r
1805 // Get the root bridge handle\r
1806 //\r
8e8227d1 1807 RootBridgeHandle = RootBridgeDev->Handle;\r
1808 PciRootBridgeIo = NULL;\r
ead42efc 1809\r
1810 //\r
1811 // Get the pci root bridge io protocol\r
1812 //\r
1813 Status = gBS->OpenProtocol (\r
1814 RootBridgeHandle,\r
1815 &gEfiPciRootBridgeIoProtocolGuid,\r
1816 (VOID **) &PciRootBridgeIo,\r
1817 gPciBusDriverBinding.DriverBindingHandle,\r
1818 RootBridgeHandle,\r
1819 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1820 );\r
1821\r
1822 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
1823 return Status;\r
1824 }\r
1825\r
1826 //\r
1827 // Store the PciRootBridgeIo protocol into root bridge private data\r
1828 //\r
1829 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
1830\r
1831 return EFI_SUCCESS;\r
1832\r
1833}\r
1834\r
bcd70414 1835/**\r
8e8227d1 1836 This routine can be used to check whether a PCI device should be rejected when light enumeration.\r
ead42efc 1837\r
97404058 1838 @param PciIoDevice Pci device instance.\r
ead42efc 1839\r
97404058 1840 @retval TRUE This device should be rejected.\r
1841 @retval FALSE This device shouldn't be rejected.\r
8e8227d1 1842\r
bcd70414 1843**/\r
a3b8e257 1844BOOLEAN\r
1845IsPciDeviceRejected (\r
1846 IN PCI_IO_DEVICE *PciIoDevice\r
1847 )\r
ead42efc 1848{\r
1849 EFI_STATUS Status;\r
1850 UINT32 TestValue;\r
1851 UINT32 OldValue;\r
1852 UINT32 Mask;\r
1853 UINT8 BarOffset;\r
1854\r
1855 //\r
1856 // PPB should be skip!\r
1857 //\r
1858 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
1859 return FALSE;\r
1860 }\r
1861\r
1862 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1863 //\r
1864 // Only test base registers for P2C\r
1865 //\r
1866 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
1867\r
1868 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
1869 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
1870 if (EFI_ERROR (Status)) {\r
1871 continue;\r
1872 }\r
1873\r
1874 TestValue = TestValue & Mask;\r
1875 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1876 //\r
1877 // The bar isn't programed, so it should be rejected\r
1878 //\r
1879 return TRUE;\r
1880 }\r
1881 }\r
1882\r
1883 return FALSE;\r
1884 }\r
1885\r
1886 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
1887 //\r
1888 // Test PCI devices\r
1889 //\r
1890 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
1891 if (EFI_ERROR (Status)) {\r
1892 continue;\r
1893 }\r
1894\r
97404058 1895 if ((TestValue & 0x01) != 0) {\r
ead42efc 1896\r
1897 //\r
1898 // IO Bar\r
1899 //\r
ead42efc 1900 Mask = 0xFFFFFFFC;\r
1901 TestValue = TestValue & Mask;\r
1902 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1903 return TRUE;\r
1904 }\r
1905\r
1906 } else {\r
1907\r
1908 //\r
1909 // Mem Bar\r
1910 //\r
ead42efc 1911 Mask = 0xFFFFFFF0;\r
1912 TestValue = TestValue & Mask;\r
1913\r
1914 if ((TestValue & 0x07) == 0x04) {\r
1915\r
1916 //\r
1917 // Mem64 or PMem64\r
1918 //\r
1919 BarOffset += sizeof (UINT32);\r
1920 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1921\r
1922 //\r
1923 // Test its high 32-Bit BAR\r
1924 //\r
ead42efc 1925 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
1926 if (TestValue == OldValue) {\r
1927 return TRUE;\r
1928 }\r
1929 }\r
1930\r
1931 } else {\r
1932\r
1933 //\r
1934 // Mem32 or PMem32\r
1935 //\r
1936 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1937 return TRUE;\r
1938 }\r
1939 }\r
1940 }\r
1941 }\r
1942\r
1943 return FALSE;\r
1944}\r
1945\r
a3b8e257 1946/**\r
8e8227d1 1947 Reset all bus number from specific bridge.\r
1948\r
97404058 1949 @param Bridge Parent specific bridge.\r
8e8227d1 1950 @param StartBusNumber Start bus number.\r
1951\r
a3b8e257 1952**/\r
8e8227d1 1953VOID\r
ff62de37 1954ResetAllPpbBusNumber (\r
ead42efc 1955 IN PCI_IO_DEVICE *Bridge,\r
1956 IN UINT8 StartBusNumber\r
1957 )\r
ead42efc 1958{\r
1959 EFI_STATUS Status;\r
1960 PCI_TYPE00 Pci;\r
1961 UINT8 Device;\r
1962 UINT32 Register;\r
1963 UINT8 Func;\r
1964 UINT64 Address;\r
ff62de37 1965 UINT8 SecondaryBus;\r
ead42efc 1966 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1967\r
1968 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
1969\r
1970 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
1971 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
1972\r
1973 //\r
1974 // Check to see whether a pci device is present\r
1975 //\r
1976 Status = PciDevicePresent (\r
9eb130ff 1977 PciRootBridgeIo,\r
1978 &Pci,\r
1979 StartBusNumber,\r
1980 Device,\r
1981 Func\r
1982 );\r
ead42efc 1983\r
1984 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
ff62de37 1985\r
ead42efc 1986 Register = 0;\r
1987 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
9eb130ff 1988 Status = PciRootBridgeIo->Pci.Read (\r
1989 PciRootBridgeIo,\r
1990 EfiPciWidthUint32,\r
1991 Address,\r
1992 1,\r
1993 &Register\r
1994 );\r
ff62de37 1995 SecondaryBus = (UINT8)(Register >> 8);\r
1996\r
1997 if (SecondaryBus != 0) {\r
1998 ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
1999 }\r
2000\r
ead42efc 2001 //\r
2002 // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2003 //\r
2004 Register &= 0xFF000000;\r
9eb130ff 2005 Status = PciRootBridgeIo->Pci.Write (\r
ead42efc 2006 PciRootBridgeIo,\r
ead42efc 2007 EfiPciWidthUint32,\r
2008 Address,\r
2009 1,\r
2010 &Register\r
2011 );\r
2012 }\r
2013\r
2014 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
2015 //\r
2016 // Skip sub functions, this is not a multi function device\r
2017 //\r
2018 Func = PCI_MAX_FUNC;\r
2019 }\r
2020 }\r
2021 }\r
ead42efc 2022}\r
2023\r