]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaIo.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / IsaBusDxe / IsaIo.c
... / ...
CommitLineData
1/** @file\r
2 The implementation for EFI_ISA_IO_PROTOCOL.\r
3\r
4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
5SPDX-License-Identifier: BSD-2-Clause-Patent\r
6\r
7**/\r
8\r
9#include "InternalIsaIo.h"\r
10\r
11//\r
12// Module Variables\r
13//\r
14EFI_ISA_IO_PROTOCOL mIsaIoInterface = {\r
15 {\r
16 IsaIoMemRead,\r
17 IsaIoMemWrite\r
18 },\r
19 {\r
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
34EFI_ISA_DMA_REGISTERS mDmaRegisters[8] = {\r
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
77/**\r
78 Initializes an ISA I/O Instance\r
79\r
80 @param[in] IsaIoDevice The iso device to be initialized.\r
81 @param[in] IsaDeviceResourceList The resource list.\r
82\r
83**/\r
84VOID\r
85InitializeIsaIoInstance (\r
86 IN ISA_IO_DEVICE *IsaIoDevice,\r
87 IN EFI_ISA_ACPI_RESOURCE_LIST *IsaDeviceResourceList\r
88 )\r
89{\r
90 //\r
91 // Use the ISA IO Protocol structure template to initialize the ISA IO instance\r
92 //\r
93 CopyMem (\r
94 &IsaIoDevice->IsaIo,\r
95 &mIsaIoInterface,\r
96 sizeof (EFI_ISA_IO_PROTOCOL)\r
97 );\r
98\r
99 IsaIoDevice->IsaIo.ResourceList = IsaDeviceResourceList;\r
100}\r
101\r
102/**\r
103 Performs an ISA I/O Read Cycle\r
104\r
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
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
109 @param[out] Buffer The destination buffer to store the results\r
110\r
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
115**/\r
116EFI_STATUS\r
117EFIAPI\r
118IsaIoIoRead (\r
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
124 )\r
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
139 Offset\r
140 );\r
141 if (EFI_ERROR (Status)) {\r
142 return Status;\r
143 }\r
144\r
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
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
159 }\r
160\r
161 return Status;\r
162}\r
163\r
164/**\r
165 Performs an ISA I/O Write Cycle\r
166\r
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
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
171 @param[in] Buffer The source buffer to write data from\r
172\r
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
177**/\r
178EFI_STATUS\r
179EFIAPI\r
180IsaIoIoWrite (\r
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
186 )\r
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
201 Offset\r
202 );\r
203 if (EFI_ERROR (Status)) {\r
204 return Status;\r
205 }\r
206\r
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
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
221 }\r
222\r
223 return Status;\r
224}\r
225\r
226/**\r
227 Writes an 8-bit I/O Port\r
228\r
229 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
230 @param[in] Offset The offset in ISA IO space to start the IO operation.\r
231 @param[in] Value The data to write port.\r
232\r
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
237**/\r
238EFI_STATUS\r
239WritePort (\r
240 IN EFI_ISA_IO_PROTOCOL *This,\r
241 IN UINT32 Offset,\r
242 IN UINT8 Value\r
243 )\r
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
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
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
263 return Status;\r
264 }\r
265\r
266 gBS->Stall (50);\r
267\r
268 return EFI_SUCCESS;\r
269}\r
270\r
271/**\r
272 Writes I/O operation base address and count number to a 8 bit I/O Port.\r
273\r
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
279 @param[in] Count The number of I/O operations to perform.\r
280\r
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
285**/\r
286EFI_STATUS\r
287WriteDmaPort (\r
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
294 )\r
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
319 return Status;\r
320}\r
321\r
322/**\r
323 Unmaps a memory region for DMA\r
324\r
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
327\r
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
330**/\r
331EFI_STATUS\r
332EFIAPI\r
333IsaIoUnmap (\r
334 IN EFI_ISA_IO_PROTOCOL *This,\r
335 IN VOID *Mapping\r
336 )\r
337{\r
338 ISA_MAP_INFO *IsaMapInfo;\r
339\r
340 //\r
341 // Check if DMA is supported.\r
342 //\r
343 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {\r
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
374 FreePool (IsaMapInfo);\r
375 }\r
376\r
377 return EFI_SUCCESS;\r
378}\r
379\r
380/**\r
381 Flushes any posted write data to the system memory.\r
382\r
383 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
384\r
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
387**/\r
388EFI_STATUS\r
389EFIAPI\r
390IsaIoFlush (\r
391 IN EFI_ISA_IO_PROTOCOL *This\r
392 )\r
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
399 Status = IsaIoDevice->PciIo->Flush (IsaIoDevice->PciIo);\r
400\r
401 if (EFI_ERROR (Status)) {\r
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
406 }\r
407\r
408 return Status;\r
409}\r
410\r
411/**\r
412 Verifies access to an ISA device\r
413\r
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
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
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
423**/\r
424EFI_STATUS\r
425IsaIoVerifyAccess (\r
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
431 )\r
432{\r
433 EFI_ISA_ACPI_RESOURCE *Item;\r
434 EFI_STATUS Status;\r
435\r
436 if ((UINT32)Width >= EfiIsaIoWidthMaximum ||\r
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
448 if (Width >= EfiIsaIoWidthFifoUint8 && Width < EfiIsaIoWidthFifoReserved) {\r
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
458 (Type == IsaAccessTypeIo && Item->Type == EfiIsaAcpiResourceIo)) {\r
459 if (Offset >= Item->StartRange && (Offset + Count * (UINT32)(1 << Width)) - 1 <= Item->EndRange) {\r
460 return EFI_SUCCESS;\r
461 }\r
462\r
463 if (Offset >= Item->StartRange && Offset <= Item->EndRange) {\r
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
474/**\r
475 Performs an ISA Memory Read Cycle\r
476\r
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
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
481 @param[out] Buffer The destination buffer to store the results\r
482\r
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
487**/\r
488EFI_STATUS\r
489EFIAPI\r
490IsaIoMemRead (\r
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
496 )\r
497{\r
498 EFI_STATUS Status;\r
499 ISA_IO_DEVICE *IsaIoDevice;\r
500\r
501 //\r
502 // Check if ISA memory is supported.\r
503 //\r
504 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {\r
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
518 Offset\r
519 );\r
520 if (EFI_ERROR (Status)) {\r
521 return Status;\r
522 }\r
523\r
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
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
538 }\r
539\r
540 return Status;\r
541}\r
542\r
543/**\r
544 Performs an ISA Memory Write Cycle\r
545\r
546 @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
547 @param[in] Width Specifies the width of the memory operation.\r
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
550 @param[in] Buffer The source buffer to write data from\r
551\r
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
556**/\r
557EFI_STATUS\r
558EFIAPI\r
559IsaIoMemWrite (\r
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
565 )\r
566{\r
567 EFI_STATUS Status;\r
568 ISA_IO_DEVICE *IsaIoDevice;\r
569\r
570 //\r
571 // Check if ISA memory is supported.\r
572 //\r
573 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {\r
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
587 Offset\r
588 );\r
589 if (EFI_ERROR (Status)) {\r
590 return Status;\r
591 }\r
592\r
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
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
607 }\r
608\r
609 return Status;\r
610}\r
611\r
612/**\r
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
617 @param[in] DestOffset The offset of the destination\r
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
625**/\r
626EFI_STATUS\r
627EFIAPI\r
628IsaIoCopyMem (\r
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
634 )\r
635{\r
636 EFI_STATUS Status;\r
637 ISA_IO_DEVICE *IsaIoDevice;\r
638\r
639 //\r
640 // Check if ISA memory is supported.\r
641 //\r
642 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {\r
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
656 DestOffset\r
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
667 SrcOffset\r
668 );\r
669 if (EFI_ERROR (Status)) {\r
670 return Status;\r
671 }\r
672\r
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
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
688 }\r
689\r
690 return Status;\r
691}\r
692\r
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
697 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
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
704 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation\r
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
707 of bytes that were mapped.\r
708 @param DeviceAddress The resulting map address for the bus master device to use\r
709 to access the hosts HostAddress.\r
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
717**/\r
718EFI_STATUS\r
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
728 )\r
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
737 UINT8 DmaMask;\r
738 UINT8 DmaClear;\r
739 UINT8 DmaChannelMode;\r
740\r
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
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
759 if (!(Operation == EfiIsaIoOperationSlaveRead ||\r
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
775 if ((PhysicalAddress + *NumberOfBytes) > ISA_MAX_MEMORY_ADDRESS) {\r
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
817 FreePool (IsaMapInfo);\r
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
845\r
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
907 mDmaRegisters[ChannelNumber].Address,\r
908 mDmaRegisters[ChannelNumber].Page,\r
909 mDmaRegisters[ChannelNumber].Count,\r
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
929/**\r
930 Maps a memory region for DMA. This implementation implement the\r
931 the full mapping support.\r
932\r
933 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
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
940 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation\r
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
943 of bytes that were mapped.\r
944 @param DeviceAddress The resulting map address for the bus master device to use\r
945 to access the hosts HostAddress.\r
946 @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().\r
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
953**/\r
954EFI_STATUS\r
955IsaIoMapFullSupport (\r
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
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
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
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
996 if ((UINT32)Operation >= EfiIsaIoOperationMaximum) {\r
997 return EFI_INVALID_PARAMETER;\r
998 }\r
999\r
1000 if (ChannelNumber >= 8) {\r
1001 return EFI_INVALID_PARAMETER;\r
1002 }\r
1003\r
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
1032 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE) == 0) {\r
1033 return EFI_INVALID_PARAMETER;\r
1034 }\r
1035\r
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
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
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
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
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
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
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
1066 return EFI_INVALID_PARAMETER;\r
1067 }\r
1068 } else {\r
1069 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) == 0) {\r
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
1120 FreePool (IsaMapInfo);\r
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
1164 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE) != 0) {\r
1165 DmaMode |= B_8237_DMA_CHMODE_AE;\r
1166 }\r
1167\r
1168 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {\r
1169 DmaMode |= V_8237_DMA_CHMODE_DEMAND;\r
1170 }\r
1171\r
1172 if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {\r
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
1233 mDmaRegisters[ChannelNumber].Address,\r
1234 mDmaRegisters[ChannelNumber].Page,\r
1235 mDmaRegisters[ChannelNumber].Count,\r
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
1255/**\r
1256 Maps a memory region for DMA\r
1257\r
1258 @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.\r
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
1265 @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation\r
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
1268 of bytes that were mapped.\r
1269 @param DeviceAddress The resulting map address for the bus master device to use\r
1270 to access the hosts HostAddress.\r
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
1278**/\r
1279EFI_STATUS\r
1280EFIAPI\r
1281IsaIoMap (\r
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
1290 )\r
1291{\r
1292 //\r
1293 // Check if DMA is supported.\r
1294 //\r
1295 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {\r
1296 return EFI_UNSUPPORTED;\r
1297 }\r
1298 //\r
1299 // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for\r
1300 // ISA Bus Master.\r
1301 //\r
1302 // So we just return EFI_UNSUPPORTED for these functions.\r
1303 //\r
1304 if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0) {\r
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
1314 );\r
1315\r
1316 } else {\r
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
1326 );\r
1327 }\r
1328}\r
1329\r
1330/**\r
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
1342 @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified\r
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
1345**/\r
1346EFI_STATUS\r
1347EFIAPI\r
1348IsaIoAllocateBuffer (\r
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
1355 )\r
1356{\r
1357 EFI_STATUS Status;\r
1358 EFI_PHYSICAL_ADDRESS PhysicalAddress;\r
1359\r
1360 //\r
1361 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for\r
1362 // ISA Bus Master.\r
1363 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.\r
1364 //\r
1365 if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||\r
1366 ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {\r
1367 return EFI_UNSUPPORTED;\r
1368 }\r
1369\r
1370 if (HostAddress == NULL) {\r
1371 return EFI_INVALID_PARAMETER;\r
1372 }\r
1373\r
1374 if ((UINT32)Type >= MaxAllocateType) {\r
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
1384 if ((Attributes & ~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED)) != 0) {\r
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
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
1407 return Status;\r
1408 }\r
1409\r
1410 *HostAddress = (VOID *) (UINTN) PhysicalAddress;\r
1411 return Status;\r
1412}\r
1413\r
1414/**\r
1415 Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().\r
1416\r
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
1420\r
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
1423**/\r
1424EFI_STATUS\r
1425EFIAPI\r
1426IsaIoFreeBuffer (\r
1427 IN EFI_ISA_IO_PROTOCOL *This,\r
1428 IN UINTN Pages,\r
1429 IN VOID *HostAddress\r
1430 )\r
1431{\r
1432 EFI_STATUS Status;\r
1433\r
1434 //\r
1435 // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for\r
1436 // ISA Bus Master.\r
1437 // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.\r
1438 //\r
1439 if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||\r
1440 ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {\r
1441 return EFI_UNSUPPORTED;\r
1442 }\r
1443\r
1444 Status = gBS->FreePages (\r
1445 (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,\r
1446 Pages\r
1447 );\r
1448 if (EFI_ERROR (Status)) {\r
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
1453 }\r
1454\r
1455 return Status;\r
1456}\r
1457\r