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