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