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