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