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