]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Pci/PciBusDxe/PciDeviceSupport.c
sync filename exactly.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciDeviceSupport.c
CommitLineData
3db51098 1/**@file\r
ead42efc 2\r
3db51098 3Copyright (c) 2006, Intel Corporation \r
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
03417d8d 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
25 Initialize the gPciDevicePool\r
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
78 @param RootBridge The bridge want to be removed\r
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
177 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
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
223\r
224 //\r
225 // Install the pciio protocol, device path protocol\r
226 //\r
227 Status = gBS->InstallMultipleProtocolInterfaces (\r
228 &PciIoDevice->Handle,\r
229 &gEfiDevicePathProtocolGuid,\r
230 PciIoDevice->DevicePath,\r
231 &gEfiPciIoProtocolGuid,\r
232 &PciIoDevice->PciIo,\r
233 NULL\r
234 );\r
235 if (EFI_ERROR (Status)) {\r
236 return Status;\r
237 }\r
238\r
239 //\r
240 // Detect if PCI Express Device\r
241 //\r
242 PciExpressCapRegOffset = 0;\r
243 Status = LocateCapabilityRegBlock (\r
244 PciIoDevice,\r
245 EFI_PCI_CAPABILITY_ID_PCIEXP,\r
246 &PciExpressCapRegOffset,\r
247 NULL\r
248 );\r
249 if (!EFI_ERROR (Status)) {\r
250 PciIoDevice->IsPciExp = TRUE;\r
251 }\r
252 \r
253 //\r
254 // Force Interrupt line to "Unknown" or "No Connection"\r
255 //\r
256 PciIo = &(PciIoDevice->PciIo);\r
257 Data8 = PCI_INT_LINE_UNKNOWN;\r
258 PciIoWrite (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &Data8);\r
259\r
260 //\r
eb9a9a5e 261 // Process OpRom\r
ead42efc 262 //\r
eb9a9a5e 263 if (!PciIoDevice->AllOpRomProcessed) {\r
ead42efc 264 PciIoDevice->AllOpRomProcessed = TRUE;\r
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
282 // Add the Rom Image to internal database for later PCI light enumeration\r
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
293 \r
294 }\r
295 }\r
96d1b172 296\r
eb9a9a5e 297 //\r
298 // Dispatch the EFI OpRom for the PCI device.\r
299 // The OpRom is got from platform in the above code\r
300 // or loaded from device in previous bus enumeration\r
301 //\r
302 if (PciIoDevice->RomSize > 0) {\r
ead42efc 303 ProcessOpRomImage (PciIoDevice);\r
304 }\r
305 }\r
306\r
307 if (PciIoDevice->BusOverride) {\r
308 //\r
309 // Install BusSpecificDriverOverride Protocol\r
310 //\r
311 Status = gBS->InstallMultipleProtocolInterfaces (\r
312 &PciIoDevice->Handle,\r
313 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
314 &PciIoDevice->PciDriverOverride,\r
315 NULL\r
316 );\r
317 if (EFI_ERROR (Status)) {\r
318 gBS->UninstallMultipleProtocolInterfaces (\r
319 &PciIoDevice->Handle,\r
320 &gEfiDevicePathProtocolGuid,\r
321 PciIoDevice->DevicePath,\r
322 &gEfiPciIoProtocolGuid,\r
323 &PciIoDevice->PciIo,\r
324 NULL\r
325 );\r
326\r
327 return Status;\r
328 }\r
329 }\r
330\r
331 Status = gBS->OpenProtocol (\r
332 Controller,\r
333 &gEfiPciRootBridgeIoProtocolGuid,\r
334 (VOID **) &(PciIoDevice->PciRootBridgeIo),\r
335 gPciBusDriverBinding.DriverBindingHandle,\r
336 PciIoDevice->Handle,\r
337 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
338 );\r
339 if (EFI_ERROR (Status)) {\r
340 return Status;\r
341 }\r
342\r
343 //\r
344 // Install Pccard Hotplug GUID for Pccard device so that\r
345 // to notify CardBus driver to stop the device when de-register happens\r
346 //\r
347 InstallPciHotplugGuid (PciIoDevice);\r
348\r
349 if (Handle != NULL) {\r
350 *Handle = PciIoDevice->Handle;\r
351 }\r
352\r
353 //\r
354 // Indicate the pci device is registered\r
355 //\r
356 PciIoDevice->Registered = TRUE;\r
357\r
358 return EFI_SUCCESS;\r
359}\r
360\r
a3b8e257 361/**\r
362 This function is used to remove the whole PCI devices from the bridge.\r
363\r
364 @param RootBridgeHandle An efi handle.\r
365 @param Bridge A pointer to the PCI_IO_DEVICE.\r
366\r
367 @retval EFI_SUCCESS\r
368**/\r
ead42efc 369EFI_STATUS\r
370RemoveAllPciDeviceOnBridge (\r
371 EFI_HANDLE RootBridgeHandle,\r
372 PCI_IO_DEVICE *Bridge\r
373 )\r
ead42efc 374\r
ead42efc 375{\r
376\r
377 LIST_ENTRY *CurrentLink;\r
378 PCI_IO_DEVICE *Temp;\r
379\r
380 while (!IsListEmpty (&Bridge->ChildList)) {\r
381\r
382 CurrentLink = Bridge->ChildList.ForwardLink;\r
383 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
384\r
385 //\r
386 // Check if the current node has been deregistered before\r
387 // If it is not, then deregister it\r
388 //\r
389 if (Temp->Registered) {\r
390 DeRegisterPciDevice (RootBridgeHandle, Temp->Handle);\r
391 }\r
392\r
393 //\r
394 // Remove this node from the linked list\r
395 //\r
396 RemoveEntryList (CurrentLink);\r
397\r
398 if (!IsListEmpty (&Temp->ChildList)) {\r
399 RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);\r
400 }\r
401\r
402 FreePciDevice (Temp);\r
403 }\r
404\r
405 return EFI_SUCCESS;\r
406}\r
407\r
bcd70414 408/**\r
ead42efc 409\r
ead42efc 410 This function is used to de-register the PCI device from the EFI,\r
411 That includes un-installing PciIo protocol from the specified PCI\r
412 device handle.\r
413\r
a3b8e257 414 @param Controller - controller handle\r
415 @param Handle - device handle\r
ead42efc 416\r
a3b8e257 417 @return Status of de-register pci device\r
bcd70414 418**/\r
a3b8e257 419EFI_STATUS\r
420DeRegisterPciDevice (\r
421 IN EFI_HANDLE Controller,\r
422 IN EFI_HANDLE Handle\r
423 )\r
424\r
ead42efc 425{\r
426 EFI_PCI_IO_PROTOCOL *PciIo;\r
427 EFI_STATUS Status;\r
428 PCI_IO_DEVICE *PciIoDevice;\r
429 PCI_IO_DEVICE *Node;\r
430 LIST_ENTRY *CurrentLink;\r
431 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
432\r
433 Status = gBS->OpenProtocol (\r
434 Handle,\r
435 &gEfiPciIoProtocolGuid,\r
436 (VOID **) &PciIo,\r
437 gPciBusDriverBinding.DriverBindingHandle,\r
438 Controller,\r
439 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
440 );\r
441 if (!EFI_ERROR (Status)) {\r
442 PciIoDevice = PCI_IO_DEVICE_FROM_PCI_IO_THIS (PciIo);\r
443\r
444 //\r
445 // If it is already de-registered\r
446 //\r
447 if (!PciIoDevice->Registered) {\r
448 return EFI_SUCCESS;\r
449 }\r
450\r
451 //\r
452 // If it is PPB, first de-register its children\r
453 //\r
454\r
455 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
456\r
457 CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
458\r
459 while (CurrentLink && CurrentLink != &PciIoDevice->ChildList) {\r
460 Node = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
461 Status = DeRegisterPciDevice (Controller, Node->Handle);\r
462\r
463 if (EFI_ERROR (Status)) {\r
464 return Status;\r
465 }\r
466\r
467 CurrentLink = CurrentLink->ForwardLink;\r
468 }\r
469 }\r
470 //\r
471 // Uninstall Pccard Hotplug GUID for Pccard device\r
472 //\r
473 UninstallPciHotplugGuid (PciIoDevice);\r
474\r
475 //\r
476 // Close the child handle\r
477 //\r
478 Status = gBS->CloseProtocol (\r
479 Controller,\r
480 &gEfiPciRootBridgeIoProtocolGuid,\r
481 gPciBusDriverBinding.DriverBindingHandle,\r
482 Handle\r
483 );\r
484\r
485 //\r
486 // Un-install the device path protocol and pci io protocol\r
487 //\r
488 if (PciIoDevice->BusOverride) {\r
489 Status = gBS->UninstallMultipleProtocolInterfaces (\r
490 Handle,\r
491 &gEfiDevicePathProtocolGuid,\r
492 PciIoDevice->DevicePath,\r
493 &gEfiPciIoProtocolGuid,\r
494 &PciIoDevice->PciIo,\r
495 &gEfiBusSpecificDriverOverrideProtocolGuid,\r
496 &PciIoDevice->PciDriverOverride,\r
497 NULL\r
498 );\r
499 } else {\r
500 Status = gBS->UninstallMultipleProtocolInterfaces (\r
501 Handle,\r
502 &gEfiDevicePathProtocolGuid,\r
503 PciIoDevice->DevicePath,\r
504 &gEfiPciIoProtocolGuid,\r
505 &PciIoDevice->PciIo,\r
506 NULL\r
507 );\r
508 }\r
509\r
510 if (EFI_ERROR (Status)) {\r
511 gBS->OpenProtocol (\r
512 Controller,\r
513 &gEfiPciRootBridgeIoProtocolGuid,\r
514 (VOID **) &PciRootBridgeIo,\r
515 gPciBusDriverBinding.DriverBindingHandle,\r
516 Handle,\r
517 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
518 );\r
519 return Status;\r
520 }\r
521\r
522 //\r
523 // The Device Driver should disable this device after disconnect\r
524 // so the Pci Bus driver will not touch this device any more.\r
525 // Restore the register field to the original value\r
526 //\r
527 PciIoDevice->Registered = FALSE;\r
528 PciIoDevice->Handle = NULL;\r
529 } else {\r
530\r
531 //\r
532 // Handle may be closed before\r
533 //\r
534 return EFI_SUCCESS;\r
535 }\r
536\r
537 return EFI_SUCCESS;\r
538}\r
539\r
a3b8e257 540/**\r
541 Start to manage the PCI device on specified the root bridge or PCI-PCI Bridge\r
542\r
543 @param Controller An efi handle.\r
544 @param RootBridge A pointer to the PCI_IO_DEVICE.\r
545 @param RemainingDevicePath A pointer to the EFI_DEVICE_PATH_PROTOCOL.\r
546 @param NumberOfChildren Children number.\r
547 @param ChildHandleBuffer A pointer to the child handle buffer.\r
548\r
549 @retval EFI_NOT_READY Device is not allocated\r
550 @retval EFI_UNSUPPORTED Device only support PCI-PCI bridge.\r
551 @retval EFI_NOT_FOUND Can not find the specific device\r
552 @retval EFI_SUCCESS Success to start Pci device on bridge\r
553\r
554**/\r
ead42efc 555EFI_STATUS\r
556StartPciDevicesOnBridge (\r
557 IN EFI_HANDLE Controller,\r
558 IN PCI_IO_DEVICE *RootBridge,\r
559 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
560 IN OUT UINT8 *NumberOfChildren,\r
561 IN OUT EFI_HANDLE *ChildHandleBuffer\r
562 )\r
ead42efc 563\r
ead42efc 564{\r
ead42efc 565 PCI_IO_DEVICE *PciIoDevice;\r
566 EFI_DEV_PATH_PTR Node;\r
567 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
568 EFI_STATUS Status;\r
569 LIST_ENTRY *CurrentLink;\r
570 UINT64 Supports;\r
571\r
572 CurrentLink = RootBridge->ChildList.ForwardLink;\r
573\r
574 while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
575\r
eb9a9a5e 576 PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
ead42efc 577 if (RemainingDevicePath != NULL) {\r
578\r
579 Node.DevPath = RemainingDevicePath;\r
580\r
eb9a9a5e 581 if (Node.Pci->Device != PciIoDevice->DeviceNumber || \r
582 Node.Pci->Function != PciIoDevice->FunctionNumber) {\r
ead42efc 583 CurrentLink = CurrentLink->ForwardLink;\r
584 continue;\r
585 }\r
586\r
587 //\r
588 // Check if the device has been assigned with required resource\r
589 //\r
eb9a9a5e 590 if (!PciIoDevice->Allocated) {\r
ead42efc 591 return EFI_NOT_READY;\r
592 }\r
eb9a9a5e 593 \r
ead42efc 594 //\r
595 // Check if the current node has been registered before\r
596 // If it is not, register it\r
597 //\r
eb9a9a5e 598 if (!PciIoDevice->Registered) {\r
ead42efc 599 Status = RegisterPciDevice (\r
eb9a9a5e 600 Controller,\r
601 PciIoDevice,\r
602 NULL\r
603 );\r
ead42efc 604\r
605 }\r
606\r
eb9a9a5e 607 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {\r
608 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
ead42efc 609 (*NumberOfChildren)++;\r
610 }\r
eb9a9a5e 611 \r
ead42efc 612 //\r
613 // Get the next device path\r
614 //\r
615 CurrentDevicePath = EfiNextDevicePathNode (RemainingDevicePath);\r
616 if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
617 return EFI_SUCCESS;\r
618 }\r
619\r
620 //\r
621 // If it is a PPB\r
622 //\r
eb9a9a5e 623 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
ead42efc 624 Status = StartPciDevicesOnBridge (\r
eb9a9a5e 625 Controller,\r
626 PciIoDevice,\r
627 CurrentDevicePath,\r
628 NumberOfChildren,\r
629 ChildHandleBuffer\r
630 );\r
631\r
632 PciIoDevice->PciIo.Attributes (\r
633 &(PciIoDevice->PciIo),\r
634 EfiPciIoAttributeOperationSupported,\r
635 0,\r
636 &Supports\r
637 );\r
ead42efc 638 Supports &= EFI_PCI_DEVICE_ENABLE;\r
eb9a9a5e 639 PciIoDevice->PciIo.Attributes (\r
640 &(PciIoDevice->PciIo),\r
641 EfiPciIoAttributeOperationEnable,\r
642 Supports,\r
643 NULL\r
644 );\r
ead42efc 645\r
646 return Status;\r
647 } else {\r
648\r
649 //\r
650 // Currently, the PCI bus driver only support PCI-PCI bridge\r
651 //\r
652 return EFI_UNSUPPORTED;\r
653 }\r
654\r
655 } else {\r
656\r
657 //\r
658 // If remaining device path is NULL,\r
659 // try to enable all the pci devices under this bridge\r
660 //\r
661\r
eb9a9a5e 662 if (!PciIoDevice->Registered && PciIoDevice->Allocated) {\r
ead42efc 663 Status = RegisterPciDevice (\r
eb9a9a5e 664 Controller,\r
665 PciIoDevice,\r
666 NULL\r
667 );\r
ead42efc 668\r
669 }\r
670\r
eb9a9a5e 671 if (NumberOfChildren != NULL && ChildHandleBuffer != NULL && PciIoDevice->Registered) {\r
672 ChildHandleBuffer[*NumberOfChildren] = PciIoDevice->Handle;\r
ead42efc 673 (*NumberOfChildren)++;\r
674 }\r
675\r
eb9a9a5e 676 if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
ead42efc 677 Status = StartPciDevicesOnBridge (\r
eb9a9a5e 678 Controller,\r
679 PciIoDevice,\r
680 RemainingDevicePath,\r
681 NumberOfChildren,\r
682 ChildHandleBuffer\r
683 );\r
684\r
685 PciIoDevice->PciIo.Attributes (\r
686 &(PciIoDevice->PciIo),\r
687 EfiPciIoAttributeOperationSupported,\r
688 0,\r
689 &Supports\r
690 );\r
ead42efc 691 Supports &= EFI_PCI_DEVICE_ENABLE;\r
eb9a9a5e 692 PciIoDevice->PciIo.Attributes (\r
693 &(PciIoDevice->PciIo),\r
694 EfiPciIoAttributeOperationEnable,\r
695 Supports,\r
696 NULL\r
697 );\r
ead42efc 698\r
699 }\r
700\r
701 CurrentLink = CurrentLink->ForwardLink;\r
ead42efc 702 }\r
703 }\r
704\r
705 return EFI_NOT_FOUND;\r
706}\r
707\r
bcd70414 708/**\r
eb9a9a5e 709 Start to manage all the PCI devices it found previously under \r
710 the entire host bridge.\r
ead42efc 711\r
a3b8e257 712 @param Controller - root bridge handle.\r
ead42efc 713\r
bcd70414 714**/\r
a3b8e257 715EFI_STATUS\r
716StartPciDevices (\r
717 IN EFI_HANDLE Controller\r
718 )\r
719\r
ead42efc 720{\r
ead42efc 721 PCI_IO_DEVICE *RootBridge;\r
eb9a9a5e 722 EFI_HANDLE ThisHostBridge;\r
ead42efc 723 LIST_ENTRY *CurrentLink;\r
724\r
eb9a9a5e 725 RootBridge = GetRootBridgeByHandle (Controller);\r
726 ASSERT (RootBridge != NULL);\r
727 ThisHostBridge = RootBridge->PciRootBridgeIo->ParentHandle;\r
ead42efc 728\r
729 CurrentLink = gPciDevicePool.ForwardLink;\r
730\r
731 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
732\r
733 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
734 //\r
735 // Locate the right root bridge to start\r
736 //\r
eb9a9a5e 737 if (RootBridge->PciRootBridgeIo->ParentHandle == ThisHostBridge) {\r
ead42efc 738 StartPciDevicesOnBridge (\r
eb9a9a5e 739 RootBridge->Handle,\r
ead42efc 740 RootBridge,\r
eb9a9a5e 741 NULL,\r
ead42efc 742 NULL,\r
743 NULL\r
744 );\r
745 }\r
746\r
747 CurrentLink = CurrentLink->ForwardLink;\r
748 }\r
749\r
750 return EFI_SUCCESS;\r
751}\r
752\r
bcd70414 753/**\r
a3b8e257 754 Create root bridge device\r
ead42efc 755\r
a3b8e257 756 @param RootBridgeHandle - Parent bridge handle.\r
ead42efc 757\r
a3b8e257 758 @return pointer to new root bridge \r
bcd70414 759**/\r
a3b8e257 760PCI_IO_DEVICE *\r
761CreateRootBridge (\r
762 IN EFI_HANDLE RootBridgeHandle\r
763 )\r
ead42efc 764{\r
765\r
766 EFI_STATUS Status;\r
767 PCI_IO_DEVICE *Dev;\r
768 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
769 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
770\r
771 Dev = NULL;\r
772 Status = gBS->AllocatePool (\r
773 EfiBootServicesData,\r
774 sizeof (PCI_IO_DEVICE),\r
775 (VOID **) &Dev\r
776 );\r
777\r
778 if (EFI_ERROR (Status)) {\r
779 return NULL;\r
780 }\r
781\r
782 ZeroMem (Dev, sizeof (PCI_IO_DEVICE));\r
783 Dev->Signature = PCI_IO_DEVICE_SIGNATURE;\r
784 Dev->Handle = RootBridgeHandle;\r
785 InitializeListHead (&Dev->ChildList);\r
786\r
787 Status = gBS->OpenProtocol (\r
788 RootBridgeHandle,\r
789 &gEfiDevicePathProtocolGuid,\r
790 (VOID **) &ParentDevicePath,\r
791 gPciBusDriverBinding.DriverBindingHandle,\r
792 RootBridgeHandle,\r
793 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
794 );\r
795\r
796 if (EFI_ERROR (Status)) {\r
797 gBS->FreePool (Dev);\r
798 return NULL;\r
799 }\r
800\r
801 //\r
802 // Record the root bridge parent device path\r
803 //\r
804 Dev->DevicePath = DuplicateDevicePath (ParentDevicePath);\r
805\r
806 //\r
807 // Get the pci root bridge io protocol\r
808 //\r
809 Status = gBS->OpenProtocol (\r
810 RootBridgeHandle,\r
811 &gEfiPciRootBridgeIoProtocolGuid,\r
812 (VOID **) &PciRootBridgeIo,\r
813 gPciBusDriverBinding.DriverBindingHandle,\r
814 RootBridgeHandle,\r
815 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
816 );\r
817\r
818 if (EFI_ERROR (Status)) {\r
819 FreePciDevice (Dev);\r
820 return NULL;\r
821 }\r
822\r
823 Dev->PciRootBridgeIo = PciRootBridgeIo;\r
824\r
825 //\r
826 // Initialize the PCI I/O instance structure\r
827 //\r
828 Status = InitializePciIoInstance (Dev);\r
829 Status = InitializePciDriverOverrideInstance (Dev);\r
830\r
831 //\r
832 // Initialize reserved resource list and\r
833 // option rom driver list\r
834 //\r
835 InitializeListHead (&Dev->ReservedResourceList);\r
836 InitializeListHead (&Dev->OptionRomDriverList);\r
837\r
838 return Dev;\r
839}\r
840\r
bcd70414 841/**\r
a3b8e257 842 Get root bridge device instance by specific handle\r
ead42efc 843\r
a3b8e257 844 @param RootBridgeHandle Given root bridge handle\r
ead42efc 845\r
a3b8e257 846 @return root bridge device instance\r
bcd70414 847**/\r
a3b8e257 848PCI_IO_DEVICE *\r
849GetRootBridgeByHandle (\r
850 EFI_HANDLE RootBridgeHandle\r
851 )\r
ead42efc 852{\r
853 PCI_IO_DEVICE *RootBridgeDev;\r
854 LIST_ENTRY *CurrentLink;\r
855\r
856 CurrentLink = gPciDevicePool.ForwardLink;\r
857\r
858 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
859\r
860 RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
861 if (RootBridgeDev->Handle == RootBridgeHandle) {\r
862 return RootBridgeDev;\r
863 }\r
864\r
865 CurrentLink = CurrentLink->ForwardLink;\r
866 }\r
867\r
868 return NULL;\r
869}\r
870\r
a3b8e257 871/**\r
872 Judege whether Pci device existed\r
873 \r
874 @param Bridge Parent bridege instance \r
875 @param PciIoDevice Device instance\r
876 \r
877 @return whether Pci device existed\r
878**/\r
ead42efc 879BOOLEAN\r
880PciDeviceExisted (\r
881 IN PCI_IO_DEVICE *Bridge,\r
882 IN PCI_IO_DEVICE *PciIoDevice\r
883 )\r
ead42efc 884{\r
885\r
886 PCI_IO_DEVICE *Temp;\r
887 LIST_ENTRY *CurrentLink;\r
888\r
889 CurrentLink = Bridge->ChildList.ForwardLink;\r
890\r
891 while (CurrentLink && CurrentLink != &Bridge->ChildList) {\r
892\r
893 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
894\r
895 if (Temp == PciIoDevice) {\r
896 return TRUE;\r
897 }\r
898\r
899 if (!IsListEmpty (&Temp->ChildList)) {\r
900 if (PciDeviceExisted (Temp, PciIoDevice)) {\r
901 return TRUE;\r
902 }\r
903 }\r
904\r
905 CurrentLink = CurrentLink->ForwardLink;\r
906 }\r
907\r
908 return FALSE;\r
909}\r
910\r
a3b8e257 911/**\r
912 Active VGA device\r
913 \r
914 @param VgaDevice device instance for VGA\r
915 \r
916 @return device instance\r
917**/\r
ead42efc 918PCI_IO_DEVICE *\r
919ActiveVGADeviceOnTheSameSegment (\r
920 IN PCI_IO_DEVICE *VgaDevice\r
921 )\r
ead42efc 922{\r
923 LIST_ENTRY *CurrentLink;\r
924 PCI_IO_DEVICE *Temp;\r
925\r
926 CurrentLink = gPciDevicePool.ForwardLink;\r
927\r
928 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
929\r
930 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
931\r
932 if (Temp->PciRootBridgeIo->SegmentNumber == VgaDevice->PciRootBridgeIo->SegmentNumber) {\r
933\r
934 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
935\r
936 if (Temp != NULL) {\r
937 return Temp;\r
938 }\r
939 }\r
940\r
941 CurrentLink = CurrentLink->ForwardLink;\r
942 }\r
943\r
944 return NULL;\r
945}\r
946\r
a3b8e257 947/**\r
948 Active VGA device on root bridge\r
949 \r
950 @param RootBridge Root bridge device instance\r
951 \r
952 @return VGA device instance\r
953**/\r
ead42efc 954PCI_IO_DEVICE *\r
955ActiveVGADeviceOnTheRootBridge (\r
956 IN PCI_IO_DEVICE *RootBridge\r
957 )\r
ead42efc 958{\r
959 LIST_ENTRY *CurrentLink;\r
960 PCI_IO_DEVICE *Temp;\r
961\r
962 CurrentLink = RootBridge->ChildList.ForwardLink;\r
963\r
964 while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
965\r
966 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
967\r
968 if (IS_PCI_VGA(&Temp->Pci) &&\r
969 (Temp->Attributes &\r
970 (EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY |\r
971 EFI_PCI_IO_ATTRIBUTE_VGA_IO |\r
972 EFI_PCI_IO_ATTRIBUTE_VGA_IO_16))) {\r
973 return Temp;\r
974 }\r
975\r
976 if (IS_PCI_BRIDGE (&Temp->Pci)) {\r
977\r
978 Temp = ActiveVGADeviceOnTheRootBridge (Temp);\r
979\r
980 if (Temp != NULL) {\r
981 return Temp;\r
982 }\r
983 }\r
984\r
985 CurrentLink = CurrentLink->ForwardLink;\r
986 }\r
987\r
988 return NULL;\r
989}\r
990\r
a3b8e257 991/**\r
992 Get HPC PCI address according to its device path\r
993 @param PciRootBridgeIo Root bridege Io instance\r
994 @param HpcDevicePath Given searching device path\r
995 @param PciAddress Buffer holding searched result\r
996 \r
997 @retval EFI_NOT_FOUND Can not find the specific device path.\r
998 @retval EFI_SUCCESS Success to get the device path\r
999**/\r
ead42efc 1000EFI_STATUS\r
1001GetHpcPciAddress (\r
1002 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
1003 IN EFI_DEVICE_PATH_PROTOCOL *HpcDevicePath,\r
1004 OUT UINT64 *PciAddress\r
1005 )\r
ead42efc 1006{\r
1007 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
1008 EFI_DEV_PATH_PTR Node;\r
1009 LIST_ENTRY *CurrentLink;\r
1010 PCI_IO_DEVICE *RootBridge;\r
1011 EFI_STATUS Status;\r
1012\r
1013 CurrentDevicePath = HpcDevicePath;\r
1014\r
1015 //\r
1016 // Get the remaining device path for this PCI device, if it is a PCI device\r
1017 //\r
1018 while (!EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1019\r
1020 Node.DevPath = CurrentDevicePath;\r
1021\r
1022 //\r
1023 // Check if it is PCI device Path?\r
1024 //\r
1025 if ((Node.DevPath->Type != HARDWARE_DEVICE_PATH) ||\r
1026 ((Node.DevPath->SubType != HW_PCI_DP) &&\r
1027 (DevicePathNodeLength (Node.DevPath) != sizeof (PCI_DEVICE_PATH)))) {\r
1028 CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
1029 continue;\r
1030 }\r
1031\r
1032 break;\r
1033 }\r
1034\r
1035 //\r
1036 // Check if it is not PCI device path\r
1037 //\r
1038 if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1039 return EFI_NOT_FOUND;\r
1040 }\r
1041\r
1042 CurrentLink = gPciDevicePool.ForwardLink;\r
1043\r
1044 while (CurrentLink && CurrentLink != &gPciDevicePool) {\r
1045\r
1046 RootBridge = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1047 //\r
1048 // Locate the right root bridge to start\r
1049 //\r
1050 if (RootBridge->PciRootBridgeIo == PciRootBridgeIo) {\r
1051 Status = GetHpcPciAddressFromRootBridge (\r
1052 RootBridge,\r
1053 CurrentDevicePath,\r
1054 PciAddress\r
1055 );\r
1056 if (EFI_ERROR (Status)) {\r
1057 return EFI_NOT_FOUND;\r
1058 }\r
1059\r
1060 return EFI_SUCCESS;\r
1061\r
1062 }\r
1063\r
1064 CurrentLink = CurrentLink->ForwardLink;\r
1065 }\r
1066\r
1067 return EFI_NOT_FOUND;\r
1068}\r
1069\r
a3b8e257 1070/**\r
1071 Get HPC PCI address according to its device path\r
1072 @param RootBridge Root bridege Io instance\r
1073 @param RemainingDevicePath Given searching device path\r
1074 @param PciAddress Buffer holding searched result\r
1075 \r
1076 @retval EFI_NOT_FOUND Can not find the specific device path.\r
1077**/\r
ead42efc 1078EFI_STATUS\r
1079GetHpcPciAddressFromRootBridge (\r
1080 IN PCI_IO_DEVICE *RootBridge,\r
1081 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath,\r
1082 OUT UINT64 *PciAddress\r
1083 )\r
ead42efc 1084{\r
1085 EFI_DEV_PATH_PTR Node;\r
1086 PCI_IO_DEVICE *Temp;\r
1087 EFI_DEVICE_PATH_PROTOCOL *CurrentDevicePath;\r
1088 LIST_ENTRY *CurrentLink;\r
1089 BOOLEAN MisMatch;\r
1090\r
1091 MisMatch = FALSE;\r
1092\r
1093 CurrentDevicePath = RemainingDevicePath;\r
1094 Node.DevPath = CurrentDevicePath;\r
1095 Temp = NULL;\r
1096\r
1097 while (!EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1098\r
1099 CurrentLink = RootBridge->ChildList.ForwardLink;\r
1100 Node.DevPath = CurrentDevicePath;\r
1101\r
1102 while (CurrentLink && CurrentLink != &RootBridge->ChildList) {\r
1103 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
1104\r
1105 if (Node.Pci->Device == Temp->DeviceNumber &&\r
1106 Node.Pci->Function == Temp->FunctionNumber) {\r
1107 RootBridge = Temp;\r
1108 break;\r
1109 }\r
1110\r
1111 CurrentLink = CurrentLink->ForwardLink;\r
1112 }\r
1113\r
1114 //\r
1115 // Check if we find the bridge\r
1116 //\r
1117 if (CurrentLink == &RootBridge->ChildList) {\r
1118\r
1119 MisMatch = TRUE;\r
1120 break;\r
1121\r
1122 }\r
1123\r
1124 CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
1125 }\r
1126\r
1127 if (MisMatch) {\r
1128\r
1129 CurrentDevicePath = EfiNextDevicePathNode (CurrentDevicePath);\r
1130\r
1131 if (EfiIsDevicePathEnd (CurrentDevicePath)) {\r
1132 *PciAddress = EFI_PCI_ADDRESS (RootBridge->BusNumber, Node.Pci->Device, Node.Pci->Function, 0);\r
1133 return EFI_SUCCESS;\r
1134 }\r
1135\r
1136 return EFI_NOT_FOUND;\r
1137 }\r
1138\r
1139 *PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);\r
1140\r
1141 return EFI_SUCCESS;\r
1142\r
1143}\r
a3b8e257 1144\r