]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Bus/Pci/PciBus/Dxe/PciLib.c
1. Added EdkPciIncompatibleDeviceSupportLib in EdkModulePkg, this library is used...
[mirror_edk2.git] / EdkModulePkg / Bus / Pci / PciBus / Dxe / PciLib.c
CommitLineData
878ddf1f 1/*++\r
2\r
98419ef4 3Copyright (c) 2006 - 2007, 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
878ddf1f 11\r
12Module Name:\r
13\r
98419ef4 14 PciLib.c\r
15\r
878ddf1f 16Abstract:\r
17\r
18 PCI Bus Driver Lib file\r
98419ef4 19 It abstracts some functions that can be different\r
878ddf1f 20 between light PCI bus driver and full PCI bus driver\r
21\r
22Revision History\r
23\r
24--*/\r
25\r
26#include "pcibus.h"\r
27\r
6874dbd0 28GLOBAL_REMOVE_IF_UNREFERENCED EFI_PCI_HOTPLUG_REQUEST_PROTOCOL gPciHotPlugRequest = {\r
878ddf1f 29 PciHotPlugRequestNotify\r
30};\r
31\r
32\r
33VOID\r
34InstallHotPlugRequestProtocol (\r
35 IN EFI_STATUS *Status\r
36 )\r
37/*++\r
38\r
39Routine Description:\r
40\r
41Arguments:\r
42 Status - A pointer to the status.\r
43\r
44Returns:\r
45\r
46 None\r
47\r
48--*/\r
49{\r
50 EFI_HANDLE Handle;\r
51\r
6874dbd0 52 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
53 return;\r
54 }\r
55\r
878ddf1f 56 Handle = NULL;\r
57 *Status = gBS->InstallProtocolInterface (\r
58 &Handle,\r
59 &gEfiPciHotPlugRequestProtocolGuid,\r
60 EFI_NATIVE_INTERFACE,\r
61 &gPciHotPlugRequest\r
62 );\r
63}\r
64\r
65VOID\r
66InstallPciHotplugGuid (\r
67 IN PCI_IO_DEVICE *PciIoDevice\r
68 )\r
69/*++\r
70\r
71Routine Description:\r
72\r
73Arguments:\r
74\r
75 PciIoDevice - A pointer to the PCI_IO_DEVICE.\r
76\r
77Returns:\r
78\r
79 None\r
80\r
81--*/\r
82{\r
83 EFI_STATUS Status;\r
84\r
6874dbd0 85 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
86 return;\r
87 }\r
88\r
878ddf1f 89 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Parent->Pci)) {\r
90\r
91 Status = gBS->InstallProtocolInterface (\r
92 &PciIoDevice->Handle,\r
93 &gEfiPciHotplugDeviceGuid,\r
94 EFI_NATIVE_INTERFACE,\r
95 NULL\r
96 );\r
1cc8ee78 97 ASSERT_EFI_ERROR (Status);\r
878ddf1f 98 }\r
99}\r
100\r
101VOID\r
102UninstallPciHotplugGuid (\r
103 IN PCI_IO_DEVICE *PciIoDevice\r
104 )\r
105/*++\r
106\r
107Routine Description:\r
108\r
109Arguments:\r
110\r
111 PciIoDevice - A pointer to the PCI_IO_DEVICE.\r
112\r
113Returns:\r
114\r
115 None\r
116\r
117--*/\r
118{\r
119 EFI_STATUS Status;\r
120\r
6874dbd0 121 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
122 return;\r
123 }\r
124\r
878ddf1f 125 Status = gBS->OpenProtocol (\r
126 PciIoDevice->Handle,\r
127 &gEfiPciHotplugDeviceGuid,\r
128 NULL,\r
129 NULL,\r
130 NULL,\r
131 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
132 );\r
133\r
134 if (Status == EFI_SUCCESS) {\r
135 //\r
136 // This may triger CardBus driver to stop for\r
137 // Pccard devices opened the GUID via BY_DRIVER\r
138 //\r
139 Status = gBS->UninstallProtocolInterface (\r
140 PciIoDevice->Handle,\r
141 &gEfiPciHotplugDeviceGuid,\r
142 NULL\r
143 );\r
144 }\r
145}\r
146\r
147VOID\r
148GetBackPcCardBar (\r
149 IN PCI_IO_DEVICE *PciIoDevice\r
150 )\r
151/*++\r
152\r
153Routine Description:\r
154\r
155\r
156Arguments:\r
157\r
158 PciIoDevice - A pointer to the PCI_IO_DEVICE.\r
159\r
160Returns:\r
161\r
162 None\r
163\r
164--*/\r
165{\r
166 UINT32 Address;\r
167\r
6874dbd0 168 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
169 return;\r
170 }\r
171\r
878ddf1f 172 //\r
173 // Read PciBar information from the bar register\r
174 //\r
175 if (!gFullEnumeration) {\r
176\r
177 Address = 0;\r
98419ef4 178 PciIoRead (\r
878ddf1f 179 &(PciIoDevice->PciIo),\r
180 EfiPciIoWidthUint32,\r
181 0x1c,\r
182 1,\r
183 &Address\r
184 );\r
185\r
186 (PciIoDevice->PciBar)[P2C_MEM_1].BaseAddress = (UINT64) (Address);\r
187 (PciIoDevice->PciBar)[P2C_MEM_1].Length = 0x2000000;\r
188 (PciIoDevice->PciBar)[P2C_MEM_1].BarType = PciBarTypeMem32;\r
189\r
190 Address = 0;\r
98419ef4 191 PciIoRead (\r
878ddf1f 192 &(PciIoDevice->PciIo),\r
193 EfiPciIoWidthUint32,\r
194 0x20,\r
195 1,\r
196 &Address\r
197 );\r
198 (PciIoDevice->PciBar)[P2C_MEM_2].BaseAddress = (UINT64) (Address);\r
199 (PciIoDevice->PciBar)[P2C_MEM_2].Length = 0x2000000;\r
200 (PciIoDevice->PciBar)[P2C_MEM_2].BarType = PciBarTypePMem32;\r
201\r
202 Address = 0;\r
98419ef4 203 PciIoRead (\r
878ddf1f 204 &(PciIoDevice->PciIo),\r
205 EfiPciIoWidthUint32,\r
206 0x2c,\r
207 1,\r
208 &Address\r
209 );\r
210 (PciIoDevice->PciBar)[P2C_IO_1].BaseAddress = (UINT64) (Address);\r
211 (PciIoDevice->PciBar)[P2C_IO_1].Length = 0x100;\r
212 (PciIoDevice->PciBar)[P2C_IO_1].BarType = PciBarTypeIo16;\r
213\r
214 Address = 0;\r
98419ef4 215 PciIoRead (\r
878ddf1f 216 &(PciIoDevice->PciIo),\r
217 EfiPciIoWidthUint32,\r
218 0x34,\r
219 1,\r
220 &Address\r
221 );\r
222 (PciIoDevice->PciBar)[P2C_IO_2].BaseAddress = (UINT64) (Address);\r
223 (PciIoDevice->PciBar)[P2C_IO_2].Length = 0x100;\r
224 (PciIoDevice->PciBar)[P2C_IO_2].BarType = PciBarTypeIo16;\r
225\r
226 }\r
227\r
228 if (gPciHotPlugInit != NULL) {\r
229 GetResourcePaddingForHpb (PciIoDevice);\r
230 }\r
231}\r
232\r
233EFI_STATUS\r
234RemoveRejectedPciDevices (\r
235 EFI_HANDLE RootBridgeHandle,\r
236 IN PCI_IO_DEVICE *Bridge\r
237 )\r
238/*++\r
239\r
240Routine Description:\r
241\r
242\r
243Arguments:\r
244\r
245 RootBridgeHandle - An efi handle.\r
246 Bridge - An pointer to the PCI_IO_DEVICE.\r
247\r
248Returns:\r
249\r
250 None\r
251\r
252--*/\r
253// TODO: EFI_SUCCESS - add return value to function comment\r
254{\r
255 PCI_IO_DEVICE *Temp;\r
256 LIST_ENTRY *CurrentLink;\r
257 LIST_ENTRY *LastLink;\r
258\r
6874dbd0 259 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
260 return EFI_SUCCESS;\r
261 }\r
262\r
878ddf1f 263 CurrentLink = Bridge->ChildList.ForwardLink;\r
264\r
265 while (CurrentLink && CurrentLink != &Bridge->ChildList) {\r
266\r
267 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
268\r
269 if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
270 //\r
271 // Remove rejected devices recusively\r
272 //\r
273 RemoveRejectedPciDevices (RootBridgeHandle, Temp);\r
274 } else {\r
275 //\r
276 // Skip rejection for all PPBs, while detect rejection for others\r
277 //\r
278 if (IsPciDeviceRejected (Temp)) {\r
98419ef4 279\r
878ddf1f 280 //\r
281 // For P2C, remove all devices on it\r
282 //\r
98419ef4 283\r
878ddf1f 284 if (!IsListEmpty (&Temp->ChildList)) {\r
285 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);\r
286 }\r
98419ef4 287\r
878ddf1f 288 //\r
289 // Finally remove itself\r
290 //\r
98419ef4 291\r
878ddf1f 292 LastLink = CurrentLink->BackLink;\r
293 RemoveEntryList (CurrentLink);\r
294 FreePciDevice (Temp);\r
295\r
296 CurrentLink = LastLink;\r
297 }\r
298 }\r
299\r
300 CurrentLink = CurrentLink->ForwardLink;\r
301 }\r
302\r
303 return EFI_SUCCESS;\r
304}\r
305\r
306EFI_STATUS\r
307PciHostBridgeResourceAllocator (\r
308 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
309 )\r
6874dbd0 310{\r
311 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
312 return PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport (\r
313 PciResAlloc\r
314 );\r
315 } else {\r
316 return PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (\r
317 PciResAlloc\r
318 );\r
98419ef4 319 }\r
6874dbd0 320}\r
321\r
322\r
323EFI_STATUS\r
324PciHostBridgeResourceAllocator_WithoutHotPlugDeviceSupport (\r
325 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
326 )\r
327/*++\r
328\r
329Routine Description:\r
330\r
331Arguments:\r
332\r
333Returns:\r
334\r
335 None\r
336\r
337--*/\r
338// TODO: PciResAlloc - add argument and description to function comment\r
339// TODO: EFI_NOT_FOUND - add return value to function comment\r
340// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
341// TODO: EFI_NOT_FOUND - add return value to function comment\r
342// TODO: EFI_SUCCESS - add return value to function comment\r
343{\r
344 PCI_IO_DEVICE *RootBridgeDev;\r
345 EFI_HANDLE RootBridgeHandle;\r
346 VOID *AcpiConfig;\r
347 EFI_STATUS Status;\r
348 UINT64 IoBase;\r
349 UINT64 Mem32Base;\r
350 UINT64 PMem32Base;\r
351 UINT64 Mem64Base;\r
352 UINT64 PMem64Base;\r
353 UINT64 MaxOptionRomSize;\r
354 PCI_RESOURCE_NODE *IoBridge;\r
355 PCI_RESOURCE_NODE *Mem32Bridge;\r
356 PCI_RESOURCE_NODE *PMem32Bridge;\r
357 PCI_RESOURCE_NODE *Mem64Bridge;\r
358 PCI_RESOURCE_NODE *PMem64Bridge;\r
359 PCI_RESOURCE_NODE IoPool;\r
360 PCI_RESOURCE_NODE Mem32Pool;\r
361 PCI_RESOURCE_NODE PMem32Pool;\r
362 PCI_RESOURCE_NODE Mem64Pool;\r
363 PCI_RESOURCE_NODE PMem64Pool;\r
364 REPORT_STATUS_CODE_LIBRARY_DEVICE_HANDLE_EXTENDED_DATA ExtendedData;\r
365\r
366 //\r
367 // Initialize resource pool\r
368 //\r
98419ef4 369\r
6874dbd0 370 InitializeResourcePool (&IoPool, PciBarTypeIo16);\r
371 InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);\r
372 InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);\r
373 InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);\r
374 InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);\r
375\r
376 RootBridgeDev = NULL;\r
377 RootBridgeHandle = 0;\r
378\r
379 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
380 //\r
381 // Get RootBridg Device by handle\r
382 //\r
383 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
384\r
385 if (RootBridgeDev == NULL) {\r
386 return EFI_NOT_FOUND;\r
387 }\r
388\r
389 //\r
390 // Get host bridge handle for status report\r
391 //\r
392 ExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;\r
393\r
394 //\r
395 // Create the entire system resource map from the information collected by\r
396 // enumerator. Several resource tree was created\r
397 //\r
398\r
399 IoBridge = CreateResourceNode (\r
400 RootBridgeDev,\r
401 0,\r
402 0xFFF,\r
403 0,\r
404 PciBarTypeIo16,\r
405 PciResUsageTypical\r
406 );\r
407\r
408 Mem32Bridge = CreateResourceNode (\r
409 RootBridgeDev,\r
410 0,\r
411 0xFFFFF,\r
412 0,\r
413 PciBarTypeMem32,\r
414 PciResUsageTypical\r
415 );\r
416\r
417 PMem32Bridge = CreateResourceNode (\r
418 RootBridgeDev,\r
419 0,\r
420 0xFFFFF,\r
421 0,\r
422 PciBarTypePMem32,\r
423 PciResUsageTypical\r
424 );\r
425\r
426 Mem64Bridge = CreateResourceNode (\r
427 RootBridgeDev,\r
428 0,\r
429 0xFFFFF,\r
430 0,\r
431 PciBarTypeMem64,\r
432 PciResUsageTypical\r
433 );\r
434\r
435 PMem64Bridge = CreateResourceNode (\r
436 RootBridgeDev,\r
437 0,\r
438 0xFFFFF,\r
439 0,\r
440 PciBarTypePMem64,\r
441 PciResUsageTypical\r
442 );\r
443\r
444 //\r
445 // Create resourcemap by going through all the devices subject to this root bridge\r
446 //\r
447 Status = CreateResourceMap (\r
448 RootBridgeDev,\r
449 IoBridge,\r
450 Mem32Bridge,\r
451 PMem32Bridge,\r
452 Mem64Bridge,\r
453 PMem64Bridge\r
454 );\r
455\r
456 //\r
457 // Get the max ROM size that the root bridge can process\r
458 //\r
459 RootBridgeDev->RomSize = Mem32Bridge->Length;\r
460\r
461 //\r
462 // Get Max Option Rom size for current root bridge\r
463 //\r
464 MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);\r
465\r
466 //\r
467 // Enlarger the mem32 resource to accomdate the option rom\r
468 // if the mem32 resource is not enough to hold the rom\r
469 //\r
470 if (MaxOptionRomSize > Mem32Bridge->Length) {\r
471\r
472 Mem32Bridge->Length = MaxOptionRomSize;\r
473 RootBridgeDev->RomSize = MaxOptionRomSize;\r
474\r
475 //\r
476 // Alignment should be adjusted as well\r
477 //\r
478 if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) {\r
479 Mem32Bridge->Alignment = MaxOptionRomSize - 1;\r
480 }\r
481 }\r
98419ef4 482\r
6874dbd0 483 //\r
484 // Based on the all the resource tree, contruct ACPI resource node to\r
485 // submit the resource aperture to pci host bridge protocol\r
486 //\r
487 Status = ConstructAcpiResourceRequestor (\r
488 RootBridgeDev,\r
489 IoBridge,\r
490 Mem32Bridge,\r
491 PMem32Bridge,\r
492 Mem64Bridge,\r
493 PMem64Bridge,\r
494 &AcpiConfig\r
495 );\r
496\r
497 //\r
498 // Insert these resource nodes into the database\r
499 //\r
500 InsertResourceNode (&IoPool, IoBridge);\r
501 InsertResourceNode (&Mem32Pool, Mem32Bridge);\r
502 InsertResourceNode (&PMem32Pool, PMem32Bridge);\r
503 InsertResourceNode (&Mem64Pool, Mem64Bridge);\r
504 InsertResourceNode (&PMem64Pool, PMem64Bridge);\r
505\r
506 if (Status == EFI_SUCCESS) {\r
507 //\r
508 // Submit the resource requirement\r
509 //\r
510 Status = PciResAlloc->SubmitResources (\r
511 PciResAlloc,\r
512 RootBridgeDev->Handle,\r
513 AcpiConfig\r
514 );\r
515 }\r
516 //\r
517 // Free acpi resource node\r
518 //\r
98419ef4 519 if (AcpiConfig != NULL) {\r
520 FreePool (AcpiConfig);\r
6874dbd0 521 }\r
522\r
523 if (EFI_ERROR (Status)) {\r
524 //\r
525 // Destroy all the resource tree\r
526 //\r
527 DestroyResourceTree (&IoPool);\r
528 DestroyResourceTree (&Mem32Pool);\r
529 DestroyResourceTree (&PMem32Pool);\r
530 DestroyResourceTree (&Mem64Pool);\r
531 DestroyResourceTree (&PMem64Pool);\r
532 return Status;\r
533 }\r
534 }\r
535 //\r
536 // End while\r
537 //\r
538\r
539 //\r
540 // Notify pci bus driver starts to program the resource\r
541 //\r
542 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);\r
543\r
544 if (EFI_ERROR (Status)) {\r
545 //\r
546 // Allocation failed, then return\r
547 //\r
548 return EFI_OUT_OF_RESOURCES;\r
549 }\r
550 //\r
551 // Raise the EFI_IOB_PCI_RES_ALLOC status code\r
552 //\r
553 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
554 EFI_PROGRESS_CODE,\r
555 EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_RES_ALLOC,\r
556 (VOID *) &ExtendedData,\r
557 sizeof (ExtendedData)\r
558 );\r
559\r
560 //\r
561 // Notify pci bus driver starts to program the resource\r
562 //\r
563 NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);\r
564\r
565 RootBridgeDev = NULL;\r
566\r
567 RootBridgeHandle = 0;\r
568\r
569 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
570 //\r
571 // Get RootBridg Device by handle\r
572 //\r
573 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
574\r
575 if (RootBridgeDev == NULL) {\r
576 return EFI_NOT_FOUND;\r
577 }\r
98419ef4 578\r
6874dbd0 579 //\r
580 // Get acpi resource node for all the resource types\r
581 //\r
582 AcpiConfig = NULL;\r
583 Status = PciResAlloc->GetProposedResources (\r
584 PciResAlloc,\r
585 RootBridgeDev->Handle,\r
586 &AcpiConfig\r
587 );\r
588\r
589 if (EFI_ERROR (Status)) {\r
590 return Status;\r
591 }\r
592\r
593 //\r
594 // Get the resource base by interpreting acpi resource node\r
595 //\r
596 //\r
597 GetResourceBase (\r
598 AcpiConfig,\r
599 &IoBase,\r
600 &Mem32Base,\r
601 &PMem32Base,\r
602 &Mem64Base,\r
603 &PMem64Base\r
604 );\r
605\r
606 //\r
607 // Process option rom for this root bridge\r
608 //\r
609 Status = ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize);\r
610\r
611 //\r
612 // Create the entire system resource map from the information collected by\r
613 // enumerator. Several resource tree was created\r
614 //\r
615 Status = GetResourceMap (\r
616 RootBridgeDev,\r
617 &IoBridge,\r
618 &Mem32Bridge,\r
619 &PMem32Bridge,\r
620 &Mem64Bridge,\r
621 &PMem64Bridge,\r
622 &IoPool,\r
623 &Mem32Pool,\r
624 &PMem32Pool,\r
625 &Mem64Pool,\r
626 &PMem64Pool\r
627 );\r
628\r
629 if (EFI_ERROR (Status)) {\r
630 return Status;\r
631 }\r
632\r
633 //\r
634 // Program IO resources\r
635 //\r
636 ProgramResource (\r
637 IoBase,\r
638 IoBridge\r
639 );\r
640\r
641 //\r
642 // Program Mem32 resources\r
643 //\r
644 ProgramResource (\r
645 Mem32Base,\r
646 Mem32Bridge\r
647 );\r
648\r
649 //\r
650 // Program PMem32 resources\r
651 //\r
652 ProgramResource (\r
653 PMem32Base,\r
654 PMem32Bridge\r
655 );\r
656\r
657 //\r
658 // Program Mem64 resources\r
659 //\r
660 ProgramResource (\r
661 Mem64Base,\r
662 Mem64Bridge\r
663 );\r
664\r
665 //\r
666 // Program PMem64 resources\r
667 //\r
668 ProgramResource (\r
669 PMem64Base,\r
670 PMem64Bridge\r
671 );\r
672\r
673 if (AcpiConfig != NULL) {\r
98419ef4 674 FreePool (AcpiConfig);\r
6874dbd0 675 }\r
676 }\r
677\r
678 //\r
679 // Destroy all the resource tree\r
680 //\r
681 DestroyResourceTree (&IoPool);\r
682 DestroyResourceTree (&Mem32Pool);\r
683 DestroyResourceTree (&PMem32Pool);\r
684 DestroyResourceTree (&Mem64Pool);\r
685 DestroyResourceTree (&PMem64Pool);\r
686\r
687 //\r
688 // Notify the resource allocation phase is to end\r
689 //\r
690 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);\r
691\r
692 return EFI_SUCCESS;\r
693}\r
694\r
695\r
696EFI_STATUS\r
697PciHostBridgeResourceAllocator_WithHotPlugDeviceSupport (\r
698 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
699 )\r
878ddf1f 700/*++\r
701\r
702Routine Description:\r
703\r
704 Host brige resource allocator.\r
705\r
706Arguments:\r
707\r
708 PciResAlloc - A pointer to the EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.\r
709\r
710Returns:\r
711\r
712 EFI Status.\r
713\r
714--*/\r
715// TODO: EFI_NOT_FOUND - add return value to function comment\r
716// TODO: EFI_NOT_FOUND - add return value to function comment\r
717// TODO: EFI_NOT_FOUND - add return value to function comment\r
718// TODO: EFI_SUCCESS - add return value to function comment\r
719{\r
720 PCI_IO_DEVICE *RootBridgeDev;\r
721 EFI_HANDLE RootBridgeHandle;\r
722 VOID *AcpiConfig;\r
723 EFI_STATUS Status;\r
724 UINT64 IoBase;\r
725 UINT64 Mem32Base;\r
726 UINT64 PMem32Base;\r
727 UINT64 Mem64Base;\r
728 UINT64 PMem64Base;\r
729 UINT64 IoResStatus;\r
730 UINT64 Mem32ResStatus;\r
731 UINT64 PMem32ResStatus;\r
732 UINT64 Mem64ResStatus;\r
733 UINT64 PMem64ResStatus;\r
734 UINT64 MaxOptionRomSize;\r
735 PCI_RESOURCE_NODE *IoBridge;\r
736 PCI_RESOURCE_NODE *Mem32Bridge;\r
737 PCI_RESOURCE_NODE *PMem32Bridge;\r
738 PCI_RESOURCE_NODE *Mem64Bridge;\r
739 PCI_RESOURCE_NODE *PMem64Bridge;\r
740 PCI_RESOURCE_NODE IoPool;\r
741 PCI_RESOURCE_NODE Mem32Pool;\r
742 PCI_RESOURCE_NODE PMem32Pool;\r
743 PCI_RESOURCE_NODE Mem64Pool;\r
744 PCI_RESOURCE_NODE PMem64Pool;\r
745 BOOLEAN ReAllocate;\r
746 REPORT_STATUS_CODE_LIBRARY_DEVICE_HANDLE_EXTENDED_DATA HandleExtendedData;\r
747 REPORT_STATUS_CODE_LIBRARY_RESOURCE_ALLOC_FAILURE_ERROR_DATA AllocFailExtendedData;\r
748\r
749 //\r
750 // Reallocate flag\r
751 //\r
752 ReAllocate = FALSE;\r
753\r
754 //\r
755 // It will try several times if the resource allocation fails\r
756 //\r
757 while (TRUE) {\r
758\r
759 //\r
760 // Initialize resource pool\r
98419ef4 761 //\r
878ddf1f 762 InitializeResourcePool (&IoPool, PciBarTypeIo16);\r
763 InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);\r
764 InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);\r
765 InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);\r
766 InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);\r
767\r
768 RootBridgeDev = NULL;\r
769 RootBridgeHandle = 0;\r
770\r
771 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
772\r
773 //\r
774 // Get RootBridg Device by handle\r
775 //\r
776 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
777\r
778 if (RootBridgeDev == NULL) {\r
779 return EFI_NOT_FOUND;\r
780 }\r
781\r
782 //\r
783 // Create the entire system resource map from the information collected by\r
784 // enumerator. Several resource tree was created\r
785 //\r
786\r
787 IoBridge = CreateResourceNode (\r
788 RootBridgeDev,\r
789 0,\r
790 0xFFF,\r
791 0,\r
792 PciBarTypeIo16,\r
793 PciResUsageTypical\r
794 );\r
795\r
796 Mem32Bridge = CreateResourceNode (\r
797 RootBridgeDev,\r
798 0,\r
799 0xFFFFF,\r
800 0,\r
801 PciBarTypeMem32,\r
802 PciResUsageTypical\r
803 );\r
804\r
805 PMem32Bridge = CreateResourceNode (\r
806 RootBridgeDev,\r
807 0,\r
808 0xFFFFF,\r
809 0,\r
810 PciBarTypePMem32,\r
811 PciResUsageTypical\r
812 );\r
813\r
814 Mem64Bridge = CreateResourceNode (\r
815 RootBridgeDev,\r
816 0,\r
817 0xFFFFF,\r
818 0,\r
819 PciBarTypeMem64,\r
820 PciResUsageTypical\r
821 );\r
822\r
823 PMem64Bridge = CreateResourceNode (\r
824 RootBridgeDev,\r
825 0,\r
826 0xFFFFF,\r
827 0,\r
828 PciBarTypePMem64,\r
829 PciResUsageTypical\r
830 );\r
831\r
832 //\r
833 // Create resourcemap by going through all the devices subject to this root bridge\r
834 //\r
835 Status = CreateResourceMap (\r
836 RootBridgeDev,\r
837 IoBridge,\r
838 Mem32Bridge,\r
839 PMem32Bridge,\r
840 Mem64Bridge,\r
841 PMem64Bridge\r
842 );\r
843\r
844 //\r
845 // Get the max ROM size that the root bridge can process\r
846 //\r
847 RootBridgeDev->RomSize = Mem32Bridge->Length;\r
848\r
849 //\r
850 // Skip to enlarge the resource request during realloction\r
851 //\r
852 if (!ReAllocate) {\r
853 //\r
854 // Get Max Option Rom size for current root bridge\r
855 //\r
856 MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);\r
857\r
858 //\r
859 // Enlarger the mem32 resource to accomdate the option rom\r
860 // if the mem32 resource is not enough to hold the rom\r
861 //\r
862 if (MaxOptionRomSize > Mem32Bridge->Length) {\r
863\r
864 Mem32Bridge->Length = MaxOptionRomSize;\r
865 RootBridgeDev->RomSize = MaxOptionRomSize;\r
866\r
867 //\r
868 // Alignment should be adjusted as well\r
869 //\r
870 if (Mem32Bridge->Alignment < MaxOptionRomSize - 1) {\r
871 Mem32Bridge->Alignment = MaxOptionRomSize - 1;\r
872 }\r
873 }\r
98419ef4 874 }\r
875\r
878ddf1f 876 //\r
877 // Based on the all the resource tree, contruct ACPI resource node to\r
878 // submit the resource aperture to pci host bridge protocol\r
879 //\r
880 Status = ConstructAcpiResourceRequestor (\r
881 RootBridgeDev,\r
882 IoBridge,\r
883 Mem32Bridge,\r
884 PMem32Bridge,\r
885 Mem64Bridge,\r
886 PMem64Bridge,\r
887 &AcpiConfig\r
888 );\r
889\r
890 //\r
891 // Insert these resource nodes into the database\r
892 //\r
893 InsertResourceNode (&IoPool, IoBridge);\r
894 InsertResourceNode (&Mem32Pool, Mem32Bridge);\r
895 InsertResourceNode (&PMem32Pool, PMem32Bridge);\r
896 InsertResourceNode (&Mem64Pool, Mem64Bridge);\r
897 InsertResourceNode (&PMem64Pool, PMem64Bridge);\r
898\r
899 if (Status == EFI_SUCCESS) {\r
900 //\r
901 // Submit the resource requirement\r
902 //\r
903 Status = PciResAlloc->SubmitResources (\r
904 PciResAlloc,\r
905 RootBridgeDev->Handle,\r
906 AcpiConfig\r
907 );\r
908 }\r
909\r
910 //\r
911 // Free acpi resource node\r
912 //\r
913 if (AcpiConfig != NULL) {\r
98419ef4 914 FreePool (AcpiConfig);\r
878ddf1f 915 }\r
916\r
917 if (EFI_ERROR (Status)) {\r
918 //\r
919 // Destroy all the resource tree\r
920 //\r
921 DestroyResourceTree (&IoPool);\r
922 DestroyResourceTree (&Mem32Pool);\r
923 DestroyResourceTree (&PMem32Pool);\r
924 DestroyResourceTree (&Mem64Pool);\r
925 DestroyResourceTree (&PMem64Pool);\r
926 return Status;\r
927 }\r
928 }\r
929\r
930 //\r
931 // Notify pci bus driver starts to program the resource\r
932 //\r
98419ef4 933\r
878ddf1f 934 Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);\r
935\r
936 if (!EFI_ERROR (Status)) {\r
937 //\r
938 // Allocation succeed, then continue the following\r
939 //\r
940 break;\r
941 }\r
98419ef4 942\r
878ddf1f 943 //\r
944 // If the resource allocation is unsuccessful, free resources on bridge\r
945 //\r
98419ef4 946\r
878ddf1f 947 RootBridgeDev = NULL;\r
948 RootBridgeHandle = 0;\r
949\r
950 IoResStatus = EFI_RESOURCE_SATISFIED;\r
951 Mem32ResStatus = EFI_RESOURCE_SATISFIED;\r
952 PMem32ResStatus = EFI_RESOURCE_SATISFIED;\r
953 Mem64ResStatus = EFI_RESOURCE_SATISFIED;\r
954 PMem64ResStatus = EFI_RESOURCE_SATISFIED;\r
955\r
956 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
957 //\r
958 // Get RootBridg Device by handle\r
959 //\r
960 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
961 if (RootBridgeDev == NULL) {\r
962 return EFI_NOT_FOUND;\r
963 }\r
98419ef4 964\r
878ddf1f 965 //\r
966 // Get host bridge handle for status report\r
967 //\r
968 HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;\r
969\r
970 //\r
971 // Get acpi resource node for all the resource types\r
972 //\r
973 AcpiConfig = NULL;\r
974\r
975 Status = PciResAlloc->GetProposedResources (\r
976 PciResAlloc,\r
977 RootBridgeDev->Handle,\r
978 &AcpiConfig\r
979 );\r
980\r
981 if (EFI_ERROR (Status)) {\r
982 return Status;\r
983 }\r
984\r
985 if (AcpiConfig != NULL) {\r
986 //\r
987 // Adjust resource allocation policy for each RB\r
988 //\r
989 GetResourceAllocationStatus (\r
990 AcpiConfig,\r
991 &IoResStatus,\r
992 &Mem32ResStatus,\r
993 &PMem32ResStatus,\r
994 &Mem64ResStatus,\r
995 &PMem64ResStatus\r
996 );\r
98419ef4 997 FreePool (AcpiConfig);\r
878ddf1f 998 }\r
999 }\r
1000 //\r
1001 // End while\r
1002 //\r
1003\r
1004 //\r
1005 // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code\r
1006 //\r
1007 //\r
1008 // It is very difficult to follow the spec here\r
1009 // Device path , Bar index can not be get here\r
1010 //\r
1011 ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));\r
1012\r
1013 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
1014 EFI_PROGRESS_CODE,\r
1015 EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,\r
1016 (VOID *) &AllocFailExtendedData,\r
1017 sizeof (AllocFailExtendedData)\r
1018 );\r
1019\r
1020 Status = PciHostBridgeAdjustAllocation (\r
1021 &IoPool,\r
1022 &Mem32Pool,\r
1023 &PMem32Pool,\r
1024 &Mem64Pool,\r
1025 &PMem64Pool,\r
1026 IoResStatus,\r
1027 Mem32ResStatus,\r
1028 PMem32ResStatus,\r
1029 Mem64ResStatus,\r
1030 PMem64ResStatus\r
1031 );\r
1032\r
1033 //\r
1034 // Destroy all the resource tree\r
1035 //\r
1036 DestroyResourceTree (&IoPool);\r
1037 DestroyResourceTree (&Mem32Pool);\r
1038 DestroyResourceTree (&PMem32Pool);\r
1039 DestroyResourceTree (&Mem64Pool);\r
1040 DestroyResourceTree (&PMem64Pool);\r
1041\r
1042 NotifyPhase (PciResAlloc, EfiPciHostBridgeFreeResources);\r
1043\r
1044 if (EFI_ERROR (Status)) {\r
1045 return Status;\r
1046 }\r
1047\r
1048 ReAllocate = TRUE;\r
1049\r
1050 }\r
1051 //\r
1052 // End main while\r
1053 //\r
1054\r
1055 //\r
1056 // Raise the EFI_IOB_PCI_RES_ALLOC status code\r
1057 //\r
1058 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
1059 EFI_PROGRESS_CODE,\r
1060 EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_RES_ALLOC,\r
1061 (VOID *) &HandleExtendedData,\r
1062 sizeof (HandleExtendedData)\r
1063 );\r
1064\r
1065 //\r
1066 // Notify pci bus driver starts to program the resource\r
1067 //\r
1068 NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);\r
1069\r
1070 RootBridgeDev = NULL;\r
1071\r
1072 RootBridgeHandle = 0;\r
1073\r
1074 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1075\r
1076 //\r
1077 // Get RootBridg Device by handle\r
1078 //\r
1079 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
1080\r
1081 if (RootBridgeDev == NULL) {\r
1082 return EFI_NOT_FOUND;\r
1083 }\r
98419ef4 1084\r
878ddf1f 1085 //\r
1086 // Get acpi resource node for all the resource types\r
1087 //\r
1088 AcpiConfig = NULL;\r
1089 Status = PciResAlloc->GetProposedResources (\r
1090 PciResAlloc,\r
1091 RootBridgeDev->Handle,\r
1092 &AcpiConfig\r
1093 );\r
1094\r
1095 if (EFI_ERROR (Status)) {\r
1096 return Status;\r
1097 }\r
1098\r
1099 //\r
1100 // Get the resource base by interpreting acpi resource node\r
1101 //\r
1102 //\r
1103 GetResourceBase (\r
1104 AcpiConfig,\r
1105 &IoBase,\r
1106 &Mem32Base,\r
1107 &PMem32Base,\r
1108 &Mem64Base,\r
1109 &PMem64Base\r
1110 );\r
1111\r
1112 //\r
1113 // Process option rom for this root bridge\r
1114 //\r
1115 Status = ProcessOptionRom (RootBridgeDev, Mem32Base, RootBridgeDev->RomSize);\r
1116\r
1117 //\r
1118 // Create the entire system resource map from the information collected by\r
1119 // enumerator. Several resource tree was created\r
1120 //\r
1121 Status = GetResourceMap (\r
1122 RootBridgeDev,\r
1123 &IoBridge,\r
1124 &Mem32Bridge,\r
1125 &PMem32Bridge,\r
1126 &Mem64Bridge,\r
1127 &PMem64Bridge,\r
1128 &IoPool,\r
1129 &Mem32Pool,\r
1130 &PMem32Pool,\r
1131 &Mem64Pool,\r
1132 &PMem64Pool\r
1133 );\r
1134\r
1135 if (EFI_ERROR (Status)) {\r
1136 return Status;\r
1137 }\r
1138\r
1139 //\r
1140 // Program IO resources\r
1141 //\r
1142 ProgramResource (\r
1143 IoBase,\r
1144 IoBridge\r
1145 );\r
1146\r
1147 //\r
1148 // Program Mem32 resources\r
1149 //\r
1150 ProgramResource (\r
1151 Mem32Base,\r
1152 Mem32Bridge\r
1153 );\r
1154\r
1155 //\r
1156 // Program PMem32 resources\r
1157 //\r
1158 ProgramResource (\r
1159 PMem32Base,\r
1160 PMem32Bridge\r
1161 );\r
1162\r
1163 //\r
1164 // Program Mem64 resources\r
1165 //\r
1166 ProgramResource (\r
1167 Mem64Base,\r
1168 Mem64Bridge\r
1169 );\r
1170\r
1171 //\r
1172 // Program PMem64 resources\r
1173 //\r
1174 ProgramResource (\r
1175 PMem64Base,\r
1176 PMem64Bridge\r
1177 );\r
1178\r
1179 if (AcpiConfig != NULL) {\r
1180 gBS->FreePool (AcpiConfig);\r
1181 }\r
1182 }\r
1183\r
1184 //\r
1185 // Destroy all the resource tree\r
1186 //\r
1187 DestroyResourceTree (&IoPool);\r
1188 DestroyResourceTree (&Mem32Pool);\r
1189 DestroyResourceTree (&PMem32Pool);\r
1190 DestroyResourceTree (&Mem64Pool);\r
1191 DestroyResourceTree (&PMem64Pool);\r
1192\r
1193 //\r
1194 // Notify the resource allocation phase is to end\r
1195 //\r
1196 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);\r
1197\r
1198 return EFI_SUCCESS;\r
1199}\r
1200\r
6874dbd0 1201\r
878ddf1f 1202EFI_STATUS\r
1203PciScanBus (\r
1204 IN PCI_IO_DEVICE *Bridge,\r
1205 IN UINT8 StartBusNumber,\r
1206 OUT UINT8 *SubBusNumber,\r
1207 OUT UINT8 *PaddedBusRange\r
1208 )\r
6874dbd0 1209{\r
1210 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1211 return PciScanBus_WithHotPlugDeviceSupport (\r
98419ef4 1212 Bridge,\r
1213 StartBusNumber,\r
1214 SubBusNumber,\r
6874dbd0 1215 PaddedBusRange\r
1216 );\r
1217 } else {\r
1218 return PciScanBus_WithoutHotPlugDeviceSupport (\r
98419ef4 1219 Bridge,\r
1220 StartBusNumber,\r
1221 SubBusNumber,\r
6874dbd0 1222 PaddedBusRange\r
1223 );\r
1224 }\r
1225}\r
1226\r
1227\r
1228EFI_STATUS\r
1229PciScanBus_WithoutHotPlugDeviceSupport (\r
1230 IN PCI_IO_DEVICE *Bridge,\r
1231 IN UINT8 StartBusNumber,\r
1232 OUT UINT8 *SubBusNumber,\r
1233 OUT UINT8 *PaddedBusRange\r
1234 )\r
1235/*++\r
1236\r
1237Routine Description:\r
1238\r
1239 This routine is used to assign bus number to the given PCI bus system\r
1240\r
1241Arguments:\r
1242\r
1243Returns:\r
1244\r
1245 None\r
1246\r
1247--*/\r
1248// TODO: Bridge - add argument and description to function comment\r
1249// TODO: StartBusNumber - add argument and description to function comment\r
1250// TODO: SubBusNumber - add argument and description to function comment\r
1251// TODO: PaddedBusRange - add argument and description to function comment\r
1252// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
1253// TODO: EFI_SUCCESS - add return value to function comment\r
1254{\r
1255 EFI_STATUS Status;\r
1256 PCI_TYPE00 Pci;\r
1257 UINT8 Device;\r
1258 UINT8 Func;\r
1259 UINT64 Address;\r
1260 UINTN SecondBus;\r
1261 UINT16 Register;\r
1262 PCI_IO_DEVICE *PciDevice;\r
1263 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1264\r
1265 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
1266 SecondBus = 0;\r
1267 Register = 0;\r
1268\r
1269 ResetAllPpbBusReg (Bridge, StartBusNumber);\r
1270\r
1271 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
1272 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
1273\r
1274 //\r
1275 // Check to see whether a pci device is present\r
1276 //\r
1277 Status = PciDevicePresent (\r
1278 PciRootBridgeIo,\r
1279 &Pci,\r
1280 StartBusNumber,\r
1281 Device,\r
1282 Func\r
1283 );\r
1284\r
98419ef4 1285 if (!EFI_ERROR (Status) &&\r
6874dbd0 1286 (IS_PCI_BRIDGE (&Pci) ||\r
1287 IS_CARDBUS_BRIDGE (&Pci))) {\r
1288\r
1289 //\r
1290 // Get the bridge information\r
1291 //\r
1292 Status = PciSearchDevice (\r
1293 Bridge,\r
1294 &Pci,\r
1295 StartBusNumber,\r
1296 Device,\r
1297 Func,\r
1298 &PciDevice\r
1299 );\r
1300\r
1301 if (EFI_ERROR (Status)) {\r
1302 return Status;\r
1303 }\r
1304\r
1305 (*SubBusNumber)++;\r
1306\r
1307 SecondBus = (*SubBusNumber);\r
1308\r
1309 Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);\r
1310\r
1311 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
1312\r
98419ef4 1313 Status = PciRootBridgeIoWrite (\r
6874dbd0 1314 PciRootBridgeIo,\r
98419ef4 1315 &Pci,\r
6874dbd0 1316 EfiPciWidthUint16,\r
1317 Address,\r
1318 1,\r
1319 &Register\r
1320 );\r
1321\r
1322 //\r
1323 // Initialize SubBusNumber to SecondBus\r
1324 //\r
1325 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
98419ef4 1326 Status = PciRootBridgeIoWrite (\r
6874dbd0 1327 PciRootBridgeIo,\r
98419ef4 1328 &Pci,\r
6874dbd0 1329 EfiPciWidthUint8,\r
1330 Address,\r
1331 1,\r
1332 SubBusNumber\r
1333 );\r
1334 //\r
1335 // If it is PPB, resursively search down this bridge\r
1336 //\r
1337 if (IS_PCI_BRIDGE (&Pci)) {\r
1338 //\r
1339 // Temporarily initialize SubBusNumber to maximum bus number to ensure the\r
1340 // PCI configuration transaction to go through any PPB\r
1341 //\r
1342 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1343 Register = 0xFF;\r
98419ef4 1344 Status = PciRootBridgeIoWrite (\r
6874dbd0 1345 PciRootBridgeIo,\r
98419ef4 1346 &Pci,\r
6874dbd0 1347 EfiPciWidthUint8,\r
1348 Address,\r
1349 1,\r
1350 &Register\r
1351 );\r
1352\r
1353 PreprocessController (\r
1354 PciDevice,\r
1355 PciDevice->BusNumber,\r
1356 PciDevice->DeviceNumber,\r
1357 PciDevice->FunctionNumber,\r
1358 EfiPciBeforeChildBusEnumeration\r
1359 );\r
1360\r
1361 Status = PciScanBus (\r
1362 PciDevice,\r
1363 (UINT8) (SecondBus),\r
1364 SubBusNumber,\r
1365 PaddedBusRange\r
1366 );\r
1367\r
1368 if (EFI_ERROR (Status)) {\r
1369 return EFI_DEVICE_ERROR;\r
1370 }\r
1371 }\r
1372\r
1373 //\r
1374 // Set the current maximum bus number under the PPB\r
1375 //\r
1376\r
1377 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1378\r
98419ef4 1379 Status = PciRootBridgeIoWrite (\r
6874dbd0 1380 PciRootBridgeIo,\r
98419ef4 1381 &Pci,\r
6874dbd0 1382 EfiPciWidthUint8,\r
1383 Address,\r
1384 1,\r
1385 SubBusNumber\r
1386 );\r
1387\r
1388 }\r
1389\r
1390 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
1391\r
1392 //\r
1393 // Skip sub functions, this is not a multi function device\r
1394 //\r
1395\r
1396 Func = PCI_MAX_FUNC;\r
1397 }\r
1398 }\r
1399 }\r
1400\r
1401 return EFI_SUCCESS;\r
1402}\r
1403\r
1404EFI_STATUS\r
1405PciScanBus_WithHotPlugDeviceSupport (\r
1406 IN PCI_IO_DEVICE *Bridge,\r
1407 IN UINT8 StartBusNumber,\r
1408 OUT UINT8 *SubBusNumber,\r
1409 OUT UINT8 *PaddedBusRange\r
1410 )\r
878ddf1f 1411/*++\r
1412\r
1413Routine Description:\r
1414\r
1415 This routine is used to assign bus number to the given PCI bus system\r
1416\r
1417Arguments:\r
1418\r
1419 Bridge - A pointer to the PCI_IO_DEVICE structure.\r
1420 StartBusNumber - The start bus number.\r
1421 SubBusNumber - A pointer to the sub bus number.\r
1422 PaddedBusRange - A pointer to the padded bus range.\r
1423\r
1424Returns:\r
1425\r
1426 None\r
1427\r
1428--*/\r
1429// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
1430// TODO: EFI_SUCCESS - add return value to function comment\r
1431{\r
1432 EFI_STATUS Status;\r
1433 PCI_TYPE00 Pci;\r
1434 UINT8 Device;\r
1435 UINT8 Func;\r
1436 UINT64 Address;\r
1437 UINTN SecondBus;\r
1438 UINT16 Register;\r
1439 UINTN HpIndex;\r
1440 PCI_IO_DEVICE *PciDevice;\r
1441 EFI_EVENT Event;\r
1442 EFI_HPC_STATE State;\r
1443 UINT64 PciAddress;\r
1444 EFI_HPC_PADDING_ATTRIBUTES Attributes;\r
1445 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
1446 UINT16 BusRange;\r
1447 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1448 BOOLEAN BusPadding;\r
1449\r
1450 PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
1451 SecondBus = 0;\r
1452 Register = 0;\r
1453 State = 0;\r
1cc8ee78 1454 Attributes = (EFI_HPC_PADDING_ATTRIBUTES) 0;\r
878ddf1f 1455 BusRange = 0;\r
1456\r
1457 ResetAllPpbBusReg (Bridge, StartBusNumber);\r
1458\r
1459 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
1460 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
1461\r
1462 //\r
1463 // Check to see whether a pci device is present\r
1464 //\r
1465 Status = PciDevicePresent (\r
1466 PciRootBridgeIo,\r
1467 &Pci,\r
1468 StartBusNumber,\r
1469 Device,\r
1470 Func\r
1471 );\r
1472\r
1473 if (EFI_ERROR (Status)) {\r
1474 if (Func == 0) {\r
1475 //\r
1476 // Skip sub functions, this is not a multi function device\r
1477 //\r
1478 Func = PCI_MAX_FUNC;\r
1479 }\r
1480\r
1481 continue;\r
1482 }\r
98419ef4 1483\r
878ddf1f 1484 //\r
1485 // Get the PCI device information\r
1486 //\r
1487 Status = PciSearchDevice (\r
1488 Bridge,\r
1489 &Pci,\r
1490 StartBusNumber,\r
1491 Device,\r
1492 Func,\r
1493 &PciDevice\r
1494 );\r
1495\r
1496 ASSERT (!EFI_ERROR (Status));\r
1497\r
1498 PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);\r
1499\r
1500 if (!IS_PCI_BRIDGE (&Pci)) {\r
1501 //\r
1502 // PCI bridges will be called later\r
1503 // Here just need for PCI device or PCI to cardbus controller\r
1504 // EfiPciBeforeChildBusEnumeration for PCI Device Node\r
1505 //\r
1506 PreprocessController (\r
1507 PciDevice,\r
1508 PciDevice->BusNumber,\r
1509 PciDevice->DeviceNumber,\r
1510 PciDevice->FunctionNumber,\r
1511 EfiPciBeforeChildBusEnumeration\r
1512 );\r
1513 }\r
98419ef4 1514\r
878ddf1f 1515 //\r
1516 // For Pci Hotplug controller devcie only\r
1517 //\r
1518 if (gPciHotPlugInit != NULL) {\r
1519 //\r
1520 // Check if it is a Hotplug PCI controller\r
1521 //\r
1522 if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {\r
1523\r
1524 if (!gPciRootHpcData[HpIndex].Initialized) {\r
1525\r
1526 Status = CreateEventForHpc (HpIndex, &Event);\r
1527\r
1528 ASSERT (!EFI_ERROR (Status));\r
1529\r
1530 Status = gPciHotPlugInit->InitializeRootHpc (\r
1531 gPciHotPlugInit,\r
1532 gPciRootHpcPool[HpIndex].HpcDevicePath,\r
1533 PciAddress,\r
1534 Event,\r
1535 &State\r
1536 );\r
98419ef4 1537\r
878ddf1f 1538 PreprocessController (\r
1539 PciDevice,\r
1540 PciDevice->BusNumber,\r
1541 PciDevice->DeviceNumber,\r
1542 PciDevice->FunctionNumber,\r
1543 EfiPciBeforeChildBusEnumeration\r
98419ef4 1544 );\r
878ddf1f 1545 continue;\r
1546 }\r
1547 }\r
1548 }\r
1549\r
1550 if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) {\r
1551 //\r
1552 // For PPB\r
1553 // Get the bridge information\r
1554 //\r
1555 BusPadding = FALSE;\r
1556 if (gPciHotPlugInit != NULL) {\r
1557\r
1558 if (IsRootPciHotPlugBus (PciDevice->DevicePath, &HpIndex)) {\r
98419ef4 1559\r
878ddf1f 1560 //\r
1561 // If it is initialized, get the padded bus range\r
1562 //\r
1563 Status = gPciHotPlugInit->GetResourcePadding (\r
1564 gPciHotPlugInit,\r
1565 gPciRootHpcPool[HpIndex].HpbDevicePath,\r
1566 PciAddress,\r
1567 &State,\r
1568 (VOID **) &Descriptors,\r
1569 &Attributes\r
1570 );\r
1571\r
1572 if (EFI_ERROR (Status)) {\r
1573 return Status;\r
1574 }\r
1575\r
1576 BusRange = 0;\r
1577 Status = PciGetBusRange (\r
1578 &Descriptors,\r
1579 NULL,\r
1580 NULL,\r
1581 &BusRange\r
1582 );\r
1583\r
1584 gBS->FreePool (Descriptors);\r
1585\r
1586 if (EFI_ERROR (Status)) {\r
1587 return Status;\r
1588 }\r
1589\r
1590 BusPadding = TRUE;\r
1591 }\r
1592 }\r
1593\r
1594 (*SubBusNumber)++;\r
1595 SecondBus = *SubBusNumber;\r
1596\r
1597 Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);\r
1598 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
1599\r
98419ef4 1600 Status = PciRootBridgeIoWrite (\r
878ddf1f 1601 PciRootBridgeIo,\r
98419ef4 1602 &Pci,\r
878ddf1f 1603 EfiPciWidthUint16,\r
1604 Address,\r
1605 1,\r
1606 &Register\r
1607 );\r
1608\r
1609\r
1610 //\r
1611 // If it is PPB, resursively search down this bridge\r
1612 //\r
1613 if (IS_PCI_BRIDGE (&Pci)) {\r
98419ef4 1614\r
878ddf1f 1615 //\r
1616 // Initialize SubBusNumber to Maximum bus number\r
1617 //\r
1618 Register = 0xFF;\r
1619 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
98419ef4 1620 Status = PciRootBridgeIoWrite (\r
878ddf1f 1621 PciRootBridgeIo,\r
98419ef4 1622 &Pci,\r
878ddf1f 1623 EfiPciWidthUint8,\r
1624 Address,\r
1625 1,\r
1626 &Register\r
1627 );\r
1628\r
1629 //\r
1630 // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige\r
1631 //\r
1632 PreprocessController (\r
1633 PciDevice,\r
1634 PciDevice->BusNumber,\r
1635 PciDevice->DeviceNumber,\r
1636 PciDevice->FunctionNumber,\r
1637 EfiPciBeforeChildBusEnumeration\r
1638 );\r
1639\r
1640 Status = PciScanBus (\r
1641 PciDevice,\r
1642 (UINT8) (SecondBus),\r
1643 SubBusNumber,\r
1644 PaddedBusRange\r
1645 );\r
1646\r
1647 if (EFI_ERROR (Status)) {\r
1648 return EFI_DEVICE_ERROR;\r
1649 }\r
1650 }\r
1651\r
1652 if (BusPadding) {\r
1653 //\r
1654 // Ensure the device is enabled and initialized\r
1655 //\r
1656 if ((Attributes == EfiPaddingPciRootBridge) &&\r
1657 (State & EFI_HPC_STATE_ENABLED) &&\r
1658 (State & EFI_HPC_STATE_INITIALIZED) ) {\r
1659 *PaddedBusRange = (UINT8) ((UINT8) (BusRange) +*PaddedBusRange);\r
1660 } else {\r
1661 *SubBusNumber = (UINT8) ((UINT8) (BusRange) +*SubBusNumber);\r
1662 }\r
1663 }\r
1664\r
1665 //\r
1666 // Set the current maximum bus number under the PPB\r
1667 //\r
1668 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x1A);\r
1669\r
98419ef4 1670 Status = PciRootBridgeIoWrite (\r
878ddf1f 1671 PciRootBridgeIo,\r
98419ef4 1672 &Pci,\r
878ddf1f 1673 EfiPciWidthUint8,\r
1674 Address,\r
1675 1,\r
1676 SubBusNumber\r
1677 );\r
1678 }\r
1679\r
1680 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
1681\r
1682 //\r
1683 // Skip sub functions, this is not a multi function device\r
1684 //\r
1685 Func = PCI_MAX_FUNC;\r
1686 }\r
1687\r
1688 }\r
1689 }\r
1690\r
1691 return EFI_SUCCESS;\r
1692}\r
1693\r
1694EFI_STATUS\r
1695PciRootBridgeP2CProcess (\r
1696 IN PCI_IO_DEVICE *Bridge\r
1697 )\r
1698/*++\r
1699\r
1700Routine Description:\r
98419ef4 1701\r
878ddf1f 1702 Process Option Rom on this host bridge\r
1703\r
1704Arguments:\r
1705\r
1706Returns:\r
1707\r
1708 None\r
1709\r
1710--*/\r
1711// TODO: Bridge - add argument and description to function comment\r
1712// TODO: EFI_SUCCESS - add return value to function comment\r
1713{\r
1714 LIST_ENTRY *CurrentLink;\r
1715 PCI_IO_DEVICE *Temp;\r
1716 EFI_HPC_STATE State;\r
1717 UINT64 PciAddress;\r
1718 EFI_STATUS Status;\r
1719\r
1720 CurrentLink = Bridge->ChildList.ForwardLink;\r
1721\r
1722 while (CurrentLink && CurrentLink != &Bridge->ChildList) {\r
1723\r
1724 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1725\r
1726 if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {\r
1727\r
1728 if (gPciHotPlugInit && Temp->Allocated) {\r
98419ef4 1729\r
878ddf1f 1730 //\r
1731 // Raise the EFI_IOB_PCI_HPC_INIT status code\r
1732 //\r
1733 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1734 EFI_PROGRESS_CODE,\r
1735 EFI_IO_BUS_PCI | EFI_IOB_PCI_PC_HPC_INIT,\r
1736 Temp->DevicePath\r
1737 );\r
1738\r
1739 PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1740 Status = gPciHotPlugInit->InitializeRootHpc (\r
1741 gPciHotPlugInit,\r
1742 Temp->DevicePath,\r
1743 PciAddress,\r
1744 NULL,\r
1745 &State\r
1746 );\r
1747\r
1748 if (!EFI_ERROR (Status)) {\r
1749 Status = PciBridgeEnumerator (Temp);\r
1750\r
1751 if (EFI_ERROR (Status)) {\r
1752 return Status;\r
1753 }\r
1754 }\r
1755\r
1756 CurrentLink = CurrentLink->ForwardLink;\r
1757 continue;\r
1758\r
1759 }\r
1760 }\r
1761\r
1762 if (!IsListEmpty (&Temp->ChildList)) {\r
1763 Status = PciRootBridgeP2CProcess (Temp);\r
1764 }\r
1765\r
1766 CurrentLink = CurrentLink->ForwardLink;\r
1767 }\r
1768\r
1769 return EFI_SUCCESS;\r
1770}\r
1771\r
1772EFI_STATUS\r
1773PciHostBridgeP2CProcess (\r
1774 IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
1775 )\r
1776/*++\r
1777\r
1778Routine Description:\r
98419ef4 1779\r
878ddf1f 1780Arguments:\r
1781\r
1782Returns:\r
1783\r
1784 None\r
1785\r
1786--*/\r
1787// TODO: PciResAlloc - add argument and description to function comment\r
1788// TODO: EFI_NOT_FOUND - add return value to function comment\r
1789// TODO: EFI_SUCCESS - add return value to function comment\r
1790{\r
1791 EFI_HANDLE RootBridgeHandle;\r
1792 PCI_IO_DEVICE *RootBridgeDev;\r
1793 EFI_STATUS Status;\r
1794\r
6874dbd0 1795 if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
1796 return EFI_SUCCESS;\r
1797 }\r
1798\r
878ddf1f 1799 RootBridgeHandle = NULL;\r
1800\r
1801 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1802\r
1803 //\r
1804 // Get RootBridg Device by handle\r
1805 //\r
1806 RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);\r
1807\r
1808 if (RootBridgeDev == NULL) {\r
1809 return EFI_NOT_FOUND;\r
1810 }\r
1811\r
1812 Status = PciRootBridgeP2CProcess (RootBridgeDev);\r
1813\r
1814 if (EFI_ERROR (Status)) {\r
1815 return Status;\r
1816 }\r
1817\r
1818 }\r
1819\r
1820 return EFI_SUCCESS;\r
1821}\r
1822\r
1823EFI_STATUS\r
1824PciHostBridgeEnumerator (\r
1825 EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc\r
1826 )\r
1827/*++\r
1828\r
1829Routine Description:\r
1830\r
98419ef4 1831 This function is used to enumerate the entire host bridge\r
878ddf1f 1832 in a given platform\r
1833\r
1834Arguments:\r
1835\r
1836 PciResAlloc - A pointer to the resource allocate protocol.\r
1837\r
1838Returns:\r
1839\r
1840 None\r
1841\r
1842--*/\r
1843// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
1844// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
1845// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment\r
1846// TODO: EFI_SUCCESS - add return value to function comment\r
1847{\r
1848 EFI_HANDLE RootBridgeHandle;\r
1849 PCI_IO_DEVICE *RootBridgeDev;\r
1850 EFI_STATUS Status;\r
1851 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
1852 UINT16 MinBus;\r
1853 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
1854\r
1855 InitializeHotPlugSupport ();\r
1856\r
1857 //\r
1858 // Notify the bus allocation phase is about to start\r
1859 //\r
1860 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);\r
1861\r
1862 RootBridgeHandle = NULL;\r
1863 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1864\r
1865 //\r
1866 // if a root bridge instance is found, create root bridge device for it\r
1867 //\r
1868\r
1869 RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1870\r
1871 if (RootBridgeDev == NULL) {\r
1872 return EFI_OUT_OF_RESOURCES;\r
1873 }\r
1874\r
1875 //\r
1876 // Enumerate all the buses under this root bridge\r
1877 //\r
1878\r
1879 Status = PciRootBridgeEnumerator (\r
1880 PciResAlloc,\r
1881 RootBridgeDev\r
1882 );\r
1883\r
1884 if (EFI_ERROR (Status)) {\r
1885 return Status;\r
1886 }\r
1887\r
1888 DestroyRootBridge (RootBridgeDev);\r
1889\r
1890 //\r
1891 // Error proccess here\r
1892 //\r
1893 }\r
1894\r
6874dbd0 1895 if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {\r
878ddf1f 1896\r
98419ef4 1897 //\r
6874dbd0 1898 // Notify the bus allocation phase is finished for the first time\r
98419ef4 1899 //\r
6874dbd0 1900 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);\r
98419ef4 1901\r
1902\r
6874dbd0 1903 if (gPciHotPlugInit != NULL) {\r
878ddf1f 1904 //\r
6874dbd0 1905 // Wait for all HPC initialized\r
878ddf1f 1906 //\r
6874dbd0 1907 Status = AllRootHPCInitialized (STALL_1_SECOND * 15);\r
878ddf1f 1908\r
6874dbd0 1909 if (EFI_ERROR (Status)) {\r
1910 return Status;\r
878ddf1f 1911 }\r
1912\r
1913 //\r
6874dbd0 1914 // Notify the bus allocation phase is about to start for the 2nd time\r
878ddf1f 1915 //\r
6874dbd0 1916 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);\r
98419ef4 1917\r
6874dbd0 1918 RootBridgeHandle = NULL;\r
1919 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
878ddf1f 1920\r
6874dbd0 1921 //\r
1922 // if a root bridge instance is found, create root bridge device for it\r
1923 //\r
878ddf1f 1924\r
6874dbd0 1925 RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1926\r
1927 if (RootBridgeDev == NULL) {\r
1928 return EFI_OUT_OF_RESOURCES;\r
1929 }\r
1930\r
1931 //\r
1932 // Enumerate all the buses under this root bridge\r
1933 //\r
1934\r
1935 Status = PciRootBridgeEnumerator (\r
1936 PciResAlloc,\r
1937 RootBridgeDev\r
1938 );\r
1939\r
1940 DestroyRootBridge (RootBridgeDev);\r
1941 if (EFI_ERROR (Status)) {\r
1942 return Status;\r
1943 }\r
878ddf1f 1944 }\r
98419ef4 1945\r
6874dbd0 1946 //\r
1947 // Notify the bus allocation phase is to end\r
1948 //\r
1949 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);\r
878ddf1f 1950 }\r
6874dbd0 1951 } else {\r
878ddf1f 1952 //\r
1953 // Notify the bus allocation phase is to end\r
1954 //\r
1955 NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);\r
1956 }\r
1957\r
1958 //\r
1959 // Notify the resource allocation phase is to start\r
1960 //\r
1961 NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation);\r
1962\r
1963 RootBridgeHandle = NULL;\r
1964 while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {\r
1965\r
1966 //\r
1967 // if a root bridge instance is found, create root bridge device for it\r
1968 //\r
1969\r
1970 RootBridgeDev = CreateRootBridge (RootBridgeHandle);\r
1971\r
1972 if (RootBridgeDev == NULL) {\r
1973 return EFI_OUT_OF_RESOURCES;\r
1974 }\r
1975\r
1976 Status = StartManagingRootBridge (RootBridgeDev);\r
1977\r
1978 if (EFI_ERROR (Status)) {\r
1979 return Status;\r
1980 }\r
1981\r
1982 PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;\r
1983 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
1984\r
1985 if (EFI_ERROR (Status)) {\r
1986 return Status;\r
1987 }\r
1988\r
1989 Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);\r
1990\r
1991 if (EFI_ERROR (Status)) {\r
1992 return Status;\r
1993 }\r
1994\r
1995 //\r
1996 // Determine root bridge attribute by calling interface of Pcihostbridge\r
1997 // protocol\r
1998 //\r
1999 DetermineRootBridgeAttributes (\r
2000 PciResAlloc,\r
2001 RootBridgeDev\r
2002 );\r
2003\r
2004 //\r
2005 // Collect all the resource information under this root bridge\r
2006 // A database that records all the information about pci device subject to this\r
2007 // root bridge will then be created\r
2008 //\r
2009 Status = PciPciDeviceInfoCollector (\r
2010 RootBridgeDev,\r
2011 (UINT8) MinBus\r
2012 );\r
2013\r
2014 if (EFI_ERROR (Status)) {\r
2015 return Status;\r
2016 }\r
2017\r
2018 InsertRootBridge (RootBridgeDev);\r
2019\r
2020 //\r
2021 // Record the hostbridge handle\r
2022 //\r
2023 AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle);\r
2024 }\r
2025\r
2026 return EFI_SUCCESS;\r
2027}\r
98419ef4 2028\r
2029/**\r
2030 Read PCI device configuration register by specified address.\r
2031\r
2032 This function check the incompatiblilites on PCI device. Return the register\r
2033 value.\r
2034\r
2035 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2036 @param PciIo A pointer to EFI_PCI_PROTOCOL.\r
2037 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.\r
2038 @param Width Signifies the width of the memory operations.\r
2039 @Param Address The address within the PCI configuration space for the PCI controller.\r
2040 @param Buffer For read operations, the destination buffer to store the results. For\r
2041 write operations, the source buffer to write data from.\r
2042\r
2043 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
2044 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
2045 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
2046 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
2047\r
2048**/\r
2049STATIC\r
2050EFI_STATUS\r
2051ReadConfigData (\r
2052 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL\r
2053 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL\r
2054 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,\r
2055 IN UINT64 Width,\r
2056 IN UINT64 Address,\r
2057 IN OUT VOID *Buffer\r
2058 )\r
2059{\r
2060 EFI_STATUS Status;\r
2061 UINT64 AccessWidth;\r
2062 EFI_PCI_REGISTER_ACCESS_DATA *PciRegisterAccessData;\r
2063 UINT64 AccessAddress;\r
2064 UINTN Stride;\r
2065 UINT64 TempBuffer;\r
2066 UINT8 *Pointer;\r
2067\r
2068 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2069\r
2070 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) {\r
2071 //\r
2072 // check access compatibility at first time\r
2073 //\r
2074 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, Address & 0xff, Width, &PciRegisterAccessData);\r
2075\r
2076 if (Status == EFI_SUCCESS) {\r
2077 //\r
2078 // there exist incompatibility on this operation\r
2079 //\r
2080 AccessWidth = Width;\r
2081\r
2082 if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2083 AccessWidth = PciRegisterAccessData->Width;\r
2084 }\r
2085\r
2086 AccessAddress = Address & ~((1 << AccessWidth) - 1);\r
2087\r
2088 TempBuffer = 0;\r
2089 Stride = 0;\r
2090 Pointer = (UINT8 *) &TempBuffer;\r
2091\r
2092 while (1) {\r
2093\r
2094 if (PciRootBridgeIo != NULL) {\r
2095 Status = PciRootBridgeIo->Pci.Read (\r
2096 PciRootBridgeIo,\r
2097 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,\r
2098 AccessAddress,\r
2099 1,\r
2100 Pointer\r
2101 );\r
2102 } else if (PciIo != NULL) {\r
2103 Status = PciIo->Pci.Read (\r
2104 PciIo,\r
2105 (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,\r
2106 (UINT32) AccessAddress,\r
2107 1,\r
2108 Pointer\r
2109 );\r
2110 }\r
2111\r
2112 if (Status != EFI_SUCCESS) {\r
2113 return Status;\r
2114 }\r
2115\r
2116 Stride = 1 << AccessWidth;\r
2117 AccessAddress += Stride;\r
2118 if (AccessAddress >= (Address + (1 << Width))) {\r
2119 //\r
2120 // if all datas have been read, exist\r
2121 //\r
2122 break;\r
2123 }\r
2124\r
2125 Pointer += Stride;\r
2126\r
2127 if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {\r
2128 //\r
2129 // if current offset doesn't reach the end\r
2130 //\r
2131 continue;\r
2132 }\r
2133\r
2134 FreePool (PciRegisterAccessData);\r
2135\r
2136 //\r
2137 // continue checking access incompatibility\r
2138 //\r
2139 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_READ, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);\r
2140 if (Status == EFI_SUCCESS) {\r
2141 if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2142 AccessWidth = PciRegisterAccessData->Width;\r
2143 }\r
2144 }\r
2145 }\r
2146\r
2147 FreePool (PciRegisterAccessData);\r
2148\r
2149 switch (Width) {\r
2150 case EfiPciWidthUint8:\r
2151 * (UINT8 *) Buffer = (UINT8) TempBuffer;\r
2152 break;\r
2153 case EfiPciWidthUint16:\r
2154 * (UINT16 *) Buffer = (UINT16) TempBuffer;\r
2155 break;\r
2156 case EfiPciWidthUint32:\r
2157 * (UINT32 *) Buffer = (UINT32) TempBuffer;\r
2158 break;\r
2159 default:\r
2160 return EFI_UNSUPPORTED;\r
2161 }\r
2162\r
2163 return Status;\r
2164 }\r
2165 }\r
2166 //\r
2167 // AccessWidth incompatible check not supportted\r
2168 // or, there doesn't exist incompatibility on this operation\r
2169 //\r
2170 if (PciRootBridgeIo != NULL) {\r
2171 Status = PciRootBridgeIo->Pci.Read (\r
2172 PciRootBridgeIo,\r
2173 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
2174 Address,\r
2175 1,\r
2176 Buffer\r
2177 );\r
2178\r
2179 } else {\r
2180 Status = PciIo->Pci.Read (\r
2181 PciIo,\r
2182 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
2183 (UINT32) Address,\r
2184 1,\r
2185 Buffer\r
2186 );\r
2187 }\r
2188\r
2189 return Status;\r
2190}\r
2191\r
2192/**\r
2193 Update register value by checking PCI device incompatibility.\r
2194\r
2195 This function check register value incompatibilites on PCI device. Return the register\r
2196 value.\r
2197\r
2198 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.\r
2199 @param AccessType Access type, READ or WRITE.\r
2200 @Param Address The address within the PCI configuration space.\r
2201 @param Buffer Store the register data.\r
2202\r
2203 @retval EFI_SUCCESS The data has been updated.\r
2204\r
2205**/\r
2206STATIC\r
2207EFI_STATUS\r
2208UpdateConfigData (\r
2209 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,\r
2210 IN UINT64 AccessType,\r
2211 IN UINT64 Width,\r
2212 IN UINT64 Address,\r
2213 IN OUT VOID *Buffer\r
2214)\r
2215{\r
2216 EFI_STATUS Status;\r
2217 EFI_PCI_REGISTER_VALUE_DATA *PciRegisterData;\r
2218 UINT64 AndValue;\r
2219 UINT64 OrValue;\r
2220 UINT32 TempValue;\r
2221\r
2222 //\r
2223 // check register value incompatibility\r
2224 //\r
2225 Status = PciRegisterUpdateCheck (PciDeviceInfo, AccessType, Address & 0xff, &PciRegisterData);\r
2226\r
2227 if (Status == EFI_SUCCESS) {\r
2228\r
2229 AndValue = (PciRegisterData->AndValue) >> ((Address & 0x3) * 8);\r
2230 OrValue = (PciRegisterData->OrValue) >> ((Address & 0x3) * 8);\r
2231\r
2232 TempValue = * (UINT32 *) Buffer;\r
2233\r
2234 if (PciRegisterData->AndValue != VALUE_NOCARE) {\r
2235 TempValue &= (UINT32) AndValue;\r
2236 }\r
2237 if (PciRegisterData->OrValue != VALUE_NOCARE) {\r
2238 TempValue |= (UINT32) OrValue;\r
2239 }\r
2240\r
2241 switch (Width) {\r
2242 case EfiPciWidthUint8:\r
2243 *(UINT32 *)Buffer = *(UINT32 *)Buffer & 0xffffff00 + (UINT8)TempValue;\r
2244 break;\r
2245\r
2246 case EfiPciWidthUint16:\r
2247 *(UINT32 *)Buffer = *(UINT32 *)Buffer & 0xffff0000 + (UINT16)TempValue;\r
2248 break;\r
2249 case EfiPciWidthUint32:\r
2250 *(UINT32 *)Buffer = TempValue;\r
2251 break;\r
2252\r
2253 default:\r
2254 return EFI_UNSUPPORTED;\r
2255 }\r
2256\r
2257 FreePool (PciRegisterData);\r
2258 }\r
2259\r
2260 return Status;\r
2261}\r
2262\r
2263/**\r
2264 Write PCI device configuration register by specified address.\r
2265\r
2266 This function check the incompatiblilites on PCI device, and write date\r
2267 into register.\r
2268\r
2269 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2270 @param PciIo A pointer to EFI_PCI_PROTOCOL.\r
2271 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.\r
2272 @param Width Signifies the width of the memory operations.\r
2273 @Param Address The address within the PCI configuration space for the PCI controller.\r
2274 @param Buffer For read operations, the destination buffer to store the results. For\r
2275 write operations, the source buffer to write data from.\r
2276\r
2277 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
2278 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
2279 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
2280 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
2281\r
2282**/\r
2283STATIC\r
2284EFI_STATUS\r
2285WriteConfigData (\r
2286 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL\r
2287 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL\r
2288 IN EFI_PCI_DEVICE_INFO *PciDeviceInfo,\r
2289 IN UINT64 Width,\r
2290 IN UINT64 Address,\r
2291 IN VOID *Buffer\r
2292 )\r
2293{\r
2294 EFI_STATUS Status;\r
2295 UINT64 AccessWidth;\r
2296 EFI_PCI_REGISTER_ACCESS_DATA *PciRegisterAccessData;\r
2297 UINT64 AccessAddress;\r
2298 UINTN Stride;\r
2299 UINT8 *Pointer;\r
2300 UINT64 Data;\r
2301 UINTN Shift;\r
2302\r
2303 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2304\r
2305 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_ACCESS_WIDTH_SUPPORT) {\r
2306 //\r
2307 // check access compatibility at first time\r
2308 //\r
2309 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, Address & 0xff, Width, &PciRegisterAccessData);\r
2310\r
2311 if (Status == EFI_SUCCESS) {\r
2312 //\r
2313 // there exist incompatibility on this operation\r
2314 //\r
2315 AccessWidth = Width;\r
2316\r
2317 if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2318 AccessWidth = PciRegisterAccessData->Width;\r
2319 }\r
2320\r
2321 AccessAddress = Address & ~((1 << AccessWidth) - 1);\r
2322\r
2323 Stride = 0;\r
2324 Pointer = (UINT8 *) &Buffer;\r
2325 Data = * (UINT64 *) Buffer;\r
2326\r
2327 while (1) {\r
2328\r
2329 if (AccessWidth > Width) {\r
2330 //\r
2331 // if actual access width is larger than orignal one, additional data need to be read back firstly\r
2332 //\r
2333 Status = ReadConfigData (PciRootBridgeIo, PciIo, PciDeviceInfo, AccessWidth, AccessAddress, &Data);\r
2334 if (Status != EFI_SUCCESS) {\r
2335 return Status;\r
2336 }\r
2337\r
2338 //\r
2339 // check data read incompatibility\r
2340 //\r
2341 UpdateConfigData (PciDeviceInfo, PCI_REGISTER_READ, AccessWidth, AccessAddress & 0xff, &Data);\r
2342\r
2343 Shift = (Address - AccessAddress) * 8;\r
2344 switch (Width) {\r
2345 case EfiPciWidthUint8:\r
2346 Data = (* (UINT8 *) Buffer) << Shift | (Data & ~(0xff << Shift));\r
2347 break;\r
2348\r
2349 case EfiPciWidthUint16:\r
2350 Data = (* (UINT16 *) Buffer) << Shift | (Data & ~(0xffff << Shift));\r
2351 break;\r
2352 }\r
2353\r
2354 //\r
2355 // check data write incompatibility\r
2356 //\r
2357 UpdateConfigData (PciDeviceInfo, PCI_REGISTER_WRITE, AccessWidth, AccessAddress * 0xff, &Data);\r
2358 }\r
2359\r
2360 if (PciRootBridgeIo != NULL) {\r
2361 Status = PciRootBridgeIo->Pci.Write (\r
2362 PciRootBridgeIo,\r
2363 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) AccessWidth,\r
2364 AccessAddress,\r
2365 1,\r
2366 &Data\r
2367 );\r
2368 } else {\r
2369 Status = PciIo->Pci.Write (\r
2370 PciIo,\r
2371 (EFI_PCI_IO_PROTOCOL_WIDTH) AccessWidth,\r
2372 (UINT32) AccessAddress,\r
2373 1,\r
2374 &Data\r
2375 );\r
2376 }\r
2377\r
2378 if (Status != EFI_SUCCESS) {\r
2379 return Status;\r
2380 }\r
2381\r
2382 Data = Data >> ((1 << AccessWidth) * 8);\r
2383\r
2384 Stride = 1 << AccessWidth;\r
2385 AccessAddress += Stride;\r
2386 if (AccessAddress >= (Address + (1 << Width))) {\r
2387 //\r
2388 // if all datas have been written, exist\r
2389 //\r
2390 break;\r
2391 }\r
2392\r
2393 Pointer += Stride;\r
2394\r
2395 if ((AccessAddress & 0xff) < PciRegisterAccessData->EndOffset) {\r
2396 //\r
2397 // if current offset doesn't reach the end\r
2398 //\r
2399 continue;\r
2400 }\r
2401\r
2402 FreePool (PciRegisterAccessData);\r
2403\r
2404 //\r
2405 // continue checking access incompatibility\r
2406 //\r
2407 Status = PciRegisterAccessCheck (PciDeviceInfo, PCI_REGISTER_WRITE, AccessAddress & 0xff, AccessWidth, &PciRegisterAccessData);\r
2408 if (Status == EFI_SUCCESS) {\r
2409 if (PciRegisterAccessData->Width != VALUE_NOCARE) {\r
2410 AccessWidth = PciRegisterAccessData->Width;\r
2411 }\r
2412 }\r
2413 };\r
2414\r
2415 FreePool (PciRegisterAccessData);\r
2416\r
2417 return Status;\r
2418 }\r
2419\r
2420 }\r
2421 //\r
2422 // AccessWidth incompatible check not supportted\r
2423 // or, there doesn't exist incompatibility on this operation\r
2424 //\r
2425 if (PciRootBridgeIo != NULL) {\r
2426 Status = PciRootBridgeIo->Pci.Write (\r
2427 PciRootBridgeIo,\r
2428 (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) Width,\r
2429 Address,\r
2430 1,\r
2431 Buffer\r
2432 );\r
2433 } else {\r
2434 Status = PciIo->Pci.Write (\r
2435 PciIo,\r
2436 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
2437 (UINT32) Address,\r
2438 1,\r
2439 Buffer\r
2440 );\r
2441 }\r
2442\r
2443 return Status;\r
2444}\r
2445\r
2446/**\r
2447 Abstract PCI device device information.\r
2448\r
2449 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2450 @param PciIo A pointer to EFI_PCI_PROTOCOL.\r
2451 @param Pci A pointer to PCI_TYPE00.\r
2452 @Param Address The address within the PCI configuration space for the PCI controller.\r
2453 @param PciDeviceInfo A pointer to EFI_PCI_DEVICE_INFO.\r
2454\r
2455 @retval EFI_SUCCESS Pci device device information has been abstracted.\r
2456\r
2457**/\r
2458STATIC\r
2459EFI_STATUS\r
2460GetPciDeviceDeviceInfo (\r
2461 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL\r
2462 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL\r
2463 IN PCI_TYPE00 *Pci, OPTIONAL\r
2464 IN UINT64 Address, OPTIONAL\r
2465 OUT EFI_PCI_DEVICE_INFO *PciDeviceInfo\r
2466)\r
2467{\r
2468 EFI_STATUS Status;\r
2469 UINT64 PciAddress;\r
2470 UINT32 PciConfigData;\r
2471 PCI_IO_DEVICE *PciIoDevice;\r
2472\r
2473 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2474\r
2475 if (PciIo != NULL) {\r
2476 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
2477\r
2478 //\r
2479 // get pointer to PCI_TYPE00 from PciIoDevice\r
2480 //\r
2481 Pci = &PciIoDevice->Pci;\r
2482 }\r
2483\r
2484 if (Pci == NULL) {\r
2485 //\r
2486 // while PCI_TYPE00 hasn't been gotten, read PCI device device information directly\r
2487 //\r
2488 PciAddress = Address & 0xffffffffffffff00ULL;\r
2489 Status = PciRootBridgeIo->Pci.Read (\r
2490 PciRootBridgeIo,\r
2491 EfiPciWidthUint32,\r
2492 PciAddress,\r
2493 1,\r
2494 &PciConfigData\r
2495 );\r
2496\r
2497 if (EFI_ERROR (Status)) {\r
2498 return Status;\r
2499 }\r
2500\r
2501 if ((PciConfigData & 0xffff) == 0xffff) {\r
2502 return EFI_NOT_FOUND;\r
2503 }\r
2504\r
2505 PciDeviceInfo->VendorID = PciConfigData & 0xffff;\r
2506 PciDeviceInfo->DeviceID = PciConfigData >> 16;\r
2507\r
2508 Status = PciRootBridgeIo->Pci.Read (\r
2509 PciRootBridgeIo,\r
2510 EfiPciWidthUint32,\r
2511 PciAddress + 8,\r
2512 1,\r
2513 &PciConfigData\r
2514 );\r
2515 if (EFI_ERROR (Status)) {\r
2516 return Status;\r
2517 }\r
2518\r
2519 PciDeviceInfo->RevisionID = PciConfigData & 0xf;\r
2520\r
2521 Status = PciRootBridgeIo->Pci.Read (\r
2522 PciRootBridgeIo,\r
2523 EfiPciWidthUint32,\r
2524 PciAddress + 0x2c,\r
2525 1,\r
2526 &PciConfigData\r
2527 );\r
2528\r
2529 if (EFI_ERROR (Status)) {\r
2530 return Status;\r
2531 }\r
2532\r
2533 PciDeviceInfo->SubsystemVendorID = PciConfigData & 0xffff;\r
2534 PciDeviceInfo->SubsystemID = PciConfigData >> 16;\r
2535\r
2536 } else {\r
2537 PciDeviceInfo->VendorID = Pci->Hdr.VendorId;\r
2538 PciDeviceInfo->DeviceID = Pci->Hdr.DeviceId;\r
2539 PciDeviceInfo->RevisionID = Pci->Hdr.RevisionID;\r
2540 PciDeviceInfo->SubsystemVendorID = Pci->Device.SubsystemVendorID;\r
2541 PciDeviceInfo->SubsystemID = Pci->Device.SubsystemID;\r
2542 }\r
2543\r
2544 return EFI_SUCCESS;\r
2545}\r
2546\r
2547/**\r
2548 Read PCI configuration space with incompatibility check.\r
2549\r
2550 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2551 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.\r
2552 @param Pci A pointer to PCI_TYPE00.\r
2553 @param Width Signifies the width of the memory operations.\r
2554 @Param Address The address within the PCI configuration space for the PCI controller.\r
2555 @param Buffer For read operations, the destination buffer to store the results. For\r
2556 write operations, the source buffer to write data from.\r
2557\r
2558 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
2559 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
2560 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
2561 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
2562\r
2563**/\r
2564STATIC\r
2565EFI_STATUS\r
2566PciIncompatibilityCheckRead (\r
2567 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL\r
2568 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL\r
2569 IN PCI_TYPE00 *Pci, OPTIONAL\r
2570 IN UINTN Width,\r
2571 IN UINT64 Address,\r
2572 IN UINTN Count,\r
2573 IN OUT VOID *Buffer\r
2574)\r
2575{\r
2576 EFI_STATUS Status;\r
2577 EFI_PCI_DEVICE_INFO PciDeviceInfo;\r
2578 UINT32 Stride;\r
2579\r
2580 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2581\r
2582 //\r
2583 // get PCI device device information\r
2584 //\r
2585 Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo);\r
2586 if (Status != EFI_SUCCESS) {\r
2587 return Status;\r
2588 }\r
2589\r
2590 Stride = 1 << Width;\r
2591\r
2592 for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *)Buffer + Stride) {\r
2593\r
2594 //\r
2595 // read configuration register\r
2596 //\r
2597 Status = ReadConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, (UINT64) Width, Address, Buffer);\r
2598\r
2599 if (Status != EFI_SUCCESS) {\r
2600 return Status;\r
2601 }\r
2602\r
2603 //\r
2604 // update the data read from configuration register\r
2605 //\r
2606 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) {\r
2607 UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_READ, Width, Address & 0xff, Buffer);\r
2608 }\r
2609 }\r
2610\r
2611 return EFI_SUCCESS;\r
2612}\r
2613\r
2614/**\r
2615 Write PCI configuration space with incompatibility check.\r
2616\r
2617 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2618 @param PciIo A pointer to the EFI_PCI_IO_PROTOCOL.\r
2619 @param Pci A pointer to PCI_TYPE00.\r
2620 @param Width Signifies the width of the memory operations.\r
2621 @Param Address The address within the PCI configuration space for the PCI controller.\r
2622 @param Buffer For read operations, the destination buffer to store the results. For\r
2623 write operations, the source buffer to write data from.\r
2624\r
2625 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
2626 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
2627 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
2628 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
2629\r
2630**/\r
2631STATIC\r
2632EFI_STATUS\r
2633PciIncompatibilityCheckWrite (\r
2634 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, OPTIONAL\r
2635 IN EFI_PCI_IO_PROTOCOL *PciIo, OPTIONAL\r
2636 IN PCI_TYPE00 *Pci, OPTIONAL\r
2637 IN UINTN Width,\r
2638 IN UINT64 Address,\r
2639 IN UINTN Count,\r
2640 IN OUT VOID *Buffer\r
2641)\r
2642{\r
2643 EFI_STATUS Status;\r
2644 EFI_PCI_DEVICE_INFO PciDeviceInfo;\r
2645 UINT32 Stride;\r
2646 UINT64 Data;\r
2647\r
2648 ASSERT ((PciRootBridgeIo == NULL) ^ (PciIo == NULL));\r
2649\r
2650 //\r
2651 // get PCI device device information\r
2652 //\r
2653 Status = GetPciDeviceDeviceInfo (PciRootBridgeIo, PciIo, Pci, Address, &PciDeviceInfo);\r
2654 if (Status != EFI_SUCCESS) {\r
2655 return Status;\r
2656 }\r
2657\r
2658 Stride = 1 << Width;\r
2659\r
2660 for (; Count > 0; Count--, Address += Stride, Buffer = (UINT8 *) Buffer + Stride) {\r
2661\r
2662 Data = 0;\r
2663\r
2664 switch (Width) {\r
2665 case EfiPciWidthUint8:\r
2666 Data = * (UINT8 *) Buffer;\r
2667 break;\r
2668 case EfiPciWidthUint16:\r
2669 Data = * (UINT16 *) Buffer;\r
2670 break;\r
2671\r
2672 case EfiPciWidthUint32:\r
2673 Data = * (UINT32 *) Buffer;\r
2674 break;\r
2675\r
2676 default:\r
2677 return EFI_UNSUPPORTED;\r
2678 }\r
2679\r
2680 //\r
2681 // update the data writen into configuration register\r
2682 //\r
2683 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_REGISTER_UPDATE_SUPPORT) {\r
2684 UpdateConfigData (&PciDeviceInfo, PCI_REGISTER_WRITE, Width, Address & 0xff, &Data);\r
2685 }\r
2686\r
2687 //\r
2688 // write configuration register\r
2689 //\r
2690 Status = WriteConfigData (PciRootBridgeIo, PciIo, &PciDeviceInfo, Width, Address, &Data);\r
2691\r
2692 if (Status != EFI_SUCCESS) {\r
2693 return Status;\r
2694 }\r
2695 }\r
2696\r
2697 return EFI_SUCCESS;\r
2698}\r
2699\r
2700/**\r
2701 Read PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2702\r
2703 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2704 @param Pci A pointer to PCI_TYPE00.\r
2705 @param Width Signifies the width of the memory operations.\r
2706 @Param Address The address within the PCI configuration space for the PCI controller.\r
2707 @param Buffer For read operations, the destination buffer to store the results. For\r
2708 write operations, the source buffer to write data from.\r
2709\r
2710 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
2711 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
2712 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
2713 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
2714\r
2715**/\r
2716EFI_STATUS\r
2717PciRootBridgeIoRead (\r
2718 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
2719 IN PCI_TYPE00 *Pci, OPTIONAL\r
2720 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
2721 IN UINT64 Address,\r
2722 IN UINTN Count,\r
2723 IN OUT VOID *Buffer\r
2724 )\r
2725{\r
2726 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) {\r
2727 //\r
2728 // if PCI incompatibility check enabled\r
2729 //\r
2730 return PciIncompatibilityCheckRead (\r
2731 PciRootBridgeIo,\r
2732 NULL,\r
2733 Pci,\r
2734 (UINTN) Width,\r
2735 Address,\r
2736 Count,\r
2737 Buffer\r
2738 );\r
2739 } else {\r
2740 return PciRootBridgeIo->Pci.Read (\r
2741 PciRootBridgeIo,\r
2742 Width,\r
2743 Address,\r
2744 Count,\r
2745 Buffer\r
2746 );\r
2747 }\r
2748}\r
2749\r
2750/**\r
2751 Write PCI configuration space through EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2752\r
2753 @param PciRootBridgeIo A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
2754 @param Pci A pointer to PCI_TYPE00.\r
2755 @param Width Signifies the width of the memory operations.\r
2756 @Param Address The address within the PCI configuration space for the PCI controller.\r
2757 @param Buffer For read operations, the destination buffer to store the results. For\r
2758 write operations, the source buffer to write data from.\r
2759\r
2760 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
2761 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
2762 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
2763 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
2764\r
2765**/\r
2766EFI_STATUS\r
2767PciRootBridgeIoWrite (\r
2768 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
2769 IN PCI_TYPE00 *Pci,\r
2770 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,\r
2771 IN UINT64 Address,\r
2772 IN UINTN Count,\r
2773 IN OUT VOID *Buffer\r
2774 )\r
2775{\r
2776 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) {\r
2777 //\r
2778 // if PCI incompatibility check enabled\r
2779 //\r
2780 return PciIncompatibilityCheckWrite (\r
2781 PciRootBridgeIo,\r
2782 NULL,\r
2783 Pci,\r
2784 Width,\r
2785 Address,\r
2786 Count,\r
2787 Buffer\r
2788 );\r
2789\r
2790 } else {\r
2791 return PciRootBridgeIo->Pci.Write (\r
2792 PciRootBridgeIo,\r
2793 Width,\r
2794 Address,\r
2795 Count,\r
2796 Buffer\r
2797 );\r
2798 }\r
2799}\r
2800\r
2801/**\r
2802 Read PCI configuration space through EFI_PCI_IO_PROTOCOL.\r
2803\r
2804 @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.\r
2805 @param Width Signifies the width of the memory operations.\r
2806 @Param Address The address within the PCI configuration space for the PCI controller.\r
2807 @param Buffer For read operations, the destination buffer to store the results. For\r
2808 write operations, the source buffer to write data from.\r
2809\r
2810 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
2811 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
2812 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
2813 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
2814\r
2815**/\r
2816EFI_STATUS\r
2817PciIoRead (\r
2818 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2819 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
2820 IN UINT32 Address,\r
2821 IN UINTN Count,\r
2822 IN OUT VOID *Buffer\r
2823 )\r
2824{\r
2825 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_READ_SUPPORT) {\r
2826 //\r
2827 // if PCI incompatibility check enabled\r
2828 //\r
2829 return PciIncompatibilityCheckRead (\r
2830 NULL,\r
2831 PciIo,\r
2832 NULL,\r
2833 (UINTN) Width,\r
2834 Address,\r
2835 Count,\r
2836 Buffer\r
2837 );\r
2838 } else {\r
2839 return PciIo->Pci.Read (\r
2840 PciIo,\r
2841 Width,\r
2842 Address,\r
2843 Count,\r
2844 Buffer\r
2845 );\r
2846 }\r
2847}\r
2848\r
2849/**\r
2850 Write PCI configuration space through EFI_PCI_IO_PROTOCOL.\r
2851\r
2852 @param PciIo A pointer to the EFI_PCI_O_PROTOCOL.\r
2853 @param Width Signifies the width of the memory operations.\r
2854 @Param Address The address within the PCI configuration space for the PCI controller.\r
2855 @param Buffer For read operations, the destination buffer to store the results. For\r
2856 write operations, the source buffer to write data from.\r
2857\r
2858 @retval EFI_SUCCESS The data was read from or written to the PCI root bridge.\r
2859 @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.\r
2860 @retval EFI_INVALID_PARAMETER Buffer is NULL.\r
2861 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
2862\r
2863**/\r
2864EFI_STATUS\r
2865PciIoWrite (\r
2866 IN EFI_PCI_IO_PROTOCOL *PciIo,\r
2867 IN EFI_PCI_IO_PROTOCOL_WIDTH Width,\r
2868 IN UINT32 Address,\r
2869 IN UINTN Count,\r
2870 IN OUT VOID *Buffer\r
2871 )\r
2872{\r
2873 if (PcdGet8 (PcdPciIncompatibleDeviceSupportMask) & PCI_INCOMPATIBLE_WRITE_SUPPORT) {\r
2874\r
2875 //\r
2876 // if PCI incompatibility check enabled\r
2877 //\r
2878 return PciIncompatibilityCheckWrite (\r
2879 NULL,\r
2880 PciIo,\r
2881 NULL,\r
2882 Width,\r
2883 Address,\r
2884 Count,\r
2885 Buffer\r
2886 );\r
2887\r
2888 } else {\r
2889 return PciIo->Pci.Write (\r
2890 PciIo,\r
2891 Width,\r
2892 Address,\r
2893 Count,\r
2894 Buffer\r
2895 );\r
2896 }\r
2897}\r