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