]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
rollback for fix scsi disk detection issue.
[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
ead42efc 770 PCI_IO_DEVICE *RootBridge;\r
eb9a9a5e 771 EFI_HANDLE ThisHostBridge;\r
ead42efc 772 LIST_ENTRY *CurrentLink;\r
773\r
eb9a9a5e 774 RootBridge = GetRootBridgeByHandle (Controller);\r
775 ASSERT (RootBridge != NULL);\r
776 ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;\r
ead42efc 777\r
48a9ea7b 778 CurrentLink = mPciDevicePool.ForwardLink;\r
ead42efc 779\r
48a9ea7b 780 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
ead42efc 781\r
782 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
783 //\r
784 // Locate the right root bridge to start\r
785 //\r
eb9a9a5e 786 if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {\r
f3f33e1d 787 StartPciDevicesOnBridge (\r
788 RootBridge->Handle,\r
789 RootBridge,\r
790 NULL,\r
791 NULL,\r
792 NULL\r
793 );\r
ead42efc 794 }\r
795\r
796 CurrentLink = CurrentLink->ForwardLink;\r
797 }\r
798\r
799 return EFI_SUCCESS;\r
800}\r
801\r
bcd70414 802/**\r
48a9ea7b 803 Create root bridge device.\r
ead42efc 804\r
48a9ea7b 805 @param RootBridgeHandle Specified root bridge hanle.\r
806\r
807 @return The crated root bridge device instance, NULL means no\r
808 root bridge device instance created.\r
ead42efc 809\r
bcd70414 810**/\r
a3b8e257 811PCI_IO_DEVICE *\r
812CreateRootBridge (\r
48a9ea7b 813 IN EFI_HANDLE RootBridgeHandle\r
a3b8e257 814 )\r
ead42efc 815{\r
ead42efc 816 EFI_STATUS Status;\r
817 PCI_IO_DEVICE *Dev;\r
818 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
819 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
820\r
48a9ea7b 821 Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
822 if (Dev == NULL) {\r
ead42efc 823 return NULL;\r
824 }\r
825\r
ead42efc 826 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;\r
827 Dev->Handle = RootBridgeHandle;\r
828 InitializeListHead (&Dev->ChildList);\r
829\r
830 Status = gBS->OpenProtocol (\r
831 RootBridgeHandle,\r
832 &gEfiDevicePathProtocolGuid,\r
833 (VOID **) &ParentDevicePath,\r
834 gPciBusDriverBinding.DriverBindingHandle,\r
835 RootBridgeHandle,\r
836 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
837 );\r
838\r
839 if (EFI_ERROR (Status)) {\r
48a9ea7b 840 FreePool (Dev);\r
ead42efc 841 return NULL;\r
842 }\r
843\r
844 //\r
845 // Record the root bridge parent device path\r
846 //\r
847 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);\r
848\r
849 //\r
850 // Get the pci root bridge io protocol\r
851 //\r
852 Status = gBS->OpenProtocol (\r
853 RootBridgeHandle,\r
854 &gEfiPciRootBridgeIoProtocolGuid,\r
855 (VOID **) &PciRootBridgeIo,\r
856 gPciBusDriverBinding.DriverBindingHandle,\r
857 RootBridgeHandle,\r
858 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
859 );\r
860\r
861 if (EFI_ERROR (Status)) {\r
862 FreePciDevice (Dev);\r
863 return NULL;\r
864 }\r
865\r
866 Dev->PciRootBridgeIo = PciRootBridgeIo;\r
867\r
868 //\r
869 // Initialize the PCI I/O instance structure\r
870 //\r
8e6b0dcb 871 InitializePciIoInstance (Dev);\r
872 InitializePciDriverOverrideInstance (Dev);\r
873 InitializePciLoadFile2 (Dev);\r
ead42efc 874\r
875 //\r
876 // Initialize reserved resource list and\r
877 // option rom driver list\r
878 //\r
879 InitializeListHead (&Dev->ReservedResourceList);\r
880 InitializeListHead (&Dev->OptionRomDriverList);\r
881\r
882 return Dev;\r
883}\r
884\r
bcd70414 885/**\r
48a9ea7b 886 Get root bridge device instance by specific root bridge handle.\r
ead42efc 887\r
97404058 888 @param RootBridgeHandle Given root bridge handle.\r
ead42efc 889\r
48a9ea7b 890 @return The root bridge device instance, NULL means no root bridge\r
891 device instance found.\r
892\r
bcd70414 893**/\r
a3b8e257 894PCI_IO_DEVICE *\r
895GetRootBridgeByHandle (\r
896 EFI_HANDLE RootBridgeHandle\r
897 )\r
ead42efc 898{\r
899 PCI_IO_DEVICE *RootBridgeDev;\r
900 LIST_ENTRY *CurrentLink;\r
901\r
48a9ea7b 902 CurrentLink = mPciDevicePool.ForwardLink;\r
ead42efc 903\r
48a9ea7b 904 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
ead42efc 905\r
906 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
907 if (RootBridgeDev->Handle == RootBridgeHandle) {\r
908 return RootBridgeDev;\r
909 }\r
910\r
911 CurrentLink = CurrentLink->ForwardLink;\r
912 }\r
913\r
914 return NULL;\r
915}\r
916\r
a3b8e257 917/**\r
97404058 918 Judege whether Pci device existed.\r
8e8227d1 919\r
97404058 920 @param Bridge Parent bridege instance.\r
921 @param PciIoDevice Device instance.\r
8e8227d1 922\r
48a9ea7b 923 @retval TRUE Pci device existed.\r
924 @retval FALSE Pci device did not exist.\r
925\r
a3b8e257 926**/\r
ead42efc 927BOOLEAN\r
928PciDeviceExisted (\r
929 IN PCI_IO_DEVICE *Bridge,\r
930 IN PCI_IO_DEVICE *PciIoDevice\r
931 )\r
ead42efc 932{\r
933\r
934 PCI_IO_DEVICE *Temp;\r
935 LIST_ENTRY *CurrentLink;\r
936\r
937 CurrentLink = Bridge->ChildList.ForwardLink;\r
938\r
97404058 939 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
ead42efc 940\r
941 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
942\r
943 if (Temp == PciIoDevice) {\r
944 return TRUE;\r
945 }\r
946\r
947 if (!IsListEmpty (&Temp->ChildList)) {\r
948 if (PciDeviceExisted (Temp, PciIoDevice)) {\r
949 return TRUE;\r
950 }\r
951 }\r
952\r
953 CurrentLink = CurrentLink->ForwardLink;\r
954 }\r
955\r
956 return FALSE;\r
957}\r
958\r
a3b8e257 959/**\r
48a9ea7b 960 Get the active VGA device on the same segment.\r
8e8227d1 961\r
48a9ea7b 962 @param VgaDevice PCI IO instance for the VGA device.\r
8e8227d1 963\r
48a9ea7b 964 @return The active VGA device on the same segment.\r
965\r
a3b8e257 966**/\r
ead42efc 967PCI_IO_DEVICE *\r
968ActiveVGADeviceOnTheSameSegment (\r
969 IN PCI_IO_DEVICE *VgaDevice\r
970 )\r
ead42efc 971{\r
972 LIST_ENTRY *CurrentLink;\r
973 PCI_IO_DEVICE *Temp;\r
974\r
48a9ea7b 975 CurrentLink = mPciDevicePool.ForwardLink;\r
ead42efc 976\r
48a9ea7b 977 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
ead42efc 978\r
979 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
980\r
981 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {\r
982\r
983 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
984\r
985 if (Temp != NULL) {\r
986 return Temp;\r
987 }\r
988 }\r
989\r
990 CurrentLink = CurrentLink->ForwardLink;\r
991 }\r
992\r
993 return NULL;\r
994}\r
995\r
a3b8e257 996/**\r
48a9ea7b 997 Get the active VGA device on the root bridge.\r
8e8227d1 998\r
48a9ea7b 999 @param RootBridge PCI IO instance for the root bridge.\r
8e8227d1 1000\r
48a9ea7b 1001 @return The active VGA device.\r
1002\r
a3b8e257 1003**/\r
ead42efc 1004PCI_IO_DEVICE *\r
1005ActiveVGADeviceOnTheRootBridge (\r
1006 IN PCI_IO_DEVICE *RootBridge\r
1007 )\r
ead42efc 1008{\r
1009 LIST_ENTRY *CurrentLink;\r
1010 PCI_IO_DEVICE *Temp;\r
1011\r
1012 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1013\r
97404058 1014 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
ead42efc 1015\r
1016 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1017\r
1018 if (IS_PCI_VGA(&Temp->Pci) &&\r
1019 (Temp->Attributes &\r
1020 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |\r
1021 EFI_PCI_IO_ATTRIBUTE_VGA_IO |\r
97404058 1022 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {\r
ead42efc 1023 return Temp;\r
1024 }\r
1025\r
1026 if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
1027\r
1028 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1029\r
1030 if (Temp != NULL) {\r
1031 return Temp;\r
1032 }\r
1033 }\r
1034\r
1035 CurrentLink = CurrentLink->ForwardLink;\r
1036 }\r
1037\r
1038 return NULL;\r
1039}\r
1040\r
ead42efc 1041\r
a3b8e257 1042/**\r
97404058 1043 Get HPC PCI address according to its device path.\r
48a9ea7b 1044\r
97404058 1045 @param RootBridge Root bridege Io instance.\r
1046 @param RemainingDevicePath Given searching device path.\r
1047 @param PciAddress Buffer holding searched result.\r
8e8227d1 1048\r
48a9ea7b 1049 @retval EFI_SUCCESS PCI address was stored in PciAddress\r
1050 @retval EFI_NOT_FOUND Can not find the specific device path.\r
8e8227d1 1051\r
a3b8e257 1052**/\r
ead42efc 1053EFI_STATUS\r
1054GetHpcPciAddressFromRootBridge (\r
1055 IN PCI_IO_DEVICE *RootBridge,\r
1056 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
1057 OUT UINT64 *PciAddress\r
1058 )\r
ead42efc 1059{\r
1060 EFI_DEV_PATH_PTR Node;\r
1061 PCI_IO_DEVICE *Temp;\r
1062 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
1063 LIST_ENTRY *CurrentLink;\r
1064 BOOLEAN MisMatch;\r
1065\r
1066 MisMatch = FALSE;\r
1067\r
1068 CurrentDevicePath = RemainingDevicePath;\r
1069 Node.DevPath = CurrentDevicePath;\r
1070 Temp = NULL;\r
1071\r
2067710d 1072 while (!IsDevicePathEnd (CurrentDevicePath)) {\r
ead42efc 1073\r
1074 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1075 Node.DevPath = CurrentDevicePath;\r
1076\r
97404058 1077 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
ead42efc 1078 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1079\r
1080 if (Node.Pci->Device == Temp->DeviceNumber &&\r
1081 Node.Pci->Function == Temp->FunctionNumber) {\r
1082 RootBridge = Temp;\r
1083 break;\r
1084 }\r
1085\r
1086 CurrentLink = CurrentLink->ForwardLink;\r
1087 }\r
1088\r
1089 //\r
1090 // Check if we find the bridge\r
1091 //\r
1092 if (CurrentLink == &RootBridge->ChildList) {\r
1093\r
1094 MisMatch = TRUE;\r
1095 break;\r
1096\r
1097 }\r
1098\r
2067710d 1099 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
ead42efc 1100 }\r
1101\r
1102 if (MisMatch) {\r
1103\r
2067710d 1104 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
ead42efc 1105\r
2067710d 1106 if (IsDevicePathEnd (CurrentDevicePath)) {\r
ead42efc 1107 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);\r
1108 return EFI_SUCCESS;\r
1109 }\r
1110\r
1111 return EFI_NOT_FOUND;\r
1112 }\r
1113\r
aa950314 1114 if (Temp != NULL) {\r
1115 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1116 } else {\r
1117 return EFI_NOT_FOUND;\r
1118 }\r
ead42efc 1119\r
1120 return EFI_SUCCESS;\r
1121\r
1122}\r
a3b8e257 1123\r