1 /** @file
2   This file contains the callback routines for undi3.1.
3   the callback routines for Undi3.1 have an extra parameter UniqueId which
4   stores the interface context for the NIC that snp is trying to talk.
5 
6 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8 
9 **/
10 
11 #include "Snp.h"
12 
13 /**
14   Acquire or release a lock of the exclusive access to a critical section of the
15   code/data.
16 
17   This is a callback routine supplied to UNDI3.1 at undi_start time.
18   New callbacks for 3.1: there won't be a virtual2physical callback for UNDI 3.1
19   because undi3.1 uses the MemMap call to map the required address by itself!
20 
21   @param UniqueId  This was supplied to UNDI at Undi_Start, SNP uses this to
22                       store Undi interface context (Undi does not read or write
23                       this variable).
24   @param Enable    Non-zero indicates acquire; Zero indicates release.
25 
26 **/
27 VOID
28 EFIAPI
SnpUndi32CallbackBlock(IN UINT64 UniqueId,IN UINT32 Enable)29 SnpUndi32CallbackBlock (
30   IN UINT64 UniqueId,
31   IN UINT32 Enable
32   )
33 {
34   SNP_DRIVER  *Snp;
35 
36   Snp = (SNP_DRIVER *) (UINTN) UniqueId;
37   //
38   // tcpip was calling snp at tpl_notify and when we acquire a lock that was
39   // created at a lower level (TPL_CALLBACK) it gives an assert!
40   //
41   if (Enable != 0) {
42     EfiAcquireLock (&Snp->Lock);
43   } else {
44     EfiReleaseLock (&Snp->Lock);
45   }
46 }
47 
48 /**
49   Delay MicroSeconds of micro seconds.
50 
51   This is a callback routine supplied to UNDI at undi_start time.
52 
53   @param UniqueId      This was supplied to UNDI at Undi_Start, SNP uses this to
54                        store Undi interface context (Undi does not read or write
55                        this variable).
56   @param MicroSeconds  Number of micro seconds to pause, ususlly multiple of 10.
57 
58 **/
59 VOID
60 EFIAPI
SnpUndi32CallbackDelay(IN UINT64 UniqueId,IN UINT64 MicroSeconds)61 SnpUndi32CallbackDelay (
62   IN UINT64 UniqueId,
63   IN UINT64 MicroSeconds
64   )
65 {
66   if (MicroSeconds != 0) {
67     gBS->Stall ((UINTN) MicroSeconds);
68   }
69 }
70 
71 /**
72   IO routine for UNDI3.1.
73 
74   This is a callback routine supplied to UNDI at undi_start time.
75 
76   @param UniqueId       This was supplied to UNDI at Undi_Start, SNP uses this
77                         to store Undi interface context (Undi does not read or
78                         write this variable).
79   @param ReadOrWrite    Indicates read or write, IO or Memory.
80   @param NumBytes       Number of bytes to read or write.
81   @param MemOrPortAddr  IO or memory address to read from or write to.
82   @param BufferPtr      Memory location to read into or that contains the bytes
83                         to write.
84 
85 **/
86 VOID
87 EFIAPI
SnpUndi32CallbackMemio(IN UINT64 UniqueId,IN UINT8 ReadOrWrite,IN UINT8 NumBytes,IN UINT64 MemOrPortAddr,IN OUT UINT64 BufferPtr)88 SnpUndi32CallbackMemio (
89   IN UINT64     UniqueId,
90   IN UINT8      ReadOrWrite,
91   IN UINT8      NumBytes,
92   IN UINT64     MemOrPortAddr,
93   IN OUT UINT64 BufferPtr
94   )
95 {
96   SNP_DRIVER                *Snp;
97   EFI_PCI_IO_PROTOCOL_WIDTH Width;
98 
99   Snp   = (SNP_DRIVER *) (UINTN) UniqueId;
100 
101   Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;
102   switch (NumBytes) {
103   case 2:
104     Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;
105     break;
106 
107   case 4:
108     Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;
109     break;
110 
111   case 8:
112     Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;
113     break;
114   }
115 
116   switch (ReadOrWrite) {
117   case PXE_IO_READ:
118     Snp->PciIo->Io.Read (
119                      Snp->PciIo,
120                      Width,
121                      Snp->IoBarIndex,      // BAR 1 (for 32bit regs), IO base address
122                      MemOrPortAddr,
123                      1,                    // count
124                      (VOID *) (UINTN) BufferPtr
125                      );
126     break;
127 
128   case PXE_IO_WRITE:
129     Snp->PciIo->Io.Write (
130                      Snp->PciIo,
131                      Width,
132                      Snp->IoBarIndex,      // BAR 1 (for 32bit regs), IO base address
133                      MemOrPortAddr,
134                      1,                    // count
135                      (VOID *) (UINTN) BufferPtr
136                      );
137     break;
138 
139   case PXE_MEM_READ:
140     Snp->PciIo->Mem.Read (
141                       Snp->PciIo,
142                       Width,
143                       Snp->MemoryBarIndex,  // BAR 0, Memory base address
144                       MemOrPortAddr,
145                       1,                    // count
146                       (VOID *) (UINTN) BufferPtr
147                       );
148     break;
149 
150   case PXE_MEM_WRITE:
151     Snp->PciIo->Mem.Write (
152                       Snp->PciIo,
153                       Width,
154                       Snp->MemoryBarIndex,  // BAR 0, Memory base address
155                       MemOrPortAddr,
156                       1,                    // count
157                       (VOID *) (UINTN) BufferPtr
158                       );
159     break;
160   }
161 
162   return ;
163 }
164 
165 /**
166   Map a CPU address to a device address.
167 
168   This is a callback routine supplied to UNDI at undi_start time.
169 
170   @param UniqueId      This was supplied to UNDI at Undi_Start, SNP uses this to
171                        store Undi interface context (Undi does not read or write
172                        this variable).
173   @param CpuAddr       Virtual address to be mapped.
174   @param NumBytes      Size of memory to be mapped.
175   @param Direction     Direction of data flow for this memory's usage:
176                        cpu->device, device->cpu or both ways.
177   @param DeviceAddrPtr Pointer to return the mapped device address.
178 
179 **/
180 VOID
181 EFIAPI
SnpUndi32CallbackMap(IN UINT64 UniqueId,IN UINT64 CpuAddr,IN UINT32 NumBytes,IN UINT32 Direction,IN OUT UINT64 DeviceAddrPtr)182 SnpUndi32CallbackMap (
183   IN UINT64     UniqueId,
184   IN UINT64     CpuAddr,
185   IN UINT32     NumBytes,
186   IN UINT32     Direction,
187   IN OUT UINT64 DeviceAddrPtr
188   )
189 {
190   EFI_PHYSICAL_ADDRESS          *DevAddrPtr;
191   EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag;
192   UINTN                         BuffSize;
193   SNP_DRIVER                    *Snp;
194   UINTN                         Index;
195   EFI_STATUS                    Status;
196 
197   BuffSize    = (UINTN) NumBytes;
198   Snp         = (SNP_DRIVER *) (UINTN) UniqueId;
199   DevAddrPtr  = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr;
200 
201   if (CpuAddr == 0) {
202     *DevAddrPtr = 0;
203     return ;
204   }
205 
206   switch (Direction) {
207   case TO_AND_FROM_DEVICE:
208     DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer;
209     break;
210 
211   case FROM_DEVICE:
212     DirectionFlag = EfiPciIoOperationBusMasterWrite;
213     break;
214 
215   case TO_DEVICE:
216     DirectionFlag = EfiPciIoOperationBusMasterRead;
217     break;
218 
219   default:
220     *DevAddrPtr = 0;
221     //
222     // any non zero indicates error!
223     //
224     return ;
225   }
226   //
227   // find an unused map_list entry
228   //
229   for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
230     if (Snp->MapList[Index].VirtualAddress == 0) {
231       break;
232     }
233   }
234 
235   if (Index >= MAX_MAP_LENGTH) {
236     DEBUG ((EFI_D_INFO, "SNP maplist is FULL\n"));
237     *DevAddrPtr = 0;
238     return ;
239   }
240 
241   Snp->MapList[Index].VirtualAddress = (EFI_PHYSICAL_ADDRESS) CpuAddr;
242 
243   Status = Snp->PciIo->Map (
244                          Snp->PciIo,
245                          DirectionFlag,
246                          (VOID *) (UINTN) CpuAddr,
247                          &BuffSize,
248                          DevAddrPtr,
249                          &(Snp->MapList[Index].MapCookie)
250                          );
251   if (Status != EFI_SUCCESS) {
252     *DevAddrPtr                        = 0;
253     Snp->MapList[Index].VirtualAddress = 0;
254   }
255 
256   return ;
257 }
258 
259 /**
260   Unmap an address that was previously mapped using map callback.
261 
262   This is a callback routine supplied to UNDI at undi_start time.
263 
264   @param UniqueId    This was supplied to UNDI at Undi_Start, SNP uses this to
265                      store. Undi interface context (Undi does not read or write
266                      this variable).
267   @param CpuAddr     Virtual address that was mapped.
268   @param NumBytes    Size of memory mapped.
269   @param Direction   Direction of data flow for this memory's usage:
270                      cpu->device, device->cpu or both ways.
271   @param DeviceAddr  The mapped device address.
272 
273 **/
274 VOID
275 EFIAPI
SnpUndi32CallbackUnmap(IN UINT64 UniqueId,IN UINT64 CpuAddr,IN UINT32 NumBytes,IN UINT32 Direction,IN UINT64 DeviceAddr)276 SnpUndi32CallbackUnmap (
277   IN UINT64 UniqueId,
278   IN UINT64 CpuAddr,
279   IN UINT32 NumBytes,
280   IN UINT32 Direction,
281   IN UINT64 DeviceAddr
282   )
283 {
284   SNP_DRIVER  *Snp;
285   UINT16      Index;
286 
287   Snp = (SNP_DRIVER *) (UINTN) UniqueId;
288 
289   for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
290     if (Snp->MapList[Index].VirtualAddress == CpuAddr) {
291       break;
292     }
293   }
294 
295   if (Index >= MAX_MAP_LENGTH) {
296     DEBUG ((EFI_D_ERROR, "SNP could not find a mapping, failed to unmap.\n"));
297     return ;
298   }
299 
300   Snp->PciIo->Unmap (Snp->PciIo, Snp->MapList[Index].MapCookie);
301   Snp->MapList[Index].VirtualAddress = 0;
302   Snp->MapList[Index].MapCookie      = NULL;
303   return ;
304 }
305 
306 /**
307   Synchronize the virtual buffer contents with the mapped buffer contents.
308 
309   This is a callback routine supplied to UNDI at undi_start time. The virtual
310   and mapped buffers need not correspond to the same physical memory (especially
311   if the virtual address is > 4GB). Depending on the direction for which the
312   buffer is mapped, undi will need to synchronize their contents whenever it
313   writes to/reads from the buffer using either the cpu address or the device
314   address.
315   EFI does not provide a sync call since virt=physical, we should just do the
316   synchronization ourselves here.
317 
318   @param UniqueId    This was supplied to UNDI at Undi_Start, SNP uses this to
319                      store Undi interface context (Undi does not read or write
320                      this variable).
321   @param CpuAddr     Virtual address that was mapped.
322   @param NumBytes    Size of memory mapped.
323   @param Direction   Direction of data flow for this memory's usage:
324                      cpu->device, device->cpu or both ways.
325   @param DeviceAddr  The mapped device address.
326 
327 **/
328 VOID
329 EFIAPI
SnpUndi32CallbackSync(IN UINT64 UniqueId,IN UINT64 CpuAddr,IN UINT32 NumBytes,IN UINT32 Direction,IN UINT64 DeviceAddr)330 SnpUndi32CallbackSync (
331   IN UINT64             UniqueId,
332   IN UINT64             CpuAddr,
333   IN UINT32             NumBytes,
334   IN UINT32             Direction,
335   IN UINT64             DeviceAddr
336   )
337 {
338   if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) {
339     return ;
340 
341   }
342 
343   switch (Direction) {
344   case FROM_DEVICE:
345     CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes);
346     break;
347 
348   case TO_DEVICE:
349     CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes);
350     break;
351   }
352 
353   return ;
354 }
355