1 /** @file
2 This file contains the callback routines for 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 - 2014, Intel Corporation. All rights reserved.<BR>
7 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 Acquire or release a lock of the exclusive access to a critical section of the
21 code/data.
22
23 This is a callback routine supplied to UNDI3.1 at undi_start time.
24 New callbacks for 3.1: there won't be a virtual2physical callback for UNDI 3.1
25 because undi3.1 uses the MemMap call to map the required address by itself!
26
27 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
28 store Undi interface context (Undi does not read or write
29 this variable).
30 @param Enable Non-zero indicates acquire; Zero indicates release.
31
32 **/
33 VOID
34 EFIAPI
SnpUndi32CallbackBlock(IN UINT64 UniqueId,IN UINT32 Enable)35 SnpUndi32CallbackBlock (
36 IN UINT64 UniqueId,
37 IN UINT32 Enable
38 )
39 {
40 SNP_DRIVER *Snp;
41
42 Snp = (SNP_DRIVER *) (UINTN) UniqueId;
43 //
44 // tcpip was calling snp at tpl_notify and when we acquire a lock that was
45 // created at a lower level (TPL_CALLBACK) it gives an assert!
46 //
47 if (Enable != 0) {
48 EfiAcquireLock (&Snp->Lock);
49 } else {
50 EfiReleaseLock (&Snp->Lock);
51 }
52 }
53
54 /**
55 Delay MicroSeconds of micro seconds.
56
57 This is a callback routine supplied to UNDI at undi_start time.
58
59 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
60 store Undi interface context (Undi does not read or write
61 this variable).
62 @param MicroSeconds Number of micro seconds to pause, ususlly multiple of 10.
63
64 **/
65 VOID
66 EFIAPI
SnpUndi32CallbackDelay(IN UINT64 UniqueId,IN UINT64 MicroSeconds)67 SnpUndi32CallbackDelay (
68 IN UINT64 UniqueId,
69 IN UINT64 MicroSeconds
70 )
71 {
72 if (MicroSeconds != 0) {
73 gBS->Stall ((UINTN) MicroSeconds);
74 }
75 }
76
77 /**
78 IO routine for UNDI3.1.
79
80 This is a callback routine supplied to UNDI at undi_start time.
81
82 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this
83 to store Undi interface context (Undi does not read or
84 write this variable).
85 @param ReadOrWrite Indicates read or write, IO or Memory.
86 @param NumBytes Number of bytes to read or write.
87 @param MemOrPortAddr IO or memory address to read from or write to.
88 @param BufferPtr Memory location to read into or that contains the bytes
89 to write.
90
91 **/
92 VOID
93 EFIAPI
SnpUndi32CallbackMemio(IN UINT64 UniqueId,IN UINT8 ReadOrWrite,IN UINT8 NumBytes,IN UINT64 MemOrPortAddr,IN OUT UINT64 BufferPtr)94 SnpUndi32CallbackMemio (
95 IN UINT64 UniqueId,
96 IN UINT8 ReadOrWrite,
97 IN UINT8 NumBytes,
98 IN UINT64 MemOrPortAddr,
99 IN OUT UINT64 BufferPtr
100 )
101 {
102 SNP_DRIVER *Snp;
103 EFI_PCI_IO_PROTOCOL_WIDTH Width;
104
105 Snp = (SNP_DRIVER *) (UINTN) UniqueId;
106
107 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;
108 switch (NumBytes) {
109 case 2:
110 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;
111 break;
112
113 case 4:
114 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;
115 break;
116
117 case 8:
118 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;
119 break;
120 }
121
122 switch (ReadOrWrite) {
123 case PXE_IO_READ:
124 Snp->PciIo->Io.Read (
125 Snp->PciIo,
126 Width,
127 Snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address
128 MemOrPortAddr,
129 1, // count
130 (VOID *) (UINTN) BufferPtr
131 );
132 break;
133
134 case PXE_IO_WRITE:
135 Snp->PciIo->Io.Write (
136 Snp->PciIo,
137 Width,
138 Snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address
139 MemOrPortAddr,
140 1, // count
141 (VOID *) (UINTN) BufferPtr
142 );
143 break;
144
145 case PXE_MEM_READ:
146 Snp->PciIo->Mem.Read (
147 Snp->PciIo,
148 Width,
149 Snp->MemoryBarIndex, // BAR 0, Memory base address
150 MemOrPortAddr,
151 1, // count
152 (VOID *) (UINTN) BufferPtr
153 );
154 break;
155
156 case PXE_MEM_WRITE:
157 Snp->PciIo->Mem.Write (
158 Snp->PciIo,
159 Width,
160 Snp->MemoryBarIndex, // BAR 0, Memory base address
161 MemOrPortAddr,
162 1, // count
163 (VOID *) (UINTN) BufferPtr
164 );
165 break;
166 }
167
168 return ;
169 }
170
171 /**
172 Map a CPU address to a device address.
173
174 This is a callback routine supplied to UNDI at undi_start time.
175
176 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
177 store Undi interface context (Undi does not read or write
178 this variable).
179 @param CpuAddr Virtual address to be mapped.
180 @param NumBytes Size of memory to be mapped.
181 @param Direction Direction of data flow for this memory's usage:
182 cpu->device, device->cpu or both ways.
183 @param DeviceAddrPtr Pointer to return the mapped device address.
184
185 **/
186 VOID
187 EFIAPI
SnpUndi32CallbackMap(IN UINT64 UniqueId,IN UINT64 CpuAddr,IN UINT32 NumBytes,IN UINT32 Direction,IN OUT UINT64 DeviceAddrPtr)188 SnpUndi32CallbackMap (
189 IN UINT64 UniqueId,
190 IN UINT64 CpuAddr,
191 IN UINT32 NumBytes,
192 IN UINT32 Direction,
193 IN OUT UINT64 DeviceAddrPtr
194 )
195 {
196 EFI_PHYSICAL_ADDRESS *DevAddrPtr;
197 EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag;
198 UINTN BuffSize;
199 SNP_DRIVER *Snp;
200 UINTN Index;
201 EFI_STATUS Status;
202
203 BuffSize = (UINTN) NumBytes;
204 Snp = (SNP_DRIVER *) (UINTN) UniqueId;
205 DevAddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr;
206
207 if (CpuAddr == 0) {
208 *DevAddrPtr = 0;
209 return ;
210 }
211
212 switch (Direction) {
213 case TO_AND_FROM_DEVICE:
214 DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer;
215 break;
216
217 case FROM_DEVICE:
218 DirectionFlag = EfiPciIoOperationBusMasterWrite;
219 break;
220
221 case TO_DEVICE:
222 DirectionFlag = EfiPciIoOperationBusMasterRead;
223 break;
224
225 default:
226 *DevAddrPtr = 0;
227 //
228 // any non zero indicates error!
229 //
230 return ;
231 }
232 //
233 // find an unused map_list entry
234 //
235 for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
236 if (Snp->MapList[Index].VirtualAddress == 0) {
237 break;
238 }
239 }
240
241 if (Index >= MAX_MAP_LENGTH) {
242 DEBUG ((EFI_D_INFO, "SNP maplist is FULL\n"));
243 *DevAddrPtr = 0;
244 return ;
245 }
246
247 Snp->MapList[Index].VirtualAddress = (EFI_PHYSICAL_ADDRESS) CpuAddr;
248
249 Status = Snp->PciIo->Map (
250 Snp->PciIo,
251 DirectionFlag,
252 (VOID *) (UINTN) CpuAddr,
253 &BuffSize,
254 DevAddrPtr,
255 &(Snp->MapList[Index].MapCookie)
256 );
257 if (Status != EFI_SUCCESS) {
258 *DevAddrPtr = 0;
259 Snp->MapList[Index].VirtualAddress = 0;
260 }
261
262 return ;
263 }
264
265 /**
266 Unmap an address that was previously mapped using map callback.
267
268 This is a callback routine supplied to UNDI at undi_start time.
269
270 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
271 store. Undi interface context (Undi does not read or write
272 this variable).
273 @param CpuAddr Virtual address that was mapped.
274 @param NumBytes Size of memory mapped.
275 @param Direction Direction of data flow for this memory's usage:
276 cpu->device, device->cpu or both ways.
277 @param DeviceAddr The mapped device address.
278
279 **/
280 VOID
281 EFIAPI
SnpUndi32CallbackUnmap(IN UINT64 UniqueId,IN UINT64 CpuAddr,IN UINT32 NumBytes,IN UINT32 Direction,IN UINT64 DeviceAddr)282 SnpUndi32CallbackUnmap (
283 IN UINT64 UniqueId,
284 IN UINT64 CpuAddr,
285 IN UINT32 NumBytes,
286 IN UINT32 Direction,
287 IN UINT64 DeviceAddr
288 )
289 {
290 SNP_DRIVER *Snp;
291 UINT16 Index;
292
293 Snp = (SNP_DRIVER *) (UINTN) UniqueId;
294
295 for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
296 if (Snp->MapList[Index].VirtualAddress == CpuAddr) {
297 break;
298 }
299 }
300
301 if (Index >= MAX_MAP_LENGTH) {
302 DEBUG ((EFI_D_ERROR, "SNP could not find a mapping, failed to unmap.\n"));
303 return ;
304 }
305
306 Snp->PciIo->Unmap (Snp->PciIo, Snp->MapList[Index].MapCookie);
307 Snp->MapList[Index].VirtualAddress = 0;
308 Snp->MapList[Index].MapCookie = NULL;
309 return ;
310 }
311
312 /**
313 Synchronize the virtual buffer contents with the mapped buffer contents.
314
315 This is a callback routine supplied to UNDI at undi_start time. The virtual
316 and mapped buffers need not correspond to the same physical memory (especially
317 if the virtual address is > 4GB). Depending on the direction for which the
318 buffer is mapped, undi will need to synchronize their contents whenever it
319 writes to/reads from the buffer using either the cpu address or the device
320 address.
321 EFI does not provide a sync call since virt=physical, we should just do the
322 synchronization ourselves here.
323
324 @param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
325 store Undi interface context (Undi does not read or write
326 this variable).
327 @param CpuAddr Virtual address that was mapped.
328 @param NumBytes Size of memory mapped.
329 @param Direction Direction of data flow for this memory's usage:
330 cpu->device, device->cpu or both ways.
331 @param DeviceAddr The mapped device address.
332
333 **/
334 VOID
335 EFIAPI
SnpUndi32CallbackSync(IN UINT64 UniqueId,IN UINT64 CpuAddr,IN UINT32 NumBytes,IN UINT32 Direction,IN UINT64 DeviceAddr)336 SnpUndi32CallbackSync (
337 IN UINT64 UniqueId,
338 IN UINT64 CpuAddr,
339 IN UINT32 NumBytes,
340 IN UINT32 Direction,
341 IN UINT64 DeviceAddr
342 )
343 {
344 if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) {
345 return ;
346
347 }
348
349 switch (Direction) {
350 case FROM_DEVICE:
351 CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes);
352 break;
353
354 case TO_DEVICE:
355 CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes);
356 break;
357 }
358
359 return ;
360 }
361