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