]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciEnumeratorSupport.c
Fixup for review
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciEnumeratorSupport.c
CommitLineData
97404058 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
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
88 @param StartBusNumer 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
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
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
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
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
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
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
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
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
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
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
984 PciEnableCommandRegister (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);\r
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
1060 PciDisableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
1061 } else {\r
1062 PciEnableBridgeControlRegister (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
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
1070 PciEnableCommandRegister (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
1071 } else {\r
1072 PciDisableCommandRegister (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
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
1150 if (EFI_ERROR (Status)) {\r
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
1667 Status = InitializePciIoInstance (PciIoDevice);\r
1668 Status = InitializePciDriverOverrideInstance (PciIoDevice);\r
1669\r
1670 if (EFI_ERROR (Status)) {\r
1671 gBS->FreePool (PciIoDevice);\r
1672 return NULL;\r
1673 }\r
1674\r
1675 //\r
1676 // Initialize the reserved resource list\r
1677 //\r
1678 InitializeListHead (&PciIoDevice->ReservedResourceList);\r
1679\r
1680 //\r
1681 // Initialize the driver list\r
1682 //\r
1683 InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
1684\r
1685 //\r
1686 // Initialize the child list\r
1687 //\r
1688 InitializeListHead (&PciIoDevice->ChildList);\r
1689\r
1690 return PciIoDevice;\r
1691}\r
1692\r
bcd70414 1693/**\r
ead42efc 1694 This routine is used to enumerate entire pci bus system\r
1695 in a given platform\r
eb9a9a5e 1696 It is only called on the second start on the same Root Bridge.\r
ead42efc 1697\r
97404058 1698 @param Controller Parent bridge handler.\r
a3b8e257 1699 \r
1700 @return status of operation.\r
bcd70414 1701**/\r
a3b8e257 1702EFI_STATUS\r
1703PciEnumeratorLight (\r
1704 IN EFI_HANDLE Controller\r
1705 )\r
ead42efc 1706{\r
1707\r
1708 EFI_STATUS Status;\r
1709 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1710 PCI_IO_DEVICE *RootBridgeDev;\r
1711 UINT16 MinBus;\r
1712 UINT16 MaxBus;\r
1713 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
1714\r
1715 MinBus = 0;\r
1716 MaxBus = PCI_MAX_BUS;\r
1717 Descriptors = NULL;\r
1718\r
1719 //\r
eb9a9a5e 1720 // If this root bridge has been already enumerated, then return successfully\r
ead42efc 1721 //\r
eb9a9a5e 1722 if (GetRootBridgeByHandle (Controller) != NULL) {\r
ead42efc 1723 return EFI_SUCCESS;\r
1724 }\r
1725\r
1726 //\r
1727 // Open pci root bridge io protocol\r
1728 //\r
1729 Status = gBS->OpenProtocol (\r
1730 Controller,\r
1731 &gEfiPciRootBridgeIoProtocolGuid,\r
1732 (VOID **) &PciRootBridgeIo,\r
1733 gPciBusDriverBinding.DriverBindingHandle,\r
1734 Controller,\r
1735 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1736 );\r
1737 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
1738 return Status;\r
1739 }\r
1740\r
1741 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
1742\r
1743 if (EFI_ERROR (Status)) {\r
1744 return Status;\r
1745 }\r
1746\r
1747 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
1748\r
1749 //\r
1750 // Create a device node for root bridge device with a NULL host bridge controller handle\r
1751 //\r
1752 RootBridgeDev = CreateRootBridge (Controller);\r
1753\r
97404058 1754 if (RootBridgeDev == NULL) {\r
ead42efc 1755 Descriptors++;\r
1756 continue;\r
1757 }\r
1758\r
1759 //\r
1760 // Record the root bridge io protocol\r
1761 //\r
1762 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
1763\r
1764 Status = PciPciDeviceInfoCollector (\r
1765 RootBridgeDev,\r
1766 (UINT8) MinBus\r
1767 );\r
1768\r
1769 if (!EFI_ERROR (Status)) {\r
1770\r
1771 //\r
1772 // Remove those PCI devices which are rejected when full enumeration\r
1773 //\r
1774 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
1775\r
1776 //\r
1777 // Process option rom light\r
1778 //\r
1779 ProcessOptionRomLight (RootBridgeDev);\r
1780\r
1781 //\r
1782 // Determine attributes for all devices under this root bridge\r
1783 //\r
1784 DetermineDeviceAttribute (RootBridgeDev);\r
1785\r
1786 //\r
1787 // If successfully, insert the node into device pool\r
1788 //\r
1789 InsertRootBridge (RootBridgeDev);\r
1790 } else {\r
1791\r
1792 //\r
1793 // If unsuccessly, destroy the entire node\r
1794 //\r
1795 DestroyRootBridge (RootBridgeDev);\r
1796 }\r
1797\r
1798 Descriptors++;\r
1799 }\r
1800\r
1801 return EFI_SUCCESS;\r
1802}\r
1803\r
a3b8e257 1804/**\r
1805 Get bus range.\r
1806 \r
1807 @param Descriptors A pointer to the address space descriptor.\r
1808 @param MinBus The min bus.\r
1809 @param MaxBus The max bus.\r
1810 @param BusRange The bus range.\r
1811 \r
1812 @retval EFI_SUCCESS Success operation.\r
1813 @retval EFI_NOT_FOUND can not find the specific bus.\r
1814**/\r
ead42efc 1815EFI_STATUS\r
1816PciGetBusRange (\r
1817 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
1818 OUT UINT16 *MinBus,\r
1819 OUT UINT16 *MaxBus,\r
1820 OUT UINT16 *BusRange\r
1821 )\r
ead42efc 1822{\r
1823\r
1824 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
1825 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
1826 if (MinBus != NULL) {\r
1827 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;\r
1828 }\r
1829\r
1830 if (MaxBus != NULL) {\r
1831 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;\r
1832 }\r
1833\r
1834 if (BusRange != NULL) {\r
1835 *BusRange = (UINT16) (*Descriptors)->AddrLen;\r
1836 }\r
1837\r
1838 return EFI_SUCCESS;\r
1839 }\r
1840\r
1841 (*Descriptors)++;\r
1842 }\r
1843\r
1844 return EFI_NOT_FOUND;\r
1845}\r
1846\r
1847EFI_STATUS\r
1848StartManagingRootBridge (\r
1849 IN PCI_IO_DEVICE *RootBridgeDev\r
1850 )\r
ead42efc 1851{\r
1852 EFI_HANDLE RootBridgeHandle;\r
1853 EFI_STATUS Status;\r
1854 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1855\r
1856 //\r
1857 // Get the root bridge handle\r
1858 //\r
1859 RootBridgeHandle = RootBridgeDev->Handle;\r
1860 PciRootBridgeIo = NULL;\r
1861\r
1862 //\r
1863 // Get the pci root bridge io protocol\r
1864 //\r
1865 Status = gBS->OpenProtocol (\r
1866 RootBridgeHandle,\r
1867 &gEfiPciRootBridgeIoProtocolGuid,\r
1868 (VOID **) &PciRootBridgeIo,\r
1869 gPciBusDriverBinding.DriverBindingHandle,\r
1870 RootBridgeHandle,\r
1871 EFI_OPEN_PROTOCOL_BY_DRIVER\r
1872 );\r
1873\r
1874 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
1875 return Status;\r
1876 }\r
1877\r
1878 //\r
1879 // Store the PciRootBridgeIo protocol into root bridge private data\r
1880 //\r
1881 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
1882\r
1883 return EFI_SUCCESS;\r
1884\r
1885}\r
1886\r
bcd70414 1887/**\r
ead42efc 1888 This routine can be used to check whether a PCI device should be rejected when light enumeration\r
1889\r
97404058 1890 @param PciIoDevice Pci device instance.\r
ead42efc 1891\r
97404058 1892 @retval TRUE This device should be rejected.\r
1893 @retval FALSE This device shouldn't be rejected.\r
a3b8e257 1894 \r
bcd70414 1895**/\r
a3b8e257 1896BOOLEAN\r
1897IsPciDeviceRejected (\r
1898 IN PCI_IO_DEVICE *PciIoDevice\r
1899 )\r
ead42efc 1900{\r
1901 EFI_STATUS Status;\r
1902 UINT32 TestValue;\r
1903 UINT32 OldValue;\r
1904 UINT32 Mask;\r
1905 UINT8 BarOffset;\r
1906\r
1907 //\r
1908 // PPB should be skip!\r
1909 //\r
1910 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
1911 return FALSE;\r
1912 }\r
1913\r
1914 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
1915 //\r
1916 // Only test base registers for P2C\r
1917 //\r
1918 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
1919\r
1920 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
1921 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
1922 if (EFI_ERROR (Status)) {\r
1923 continue;\r
1924 }\r
1925\r
1926 TestValue = TestValue & Mask;\r
1927 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1928 //\r
1929 // The bar isn't programed, so it should be rejected\r
1930 //\r
1931 return TRUE;\r
1932 }\r
1933 }\r
1934\r
1935 return FALSE;\r
1936 }\r
1937\r
1938 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
1939 //\r
1940 // Test PCI devices\r
1941 //\r
1942 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
1943 if (EFI_ERROR (Status)) {\r
1944 continue;\r
1945 }\r
1946\r
97404058 1947 if ((TestValue & 0x01) != 0) {\r
ead42efc 1948\r
1949 //\r
1950 // IO Bar\r
1951 //\r
1952\r
1953 Mask = 0xFFFFFFFC;\r
1954 TestValue = TestValue & Mask;\r
1955 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1956 return TRUE;\r
1957 }\r
1958\r
1959 } else {\r
1960\r
1961 //\r
1962 // Mem Bar\r
1963 //\r
1964\r
1965 Mask = 0xFFFFFFF0;\r
1966 TestValue = TestValue & Mask;\r
1967\r
1968 if ((TestValue & 0x07) == 0x04) {\r
1969\r
1970 //\r
1971 // Mem64 or PMem64\r
1972 //\r
1973 BarOffset += sizeof (UINT32);\r
1974 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1975\r
1976 //\r
1977 // Test its high 32-Bit BAR\r
1978 //\r
1979\r
1980 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
1981 if (TestValue == OldValue) {\r
1982 return TRUE;\r
1983 }\r
1984 }\r
1985\r
1986 } else {\r
1987\r
1988 //\r
1989 // Mem32 or PMem32\r
1990 //\r
1991 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
1992 return TRUE;\r
1993 }\r
1994 }\r
1995 }\r
1996 }\r
1997\r
1998 return FALSE;\r
1999}\r
2000\r
a3b8e257 2001/**\r
2002 Reset and all bus number from specific bridge.\r
2003 \r
97404058 2004 @param Bridge Parent specific bridge.\r
2005 @param StartBusNumber start bus number.\r
a3b8e257 2006**/\r
ead42efc 2007EFI_STATUS\r
ff62de37 2008ResetAllPpbBusNumber (\r
ead42efc 2009 IN PCI_IO_DEVICE *Bridge,\r
2010 IN UINT8 StartBusNumber\r
2011 )\r
ead42efc 2012{\r
2013 EFI_STATUS Status;\r
2014 PCI_TYPE00 Pci;\r
2015 UINT8 Device;\r
2016 UINT32 Register;\r
2017 UINT8 Func;\r
2018 UINT64 Address;\r
ff62de37 2019 UINT8 SecondaryBus;\r
ead42efc 2020 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
2021\r
2022 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
2023\r
2024 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
2025 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
2026\r
2027 //\r
2028 // Check to see whether a pci device is present\r
2029 //\r
2030 Status = PciDevicePresent (\r
2031 PciRootBridgeIo,\r
2032 &Pci,\r
2033 StartBusNumber,\r
2034 Device,\r
2035 Func\r
2036 );\r
2037\r
2038 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
ff62de37 2039\r
ead42efc 2040 Register = 0;\r
2041 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
2042 Status = PciRootBridgeIoRead (\r
2043 PciRootBridgeIo,\r
2044 &Pci,\r
2045 EfiPciWidthUint32,\r
2046 Address,\r
2047 1,\r
2048 &Register\r
2049 );\r
ff62de37 2050 SecondaryBus = (UINT8)(Register >> 8);\r
2051\r
2052 if (SecondaryBus != 0) {\r
2053 ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
2054 }\r
2055\r
ead42efc 2056 //\r
2057 // Reset register 18h, 19h, 1Ah on PCI Bridge\r
2058 //\r
2059 Register &= 0xFF000000;\r
2060 Status = PciRootBridgeIoWrite (\r
2061 PciRootBridgeIo,\r
2062 &Pci,\r
2063 EfiPciWidthUint32,\r
2064 Address,\r
2065 1,\r
2066 &Register\r
2067 );\r
2068 }\r
2069\r
2070 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
2071 //\r
2072 // Skip sub functions, this is not a multi function device\r
2073 //\r
2074 Func = PCI_MAX_FUNC;\r
2075 }\r
2076 }\r
2077 }\r
2078\r
2079 return EFI_SUCCESS;\r
2080}\r
2081\r