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