SioBusDxe.c 21 KB

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