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