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