]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
Clean up HiiLib.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciEnumeratorSupport.c
CommitLineData
3db51098 1/**@file\r
ead42efc 2\r
ea5632e5 3Copyright (c) 2006, Intel Corporation\r
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
15#include "pcibus.h"\r
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
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
28 \r
29 @retval EFI_NOT_FOUND device not present\r
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
87 @param Bridge Parent bridge instance\r
88 @param StartBusNumer Bus number of begining \r
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
193 @param Bridge Parent bridge instance\r
194 @param Pci Output of PCI device info block\r
195 @param Bus PCI bus NO.\r
196 @param Device PCI device NO.\r
197 @param Func PCI func NO.\r
198 @param PciDevice output of searched PCI device instance\r
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
263 if (!PciIoDevice) {\r
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
310 @param Bridge Parent bridge instance\r
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
341 if (!PciIoDevice) {\r
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
358 PciDisableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
359\r
360 }\r
361\r
362 //\r
363 // Start to parse the bars\r
364 //\r
365 for (Offset = 0x10, BarIndex = 0; Offset <= 0x24; BarIndex++) {\r
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
381 @return bridge device instance\r
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
395 UINT32 Value;\r
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
408 if (!PciIoDevice) {\r
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
421 PciDisableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
422\r
423 //\r
424 // Initalize the bridge control register\r
425 //\r
426 PciDisableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);\r
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
450 if (Value) {\r
451 if (Value & 0x01) {\r
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
504 @return hotplug bridge device instance\r
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
527 if (!PciIoDevice) {\r
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
540 PciDisableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
541\r
542 //\r
543 // Initalize the bridge control register\r
544 //\r
545 PciDisableBridgeControlRegister (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);\r
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
567 @param ParentDevicePath Parent bridge's path\r
568 @param PciIoDevice Pci device instance\r
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
665 @param PciIoDevice Pci device instance\r
666 @param Command Command register value.\r
667 @param BridgeControl Bridge control value for PPB or P2C.\r
668 @param OldCommand Old command register offset\r
669 @param OldBridgeControl Old Bridge control value for PPB or P2C.\r
670 \r
671 @return EFI_SUCCESS\r
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
687 PciReadCommandRegister (PciIoDevice, OldCommand);\r
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
694 PciSetCommandRegister (PciIoDevice, *Command);\r
695 PciReadCommandRegister (PciIoDevice, Command);\r
696\r
697 //\r
698 // Write back the original value\r
699 //\r
700 PciSetCommandRegister (PciIoDevice, *OldCommand);\r
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
712 PciReadBridgeControlRegister (PciIoDevice, OldBridgeControl);\r
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
719 PciSetBridgeControlRegister (PciIoDevice, *BridgeControl);\r
720 PciReadBridgeControlRegister (PciIoDevice, BridgeControl);\r
721\r
722 //\r
723 // Write back the original value\r
724 //\r
725 PciSetBridgeControlRegister (PciIoDevice, *OldBridgeControl);\r
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
761 if (Command & EFI_PCI_COMMAND_IO_SPACE) {\r
762 Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;\r
763 }\r
764\r
765 if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) {\r
766 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;\r
767 }\r
768\r
769 if (Command & EFI_PCI_COMMAND_BUS_MASTER) {\r
770 Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;\r
771 }\r
772\r
773 if (Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) {\r
774 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
775 }\r
776\r
777 if (BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) {\r
778 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;\r
779 }\r
780\r
781 if (BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) {\r
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
787 if (BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) {\r
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
801 if (Attributes & EFI_PCI_IO_ATTRIBUTE_IO) {\r
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
838 Determine if the device can support Fast Back to Back attribute\r
839 \r
840 @param PciIoDevice Pci device instance\r
841 @param StatusIndex Status register value\r
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
865 if (StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) {\r
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
a3b8e257 877 @param PciIoDevice Pci device instance\r
878 \r
879 @retval EFI_SUCCESS Success Operation.\r
bcd70414 880**/\r
a3b8e257 881STATIC\r
882EFI_STATUS\r
883ProcessOptionRomLight (\r
884 IN PCI_IO_DEVICE *PciIoDevice\r
885 )\r
ead42efc 886{\r
887 PCI_IO_DEVICE *Temp;\r
888 LIST_ENTRY *CurrentLink;\r
889\r
890 //\r
891 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
892 //\r
893 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
894 while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {\r
895\r
896 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
897\r
898 if (!IsListEmpty (&Temp->ChildList)) {\r
899 ProcessOptionRomLight (Temp);\r
900 }\r
901\r
902 PciRomGetImageMapping (Temp);\r
eb9a9a5e 903\r
904 //\r
905 // The OpRom has already been processed in the first round\r
906 //\r
907 Temp->AllOpRomProcessed = TRUE;\r
908\r
ead42efc 909 CurrentLink = CurrentLink->ForwardLink;\r
910 }\r
911\r
912 return EFI_SUCCESS;\r
913}\r
914\r
a3b8e257 915/**\r
916 Determine the related attributes of all devices under a Root Bridge\r
917 \r
918 @param PciIoDevice PCI device instance\r
919 \r
920**/\r
ead42efc 921EFI_STATUS\r
922DetermineDeviceAttribute (\r
923 IN PCI_IO_DEVICE *PciIoDevice\r
924 )\r
ead42efc 925{\r
926 UINT16 Command;\r
927 UINT16 BridgeControl;\r
928 UINT16 OldCommand;\r
929 UINT16 OldBridgeControl;\r
930 BOOLEAN FastB2BSupport;\r
931\r
932 /*\r
933 UINT8 IdePI;\r
934 EFI_PCI_IO_PROTOCOL *PciIo;\r
935 */\r
936 PCI_IO_DEVICE *Temp;\r
937 LIST_ENTRY *CurrentLink;\r
938 EFI_STATUS Status;\r
939\r
940 //\r
941 // For Root Bridge, just copy it by RootBridgeIo proctocol\r
942 // so as to keep consistent with the actual attribute\r
943 //\r
944 if (!PciIoDevice->Parent) {\r
945 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (\r
946 PciIoDevice->PciRootBridgeIo,\r
947 &PciIoDevice->Supports,\r
948 &PciIoDevice->Attributes\r
949 );\r
950 if (EFI_ERROR (Status)) {\r
951 return Status;\r
952 }\r
953 } else {\r
954\r
955 //\r
956 // Set the attributes to be checked for common PCI devices and PPB or P2C\r
957 // Since some devices only support part of them, it is better to set the\r
958 // attribute according to its command or bridge control register\r
959 //\r
960 Command = EFI_PCI_COMMAND_IO_SPACE |\r
961 EFI_PCI_COMMAND_MEMORY_SPACE |\r
962 EFI_PCI_COMMAND_BUS_MASTER |\r
963 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;\r
964\r
965 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;\r
966\r
967 //\r
968 // Test whether the device can support attributes above\r
969 //\r
970 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);\r
971\r
972 //\r
973 // Set the supported attributes for specified PCI device\r
974 //\r
975 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);\r
976\r
977 //\r
978 // Set the current attributes for specified PCI device\r
979 //\r
980 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);\r
981\r
982 //\r
983 // Enable other supported attributes but not defined in PCI_IO_PROTOCOL\r
984 //\r
985 PciEnableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);\r
986\r
987 //\r
988 // Enable IDE native mode\r
989 //\r
990 /*\r
991 if (IS_PCI_IDE(&PciIoDevice->Pci)) {\r
992\r
993 PciIo = &PciIoDevice->PciIo;\r
994\r
995 PciIoRead (\r
996 PciIo,\r
997 EfiPciIoWidthUint8,\r
998 0x09,\r
999 1,\r
1000 &IdePI\r
1001 );\r
1002\r
1003 //\r
1004 // Set native mode if it can be supported\r
1005 //\r
1006 IdePI |= (((IdePI & 0x0F) >> 1) & 0x05);\r
1007\r
1008 PciIoWrite (\r
1009 PciIo,\r
1010 EfiPciIoWidthUint8,\r
1011 0x09,\r
1012 1,\r
1013 &IdePI\r
1014 );\r
1015\r
1016 }\r
1017 */\r
1018 }\r
1019\r
1020 FastB2BSupport = TRUE;\r
1021\r
1022 //\r
1023 // P2C can not support FB2B on the secondary side\r
1024 //\r
1025 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1026 FastB2BSupport = FALSE;\r
1027 }\r
1028\r
1029 //\r
1030 // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
1031 //\r
1032 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1033 while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {\r
1034\r
1035 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1036 Status = DetermineDeviceAttribute (Temp);\r
1037 if (EFI_ERROR (Status)) {\r
1038 return Status;\r
1039 }\r
1040 //\r
1041 // Detect Fast Bact to Bact support for the device under the bridge\r
1042 //\r
1043 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);\r
1044 if (FastB2BSupport && EFI_ERROR (Status)) {\r
1045 FastB2BSupport = FALSE;\r
1046 }\r
1047\r
1048 CurrentLink = CurrentLink->ForwardLink;\r
1049 }\r
1050 //\r
1051 // Set or clear Fast Back to Back bit for the whole bridge\r
1052 //\r
1053 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
1054\r
1055 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
1056\r
1057 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);\r
1058\r
1059 if (EFI_ERROR (Status) || (!FastB2BSupport)) {\r
1060 FastB2BSupport = FALSE;\r
1061 PciDisableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1062 } else {\r
1063 PciEnableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1064 }\r
1065 }\r
1066\r
1067 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
1068 while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {\r
1069 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1070 if (FastB2BSupport) {\r
1071 PciEnableCommandRegister (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1072 } else {\r
1073 PciDisableCommandRegister (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1074 }\r
1075\r
1076 CurrentLink = CurrentLink->ForwardLink;\r
1077 }\r
1078 }\r
1079 //\r
1080 // End for IsListEmpty\r
1081 //\r
1082 return EFI_SUCCESS;\r
1083}\r
1084\r
a3b8e257 1085/**\r
1086 This routine is used to update the bar information for those incompatible PCI device\r
1087 \r
1088 @param PciIoDevice Pci device instance\r
1089 @return EFI_UNSUPPORTED failed to update Pci Info\r
1090**/\r
ead42efc 1091EFI_STATUS\r
1092UpdatePciInfo (\r
1093 IN PCI_IO_DEVICE *PciIoDevice\r
1094 )\r
ead42efc 1095{\r
1096 EFI_STATUS Status;\r
1097 UINTN BarIndex;\r
1098 UINTN BarEndIndex;\r
1099 BOOLEAN SetFlag;\r
1100 EFI_PCI_DEVICE_INFO PciDeviceInfo;\r
1101 VOID *Configuration;\r
1102 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
1103\r
1104 Configuration = NULL;\r
ea5632e5 1105 Status = EFI_SUCCESS;\r
ead42efc 1106\r
ea5632e5 1107 if (gEfiIncompatiblePciDeviceSupport == NULL) {\r
1108 //\r
1109 // It can only be supported after the Incompatible PCI Device\r
1110 // Support Protocol has been installed\r
1111 //\r
1112 Status = gBS->LocateProtocol (\r
1113 &gEfiIncompatiblePciDeviceSupportProtocolGuid,\r
1114 NULL,\r
1115 (VOID **) &gEfiIncompatiblePciDeviceSupport\r
1116 );\r
1117 }\r
1118 if (Status == EFI_SUCCESS) {\r
1119 //\r
1120 // Check whether the device belongs to incompatible devices from protocol or not\r
1121 // If it is , then get its special requirement in the ACPI table\r
1122 //\r
1123 Status = gEfiIncompatiblePciDeviceSupport->CheckDevice (\r
1124 gEfiIncompatiblePciDeviceSupport,\r
1125 PciIoDevice->Pci.Hdr.VendorId,\r
1126 PciIoDevice->Pci.Hdr.DeviceId,\r
1127 PciIoDevice->Pci.Hdr.RevisionID,\r
1128 PciIoDevice->Pci.Device.SubsystemVendorID,\r
1129 PciIoDevice->Pci.Device.SubsystemID,\r
1130 &Configuration\r
1131 );\r
ead42efc 1132\r
ea5632e5 1133 }\r
ead42efc 1134\r
1135 if (EFI_ERROR (Status)) {\r
ea5632e5 1136 //\r
1137 // Check whether the device belongs to incompatible devices from library or not\r
1138 // If it is , then get its special requirement in the ACPI table\r
1139 //\r
1140 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACPI_RESOURCE_SUPPORT) {\r
1141 PciDeviceInfo.VendorID = PciIoDevice->Pci.Hdr.VendorId;\r
1142 PciDeviceInfo.DeviceID = PciIoDevice->Pci.Hdr.DeviceId;\r
1143 PciDeviceInfo.RevisionID = PciIoDevice->Pci.Hdr.RevisionID;\r
1144 PciDeviceInfo.SubsystemVendorID = PciIoDevice->Pci.Device.SubsystemVendorID;\r
1145 PciDeviceInfo.SubsystemID = PciIoDevice->Pci.Device.SubsystemID;\r
1146\r
1147 Status = PciResourceUpdateCheck (&PciDeviceInfo, &Configuration);\r
1148 }\r
1149 }\r
1150\r
1151 if (EFI_ERROR (Status)) {\r
1152 return EFI_UNSUPPORTED;\r
ead42efc 1153 }\r
1154\r
1155 //\r
1156 // Update PCI device information from the ACPI table\r
1157 //\r
1158 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;\r
1159\r
1160 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1161\r
1162 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
1163 //\r
1164 // The format is not support\r
1165 //\r
1166 break;\r
1167 }\r
1168\r
1169 BarIndex = (UINTN) Ptr->AddrTranslationOffset;\r
1170 BarEndIndex = BarIndex;\r
1171\r
1172 //\r
1173 // Update all the bars in the device\r
1174 //\r
1175 if (BarIndex == PCI_BAR_ALL) {\r
1176 BarIndex = 0;\r
1177 BarEndIndex = PCI_MAX_BAR - 1;\r
1178 }\r
1179\r
1180 if (BarIndex >= PCI_MAX_BAR) {\r
1181 Ptr++;\r
1182 continue;\r
1183 }\r
1184\r
1185 for (; BarIndex <= BarEndIndex; BarIndex++) {\r
1186 SetFlag = FALSE;\r
1187 switch (Ptr->ResType) {\r
1188 case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
1189\r
1190 //\r
1191 // Make sure the bar is memory type\r
1192 //\r
1193 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {\r
1194 SetFlag = TRUE;\r
1195 }\r
1196 break;\r
1197\r
1198 case ACPI_ADDRESS_SPACE_TYPE_IO:\r
1199\r
1200 //\r
1201 // Make sure the bar is IO type\r
1202 //\r
1203 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {\r
1204 SetFlag = TRUE;\r
1205 }\r
1206 break;\r
1207 }\r
1208\r
1209 if (SetFlag) {\r
1210\r
1211 //\r
1212 // Update the new alignment for the device\r
1213 //\r
1214 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);\r
1215\r
1216 //\r
1217 // Update the new length for the device\r
1218 //\r
1219 if (Ptr->AddrLen != PCI_BAR_NOCHANGE) {\r
1220 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;\r
1221 }\r
1222 }\r
1223 }\r
1224\r
1225 Ptr++;\r
1226 }\r
1227\r
1228 gBS->FreePool (Configuration);\r
1229 return Status;\r
1230\r
1231}\r
1232\r
a3b8e257 1233/**\r
1234 This routine will update the alignment with the new alignment\r
1235 \r
1236 @param Alignment old alignment\r
1237 @param NewAlignment new alignment\r
1238 \r
1239**/\r
ead42efc 1240VOID\r
1241SetNewAlign (\r
1242 IN UINT64 *Alignment,\r
1243 IN UINT64 NewAlignment\r
1244 )\r
ead42efc 1245{\r
1246 UINT64 OldAlignment;\r
1247 UINTN ShiftBit;\r
1248\r
1249 //\r
1250 // The new alignment is the same as the original,\r
1251 // so skip it\r
1252 //\r
1253 if (NewAlignment == PCI_BAR_OLD_ALIGN) {\r
1254 return ;\r
1255 }\r
1256 //\r
1257 // Check the validity of the parameter\r
1258 //\r
1259 if (NewAlignment != PCI_BAR_EVEN_ALIGN &&\r
1260 NewAlignment != PCI_BAR_SQUAD_ALIGN &&\r
1261 NewAlignment != PCI_BAR_DQUAD_ALIGN ) {\r
1262 *Alignment = NewAlignment;\r
1263 return ;\r
1264 }\r
1265\r
1266 OldAlignment = (*Alignment) + 1;\r
1267 ShiftBit = 0;\r
1268\r
1269 //\r
1270 // Get the first non-zero hex value of the length\r
1271 //\r
1272 while ((OldAlignment & 0x0F) == 0x00) {\r
1273 OldAlignment = RShiftU64 (OldAlignment, 4);\r
1274 ShiftBit += 4;\r
1275 }\r
1276\r
1277 //\r
1278 // Adjust the alignment to even, quad or double quad boundary\r
1279 //\r
1280 if (NewAlignment == PCI_BAR_EVEN_ALIGN) {\r
1281 if (OldAlignment & 0x01) {\r
1282 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);\r
1283 }\r
1284 } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {\r
1285 if (OldAlignment & 0x03) {\r
1286 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);\r
1287 }\r
1288 } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {\r
1289 if (OldAlignment & 0x07) {\r
1290 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);\r
1291 }\r
1292 }\r
1293\r
1294 //\r
1295 // Update the old value\r
1296 //\r
1297 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;\r
1298 *Alignment = NewAlignment;\r
1299\r
1300 return ;\r
1301}\r
1302\r
a3b8e257 1303/**\r
1304 Parse PCI bar bit.\r
1305 \r
1306 @param PciIoDevice Pci device instance\r
1307 @param Offset bar offset\r
1308 @param BarIndex bar index\r
1309 \r
1310 @return next bar offset.\r
1311**/\r
ead42efc 1312UINTN\r
1313PciParseBar (\r
1314 IN PCI_IO_DEVICE *PciIoDevice,\r
1315 IN UINTN Offset,\r
1316 IN UINTN BarIndex\r
1317 )\r
ead42efc 1318{\r
1319 UINT32 Value;\r
1320 UINT32 OriginalValue;\r
1321 UINT32 Mask;\r
1322 UINT32 Data;\r
1323 UINT8 Index;\r
1324 EFI_STATUS Status;\r
1325\r
1326 OriginalValue = 0;\r
1327 Value = 0;\r
1328\r
1329 Status = BarExisted (\r
1330 PciIoDevice,\r
1331 Offset,\r
1332 &Value,\r
1333 &OriginalValue\r
1334 );\r
1335\r
1336 if (EFI_ERROR (Status)) {\r
1337 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1338 PciIoDevice->PciBar[BarIndex].Length = 0;\r
1339 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1340\r
1341 //\r
1342 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway\r
1343 //\r
1344 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1345 return Offset + 4;\r
1346 }\r
1347\r
1348 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
1349 if (Value & 0x01) {\r
1350 //\r
1351 // Device I/Os\r
1352 //\r
1353 Mask = 0xfffffffc;\r
1354\r
1355 if (Value & 0xFFFF0000) {\r
1356 //\r
1357 // It is a IO32 bar\r
1358 //\r
1359 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;\r
1360 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);\r
1361 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1362\r
1363 } else {\r
1364 //\r
1365 // It is a IO16 bar\r
1366 //\r
1367 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;\r
1368 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);\r
1369 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1370\r
1371 }\r
1372 //\r
1373 // Workaround. Some platforms inplement IO bar with 0 length\r
1374 // Need to treat it as no-bar\r
1375 //\r
1376 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1377 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;\r
1378 }\r
1379\r
1380 PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;\r
1381 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1382\r
1383 } else {\r
1384\r
1385 Mask = 0xfffffff0;\r
1386\r
1387 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
1388\r
1389 switch (Value & 0x07) {\r
1390\r
1391 //\r
1392 //memory space; anywhere in 32 bit address space\r
1393 //\r
1394 case 0x00:\r
1395 if (Value & 0x08) {\r
1396 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
1397 } else {\r
1398 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
1399 }\r
1400\r
1401 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1402 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1403\r
1404 break;\r
1405\r
1406 //\r
1407 // memory space; anywhere in 64 bit address space\r
1408 //\r
1409 case 0x04:\r
1410 if (Value & 0x08) {\r
1411 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;\r
1412 } else {\r
1413 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;\r
1414 }\r
1415\r
1416 //\r
1417 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
1418 // is regarded as an extension for the first bar. As a result\r
1419 // the sizing will be conducted on combined 64 bit value\r
1420 // Here just store the masked first 32bit value for future size\r
1421 // calculation\r
1422 //\r
1423 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;\r
1424 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1425\r
1426 //\r
1427 // Increment the offset to point to next DWORD\r
1428 //\r
1429 Offset += 4;\r
1430\r
1431 Status = BarExisted (\r
1432 PciIoDevice,\r
1433 Offset,\r
1434 &Value,\r
1435 &OriginalValue\r
1436 );\r
1437\r
1438 if (EFI_ERROR (Status)) {\r
1439 return Offset + 4;\r
1440 }\r
1441\r
1442 //\r
1443 // Fix the length to support some spefic 64 bit BAR\r
1444 //\r
1445 Data = Value;\r
1446 Index = 0;\r
1447 for (Data = Value; Data != 0; Data >>= 1) {\r
a3b8e257 1448 Index ++;\r
ead42efc 1449 }\r
1450 Value |= ((UINT32)(-1) << Index);\r
1451\r
1452 //\r
1453 // Calculate the size of 64bit bar\r
1454 //\r
1455 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
1456\r
1457 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
1458 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
1459 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1460\r
1461 break;\r
1462\r
1463 //\r
1464 // reserved\r
1465 //\r
1466 default:\r
1467 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1468 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
1469 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
1470\r
1471 break;\r
1472 }\r
1473 }\r
1474\r
1475 //\r
1476 // Check the length again so as to keep compatible with some special bars\r
1477 //\r
1478 if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
1479 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
1480 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
1481 PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
1482 }\r
1483\r
1484 //\r
1485 // Increment number of bar\r
1486 //\r
1487 return Offset + 4;\r
1488}\r
1489\r
bcd70414 1490/**\r
ead42efc 1491 This routine is used to initialize the bar of a PCI device\r
1492 It can be called typically when a device is going to be rejected\r
1493\r
a3b8e257 1494 @param PciIoDevice Pci device instance\r
bcd70414 1495**/\r
a3b8e257 1496EFI_STATUS\r
1497InitializePciDevice (\r
1498 IN PCI_IO_DEVICE *PciIoDevice\r
1499 )\r
ead42efc 1500{\r
1501 EFI_PCI_IO_PROTOCOL *PciIo;\r
1502 UINT8 Offset;\r
1503\r
1504 PciIo = &(PciIoDevice->PciIo);\r
1505\r
1506 //\r
1507 // Put all the resource apertures\r
1508 // Resource base is set to all ones so as to indicate its resource\r
1509 // has not been alloacted\r
1510 //\r
1511 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
1512 PciIoWrite (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
1513 }\r
1514\r
1515 return EFI_SUCCESS;\r
1516}\r
1517\r
a3b8e257 1518/**\r
1519 Init PPB for bridge device\r
1520 \r
1521 @param PciIoDevice Pci device instance\r
1522**/\r
ead42efc 1523EFI_STATUS\r
1524InitializePpb (\r
1525 IN PCI_IO_DEVICE *PciIoDevice\r
1526 )\r
ead42efc 1527{\r
1528 EFI_PCI_IO_PROTOCOL *PciIo;\r
1529\r
1530 PciIo = &(PciIoDevice->PciIo);\r
1531\r
1532 //\r
1533 // Put all the resource apertures including IO16\r
1534 // Io32, pMem32, pMem64 to quiescent state\r
1535 // Resource base all ones, Resource limit all zeros\r
1536 //\r
1537 PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
1538 PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
1539\r
1540 PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
1541 PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
1542\r
1543 PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
1544 PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
1545\r
1546 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
1547 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
1548\r
1549 //\r
1550 // don't support use io32 as for now\r
1551 //\r
1552 PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
1553 PciIoWrite (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
1554\r
1555 //\r
1556 // Force Interrupt line to zero for cards that come up randomly\r
1557 //\r
1558 PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
1559\r
1560 return EFI_SUCCESS;\r
1561}\r
1562\r
a3b8e257 1563/**\r
1564 Init private data for Hotplug bridge device\r
1565 \r
1566 @param PciIoDevice hotplug bridge device\r
1567**/\r
ead42efc 1568EFI_STATUS\r
1569InitializeP2C (\r
1570 IN PCI_IO_DEVICE *PciIoDevice\r
1571 )\r
ead42efc 1572{\r
1573 EFI_PCI_IO_PROTOCOL *PciIo;\r
1574\r
1575 PciIo = &(PciIoDevice->PciIo);\r
1576\r
1577 //\r
1578 // Put all the resource apertures including IO16\r
1579 // Io32, pMem32, pMem64 to quiescent state(\r
1580 // Resource base all ones, Resource limit all zeros\r
1581 //\r
1582 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
1583 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
1584\r
1585 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
1586 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
1587\r
1588 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
1589 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
1590\r
1591 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
1592 PciIoWrite (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
1593\r
1594 //\r
1595 // Force Interrupt line to zero for cards that come up randomly\r
1596 //\r
1597 PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
1598 return EFI_SUCCESS;\r
1599}\r
1600\r
a3b8e257 1601/**\r
1602 Create and initiliaze general PCI I/O device instance for\r
1603 PCI device/bridge device/hotplug bridge device.\r
1604 \r
1605 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL\r
1606 @param Pci Pci bar block\r
1607 @param Bus device Bus NO.\r
1608 @param Device device device NO.\r
1609 @param Func device func NO.\r
1610 \r
1611 @return instance of PCI device\r
1612**/\r
ead42efc 1613PCI_IO_DEVICE *\r
1614CreatePciIoDevice (\r
1615 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
1616 IN PCI_TYPE00 *Pci,\r
1617 UINT8 Bus,\r
1618 UINT8 Device,\r
1619 UINT8 Func\r
1620 )\r
ead42efc 1621{\r
1622\r
1623 EFI_STATUS Status;\r
1624 PCI_IO_DEVICE *PciIoDevice;\r
1625\r
1626 PciIoDevice = NULL;\r
1627\r
1628 Status = gBS->AllocatePool (\r
1629 EfiBootServicesData,\r
1630 sizeof (PCI_IO_DEVICE),\r
1631 (VOID **) &PciIoDevice\r
1632 );\r
1633\r
1634 if (EFI_ERROR (Status)) {\r
1635 return NULL;\r
1636 }\r
1637\r
1638 ZeroMem (PciIoDevice, sizeof (PCI_IO_DEVICE));\r
1639\r
1640 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;\r
1641 PciIoDevice->Handle = NULL;\r
1642 PciIoDevice->PciRootBridgeIo = PciRootBridgeIo;\r
1643 PciIoDevice->DevicePath = NULL;\r
1644 PciIoDevice->BusNumber = Bus;\r
1645 PciIoDevice->DeviceNumber = Device;\r
1646 PciIoDevice->FunctionNumber = Func;\r
1647 PciIoDevice->Decodes = 0;\r
1648 if (gFullEnumeration) {\r
1649 PciIoDevice->Allocated = FALSE;\r
1650 } else {\r
1651 PciIoDevice->Allocated = TRUE;\r
1652 }\r
1653\r
1654 PciIoDevice->Registered = FALSE;\r
1655 PciIoDevice->Attributes = 0;\r
1656 PciIoDevice->Supports = 0;\r
1657 PciIoDevice->BusOverride = FALSE;\r
1658 PciIoDevice->AllOpRomProcessed = FALSE;\r
1659\r
1660 PciIoDevice->IsPciExp = FALSE;\r
1661\r
1662 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
1663\r
1664 //\r
1665 // Initialize the PCI I/O instance structure\r
1666 //\r
1667\r
1668 Status = InitializePciIoInstance (PciIoDevice);\r
1669 Status = InitializePciDriverOverrideInstance (PciIoDevice);\r
1670\r
1671 if (EFI_ERROR (Status)) {\r
1672 gBS->FreePool (PciIoDevice);\r
1673 return NULL;\r
1674 }\r
1675\r
1676 //\r
1677 // Initialize the reserved resource list\r
1678 //\r
1679 InitializeListHead (&PciIoDevice->ReservedResourceList);\r
1680\r
1681 //\r
1682 // Initialize the driver list\r
1683 //\r
1684 InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
1685\r
1686 //\r
1687 // Initialize the child list\r
1688 //\r
1689 InitializeListHead (&PciIoDevice->ChildList);\r
1690\r
1691 return PciIoDevice;\r
1692}\r
1693\r
bcd70414 1694/**\r
ead42efc 1695 This routine is used to enumerate entire pci bus system\r
1696 in a given platform\r
eb9a9a5e 1697 It is only called on the second start on the same Root Bridge.\r
ead42efc 1698\r
a3b8e257 1699 @param Controller Parent bridge handler\r
1700 \r
1701 @return status of operation.\r
bcd70414 1702**/\r
a3b8e257 1703EFI_STATUS\r
1704PciEnumeratorLight (\r
1705 IN EFI_HANDLE Controller\r
1706 )\r
ead42efc 1707{\r
1708\r
1709 EFI_STATUS Status;\r
1710 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1711 PCI_IO_DEVICE *RootBridgeDev;\r
1712 UINT16 MinBus;\r
1713 UINT16 MaxBus;\r
1714 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
1715\r
1716 MinBus = 0;\r
1717 MaxBus = PCI_MAX_BUS;\r
1718 Descriptors = NULL;\r
1719\r
1720 //\r
eb9a9a5e 1721 // If this root bridge has been already enumerated, then return successfully\r
ead42efc 1722 //\r
eb9a9a5e 1723 if (GetRootBridgeByHandle (Controller) != NULL) {\r
ead42efc 1724 return EFI_SUCCESS;\r
1725 }\r
1726\r
1727 //\r
1728 // Open pci root bridge io protocol\r
1729 //\r
1730 Status = gBS->OpenProtocol (\r
1731 Controller,\r
1732 &gEfiPciRootBridgeIoProtocolGuid,\r
1733 (VOID **) &PciRootBridgeIo,\r
1734 gPciBusDriverBinding.DriverBindingHandle,\r
1735 Controller,\r
1736 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1737 );\r
1738 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
1739 return Status;\r
1740 }\r
1741\r
1742 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
1743\r
1744 if (EFI_ERROR (Status)) {\r
1745 return Status;\r
1746 }\r
1747\r
1748 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
1749\r
1750 //\r
1751 // Create a device node for root bridge device with a NULL host bridge controller handle\r
1752 //\r
1753 RootBridgeDev = CreateRootBridge (Controller);\r
1754\r
1755 if (!RootBridgeDev) {\r
1756 Descriptors++;\r
1757 continue;\r
1758 }\r
1759\r
1760 //\r
1761 // Record the root bridge io protocol\r
1762 //\r
1763 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
1764\r
1765 Status = PciPciDeviceInfoCollector (\r
1766 RootBridgeDev,\r
1767 (UINT8) MinBus\r
1768 );\r
1769\r
1770 if (!EFI_ERROR (Status)) {\r
1771\r
1772 //\r
1773 // Remove those PCI devices which are rejected when full enumeration\r
1774 //\r
1775 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
1776\r
1777 //\r
1778 // Process option rom light\r
1779 //\r
1780 ProcessOptionRomLight (RootBridgeDev);\r
1781\r
1782 //\r
1783 // Determine attributes for all devices under this root bridge\r
1784 //\r
1785 DetermineDeviceAttribute (RootBridgeDev);\r
1786\r
1787 //\r
1788 // If successfully, insert the node into device pool\r
1789 //\r
1790 InsertRootBridge (RootBridgeDev);\r
1791 } else {\r
1792\r
1793 //\r
1794 // If unsuccessly, destroy the entire node\r
1795 //\r
1796 DestroyRootBridge (RootBridgeDev);\r
1797 }\r
1798\r
1799 Descriptors++;\r
1800 }\r
1801\r
1802 return EFI_SUCCESS;\r
1803}\r
1804\r
a3b8e257 1805/**\r
1806 Get bus range.\r
1807 \r
1808 @param Descriptors A pointer to the address space descriptor.\r
1809 @param MinBus The min bus.\r
1810 @param MaxBus The max bus.\r
1811 @param BusRange The bus range.\r
1812 \r
1813 @retval EFI_SUCCESS Success operation.\r
1814 @retval EFI_NOT_FOUND can not find the specific bus.\r
1815**/\r
ead42efc 1816EFI_STATUS\r
1817PciGetBusRange (\r
1818 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
1819 OUT UINT16 *MinBus,\r
1820 OUT UINT16 *MaxBus,\r
1821 OUT UINT16 *BusRange\r
1822 )\r
ead42efc 1823{\r
1824\r
1825 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1826 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
1827 if (MinBus != NULL) {\r
1828 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;\r
1829 }\r
1830\r
1831 if (MaxBus != NULL) {\r
1832 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;\r
1833 }\r
1834\r
1835 if (BusRange != NULL) {\r
1836 *BusRange = (UINT16) (*Descriptors)->AddrLen;\r
1837 }\r
1838\r
1839 return EFI_SUCCESS;\r
1840 }\r
1841\r
1842 (*Descriptors)++;\r
1843 }\r
1844\r
1845 return EFI_NOT_FOUND;\r
1846}\r
1847\r
1848EFI_STATUS\r
1849StartManagingRootBridge (\r
1850 IN PCI_IO_DEVICE *RootBridgeDev\r
1851 )\r
ead42efc 1852{\r
1853 EFI_HANDLE RootBridgeHandle;\r
1854 EFI_STATUS Status;\r
1855 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1856\r
1857 //\r
1858 // Get the root bridge handle\r
1859 //\r
1860 RootBridgeHandle = RootBridgeDev->Handle;\r
1861 PciRootBridgeIo = NULL;\r
1862\r
1863 //\r
1864 // Get the pci root bridge io protocol\r
1865 //\r
1866 Status = gBS->OpenProtocol (\r
1867 RootBridgeHandle,\r
1868 &gEfiPciRootBridgeIoProtocolGuid,\r
1869 (VOID **) &PciRootBridgeIo,\r
1870 gPciBusDriverBinding.DriverBindingHandle,\r
1871 RootBridgeHandle,\r
1872 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1873 );\r
1874\r
1875 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
1876 return Status;\r
1877 }\r
1878\r
1879 //\r
1880 // Store the PciRootBridgeIo protocol into root bridge private data\r
1881 //\r
1882 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
1883\r
1884 return EFI_SUCCESS;\r
1885\r
1886}\r
1887\r
bcd70414 1888/**\r
ead42efc 1889 This routine can be used to check whether a PCI device should be rejected when light enumeration\r
1890\r
a3b8e257 1891 @param PciIoDevice Pci device instance\r
ead42efc 1892\r
a3b8e257 1893 @retval TRUE This device should be rejected\r
1894 @retval FALSE This device shouldn't be rejected\r
1895 \r
bcd70414 1896**/\r
a3b8e257 1897BOOLEAN\r
1898IsPciDeviceRejected (\r
1899 IN PCI_IO_DEVICE *PciIoDevice\r
1900 )\r
ead42efc 1901{\r
1902 EFI_STATUS Status;\r
1903 UINT32 TestValue;\r
1904 UINT32 OldValue;\r
1905 UINT32 Mask;\r
1906 UINT8 BarOffset;\r
1907\r
1908 //\r
1909 // PPB should be skip!\r
1910 //\r
1911 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
1912 return FALSE;\r
1913 }\r
1914\r
1915 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1916 //\r
1917 // Only test base registers for P2C\r
1918 //\r
1919 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
1920\r
1921 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
1922 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
1923 if (EFI_ERROR (Status)) {\r
1924 continue;\r
1925 }\r
1926\r
1927 TestValue = TestValue & Mask;\r
1928 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1929 //\r
1930 // The bar isn't programed, so it should be rejected\r
1931 //\r
1932 return TRUE;\r
1933 }\r
1934 }\r
1935\r
1936 return FALSE;\r
1937 }\r
1938\r
1939 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
1940 //\r
1941 // Test PCI devices\r
1942 //\r
1943 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
1944 if (EFI_ERROR (Status)) {\r
1945 continue;\r
1946 }\r
1947\r
1948 if (TestValue & 0x01) {\r
1949\r
1950 //\r
1951 // IO Bar\r
1952 //\r
1953\r
1954 Mask = 0xFFFFFFFC;\r
1955 TestValue = TestValue & Mask;\r
1956 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1957 return TRUE;\r
1958 }\r
1959\r
1960 } else {\r
1961\r
1962 //\r
1963 // Mem Bar\r
1964 //\r
1965\r
1966 Mask = 0xFFFFFFF0;\r
1967 TestValue = TestValue & Mask;\r
1968\r
1969 if ((TestValue & 0x07) == 0x04) {\r
1970\r
1971 //\r
1972 // Mem64 or PMem64\r
1973 //\r
1974 BarOffset += sizeof (UINT32);\r
1975 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1976\r
1977 //\r
1978 // Test its high 32-Bit BAR\r
1979 //\r
1980\r
1981 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
1982 if (TestValue == OldValue) {\r
1983 return TRUE;\r
1984 }\r
1985 }\r
1986\r
1987 } else {\r
1988\r
1989 //\r
1990 // Mem32 or PMem32\r
1991 //\r
1992 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1993 return TRUE;\r
1994 }\r
1995 }\r
1996 }\r
1997 }\r
1998\r
1999 return FALSE;\r
2000}\r
2001\r
a3b8e257 2002/**\r
2003 Reset and all bus number from specific bridge.\r
2004 \r
2005 @param Bridge Parent specific bridge\r
2006 @param StartBusNumber start bus number\r
2007**/\r
ead42efc 2008EFI_STATUS\r
ff62de37 2009ResetAllPpbBusNumber (\r
ead42efc 2010 IN PCI_IO_DEVICE *Bridge,\r
2011 IN UINT8 StartBusNumber\r
2012 )\r
ead42efc 2013{\r
2014 EFI_STATUS Status;\r
2015 PCI_TYPE00 Pci;\r
2016 UINT8 Device;\r
2017 UINT32 Register;\r
2018 UINT8 Func;\r
2019 UINT64 Address;\r
ff62de37 2020 UINT8 SecondaryBus;\r
ead42efc 2021 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2022\r
2023 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2024\r
2025 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
2026 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
2027\r
2028 //\r
2029 // Check to see whether a pci device is present\r
2030 //\r
2031 Status = PciDevicePresent (\r
2032 PciRootBridgeIo,\r
2033 &Pci,\r
2034 StartBusNumber,\r
2035 Device,\r
2036 Func\r
2037 );\r
2038\r
2039 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
ff62de37 2040\r
ead42efc 2041 Register = 0;\r
2042 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
2043 Status = PciRootBridgeIoRead (\r
2044 PciRootBridgeIo,\r
2045 &Pci,\r
2046 EfiPciWidthUint32,\r
2047 Address,\r
2048 1,\r
2049 &Register\r
2050 );\r
ff62de37 2051 SecondaryBus = (UINT8)(Register >> 8);\r
2052\r
2053 if (SecondaryBus != 0) {\r
2054 ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
2055 }\r
2056\r
ead42efc 2057 //\r
2058 // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2059 //\r
2060 Register &= 0xFF000000;\r
2061 Status = PciRootBridgeIoWrite (\r
2062 PciRootBridgeIo,\r
2063 &Pci,\r
2064 EfiPciWidthUint32,\r
2065 Address,\r
2066 1,\r
2067 &Register\r
2068 );\r
2069 }\r
2070\r
2071 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
2072 //\r
2073 // Skip sub functions, this is not a multi function device\r
2074 //\r
2075 Func = PCI_MAX_FUNC;\r
2076 }\r
2077 }\r
2078 }\r
2079\r
2080 return EFI_SUCCESS;\r
2081}\r
2082\r