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