]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
1. used PciPlatfromProtocolGuid to get VgaIo and IsaIo supported capability.
[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
1227 gBS->FreePool (Configuration);\r
1228 return Status;\r
1229\r
1230}\r
1231\r
a3b8e257 1232/**\r
1233 This routine will update the alignment with the new alignment\r
1234 \r
97404058 1235 @param Alignment old alignment.\r
1236 @param NewAlignment new alignment.\r
a3b8e257 1237 \r
1238**/\r
ead42efc 1239VOID\r
1240SetNewAlign (\r
1241 IN UINT64 *Alignment,\r
1242 IN UINT64 NewAlignment\r
1243 )\r
ead42efc 1244{\r
1245 UINT64 OldAlignment;\r
1246 UINTN ShiftBit;\r
1247\r
1248 //\r
1249 // The new alignment is the same as the original,\r
1250 // so skip it\r
1251 //\r
1252 if (NewAlignment == PCI_BAR_OLD_ALIGN) {\r
1253 return ;\r
1254 }\r
1255 //\r
1256 // Check the validity of the parameter\r
1257 //\r
1258 if (NewAlignment != PCI_BAR_EVEN_ALIGN &&\r
1259 NewAlignment != PCI_BAR_SQUAD_ALIGN &&\r
1260 NewAlignment != PCI_BAR_DQUAD_ALIGN ) {\r
1261 *Alignment = NewAlignment;\r
1262 return ;\r
1263 }\r
1264\r
1265 OldAlignment = (*Alignment) + 1;\r
1266 ShiftBit = 0;\r
1267\r
1268 //\r
1269 // Get the first non-zero hex value of the length\r
1270 //\r
1271 while ((OldAlignment & 0x0F) == 0x00) {\r
1272 OldAlignment = RShiftU64 (OldAlignment, 4);\r
1273 ShiftBit += 4;\r
1274 }\r
1275\r
1276 //\r
1277 // Adjust the alignment to even, quad or double quad boundary\r
1278 //\r
1279 if (NewAlignment == PCI_BAR_EVEN_ALIGN) {\r
97404058 1280 if ((OldAlignment & 0x01) != 0) {\r
ead42efc 1281 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);\r
1282 }\r
1283 } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {\r
97404058 1284 if ((OldAlignment & 0x03) != 0) {\r
ead42efc 1285 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);\r
1286 }\r
1287 } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {\r
97404058 1288 if ((OldAlignment & 0x07) != 0) {\r
ead42efc 1289 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);\r
1290 }\r
1291 }\r
1292\r
1293 //\r
1294 // Update the old value\r
1295 //\r
1296 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;\r
1297 *Alignment = NewAlignment;\r
1298\r
1299 return ;\r
1300}\r
1301\r
a3b8e257 1302/**\r
1303 Parse PCI bar bit.\r
1304 \r
97404058 1305 @param PciIoDevice Pci device instance.\r
1306 @param Offset bar offset.\r
1307 @param BarIndex bar index.\r
a3b8e257 1308 \r
1309 @return next bar offset.\r
1310**/\r
ead42efc 1311UINTN\r
1312PciParseBar (\r
1313 IN PCI_IO_DEVICE *PciIoDevice,\r
1314 IN UINTN Offset,\r
1315 IN UINTN BarIndex\r
1316 )\r
ead42efc 1317{\r
1318 UINT32 Value;\r
1319 UINT32 OriginalValue;\r
1320 UINT32 Mask;\r
1321 UINT32 Data;\r
1322 UINT8 Index;\r
1323 EFI_STATUS Status;\r
1324\r
1325 OriginalValue = 0;\r
1326 Value = 0;\r
1327\r
1328 Status = BarExisted (\r
1329 PciIoDevice,\r
1330 Offset,\r
1331 &Value,\r
1332 &OriginalValue\r
1333 );\r
1334\r
1335 if (EFI_ERROR (Status)) {\r
1336 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1337 PciIoDevice->PciBar[BarIndex].Length = 0;\r
1338 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1339\r
1340 //\r
1341 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway\r
1342 //\r
1343 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1344 return Offset + 4;\r
1345 }\r
1346\r
1347 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
97404058 1348 if ((Value & 0x01) != 0) {\r
ead42efc 1349 //\r
1350 // Device I/Os\r
1351 //\r
1352 Mask = 0xfffffffc;\r
1353\r
97404058 1354 if ((Value & 0xFFFF0000) != 0) {\r
ead42efc 1355 //\r
1356 // It is a IO32 bar\r
1357 //\r
1358 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;\r
1359 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);\r
1360 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1361\r
1362 } else {\r
1363 //\r
1364 // It is a IO16 bar\r
1365 //\r
1366 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;\r
1367 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);\r
1368 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1369\r
1370 }\r
1371 //\r
1372 // Workaround. Some platforms inplement IO bar with 0 length\r
1373 // Need to treat it as no-bar\r
1374 //\r
1375 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1376 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;\r
1377 }\r
1378\r
1379 PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;\r
1380 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1381\r
1382 } else {\r
1383\r
1384 Mask = 0xfffffff0;\r
1385\r
1386 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1387\r
1388 switch (Value & 0x07) {\r
1389\r
1390 //\r
1391 //memory space; anywhere in 32 bit address space\r
1392 //\r
1393 case 0x00:\r
97404058 1394 if ((Value & 0x08) != 0) {\r
ead42efc 1395 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1396 } else {\r
1397 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1398 }\r
1399\r
1400 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1401 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1402\r
1403 break;\r
1404\r
1405 //\r
1406 // memory space; anywhere in 64 bit address space\r
1407 //\r
1408 case 0x04:\r
97404058 1409 if ((Value & 0x08) != 0) {\r
ead42efc 1410 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;\r
1411 } else {\r
1412 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;\r
1413 }\r
1414\r
1415 //\r
1416 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1417 // is regarded as an extension for the first bar. As a result\r
1418 // the sizing will be conducted on combined 64 bit value\r
1419 // Here just store the masked first 32bit value for future size\r
1420 // calculation\r
1421 //\r
1422 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;\r
1423 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1424\r
1425 //\r
1426 // Increment the offset to point to next DWORD\r
1427 //\r
1428 Offset += 4;\r
1429\r
1430 Status = BarExisted (\r
1431 PciIoDevice,\r
1432 Offset,\r
1433 &Value,\r
1434 &OriginalValue\r
1435 );\r
1436\r
1437 if (EFI_ERROR (Status)) {\r
1438 return Offset + 4;\r
1439 }\r
1440\r
1441 //\r
1442 // Fix the length to support some spefic 64 bit BAR\r
1443 //\r
1444 Data = Value;\r
1445 Index = 0;\r
1446 for (Data = Value; Data != 0; Data >>= 1) {\r
a3b8e257 1447 Index ++;\r
ead42efc 1448 }\r
1449 Value |= ((UINT32)(-1) << Index);\r
1450\r
1451 //\r
1452 // Calculate the size of 64bit bar\r
1453 //\r
1454 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1455\r
1456 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1457 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
1458 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1459\r
1460 break;\r
1461\r
1462 //\r
1463 // reserved\r
1464 //\r
1465 default:\r
1466 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1467 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1468 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1469\r
1470 break;\r
1471 }\r
1472 }\r
1473\r
1474 //\r
1475 // Check the length again so as to keep compatible with some special bars\r
1476 //\r
1477 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1478 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1479 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1480 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1481 }\r
1482\r
1483 //\r
1484 // Increment number of bar\r
1485 //\r
1486 return Offset + 4;\r
1487}\r
1488\r
bcd70414 1489/**\r
97404058 1490 This routine is used to initialize the bar of a PCI device.\r
1491 It can be called typically when a device is going to be rejected.\r
ead42efc 1492\r
97404058 1493 @param PciIoDevice Pci device instance.\r
bcd70414 1494**/\r
a3b8e257 1495EFI_STATUS\r
1496InitializePciDevice (\r
1497 IN PCI_IO_DEVICE *PciIoDevice\r
1498 )\r
ead42efc 1499{\r
1500 EFI_PCI_IO_PROTOCOL *PciIo;\r
1501 UINT8 Offset;\r
1502\r
1503 PciIo = &(PciIoDevice->PciIo);\r
1504\r
1505 //\r
1506 // Put all the resource apertures\r
1507 // Resource base is set to all ones so as to indicate its resource\r
1508 // has not been alloacted\r
1509 //\r
1510 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
1511 PciIoWrite (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
1512 }\r
1513\r
1514 return EFI_SUCCESS;\r
1515}\r
1516\r
a3b8e257 1517/**\r
1518 Init PPB for bridge device\r
1519 \r
97404058 1520 @param PciIoDevice Pci device instance.\r
a3b8e257 1521**/\r
ead42efc 1522EFI_STATUS\r
1523InitializePpb (\r
1524 IN PCI_IO_DEVICE *PciIoDevice\r
1525 )\r
ead42efc 1526{\r
1527 EFI_PCI_IO_PROTOCOL *PciIo;\r
1528\r
1529 PciIo = &(PciIoDevice->PciIo);\r
1530\r
1531 //\r
1532 // Put all the resource apertures including IO16\r
1533 // Io32, pMem32, pMem64 to quiescent state\r
1534 // Resource base all ones, Resource limit all zeros\r
1535 //\r
1536 PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
1537 PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
1538\r
1539 PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
1540 PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
1541\r
1542 PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
1543 PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
1544\r
1545 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
1546 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
1547\r
1548 //\r
1549 // don't support use io32 as for now\r
1550 //\r
1551 PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
1552 PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
1553\r
1554 //\r
1555 // Force Interrupt line to zero for cards that come up randomly\r
1556 //\r
1557 PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
1558\r
1559 return EFI_SUCCESS;\r
1560}\r
1561\r
a3b8e257 1562/**\r
1563 Init private data for Hotplug bridge device\r
1564 \r
97404058 1565 @param PciIoDevice hotplug bridge device.\r
a3b8e257 1566**/\r
ead42efc 1567EFI_STATUS\r
1568InitializeP2C (\r
1569 IN PCI_IO_DEVICE *PciIoDevice\r
1570 )\r
ead42efc 1571{\r
1572 EFI_PCI_IO_PROTOCOL *PciIo;\r
1573\r
1574 PciIo = &(PciIoDevice->PciIo);\r
1575\r
1576 //\r
1577 // Put all the resource apertures including IO16\r
1578 // Io32, pMem32, pMem64 to quiescent state(\r
1579 // Resource base all ones, Resource limit all zeros\r
1580 //\r
1581 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
1582 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
1583\r
1584 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
1585 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
1586\r
1587 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
1588 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
1589\r
1590 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
1591 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
1592\r
1593 //\r
1594 // Force Interrupt line to zero for cards that come up randomly\r
1595 //\r
1596 PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
1597 return EFI_SUCCESS;\r
1598}\r
1599\r
a3b8e257 1600/**\r
1601 Create and initiliaze general PCI I/O device instance for\r
1602 PCI device/bridge device/hotplug bridge device.\r
1603 \r
97404058 1604 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
1605 @param Pci Pci bar block.\r
a3b8e257 1606 @param Bus device Bus NO.\r
1607 @param Device device device NO.\r
1608 @param Func device func NO.\r
1609 \r
97404058 1610 @return instance of PCI device.\r
a3b8e257 1611**/\r
ead42efc 1612PCI_IO_DEVICE *\r
1613CreatePciIoDevice (\r
1614 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
1615 IN PCI_TYPE00 *Pci,\r
1616 UINT8 Bus,\r
1617 UINT8 Device,\r
1618 UINT8 Func\r
1619 )\r
ead42efc 1620{\r
1621\r
1622 EFI_STATUS Status;\r
1623 PCI_IO_DEVICE *PciIoDevice;\r
1624\r
1625 PciIoDevice = NULL;\r
1626\r
1627 Status = gBS->AllocatePool (\r
1628 EfiBootServicesData,\r
1629 sizeof (PCI_IO_DEVICE),\r
1630 (VOID **) &PciIoDevice\r
1631 );\r
1632\r
1633 if (EFI_ERROR (Status)) {\r
1634 return NULL;\r
1635 }\r
1636\r
1637 ZeroMem (PciIoDevice, sizeof (PCI_IO_DEVICE));\r
1638\r
1639 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;\r
1640 PciIoDevice->Handle = NULL;\r
1641 PciIoDevice->PciRootBridgeIo = PciRootBridgeIo;\r
1642 PciIoDevice->DevicePath = NULL;\r
1643 PciIoDevice->BusNumber = Bus;\r
1644 PciIoDevice->DeviceNumber = Device;\r
1645 PciIoDevice->FunctionNumber = Func;\r
1646 PciIoDevice->Decodes = 0;\r
1647 if (gFullEnumeration) {\r
1648 PciIoDevice->Allocated = FALSE;\r
1649 } else {\r
1650 PciIoDevice->Allocated = TRUE;\r
1651 }\r
1652\r
1653 PciIoDevice->Registered = FALSE;\r
1654 PciIoDevice->Attributes = 0;\r
1655 PciIoDevice->Supports = 0;\r
1656 PciIoDevice->BusOverride = FALSE;\r
1657 PciIoDevice->AllOpRomProcessed = FALSE;\r
1658\r
1659 PciIoDevice->IsPciExp = FALSE;\r
1660\r
1661 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
1662\r
1663 //\r
1664 // Initialize the PCI I/O instance structure\r
1665 //\r
1666\r
8e6b0dcb 1667 InitializePciIoInstance (PciIoDevice);\r
1668 InitializePciDriverOverrideInstance (PciIoDevice);\r
1669 InitializePciLoadFile2 (PciIoDevice);\r
ead42efc 1670\r
ead42efc 1671\r
1672 //\r
1673 // Initialize the reserved resource list\r
1674 //\r
1675 InitializeListHead (&PciIoDevice->ReservedResourceList);\r
1676\r
1677 //\r
1678 // Initialize the driver list\r
1679 //\r
1680 InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
1681\r
1682 //\r
1683 // Initialize the child list\r
1684 //\r
1685 InitializeListHead (&PciIoDevice->ChildList);\r
1686\r
1687 return PciIoDevice;\r
1688}\r
1689\r
bcd70414 1690/**\r
ead42efc 1691 This routine is used to enumerate entire pci bus system\r
1692 in a given platform\r
eb9a9a5e 1693 It is only called on the second start on the same Root Bridge.\r
ead42efc 1694\r
97404058 1695 @param Controller Parent bridge handler.\r
a3b8e257 1696 \r
1697 @return status of operation.\r
bcd70414 1698**/\r
a3b8e257 1699EFI_STATUS\r
1700PciEnumeratorLight (\r
1701 IN EFI_HANDLE Controller\r
1702 )\r
ead42efc 1703{\r
1704\r
1705 EFI_STATUS Status;\r
1706 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1707 PCI_IO_DEVICE *RootBridgeDev;\r
1708 UINT16 MinBus;\r
1709 UINT16 MaxBus;\r
1710 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
1711\r
1712 MinBus = 0;\r
1713 MaxBus = PCI_MAX_BUS;\r
1714 Descriptors = NULL;\r
1715\r
1716 //\r
eb9a9a5e 1717 // If this root bridge has been already enumerated, then return successfully\r
ead42efc 1718 //\r
eb9a9a5e 1719 if (GetRootBridgeByHandle (Controller) != NULL) {\r
ead42efc 1720 return EFI_SUCCESS;\r
1721 }\r
1722\r
1723 //\r
1724 // Open pci root bridge io protocol\r
1725 //\r
1726 Status = gBS->OpenProtocol (\r
1727 Controller,\r
1728 &gEfiPciRootBridgeIoProtocolGuid,\r
1729 (VOID **) &PciRootBridgeIo,\r
1730 gPciBusDriverBinding.DriverBindingHandle,\r
1731 Controller,\r
1732 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1733 );\r
1734 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
1735 return Status;\r
1736 }\r
1737\r
1738 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
1739\r
1740 if (EFI_ERROR (Status)) {\r
1741 return Status;\r
1742 }\r
1743\r
1744 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
1745\r
1746 //\r
1747 // Create a device node for root bridge device with a NULL host bridge controller handle\r
1748 //\r
1749 RootBridgeDev = CreateRootBridge (Controller);\r
1750\r
97404058 1751 if (RootBridgeDev == NULL) {\r
ead42efc 1752 Descriptors++;\r
1753 continue;\r
1754 }\r
1755\r
1756 //\r
1757 // Record the root bridge io protocol\r
1758 //\r
1759 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
1760\r
1761 Status = PciPciDeviceInfoCollector (\r
1762 RootBridgeDev,\r
1763 (UINT8) MinBus\r
1764 );\r
1765\r
1766 if (!EFI_ERROR (Status)) {\r
1767\r
1768 //\r
1769 // Remove those PCI devices which are rejected when full enumeration\r
1770 //\r
1771 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
1772\r
1773 //\r
1774 // Process option rom light\r
1775 //\r
1776 ProcessOptionRomLight (RootBridgeDev);\r
1777\r
1778 //\r
1779 // Determine attributes for all devices under this root bridge\r
1780 //\r
1781 DetermineDeviceAttribute (RootBridgeDev);\r
1782\r
1783 //\r
1784 // If successfully, insert the node into device pool\r
1785 //\r
1786 InsertRootBridge (RootBridgeDev);\r
1787 } else {\r
1788\r
1789 //\r
1790 // If unsuccessly, destroy the entire node\r
1791 //\r
1792 DestroyRootBridge (RootBridgeDev);\r
1793 }\r
1794\r
1795 Descriptors++;\r
1796 }\r
1797\r
1798 return EFI_SUCCESS;\r
1799}\r
1800\r
a3b8e257 1801/**\r
1802 Get bus range.\r
1803 \r
1804 @param Descriptors A pointer to the address space descriptor.\r
1805 @param MinBus The min bus.\r
1806 @param MaxBus The max bus.\r
1807 @param BusRange The bus range.\r
1808 \r
1809 @retval EFI_SUCCESS Success operation.\r
1810 @retval EFI_NOT_FOUND can not find the specific bus.\r
1811**/\r
ead42efc 1812EFI_STATUS\r
1813PciGetBusRange (\r
1814 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
1815 OUT UINT16 *MinBus,\r
1816 OUT UINT16 *MaxBus,\r
1817 OUT UINT16 *BusRange\r
1818 )\r
ead42efc 1819{\r
1820\r
1821 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1822 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
1823 if (MinBus != NULL) {\r
1824 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;\r
1825 }\r
1826\r
1827 if (MaxBus != NULL) {\r
1828 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;\r
1829 }\r
1830\r
1831 if (BusRange != NULL) {\r
1832 *BusRange = (UINT16) (*Descriptors)->AddrLen;\r
1833 }\r
1834\r
1835 return EFI_SUCCESS;\r
1836 }\r
1837\r
1838 (*Descriptors)++;\r
1839 }\r
1840\r
1841 return EFI_NOT_FOUND;\r
1842}\r
1843\r
eeefcb9d 1844/**\r
1845 This routine can be used to start the root bridge.\r
1846\r
1847 @param RootBridgeDev Pci device instance.\r
1848\r
1849 @retval EFI_SUCCESS This device started.\r
1850 \r
1851**/\r
ead42efc 1852EFI_STATUS\r
1853StartManagingRootBridge (\r
1854 IN PCI_IO_DEVICE *RootBridgeDev\r
1855 )\r
ead42efc 1856{\r
1857 EFI_HANDLE RootBridgeHandle;\r
1858 EFI_STATUS Status;\r
1859 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1860\r
1861 //\r
1862 // Get the root bridge handle\r
1863 //\r
1864 RootBridgeHandle = RootBridgeDev->Handle;\r
1865 PciRootBridgeIo = NULL;\r
1866\r
1867 //\r
1868 // Get the pci root bridge io protocol\r
1869 //\r
1870 Status = gBS->OpenProtocol (\r
1871 RootBridgeHandle,\r
1872 &gEfiPciRootBridgeIoProtocolGuid,\r
1873 (VOID **) &PciRootBridgeIo,\r
1874 gPciBusDriverBinding.DriverBindingHandle,\r
1875 RootBridgeHandle,\r
1876 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1877 );\r
1878\r
1879 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
1880 return Status;\r
1881 }\r
1882\r
1883 //\r
1884 // Store the PciRootBridgeIo protocol into root bridge private data\r
1885 //\r
1886 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
1887\r
1888 return EFI_SUCCESS;\r
1889\r
1890}\r
1891\r
bcd70414 1892/**\r
ead42efc 1893 This routine can be used to check whether a PCI device should be rejected when light enumeration\r
1894\r
97404058 1895 @param PciIoDevice Pci device instance.\r
ead42efc 1896\r
97404058 1897 @retval TRUE This device should be rejected.\r
1898 @retval FALSE This device shouldn't be rejected.\r
a3b8e257 1899 \r
bcd70414 1900**/\r
a3b8e257 1901BOOLEAN\r
1902IsPciDeviceRejected (\r
1903 IN PCI_IO_DEVICE *PciIoDevice\r
1904 )\r
ead42efc 1905{\r
1906 EFI_STATUS Status;\r
1907 UINT32 TestValue;\r
1908 UINT32 OldValue;\r
1909 UINT32 Mask;\r
1910 UINT8 BarOffset;\r
1911\r
1912 //\r
1913 // PPB should be skip!\r
1914 //\r
1915 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
1916 return FALSE;\r
1917 }\r
1918\r
1919 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1920 //\r
1921 // Only test base registers for P2C\r
1922 //\r
1923 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
1924\r
1925 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
1926 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
1927 if (EFI_ERROR (Status)) {\r
1928 continue;\r
1929 }\r
1930\r
1931 TestValue = TestValue & Mask;\r
1932 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1933 //\r
1934 // The bar isn't programed, so it should be rejected\r
1935 //\r
1936 return TRUE;\r
1937 }\r
1938 }\r
1939\r
1940 return FALSE;\r
1941 }\r
1942\r
1943 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
1944 //\r
1945 // Test PCI devices\r
1946 //\r
1947 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
1948 if (EFI_ERROR (Status)) {\r
1949 continue;\r
1950 }\r
1951\r
97404058 1952 if ((TestValue & 0x01) != 0) {\r
ead42efc 1953\r
1954 //\r
1955 // IO Bar\r
1956 //\r
1957\r
1958 Mask = 0xFFFFFFFC;\r
1959 TestValue = TestValue & Mask;\r
1960 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1961 return TRUE;\r
1962 }\r
1963\r
1964 } else {\r
1965\r
1966 //\r
1967 // Mem Bar\r
1968 //\r
1969\r
1970 Mask = 0xFFFFFFF0;\r
1971 TestValue = TestValue & Mask;\r
1972\r
1973 if ((TestValue & 0x07) == 0x04) {\r
1974\r
1975 //\r
1976 // Mem64 or PMem64\r
1977 //\r
1978 BarOffset += sizeof (UINT32);\r
1979 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1980\r
1981 //\r
1982 // Test its high 32-Bit BAR\r
1983 //\r
1984\r
1985 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
1986 if (TestValue == OldValue) {\r
1987 return TRUE;\r
1988 }\r
1989 }\r
1990\r
1991 } else {\r
1992\r
1993 //\r
1994 // Mem32 or PMem32\r
1995 //\r
1996 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1997 return TRUE;\r
1998 }\r
1999 }\r
2000 }\r
2001 }\r
2002\r
2003 return FALSE;\r
2004}\r
2005\r
a3b8e257 2006/**\r
2007 Reset and all bus number from specific bridge.\r
2008 \r
97404058 2009 @param Bridge Parent specific bridge.\r
2010 @param StartBusNumber start bus number.\r
a3b8e257 2011**/\r
ead42efc 2012EFI_STATUS\r
ff62de37 2013ResetAllPpbBusNumber (\r
ead42efc 2014 IN PCI_IO_DEVICE *Bridge,\r
2015 IN UINT8 StartBusNumber\r
2016 )\r
ead42efc 2017{\r
2018 EFI_STATUS Status;\r
2019 PCI_TYPE00 Pci;\r
2020 UINT8 Device;\r
2021 UINT32 Register;\r
2022 UINT8 Func;\r
2023 UINT64 Address;\r
ff62de37 2024 UINT8 SecondaryBus;\r
ead42efc 2025 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2026\r
2027 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2028\r
2029 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
2030 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
2031\r
2032 //\r
2033 // Check to see whether a pci device is present\r
2034 //\r
2035 Status = PciDevicePresent (\r
2036 PciRootBridgeIo,\r
2037 &Pci,\r
2038 StartBusNumber,\r
2039 Device,\r
2040 Func\r
2041 );\r
2042\r
2043 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
ff62de37 2044\r
ead42efc 2045 Register = 0;\r
2046 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
2047 Status = PciRootBridgeIoRead (\r
2048 PciRootBridgeIo,\r
2049 &Pci,\r
2050 EfiPciWidthUint32,\r
2051 Address,\r
2052 1,\r
2053 &Register\r
2054 );\r
ff62de37 2055 SecondaryBus = (UINT8)(Register >> 8);\r
2056\r
2057 if (SecondaryBus != 0) {\r
2058 ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
2059 }\r
2060\r
ead42efc 2061 //\r
2062 // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2063 //\r
2064 Register &= 0xFF000000;\r
2065 Status = PciRootBridgeIoWrite (\r
2066 PciRootBridgeIo,\r
2067 &Pci,\r
2068 EfiPciWidthUint32,\r
2069 Address,\r
2070 1,\r
2071 &Register\r
2072 );\r
2073 }\r
2074\r
2075 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
2076 //\r
2077 // Skip sub functions, this is not a multi function device\r
2078 //\r
2079 Func = PCI_MAX_FUNC;\r
2080 }\r
2081 }\r
2082 }\r
2083\r
2084 return EFI_SUCCESS;\r
2085}\r
2086\r