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