]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaIo.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / IsaBusDxe / IsaIo.c
CommitLineData
0a2dfa19 1/** @file\r
0a6f4824
LG
2 The implementation for EFI_ISA_IO_PROTOCOL.\r
3\r
4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
c0a00b14 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
c3902377 6\r
f8cd287b 7**/\r
c3902377 8\r
c3902377 9#include "InternalIsaIo.h"\r
10\r
c3902377 11//\r
6fcb2d91 12// Module Variables\r
c3902377 13//\r
6fcb2d91 14EFI_ISA_IO_PROTOCOL mIsaIoInterface = {\r
0a6f4824 15 {\r
c3902377 16 IsaIoMemRead,\r
17 IsaIoMemWrite\r
18 },\r
0a6f4824 19 {\r
c3902377 20 IsaIoIoRead,\r
21 IsaIoIoWrite\r
22 },\r
23 IsaIoCopyMem,\r
24 IsaIoMap,\r
25 IsaIoUnmap,\r
26 IsaIoAllocateBuffer,\r
27 IsaIoFreeBuffer,\r
28 IsaIoFlush,\r
29 NULL,\r
30 0,\r
31 NULL\r
32};\r
33\r
6fcb2d91 34EFI_ISA_DMA_REGISTERS mDmaRegisters[8] = {\r
c3902377 35 {\r
36 0x00,\r
37 0x87,\r
38 0x01\r
39 },\r
40 {\r
41 0x02,\r
42 0x83,\r
43 0x03\r
44 },\r
45 {\r
46 0x04,\r
47 0x81,\r
48 0x05\r
49 },\r
50 {\r
51 0x06,\r
52 0x82,\r
53 0x07\r
54 },\r
55 {\r
56 0x00,\r
57 0x00,\r
58 0x00\r
59 }, // Channel 4 is invalid\r
60 {\r
61 0xC4,\r
62 0x8B,\r
63 0xC6\r
64 },\r
65 {\r
66 0xC8,\r
67 0x89,\r
68 0xCA\r
69 },\r
70 {\r
71 0xCC,\r
72 0x8A,\r
73 0xCE\r
74 },\r
75};\r
76\r
bcd70414 77/**\r
bcd70414 78 Initializes an ISA I/O Instance\r
c3902377 79\r
6fcb2d91 80 @param[in] IsaIoDevice The iso device to be initialized.\r
81 @param[in] IsaDeviceResourceList The resource list.\r
0a6f4824 82\r
bcd70414 83**/\r
6fcb2d91 84VOID\r
c3902377 85InitializeIsaIoInstance (\r
86 IN ISA_IO_DEVICE *IsaIoDevice,\r
87 IN EFI_ISA_ACPI_RESOURCE_LIST *IsaDeviceResourceList\r
88 )\r
c3902377 89{\r
90 //\r
6fcb2d91 91 // Use the ISA IO Protocol structure template to initialize the ISA IO instance\r
c3902377 92 //\r
93 CopyMem (\r
94 &IsaIoDevice->IsaIo,\r
6fcb2d91 95 &mIsaIoInterface,\r
c3902377 96 sizeof (EFI_ISA_IO_PROTOCOL)\r
97 );\r
98\r
99 IsaIoDevice->IsaIo.ResourceList = IsaDeviceResourceList;\r
c3902377 100}\r
101\r
bcd70414 102/**\r
103 Performs an ISA I/O Read Cycle\r
104\r
6fcb2d91 105 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
106 @param[in] Width Specifies the width of the I/O operation.\r
0a6f4824
LG
107 @param[in] Offset The offset in ISA I/O space to start the I/O operation.\r
108 @param[in] Count The number of I/O operations to perform.\r
6fcb2d91 109 @param[out] Buffer The destination buffer to store the results\r
bcd70414 110\r
6fcb2d91 111 @retval EFI_SUCCESS The data was read from the device sucessfully.\r
112 @retval EFI_UNSUPPORTED The Offset is not valid for this device.\r
113 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
114 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
bcd70414 115**/\r
c3902377 116EFI_STATUS\r
117EFIAPI\r
118IsaIoIoRead (\r
6fcb2d91 119 IN EFI_ISA_IO_PROTOCOL *This,\r
120 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,\r
121 IN UINT32 Offset,\r
122 IN UINTN Count,\r
123 OUT VOID *Buffer\r
c3902377 124 )\r
c3902377 125{\r
126 EFI_STATUS Status;\r
127 ISA_IO_DEVICE *IsaIoDevice;\r
128\r
129 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
130\r
131 //\r
132 // Verify Isa IO Access\r
133 //\r
134 Status = IsaIoVerifyAccess (\r
135 IsaIoDevice,\r
136 IsaAccessTypeIo,\r
137 Width,\r
138 Count,\r
6fcb2d91 139 Offset\r
c3902377 140 );\r
141 if (EFI_ERROR (Status)) {\r
142 return Status;\r
143 }\r
6fcb2d91 144\r
c3902377 145 Status = IsaIoDevice->PciIo->Io.Read (\r
146 IsaIoDevice->PciIo,\r
147 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
148 EFI_PCI_IO_PASS_THROUGH_BAR,\r
149 Offset,\r
150 Count,\r
151 Buffer\r
152 );\r
153\r
154 if (EFI_ERROR (Status)) {\r
ee686203 155 REPORT_STATUS_CODE (\r
156 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
157 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
158 );\r
c3902377 159 }\r
160\r
161 return Status;\r
162}\r
163\r
bcd70414 164/**\r
165 Performs an ISA I/O Write Cycle\r
166\r
6fcb2d91 167 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
168 @param[in] Width Specifies the width of the I/O operation.\r
0a6f4824
LG
169 @param[in] Offset The offset in ISA I/O space to start the I/O operation.\r
170 @param[in] Count The number of I/O operations to perform.\r
6fcb2d91 171 @param[in] Buffer The source buffer to write data from\r
bcd70414 172\r
6fcb2d91 173 @retval EFI_SUCCESS The data was writen to the device sucessfully.\r
174 @retval EFI_UNSUPPORTED The Offset is not valid for this device.\r
175 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
176 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
bcd70414 177**/\r
c3902377 178EFI_STATUS\r
179EFIAPI\r
180IsaIoIoWrite (\r
6fcb2d91 181 IN EFI_ISA_IO_PROTOCOL *This,\r
182 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,\r
183 IN UINT32 Offset,\r
184 IN UINTN Count,\r
185 IN VOID *Buffer\r
c3902377 186 )\r
c3902377 187{\r
188 EFI_STATUS Status;\r
189 ISA_IO_DEVICE *IsaIoDevice;\r
190\r
191 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
192\r
193 //\r
194 // Verify Isa IO Access\r
195 //\r
196 Status = IsaIoVerifyAccess (\r
197 IsaIoDevice,\r
198 IsaAccessTypeIo,\r
199 Width,\r
200 Count,\r
6fcb2d91 201 Offset\r
c3902377 202 );\r
203 if (EFI_ERROR (Status)) {\r
204 return Status;\r
205 }\r
6fcb2d91 206\r
c3902377 207 Status = IsaIoDevice->PciIo->Io.Write (\r
208 IsaIoDevice->PciIo,\r
209 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
210 EFI_PCI_IO_PASS_THROUGH_BAR,\r
211 Offset,\r
212 Count,\r
213 Buffer\r
214 );\r
215\r
216 if (EFI_ERROR (Status)) {\r
ee686203 217 REPORT_STATUS_CODE (\r
218 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
219 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
220 );\r
c3902377 221 }\r
222\r
223 return Status;\r
224}\r
225\r
bcd70414 226/**\r
6fcb2d91 227 Writes an 8-bit I/O Port\r
bcd70414 228\r
6fcb2d91 229 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
0a6f4824 230 @param[in] Offset The offset in ISA IO space to start the IO operation.\r
6fcb2d91 231 @param[in] Value The data to write port.\r
bcd70414 232\r
6fcb2d91 233 @retval EFI_SUCCESS Success.\r
234 @retval EFI_INVALID_PARAMETER Parameter is invalid.\r
235 @retval EFI_UNSUPPORTED The address range specified by Offset is not valid.\r
236 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
bcd70414 237**/\r
c3902377 238EFI_STATUS\r
239WritePort (\r
6fcb2d91 240 IN EFI_ISA_IO_PROTOCOL *This,\r
241 IN UINT32 Offset,\r
242 IN UINT8 Value\r
c3902377 243 )\r
c3902377 244{\r
245 EFI_STATUS Status;\r
246 ISA_IO_DEVICE *IsaIoDevice;\r
247\r
248 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
249\r
c3902377 250 Status = IsaIoDevice->PciIo->Io.Write (\r
251 IsaIoDevice->PciIo,\r
252 EfiPciIoWidthUint8,\r
253 EFI_PCI_IO_PASS_THROUGH_BAR,\r
254 Offset,\r
255 1,\r
256 &Value\r
257 );\r
258 if (EFI_ERROR (Status)) {\r
ee686203 259 REPORT_STATUS_CODE (\r
260 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
261 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
262 );\r
c3902377 263 return Status;\r
264 }\r
265\r
266 gBS->Stall (50);\r
267\r
268 return EFI_SUCCESS;\r
269}\r
270\r
bcd70414 271/**\r
272 Writes I/O operation base address and count number to a 8 bit I/O Port.\r
273\r
6fcb2d91 274 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
275 @param[in] AddrOffset The address' offset.\r
276 @param[in] PageOffset The page's offest.\r
277 @param[in] CountOffset The count's offset.\r
278 @param[in] BaseAddress The base address.\r
0a6f4824
LG
279 @param[in] Count The number of I/O operations to perform.\r
280\r
6fcb2d91 281 @retval EFI_SUCCESS Success.\r
282 @retval EFI_INVALID_PARAMETER Parameter is invalid.\r
283 @retval EFI_UNSUPPORTED The address range specified by these Offsets and Count is not valid.\r
284 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
bcd70414 285**/\r
c3902377 286EFI_STATUS\r
287WriteDmaPort (\r
6fcb2d91 288 IN EFI_ISA_IO_PROTOCOL *This,\r
289 IN UINT32 AddrOffset,\r
290 IN UINT32 PageOffset,\r
291 IN UINT32 CountOffset,\r
292 IN UINT32 BaseAddress,\r
293 IN UINT16 Count\r
c3902377 294 )\r
c3902377 295{\r
296 EFI_STATUS Status;\r
297\r
298 Status = WritePort (This, AddrOffset, (UINT8) (BaseAddress & 0xff));\r
299 if (EFI_ERROR (Status)) {\r
300 return Status;\r
301 }\r
302\r
303 Status = WritePort (This, AddrOffset, (UINT8) ((BaseAddress >> 8) & 0xff));\r
304 if (EFI_ERROR (Status)) {\r
305 return Status;\r
306 }\r
307\r
308 Status = WritePort (This, PageOffset, (UINT8) ((BaseAddress >> 16) & 0xff));\r
309 if (EFI_ERROR (Status)) {\r
310 return Status;\r
311 }\r
312\r
313 Status = WritePort (This, CountOffset, (UINT8) (Count & 0xff));\r
314 if (EFI_ERROR (Status)) {\r
315 return Status;\r
316 }\r
317\r
318 Status = WritePort (This, CountOffset, (UINT8) ((Count >> 8) & 0xff));\r
6fcb2d91 319 return Status;\r
c3902377 320}\r
321\r
bcd70414 322/**\r
323 Unmaps a memory region for DMA\r
324\r
6fcb2d91 325 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
326 @param[in] Mapping The mapping value returned from EFI_ISA_IO.Map().\r
bcd70414 327\r
6fcb2d91 328 @retval EFI_SUCCESS The range was unmapped.\r
329 @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.\r
bcd70414 330**/\r
c3902377 331EFI_STATUS\r
332EFIAPI\r
333IsaIoUnmap (\r
6fcb2d91 334 IN EFI_ISA_IO_PROTOCOL *This,\r
335 IN VOID *Mapping\r
c3902377 336 )\r
c3902377 337{\r
338 ISA_MAP_INFO *IsaMapInfo;\r
339\r
340 //\r
10c1a4ca 341 // Check if DMA is supported.\r
c3902377 342 //\r
10c1a4ca 343 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {\r
c3902377 344 return EFI_UNSUPPORTED;\r
345 }\r
346\r
347 //\r
348 // See if the Map() operation associated with this Unmap() required a mapping\r
349 // buffer.If a mapping buffer was not required, then this function simply\r
350 // returns EFI_SUCCESS.\r
351 //\r
352 if (Mapping != NULL) {\r
353 //\r
354 // Get the MAP_INFO structure from Mapping\r
355 //\r
356 IsaMapInfo = (ISA_MAP_INFO *) Mapping;\r
357\r
358 //\r
359 // If this is a write operation from the Agent's point of view,\r
360 // then copy the contents of the mapped buffer into the real buffer\r
361 // so the processor can read the contents of the real buffer.\r
362 //\r
363 if (IsaMapInfo->Operation == EfiIsaIoOperationBusMasterWrite) {\r
364 CopyMem (\r
365 (VOID *) (UINTN) IsaMapInfo->HostAddress,\r
366 (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,\r
367 IsaMapInfo->NumberOfBytes\r
368 );\r
369 }\r
370 //\r
371 // Free the mapped buffer and the MAP_INFO structure.\r
372 //\r
373 gBS->FreePages (IsaMapInfo->MappedHostAddress, IsaMapInfo->NumberOfPages);\r
f423cbf1 374 FreePool (IsaMapInfo);\r
c3902377 375 }\r
376\r
377 return EFI_SUCCESS;\r
378}\r
379\r
bcd70414 380/**\r
6fcb2d91 381 Flushes any posted write data to the system memory.\r
bcd70414 382\r
6fcb2d91 383 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
bcd70414 384\r
6fcb2d91 385 @retval EFI_SUCCESS The buffers were flushed.\r
386 @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error.\r
bcd70414 387**/\r
c3902377 388EFI_STATUS\r
389EFIAPI\r
390IsaIoFlush (\r
6fcb2d91 391 IN EFI_ISA_IO_PROTOCOL *This\r
c3902377 392 )\r
c3902377 393{\r
394 EFI_STATUS Status;\r
395 ISA_IO_DEVICE *IsaIoDevice;\r
396\r
397 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
398\r
c3902377 399 Status = IsaIoDevice->PciIo->Flush (IsaIoDevice->PciIo);\r
400\r
401 if (EFI_ERROR (Status)) {\r
ee686203 402 REPORT_STATUS_CODE (\r
403 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
404 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
405 );\r
c3902377 406 }\r
407\r
408 return Status;\r
409}\r
410\r
bcd70414 411/**\r
412 Verifies access to an ISA device\r
413\r
6fcb2d91 414 @param[in] IsaIoDevice The ISA device to be verified.\r
415 @param[in] Type The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.\r
416 @param[in] Width The width of the memory operation.\r
0a6f4824
LG
417 @param[in] Count The number of memory operations to perform.\r
418 @param[in] Offset The offset in ISA memory space to start the memory operation.\r
419\r
6fcb2d91 420 @retval EFI_SUCCESS Verify success.\r
421 @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.\r
422 @retval EFI_UNSUPPORTED The device ont support the access type.\r
bcd70414 423**/\r
c3902377 424EFI_STATUS\r
425IsaIoVerifyAccess (\r
6fcb2d91 426 IN ISA_IO_DEVICE *IsaIoDevice,\r
427 IN ISA_ACCESS_TYPE Type,\r
428 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,\r
429 IN UINTN Count,\r
430 IN UINT32 Offset\r
c3902377 431 )\r
c3902377 432{\r
433 EFI_ISA_ACPI_RESOURCE *Item;\r
434 EFI_STATUS Status;\r
435\r
3d78c020 436 if ((UINT32)Width >= EfiIsaIoWidthMaximum ||\r
c3902377 437 Width == EfiIsaIoWidthReserved ||\r
438 Width == EfiIsaIoWidthFifoReserved ||\r
439 Width == EfiIsaIoWidthFillReserved\r
440 ) {\r
441 return EFI_INVALID_PARAMETER;\r
442 }\r
443\r
444 //\r
445 // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX\r
446 // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX\r
447 //\r
6fcb2d91 448 if (Width >= EfiIsaIoWidthFifoUint8 && Width < EfiIsaIoWidthFifoReserved) {\r
c3902377 449 Count = 1;\r
450 }\r
451\r
452 Width = (EFI_ISA_IO_PROTOCOL_WIDTH) (Width & 0x03);\r
453\r
454 Status = EFI_UNSUPPORTED;\r
455 Item = IsaIoDevice->IsaIo.ResourceList->ResourceItem;\r
456 while (Item->Type != EfiIsaAcpiResourceEndOfList) {\r
457 if ((Type == IsaAccessTypeMem && Item->Type == EfiIsaAcpiResourceMemory) ||\r
6fcb2d91 458 (Type == IsaAccessTypeIo && Item->Type == EfiIsaAcpiResourceIo)) {\r
459 if (Offset >= Item->StartRange && (Offset + Count * (UINT32)(1 << Width)) - 1 <= Item->EndRange) {\r
c3902377 460 return EFI_SUCCESS;\r
461 }\r
462\r
6fcb2d91 463 if (Offset >= Item->StartRange && Offset <= Item->EndRange) {\r
c3902377 464 Status = EFI_INVALID_PARAMETER;\r
465 }\r
466 }\r
467\r
468 Item++;\r
469 }\r
470\r
471 return Status;\r
472}\r
473\r
bcd70414 474/**\r
bcd70414 475 Performs an ISA Memory Read Cycle\r
476\r
6fcb2d91 477 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
478 @param[in] Width Specifies the width of the memory operation.\r
0a6f4824
LG
479 @param[in] Offset The offset in ISA memory space to start the memory operation.\r
480 @param[in] Count The number of memory operations to perform.\r
6fcb2d91 481 @param[out] Buffer The destination buffer to store the results\r
0a6f4824 482\r
6fcb2d91 483 @retval EFI_SUCCESS The data was read from the device successfully.\r
484 @retval EFI_UNSUPPORTED The Offset is not valid for this device.\r
485 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
486 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
bcd70414 487**/\r
c3902377 488EFI_STATUS\r
489EFIAPI\r
490IsaIoMemRead (\r
6fcb2d91 491 IN EFI_ISA_IO_PROTOCOL *This,\r
492 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,\r
493 IN UINT32 Offset,\r
494 IN UINTN Count,\r
495 OUT VOID *Buffer\r
c3902377 496 )\r
c3902377 497{\r
498 EFI_STATUS Status;\r
499 ISA_IO_DEVICE *IsaIoDevice;\r
500\r
501 //\r
10c1a4ca 502 // Check if ISA memory is supported.\r
c3902377 503 //\r
10c1a4ca 504 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {\r
c3902377 505 return EFI_UNSUPPORTED;\r
506 }\r
507\r
508 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
509\r
510 //\r
511 // Verify the Isa Io Access\r
512 //\r
513 Status = IsaIoVerifyAccess (\r
514 IsaIoDevice,\r
515 IsaAccessTypeMem,\r
516 Width,\r
517 Count,\r
6fcb2d91 518 Offset\r
c3902377 519 );\r
520 if (EFI_ERROR (Status)) {\r
521 return Status;\r
522 }\r
6fcb2d91 523\r
c3902377 524 Status = IsaIoDevice->PciIo->Mem.Read (\r
525 IsaIoDevice->PciIo,\r
526 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
527 EFI_PCI_IO_PASS_THROUGH_BAR,\r
528 Offset,\r
529 Count,\r
530 Buffer\r
531 );\r
532\r
533 if (EFI_ERROR (Status)) {\r
ee686203 534 REPORT_STATUS_CODE (\r
535 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
536 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
537 );\r
c3902377 538 }\r
539\r
540 return Status;\r
541}\r
542\r
bcd70414 543/**\r
544 Performs an ISA Memory Write Cycle\r
545\r
0a6f4824 546 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
6fcb2d91 547 @param[in] Width Specifies the width of the memory operation.\r
0a6f4824
LG
548 @param[in] Offset The offset in ISA memory space to start the memory operation.\r
549 @param[in] Count The number of memory operations to perform.\r
6fcb2d91 550 @param[in] Buffer The source buffer to write data from\r
bcd70414 551\r
6fcb2d91 552 @retval EFI_SUCCESS The data was written to the device sucessfully.\r
553 @retval EFI_UNSUPPORTED The Offset is not valid for this device.\r
554 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
555 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
bcd70414 556**/\r
c3902377 557EFI_STATUS\r
558EFIAPI\r
559IsaIoMemWrite (\r
6fcb2d91 560 IN EFI_ISA_IO_PROTOCOL *This,\r
561 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,\r
562 IN UINT32 Offset,\r
563 IN UINTN Count,\r
564 IN VOID *Buffer\r
c3902377 565 )\r
c3902377 566{\r
567 EFI_STATUS Status;\r
568 ISA_IO_DEVICE *IsaIoDevice;\r
569\r
570 //\r
10c1a4ca 571 // Check if ISA memory is supported.\r
c3902377 572 //\r
10c1a4ca 573 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {\r
c3902377 574 return EFI_UNSUPPORTED;\r
575 }\r
576\r
577 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
578\r
579 //\r
580 // Verify Isa IO Access\r
581 //\r
582 Status = IsaIoVerifyAccess (\r
583 IsaIoDevice,\r
584 IsaAccessTypeMem,\r
585 Width,\r
586 Count,\r
6fcb2d91 587 Offset\r
c3902377 588 );\r
589 if (EFI_ERROR (Status)) {\r
590 return Status;\r
591 }\r
6fcb2d91 592\r
c3902377 593 Status = IsaIoDevice->PciIo->Mem.Write (\r
594 IsaIoDevice->PciIo,\r
595 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
596 EFI_PCI_IO_PASS_THROUGH_BAR,\r
597 Offset,\r
598 Count,\r
599 Buffer\r
600 );\r
601\r
602 if (EFI_ERROR (Status)) {\r
ee686203 603 REPORT_STATUS_CODE (\r
604 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
605 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
606 );\r
c3902377 607 }\r
608\r
609 return Status;\r
610}\r
611\r
bcd70414 612/**\r
6fcb2d91 613 Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.\r
614\r
615 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
616 @param[in] Width Specifies the width of the memory copy operation.\r
0a6f4824 617 @param[in] DestOffset The offset of the destination\r
6fcb2d91 618 @param[in] SrcOffset The offset of the source\r
619 @param[in] Count The number of memory copy operations to perform\r
620\r
621 @retval EFI_SUCCESS The data was copied sucessfully.\r
622 @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device.\r
623 @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.\r
624 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
bcd70414 625**/\r
c3902377 626EFI_STATUS\r
627EFIAPI\r
628IsaIoCopyMem (\r
6fcb2d91 629 IN EFI_ISA_IO_PROTOCOL *This,\r
630 IN EFI_ISA_IO_PROTOCOL_WIDTH Width,\r
631 IN UINT32 DestOffset,\r
632 IN UINT32 SrcOffset,\r
633 IN UINTN Count\r
c3902377 634 )\r
c3902377 635{\r
636 EFI_STATUS Status;\r
637 ISA_IO_DEVICE *IsaIoDevice;\r
638\r
639 //\r
10c1a4ca 640 // Check if ISA memory is supported.\r
c3902377 641 //\r
10c1a4ca 642 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {\r
c3902377 643 return EFI_UNSUPPORTED;\r
644 }\r
645\r
646 IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);\r
647\r
648 //\r
649 // Verify Isa IO Access for destination and source\r
650 //\r
651 Status = IsaIoVerifyAccess (\r
652 IsaIoDevice,\r
653 IsaAccessTypeMem,\r
654 Width,\r
655 Count,\r
6fcb2d91 656 DestOffset\r
c3902377 657 );\r
658 if (EFI_ERROR (Status)) {\r
659 return Status;\r
660 }\r
661\r
662 Status = IsaIoVerifyAccess (\r
663 IsaIoDevice,\r
664 IsaAccessTypeMem,\r
665 Width,\r
666 Count,\r
6fcb2d91 667 SrcOffset\r
c3902377 668 );\r
669 if (EFI_ERROR (Status)) {\r
670 return Status;\r
671 }\r
6fcb2d91 672\r
c3902377 673 Status = IsaIoDevice->PciIo->CopyMem (\r
674 IsaIoDevice->PciIo,\r
675 (EFI_PCI_IO_PROTOCOL_WIDTH) Width,\r
676 EFI_PCI_IO_PASS_THROUGH_BAR,\r
677 DestOffset,\r
678 EFI_PCI_IO_PASS_THROUGH_BAR,\r
679 SrcOffset,\r
680 Count\r
681 );\r
682\r
683 if (EFI_ERROR (Status)) {\r
ee686203 684 REPORT_STATUS_CODE (\r
685 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
686 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
687 );\r
c3902377 688 }\r
689\r
690 return Status;\r
691}\r
692\r
bcd70414 693/**\r
694 Maps a memory region for DMA, note this implementation\r
695 only supports slave read/write operation to save code size.\r
696\r
6fcb2d91 697 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
0a6f4824
LG
698 @param Operation Indicates the type of DMA (slave or bus master), and if\r
699 the DMA operation is going to read or write to system memory.\r
700 @param ChannelNumber The slave channel number to use for this DMA operation.\r
701 If Operation and ChannelAttributes shows that this device\r
702 performs bus mastering DMA, then this field is ignored.\r
703 The legal range for this field is 0..7.\r
6fcb2d91 704 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation\r
0a6f4824
LG
705 @param HostAddress The system memory address to map to the device.\r
706 @param NumberOfBytes On input the number of bytes to map. On output the number\r
6fcb2d91 707 of bytes that were mapped.\r
0a6f4824
LG
708 @param DeviceAddress The resulting map address for the bus master device to use\r
709 to access the hosts HostAddress.\r
6fcb2d91 710 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().\r
711\r
712 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
713 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.\r
714 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.\r
715 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
716 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
bcd70414 717**/\r
c3902377 718EFI_STATUS\r
6fcb2d91 719IsaIoMapOnlySupportSlaveReadWrite (\r
720 IN EFI_ISA_IO_PROTOCOL *This,\r
721 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,\r
722 IN UINT8 ChannelNumber OPTIONAL,\r
723 IN UINT32 ChannelAttributes,\r
724 IN VOID *HostAddress,\r
725 IN OUT UINTN *NumberOfBytes,\r
726 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
727 OUT VOID **Mapping\r
c3902377 728 )\r
c3902377 729{\r
730 EFI_STATUS Status;\r
731 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
732 ISA_MAP_INFO *IsaMapInfo;\r
733 UINT8 DmaMode;\r
734 UINTN MaxNumberOfBytes;\r
735 UINT32 BaseAddress;\r
736 UINT16 Count;\r
c3902377 737 UINT8 DmaMask;\r
738 UINT8 DmaClear;\r
739 UINT8 DmaChannelMode;\r
0a6f4824 740\r
c3902377 741 if ((NULL == This) ||\r
742 (NULL == HostAddress) ||\r
743 (NULL == NumberOfBytes) ||\r
744 (NULL == DeviceAddress) ||\r
745 (NULL == Mapping)\r
746 ) {\r
747 return EFI_INVALID_PARAMETER;\r
748 }\r
749\r
c3902377 750 //\r
751 // Initialize the return values to their defaults\r
752 //\r
753 *Mapping = NULL;\r
754\r
755 //\r
756 // Make sure the Operation parameter is valid.\r
757 // Light IsaIo only supports two operations.\r
758 //\r
0a6f4824 759 if (!(Operation == EfiIsaIoOperationSlaveRead ||\r
c3902377 760 Operation == EfiIsaIoOperationSlaveWrite)) {\r
761 return EFI_INVALID_PARAMETER;\r
762 }\r
763\r
764 if (ChannelNumber >= 4) {\r
765 //\r
766 // The Light IsaIo doesn't support channelNumber larger than 4.\r
767 //\r
768 return EFI_INVALID_PARAMETER;\r
769 }\r
770\r
771 //\r
772 // Map the HostAddress to a DeviceAddress.\r
773 //\r
774 PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
6fcb2d91 775 if ((PhysicalAddress + *NumberOfBytes) > ISA_MAX_MEMORY_ADDRESS) {\r
c3902377 776 //\r
777 // Common Buffer operations can not be remapped. If the common buffer\r
778 // is above 16MB, then it is not possible to generate a mapping, so return\r
779 // an error.\r
780 //\r
781 if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {\r
782 return EFI_UNSUPPORTED;\r
783 }\r
784 //\r
785 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()\r
786 // is called later.\r
787 //\r
788 IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));\r
789 if (IsaMapInfo == NULL) {\r
790 *NumberOfBytes = 0;\r
791 return EFI_OUT_OF_RESOURCES;\r
792 }\r
793 //\r
794 // Return a pointer to the MAP_INFO structure in Mapping\r
795 //\r
796 *Mapping = IsaMapInfo;\r
797\r
798 //\r
799 // Initialize the MAP_INFO structure\r
800 //\r
801 IsaMapInfo->Operation = Operation;\r
802 IsaMapInfo->NumberOfBytes = *NumberOfBytes;\r
803 IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);\r
804 IsaMapInfo->HostAddress = PhysicalAddress;\r
805 IsaMapInfo->MappedHostAddress = ISA_MAX_MEMORY_ADDRESS - 1;\r
806\r
807 //\r
808 // Allocate a buffer below 16MB to map the transfer to.\r
809 //\r
810 Status = gBS->AllocatePages (\r
811 AllocateMaxAddress,\r
812 EfiBootServicesData,\r
813 IsaMapInfo->NumberOfPages,\r
814 &IsaMapInfo->MappedHostAddress\r
815 );\r
816 if (EFI_ERROR (Status)) {\r
f423cbf1 817 FreePool (IsaMapInfo);\r
c3902377 818 *NumberOfBytes = 0;\r
819 *Mapping = NULL;\r
820 return Status;\r
821 }\r
822 //\r
823 // If this is a read operation from the DMA agents's point of view,\r
824 // then copy the contents of the real buffer into the mapped buffer\r
825 // so the DMA agent can read the contents of the real buffer.\r
826 //\r
827 if (Operation == EfiIsaIoOperationSlaveRead) {\r
828 CopyMem (\r
829 (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,\r
830 (VOID *) (UINTN) IsaMapInfo->HostAddress,\r
831 IsaMapInfo->NumberOfBytes\r
832 );\r
833 }\r
834 //\r
835 // The DeviceAddress is the address of the maped buffer below 16 MB\r
836 //\r
837 *DeviceAddress = IsaMapInfo->MappedHostAddress;\r
838 } else {\r
839 //\r
840 // The transfer is below 16 MB, so the DeviceAddress is simply the\r
841 // HostAddress\r
842 //\r
843 *DeviceAddress = PhysicalAddress;\r
844 }\r
0a6f4824 845\r
c3902377 846 //\r
847 // Figure out what to program into the DMA Channel Mode Register\r
848 //\r
849 DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));\r
850 if (Operation == EfiIsaIoOperationSlaveRead) {\r
851 DmaMode |= V_8237_DMA_CHMODE_MEM2IO;\r
852 } else {\r
853 DmaMode |= V_8237_DMA_CHMODE_IO2MEM;\r
854 }\r
855 //\r
856 // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo\r
857 //\r
858 DmaMode |= V_8237_DMA_CHMODE_SINGLE;\r
859\r
860 //\r
861 // A Slave DMA transfer can not cross a 64K boundary.\r
862 // Compute *NumberOfBytes based on this restriction.\r
863 //\r
864 MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);\r
865 if (*NumberOfBytes > MaxNumberOfBytes) {\r
866 *NumberOfBytes = MaxNumberOfBytes;\r
867 }\r
868 //\r
869 // Compute the values to program into the BaseAddress and Count registers\r
870 // of the Slave DMA controller\r
871 //\r
872 BaseAddress = (UINT32) (*DeviceAddress);\r
873 Count = (UINT16) (*NumberOfBytes - 1);\r
874 //\r
875 // Program the DMA Write Single Mask Register for ChannelNumber\r
876 // Clear the DMA Byte Pointer Register\r
877 //\r
878 DmaMask = R_8237_DMA_WRSMSK_CH0_3;\r
879 DmaClear = R_8237_DMA_CBPR_CH0_3;\r
880 DmaChannelMode = R_8237_DMA_CHMODE_CH0_3;\r
881\r
882 Status = WritePort (\r
883 This,\r
884 DmaMask,\r
885 (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))\r
886 );\r
887 if (EFI_ERROR (Status)) {\r
888 return Status;\r
889 }\r
890\r
891 Status = WritePort (\r
892 This,\r
893 DmaClear,\r
894 (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))\r
895 );\r
896 if (EFI_ERROR (Status)) {\r
897 return Status;\r
898 }\r
899\r
900 Status = WritePort (This, DmaChannelMode, DmaMode);\r
901 if (EFI_ERROR (Status)) {\r
902 return Status;\r
903 }\r
904\r
905 Status = WriteDmaPort (\r
906 This,\r
6fcb2d91 907 mDmaRegisters[ChannelNumber].Address,\r
908 mDmaRegisters[ChannelNumber].Page,\r
909 mDmaRegisters[ChannelNumber].Count,\r
c3902377 910 BaseAddress,\r
911 Count\r
912 );\r
913 if (EFI_ERROR (Status)) {\r
914 return Status;\r
915 }\r
916\r
917 Status = WritePort (\r
918 This,\r
919 DmaMask,\r
920 (UINT8) (ChannelNumber & 0x03)\r
921 );\r
922 if (EFI_ERROR (Status)) {\r
923 return Status;\r
924 }\r
925\r
926 return EFI_SUCCESS;\r
927}\r
928\r
bcd70414 929/**\r
0a6f4824 930 Maps a memory region for DMA. This implementation implement the\r
bcd70414 931 the full mapping support.\r
932\r
6fcb2d91 933 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
0a6f4824
LG
934 @param Operation Indicates the type of DMA (slave or bus master), and if\r
935 the DMA operation is going to read or write to system memory.\r
936 @param ChannelNumber The slave channel number to use for this DMA operation.\r
937 If Operation and ChannelAttributes shows that this device\r
938 performs bus mastering DMA, then this field is ignored.\r
939 The legal range for this field is 0..7.\r
6fcb2d91 940 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation\r
0a6f4824
LG
941 @param HostAddress The system memory address to map to the device.\r
942 @param NumberOfBytes On input the number of bytes to map. On output the number\r
6fcb2d91 943 of bytes that were mapped.\r
0a6f4824
LG
944 @param DeviceAddress The resulting map address for the bus master device to use\r
945 to access the hosts HostAddress.\r
6fcb2d91 946 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().\r
bcd70414 947\r
948 @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.\r
949 @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.\r
950 @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.\r
951 @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.\r
952 @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.\r
bcd70414 953**/\r
c3902377 954EFI_STATUS\r
6fcb2d91 955IsaIoMapFullSupport (\r
c3902377 956 IN EFI_ISA_IO_PROTOCOL *This,\r
957 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,\r
958 IN UINT8 ChannelNumber OPTIONAL,\r
959 IN UINT32 ChannelAttributes,\r
960 IN VOID *HostAddress,\r
961 IN OUT UINTN *NumberOfBytes,\r
962 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
963 OUT VOID **Mapping\r
964 )\r
c3902377 965{\r
966 EFI_STATUS Status;\r
967 BOOLEAN Master;\r
968 BOOLEAN Read;\r
969 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
970 ISA_MAP_INFO *IsaMapInfo;\r
971 UINT8 DmaMode;\r
972 UINTN MaxNumberOfBytes;\r
973 UINT32 BaseAddress;\r
974 UINT16 Count;\r
c3902377 975 UINT8 DmaMask;\r
976 UINT8 DmaClear;\r
977 UINT8 DmaChannelMode;\r
978\r
979 if ((NULL == This) ||\r
980 (NULL == HostAddress) ||\r
981 (NULL == NumberOfBytes) ||\r
982 (NULL == DeviceAddress) ||\r
983 (NULL == Mapping)\r
984 ) {\r
985 return EFI_INVALID_PARAMETER;\r
986 }\r
987\r
c3902377 988 //\r
989 // Initialize the return values to their defaults\r
990 //\r
991 *Mapping = NULL;\r
992\r
993 //\r
994 // Make sure the Operation parameter is valid\r
995 //\r
3d78c020 996 if ((UINT32)Operation >= EfiIsaIoOperationMaximum) {\r
c3902377 997 return EFI_INVALID_PARAMETER;\r
998 }\r
aa950314 999\r
1000 if (ChannelNumber >= 8) {\r
1001 return EFI_INVALID_PARAMETER;\r
1002 }\r
1003\r
c3902377 1004 //\r
1005 // See if this is a Slave DMA Operation\r
1006 //\r
1007 Master = TRUE;\r
1008 Read = FALSE;\r
1009 if (Operation == EfiIsaIoOperationSlaveRead) {\r
1010 Operation = EfiIsaIoOperationBusMasterRead;\r
1011 Master = FALSE;\r
1012 Read = TRUE;\r
1013 }\r
1014\r
1015 if (Operation == EfiIsaIoOperationSlaveWrite) {\r
1016 Operation = EfiIsaIoOperationBusMasterWrite;\r
1017 Master = FALSE;\r
1018 Read = FALSE;\r
1019 }\r
1020\r
1021 if (!Master) {\r
1022 //\r
1023 // Make sure that ChannelNumber is a valid channel number\r
1024 // Channel 4 is used to cascade, so it is illegal.\r
1025 //\r
1026 if (ChannelNumber == 4 || ChannelNumber > 7) {\r
1027 return EFI_INVALID_PARAMETER;\r
1028 }\r
1029 //\r
1030 // This implementation only support COMPATIBLE DMA Transfers\r
1031 //\r
0a2dfa19 1032 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE) == 0) {\r
c3902377 1033 return EFI_INVALID_PARAMETER;\r
1034 }\r
1035\r
0a2dfa19 1036 if ((ChannelAttributes &\r
1037 (EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A |\r
1038 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B |\r
1039 EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C)) != 0) {\r
c3902377 1040 return EFI_INVALID_PARAMETER;\r
1041 }\r
1042\r
1043 if (ChannelNumber < 4) {\r
1044 //\r
1045 // If this is Channel 0..3, then the width must be 8 bit\r
1046 //\r
0a2dfa19 1047 if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) == 0) ||\r
1048 ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) != 0)\r
c3902377 1049 ) {\r
1050 return EFI_INVALID_PARAMETER;\r
1051 }\r
1052 } else {\r
1053 //\r
1054 // If this is Channel 4..7, then the width must be 16 bit\r
1055 //\r
0a2dfa19 1056 if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) != 0) ||\r
1057 ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) == 0)) {\r
c3902377 1058 return EFI_INVALID_PARAMETER;\r
1059 }\r
1060 }\r
1061 //\r
1062 // Either Demand Mode or Single Mode must be selected, but not both\r
1063 //\r
0a2dfa19 1064 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {\r
1065 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {\r
c3902377 1066 return EFI_INVALID_PARAMETER;\r
1067 }\r
1068 } else {\r
0a2dfa19 1069 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) == 0) {\r
c3902377 1070 return EFI_INVALID_PARAMETER;\r
1071 }\r
1072 }\r
1073 }\r
1074 //\r
1075 // Map the HostAddress to a DeviceAddress.\r
1076 //\r
1077 PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;\r
1078 if ((PhysicalAddress +*NumberOfBytes) > ISA_MAX_MEMORY_ADDRESS) {\r
1079 //\r
1080 // Common Buffer operations can not be remapped. If the common buffer\r
1081 // is above 16MB, then it is not possible to generate a mapping, so return\r
1082 // an error.\r
1083 //\r
1084 if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {\r
1085 return EFI_UNSUPPORTED;\r
1086 }\r
1087 //\r
1088 // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()\r
1089 // is called later.\r
1090 //\r
1091 IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));\r
1092 if (IsaMapInfo == NULL) {\r
1093 *NumberOfBytes = 0;\r
1094 return EFI_OUT_OF_RESOURCES;\r
1095 }\r
1096 //\r
1097 // Return a pointer to the MAP_INFO structure in Mapping\r
1098 //\r
1099 *Mapping = IsaMapInfo;\r
1100\r
1101 //\r
1102 // Initialize the MAP_INFO structure\r
1103 //\r
1104 IsaMapInfo->Operation = Operation;\r
1105 IsaMapInfo->NumberOfBytes = *NumberOfBytes;\r
1106 IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);\r
1107 IsaMapInfo->HostAddress = PhysicalAddress;\r
1108 IsaMapInfo->MappedHostAddress = ISA_MAX_MEMORY_ADDRESS - 1;\r
1109\r
1110 //\r
1111 // Allocate a buffer below 16MB to map the transfer to.\r
1112 //\r
1113 Status = gBS->AllocatePages (\r
1114 AllocateMaxAddress,\r
1115 EfiBootServicesData,\r
1116 IsaMapInfo->NumberOfPages,\r
1117 &IsaMapInfo->MappedHostAddress\r
1118 );\r
1119 if (EFI_ERROR (Status)) {\r
f423cbf1 1120 FreePool (IsaMapInfo);\r
c3902377 1121 *NumberOfBytes = 0;\r
1122 *Mapping = NULL;\r
1123 return Status;\r
1124 }\r
1125 //\r
1126 // If this is a read operation from the DMA agents's point of view,\r
1127 // then copy the contents of the real buffer into the mapped buffer\r
1128 // so the DMA agent can read the contents of the real buffer.\r
1129 //\r
1130 if (Operation == EfiIsaIoOperationBusMasterRead) {\r
1131 CopyMem (\r
1132 (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,\r
1133 (VOID *) (UINTN) IsaMapInfo->HostAddress,\r
1134 IsaMapInfo->NumberOfBytes\r
1135 );\r
1136 }\r
1137 //\r
1138 // The DeviceAddress is the address of the maped buffer below 16 MB\r
1139 //\r
1140 *DeviceAddress = IsaMapInfo->MappedHostAddress;\r
1141 } else {\r
1142 //\r
1143 // The transfer is below 16 MB, so the DeviceAddress is simply the\r
1144 // HostAddress\r
1145 //\r
1146 *DeviceAddress = PhysicalAddress;\r
1147 }\r
1148 //\r
1149 // If this is a Bus Master operation then return\r
1150 //\r
1151 if (Master) {\r
1152 return EFI_SUCCESS;\r
1153 }\r
1154 //\r
1155 // Figure out what to program into the DMA Channel Mode Register\r
1156 //\r
1157 DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));\r
1158 if (Read) {\r
1159 DmaMode |= V_8237_DMA_CHMODE_MEM2IO;\r
1160 } else {\r
1161 DmaMode |= V_8237_DMA_CHMODE_IO2MEM;\r
1162 }\r
1163\r
0a2dfa19 1164 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE) != 0) {\r
c3902377 1165 DmaMode |= B_8237_DMA_CHMODE_AE;\r
1166 }\r
1167\r
0a2dfa19 1168 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {\r
c3902377 1169 DmaMode |= V_8237_DMA_CHMODE_DEMAND;\r
1170 }\r
1171\r
0a2dfa19 1172 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {\r
c3902377 1173 DmaMode |= V_8237_DMA_CHMODE_SINGLE;\r
1174 }\r
1175 //\r
1176 // A Slave DMA transfer can not cross a 64K boundary.\r
1177 // Compute *NumberOfBytes based on this restriction.\r
1178 //\r
1179 MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);\r
1180 if (*NumberOfBytes > MaxNumberOfBytes) {\r
1181 *NumberOfBytes = MaxNumberOfBytes;\r
1182 }\r
1183 //\r
1184 // Compute the values to program into the BaseAddress and Count registers\r
1185 // of the Slave DMA controller\r
1186 //\r
1187 if (ChannelNumber < 4) {\r
1188 BaseAddress = (UINT32) (*DeviceAddress);\r
1189 Count = (UINT16) (*NumberOfBytes - 1);\r
1190 } else {\r
1191 BaseAddress = (UINT32) (((UINT32) (*DeviceAddress) & 0xff0000) | (((UINT32) (*DeviceAddress) & 0xffff) >> 1));\r
1192 Count = (UINT16) ((*NumberOfBytes - 1) >> 1);\r
1193 }\r
1194 //\r
1195 // Program the DMA Write Single Mask Register for ChannelNumber\r
1196 // Clear the DMA Byte Pointer Register\r
1197 //\r
1198 if (ChannelNumber < 4) {\r
1199 DmaMask = R_8237_DMA_WRSMSK_CH0_3;\r
1200 DmaClear = R_8237_DMA_CBPR_CH0_3;\r
1201 DmaChannelMode = R_8237_DMA_CHMODE_CH0_3;\r
1202 } else {\r
1203 DmaMask = R_8237_DMA_WRSMSK_CH4_7;\r
1204 DmaClear = R_8237_DMA_CBPR_CH4_7;\r
1205 DmaChannelMode = R_8237_DMA_CHMODE_CH4_7;\r
1206 }\r
1207\r
1208 Status = WritePort (\r
1209 This,\r
1210 DmaMask,\r
1211 (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))\r
1212 );\r
1213 if (EFI_ERROR (Status)) {\r
1214 return Status;\r
1215 }\r
1216\r
1217 Status = WritePort (\r
1218 This,\r
1219 DmaClear,\r
1220 (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))\r
1221 );\r
1222 if (EFI_ERROR (Status)) {\r
1223 return Status;\r
1224 }\r
1225\r
1226 Status = WritePort (This, DmaChannelMode, DmaMode);\r
1227 if (EFI_ERROR (Status)) {\r
1228 return Status;\r
1229 }\r
1230\r
1231 Status = WriteDmaPort (\r
1232 This,\r
6fcb2d91 1233 mDmaRegisters[ChannelNumber].Address,\r
1234 mDmaRegisters[ChannelNumber].Page,\r
1235 mDmaRegisters[ChannelNumber].Count,\r
c3902377 1236 BaseAddress,\r
1237 Count\r
1238 );\r
1239 if (EFI_ERROR (Status)) {\r
1240 return Status;\r
1241 }\r
1242\r
1243 Status = WritePort (\r
1244 This,\r
1245 DmaMask,\r
1246 (UINT8) (ChannelNumber & 0x03)\r
1247 );\r
1248 if (EFI_ERROR (Status)) {\r
1249 return Status;\r
1250 }\r
1251\r
1252 return EFI_SUCCESS;\r
1253}\r
1254\r
bcd70414 1255/**\r
1256 Maps a memory region for DMA\r
1257\r
6fcb2d91 1258 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
0a6f4824
LG
1259 @param Operation Indicates the type of DMA (slave or bus master), and if\r
1260 the DMA operation is going to read or write to system memory.\r
1261 @param ChannelNumber The slave channel number to use for this DMA operation.\r
1262 If Operation and ChannelAttributes shows that this device\r
1263 performs bus mastering DMA, then this field is ignored.\r
1264 The legal range for this field is 0..7.\r
6fcb2d91 1265 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation\r
0a6f4824
LG
1266 @param HostAddress The system memory address to map to the device.\r
1267 @param NumberOfBytes On input the number of bytes to map. On output the number\r
6fcb2d91 1268 of bytes that were mapped.\r
0a6f4824
LG
1269 @param DeviceAddress The resulting map address for the bus master device to use\r
1270 to access the hosts HostAddress.\r
6fcb2d91 1271 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().\r
1272\r
1273 @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.\r
1274 @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.\r
1275 @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.\r
1276 @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.\r
1277 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
bcd70414 1278**/\r
c3902377 1279EFI_STATUS\r
1280EFIAPI\r
1281IsaIoMap (\r
6fcb2d91 1282 IN EFI_ISA_IO_PROTOCOL *This,\r
1283 IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,\r
1284 IN UINT8 ChannelNumber OPTIONAL,\r
1285 IN UINT32 ChannelAttributes,\r
1286 IN VOID *HostAddress,\r
1287 IN OUT UINTN *NumberOfBytes,\r
1288 OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,\r
1289 OUT VOID **Mapping\r
c3902377 1290 )\r
c3902377 1291{\r
1292 //\r
10c1a4ca 1293 // Check if DMA is supported.\r
c3902377 1294 //\r
10c1a4ca 1295 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {\r
c3902377 1296 return EFI_UNSUPPORTED;\r
1297 }\r
1298 //\r
0a6f4824 1299 // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for\r
c3902377 1300 // ISA Bus Master.\r
1301 //\r
1302 // So we just return EFI_UNSUPPORTED for these functions.\r
1303 //\r
10c1a4ca 1304 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0) {\r
6fcb2d91 1305 return IsaIoMapOnlySupportSlaveReadWrite (\r
1306 This,\r
1307 Operation,\r
1308 ChannelNumber,\r
1309 ChannelAttributes,\r
1310 HostAddress,\r
1311 NumberOfBytes,\r
1312 DeviceAddress,\r
1313 Mapping\r
c3902377 1314 );\r
1315\r
1316 } else {\r
6fcb2d91 1317 return IsaIoMapFullSupport (\r
1318 This,\r
1319 Operation,\r
1320 ChannelNumber,\r
1321 ChannelAttributes,\r
1322 HostAddress,\r
1323 NumberOfBytes,\r
1324 DeviceAddress,\r
1325 Mapping\r
c3902377 1326 );\r
1327 }\r
1328}\r
bcd70414 1329\r
1330/**\r
6fcb2d91 1331 Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.\r
1332\r
1333 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
1334 @param[in] Type The type allocation to perform.\r
1335 @param[in] MemoryType The type of memory to allocate.\r
1336 @param[in] Pages The number of pages to allocate.\r
1337 @param[out] HostAddress A pointer to store the base address of the allocated range.\r
1338 @param[in] Attributes The requested bit mask of attributes for the allocated range.\r
1339\r
1340 @retval EFI_SUCCESS The requested memory pages were allocated.\r
1341 @retval EFI_INVALID_PARAMETER Type is invalid or MemoryType is invalid or HostAddress is NULL\r
0a6f4824 1342 @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified\r
6fcb2d91 1343 by HostAddress, Pages, and Type is not available for common buffer use.\r
1344 @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.\r
bcd70414 1345**/\r
c3902377 1346EFI_STATUS\r
1347EFIAPI\r
1348IsaIoAllocateBuffer (\r
6fcb2d91 1349 IN EFI_ISA_IO_PROTOCOL *This,\r
1350 IN EFI_ALLOCATE_TYPE Type,\r
1351 IN EFI_MEMORY_TYPE MemoryType,\r
1352 IN UINTN Pages,\r
1353 OUT VOID **HostAddress,\r
1354 IN UINT64 Attributes\r
c3902377 1355 )\r
c3902377 1356{\r
1357 EFI_STATUS Status;\r
1358 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
1359\r
1360 //\r
0a6f4824 1361 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for\r
c3902377 1362 // ISA Bus Master.\r
1363 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.\r
1364 //\r
10c1a4ca 1365 if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||\r
1366 ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {\r
c3902377 1367 return EFI_UNSUPPORTED;\r
1368 }\r
1369\r
1370 if (HostAddress == NULL) {\r
1371 return EFI_INVALID_PARAMETER;\r
1372 }\r
1373\r
3d78c020 1374 if ((UINT32)Type >= MaxAllocateType) {\r
c3902377 1375 return EFI_INVALID_PARAMETER;\r
1376 }\r
1377 //\r
1378 // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData\r
1379 //\r
1380 if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) {\r
1381 return EFI_INVALID_PARAMETER;\r
1382 }\r
1383\r
0a2dfa19 1384 if ((Attributes & ~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED)) != 0) {\r
c3902377 1385 return EFI_UNSUPPORTED;\r
1386 }\r
1387\r
1388 PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (ISA_MAX_MEMORY_ADDRESS - 1);\r
1389 if (Type == AllocateAddress) {\r
1390 if ((UINTN) (*HostAddress) >= ISA_MAX_MEMORY_ADDRESS) {\r
1391 return EFI_UNSUPPORTED;\r
1392 } else {\r
1393 PhysicalAddress = (UINTN) (*HostAddress);\r
1394 }\r
1395 }\r
1396\r
1397 if (Type == AllocateAnyPages) {\r
1398 Type = AllocateMaxAddress;\r
1399 }\r
1400\r
1401 Status = gBS->AllocatePages (Type, MemoryType, Pages, &PhysicalAddress);\r
1402 if (EFI_ERROR (Status)) {\r
ee686203 1403 REPORT_STATUS_CODE (\r
1404 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
1405 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
1406 );\r
c3902377 1407 return Status;\r
1408 }\r
1409\r
1410 *HostAddress = (VOID *) (UINTN) PhysicalAddress;\r
1411 return Status;\r
1412}\r
1413\r
bcd70414 1414/**\r
0a6f4824 1415 Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().\r
c3902377 1416\r
6fcb2d91 1417 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
1418 @param[in] Pages The number of pages to free.\r
1419 @param[in] HostAddress The base address of the allocated range.\r
c3902377 1420\r
6fcb2d91 1421 @retval EFI_SUCCESS The requested memory pages were freed.\r
1422 @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().\r
bcd70414 1423**/\r
bcd70414 1424EFI_STATUS\r
1425EFIAPI\r
1426IsaIoFreeBuffer (\r
6fcb2d91 1427 IN EFI_ISA_IO_PROTOCOL *This,\r
1428 IN UINTN Pages,\r
1429 IN VOID *HostAddress\r
bcd70414 1430 )\r
c3902377 1431{\r
6fcb2d91 1432 EFI_STATUS Status;\r
c3902377 1433\r
1434 //\r
0a6f4824 1435 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for\r
c3902377 1436 // ISA Bus Master.\r
1437 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.\r
1438 //\r
10c1a4ca 1439 if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||\r
1440 ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {\r
c3902377 1441 return EFI_UNSUPPORTED;\r
1442 }\r
1443\r
c3902377 1444 Status = gBS->FreePages (\r
6fcb2d91 1445 (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,\r
c3902377 1446 Pages\r
1447 );\r
1448 if (EFI_ERROR (Status)) {\r
ee686203 1449 REPORT_STATUS_CODE (\r
1450 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
1451 EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR\r
1452 );\r
c3902377 1453 }\r
1454\r
1455 return Status;\r
1456}\r
1457\r