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