]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/SioBusDxe/SioBusDxe.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / SioBusDxe / SioBusDxe.c
CommitLineData
a5cc178a
HW
1/** @file\r
2 The SioBusDxe driver is used to create child devices on the ISA bus and\r
3 installs the Super I/O protocols on them.\r
4\r
5 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
6\r
b26f0cf9 7 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a5cc178a
HW
8\r
9**/\r
10\r
11#include "SioBusDxe.h"\r
12\r
13//\r
14// SioBus Driver Binding Protocol\r
15//\r
ac0a286f 16EFI_DRIVER_BINDING_PROTOCOL gSioBusDriverBinding = {\r
a5cc178a
HW
17 SioBusDriverBindingSupported,\r
18 SioBusDriverBindingStart,\r
19 SioBusDriverBindingStop,\r
20 0x10,\r
21 NULL,\r
22 NULL\r
23};\r
24\r
a5cc178a
HW
25/**\r
26 Tests to see if this driver supports a given controller. If a child device is\r
27 provided, it further tests to see if this driver supports creating a handle\r
28 for the specified child device.\r
29\r
30 This function checks to see if the driver specified by This supports the\r
31 device specified by ControllerHandle. Drivers will typically use the device\r
32 path attached to ControllerHandle and/or the services from the bus I/O\r
33 abstraction attached to ControllerHandle to determine if the driver supports\r
34 ControllerHandle. This function may be called many times during platform\r
35 initialization. In order to reduce boot times, the tests performed by this\r
36 function must be very small, and take as little time as possible to execute.\r
37 This function must not change the state of any hardware devices, and this\r
38 function must be aware that the device specified by ControllerHandle may\r
39 already be managed by the same driver or a different driver. This function\r
40 must match its calls to AllocatePages() with FreePages(), AllocatePool() with\r
41 FreePool(), and OpenProtocol() with CloseProtocol(). Since ControllerHandle\r
42 may have been previously started by the same driver, if a protocol is already\r
43 in the opened state, then it must not be closed with CloseProtocol(). This is\r
44 required to guarantee the state of ControllerHandle is not modified by this\r
45 function.\r
46\r
47 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL\r
48 instance.\r
49 @param[in] ControllerHandle The handle of the controller to test. This\r
50 handle must support a protocol interface\r
51 that supplies an I/O abstraction to the\r
52 driver.\r
53 @param[in] RemainingDevicePath A pointer to the remaining portion of a\r
54 device path. This parameter is ignored by\r
55 device drivers, and is optional for bus\r
56 drivers. For bus drivers, if this parameter\r
57 is not NULL, then the bus driver must\r
58 determine if the bus controller specified by\r
59 ControllerHandle and the child controller\r
60 specified by RemainingDevicePath are both\r
61 supported by this bus driver.\r
62\r
63 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
64 RemainingDevicePath is supported by the\r
65 driver specified by This.\r
66 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
67 RemainingDevicePath is already being managed\r
68 by the driver specified by This.\r
69 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
70 RemainingDevicePath is already being managed\r
71 by a different driver or an application that\r
72 requires exclusive access.\r
73 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
74 RemainingDevicePath is not supported by the\r
75 driver specified by This.\r
76\r
77**/\r
78EFI_STATUS\r
79EFIAPI\r
80SioBusDriverBindingSupported (\r
ac0a286f
MK
81 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
82 IN EFI_HANDLE Controller,\r
83 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
a5cc178a
HW
84 )\r
85{\r
ac0a286f
MK
86 EFI_STATUS Status;\r
87 EFI_PCI_IO_PROTOCOL *PciIo;\r
88 PCI_TYPE00 Pci;\r
89 UINTN SegmentNumber;\r
90 UINTN BusNumber;\r
91 UINTN DeviceNumber;\r
92 UINTN FunctionNumber;\r
a5cc178a
HW
93\r
94 //\r
95 // Get PciIo protocol instance\r
96 //\r
97 Status = gBS->OpenProtocol (\r
98 Controller,\r
99 &gEfiPciIoProtocolGuid,\r
ac0a286f 100 (VOID **)&PciIo,\r
a5cc178a
HW
101 This->DriverBindingHandle,\r
102 Controller,\r
103 EFI_OPEN_PROTOCOL_BY_DRIVER\r
104 );\r
ac0a286f 105 if (EFI_ERROR (Status)) {\r
a5cc178a
HW
106 return Status;\r
107 }\r
108\r
109 Status = PciIo->Pci.Read (\r
ac0a286f
MK
110 PciIo,\r
111 EfiPciIoWidthUint32,\r
112 0,\r
113 sizeof (Pci) / sizeof (UINT32),\r
114 &Pci\r
115 );\r
a5cc178a
HW
116\r
117 if (!EFI_ERROR (Status)) {\r
118 Status = EFI_UNSUPPORTED;\r
119 if ((Pci.Hdr.Command & 0x03) == 0x03) {\r
120 if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) {\r
121 //\r
122 // See if this is a standard PCI to ISA Bridge from the Base Code and\r
123 // Class Code\r
124 //\r
125 if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA) {\r
126 Status = EFI_SUCCESS;\r
127 }\r
128\r
129 //\r
130 // See if this is an Intel PCI to ISA bridge in Positive Decode Mode\r
131 //\r
ac0a286f
MK
132 if ((Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE) &&\r
133 (Pci.Hdr.VendorId == 0x8086))\r
134 {\r
a5cc178a
HW
135 //\r
136 // See if this is on Function #0 to avoid false positives on\r
137 // PCI_CLASS_BRIDGE_OTHER that has the same value as\r
138 // PCI_CLASS_BRIDGE_ISA_PDECODE\r
139 //\r
140 Status = PciIo->GetLocation (\r
141 PciIo,\r
142 &SegmentNumber,\r
143 &BusNumber,\r
144 &DeviceNumber,\r
145 &FunctionNumber\r
146 );\r
ac0a286f 147 if (!EFI_ERROR (Status) && (FunctionNumber == 0)) {\r
a5cc178a
HW
148 Status = EFI_SUCCESS;\r
149 } else {\r
150 Status = EFI_UNSUPPORTED;\r
151 }\r
152 }\r
153 }\r
154 }\r
155 }\r
156\r
157 gBS->CloseProtocol (\r
158 Controller,\r
159 &gEfiPciIoProtocolGuid,\r
160 This->DriverBindingHandle,\r
161 Controller\r
162 );\r
163\r
164 return Status;\r
165}\r
166\r
167/**\r
168 Starts a device controller or a bus controller.\r
169\r
170 The Start() function is designed to be invoked from the EFI boot service\r
171 ConnectController(). As a result, much of the error checking on the\r
172 parameters to Start() has been moved into this common boot service. It is\r
173 legal to call Start() from other locations, but the following calling\r
174 restrictions must be followed or the system behavior will not be\r
175 deterministic.\r
176 1. ControllerHandle must be a valid EFI_HANDLE.\r
177 2. If RemainingDevicePath is not NULL, then it must be a pointer to a\r
178 naturally aligned EFI_DEVICE_PATH_PROTOCOL.\r
179 3. Prior to calling Start(), the Supported() function for the driver\r
180 specified by This must have been called with the same calling parameters,\r
181 and Supported() must have returned EFI_SUCCESS.\r
182\r
183 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL\r
184 instance.\r
185 @param[in] ControllerHandle The handle of the controller to start. This\r
186 handle must support a protocol interface\r
187 that supplies an I/O abstraction to the\r
188 driver.\r
189 @param[in] RemainingDevicePath A pointer to the remaining portion of a\r
190 device path. This parameter is ignored by\r
191 device drivers, and is optional for bus\r
192 drivers. For a bus driver, if this parameter\r
193 is NULL, then handles for all the children\r
194 of Controller are created by this driver. If\r
195 this parameter is not NULL and the first\r
196 Device Path Node is not the End of Device\r
197 Path Node, then only the handle for the\r
198 child device specified by the first Device\r
199 Path Node of RemainingDevicePath is created\r
200 by this driver. If the first Device Path\r
201 Node of RemainingDevicePath is the End of\r
202 Device Path Node, no child handle is created\r
203 by this driver.\r
204\r
205 @retval EFI_SUCCESS The device was started.\r
206 @retval EFI_DEVICE_ERROR The device could not be started due to a\r
207 device error.\r
208 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a\r
209 lack of resources.\r
210 @retval Others The driver failded to start the device.\r
211\r
212**/\r
213EFI_STATUS\r
214EFIAPI\r
215SioBusDriverBindingStart (\r
ac0a286f
MK
216 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
217 IN EFI_HANDLE Controller,\r
218 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
a5cc178a
HW
219 )\r
220{\r
ac0a286f
MK
221 EFI_STATUS Status;\r
222 EFI_PCI_IO_PROTOCOL *PciIo;\r
223 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;\r
224 UINT64 Supports;\r
225 UINT64 OriginalAttributes;\r
226 UINT64 Attributes;\r
227 BOOLEAN Enabled;\r
228 SIO_BUS_DRIVER_PRIVATE_DATA *Private;\r
229 UINT32 ChildDeviceNumber;\r
a5cc178a
HW
230\r
231 Enabled = FALSE;\r
232 Supports = 0;\r
233 OriginalAttributes = 0;\r
234 Private = NULL;\r
235\r
236 //\r
237 // Open the PCI I/O Protocol Interface\r
238 //\r
ac0a286f 239 PciIo = NULL;\r
a5cc178a
HW
240 Status = gBS->OpenProtocol (\r
241 Controller,\r
242 &gEfiPciIoProtocolGuid,\r
ac0a286f 243 (VOID **)&PciIo,\r
a5cc178a
HW
244 This->DriverBindingHandle,\r
245 Controller,\r
246 EFI_OPEN_PROTOCOL_BY_DRIVER\r
247 );\r
248 if (EFI_ERROR (Status)) {\r
249 return Status;\r
250 }\r
251\r
252 //\r
253 // Open Device Path Protocol\r
254 //\r
255 Status = gBS->OpenProtocol (\r
256 Controller,\r
257 &gEfiDevicePathProtocolGuid,\r
ac0a286f 258 (VOID **)&ParentDevicePath,\r
a5cc178a
HW
259 This->DriverBindingHandle,\r
260 Controller,\r
261 EFI_OPEN_PROTOCOL_BY_DRIVER\r
262 );\r
263 if (EFI_ERROR (Status)) {\r
264 gBS->CloseProtocol (\r
265 Controller,\r
266 &gEfiPciIoProtocolGuid,\r
267 This->DriverBindingHandle,\r
268 Controller\r
269 );\r
270 return Status;\r
271 }\r
272\r
273 //\r
274 // Get supported PCI attributes\r
275 //\r
276 Status = PciIo->Attributes (\r
277 PciIo,\r
278 EfiPciIoAttributeOperationSupported,\r
279 0,\r
280 &Supports\r
281 );\r
282 if (EFI_ERROR (Status)) {\r
283 goto Done;\r
284 }\r
285\r
ac0a286f
MK
286 Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_ISA_IO |\r
287 EFI_PCI_IO_ATTRIBUTE_ISA_IO_16);\r
288 if ((Supports == 0) ||\r
289 (Supports == (EFI_PCI_IO_ATTRIBUTE_ISA_IO |\r
290 EFI_PCI_IO_ATTRIBUTE_ISA_IO_16)))\r
291 {\r
a5cc178a
HW
292 Status = EFI_UNSUPPORTED;\r
293 goto Done;\r
294 }\r
295\r
296 Status = PciIo->Attributes (\r
297 PciIo,\r
298 EfiPciIoAttributeOperationGet,\r
299 0,\r
300 &OriginalAttributes\r
301 );\r
302 if (EFI_ERROR (Status)) {\r
303 goto Done;\r
304 }\r
305\r
306 Attributes = EFI_PCI_DEVICE_ENABLE |\r
307 Supports |\r
308 EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;\r
309 Status = PciIo->Attributes (\r
310 PciIo,\r
311 EfiPciIoAttributeOperationEnable,\r
312 Attributes,\r
313 NULL\r
314 );\r
315 if (EFI_ERROR (Status)) {\r
316 goto Done;\r
317 }\r
318\r
319 Enabled = TRUE;\r
320\r
321 //\r
322 // Store the OriginalAttributes for the restore in BindingStop()\r
323 //\r
324 Private = AllocateZeroPool (sizeof (SIO_BUS_DRIVER_PRIVATE_DATA));\r
325 if (Private == NULL) {\r
326 Status = EFI_OUT_OF_RESOURCES;\r
327 goto Done;\r
328 }\r
ac0a286f 329\r
a5cc178a
HW
330 Private->PciIo = PciIo;\r
331 Private->OriginalAttributes = OriginalAttributes;\r
332\r
333 Status = gBS->InstallProtocolInterface (\r
334 &Controller,\r
335 &gEfiCallerIdGuid,\r
336 EFI_NATIVE_INTERFACE,\r
337 Private\r
338 );\r
339 if (EFI_ERROR (Status)) {\r
340 goto Done;\r
341 }\r
342\r
343 //\r
344 // Report status code for the start of general controller initialization\r
345 //\r
346 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
347 EFI_PROGRESS_CODE,\r
348 (EFI_IO_BUS_LPC | EFI_IOB_PC_INIT),\r
349 ParentDevicePath\r
350 );\r
351\r
352 //\r
353 // Report status code for the start of enabling devices on the bus\r
354 //\r
355 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
356 EFI_PROGRESS_CODE,\r
357 (EFI_IO_BUS_LPC | EFI_IOB_PC_ENABLE),\r
358 ParentDevicePath\r
359 );\r
360\r
361 //\r
362 // Create all the children upon the first entrance\r
363 //\r
364 ChildDeviceNumber = SioCreateAllChildDevices (\r
365 This,\r
366 Controller,\r
367 PciIo,\r
368 ParentDevicePath\r
369 );\r
370 if (ChildDeviceNumber == 0) {\r
371 Status = EFI_DEVICE_ERROR;\r
372 }\r
373\r
374Done:\r
375 if (EFI_ERROR (Status)) {\r
ac0a286f 376 if ((PciIo != NULL) && Enabled) {\r
a5cc178a
HW
377 PciIo->Attributes (\r
378 PciIo,\r
379 EfiPciIoAttributeOperationSet,\r
380 OriginalAttributes,\r
381 NULL\r
382 );\r
383 }\r
384\r
385 gBS->CloseProtocol (\r
386 Controller,\r
387 &gEfiDevicePathProtocolGuid,\r
388 This->DriverBindingHandle,\r
389 Controller\r
390 );\r
391\r
392 gBS->CloseProtocol (\r
393 Controller,\r
394 &gEfiPciIoProtocolGuid,\r
395 This->DriverBindingHandle,\r
396 Controller\r
397 );\r
398\r
399 if (Private != NULL) {\r
400 gBS->UninstallMultipleProtocolInterfaces (\r
401 Controller,\r
402 &gEfiCallerIdGuid,\r
403 Private,\r
404 NULL\r
405 );\r
406 FreePool (Private);\r
407 }\r
408\r
409 return Status;\r
410 }\r
411\r
412 return EFI_SUCCESS;\r
413}\r
414\r
415/**\r
416 Stops a device controller or a bus controller.\r
417\r
418 The Stop() function is designed to be invoked from the EFI boot service\r
419 DisconnectController(). As a result, much of the error checking on the\r
420 parameters to Stop() has been moved into this common boot service. It is\r
421 legal to call Stop() from other locations, but the following calling\r
422 restrictions must be followed or the system behavior will not be\r
423 deterministic.\r
424 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous\r
425 call to this same driver's Start() function.\r
426 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a\r
427 valid EFI_HANDLE. In addition, all of these handles must have been created\r
428 in this driver's Start() function, and the Start() function must have\r
429 called OpenProtocol() on ControllerHandle with an Attribute of\r
430 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
431\r
432 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL\r
433 instance.\r
434 @param[in] ControllerHandle A handle to the device being stopped. The\r
435 handle must support a bus specific I/O\r
436 protocol for the driver to use to stop the\r
437 device.\r
438 @param[in] NumberOfChildren The number of child device handles in\r
439 ChildHandleBuffer.\r
440 @param[in] ChildHandleBuffer An array of child handles to be freed. May be\r
441 NULL if NumberOfChildren is 0.\r
442\r
443 @retval EFI_SUCCESS The device was stopped.\r
444 @retval EFI_DEVICE_ERROR The device could not be stopped due to a\r
445 device error.\r
446\r
447**/\r
448EFI_STATUS\r
449EFIAPI\r
450SioBusDriverBindingStop (\r
ac0a286f
MK
451 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
452 IN EFI_HANDLE Controller,\r
453 IN UINTN NumberOfChildren,\r
454 IN EFI_HANDLE *ChildHandleBuffer\r
a5cc178a
HW
455 )\r
456{\r
ac0a286f
MK
457 EFI_STATUS Status;\r
458 SIO_BUS_DRIVER_PRIVATE_DATA *Private;\r
459 UINTN Index;\r
460 BOOLEAN AllChildrenStopped;\r
461 EFI_SIO_PROTOCOL *Sio;\r
462 SIO_DEV *SioDevice;\r
463 EFI_PCI_IO_PROTOCOL *PciIo;\r
a5cc178a
HW
464\r
465 if (NumberOfChildren == 0) {\r
466 //\r
467 // Restore PCI attributes\r
468 //\r
469 Status = gBS->OpenProtocol (\r
470 Controller,\r
471 &gEfiCallerIdGuid,\r
ac0a286f 472 (VOID **)&Private,\r
a5cc178a
HW
473 This->DriverBindingHandle,\r
474 Controller,\r
475 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
476 );\r
477 if (EFI_ERROR (Status)) {\r
478 return Status;\r
479 }\r
480\r
481 Status = Private->PciIo->Attributes (\r
482 Private->PciIo,\r
483 EfiPciIoAttributeOperationSet,\r
484 Private->OriginalAttributes,\r
485 NULL\r
486 );\r
487 if (EFI_ERROR (Status)) {\r
488 return Status;\r
489 }\r
490\r
491 gBS->UninstallProtocolInterface (\r
ac0a286f
MK
492 Controller,\r
493 &gEfiCallerIdGuid,\r
494 Private\r
495 );\r
a5cc178a
HW
496 FreePool (Private);\r
497\r
498 //\r
499 // Close the bus driver\r
500 //\r
501 Status = gBS->CloseProtocol (\r
502 Controller,\r
503 &gEfiDevicePathProtocolGuid,\r
504 This->DriverBindingHandle,\r
505 Controller\r
506 );\r
507 if (EFI_ERROR (Status)) {\r
508 return Status;\r
509 }\r
510\r
511 Status = gBS->CloseProtocol (\r
512 Controller,\r
513 &gEfiPciIoProtocolGuid,\r
514 This->DriverBindingHandle,\r
515 Controller\r
516 );\r
517 if (EFI_ERROR (Status)) {\r
518 return Status;\r
519 }\r
520\r
521 return EFI_SUCCESS;\r
522 }\r
523\r
524 //\r
525 // Stop all the children\r
526 //\r
527 AllChildrenStopped = TRUE;\r
528\r
529 for (Index = 0; Index < NumberOfChildren; Index++) {\r
530 Status = gBS->OpenProtocol (\r
531 ChildHandleBuffer[Index],\r
532 &gEfiSioProtocolGuid,\r
ac0a286f 533 (VOID **)&Sio,\r
a5cc178a
HW
534 This->DriverBindingHandle,\r
535 Controller,\r
536 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
537 );\r
538 if (!EFI_ERROR (Status)) {\r
539 SioDevice = SIO_DEV_FROM_SIO (Sio);\r
540\r
541 //\r
542 // Close the child handle\r
543 //\r
544 Status = gBS->CloseProtocol (\r
545 Controller,\r
546 &gEfiPciIoProtocolGuid,\r
547 This->DriverBindingHandle,\r
548 ChildHandleBuffer[Index]\r
549 );\r
550 Status = gBS->UninstallMultipleProtocolInterfaces (\r
551 ChildHandleBuffer[Index],\r
552 &gEfiDevicePathProtocolGuid,\r
553 SioDevice->DevicePath,\r
554 &gEfiSioProtocolGuid,\r
555 &SioDevice->Sio,\r
556 NULL\r
557 );\r
558\r
559 if (!EFI_ERROR (Status)) {\r
560 FreePool (SioDevice->DevicePath);\r
561 FreePool (SioDevice);\r
562 } else {\r
563 //\r
564 // Re-open PCI IO Protocol on behalf of the child device\r
565 // because of failure of destroying the child device handle\r
566 //\r
567 gBS->OpenProtocol (\r
568 Controller,\r
569 &gEfiPciIoProtocolGuid,\r
ac0a286f 570 (VOID **)&PciIo,\r
a5cc178a
HW
571 This->DriverBindingHandle,\r
572 ChildHandleBuffer[Index],\r
573 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
574 );\r
575 }\r
576 }\r
577\r
578 if (EFI_ERROR (Status)) {\r
579 AllChildrenStopped = FALSE;\r
580 }\r
581 }\r
582\r
583 if (!AllChildrenStopped) {\r
584 return EFI_DEVICE_ERROR;\r
585 }\r
586\r
587 return EFI_SUCCESS;\r
588}\r
589\r
590/**\r
591 The entry point for the SioBusDxe driver.\r
592\r
593 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
594 @param[in] SystemTable A pointer to the EFI System Table.\r
595\r
596 @retval EFI_SUCCESS The entry point is executed successfully.\r
597 @retval other Some error occurs when executing this entry point.\r
598\r
599**/\r
600EFI_STATUS\r
601EFIAPI\r
602SioBusDxeDriverEntryPoint (\r
ac0a286f
MK
603 IN EFI_HANDLE ImageHandle,\r
604 IN EFI_SYSTEM_TABLE *SystemTable\r
a5cc178a
HW
605 )\r
606{\r
607 //\r
608 // Install driver model protocol(s).\r
609 //\r
610 return EfiLibInstallDriverBindingComponentName2 (\r
611 ImageHandle,\r
612 SystemTable,\r
613 &gSioBusDriverBinding,\r
614 ImageHandle,\r
615 &gSioBusComponentName,\r
616 &gSioBusComponentName2\r
617 );\r
618}\r