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