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