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