]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
update the comments on Event
[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
8e6b0dcb 4Copyright (c) 2006 - 2009, Intel Corporation \r
3db51098 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
69 \r
48a9ea7b 70 @param RootBridge The bridge want to be removed.\r
a3b8e257 71 \r
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
48a9ea7b 190 This function registers the PCI IO device. \r
ead42efc 191\r
48a9ea7b 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
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
201 @retval Others 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
247 \r
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
253 PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);\r
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
333 // Install BusSpecificDriverOverride Protocol\r
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
440 @retval Others 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
506 // Un-install the device path protocol and pci io protocol\r
507 //\r
508 if (PciIoDevice->BusOverride) {\r
509 Status = gBS->UninstallMultipleProtocolInterfaces (\r
510 Handle,\r
511 &gEfiDevicePathProtocolGuid,\r
512 PciIoDevice->DevicePath,\r
513 &gEfiPciIoProtocolGuid,\r
514 &PciIoDevice->PciIo,\r
515 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
516 &PciIoDevice->PciDriverOverride,\r
517 NULL\r
518 );\r
519 } else {\r
520 Status = gBS->UninstallMultipleProtocolInterfaces (\r
521 Handle,\r
522 &gEfiDevicePathProtocolGuid,\r
523 PciIoDevice->DevicePath,\r
524 &gEfiPciIoProtocolGuid,\r
525 &PciIoDevice->PciIo,\r
526 NULL\r
527 );\r
528 }\r
529\r
8e6b0dcb 530 if (!EFI_ERROR (Status)) {\r
531 //\r
532 // Try to uninstall LoadFile2 protocol if exists\r
533 //\r
534 Status = gBS->OpenProtocol (\r
535 Handle,\r
536 &gEfiLoadFile2ProtocolGuid,\r
537 NULL,\r
538 gPciBusDriverBinding.DriverBindingHandle,\r
539 Controller,\r
540 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
541 );\r
542 if (!EFI_ERROR (Status)) {\r
543 Status = gBS->UninstallMultipleProtocolInterfaces (\r
544 Handle,\r
545 &gEfiLoadFile2ProtocolGuid,\r
546 &PciIoDevice->LoadFile2,\r
547 NULL\r
548 );\r
549 }\r
550 //\r
551 // Restore Status\r
552 //\r
553 Status = EFI_SUCCESS;\r
554 }\r
555\r
556\r
ead42efc 557 if (EFI_ERROR (Status)) {\r
558 gBS->OpenProtocol (\r
559 Controller,\r
560 &gEfiPciRootBridgeIoProtocolGuid,\r
561 (VOID **) &PciRootBridgeIo,\r
562 gPciBusDriverBinding.DriverBindingHandle,\r
563 Handle,\r
564 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
565 );\r
566 return Status;\r
567 }\r
568\r
569 //\r
570 // The Device Driver should disable this device after disconnect\r
571 // so the Pci Bus driver will not touch this device any more.\r
572 // Restore the register field to the original value\r
573 //\r
574 PciIoDevice->Registered = FALSE;\r
575 PciIoDevice->Handle = NULL;\r
576 } else {\r
577\r
578 //\r
579 // Handle may be closed before\r
580 //\r
581 return EFI_SUCCESS;\r
582 }\r
583\r
584 return EFI_SUCCESS;\r
585}\r
586\r
a3b8e257 587/**\r
588 Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge\r
589\r
48a9ea7b 590 @param Controller The root bridge handle.\r
a3b8e257 591 @param RootBridge A pointer to the PCI_IO_DEVICE.\r
592 @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
593 @param NumberOfChildren Children number.\r
594 @param ChildHandleBuffer A pointer to the child handle buffer.\r
595\r
48a9ea7b 596 @retval EFI_NOT_READY Device is not allocated.\r
a3b8e257 597 @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.\r
598 @retval EFI_NOT_FOUND Can not find the specific device\r
599 @retval EFI_SUCCESS Success to start Pci device on bridge\r
600\r
601**/\r
ead42efc 602EFI_STATUS\r
603StartPciDevicesOnBridge (\r
604 IN EFI_HANDLE Controller,\r
605 IN PCI_IO_DEVICE *RootBridge,\r
606 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
607 IN OUT UINT8 *NumberOfChildren,\r
608 IN OUT EFI_HANDLE *ChildHandleBuffer\r
609 )\r
ead42efc 610\r
ead42efc 611{\r
ead42efc 612 PCI_IO_DEVICE *PciIoDevice;\r
613 EFI_DEV_PATH_PTR Node;\r
614 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
615 EFI_STATUS Status;\r
616 LIST_ENTRY *CurrentLink;\r
617 UINT64 Supports;\r
618\r
619 CurrentLink = RootBridge->ChildList.ForwardLink;\r
620\r
97404058 621 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
ead42efc 622\r
eb9a9a5e 623 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
ead42efc 624 if (RemainingDevicePath != NULL) {\r
625\r
626 Node.DevPath = RemainingDevicePath;\r
627\r
eb9a9a5e 628 if (Node.Pci->Device != PciIoDevice->DeviceNumber || \r
629 Node.Pci->Function != PciIoDevice->FunctionNumber) {\r
ead42efc 630 CurrentLink = CurrentLink->ForwardLink;\r
631 continue;\r
632 }\r
633\r
634 //\r
635 // Check if the device has been assigned with required resource\r
636 //\r
eb9a9a5e 637 if (!PciIoDevice->Allocated) {\r
ead42efc 638 return EFI_NOT_READY;\r
639 }\r
eb9a9a5e 640 \r
ead42efc 641 //\r
642 // Check if the current node has been registered before\r
643 // If it is not, register it\r
644 //\r
eb9a9a5e 645 if (!PciIoDevice->Registered) {\r
ead42efc 646 Status = RegisterPciDevice (\r
eb9a9a5e 647 Controller,\r
648 PciIoDevice,\r
649 NULL\r
650 );\r
ead42efc 651\r
652 }\r
653\r
eb9a9a5e 654 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {\r
655 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
ead42efc 656 (*NumberOfChildren)++;\r
657 }\r
eb9a9a5e 658 \r
ead42efc 659 //\r
660 // Get the next device path\r
661 //\r
2067710d 662 CurrentDevicePath = NextDevicePathNode (RemainingDevicePath);\r
663 if (IsDevicePathEnd (CurrentDevicePath)) {\r
ead42efc 664 return EFI_SUCCESS;\r
665 }\r
666\r
667 //\r
668 // If it is a PPB\r
669 //\r
eb9a9a5e 670 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
ead42efc 671 Status = StartPciDevicesOnBridge (\r
eb9a9a5e 672 Controller,\r
673 PciIoDevice,\r
674 CurrentDevicePath,\r
675 NumberOfChildren,\r
676 ChildHandleBuffer\r
677 );\r
678\r
679 PciIoDevice->PciIo.Attributes (\r
680 &(PciIoDevice->PciIo),\r
681 EfiPciIoAttributeOperationSupported,\r
682 0,\r
683 &Supports\r
684 );\r
ead42efc 685 Supports &= EFI_PCI_DEVICE_ENABLE;\r
eb9a9a5e 686 PciIoDevice->PciIo.Attributes (\r
687 &(PciIoDevice->PciIo),\r
688 EfiPciIoAttributeOperationEnable,\r
689 Supports,\r
690 NULL\r
691 );\r
ead42efc 692\r
693 return Status;\r
694 } else {\r
695\r
696 //\r
697 // Currently, the PCI bus driver only support PCI-PCI bridge\r
698 //\r
699 return EFI_UNSUPPORTED;\r
700 }\r
701\r
702 } else {\r
703\r
704 //\r
705 // If remaining device path is NULL,\r
706 // try to enable all the pci devices under this bridge\r
707 //\r
eb9a9a5e 708 if (!PciIoDevice->Registered && PciIoDevice->Allocated) {\r
ead42efc 709 Status = RegisterPciDevice (\r
eb9a9a5e 710 Controller,\r
711 PciIoDevice,\r
712 NULL\r
713 );\r
ead42efc 714\r
715 }\r
716\r
eb9a9a5e 717 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {\r
718 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
ead42efc 719 (*NumberOfChildren)++;\r
720 }\r
721\r
eb9a9a5e 722 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
ead42efc 723 Status = StartPciDevicesOnBridge (\r
eb9a9a5e 724 Controller,\r
725 PciIoDevice,\r
726 RemainingDevicePath,\r
727 NumberOfChildren,\r
728 ChildHandleBuffer\r
729 );\r
730\r
731 PciIoDevice->PciIo.Attributes (\r
732 &(PciIoDevice->PciIo),\r
733 EfiPciIoAttributeOperationSupported,\r
734 0,\r
735 &Supports\r
736 );\r
ead42efc 737 Supports &= EFI_PCI_DEVICE_ENABLE;\r
eb9a9a5e 738 PciIoDevice->PciIo.Attributes (\r
739 &(PciIoDevice->PciIo),\r
740 EfiPciIoAttributeOperationEnable,\r
741 Supports,\r
742 NULL\r
743 );\r
ead42efc 744\r
745 }\r
746\r
747 CurrentLink = CurrentLink->ForwardLink;\r
ead42efc 748 }\r
749 }\r
750\r
751 return EFI_NOT_FOUND;\r
752}\r
753\r
bcd70414 754/**\r
eb9a9a5e 755 Start to manage all the PCI devices it found previously under \r
756 the entire host bridge.\r
ead42efc 757\r
48a9ea7b 758 @param Controller The root bridge handle.\r
ead42efc 759\r
bcd70414 760**/\r
a3b8e257 761EFI_STATUS\r
762StartPciDevices (\r
763 IN EFI_HANDLE Controller\r
764 )\r
765\r
ead42efc 766{\r
ead42efc 767 PCI_IO_DEVICE *RootBridge;\r
eb9a9a5e 768 EFI_HANDLE ThisHostBridge;\r
ead42efc 769 LIST_ENTRY *CurrentLink;\r
770\r
eb9a9a5e 771 RootBridge = GetRootBridgeByHandle (Controller);\r
772 ASSERT (RootBridge != NULL);\r
773 ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;\r
ead42efc 774\r
48a9ea7b 775 CurrentLink = mPciDevicePool.ForwardLink;\r
ead42efc 776\r
48a9ea7b 777 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
ead42efc 778\r
779 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
780 //\r
781 // Locate the right root bridge to start\r
782 //\r
eb9a9a5e 783 if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {\r
ead42efc 784 StartPciDevicesOnBridge (\r
eb9a9a5e 785 RootBridge->Handle,\r
ead42efc 786 RootBridge,\r
eb9a9a5e 787 NULL,\r
ead42efc 788 NULL,\r
789 NULL\r
790 );\r
791 }\r
792\r
793 CurrentLink = CurrentLink->ForwardLink;\r
794 }\r
795\r
796 return EFI_SUCCESS;\r
797}\r
798\r
bcd70414 799/**\r
48a9ea7b 800 Create root bridge device.\r
ead42efc 801\r
48a9ea7b 802 @param RootBridgeHandle Specified root bridge hanle.\r
803\r
804 @return The crated root bridge device instance, NULL means no\r
805 root bridge device instance created.\r
ead42efc 806\r
bcd70414 807**/\r
a3b8e257 808PCI_IO_DEVICE *\r
809CreateRootBridge (\r
48a9ea7b 810 IN EFI_HANDLE RootBridgeHandle\r
a3b8e257 811 )\r
ead42efc 812{\r
ead42efc 813 EFI_STATUS Status;\r
814 PCI_IO_DEVICE *Dev;\r
815 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
816 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
817\r
48a9ea7b 818 Dev = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
819 if (Dev == NULL) {\r
ead42efc 820 return NULL;\r
821 }\r
822\r
ead42efc 823 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;\r
824 Dev->Handle = RootBridgeHandle;\r
825 InitializeListHead (&Dev->ChildList);\r
826\r
827 Status = gBS->OpenProtocol (\r
828 RootBridgeHandle,\r
829 &gEfiDevicePathProtocolGuid,\r
830 (VOID **) &ParentDevicePath,\r
831 gPciBusDriverBinding.DriverBindingHandle,\r
832 RootBridgeHandle,\r
833 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
834 );\r
835\r
836 if (EFI_ERROR (Status)) {\r
48a9ea7b 837 FreePool (Dev);\r
ead42efc 838 return NULL;\r
839 }\r
840\r
841 //\r
842 // Record the root bridge parent device path\r
843 //\r
844 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);\r
845\r
846 //\r
847 // Get the pci root bridge io protocol\r
848 //\r
849 Status = gBS->OpenProtocol (\r
850 RootBridgeHandle,\r
851 &gEfiPciRootBridgeIoProtocolGuid,\r
852 (VOID **) &PciRootBridgeIo,\r
853 gPciBusDriverBinding.DriverBindingHandle,\r
854 RootBridgeHandle,\r
855 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
856 );\r
857\r
858 if (EFI_ERROR (Status)) {\r
859 FreePciDevice (Dev);\r
860 return NULL;\r
861 }\r
862\r
863 Dev->PciRootBridgeIo = PciRootBridgeIo;\r
864\r
865 //\r
866 // Initialize the PCI I/O instance structure\r
867 //\r
8e6b0dcb 868 InitializePciIoInstance (Dev);\r
869 InitializePciDriverOverrideInstance (Dev);\r
870 InitializePciLoadFile2 (Dev);\r
ead42efc 871\r
872 //\r
873 // Initialize reserved resource list and\r
874 // option rom driver list\r
875 //\r
876 InitializeListHead (&Dev->ReservedResourceList);\r
877 InitializeListHead (&Dev->OptionRomDriverList);\r
878\r
879 return Dev;\r
880}\r
881\r
bcd70414 882/**\r
48a9ea7b 883 Get root bridge device instance by specific root bridge handle.\r
ead42efc 884\r
97404058 885 @param RootBridgeHandle Given root bridge handle.\r
ead42efc 886\r
48a9ea7b 887 @return The root bridge device instance, NULL means no root bridge\r
888 device instance found.\r
889\r
bcd70414 890**/\r
a3b8e257 891PCI_IO_DEVICE *\r
892GetRootBridgeByHandle (\r
893 EFI_HANDLE RootBridgeHandle\r
894 )\r
ead42efc 895{\r
896 PCI_IO_DEVICE *RootBridgeDev;\r
897 LIST_ENTRY *CurrentLink;\r
898\r
48a9ea7b 899 CurrentLink = mPciDevicePool.ForwardLink;\r
ead42efc 900\r
48a9ea7b 901 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
ead42efc 902\r
903 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
904 if (RootBridgeDev->Handle == RootBridgeHandle) {\r
905 return RootBridgeDev;\r
906 }\r
907\r
908 CurrentLink = CurrentLink->ForwardLink;\r
909 }\r
910\r
911 return NULL;\r
912}\r
913\r
a3b8e257 914/**\r
97404058 915 Judege whether Pci device existed.\r
a3b8e257 916 \r
97404058 917 @param Bridge Parent bridege instance.\r
918 @param PciIoDevice Device instance.\r
a3b8e257 919 \r
48a9ea7b 920 @retval TRUE Pci device existed.\r
921 @retval FALSE Pci device did not exist.\r
922\r
a3b8e257 923**/\r
ead42efc 924BOOLEAN\r
925PciDeviceExisted (\r
926 IN PCI_IO_DEVICE *Bridge,\r
927 IN PCI_IO_DEVICE *PciIoDevice\r
928 )\r
ead42efc 929{\r
930\r
931 PCI_IO_DEVICE *Temp;\r
932 LIST_ENTRY *CurrentLink;\r
933\r
934 CurrentLink = Bridge->ChildList.ForwardLink;\r
935\r
97404058 936 while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {\r
ead42efc 937\r
938 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
939\r
940 if (Temp == PciIoDevice) {\r
941 return TRUE;\r
942 }\r
943\r
944 if (!IsListEmpty (&Temp->ChildList)) {\r
945 if (PciDeviceExisted (Temp, PciIoDevice)) {\r
946 return TRUE;\r
947 }\r
948 }\r
949\r
950 CurrentLink = CurrentLink->ForwardLink;\r
951 }\r
952\r
953 return FALSE;\r
954}\r
955\r
a3b8e257 956/**\r
48a9ea7b 957 Get the active VGA device on the same segment.\r
a3b8e257 958 \r
48a9ea7b 959 @param VgaDevice PCI IO instance for the VGA device.\r
a3b8e257 960 \r
48a9ea7b 961 @return The active VGA device on the same segment.\r
962\r
a3b8e257 963**/\r
ead42efc 964PCI_IO_DEVICE *\r
965ActiveVGADeviceOnTheSameSegment (\r
966 IN PCI_IO_DEVICE *VgaDevice\r
967 )\r
ead42efc 968{\r
969 LIST_ENTRY *CurrentLink;\r
970 PCI_IO_DEVICE *Temp;\r
971\r
48a9ea7b 972 CurrentLink = mPciDevicePool.ForwardLink;\r
ead42efc 973\r
48a9ea7b 974 while (CurrentLink != NULL && CurrentLink != &mPciDevicePool) {\r
ead42efc 975\r
976 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
977\r
978 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {\r
979\r
980 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
981\r
982 if (Temp != NULL) {\r
983 return Temp;\r
984 }\r
985 }\r
986\r
987 CurrentLink = CurrentLink->ForwardLink;\r
988 }\r
989\r
990 return NULL;\r
991}\r
992\r
a3b8e257 993/**\r
48a9ea7b 994 Get the active VGA device on the root bridge.\r
a3b8e257 995 \r
48a9ea7b 996 @param RootBridge PCI IO instance for the root bridge.\r
a3b8e257 997 \r
48a9ea7b 998 @return The active VGA device.\r
999\r
a3b8e257 1000**/\r
ead42efc 1001PCI_IO_DEVICE *\r
1002ActiveVGADeviceOnTheRootBridge (\r
1003 IN PCI_IO_DEVICE *RootBridge\r
1004 )\r
ead42efc 1005{\r
1006 LIST_ENTRY *CurrentLink;\r
1007 PCI_IO_DEVICE *Temp;\r
1008\r
1009 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1010\r
97404058 1011 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
ead42efc 1012\r
1013 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1014\r
1015 if (IS_PCI_VGA(&Temp->Pci) &&\r
1016 (Temp->Attributes &\r
1017 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |\r
1018 EFI_PCI_IO_ATTRIBUTE_VGA_IO |\r
97404058 1019 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) != 0) {\r
ead42efc 1020 return Temp;\r
1021 }\r
1022\r
1023 if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
1024\r
1025 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
1026\r
1027 if (Temp != NULL) {\r
1028 return Temp;\r
1029 }\r
1030 }\r
1031\r
1032 CurrentLink = CurrentLink->ForwardLink;\r
1033 }\r
1034\r
1035 return NULL;\r
1036}\r
1037\r
ead42efc 1038\r
a3b8e257 1039/**\r
97404058 1040 Get HPC PCI address according to its device path.\r
48a9ea7b 1041\r
97404058 1042 @param RootBridge Root bridege Io instance.\r
1043 @param RemainingDevicePath Given searching device path.\r
1044 @param PciAddress Buffer holding searched result.\r
a3b8e257 1045 \r
48a9ea7b 1046 @retval EFI_SUCCESS PCI address was stored in PciAddress\r
1047 @retval EFI_NOT_FOUND Can not find the specific device path.\r
1048 \r
a3b8e257 1049**/\r
ead42efc 1050EFI_STATUS\r
1051GetHpcPciAddressFromRootBridge (\r
1052 IN PCI_IO_DEVICE *RootBridge,\r
1053 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
1054 OUT UINT64 *PciAddress\r
1055 )\r
ead42efc 1056{\r
1057 EFI_DEV_PATH_PTR Node;\r
1058 PCI_IO_DEVICE *Temp;\r
1059 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
1060 LIST_ENTRY *CurrentLink;\r
1061 BOOLEAN MisMatch;\r
1062\r
1063 MisMatch = FALSE;\r
1064\r
1065 CurrentDevicePath = RemainingDevicePath;\r
1066 Node.DevPath = CurrentDevicePath;\r
1067 Temp = NULL;\r
1068\r
2067710d 1069 while (!IsDevicePathEnd (CurrentDevicePath)) {\r
ead42efc 1070\r
1071 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1072 Node.DevPath = CurrentDevicePath;\r
1073\r
97404058 1074 while (CurrentLink != NULL && CurrentLink != &RootBridge->ChildList) {\r
ead42efc 1075 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1076\r
1077 if (Node.Pci->Device == Temp->DeviceNumber &&\r
1078 Node.Pci->Function == Temp->FunctionNumber) {\r
1079 RootBridge = Temp;\r
1080 break;\r
1081 }\r
1082\r
1083 CurrentLink = CurrentLink->ForwardLink;\r
1084 }\r
1085\r
1086 //\r
1087 // Check if we find the bridge\r
1088 //\r
1089 if (CurrentLink == &RootBridge->ChildList) {\r
1090\r
1091 MisMatch = TRUE;\r
1092 break;\r
1093\r
1094 }\r
1095\r
2067710d 1096 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
ead42efc 1097 }\r
1098\r
1099 if (MisMatch) {\r
1100\r
2067710d 1101 CurrentDevicePath = NextDevicePathNode (CurrentDevicePath);\r
ead42efc 1102\r
2067710d 1103 if (IsDevicePathEnd (CurrentDevicePath)) {\r
ead42efc 1104 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);\r
1105 return EFI_SUCCESS;\r
1106 }\r
1107\r
1108 return EFI_NOT_FOUND;\r
1109 }\r
1110\r
aa950314 1111 if (Temp != NULL) {\r
1112 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1113 } else {\r
1114 return EFI_NOT_FOUND;\r
1115 }\r
ead42efc 1116\r
1117 return EFI_SUCCESS;\r
1118\r
1119}\r
a3b8e257 1120\r