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