]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Bus/Ata/AhciPei/AhciPei.c
MdeModulePkg/AhciPei: Add AHCI mode ATA device support in PEI
[mirror_edk2.git] / MdeModulePkg / Bus / Ata / AhciPei / AhciPei.c
CommitLineData
87bc3f19
HW
1/** @file\r
2 The AhciPei driver is used to manage ATA hard disk device working under AHCI\r
3 mode at PEI phase.\r
4\r
5 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
6\r
7 This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions\r
9 of the BSD License which accompanies this distribution. The\r
10 full text of the license may be found at\r
11 http://opensource.org/licenses/bsd-license.php\r
12\r
13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
15\r
16**/\r
17\r
18#include "AhciPei.h"\r
19\r
20EFI_PEI_PPI_DESCRIPTOR mAhciAtaPassThruPpiListTemplate = {\r
21 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
22 &gEdkiiPeiAtaPassThruPpiGuid,\r
23 NULL\r
24};\r
25\r
26EFI_PEI_PPI_DESCRIPTOR mAhciStorageSecurityPpiListTemplate = {\r
27 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
28 &gEdkiiPeiStorageSecurityCommandPpiGuid,\r
29 NULL\r
30};\r
31\r
32EFI_PEI_NOTIFY_DESCRIPTOR mAhciEndOfPeiNotifyListTemplate = {\r
33 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
34 &gEfiEndOfPeiSignalPpiGuid,\r
35 AhciPeimEndOfPei\r
36};\r
37\r
38\r
39/**\r
40 Free the DMA resources allocated by an ATA AHCI controller.\r
41\r
42 @param[in] Private A pointer to the PEI_AHCI_CONTROLLER_PRIVATE_DATA data\r
43 structure.\r
44\r
45**/\r
46VOID\r
47AhciFreeDmaResource (\r
48 IN PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private\r
49 )\r
50{\r
51 EFI_AHCI_REGISTERS *AhciRegisters;\r
52\r
53 ASSERT (Private != NULL);\r
54\r
55 AhciRegisters = &Private->AhciRegisters;\r
56\r
57 if (AhciRegisters->AhciRFisMap != NULL) {\r
58 IoMmuFreeBuffer (\r
59 EFI_SIZE_TO_PAGES (AhciRegisters->MaxRFisSize),\r
60 AhciRegisters->AhciRFis,\r
61 AhciRegisters->AhciRFisMap\r
62 );\r
63 }\r
64\r
65 if (AhciRegisters->AhciCmdListMap != NULL) {\r
66 IoMmuFreeBuffer (\r
67 EFI_SIZE_TO_PAGES (AhciRegisters->MaxCmdListSize),\r
68 AhciRegisters->AhciCmdList,\r
69 AhciRegisters->AhciCmdListMap\r
70 );\r
71 }\r
72\r
73 if (AhciRegisters->AhciCmdTableMap != NULL) {\r
74 IoMmuFreeBuffer (\r
75 EFI_SIZE_TO_PAGES (AhciRegisters->MaxCmdTableSize),\r
76 AhciRegisters->AhciCmdTable,\r
77 AhciRegisters->AhciCmdTableMap\r
78 );\r
79 }\r
80\r
81}\r
82\r
83/**\r
84 One notified function to cleanup the allocated DMA buffers at EndOfPei.\r
85\r
86 @param[in] PeiServices Pointer to PEI Services Table.\r
87 @param[in] NotifyDescriptor Pointer to the descriptor for the Notification\r
88 event that caused this function to execute.\r
89 @param[in] Ppi Pointer to the PPI data associated with this function.\r
90\r
91 @retval EFI_SUCCESS The function completes successfully\r
92\r
93**/\r
94EFI_STATUS\r
95EFIAPI\r
96AhciPeimEndOfPei (\r
97 IN EFI_PEI_SERVICES **PeiServices,\r
98 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,\r
99 IN VOID *Ppi\r
100 )\r
101{\r
102 PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;\r
103\r
104 Private = GET_AHCI_PEIM_HC_PRIVATE_DATA_FROM_THIS_NOTIFY (NotifyDescriptor);\r
105 AhciFreeDmaResource (Private);\r
106\r
107 return EFI_SUCCESS;\r
108}\r
109\r
110/**\r
111 Entry point of the PEIM.\r
112\r
113 @param[in] FileHandle Handle of the file being invoked.\r
114 @param[in] PeiServices Describes the list of possible PEI Services.\r
115\r
116 @retval EFI_SUCCESS PPI successfully installed.\r
117\r
118**/\r
119EFI_STATUS\r
120EFIAPI\r
121AtaAhciPeimEntry (\r
122 IN EFI_PEI_FILE_HANDLE FileHandle,\r
123 IN CONST EFI_PEI_SERVICES **PeiServices\r
124 )\r
125{\r
126 EFI_STATUS Status;\r
127 EFI_BOOT_MODE BootMode;\r
128 EDKII_ATA_AHCI_HOST_CONTROLLER_PPI *AhciHcPpi;\r
129 UINT8 Controller;\r
130 UINTN MmioBase;\r
131 UINTN DevicePathLength;\r
132 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
133 UINT32 PortBitMap;\r
134 PEI_AHCI_CONTROLLER_PRIVATE_DATA *Private;\r
135 UINT8 NumberOfPorts;\r
136\r
137 DEBUG ((DEBUG_INFO, "%a: Enters.\n", __FUNCTION__));\r
138\r
139 //\r
140 // Get the current boot mode.\r
141 //\r
142 Status = PeiServicesGetBootMode (&BootMode);\r
143 if (EFI_ERROR (Status)) {\r
144 DEBUG ((DEBUG_ERROR, "%a: Fail to get the current boot mode.\n", __FUNCTION__));\r
145 return Status;\r
146 }\r
147\r
148 //\r
149 // Locate the ATA AHCI host controller PPI.\r
150 //\r
151 Status = PeiServicesLocatePpi (\r
152 &gEdkiiPeiAtaAhciHostControllerPpiGuid,\r
153 0,\r
154 NULL,\r
155 (VOID **) &AhciHcPpi\r
156 );\r
157 if (EFI_ERROR (Status)) {\r
158 DEBUG ((DEBUG_ERROR, "%a: Failed to locate AtaAhciHostControllerPpi.\n", __FUNCTION__));\r
159 return EFI_UNSUPPORTED;\r
160 }\r
161\r
162 Controller = 0;\r
163 MmioBase = 0;\r
164 while (TRUE) {\r
165 Status = AhciHcPpi->GetAhciHcMmioBar (\r
166 AhciHcPpi,\r
167 Controller,\r
168 &MmioBase\r
169 );\r
170 //\r
171 // When status is error, meant no controller is found.\r
172 //\r
173 if (EFI_ERROR (Status)) {\r
174 break;\r
175 }\r
176\r
177 Status = AhciHcPpi->GetAhciHcDevicePath (\r
178 AhciHcPpi,\r
179 Controller,\r
180 &DevicePathLength,\r
181 &DevicePath\r
182 );\r
183 if (EFI_ERROR (Status)) {\r
184 DEBUG ((\r
185 DEBUG_ERROR, "%a: Fail to allocate get the device path for Controller %d.\n",\r
186 __FUNCTION__, Controller\r
187 ));\r
188 return Status;\r
189 }\r
190\r
191 //\r
192 // Check validity of the device path of the ATA AHCI controller.\r
193 //\r
194 Status = AhciIsHcDevicePathValid (DevicePath, DevicePathLength);\r
195 if (EFI_ERROR (Status)) {\r
196 DEBUG ((\r
197 DEBUG_ERROR, "%a: The device path is invalid for Controller %d.\n",\r
198 __FUNCTION__, Controller\r
199 ));\r
200 Controller++;\r
201 continue;\r
202 }\r
203\r
204 //\r
205 // For S3 resume performance consideration, not all ports on an ATA AHCI\r
206 // controller will be enumerated/initialized. The driver consumes the\r
207 // content within S3StorageDeviceInitList LockBox to get the ports that\r
208 // will be enumerated/initialized during S3 resume.\r
209 //\r
210 if (BootMode == BOOT_ON_S3_RESUME) {\r
211 NumberOfPorts = AhciS3GetEumeratePorts (DevicePath, DevicePathLength, &PortBitMap);\r
212 if (NumberOfPorts == 0) {\r
213 //\r
214 // No ports need to be enumerated for this controller.\r
215 //\r
216 Controller++;\r
217 continue;\r
218 }\r
219 } else {\r
220 PortBitMap = MAX_UINT32;\r
221 }\r
222\r
223 //\r
224 // Memory allocation for controller private data.\r
225 //\r
226 Private = AllocateZeroPool (sizeof (PEI_AHCI_CONTROLLER_PRIVATE_DATA));\r
227 if (Private == NULL) {\r
228 DEBUG ((\r
229 DEBUG_ERROR, "%a: Fail to allocate private data for Controller %d.\n",\r
230 __FUNCTION__, Controller\r
231 ));\r
232 return EFI_OUT_OF_RESOURCES;\r
233 }\r
234\r
235 //\r
236 // Initialize controller private data.\r
237 //\r
238 Private->Signature = AHCI_PEI_CONTROLLER_PRIVATE_DATA_SIGNATURE;\r
239 Private->MmioBase = MmioBase;\r
240 Private->DevicePathLength = DevicePathLength;\r
241 Private->DevicePath = DevicePath;\r
242 Private->PortBitMap = PortBitMap;\r
243 InitializeListHead (&Private->DeviceList);\r
244\r
245 Status = AhciModeInitialization (Private);\r
246 if (EFI_ERROR (Status)) {\r
247 DEBUG ((\r
248 DEBUG_ERROR,\r
249 "%a: Controller initialization fail for Controller %d with Status - %r.\n",\r
250 __FUNCTION__,\r
251 Controller,\r
252 Status\r
253 ));\r
254 Controller++;\r
255 continue;\r
256 }\r
257\r
258 Private->AtaPassThruMode.Attributes = EFI_ATA_PASS_THRU_ATTRIBUTES_PHYSICAL |\r
259 EFI_ATA_PASS_THRU_ATTRIBUTES_LOGICAL;\r
260 Private->AtaPassThruMode.IoAlign = sizeof (UINTN);\r
261 Private->AtaPassThruPpi.Revision = EDKII_PEI_ATA_PASS_THRU_PPI_REVISION;\r
262 Private->AtaPassThruPpi.Mode = &Private->AtaPassThruMode;\r
263 Private->AtaPassThruPpi.PassThru = AhciAtaPassThruPassThru;\r
264 Private->AtaPassThruPpi.GetNextPort = AhciAtaPassThruGetNextPort;\r
265 Private->AtaPassThruPpi.GetNextDevice = AhciAtaPassThruGetNextDevice;\r
266 Private->AtaPassThruPpi.GetDevicePath = AhciAtaPassThruGetDevicePath;\r
267 CopyMem (\r
268 &Private->AtaPassThruPpiList,\r
269 &mAhciAtaPassThruPpiListTemplate,\r
270 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
271 );\r
272 Private->AtaPassThruPpiList.Ppi = &Private->AtaPassThruPpi;\r
273 PeiServicesInstallPpi (&Private->AtaPassThruPpiList);\r
274\r
275 if (Private->TrustComputingDevices != 0) {\r
276 DEBUG ((\r
277 DEBUG_INFO,\r
278 "%a: Security Security Command PPI will be produced for Controller %d.\n",\r
279 __FUNCTION__, Controller\r
280 ));\r
281 Private->StorageSecurityPpi.Revision = EDKII_STORAGE_SECURITY_PPI_REVISION;\r
282 Private->StorageSecurityPpi.GetNumberofDevices = AhciStorageSecurityGetDeviceNo;\r
283 Private->StorageSecurityPpi.GetDevicePath = AhciStorageSecurityGetDevicePath;\r
284 Private->StorageSecurityPpi.ReceiveData = AhciStorageSecurityReceiveData;\r
285 Private->StorageSecurityPpi.SendData = AhciStorageSecuritySendData;\r
286 CopyMem (\r
287 &Private->StorageSecurityPpiList,\r
288 &mAhciStorageSecurityPpiListTemplate,\r
289 sizeof (EFI_PEI_PPI_DESCRIPTOR)\r
290 );\r
291 Private->StorageSecurityPpiList.Ppi = &Private->StorageSecurityPpi;\r
292 PeiServicesInstallPpi (&Private->StorageSecurityPpiList);\r
293 }\r
294\r
295 CopyMem (\r
296 &Private->EndOfPeiNotifyList,\r
297 &mAhciEndOfPeiNotifyListTemplate,\r
298 sizeof (EFI_PEI_NOTIFY_DESCRIPTOR)\r
299 );\r
300 PeiServicesNotifyPpi (&Private->EndOfPeiNotifyList);\r
301\r
302 DEBUG ((\r
303 DEBUG_INFO, "%a: Controller %d has been successfully initialized.\n",\r
304 __FUNCTION__, Controller\r
305 ));\r
306 Controller++;\r
307 }\r
308\r
309 return EFI_SUCCESS;\r
310}\r