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