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