]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/SnpDxe/transmit.c
d113edec962b70087246f27ad86886440d001492
[mirror_edk2.git] / MdeModulePkg / Universal / Network / SnpDxe / transmit.c
1 /** @file
2 Copyright (c) 2004 - 2007, 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
13 transmit.c
14
15 Abstract:
16
17 Revision history:
18 2000-Feb-03 M(f)J Genesis.
19
20 **/
21
22 #include "Snp.h"
23
24
25 /**
26 This routine calls undi to create the meadia header for the given data buffer.
27
28 @param snp pointer to SNP driver structure
29 @param MacHeaderPtr address where the media header will be filled in.
30 @param MacHeaderSize size of the memory at MacHeaderPtr
31 @param BufferPtr data buffer pointer
32 @param BufferLength Size of data in the BufferPtr
33 @param DestinationAddrPtr address of the destination mac address buffer
34 @param SourceAddrPtr address of the source mac address buffer
35 @param ProtocolPtr address of the protocol type
36
37 @retval EFI_SUCCESS if successfully completed the undi call
38 @retval Other error return from undi call.
39
40 **/
41 STATIC
42 EFI_STATUS
43 pxe_fillheader (
44 SNP_DRIVER *snp,
45 VOID *MacHeaderPtr,
46 UINTN MacHeaderSize,
47 VOID *BufferPtr,
48 UINTN BufferLength,
49 EFI_MAC_ADDRESS *DestinationAddrPtr,
50 EFI_MAC_ADDRESS *SourceAddrPtr,
51 UINT16 *ProtocolPtr
52 )
53 {
54 PXE_CPB_FILL_HEADER_FRAGMENTED *cpb;
55 EFI_STATUS Status;
56 struct s_v2p *pkt_v2p;
57 UINT64 TempData;
58
59 cpb = snp->cpb;
60 if (SourceAddrPtr) {
61 CopyMem (
62 (VOID *) cpb->SrcAddr,
63 (VOID *) SourceAddrPtr,
64 snp->mode.HwAddressSize
65 );
66 } else {
67 CopyMem (
68 (VOID *) cpb->SrcAddr,
69 (VOID *) &(snp->mode.CurrentAddress),
70 snp->mode.HwAddressSize
71 );
72 }
73
74 CopyMem (
75 (VOID *) cpb->DestAddr,
76 (VOID *) DestinationAddrPtr,
77 snp->mode.HwAddressSize
78 );
79
80 //
81 // we need to do the byte swapping
82 //
83 cpb->Protocol = (UINT16) PXE_SWAP_UINT16 (*ProtocolPtr);
84
85 cpb->PacketLen = (UINT32) (BufferLength);
86 cpb->MediaHeaderLen = (UINT16) MacHeaderSize;
87
88 cpb->FragCnt = 2;
89 cpb->reserved = 0;
90
91 cpb->FragDesc[0].FragAddr = (UINT64)(UINTN) MacHeaderPtr;
92 cpb->FragDesc[0].FragLen = (UINT32) MacHeaderSize;
93 cpb->FragDesc[1].FragAddr = (UINT64)(UINTN) BufferPtr;
94 cpb->FragDesc[1].FragLen = (UINT32) BufferLength;
95
96 cpb->FragDesc[0].reserved = cpb->FragDesc[1].reserved = 0;
97
98 if (snp->IsOldUndi) {
99 TempData = (UINT64) (UINTN) MacHeaderPtr;
100 if (TempData >= FOUR_GIGABYTES) {
101 cpb->FragDesc[0].FragAddr = (UINT64) (UINTN) snp->fill_hdr_buf;
102 cpb->FragDesc[0].FragLen = (UINT32) snp->init_info.MediaHeaderLen;
103 }
104
105 TempData = (UINT64) (UINTN) (BufferPtr);
106 if (TempData >= FOUR_GIGABYTES) {
107 //
108 // Let the device just read this buffer
109 //
110 Status = add_v2p (
111 &pkt_v2p,
112 EfiPciIoOperationBusMasterRead,
113 BufferPtr,
114 BufferLength
115 );
116 if (Status != EFI_SUCCESS) {
117 return Status;
118 }
119 //
120 // give the virtual address to UNDI and it will call back on Virt2Phys
121 // to get the mapped address, if it needs it
122 //
123 cpb->FragDesc[1].FragLen = (UINT32) pkt_v2p->bsize;
124 }
125 }
126
127 snp->cdb.OpCode = PXE_OPCODE_FILL_HEADER;
128 snp->cdb.OpFlags = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED;
129
130 snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
131 snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
132
133 snp->cdb.CPBsize = sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED);
134 snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;
135
136 snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
137 snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
138 snp->cdb.IFnum = snp->if_num;
139 snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
140
141 //
142 // Issue UNDI command and check result.
143 //
144 DEBUG ((EFI_D_NET, "\nsnp->undi.fill_header() "));
145
146 (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
147
148 if (snp->IsOldUndi) {
149 TempData = (UINT64) (UINTN) (BufferPtr);
150 if (TempData >= FOUR_GIGABYTES) {
151 del_v2p (BufferPtr);
152 }
153 //
154 // if we used the global buffer for header, copy the contents
155 //
156 TempData = (UINT64) (UINTN) MacHeaderPtr;
157 if (TempData >= FOUR_GIGABYTES) {
158 CopyMem (
159 MacHeaderPtr,
160 snp->fill_hdr_buf,
161 snp->init_info.MediaHeaderLen
162 );
163 }
164 }
165
166 switch (snp->cdb.StatCode) {
167 case PXE_STATCODE_SUCCESS:
168 return EFI_SUCCESS;
169
170 case PXE_STATCODE_INVALID_PARAMETER:
171 DEBUG (
172 (EFI_D_ERROR,
173 "\nsnp->undi.fill_header() %xh:%xh\n",
174 snp->cdb.StatFlags,
175 snp->cdb.StatCode)
176 );
177
178 return EFI_INVALID_PARAMETER;
179
180 default:
181 DEBUG (
182 (EFI_D_ERROR,
183 "\nsnp->undi.fill_header() %xh:%xh\n",
184 snp->cdb.StatFlags,
185 snp->cdb.StatCode)
186 );
187
188 return EFI_DEVICE_ERROR;
189 }
190 }
191
192
193 /**
194 This routine calls undi to transmit the given data buffer
195
196 @param snp pointer to SNP driver structure
197 @param BufferPtr data buffer pointer
198 @param BufferLength Size of data in the BufferPtr
199
200 @retval EFI_SUCCESS if successfully completed the undi call
201 @retval Other error return from undi call.
202
203 **/
204 STATIC
205 EFI_STATUS
206 pxe_transmit (
207 SNP_DRIVER *snp,
208 VOID *BufferPtr,
209 UINTN BufferLength
210 )
211 {
212 PXE_CPB_TRANSMIT *cpb;
213 EFI_STATUS Status;
214 struct s_v2p *v2p;
215 UINT64 TempData;
216
217 cpb = snp->cpb;
218 cpb->FrameAddr = (UINT64) (UINTN) BufferPtr;
219 cpb->DataLen = (UINT32) BufferLength;
220
221 TempData = (UINT64) (UINTN) BufferPtr;
222 if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {
223 //
224 // we need to create a mapping now and give it to the undi when it calls
225 // the Virt2Phys on this address.
226 // this is a transmit, just map it for the device to READ
227 //
228 Status = add_v2p (
229 &v2p,
230 EfiPciIoOperationBusMasterRead,
231 BufferPtr,
232 BufferLength
233 );
234 if (Status != EFI_SUCCESS) {
235 return Status;
236 }
237
238 cpb->DataLen = (UINT32) v2p->bsize;
239 }
240
241 cpb->MediaheaderLen = 0;
242 cpb->reserved = 0;
243
244 snp->cdb.OpFlags = PXE_OPFLAGS_TRANSMIT_WHOLE;
245
246 snp->cdb.CPBsize = sizeof (PXE_CPB_TRANSMIT);
247 snp->cdb.CPBaddr = (UINT64)(UINTN) cpb;
248
249 snp->cdb.OpCode = PXE_OPCODE_TRANSMIT;
250 snp->cdb.DBsize = PXE_DBSIZE_NOT_USED;
251 snp->cdb.DBaddr = PXE_DBADDR_NOT_USED;
252
253 snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;
254 snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
255 snp->cdb.IFnum = snp->if_num;
256 snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
257
258 //
259 // Issue UNDI command and check result.
260 //
261 DEBUG ((EFI_D_NET, "\nsnp->undi.transmit() "));
262 DEBUG ((EFI_D_NET, "\nsnp->cdb.OpCode == %x", snp->cdb.OpCode));
263 DEBUG ((EFI_D_NET, "\nsnp->cdb.CPBaddr == %X", snp->cdb.CPBaddr));
264 DEBUG ((EFI_D_NET, "\nsnp->cdb.DBaddr == %X", snp->cdb.DBaddr));
265 DEBUG ((EFI_D_NET, "\ncpb->FrameAddr == %X\n", cpb->FrameAddr));
266
267 (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);
268
269 DEBUG ((EFI_D_NET, "\nexit snp->undi.transmit() "));
270 DEBUG ((EFI_D_NET, "\nsnp->cdb.StatCode == %r", snp->cdb.StatCode));
271
272 //
273 // we will unmap the buffers in get_status call, not here
274 //
275 switch (snp->cdb.StatCode) {
276 case PXE_STATCODE_SUCCESS:
277 return EFI_SUCCESS;
278
279 case PXE_STATCODE_QUEUE_FULL:
280 case PXE_STATCODE_BUSY:
281 Status = EFI_NOT_READY;
282 break;
283
284 default:
285 Status = EFI_DEVICE_ERROR;
286 }
287
288 DEBUG (
289 (EFI_D_ERROR,
290 "\nsnp->undi.transmit() %xh:%xh\n",
291 snp->cdb.StatFlags,
292 snp->cdb.StatCode)
293 );
294
295 return Status;
296 }
297
298
299 /**
300 This is the snp interface routine for transmitting a packet. this routine
301 basically retrieves the snp structure, checks the snp state and calls
302 pxe_fill_header and pxe_transmit calls to complete the transmission.
303
304 @param this pointer to SNP driver context
305 @param MacHeaderSize size of the memory at MacHeaderPtr
306 @param BufferLength Size of data in the BufferPtr
307 @param BufferPtr data buffer pointer
308 @param SourceAddrPtr address of the source mac address buffer
309 @param DestinationAddrPtr address of the destination mac address buffer
310 @param ProtocolPtr address of the protocol type
311
312 @retval EFI_SUCCESS if successfully completed the undi call
313 @retval Other error return from undi call.
314
315 **/
316 EFI_STATUS
317 EFIAPI
318 snp_undi32_transmit (
319 IN EFI_SIMPLE_NETWORK_PROTOCOL * this,
320 IN UINTN MacHeaderSize,
321 IN UINTN BufferLength,
322 IN VOID *BufferPtr,
323 IN EFI_MAC_ADDRESS * SourceAddrPtr OPTIONAL,
324 IN EFI_MAC_ADDRESS * DestinationAddrPtr OPTIONAL,
325 IN UINT16 *ProtocolPtr OPTIONAL
326 )
327 {
328 SNP_DRIVER *snp;
329 EFI_STATUS Status;
330 EFI_TPL OldTpl;
331
332 if (this == NULL) {
333 return EFI_INVALID_PARAMETER;
334 }
335
336 snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);
337
338 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
339
340 if (snp == NULL) {
341 return EFI_DEVICE_ERROR;
342 }
343
344 switch (snp->mode.State) {
345 case EfiSimpleNetworkInitialized:
346 break;
347
348 case EfiSimpleNetworkStopped:
349 Status = EFI_NOT_STARTED;
350 goto ON_EXIT;
351
352 default:
353 Status = EFI_DEVICE_ERROR;
354 goto ON_EXIT;
355 }
356
357 if (BufferPtr == NULL) {
358 Status = EFI_INVALID_PARAMETER;
359 goto ON_EXIT;
360 }
361
362 if (BufferLength < snp->mode.MediaHeaderSize) {
363 Status = EFI_BUFFER_TOO_SMALL;
364 goto ON_EXIT;
365 }
366
367 //
368 // if the MacHeaderSize is non-zero, we need to fill up the header and for that
369 // we need the destination address and the protocol
370 //
371 if (MacHeaderSize != 0) {
372 if (MacHeaderSize != snp->mode.MediaHeaderSize || DestinationAddrPtr == 0 || ProtocolPtr == 0) {
373 Status = EFI_INVALID_PARAMETER;
374 goto ON_EXIT;
375 }
376
377 Status = pxe_fillheader (
378 snp,
379 BufferPtr,
380 MacHeaderSize,
381 (UINT8 *) BufferPtr + MacHeaderSize,
382 BufferLength - MacHeaderSize,
383 DestinationAddrPtr,
384 SourceAddrPtr,
385 ProtocolPtr
386 );
387
388 if (EFI_ERROR (Status)) {
389 goto ON_EXIT;
390 }
391 }
392
393 Status = pxe_transmit (snp, BufferPtr, BufferLength);
394
395 ON_EXIT:
396 gBS->RestoreTPL (OldTpl);
397
398 return Status;
399 }