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