1 /*++
2 
3 Copyright (c) 2005 - 2012, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13     PcatPciRootBridgeIo.c
14 
15 Abstract:
16 
17     EFI PC AT PCI Root Bridge Io Protocol
18 
19 Revision History
20 
21 --*/
22 
23 #include "PcatPciRootBridge.h"
24 
25 //
26 // Protocol Member Function Prototypes
27 //
28 EFI_STATUS
29 EFIAPI
30 PcatRootBridgeIoPollMem (
31   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
32   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
33   IN  UINT64                                 Address,
34   IN  UINT64                                 Mask,
35   IN  UINT64                                 Value,
36   IN  UINT64                                 Delay,
37   OUT UINT64                                 *Result
38   );
39 
40 EFI_STATUS
41 EFIAPI
42 PcatRootBridgeIoPollIo (
43   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
44   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
45   IN  UINT64                                 Address,
46   IN  UINT64                                 Mask,
47   IN  UINT64                                 Value,
48   IN  UINT64                                 Delay,
49   OUT UINT64                                 *Result
50   );
51 
52 EFI_STATUS
53 EFIAPI
54 PcatRootBridgeIoMemRead (
55   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
56   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
57   IN     UINT64                                 Address,
58   IN     UINTN                                  Count,
59   IN OUT VOID                                   *Buffer
60   );
61 
62 EFI_STATUS
63 EFIAPI
64 PcatRootBridgeIoMemWrite (
65   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
66   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
67   IN     UINT64                                 Address,
68   IN     UINTN                                  Count,
69   IN OUT VOID                                   *Buffer
70   );
71 
72 EFI_STATUS
73 EFIAPI
74 PcatRootBridgeIoCopyMem (
75   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
76   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
77   IN UINT64                                 DestAddress,
78   IN UINT64                                 SrcAddress,
79   IN UINTN                                  Count
80   );
81 
82 EFI_STATUS
83 EFIAPI
84 PcatRootBridgeIoPciRead (
85   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
86   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
87   IN     UINT64                                 Address,
88   IN     UINTN                                  Count,
89   IN OUT VOID                                   *Buffer
90   );
91 
92 EFI_STATUS
93 EFIAPI
94 PcatRootBridgeIoPciWrite (
95   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
96   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
97   IN     UINT64                                 Address,
98   IN     UINTN                                  Count,
99   IN OUT VOID                                   *Buffer
100   );
101 
102 EFI_STATUS
103 EFIAPI
104 PcatRootBridgeIoMap (
105   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL            *This,
106   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION  Operation,
107   IN     VOID                                       *HostAddress,
108   IN OUT UINTN                                      *NumberOfBytes,
109   OUT    EFI_PHYSICAL_ADDRESS                       *DeviceAddress,
110   OUT    VOID                                       **Mapping
111   );
112 
113 EFI_STATUS
114 EFIAPI
115 PcatRootBridgeIoUnmap (
116   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
117   IN VOID                             *Mapping
118   );
119 
120 EFI_STATUS
121 EFIAPI
122 PcatRootBridgeIoAllocateBuffer (
123   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
124   IN  EFI_ALLOCATE_TYPE                Type,
125   IN  EFI_MEMORY_TYPE                  MemoryType,
126   IN  UINTN                            Pages,
127   OUT VOID                             **HostAddress,
128   IN  UINT64                           Attributes
129   );
130 
131 EFI_STATUS
132 EFIAPI
133 PcatRootBridgeIoFreeBuffer (
134   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
135   IN  UINTN                            Pages,
136   OUT VOID                             *HostAddress
137   );
138 
139 EFI_STATUS
140 EFIAPI
141 PcatRootBridgeIoFlush (
142   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This
143   );
144 
145 EFI_STATUS
146 EFIAPI
147 PcatRootBridgeIoGetAttributes (
148   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
149   OUT UINT64                           *Supported,
150   OUT UINT64                           *Attributes
151   );
152 
153 EFI_STATUS
154 EFIAPI
155 PcatRootBridgeIoSetAttributes (
156   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
157   IN     UINT64                           Attributes,
158   IN OUT UINT64                           *ResourceBase,
159   IN OUT UINT64                           *ResourceLength
160   );
161 
162 EFI_STATUS
163 EFIAPI
164 PcatRootBridgeIoConfiguration (
165   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
166   OUT VOID                             **Resources
167   );
168 
169 //
170 // Private Function Prototypes
171 //
172 EFI_STATUS
173 EFIAPI
174 PcatRootBridgeIoMemRW (
175   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
176   IN  UINTN                                  Count,
177   IN  BOOLEAN                                InStrideFlag,
178   IN  PTR                                    In,
179   IN  BOOLEAN                                OutStrideFlag,
180   OUT PTR                                    Out
181   );
182 
183 EFI_STATUS
PcatRootBridgeIoConstructor(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * Protocol,IN UINTN SegmentNumber)184 PcatRootBridgeIoConstructor (
185   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *Protocol,
186   IN UINTN                            SegmentNumber
187   )
188 /*++
189 
190 Routine Description:
191 
192     Contruct the Pci Root Bridge Io protocol
193 
194 Arguments:
195 
196     Protocol - protocol to initialize
197 
198 Returns:
199 
200     None
201 
202 --*/
203 {
204   Protocol->ParentHandle   = NULL;
205 
206   Protocol->PollMem        = PcatRootBridgeIoPollMem;
207   Protocol->PollIo         = PcatRootBridgeIoPollIo;
208 
209   Protocol->Mem.Read       = PcatRootBridgeIoMemRead;
210   Protocol->Mem.Write      = PcatRootBridgeIoMemWrite;
211 
212   Protocol->Io.Read        = PcatRootBridgeIoIoRead;
213   Protocol->Io.Write       = PcatRootBridgeIoIoWrite;
214 
215   Protocol->CopyMem        = PcatRootBridgeIoCopyMem;
216 
217   Protocol->Pci.Read       = PcatRootBridgeIoPciRead;
218   Protocol->Pci.Write      = PcatRootBridgeIoPciWrite;
219 
220   Protocol->Map            = PcatRootBridgeIoMap;
221   Protocol->Unmap          = PcatRootBridgeIoUnmap;
222 
223   Protocol->AllocateBuffer = PcatRootBridgeIoAllocateBuffer;
224   Protocol->FreeBuffer     = PcatRootBridgeIoFreeBuffer;
225 
226   Protocol->Flush          = PcatRootBridgeIoFlush;
227 
228   Protocol->GetAttributes  = PcatRootBridgeIoGetAttributes;
229   Protocol->SetAttributes  = PcatRootBridgeIoSetAttributes;
230 
231   Protocol->Configuration  = PcatRootBridgeIoConfiguration;
232 
233   Protocol->SegmentNumber  = (UINT32)SegmentNumber;
234 
235   return EFI_SUCCESS;
236 }
237 
238 EFI_STATUS
239 EFIAPI
PcatRootBridgeIoPollMem(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINT64 Mask,IN UINT64 Value,IN UINT64 Delay,OUT UINT64 * Result)240 PcatRootBridgeIoPollMem (
241   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
242   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
243   IN  UINT64                                 Address,
244   IN  UINT64                                 Mask,
245   IN  UINT64                                 Value,
246   IN  UINT64                                 Delay,
247   OUT UINT64                                 *Result
248   )
249 {
250   EFI_STATUS  Status;
251   UINT64      NumberOfTicks;
252   UINT32      Remainder;
253 
254   if (Result == NULL) {
255     return EFI_INVALID_PARAMETER;
256   }
257 
258 
259   if ((UINT32)Width > EfiPciWidthUint64) {
260     return EFI_INVALID_PARAMETER;
261   }
262   //
263   // No matter what, always do a single poll.
264   //
265   Status = This->Mem.Read (This, Width, Address, 1, Result);
266   if ( EFI_ERROR(Status) ) {
267     return Status;
268   }
269   if ( (*Result & Mask) == Value ) {
270     return EFI_SUCCESS;
271   }
272 
273   if (Delay == 0) {
274     return EFI_SUCCESS;
275   } else {
276 
277     NumberOfTicks = DivU64x32Remainder (Delay, 100, &Remainder);
278     if ( Remainder !=0 ) {
279       NumberOfTicks += 1;
280     }
281     NumberOfTicks += 1;
282 
283     while ( NumberOfTicks ) {
284 
285       gBS->Stall (10);
286 
287       Status = This->Mem.Read (This, Width, Address, 1, Result);
288       if ( EFI_ERROR(Status) ) {
289         return Status;
290       }
291 
292       if ( (*Result & Mask) == Value ) {
293         return EFI_SUCCESS;
294       }
295 
296       NumberOfTicks -= 1;
297     }
298   }
299   return EFI_TIMEOUT;
300 }
301 
302 EFI_STATUS
303 EFIAPI
PcatRootBridgeIoPollIo(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINT64 Mask,IN UINT64 Value,IN UINT64 Delay,OUT UINT64 * Result)304 PcatRootBridgeIoPollIo (
305   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
306   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
307   IN  UINT64                                 Address,
308   IN  UINT64                                 Mask,
309   IN  UINT64                                 Value,
310   IN  UINT64                                 Delay,
311   OUT UINT64                                 *Result
312   )
313 {
314   EFI_STATUS  Status;
315   UINT64      NumberOfTicks;
316   UINT32       Remainder;
317 
318   if (Result == NULL) {
319     return EFI_INVALID_PARAMETER;
320   }
321 
322   if ((UINT32)Width > EfiPciWidthUint64) {
323     return EFI_INVALID_PARAMETER;
324   }
325   //
326   // No matter what, always do a single poll.
327   //
328   Status = This->Io.Read (This, Width, Address, 1, Result);
329   if ( EFI_ERROR(Status) ) {
330     return Status;
331   }
332   if ( (*Result & Mask) == Value ) {
333     return EFI_SUCCESS;
334   }
335 
336   if (Delay == 0) {
337     return EFI_SUCCESS;
338   } else {
339 
340     NumberOfTicks = DivU64x32Remainder (Delay, 100, &Remainder);
341     if ( Remainder !=0 ) {
342       NumberOfTicks += 1;
343     }
344     NumberOfTicks += 1;
345 
346     while ( NumberOfTicks ) {
347 
348       gBS->Stall(10);
349 
350       Status = This->Io.Read (This, Width, Address, 1, Result);
351       if ( EFI_ERROR(Status) ) {
352         return Status;
353       }
354 
355       if ( (*Result & Mask) == Value ) {
356         return EFI_SUCCESS;
357       }
358 
359       NumberOfTicks -= 1;
360     }
361   }
362   return EFI_TIMEOUT;
363 }
364 
365 BOOLEAN
PcatRootBridgeMemAddressValid(IN PCAT_PCI_ROOT_BRIDGE_INSTANCE * PrivateData,IN UINT64 Address)366 PcatRootBridgeMemAddressValid (
367   IN PCAT_PCI_ROOT_BRIDGE_INSTANCE  *PrivateData,
368   IN UINT64                         Address
369   )
370 {
371   if ((Address >= PrivateData->PciExpressBaseAddress) && (Address < PrivateData->PciExpressBaseAddress + 0x10000000)) {
372     return TRUE;
373   }
374   if ((Address >= PrivateData->MemBase) && (Address < PrivateData->MemLimit)) {
375     return TRUE;
376   }
377 
378   return FALSE;
379 }
380 
381 EFI_STATUS
382 EFIAPI
PcatRootBridgeIoMemRead(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN OUT VOID * Buffer)383 PcatRootBridgeIoMemRead (
384   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
385   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
386   IN     UINT64                                 Address,
387   IN     UINTN                                  Count,
388   IN OUT VOID                                   *Buffer
389   )
390 {
391   PCAT_PCI_ROOT_BRIDGE_INSTANCE  *PrivateData;
392   UINTN                          AlignMask;
393   PTR                            In;
394   PTR                            Out;
395 
396   if ( Buffer == NULL ) {
397     return EFI_INVALID_PARAMETER;
398   }
399 
400   PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);
401 
402   if (!PcatRootBridgeMemAddressValid (PrivateData, Address)) {
403     return EFI_INVALID_PARAMETER;
404   }
405 
406   AlignMask = (1 << (Width & 0x03)) - 1;
407   if (Address & AlignMask) {
408     return EFI_INVALID_PARAMETER;
409   }
410 
411   Address += PrivateData->PhysicalMemoryBase;
412 
413   In.buf  = Buffer;
414   Out.buf = (VOID *)(UINTN) Address;
415   if ((UINT32)Width <= EfiPciWidthUint64) {
416     return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out);
417   }
418   if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
419     return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out);
420   }
421   if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) {
422     return PcatRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out);
423   }
424 
425   return EFI_INVALID_PARAMETER;
426 }
427 
428 EFI_STATUS
429 EFIAPI
PcatRootBridgeIoMemWrite(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN OUT VOID * Buffer)430 PcatRootBridgeIoMemWrite (
431   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
432   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
433   IN     UINT64                                 Address,
434   IN     UINTN                                  Count,
435   IN OUT VOID                                   *Buffer
436   )
437 {
438   PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
439   UINTN  AlignMask;
440   PTR    In;
441   PTR    Out;
442 
443   if ( Buffer == NULL ) {
444     return EFI_INVALID_PARAMETER;
445   }
446 
447   PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);
448 
449   if (!PcatRootBridgeMemAddressValid (PrivateData, Address)) {
450     return EFI_INVALID_PARAMETER;
451   }
452 
453   AlignMask = (1 << (Width & 0x03)) - 1;
454   if (Address & AlignMask) {
455     return EFI_INVALID_PARAMETER;
456   }
457 
458   Address += PrivateData->PhysicalMemoryBase;
459 
460   In.buf  = (VOID *)(UINTN) Address;
461   Out.buf = Buffer;
462   if ((UINT32)Width <= EfiPciWidthUint64) {
463     return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, TRUE, Out);
464   }
465   if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
466     return PcatRootBridgeIoMemRW (Width, Count, FALSE, In, TRUE, Out);
467   }
468   if (Width >= EfiPciWidthFillUint8 && Width <= EfiPciWidthFillUint64) {
469     return PcatRootBridgeIoMemRW (Width, Count, TRUE, In, FALSE, Out);
470   }
471 
472   return EFI_INVALID_PARAMETER;
473 }
474 
475 EFI_STATUS
476 EFIAPI
PcatRootBridgeIoCopyMem(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 DestAddress,IN UINT64 SrcAddress,IN UINTN Count)477 PcatRootBridgeIoCopyMem (
478   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
479   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
480   IN UINT64                                 DestAddress,
481   IN UINT64                                 SrcAddress,
482   IN UINTN                                  Count
483   )
484 
485 {
486   EFI_STATUS  Status;
487   BOOLEAN     Direction;
488   UINTN       Stride;
489   UINTN       Index;
490   UINT64      Result;
491 
492   if ((UINT32)Width > EfiPciWidthUint64) {
493     return EFI_INVALID_PARAMETER;
494   }
495 
496   if (DestAddress == SrcAddress) {
497     return EFI_SUCCESS;
498   }
499 
500   Stride = (UINTN)1 << Width;
501 
502   Direction = TRUE;
503   if ((DestAddress > SrcAddress) && (DestAddress < (SrcAddress + Count * Stride))) {
504     Direction   = FALSE;
505     SrcAddress  = SrcAddress  + (Count-1) * Stride;
506     DestAddress = DestAddress + (Count-1) * Stride;
507   }
508 
509   for (Index = 0;Index < Count;Index++) {
510     Status = PcatRootBridgeIoMemRead (
511                This,
512                Width,
513                SrcAddress,
514                1,
515                &Result
516                );
517     if (EFI_ERROR (Status)) {
518       return Status;
519     }
520     Status = PcatRootBridgeIoMemWrite (
521                This,
522                Width,
523                DestAddress,
524                1,
525                &Result
526                );
527     if (EFI_ERROR (Status)) {
528       return Status;
529     }
530     if (Direction) {
531       SrcAddress  += Stride;
532       DestAddress += Stride;
533     } else {
534       SrcAddress  -= Stride;
535       DestAddress -= Stride;
536     }
537   }
538   return EFI_SUCCESS;
539 }
540 
541 EFI_STATUS
542 EFIAPI
PcatRootBridgeIoPciRead(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN OUT VOID * Buffer)543 PcatRootBridgeIoPciRead (
544   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
545   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
546   IN     UINT64                                 Address,
547   IN     UINTN                                  Count,
548   IN OUT VOID                                   *Buffer
549   )
550 {
551   if (Buffer == NULL) {
552     return EFI_INVALID_PARAMETER;
553   }
554 
555   return PcatRootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer);
556 }
557 
558 EFI_STATUS
559 EFIAPI
PcatRootBridgeIoPciWrite(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINT64 Address,IN UINTN Count,IN OUT VOID * Buffer)560 PcatRootBridgeIoPciWrite (
561   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL        *This,
562   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
563   IN     UINT64                                 Address,
564   IN     UINTN                                  Count,
565   IN OUT VOID                                   *Buffer
566   )
567 {
568   if (Buffer == NULL) {
569     return EFI_INVALID_PARAMETER;
570   }
571 
572   return PcatRootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer);
573 }
574 
575 EFI_STATUS
576 EFIAPI
PcatRootBridgeIoMap(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,IN VOID * HostAddress,IN OUT UINTN * NumberOfBytes,OUT EFI_PHYSICAL_ADDRESS * DeviceAddress,OUT VOID ** Mapping)577 PcatRootBridgeIoMap (
578   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL            *This,
579   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION  Operation,
580   IN     VOID                                       *HostAddress,
581   IN OUT UINTN                                      *NumberOfBytes,
582   OUT    EFI_PHYSICAL_ADDRESS                       *DeviceAddress,
583   OUT    VOID                                       **Mapping
584   )
585 
586 {
587   EFI_STATUS            Status;
588   EFI_PHYSICAL_ADDRESS  PhysicalAddress;
589   MAP_INFO              *MapInfo;
590   MAP_INFO_INSTANCE    *MapInstance;
591   PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
592 
593   if ( HostAddress == NULL || NumberOfBytes == NULL ||
594        DeviceAddress == NULL || Mapping == NULL ) {
595 
596     return EFI_INVALID_PARAMETER;
597   }
598 
599   //
600   // Perform a fence operation to make sure all memory operations are flushed
601   //
602   MemoryFence();
603 
604   //
605   // Initialize the return values to their defaults
606   //
607   *Mapping = NULL;
608 
609   //
610   // Make sure that Operation is valid
611   //
612   if ((UINT32)Operation >= EfiPciOperationMaximum) {
613     return EFI_INVALID_PARAMETER;
614   }
615 
616   //
617   // Most PCAT like chipsets can not handle performing DMA above 4GB.
618   // If any part of the DMA transfer being mapped is above 4GB, then
619   // map the DMA transfer to a buffer below 4GB.
620   //
621   PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress;
622   if ((PhysicalAddress + *NumberOfBytes) > 0x100000000ULL) {
623 
624     //
625     // Common Buffer operations can not be remapped.  If the common buffer
626     // if above 4GB, then it is not possible to generate a mapping, so return
627     // an error.
628     //
629     if (Operation == EfiPciOperationBusMasterCommonBuffer || Operation == EfiPciOperationBusMasterCommonBuffer64) {
630       return EFI_UNSUPPORTED;
631     }
632 
633     //
634     // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
635     // called later.
636     //
637     Status = gBS->AllocatePool (
638                     EfiBootServicesData,
639                     sizeof(MAP_INFO),
640                     (VOID **)&MapInfo
641                     );
642     if (EFI_ERROR (Status)) {
643       *NumberOfBytes = 0;
644       return Status;
645     }
646 
647     //
648     // Return a pointer to the MAP_INFO structure in Mapping
649     //
650     *Mapping = MapInfo;
651 
652     //
653     // Initialize the MAP_INFO structure
654     //
655     MapInfo->Operation         = Operation;
656     MapInfo->NumberOfBytes     = *NumberOfBytes;
657     MapInfo->NumberOfPages     = EFI_SIZE_TO_PAGES(*NumberOfBytes);
658     MapInfo->HostAddress       = PhysicalAddress;
659     MapInfo->MappedHostAddress = 0x00000000ffffffff;
660 
661     //
662     // Allocate a buffer below 4GB to map the transfer to.
663     //
664     Status = gBS->AllocatePages (
665                     AllocateMaxAddress,
666                     EfiBootServicesData,
667                     MapInfo->NumberOfPages,
668                     &MapInfo->MappedHostAddress
669                     );
670     if (EFI_ERROR(Status)) {
671       gBS->FreePool (MapInfo);
672       *NumberOfBytes = 0;
673       return Status;
674     }
675 
676     //
677     // If this is a read operation from the Bus Master's point of view,
678     // then copy the contents of the real buffer into the mapped buffer
679     // so the Bus Master can read the contents of the real buffer.
680     //
681     if (Operation == EfiPciOperationBusMasterRead || Operation == EfiPciOperationBusMasterRead64) {
682       CopyMem (
683         (VOID *)(UINTN)MapInfo->MappedHostAddress,
684         (VOID *)(UINTN)MapInfo->HostAddress,
685         MapInfo->NumberOfBytes
686         );
687     }
688 
689 
690   Status =gBS->AllocatePool (
691                     EfiBootServicesData,
692                     sizeof(MAP_INFO_INSTANCE),
693                     (VOID **)&MapInstance
694                     );
695     if (EFI_ERROR(Status)) {
696       gBS->FreePages (MapInfo->MappedHostAddress,MapInfo->NumberOfPages);
697       gBS->FreePool (MapInfo);
698       *NumberOfBytes = 0;
699       return Status;
700     }
701 
702     MapInstance->Map=MapInfo;
703     PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);
704     InsertTailList(&PrivateData->MapInfo,&MapInstance->Link);
705 
706   //
707     // The DeviceAddress is the address of the maped buffer below 4GB
708     //
709     *DeviceAddress = MapInfo->MappedHostAddress;
710   } else {
711     //
712     // The transfer is below 4GB, so the DeviceAddress is simply the HostAddress
713     //
714     *DeviceAddress = PhysicalAddress;
715   }
716 
717   //
718   // Perform a fence operation to make sure all memory operations are flushed
719   //
720   MemoryFence();
721 
722   return EFI_SUCCESS;
723 }
724 
725 EFI_STATUS
726 EFIAPI
PcatRootBridgeIoUnmap(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN VOID * Mapping)727 PcatRootBridgeIoUnmap (
728   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
729   IN VOID                             *Mapping
730   )
731 
732 {
733   MAP_INFO    *MapInfo;
734   PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
735   LIST_ENTRY *Link;
736 
737   //
738   // Perform a fence operation to make sure all memory operations are flushed
739   //
740   MemoryFence();
741 
742   PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);
743   //
744   // See if the Map() operation associated with this Unmap() required a mapping buffer.
745   // If a mapping buffer was not required, then this function simply returns EFI_SUCCESS.
746   //
747   if (Mapping != NULL) {
748     //
749     // Get the MAP_INFO structure from Mapping
750     //
751     MapInfo = (MAP_INFO *)Mapping;
752 
753   for (Link = PrivateData->MapInfo.ForwardLink; Link != &PrivateData->MapInfo; Link = Link->ForwardLink) {
754       if (((MAP_INFO_INSTANCE*)Link)->Map == MapInfo)
755         break;
756     }
757 
758     if (Link == &PrivateData->MapInfo) {
759       return EFI_INVALID_PARAMETER;
760   }
761 
762     RemoveEntryList(Link);
763     ((MAP_INFO_INSTANCE*)Link)->Map = NULL;
764     gBS->FreePool((MAP_INFO_INSTANCE*)Link);
765 
766     //
767     // If this is a write operation from the Bus Master's point of view,
768     // then copy the contents of the mapped buffer into the real buffer
769     // so the processor can read the contents of the real buffer.
770     //
771     if (MapInfo->Operation == EfiPciOperationBusMasterWrite || MapInfo->Operation == EfiPciOperationBusMasterWrite64) {
772       CopyMem (
773         (VOID *)(UINTN)MapInfo->HostAddress,
774         (VOID *)(UINTN)MapInfo->MappedHostAddress,
775         MapInfo->NumberOfBytes
776         );
777     }
778 
779     //
780     // Free the mapped buffer and the MAP_INFO structure.
781     //
782     gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->NumberOfPages);
783     gBS->FreePool (Mapping);
784   }
785 
786   //
787   // Perform a fence operation to make sure all memory operations are flushed
788   //
789   MemoryFence();
790 
791   return EFI_SUCCESS;
792 }
793 
794 EFI_STATUS
795 EFIAPI
PcatRootBridgeIoAllocateBuffer(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN EFI_ALLOCATE_TYPE Type,IN EFI_MEMORY_TYPE MemoryType,IN UINTN Pages,OUT VOID ** HostAddress,IN UINT64 Attributes)796 PcatRootBridgeIoAllocateBuffer (
797   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
798   IN  EFI_ALLOCATE_TYPE                Type,
799   IN  EFI_MEMORY_TYPE                  MemoryType,
800   IN  UINTN                            Pages,
801   OUT VOID                             **HostAddress,
802   IN  UINT64                           Attributes
803   )
804 {
805   EFI_STATUS            Status;
806   EFI_PHYSICAL_ADDRESS  PhysicalAddress;
807 
808   //
809   // Validate Attributes
810   //
811   if (Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) {
812     return EFI_UNSUPPORTED;
813   }
814 
815   //
816   // Check for invalid inputs
817   //
818   if (HostAddress == NULL) {
819     return EFI_INVALID_PARAMETER;
820   }
821 
822   //
823   // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
824   //
825   if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) {
826     return EFI_INVALID_PARAMETER;
827   }
828 
829   //
830   // Limit allocations to memory below 4GB
831   //
832   PhysicalAddress = (EFI_PHYSICAL_ADDRESS)(0xffffffff);
833 
834   Status = gBS->AllocatePages (AllocateMaxAddress, MemoryType, Pages, &PhysicalAddress);
835   if (EFI_ERROR (Status)) {
836     return Status;
837   }
838 
839   *HostAddress = (VOID *)(UINTN)PhysicalAddress;
840 
841   return EFI_SUCCESS;
842 }
843 
844 EFI_STATUS
845 EFIAPI
PcatRootBridgeIoFreeBuffer(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN UINTN Pages,OUT VOID * HostAddress)846 PcatRootBridgeIoFreeBuffer (
847   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
848   IN  UINTN                            Pages,
849   OUT VOID                             *HostAddress
850   )
851 
852 {
853 
854   if( HostAddress == NULL ){
855      return EFI_INVALID_PARAMETER;
856   }
857   return gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)HostAddress, Pages);
858 }
859 
860 EFI_STATUS
861 EFIAPI
PcatRootBridgeIoFlush(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This)862 PcatRootBridgeIoFlush (
863   IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This
864   )
865 
866 {
867   //
868   // Perform a fence operation to make sure all memory operations are flushed
869   //
870   MemoryFence();
871 
872   return EFI_SUCCESS;
873 }
874 
875 EFI_STATUS
876 EFIAPI
PcatRootBridgeIoGetAttributes(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,OUT UINT64 * Supported,OPTIONAL OUT UINT64 * Attributes)877 PcatRootBridgeIoGetAttributes (
878   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
879   OUT UINT64                           *Supported,  OPTIONAL
880   OUT UINT64                           *Attributes
881   )
882 
883 {
884   PCAT_PCI_ROOT_BRIDGE_INSTANCE *PrivateData;
885 
886   PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);
887 
888   if (Attributes == NULL && Supported == NULL) {
889     return EFI_INVALID_PARAMETER;
890   }
891 
892   //
893   // Supported is an OPTIONAL parameter.  See if it is NULL
894   //
895   if (Supported) {
896     //
897     // This is a generic driver for a PC-AT class system.  It does not have any
898     // chipset specific knowlegde, so none of the attributes can be set or
899     // cleared.  Any attempt to set attribute that are already set will succeed,
900     // and any attempt to set an attribute that is not supported will fail.
901     //
902     *Supported = PrivateData->Attributes;
903   }
904 
905   //
906   // Set Attrbutes to the attributes detected when the PCI Root Bridge was initialized
907   //
908 
909   if (Attributes) {
910     *Attributes = PrivateData->Attributes;
911   }
912 
913 
914   return EFI_SUCCESS;
915 }
916 
917 EFI_STATUS
918 EFIAPI
PcatRootBridgeIoSetAttributes(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,IN UINT64 Attributes,IN OUT UINT64 * ResourceBase,IN OUT UINT64 * ResourceLength)919 PcatRootBridgeIoSetAttributes (
920   IN     EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
921   IN     UINT64                           Attributes,
922   IN OUT UINT64                           *ResourceBase,
923   IN OUT UINT64                           *ResourceLength
924   )
925 
926 {
927   PCAT_PCI_ROOT_BRIDGE_INSTANCE   *PrivateData;
928 
929   PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);
930 
931   //
932   // This is a generic driver for a PC-AT class system.  It does not have any
933   // chipset specific knowlegde, so none of the attributes can be set or
934   // cleared.  Any attempt to set attribute that are already set will succeed,
935   // and any attempt to set an attribute that is not supported will fail.
936   //
937   if (Attributes & (~PrivateData->Attributes)) {
938     return EFI_UNSUPPORTED;
939   }
940 
941   return EFI_SUCCESS;
942 }
943 
944 EFI_STATUS
945 EFIAPI
PcatRootBridgeIoConfiguration(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL * This,OUT VOID ** Resources)946 PcatRootBridgeIoConfiguration (
947   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL  *This,
948   OUT VOID                             **Resources
949   )
950 
951 {
952   PCAT_PCI_ROOT_BRIDGE_INSTANCE   *PrivateData;
953 
954   PrivateData = DRIVER_INSTANCE_FROM_PCI_ROOT_BRIDGE_IO_THIS(This);
955 
956   *Resources = PrivateData->Configuration;
957 
958   return EFI_SUCCESS;
959 }
960 
961 //
962 // Internal function
963 //
964 
965 EFI_STATUS
966 EFIAPI
PcatRootBridgeIoMemRW(IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,IN UINTN Count,IN BOOLEAN InStrideFlag,IN PTR In,IN BOOLEAN OutStrideFlag,OUT PTR Out)967 PcatRootBridgeIoMemRW (
968   IN  EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH  Width,
969   IN  UINTN                                  Count,
970   IN  BOOLEAN                                InStrideFlag,
971   IN  PTR                                    In,
972   IN  BOOLEAN                                OutStrideFlag,
973   OUT PTR                                    Out
974   )
975 /*++
976 
977 Routine Description:
978 
979   Private service to provide the memory read/write
980 
981 Arguments:
982 
983   Width of the Memory Access
984   Count of the number of accesses to perform
985 
986 Returns:
987 
988   Status
989 
990   EFI_SUCCESS           - Successful transaction
991   EFI_INVALID_PARAMETER - Unsupported width and address combination
992 
993 --*/
994 {
995   UINTN  Stride;
996   UINTN  InStride;
997   UINTN  OutStride;
998 
999 
1000   Width     = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03);
1001   Stride    = (UINTN)1 << Width;
1002   InStride  = InStrideFlag  ? Stride : 0;
1003   OutStride = OutStrideFlag ? Stride : 0;
1004 
1005   //
1006   // Loop for each iteration and move the data
1007   //
1008   switch (Width) {
1009   case EfiPciWidthUint8:
1010     for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
1011       MemoryFence();
1012       *In.ui8 = *Out.ui8;
1013       MemoryFence();
1014     }
1015     break;
1016   case EfiPciWidthUint16:
1017     for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
1018       MemoryFence();
1019       *In.ui16 = *Out.ui16;
1020       MemoryFence();
1021     }
1022     break;
1023   case EfiPciWidthUint32:
1024     for (;Count > 0; Count--, In.buf += InStride, Out.buf += OutStride) {
1025       MemoryFence();
1026       *In.ui32 = *Out.ui32;
1027       MemoryFence();
1028     }
1029     break;
1030   default:
1031     return EFI_INVALID_PARAMETER;
1032   }
1033 
1034   return EFI_SUCCESS;
1035 }
1036 
1037