]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
Add IncompatiblePciDeviceSupportDxe module in IntelFrameworkModulePkg.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciDeviceSupport.c
CommitLineData
97404058 1/** @file\r
48a9ea7b 2 Supporting functions implementaion for PCI devices management.\r
ead42efc 3\r
8e8227d1 4Copyright (c) 2006 - 2009, Intel Corporation\r
5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
ead42efc 12\r
3db51098 13**/\r
ead42efc 14\r
19efd9ec 15#include "PciBus.h"\r
ead42efc 16\r
17//\r
18// This device structure is serviced as a header.\r
48a9ea7b 19// Its next field points to the first root bridge device node.\r
ead42efc 20//\r
48a9ea7b 21LIST_ENTRY mPciDevicePool;\r
ead42efc 22\r
a3b8e257 23/**\r
48a9ea7b 24 Initialize the PCI devices pool.\r
25\r
a3b8e257 26**/\r
48a9ea7b 27VOID\r
ead42efc 28InitializePciDevicePool (\r
29 VOID\r
30 )\r
ead42efc 31{\r
48a9ea7b 32 InitializeListHead (&mPciDevicePool);\r
ead42efc 33}\r
34\r
bcd70414 35/**\r
48a9ea7b 36 Insert a root bridge into PCI device pool.\r
ead42efc 37\r
48a9ea7b 38 @param RootBridge A pointer to the PCI_IO_DEVICE.\r
ead42efc 39\r
bcd70414 40**/\r
48a9ea7b 41VOID\r
a3b8e257 42InsertRootBridge (\r
48a9ea7b 43 IN PCI_IO_DEVICE *RootBridge\r
a3b8e257 44 )\r
ead42efc 45{\r
48a9ea7b 46 InsertTailList (&mPciDevicePool, &(RootBridge->Link));\r
ead42efc 47}\r
48\r
bcd70414 49/**\r
ead42efc 50 This function is used to insert a PCI device node under\r
48a9ea7b 51 a bridge.\r
ead42efc 52\r
48a9ea7b 53 @param Bridge The PCI bridge.\r
54 @param PciDeviceNode The PCI device needs inserting.\r
ead42efc 55\r
bcd70414 56**/\r
48a9ea7b 57VOID\r
a3b8e257 58InsertPciDevice (\r
48a9ea7b 59 IN PCI_IO_DEVICE *Bridge,\r
60 IN PCI_IO_DEVICE *PciDeviceNode\r
a3b8e257 61 )\r
ead42efc 62{\r
ead42efc 63 InsertTailList (&Bridge->ChildList, &(PciDeviceNode->Link));\r
64 PciDeviceNode->Parent = Bridge;\r
ead42efc 65}\r
66\r
a3b8e257 67/**\r
68 Destroy root bridge and remove it from deivce tree.\r
8e8227d1 69\r
48a9ea7b 70 @param RootBridge The bridge want to be removed.\r
8e8227d1 71\r
a3b8e257 72**/\r
48a9ea7b 73VOID\r
ead42efc 74DestroyRootBridge (\r
48a9ea7b 75 IN PCI_IO_DEVICE *RootBridge\r
ead42efc 76 )\r
ead42efc 77{\r
78 DestroyPciDeviceTree (RootBridge);\r
79\r
80 FreePciDevice (RootBridge);\r
ead42efc 81}\r
82\r
bcd70414 83/**\r
ead42efc 84 Destroy a pci device node.\r
ead42efc 85\r
48a9ea7b 86 All direct or indirect allocated resource for this node will be freed.\r
87\r
88 @param PciIoDevice A pointer to the PCI_IO_DEVICE to be destoried.\r
ead42efc 89\r
bcd70414 90**/\r
48a9ea7b 91VOID\r
a3b8e257 92FreePciDevice (\r
48a9ea7b 93 IN PCI_IO_DEVICE *PciIoDevice\r
a3b8e257 94 )\r
ead42efc 95{\r
48a9ea7b 96 ASSERT (PciIoDevice != NULL);\r
ead42efc 97 //\r
98 // Assume all children have been removed underneath this device\r
99 //\r
100 if (PciIoDevice->ResourcePaddingDescriptors != NULL) {\r
48a9ea7b 101 FreePool (PciIoDevice->ResourcePaddingDescriptors);\r
ead42efc 102 }\r
103\r
104 if (PciIoDevice->DevicePath != NULL) {\r
48a9ea7b 105 FreePool (PciIoDevice->DevicePath);\r
ead42efc 106 }\r
107\r
48a9ea7b 108 FreePool (PciIoDevice);\r
ead42efc 109}\r
110\r
bcd70414 111/**\r
ead42efc 112 Destroy all the pci device node under the bridge.\r
113 Bridge itself is not included.\r
114\r
48a9ea7b 115 @param Bridge A pointer to the PCI_IO_DEVICE.\r
ead42efc 116\r
bcd70414 117**/\r
48a9ea7b 118VOID\r
a3b8e257 119DestroyPciDeviceTree (\r
48a9ea7b 120 IN PCI_IO_DEVICE *Bridge\r
a3b8e257 121 )\r
ead42efc 122{\r
123 LIST_ENTRY *CurrentLink;\r
124 PCI_IO_DEVICE *Temp;\r
125\r
126 while (!IsListEmpty (&Bridge->ChildList)) {\r
127\r
128 CurrentLink = Bridge->ChildList.ForwardLink;\r
129\r
130 //\r
131 // Remove this node from the linked list\r
132 //\r
133 RemoveEntryList (CurrentLink);\r
134\r
135 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
136\r
137 if (!IsListEmpty (&Temp->ChildList)) {\r
138 DestroyPciDeviceTree (Temp);\r
139 }\r
140\r
141 FreePciDevice (Temp);\r
142 }\r
ead42efc 143}\r
144\r
bcd70414 145/**\r
ead42efc 146 Destroy all device nodes under the root bridge\r
147 specified by Controller.\r
48a9ea7b 148\r
ead42efc 149 The root bridge itself is also included.\r
150\r
48a9ea7b 151 @param Controller Root bridge handle.\r
152\r
153 @retval EFI_SUCCESS Destory all devcie nodes successfully.\r
154 @retval EFI_NOT_FOUND Cannot find any PCI device under specified\r
155 root bridge.\r
ead42efc 156\r
bcd70414 157**/\r
a3b8e257 158EFI_STATUS\r
159DestroyRootBridgeByHandle (\r
48a9ea7b 160 IN EFI_HANDLE Controller\r
a3b8e257 161 )\r
ead42efc 162{\r
163\r
164 LIST_ENTRY *CurrentLink;\r
165 PCI_IO_DEVICE *Temp;\r
166\r
48a9ea7b 167 CurrentLink = mPciDevicePool.ForwardLink;\r
ead42efc 168\r
48a9ea7b 169 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
ead42efc 170 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
171\r
172 if (Temp->Handle == Controller) {\r
173\r
174 RemoveEntryList (CurrentLink);\r
175\r
176 DestroyPciDeviceTree (Temp);\r
177\r
178 FreePciDevice (Temp);\r
179\r
180 return EFI_SUCCESS;\r
181 }\r
182\r
183 CurrentLink = CurrentLink->ForwardLink;\r
184 }\r
185\r
186 return EFI_NOT_FOUND;\r
187}\r
188\r
bcd70414 189/**\r
8e8227d1 190 This function registers the PCI IO device.\r
ead42efc 191\r
8e8227d1 192 It creates a handle for this PCI IO device (if the handle does not exist), attaches\r
193 appropriate protocols onto the handle, does necessary initialization, and sets up\r
48a9ea7b 194 parent/child relationship with its bus controller.\r
ead42efc 195\r
48a9ea7b 196 @param Controller An EFI handle for the PCI bus controller.\r
197 @param PciIoDevice A PCI_IO_DEVICE pointer to the PCI IO device to be registered.\r
198 @param Handle A pointer to hold the returned EFI handle for the PCI IO device.\r
199\r
200 @retval EFI_SUCCESS The PCI device is successfully registered.\r
8e8227d1 201 @retval other An error occurred when registering the PCI device.\r
ead42efc 202\r
bcd70414 203**/\r
a3b8e257 204EFI_STATUS\r
205RegisterPciDevice (\r
48a9ea7b 206 IN EFI_HANDLE Controller,\r
207 IN PCI_IO_DEVICE *PciIoDevice,\r
208 OUT EFI_HANDLE *Handle OPTIONAL\r
a3b8e257 209 )\r
ead42efc 210{\r
211 EFI_STATUS Status;\r
212 VOID *PlatformOpRomBuffer;\r
213 UINTN PlatformOpRomSize;\r
214 UINT8 PciExpressCapRegOffset;\r
215 EFI_PCI_IO_PROTOCOL *PciIo;\r
216 UINT8 Data8;\r
8e6b0dcb 217 BOOLEAN HasEfiImage;\r
ead42efc 218\r
219 //\r
220 // Install the pciio protocol, device path protocol\r
221 //\r
222 Status = gBS->InstallMultipleProtocolInterfaces (\r
223 &PciIoDevice->Handle,\r
224 &gEfiDevicePathProtocolGuid,\r
225 PciIoDevice->DevicePath,\r
226 &gEfiPciIoProtocolGuid,\r
227 &PciIoDevice->PciIo,\r
228 NULL\r
229 );\r
230 if (EFI_ERROR (Status)) {\r
231 return Status;\r
232 }\r
233\r
234 //\r
235 // Detect if PCI Express Device\r
236 //\r
237 PciExpressCapRegOffset = 0;\r
238 Status = LocateCapabilityRegBlock (\r
239 PciIoDevice,\r
240 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
241 &PciExpressCapRegOffset,\r
242 NULL\r
243 );\r
244 if (!EFI_ERROR (Status)) {\r
245 PciIoDevice->IsPciExp = TRUE;\r
246 }\r
8e8227d1 247\r
ead42efc 248 //\r
249 // Force Interrupt line to "Unknown" or "No Connection"\r
250 //\r
251 PciIo = &(PciIoDevice->PciIo);\r
252 Data8 = PCI_INT_LINE_UNKNOWN;\r
9eb130ff 253 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);\r
ead42efc 254\r
255 //\r
eb9a9a5e 256 // Process OpRom\r
ead42efc 257 //\r
eb9a9a5e 258 if (!PciIoDevice->AllOpRomProcessed) {\r
ead42efc 259\r
eb9a9a5e 260 //\r
261 // Get the OpRom provided by platform\r
262 //\r
263 if (gPciPlatformProtocol != NULL) {\r
264 Status = gPciPlatformProtocol->GetPciRom (\r
265 gPciPlatformProtocol,\r
266 PciIoDevice->Handle,\r
267 &PlatformOpRomBuffer,\r
268 &PlatformOpRomSize\r
269 );\r
270 if (!EFI_ERROR (Status)) {\r
271 PciIoDevice->RomSize = PlatformOpRomSize;\r
272 PciIoDevice->PciIo.RomSize = PlatformOpRomSize;\r
273 PciIoDevice->PciIo.RomImage = PlatformOpRomBuffer;\r
274 //\r
275 // For OpROM read from gPciPlatformProtocol:\r
8e6b0dcb 276 // Add the Rom Image to internal database for later PCI light enumeration\r
eb9a9a5e 277 //\r
278 PciRomAddImageMapping (\r
279 NULL,\r
280 PciIoDevice->PciRootBridgeIo->SegmentNumber,\r
281 PciIoDevice->BusNumber,\r
282 PciIoDevice->DeviceNumber,\r
283 PciIoDevice->FunctionNumber,\r
284 (UINT64) (UINTN) PciIoDevice->PciIo.RomImage,\r
285 PciIoDevice->PciIo.RomSize\r
286 );\r
eb9a9a5e 287 }\r
288 }\r
8e6b0dcb 289 }\r
290\r
291 //\r
292 // Determine if there are EFI images in the option rom\r
293 //\r
294 HasEfiImage = ContainEfiImage (PciIoDevice->PciIo.RomImage, PciIoDevice->PciIo.RomSize);\r
295\r
296 if (HasEfiImage) {\r
297 Status = gBS->InstallMultipleProtocolInterfaces (\r
298 &PciIoDevice->Handle,\r
299 &gEfiLoadFile2ProtocolGuid,\r
300 &PciIoDevice->LoadFile2,\r
301 NULL\r
302 );\r
303 if (EFI_ERROR (Status)) {\r
304 gBS->UninstallMultipleProtocolInterfaces (\r
305 &PciIoDevice->Handle,\r
306 &gEfiDevicePathProtocolGuid,\r
307 PciIoDevice->DevicePath,\r
308 &gEfiPciIoProtocolGuid,\r
309 &PciIoDevice->PciIo,\r
310 NULL\r
311 );\r
312 return Status;\r
313 }\r
314 }\r
315\r
316\r
317 if (!PciIoDevice->AllOpRomProcessed) {\r
318\r
319 PciIoDevice->AllOpRomProcessed = TRUE;\r
96d1b172 320\r
eb9a9a5e 321 //\r
322 // Dispatch the EFI OpRom for the PCI device.\r
323 // The OpRom is got from platform in the above code\r
8e6b0dcb 324 // or loaded from device in the previous round of bus enumeration\r
eb9a9a5e 325 //\r
8e6b0dcb 326 if (HasEfiImage) {\r
ead42efc 327 ProcessOpRomImage (PciIoDevice);\r
328 }\r
329 }\r
330\r
331 if (PciIoDevice->BusOverride) {\r
332 //\r
8e8227d1 333 // Install Bus Specific Driver Override Protocol\r
ead42efc 334 //\r
335 Status = gBS->InstallMultipleProtocolInterfaces (\r
336 &PciIoDevice->Handle,\r
337 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
338 &PciIoDevice->PciDriverOverride,\r
339 NULL\r
340 );\r
341 if (EFI_ERROR (Status)) {\r
342 gBS->UninstallMultipleProtocolInterfaces (\r
343 &PciIoDevice->Handle,\r
344 &gEfiDevicePathProtocolGuid,\r
345 PciIoDevice->DevicePath,\r
346 &gEfiPciIoProtocolGuid,\r
347 &PciIoDevice->PciIo,\r
348 NULL\r
349 );\r
8e6b0dcb 350 if (HasEfiImage) {\r
351 gBS->UninstallMultipleProtocolInterfaces (\r
352 &PciIoDevice->Handle,\r
353 &gEfiLoadFile2ProtocolGuid,\r
354 &PciIoDevice->LoadFile2,\r
355 NULL\r
356 );\r
357 }\r
ead42efc 358\r
359 return Status;\r
360 }\r
361 }\r
362\r
363 Status = gBS->OpenProtocol (\r
364 Controller,\r
365 &gEfiPciRootBridgeIoProtocolGuid,\r
366 (VOID **) &(PciIoDevice->PciRootBridgeIo),\r
367 gPciBusDriverBinding.DriverBindingHandle,\r
368 PciIoDevice->Handle,\r
369 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
370 );\r
371 if (EFI_ERROR (Status)) {\r
372 return Status;\r
373 }\r
374\r
ead42efc 375 if (Handle != NULL) {\r
376 *Handle = PciIoDevice->Handle;\r
377 }\r
378\r
379 //\r
380 // Indicate the pci device is registered\r
381 //\r
382 PciIoDevice->Registered = TRUE;\r
383\r
384 return EFI_SUCCESS;\r
385}\r
386\r
a3b8e257 387/**\r
48a9ea7b 388 This function is used to remove the whole PCI devices on the specified bridge from\r
389 the root bridge.\r
a3b8e257 390\r
48a9ea7b 391 @param RootBridgeHandle The root bridge device handle.\r
392 @param Bridge The bridge device to be removed.\r
a3b8e257 393\r
a3b8e257 394**/\r
48a9ea7b 395VOID\r
ead42efc 396RemoveAllPciDeviceOnBridge (\r
397 EFI_HANDLE RootBridgeHandle,\r
398 PCI_IO_DEVICE *Bridge\r
399 )\r
ead42efc 400{\r
ead42efc 401 LIST_ENTRY *CurrentLink;\r
402 PCI_IO_DEVICE *Temp;\r
403\r
404 while (!IsListEmpty (&Bridge->ChildList)) {\r
405\r
406 CurrentLink = Bridge->ChildList.ForwardLink;\r
407 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
408\r
409 //\r
410 // Check if the current node has been deregistered before\r
411 // If it is not, then deregister it\r
412 //\r
413 if (Temp->Registered) {\r
414 DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);\r
415 }\r
416\r
417 //\r
418 // Remove this node from the linked list\r
419 //\r
420 RemoveEntryList (CurrentLink);\r
421\r
422 if (!IsListEmpty (&Temp->ChildList)) {\r
423 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);\r
424 }\r
425\r
426 FreePciDevice (Temp);\r
427 }\r
ead42efc 428}\r
429\r
bcd70414 430/**\r
48a9ea7b 431 This function is used to de-register the PCI IO device.\r
ead42efc 432\r
ead42efc 433 That includes un-installing PciIo protocol from the specified PCI\r
434 device handle.\r
435\r
48a9ea7b 436 @param Controller An EFI handle for the PCI bus controller.\r
437 @param Handle PCI device handle.\r
438\r
439 @retval EFI_SUCCESS The PCI device is successfully de-registered.\r
8e8227d1 440 @retval other An error occurred when de-registering the PCI device.\r
ead42efc 441\r
bcd70414 442**/\r
a3b8e257 443EFI_STATUS\r
444DeRegisterPciDevice (\r
445 IN EFI_HANDLE Controller,\r
446 IN EFI_HANDLE Handle\r
447 )\r
448\r
ead42efc 449{\r
450 EFI_PCI_IO_PROTOCOL *PciIo;\r
451 EFI_STATUS Status;\r
452 PCI_IO_DEVICE *PciIoDevice;\r
453 PCI_IO_DEVICE *Node;\r
454 LIST_ENTRY *CurrentLink;\r
455 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
456\r
457 Status = gBS->OpenProtocol (\r
458 Handle,\r
459 &gEfiPciIoProtocolGuid,\r
460 (VOID **) &PciIo,\r
461 gPciBusDriverBinding.DriverBindingHandle,\r
462 Controller,\r
463 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
464 );\r
465 if (!EFI_ERROR (Status)) {\r
466 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
467\r
468 //\r
469 // If it is already de-registered\r
470 //\r
471 if (!PciIoDevice->Registered) {\r
472 return EFI_SUCCESS;\r
473 }\r
474\r
475 //\r
476 // If it is PPB, first de-register its children\r
477 //\r
478\r
479 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
480\r
481 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
482\r
97404058 483 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
ead42efc 484 Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
485 Status = DeRegisterPciDevice (Controller, Node->Handle);\r
486\r
487 if (EFI_ERROR (Status)) {\r
488 return Status;\r
489 }\r
490\r
491 CurrentLink = CurrentLink->ForwardLink;\r
492 }\r
493 }\r
ead42efc 494\r
495 //\r
496 // Close the child handle\r
497 //\r
498 Status = gBS->CloseProtocol (\r
499 Controller,\r
500 &gEfiPciRootBridgeIoProtocolGuid,\r
501 gPciBusDriverBinding.DriverBindingHandle,\r
502 Handle\r
503 );\r
504\r
505 //\r
8e8227d1 506 // Un-install the Device Path protocol and PCI I/O protocol\r
507 // and Bus Specific Driver Override protocol if needed.\r
ead42efc 508 //\r
509 if (PciIoDevice->BusOverride) {\r
510 Status = gBS->UninstallMultipleProtocolInterfaces (\r
511 Handle,\r
512 &gEfiDevicePathProtocolGuid,\r
513 PciIoDevice->DevicePath,\r
514 &gEfiPciIoProtocolGuid,\r
515 &PciIoDevice->PciIo,\r
516 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
517 &PciIoDevice->PciDriverOverride,\r
518 NULL\r
519 );\r
520 } else {\r
521 Status = gBS->UninstallMultipleProtocolInterfaces (\r
522 Handle,\r
523 &gEfiDevicePathProtocolGuid,\r
524 PciIoDevice->DevicePath,\r
525 &gEfiPciIoProtocolGuid,\r
526 &PciIoDevice->PciIo,\r
527 NULL\r
528 );\r
529 }\r
530\r
8e6b0dcb 531 if (!EFI_ERROR (Status)) {\r
532 //\r
533 // Try to uninstall LoadFile2 protocol if exists\r
534 //\r
535 Status = gBS->OpenProtocol (\r
536 Handle,\r
537 &gEfiLoadFile2ProtocolGuid,\r
538 NULL,\r
539 gPciBusDriverBinding.DriverBindingHandle,\r
540 Controller,\r
541 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
542 );\r
543 if (!EFI_ERROR (Status)) {\r
544 Status = gBS->UninstallMultipleProtocolInterfaces (\r
545 Handle,\r
546 &gEfiLoadFile2ProtocolGuid,\r
547 &PciIoDevice->LoadFile2,\r
548 NULL\r
549 );\r
550 }\r
551 //\r
552 // Restore Status\r
553 //\r
554 Status = EFI_SUCCESS;\r
555 }\r
556\r
557\r
ead42efc 558 if (EFI_ERROR (Status)) {\r
559 gBS->OpenProtocol (\r
560 Controller,\r
561 &gEfiPciRootBridgeIoProtocolGuid,\r
562 (VOID **) &PciRootBridgeIo,\r
563 gPciBusDriverBinding.DriverBindingHandle,\r
564 Handle,\r
565 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
566 );\r
567 return Status;\r
568 }\r
569\r
570 //\r
571 // The Device Driver should disable this device after disconnect\r
572 // so the Pci Bus driver will not touch this device any more.\r
573 // Restore the register field to the original value\r
574 //\r
575 PciIoDevice->Registered = FALSE;\r
576 PciIoDevice->Handle = NULL;\r
577 } else {\r
578\r
579 //\r
580 // Handle may be closed before\r
581 //\r
582 return EFI_SUCCESS;\r
583 }\r
584\r
585 return EFI_SUCCESS;\r
586}\r
587\r
a3b8e257 588/**\r
589 Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge\r
590\r
48a9ea7b 591 @param Controller The root bridge handle.\r
a3b8e257 592 @param RootBridge A pointer to the PCI_IO_DEVICE.\r
593 @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
594 @param NumberOfChildren Children number.\r
595 @param ChildHandleBuffer A pointer to the child handle buffer.\r
596\r
48a9ea7b 597 @retval EFI_NOT_READY Device is not allocated.\r
a3b8e257 598 @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.\r
8e8227d1 599 @retval EFI_NOT_FOUND Can not find the specific device.\r
600 @retval EFI_SUCCESS Success to start Pci device on bridge.\r
a3b8e257 601\r
602**/\r
ead42efc 603EFI_STATUS\r
604StartPciDevicesOnBridge (\r
605 IN EFI_HANDLE Controller,\r
606 IN PCI_IO_DEVICE *RootBridge,\r
607 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
608 IN OUT UINT8 *NumberOfChildren,\r
609 IN OUT EFI_HANDLE *ChildHandleBuffer\r
610 )\r
ead42efc 611\r
ead42efc 612{\r
ead42efc 613 PCI_IO_DEVICE *PciIoDevice;\r
614 EFI_DEV_PATH_PTR Node;\r
615 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
616 EFI_STATUS Status;\r
617 LIST_ENTRY *CurrentLink;\r
618 UINT64 Supports;\r
619\r
620 CurrentLink = RootBridge->ChildList.ForwardLink;\r
621\r
97404058 622 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
ead42efc 623\r
eb9a9a5e 624 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
ead42efc 625 if (RemainingDevicePath != NULL) {\r
626\r
627 Node.DevPath = RemainingDevicePath;\r
628\r
8e8227d1 629 if (Node.Pci->Device != PciIoDevice->DeviceNumber ||\r
eb9a9a5e 630 Node.Pci->Function != PciIoDevice->FunctionNumber) {\r
ead42efc 631 CurrentLink = CurrentLink->ForwardLink;\r
632 continue;\r
633 }\r
634\r
635 //\r
636 // Check if the device has been assigned with required resource\r
637 //\r
eb9a9a5e 638 if (!PciIoDevice->Allocated) {\r
ead42efc 639 return EFI_NOT_READY;\r
640 }\r
8e8227d1 641\r
ead42efc 642 //\r
643 // Check if the current node has been registered before\r
644 // If it is not, register it\r
645 //\r
eb9a9a5e 646 if (!PciIoDevice->Registered) {\r
ead42efc 647 Status = RegisterPciDevice (\r
eb9a9a5e 648 Controller,\r
649 PciIoDevice,\r
650 NULL\r
651 );\r
ead42efc 652\r
653 }\r
654\r
eb9a9a5e 655 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {\r
656 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
ead42efc 657 (*NumberOfChildren)++;\r
658 }\r
8e8227d1 659\r
ead42efc 660 //\r
661 // Get the next device path\r
662 //\r
2067710d 663 CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);\r
664 if (IsDevicePathEnd (CurrentDevicePath)) {\r
ead42efc 665 return EFI_SUCCESS;\r
666 }\r
667\r
668 //\r
669 // If it is a PPB\r
670 //\r
eb9a9a5e 671 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
ead42efc 672 Status = StartPciDevicesOnBridge (\r
eb9a9a5e 673 Controller,\r
674 PciIoDevice,\r
675 CurrentDevicePath,\r
676 NumberOfChildren,\r
677 ChildHandleBuffer\r
678 );\r
679\r
680 PciIoDevice->PciIo.Attributes (\r
681 &(PciIoDevice->PciIo),\r
682 EfiPciIoAttributeOperationSupported,\r
683 0,\r
684 &Supports\r
685 );\r
ead42efc 686 Supports &= EFI_PCI_DEVICE_ENABLE;\r
eb9a9a5e 687 PciIoDevice->PciIo.Attributes (\r
688 &(PciIoDevice->PciIo),\r
689 EfiPciIoAttributeOperationEnable,\r
690 Supports,\r
691 NULL\r
692 );\r
ead42efc 693\r
694 return Status;\r
695 } else {\r
696\r
697 //\r
698 // Currently, the PCI bus driver only support PCI-PCI bridge\r
699 //\r
700 return EFI_UNSUPPORTED;\r
701 }\r
702\r
703 } else {\r
704\r
705 //\r
706 // If remaining device path is NULL,\r
707 // try to enable all the pci devices under this bridge\r
708 //\r
eb9a9a5e 709 if (!PciIoDevice->Registered && PciIoDevice->Allocated) {\r
ead42efc 710 Status = RegisterPciDevice (\r
eb9a9a5e 711 Controller,\r
712 PciIoDevice,\r
713 NULL\r
714 );\r
ead42efc 715\r
716 }\r
717\r
eb9a9a5e 718 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {\r
719 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
ead42efc 720 (*NumberOfChildren)++;\r
721 }\r
722\r
eb9a9a5e 723 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
ead42efc 724 Status = StartPciDevicesOnBridge (\r
eb9a9a5e 725 Controller,\r
726 PciIoDevice,\r
727 RemainingDevicePath,\r
728 NumberOfChildren,\r
729 ChildHandleBuffer\r
730 );\r
731\r
732 PciIoDevice->PciIo.Attributes (\r
733 &(PciIoDevice->PciIo),\r
734 EfiPciIoAttributeOperationSupported,\r
735 0,\r
736 &Supports\r
737 );\r
ead42efc 738 Supports &= EFI_PCI_DEVICE_ENABLE;\r
eb9a9a5e 739 PciIoDevice->PciIo.Attributes (\r
740 &(PciIoDevice->PciIo),\r
741 EfiPciIoAttributeOperationEnable,\r
742 Supports,\r
743 NULL\r
744 );\r
ead42efc 745\r
746 }\r
747\r
748 CurrentLink = CurrentLink->ForwardLink;\r
ead42efc 749 }\r
750 }\r
751\r
752 return EFI_NOT_FOUND;\r
753}\r
754\r
bcd70414 755/**\r
8e8227d1 756 Start to manage all the PCI devices it found previously under\r
eb9a9a5e 757 the entire host bridge.\r
ead42efc 758\r
48a9ea7b 759 @param Controller The root bridge handle.\r
ead42efc 760\r
8e8227d1 761 @retval EFI_NOT_READY Device is not allocated.\r
762 @retval EFI_SUCCESS Success to start Pci device on host bridge.\r
763\r
bcd70414 764**/\r
a3b8e257 765EFI_STATUS\r
766StartPciDevices (\r
767 IN EFI_HANDLE Controller\r
768 )\r
ead42efc 769{\r
8e8227d1 770 EFI_STATUS Status;\r
ead42efc 771 PCI_IO_DEVICE *RootBridge;\r
eb9a9a5e 772 EFI_HANDLE ThisHostBridge;\r
ead42efc 773 LIST_ENTRY *CurrentLink;\r
774\r
eb9a9a5e 775 RootBridge = GetRootBridgeByHandle (Controller);\r
776 ASSERT (RootBridge != NULL);\r
777 ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;\r
ead42efc 778\r
48a9ea7b 779 CurrentLink = mPciDevicePool.ForwardLink;\r
ead42efc 780\r
48a9ea7b 781 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
ead42efc 782\r
783 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
784 //\r
785 // Locate the right root bridge to start\r
786 //\r
eb9a9a5e 787 if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {\r
8e8227d1 788 Status = StartPciDevicesOnBridge (\r
789 RootBridge->Handle,\r
790 RootBridge,\r
791 NULL,\r
792 NULL,\r
793 NULL\r
794 );\r
795 if (EFI_ERROR (Status)) {\r
796 return Status;\r
797 }\r
ead42efc 798 }\r
799\r
800 CurrentLink = CurrentLink->ForwardLink;\r
801 }\r
802\r
803 return EFI_SUCCESS;\r
804}\r
805\r
bcd70414 806/**\r
48a9ea7b 807 Create root bridge device.\r
ead42efc 808\r
48a9ea7b 809 @param RootBridgeHandle Specified root bridge hanle.\r
810\r
811 @return The crated root bridge device instance, NULL means no\r
812 root bridge device instance created.\r
ead42efc 813\r
bcd70414 814**/\r
a3b8e257 815PCI_IO_DEVICE *\r
816CreateRootBridge (\r
48a9ea7b 817 IN EFI_HANDLE RootBridgeHandle\r
a3b8e257 818 )\r
ead42efc 819{\r
ead42efc 820 EFI_STATUS Status;\r
821 PCI_IO_DEVICE *Dev;\r
822 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
823 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
824\r
48a9ea7b 825 Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
826 if (Dev == NULL) {\r
ead42efc 827 return NULL;\r
828 }\r
829\r
ead42efc 830 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;\r
831 Dev->Handle = RootBridgeHandle;\r
832 InitializeListHead (&Dev->ChildList);\r
833\r
834 Status = gBS->OpenProtocol (\r
835 RootBridgeHandle,\r
836 &gEfiDevicePathProtocolGuid,\r
837 (VOID **) &ParentDevicePath,\r
838 gPciBusDriverBinding.DriverBindingHandle,\r
839 RootBridgeHandle,\r
840 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
841 );\r
842\r
843 if (EFI_ERROR (Status)) {\r
48a9ea7b 844 FreePool (Dev);\r
ead42efc 845 return NULL;\r
846 }\r
847\r
848 //\r
849 // Record the root bridge parent device path\r
850 //\r
851 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);\r
852\r
853 //\r
854 // Get the pci root bridge io protocol\r
855 //\r
856 Status = gBS->OpenProtocol (\r
857 RootBridgeHandle,\r
858 &gEfiPciRootBridgeIoProtocolGuid,\r
859 (VOID **) &PciRootBridgeIo,\r
860 gPciBusDriverBinding.DriverBindingHandle,\r
861 RootBridgeHandle,\r
862 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
863 );\r
864\r
865 if (EFI_ERROR (Status)) {\r
866 FreePciDevice (Dev);\r
867 return NULL;\r
868 }\r
869\r
870 Dev->PciRootBridgeIo = PciRootBridgeIo;\r
871\r
872 //\r
873 // Initialize the PCI I/O instance structure\r
874 //\r
8e6b0dcb 875 InitializePciIoInstance (Dev);\r
876 InitializePciDriverOverrideInstance (Dev);\r
877 InitializePciLoadFile2 (Dev);\r
ead42efc 878\r
879 //\r
880 // Initialize reserved resource list and\r
881 // option rom driver list\r
882 //\r
883 InitializeListHead (&Dev->ReservedResourceList);\r
884 InitializeListHead (&Dev->OptionRomDriverList);\r
885\r
886 return Dev;\r
887}\r
888\r
bcd70414 889/**\r
48a9ea7b 890 Get root bridge device instance by specific root bridge handle.\r
ead42efc 891\r
97404058 892 @param RootBridgeHandle Given root bridge handle.\r
ead42efc 893\r
48a9ea7b 894 @return The root bridge device instance, NULL means no root bridge\r
895 device instance found.\r
896\r
bcd70414 897**/\r
a3b8e257 898PCI_IO_DEVICE *\r
899GetRootBridgeByHandle (\r
900 EFI_HANDLE RootBridgeHandle\r
901 )\r
ead42efc 902{\r
903 PCI_IO_DEVICE *RootBridgeDev;\r
904 LIST_ENTRY *CurrentLink;\r
905\r
48a9ea7b 906 CurrentLink = mPciDevicePool.ForwardLink;\r
ead42efc 907\r
48a9ea7b 908 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
ead42efc 909\r
910 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
911 if (RootBridgeDev->Handle == RootBridgeHandle) {\r
912 return RootBridgeDev;\r
913 }\r
914\r
915 CurrentLink = CurrentLink->ForwardLink;\r
916 }\r
917\r
918 return NULL;\r
919}\r
920\r
a3b8e257 921/**\r
97404058 922 Judege whether Pci device existed.\r
8e8227d1 923\r
97404058 924 @param Bridge Parent bridege instance.\r
925 @param PciIoDevice Device instance.\r
8e8227d1 926\r
48a9ea7b 927 @retval TRUE Pci device existed.\r
928 @retval FALSE Pci device did not exist.\r
929\r
a3b8e257 930**/\r
ead42efc 931BOOLEAN\r
932PciDeviceExisted (\r
933 IN PCI_IO_DEVICE *Bridge,\r
934 IN PCI_IO_DEVICE *PciIoDevice\r
935 )\r
ead42efc 936{\r
937\r
938 PCI_IO_DEVICE *Temp;\r
939 LIST_ENTRY *CurrentLink;\r
940\r
941 CurrentLink = Bridge->ChildList.ForwardLink;\r
942\r
97404058 943 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
ead42efc 944\r
945 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
946\r
947 if (Temp == PciIoDevice) {\r
948 return TRUE;\r
949 }\r
950\r
951 if (!IsListEmpty (&Temp->ChildList)) {\r
952 if (PciDeviceExisted (Temp, PciIoDevice)) {\r
953 return TRUE;\r
954 }\r
955 }\r
956\r
957 CurrentLink = CurrentLink->ForwardLink;\r
958 }\r
959\r
960 return FALSE;\r
961}\r
962\r
a3b8e257 963/**\r
48a9ea7b 964 Get the active VGA device on the same segment.\r
8e8227d1 965\r
48a9ea7b 966 @param VgaDevice PCI IO instance for the VGA device.\r
8e8227d1 967\r
48a9ea7b 968 @return The active VGA device on the same segment.\r
969\r
a3b8e257 970**/\r
ead42efc 971PCI_IO_DEVICE *\r
972ActiveVGADeviceOnTheSameSegment (\r
973 IN PCI_IO_DEVICE *VgaDevice\r
974 )\r
ead42efc 975{\r
976 LIST_ENTRY *CurrentLink;\r
977 PCI_IO_DEVICE *Temp;\r
978\r
48a9ea7b 979 CurrentLink = mPciDevicePool.ForwardLink;\r
ead42efc 980\r
48a9ea7b 981 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
ead42efc 982\r
983 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
984\r
985 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {\r
986\r
987 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
988\r
989 if (Temp != NULL) {\r
990 return Temp;\r
991 }\r
992 }\r
993\r
994 CurrentLink = CurrentLink->ForwardLink;\r
995 }\r
996\r
997 return NULL;\r
998}\r
999\r
a3b8e257 1000/**\r
48a9ea7b 1001 Get the active VGA device on the root bridge.\r
8e8227d1 1002\r
48a9ea7b 1003 @param RootBridge PCI IO instance for the root bridge.\r
8e8227d1 1004\r
48a9ea7b 1005 @return The active VGA device.\r
1006\r
a3b8e257 1007**/\r
ead42efc 1008PCI_IO_DEVICE *\r
1009ActiveVGADeviceOnTheRootBridge (\r
1010 IN PCI_IO_DEVICE *RootBridge\r
1011 )\r
ead42efc 1012{\r
1013 LIST_ENTRY *CurrentLink;\r
1014 PCI_IO_DEVICE *Temp;\r
1015\r
1016 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1017\r
97404058 1018 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
ead42efc 1019\r
1020 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1021\r
1022 if (IS_PCI_VGA(&Temp->Pci) &&\r
1023 (Temp->Attributes &\r
1024 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |\r
1025 EFI_PCI_IO_ATTRIBUTE_VGA_IO |\r
97404058 1026 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {\r
ead42efc 1027 return Temp;\r
1028 }\r
1029\r
1030 if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
1031\r
1032 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1033\r
1034 if (Temp != NULL) {\r
1035 return Temp;\r
1036 }\r
1037 }\r
1038\r
1039 CurrentLink = CurrentLink->ForwardLink;\r
1040 }\r
1041\r
1042 return NULL;\r
1043}\r
1044\r
ead42efc 1045\r
a3b8e257 1046/**\r
97404058 1047 Get HPC PCI address according to its device path.\r
48a9ea7b 1048\r
97404058 1049 @param RootBridge Root bridege Io instance.\r
1050 @param RemainingDevicePath Given searching device path.\r
1051 @param PciAddress Buffer holding searched result.\r
8e8227d1 1052\r
48a9ea7b 1053 @retval EFI_SUCCESS PCI address was stored in PciAddress\r
1054 @retval EFI_NOT_FOUND Can not find the specific device path.\r
8e8227d1 1055\r
a3b8e257 1056**/\r
ead42efc 1057EFI_STATUS\r
1058GetHpcPciAddressFromRootBridge (\r
1059 IN PCI_IO_DEVICE *RootBridge,\r
1060 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
1061 OUT UINT64 *PciAddress\r
1062 )\r
ead42efc 1063{\r
1064 EFI_DEV_PATH_PTR Node;\r
1065 PCI_IO_DEVICE *Temp;\r
1066 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
1067 LIST_ENTRY *CurrentLink;\r
1068 BOOLEAN MisMatch;\r
1069\r
1070 MisMatch = FALSE;\r
1071\r
1072 CurrentDevicePath = RemainingDevicePath;\r
1073 Node.DevPath = CurrentDevicePath;\r
1074 Temp = NULL;\r
1075\r
2067710d 1076 while (!IsDevicePathEnd (CurrentDevicePath)) {\r
ead42efc 1077\r
1078 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1079 Node.DevPath = CurrentDevicePath;\r
1080\r
97404058 1081 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
ead42efc 1082 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1083\r
1084 if (Node.Pci->Device == Temp->DeviceNumber &&\r
1085 Node.Pci->Function == Temp->FunctionNumber) {\r
1086 RootBridge = Temp;\r
1087 break;\r
1088 }\r
1089\r
1090 CurrentLink = CurrentLink->ForwardLink;\r
1091 }\r
1092\r
1093 //\r
1094 // Check if we find the bridge\r
1095 //\r
1096 if (CurrentLink == &RootBridge->ChildList) {\r
1097\r
1098 MisMatch = TRUE;\r
1099 break;\r
1100\r
1101 }\r
1102\r
2067710d 1103 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
ead42efc 1104 }\r
1105\r
1106 if (MisMatch) {\r
1107\r
2067710d 1108 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
ead42efc 1109\r
2067710d 1110 if (IsDevicePathEnd (CurrentDevicePath)) {\r
ead42efc 1111 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);\r
1112 return EFI_SUCCESS;\r
1113 }\r
1114\r
1115 return EFI_NOT_FOUND;\r
1116 }\r
1117\r
aa950314 1118 if (Temp != NULL) {\r
1119 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1120 } else {\r
1121 return EFI_NOT_FOUND;\r
1122 }\r
ead42efc 1123\r
1124 return EFI_SUCCESS;\r
1125\r
1126}\r
a3b8e257 1127\r