]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/SnpDxe/Callback.c
sync comments, fix function header, rename variable name to follow coding style.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / SnpDxe / Callback.c
CommitLineData
fb0b259e 1/** @file\r
2 This file contains two sets of callback routines for undi3.0 and 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
4cda7726 6Copyright (c) 2006 - 2008, Intel Corporation. <BR>\r
5e7e4fad 7All rights reserved. This program and the accompanying materials\r
8are licensed and made available under the terms and conditions of the BSD License\r
9which accompanies this distribution. The full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
fb0b259e 15**/\r
5e7e4fad 16\r
17#include "Snp.h"\r
18\r
19//\r
20// Global variables\r
21// these 2 global variables are used only for 3.0 undi. we could not place\r
22// them in the snp structure because we will not know which snp structure\r
23// in the callback context!\r
24//\r
fe1e36e5 25BOOLEAN mInitializeLock = TRUE;\r
26EFI_LOCK mLock;\r
5e7e4fad 27\r
28//\r
29// End Global variables\r
30//\r
4cda7726 31extern EFI_PCI_IO_PROTOCOL *mPciIo;\r
5e7e4fad 32\r
4cda7726 33/**\r
34 This is a callback routine supplied to UNDI at undi_start time.\r
35 UNDI call this routine with a virtual or CPU address that SNP provided to \r
36 convert it to a physical or device address. Since EFI uses the identical \r
37 mapping, this routine returns the physical address same as the virtual address\r
38 for most of the addresses. an address above 4GB cannot generally be used as a \r
39 device address, it needs to be mapped to a lower physical address. This \r
40 routine does not call the map routine itself, but it assumes that the mapping\r
41 was done at the time of providing the address to UNDI. This routine just \r
42 looks up the address in a map table (which is the v2p structure chain). \r
43 \r
44 @param CpuAddr virtual address of a buffer.\r
45 @param DeviceAddrPtr pointer to the physical address.\r
46 The DeviceAddrPtr will contain 0 in case of any error.\r
47\r
48**/\r
5e7e4fad 49VOID\r
4cda7726 50SnpUndi32CallbackV2p30 (\r
5e7e4fad 51 IN UINT64 CpuAddr,\r
52 IN OUT UINT64 DeviceAddrPtr\r
53 )\r
5e7e4fad 54{\r
4cda7726 55 V2P *V2p;\r
5e7e4fad 56 //\r
57 // Do nothing if virtual address is zero or physical pointer is NULL.\r
58 // No need to map if the virtual address is within 4GB limit since\r
59 // EFI uses identical mapping\r
60 //\r
61 if ((CpuAddr == 0) || (DeviceAddrPtr == 0)) {\r
4cda7726 62 DEBUG ((EFI_D_NET, "\nv2p: Null virtual address or physical pointer.\n"));\r
5e7e4fad 63 return ;\r
64 }\r
65\r
66 if (CpuAddr < FOUR_GIGABYTES) {\r
67 *(UINT64 *) (UINTN) DeviceAddrPtr = CpuAddr;\r
68 return ;\r
69 }\r
70 //\r
71 // SNP creates a vaddr tp paddr mapping at the time of calling undi with any\r
72 // big address, this callback routine just looks up in the v2p list and\r
73 // returns the physical address for any given virtual address.\r
74 //\r
4cda7726 75 if (FindV2p (&V2p, (VOID *) (UINTN) CpuAddr) != EFI_SUCCESS) {\r
5e7e4fad 76 *(UINT64 *) (UINTN) DeviceAddrPtr = CpuAddr;\r
77 } else {\r
4cda7726 78 *(UINT64 *) (UINTN) DeviceAddrPtr = V2p->PhysicalAddress;\r
5e7e4fad 79 }\r
80}\r
81\r
4cda7726 82/**\r
83 This is a callback routine supplied to UNDI at undi_start time.\r
84 UNDI call this routine when it wants to have exclusive access to a critical\r
85 section of the code/data.\r
86\r
87 @param Enable non-zero indicates acquire\r
88 zero indicates release\r
89\r
90**/\r
5e7e4fad 91VOID\r
4cda7726 92SnpUndi32CallbackBlock30 (\r
5e7e4fad 93 IN UINT32 Enable\r
94 )\r
5e7e4fad 95{\r
96 //\r
97 // tcpip was calling snp at tpl_notify and if we acquire a lock that was\r
98 // created at a lower level (TPL_CALLBACK) it gives an assert!\r
99 //\r
100 if (mInitializeLock) {\r
101 EfiInitializeLock (&mLock, TPL_NOTIFY);\r
102 mInitializeLock = FALSE;\r
103 }\r
104\r
105 if (Enable != 0) {\r
106 EfiAcquireLock (&mLock);\r
107 } else {\r
108 EfiReleaseLock (&mLock);\r
109 }\r
110}\r
111\r
4cda7726 112/**\r
113 This is a callback routine supplied to UNDI at undi_start time.\r
114 UNDI call this routine with the number of micro seconds when it wants to\r
115 pause.\r
116\r
117 @param MicroSeconds number of micro seconds to pause, ususlly multiple of 10.\r
118\r
119**/\r
5e7e4fad 120VOID\r
4cda7726 121SnpUndi32CallbackDelay30 (\r
5e7e4fad 122 IN UINT64 MicroSeconds\r
123 )\r
5e7e4fad 124{\r
125 if (MicroSeconds != 0) {\r
126 gBS->Stall ((UINTN) MicroSeconds);\r
127 }\r
128}\r
129\r
4cda7726 130/**\r
131 This is a callback routine supplied to UNDI at undi_start time.\r
132 This is the IO routine for UNDI. This is not currently being used by UNDI3.0\r
133 because Undi3.0 uses io/mem offsets relative to the beginning of the device\r
134 io/mem address and so it needs to use the PCI_IO_FUNCTION that abstracts the\r
135 start of the device's io/mem addresses. Since SNP cannot retrive the context\r
136 of the undi3.0 interface it cannot use the PCI_IO_FUNCTION that specific for\r
137 that NIC and uses one global IO functions structure, this does not work.\r
138 This however works fine for EFI1.0 Undis because they use absolute addresses\r
139 for io/mem access.\r
140\r
141 @param ReadOrWrite indicates read or write, IO or Memory\r
142 @param NumBytes number of bytes to read or write\r
143 @param Address IO or memory address to read from or write to\r
144 @param BufferAddr memory location to read into or that contains the bytes to \r
145 write\r
146\r
147**/\r
5e7e4fad 148VOID\r
4cda7726 149SnpUndi32CallbackMemio30 (\r
5e7e4fad 150 IN UINT8 ReadOrWrite,\r
151 IN UINT8 NumBytes,\r
152 IN UINT64 Address,\r
153 IN OUT UINT64 BufferAddr\r
154 )\r
5e7e4fad 155{\r
156 EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
157\r
158 switch (NumBytes) {\r
159 case 2:\r
160 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;\r
161 break;\r
162\r
163 case 4:\r
164 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;\r
165 break;\r
166\r
167 case 8:\r
168 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;\r
169 break;\r
170\r
171 default:\r
172 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;\r
173 }\r
174\r
175 switch (ReadOrWrite) {\r
176 case PXE_IO_READ:\r
4cda7726 177 mPciIo->Io.Read (\r
178 mPciIo,\r
179 Width,\r
180 1, // BAR 1, IO base address\r
181 Address,\r
182 1, // count\r
183 (VOID *) (UINTN) BufferAddr\r
184 );\r
5e7e4fad 185 break;\r
186\r
187 case PXE_IO_WRITE:\r
4cda7726 188 mPciIo->Io.Write (\r
189 mPciIo,\r
190 Width,\r
191 1, // BAR 1, IO base address\r
192 Address,\r
193 1, // count\r
194 (VOID *) (UINTN) BufferAddr\r
195 );\r
5e7e4fad 196 break;\r
197\r
198 case PXE_MEM_READ:\r
4cda7726 199 mPciIo->Mem.Read (\r
200 mPciIo,\r
201 Width,\r
202 0, // BAR 0, Memory base address\r
203 Address,\r
204 1, // count\r
205 (VOID *) (UINTN) BufferAddr\r
206 );\r
5e7e4fad 207 break;\r
208\r
209 case PXE_MEM_WRITE:\r
4cda7726 210 mPciIo->Mem.Write (\r
211 mPciIo,\r
212 Width,\r
213 0, // BAR 0, Memory base address\r
214 Address,\r
215 1, // count\r
216 (VOID *) (UINTN) BufferAddr\r
217 );\r
5e7e4fad 218 break;\r
219 }\r
220\r
221 return ;\r
222}\r
4cda7726 223\r
224/**\r
225 This is a callback routine supplied to UNDI3.1 at undi_start time.\r
226 UNDI call this routine when it wants to have exclusive access to a critical\r
227 section of the code/data.\r
228 New callbacks for 3.1:\r
229 there won't be a virtual2physical callback for UNDI 3.1 because undi3.1 uses\r
230 the MemMap call to map the required address by itself!\r
231\r
232 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to \r
233 store Undi interface context (Undi does not read or write\r
234 this variable)\r
235 @param Enable non-zero indicates acquire\r
236 zero indicates release\r
237**/\r
5e7e4fad 238VOID\r
4cda7726 239SnpUndi32CallbackBlock (\r
5e7e4fad 240 IN UINT64 UniqueId,\r
241 IN UINT32 Enable\r
242 )\r
5e7e4fad 243{\r
4cda7726 244 SNP_DRIVER *Snp;\r
5e7e4fad 245\r
4cda7726 246 Snp = (SNP_DRIVER *) (UINTN) UniqueId;\r
5e7e4fad 247 //\r
248 // tcpip was calling snp at tpl_notify and when we acquire a lock that was\r
249 // created at a lower level (TPL_CALLBACK) it gives an assert!\r
250 //\r
251 if (Enable != 0) {\r
4cda7726 252 EfiAcquireLock (&Snp->Lock);\r
5e7e4fad 253 } else {\r
4cda7726 254 EfiReleaseLock (&Snp->Lock);\r
5e7e4fad 255 }\r
256}\r
257\r
4cda7726 258/**\r
259 This is a callback routine supplied to UNDI at undi_start time.\r
260 UNDI call this routine with the number of micro seconds when it wants to\r
261 pause.\r
262\r
263 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to\r
264 store Undi interface context (Undi does not read or write\r
265 this variable)\r
266 @param MicroSeconds number of micro seconds to pause, ususlly multiple of 10.\r
267**/\r
5e7e4fad 268VOID\r
4cda7726 269SnpUndi32CallbackDelay (\r
5e7e4fad 270 IN UINT64 UniqueId,\r
271 IN UINT64 MicroSeconds\r
272 )\r
5e7e4fad 273{\r
274 if (MicroSeconds != 0) {\r
275 gBS->Stall ((UINTN) MicroSeconds);\r
276 }\r
277}\r
278\r
4cda7726 279/**\r
280 This is a callback routine supplied to UNDI at undi_start time.\r
281 This is the IO routine for UNDI3.1 to start CPB.\r
282\r
283 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this \r
284 to store Undi interface context (Undi does not read or\r
285 write this variable)\r
286 @param ReadOrWrite indicates read or write, IO or Memory.\r
287 @param NumBytes number of bytes to read or write.\r
288 @param MemOrPortAddr IO or memory address to read from or write to.\r
289 @param BufferPtr memory location to read into or that contains the bytes\r
290 to write.\r
291**/\r
5e7e4fad 292VOID\r
4cda7726 293SnpUndi32CallbackMemio (\r
294 IN UINT64 UniqueId,\r
295 IN UINT8 ReadOrWrite,\r
296 IN UINT8 NumBytes,\r
297 IN UINT64 MemOrPortAddr,\r
298 IN OUT UINT64 BufferPtr\r
5e7e4fad 299 )\r
5e7e4fad 300{\r
4cda7726 301 SNP_DRIVER *Snp;\r
5e7e4fad 302 EFI_PCI_IO_PROTOCOL_WIDTH Width;\r
303\r
4cda7726 304 Snp = (SNP_DRIVER *) (UINTN) UniqueId;\r
5e7e4fad 305\r
306 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;\r
307 switch (NumBytes) {\r
308 case 2:\r
309 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;\r
310 break;\r
311\r
312 case 4:\r
313 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;\r
314 break;\r
315\r
316 case 8:\r
317 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;\r
318 break;\r
319 }\r
320\r
321 switch (ReadOrWrite) {\r
322 case PXE_IO_READ:\r
4cda7726 323 Snp->PciIo->Io.Read (\r
324 Snp->PciIo,\r
325 Width,\r
326 Snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address\r
327 MemOrPortAddr,\r
328 1, // count\r
329 (VOID *) (UINTN) BufferPtr\r
330 );\r
5e7e4fad 331 break;\r
332\r
333 case PXE_IO_WRITE:\r
4cda7726 334 Snp->PciIo->Io.Write (\r
335 Snp->PciIo,\r
336 Width,\r
337 Snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address\r
338 MemOrPortAddr,\r
339 1, // count\r
340 (VOID *) (UINTN) BufferPtr\r
341 );\r
5e7e4fad 342 break;\r
343\r
344 case PXE_MEM_READ:\r
4cda7726 345 Snp->PciIo->Mem.Read (\r
346 Snp->PciIo,\r
5e7e4fad 347 Width,\r
4cda7726 348 Snp->MemoryBarIndex, // BAR 0, Memory base address\r
349 MemOrPortAddr,\r
5e7e4fad 350 1, // count\r
4cda7726 351 (VOID *) (UINTN) BufferPtr\r
5e7e4fad 352 );\r
353 break;\r
354\r
355 case PXE_MEM_WRITE:\r
4cda7726 356 Snp->PciIo->Mem.Write (\r
357 Snp->PciIo,\r
5e7e4fad 358 Width,\r
4cda7726 359 Snp->MemoryBarIndex, // BAR 0, Memory base address\r
360 MemOrPortAddr,\r
5e7e4fad 361 1, // count\r
4cda7726 362 (VOID *) (UINTN) BufferPtr\r
5e7e4fad 363 );\r
364 break;\r
365 }\r
366\r
367 return ;\r
368}\r
369\r
4cda7726 370/**\r
371 This is a callback routine supplied to UNDI at undi_start time.\r
372 UNDI call this routine when it has to map a CPU address to a device\r
373 address.\r
374\r
375 @param UniqueId - This was supplied to UNDI at Undi_Start, SNP uses this to store\r
376 Undi interface context (Undi does not read or write this variable)\r
377 @param CpuAddr - Virtual address to be mapped!\r
378 @param NumBytes - size of memory to be mapped\r
379 @param Direction - direction of data flow for this memory's usage:\r
380 cpu->device, device->cpu or both ways\r
381 @param DeviceAddrPtr - pointer to return the mapped device address\r
382\r
383**/\r
5e7e4fad 384VOID\r
4cda7726 385SnpUndi32CallbackMap (\r
5e7e4fad 386 IN UINT64 UniqueId,\r
387 IN UINT64 CpuAddr,\r
388 IN UINT32 NumBytes,\r
389 IN UINT32 Direction,\r
390 IN OUT UINT64 DeviceAddrPtr\r
391 )\r
5e7e4fad 392{\r
393 EFI_PHYSICAL_ADDRESS *DevAddrPtr;\r
394 EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag;\r
395 UINTN BuffSize;\r
4cda7726 396 SNP_DRIVER *Snp;\r
5e7e4fad 397 UINTN Index;\r
398 EFI_STATUS Status;\r
399\r
400 BuffSize = (UINTN) NumBytes;\r
4cda7726 401 Snp = (SNP_DRIVER *) (UINTN) UniqueId;\r
5e7e4fad 402 DevAddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr;\r
403\r
404 if (CpuAddr == 0) {\r
405 *DevAddrPtr = 0;\r
406 return ;\r
407 }\r
408\r
409 switch (Direction) {\r
410 case TO_AND_FROM_DEVICE:\r
411 DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer;\r
412 break;\r
413\r
414 case FROM_DEVICE:\r
415 DirectionFlag = EfiPciIoOperationBusMasterWrite;\r
416 break;\r
417\r
418 case TO_DEVICE:\r
419 DirectionFlag = EfiPciIoOperationBusMasterRead;\r
420 break;\r
421\r
422 default:\r
423 *DevAddrPtr = 0;\r
424 //\r
425 // any non zero indicates error!\r
426 //\r
427 return ;\r
428 }\r
429 //\r
430 // find an unused map_list entry\r
431 //\r
432 for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {\r
4cda7726 433 if (Snp->MapList[Index].VirtualAddress == 0) {\r
5e7e4fad 434 break;\r
435 }\r
436 }\r
437\r
438 if (Index >= MAX_MAP_LENGTH) {\r
439 DEBUG ((EFI_D_INFO, "SNP maplist is FULL\n"));\r
440 *DevAddrPtr = 0;\r
441 return ;\r
442 }\r
443\r
4cda7726 444 Snp->MapList[Index].VirtualAddress = (EFI_PHYSICAL_ADDRESS) CpuAddr;\r
5e7e4fad 445\r
4cda7726 446 Status = Snp->PciIo->Map (\r
447 Snp->PciIo,\r
448 DirectionFlag,\r
449 (VOID *) (UINTN) CpuAddr,\r
450 &BuffSize,\r
451 DevAddrPtr,\r
452 &(Snp->MapList[Index].MapCookie)\r
453 );\r
5e7e4fad 454 if (Status != EFI_SUCCESS) {\r
4cda7726 455 *DevAddrPtr = 0;\r
456 Snp->MapList[Index].VirtualAddress = 0;\r
5e7e4fad 457 }\r
458\r
459 return ;\r
460}\r
461\r
4cda7726 462/**\r
463 This is a callback routine supplied to UNDI at undi_start time.\r
464 UNDI call this routine when it wants to unmap an address that was previously\r
465 mapped using map callback.\r
466\r
467 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to store.\r
468 Undi interface context (Undi does not read or write this variable)\r
469 @param CpuAddr Virtual address that was mapped!\r
470 @param NumBytes size of memory mapped\r
471 @param Direction direction of data flow for this memory's usage:\r
472 cpu->device, device->cpu or both ways\r
473 @param DeviceAddr the mapped device address\r
474\r
475**/\r
5e7e4fad 476VOID\r
4cda7726 477SnpUndi32CallbackUnmap (\r
5e7e4fad 478 IN UINT64 UniqueId,\r
479 IN UINT64 CpuAddr,\r
480 IN UINT32 NumBytes,\r
481 IN UINT32 Direction,\r
482 IN UINT64 DeviceAddr\r
483 )\r
5e7e4fad 484{\r
4cda7726 485 SNP_DRIVER *Snp;\r
5e7e4fad 486 UINT16 Index;\r
487\r
4cda7726 488 Snp = (SNP_DRIVER *) (UINTN) UniqueId;\r
5e7e4fad 489\r
490 for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {\r
4cda7726 491 if (Snp->MapList[Index].VirtualAddress == CpuAddr) {\r
5e7e4fad 492 break;\r
493 }\r
494 }\r
495\r
496 if (Index >= MAX_MAP_LENGTH)\r
497 {\r
498 DEBUG ((EFI_D_ERROR, "SNP could not find a mapping, failed to unmap.\n"));\r
499 return ;\r
500 }\r
501\r
4cda7726 502 Snp->PciIo->Unmap (Snp->PciIo, Snp->MapList[Index].MapCookie);\r
503 Snp->MapList[Index].VirtualAddress = 0;\r
504 Snp->MapList[Index].MapCookie = NULL;\r
5e7e4fad 505 return ;\r
506}\r
507\r
4cda7726 508/**\r
509 This is a callback routine supplied to UNDI at undi_start time.\r
510 UNDI call this routine when it wants synchronize the virtual buffer contents\r
511 with the mapped buffer contents. The virtual and mapped buffers need not\r
512 correspond to the same physical memory (especially if the virtual address is\r
513 > 4GB). Depending on the direction for which the buffer is mapped, undi will\r
514 need to synchronize their contents whenever it writes to/reads from the buffer\r
515 using either the cpu address or the device address.\r
516\r
517 EFI does not provide a sync call, since virt=physical, we sould just do\r
518 the synchronization ourself here!\r
519\r
520 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to store\r
521 Undi interface context (Undi does not read or write this variable)\r
522 @param CpuAddr Virtual address that was mapped!\r
523 @param NumBytes size of memory mapped.\r
524 @param Direction direction of data flow for this memory's usage:\r
525 cpu->device, device->cpu or both ways.\r
526 @param DeviceAddr the mapped device address.\r
527\r
528**/\r
5e7e4fad 529VOID\r
4cda7726 530SnpUndi32CallbackSync (\r
531 IN UINT64 UniqueId,\r
532 IN UINT64 CpuAddr,\r
533 IN UINT32 NumBytes,\r
534 IN UINT32 Direction,\r
535 IN UINT64 DeviceAddr\r
5e7e4fad 536 )\r
5e7e4fad 537{\r
538 if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) {\r
539 return ;\r
540\r
541 }\r
542\r
543 switch (Direction) {\r
544 case FROM_DEVICE:\r
545 CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes);\r
546 break;\r
547\r
548 case TO_DEVICE:\r
549 CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes);\r
550 break;\r
551 }\r
552\r
553 return ;\r
554}\r