]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Network/Snp32_64/Dxe/snp.c
Partially make EdkModulePkg pass intel IPF compiler with /W4 /WX switched on.
[mirror_edk2.git] / EdkModulePkg / Universal / Network / Snp32_64 / Dxe / snp.c
CommitLineData
878ddf1f 1/*++\r
2Copyright (c) 2006, 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 snp.c\r
13\r
14Abstract:\r
15\r
16--*/\r
17\r
18\r
4cbd855e 19#include "Snp.h"\r
878ddf1f 20\r
878ddf1f 21//\r
22// Module global variables needed to support undi 3.0 interface\r
23//\r
24EFI_PCI_IO_PROTOCOL *mPciIoFncs;\r
25struct s_v2p *_v2p = NULL; // undi3.0 map_list head\r
26// End Global variables\r
27//\r
878ddf1f 28\r
29STATIC\r
30EFI_STATUS\r
31issue_hwundi_command (\r
32 UINT64 cdb\r
33 )\r
34/*++\r
35\r
36Routine Description:\r
37\r
38Arguments:\r
39\r
40Returns:\r
41\r
42--*/\r
43{\r
44#if SNP_DEBUG\r
45 Aprint ("\nissue_hwundi_command() - This should not be called!");\r
46 snp_wait_for_key ();\r
47#endif\r
48 if (cdb == 0) {\r
49 return EFI_INVALID_PARAMETER;\r
50\r
51 }\r
52 //\r
53 // %%TBD - For now, nothing is done.\r
54 //\r
55 return EFI_UNSUPPORTED;\r
56}\r
57\r
58STATIC\r
59UINT8\r
60calc_8bit_cksum (\r
61 VOID *ptr,\r
62 UINTN len\r
63 )\r
64/*++\r
65\r
66Routine Description:\r
67 Compute 8-bit checksum of a buffer.\r
68 \r
69Arguments:\r
70 ptr - Pointer to buffer.\r
71 len - Length of buffer in bytes.\r
72\r
73Returns:\r
74 8-bit checksum of all bytes in buffer.\r
75 If ptr is NULL or len is zero, zero is returned.\r
76\r
77--*/\r
78{\r
79 UINT8 *bptr;\r
80 UINT8 cksum;\r
81\r
82 bptr = ptr;\r
83 cksum = 0;\r
84\r
85 if (ptr == NULL || len == 0) {\r
86 return 0;\r
87 }\r
88\r
89 while (len--) {\r
90 cksum = (UINT8) (cksum +*bptr++);\r
91 }\r
92\r
93 return cksum;\r
94}\r
95\r
1cc8ee78 96STATIC\r
878ddf1f 97EFI_STATUS\r
98EFIAPI\r
99SimpleNetworkDriverSupported (\r
100 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
101 IN EFI_HANDLE Controller,\r
102 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
103 )\r
104/*++\r
105\r
106 Routine Description:\r
107 Test to see if this driver supports Controller. Any Controller\r
108 that contains a Nii protocol can be supported.\r
109\r
110 Arguments:\r
111 This - Protocol instance pointer.\r
112 Controller - Handle of device to test.\r
113 RemainingDevicePath - Not used.\r
114\r
115 Returns:\r
116 EFI_SUCCESS - This driver supports this device.\r
117 EFI_ALREADY_STARTED - This driver is already running on this device.\r
118 other - This driver does not support this device.\r
119\r
120--*/\r
121{\r
122 EFI_STATUS Status;\r
123 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;\r
124 PXE_UNDI *pxe;\r
125 BOOLEAN IsUndi31;\r
126\r
127 IsUndi31 = FALSE;\r
128 Status = gBS->OpenProtocol (\r
129 Controller,\r
130 &gEfiDevicePathProtocolGuid,\r
131 NULL,\r
132 This->DriverBindingHandle,\r
133 Controller,\r
134 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
135 );\r
136 if (EFI_ERROR (Status)) {\r
137 return Status;\r
138 }\r
139\r
140 Status = gBS->OpenProtocol (\r
141 Controller,\r
142 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
143 (VOID **) &NiiProtocol,\r
144 This->DriverBindingHandle,\r
145 Controller,\r
146 EFI_OPEN_PROTOCOL_BY_DRIVER\r
147 );\r
148 if (Status == EFI_ALREADY_STARTED)\r
149 {\r
150#if SNP_DEBUG\r
151 Aprint ("Support(): Already Started. on handle %x\n", Controller);\r
152#endif\r
153 return EFI_ALREADY_STARTED;\r
154 }\r
155\r
156 if (!EFI_ERROR (Status))\r
157 {\r
158\r
159#if SNP_DEBUG\r
160 Aprint ("Support(): UNDI3.1 found on handle %x\n", Controller);\r
161 snp_wait_for_key ();\r
162#endif\r
163 IsUndi31 = TRUE;\r
164 } else {\r
165 //\r
166 // try the older 3.0 driver\r
167 //\r
168 Status = gBS->OpenProtocol (\r
169 Controller,\r
170 &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
171 (VOID **) &NiiProtocol,\r
172 This->DriverBindingHandle,\r
173 Controller,\r
174 EFI_OPEN_PROTOCOL_BY_DRIVER\r
175 );\r
176 if (EFI_ERROR (Status)) {\r
177 return Status;\r
178 }\r
179\r
180#if SNP_DEBUG\r
181 Aprint ("Support(): UNDI3.0 found on handle %x\n", Controller);\r
182 snp_wait_for_key ();\r
183#endif\r
184 }\r
185 //\r
186 // check the version, we don't want to connect to the undi16\r
187 //\r
188 if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {\r
189 Status = EFI_UNSUPPORTED;\r
190 goto Done;\r
191 }\r
192 //\r
193 // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.\r
194 //\r
195 if (NiiProtocol->ID & 0x0F) {\r
196 DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));\r
197 Status = EFI_UNSUPPORTED;\r
198 goto Done;\r
199 }\r
200\r
201 pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->ID);\r
202\r
203 //\r
204 // Verify !PXE revisions.\r
205 //\r
206 if (pxe->hw.Signature != PXE_ROMID_SIGNATURE) {\r
207 DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));\r
208 Status = EFI_UNSUPPORTED;\r
209 goto Done;\r
210 }\r
211\r
212 if (pxe->hw.Rev < PXE_ROMID_REV) {\r
213 DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));\r
214 Status = EFI_UNSUPPORTED;\r
215 goto Done;\r
216 }\r
217\r
218 if (pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {\r
219\r
220 DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));\r
221 Status = EFI_UNSUPPORTED;\r
222 goto Done;\r
223\r
224 } else if (pxe->hw.MajorVer == PXE_ROMID_MAJORVER && pxe->hw.MinorVer < PXE_ROMID_MINORVER) {\r
225 DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));\r
226 Status = EFI_UNSUPPORTED;\r
227 goto Done;\r
228 }\r
229 //\r
230 // Do S/W UNDI specific checks.\r
231 //\r
232 if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {\r
233 if (pxe->sw.EntryPoint < pxe->sw.Len) {\r
234 DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));\r
235 Status = EFI_UNSUPPORTED;\r
236 goto Done;\r
237 }\r
238\r
239 if (pxe->sw.BusCnt == 0) {\r
240 DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));\r
241 Status = EFI_UNSUPPORTED;\r
242 goto Done;\r
243 }\r
244 }\r
245\r
246 Status = EFI_SUCCESS;\r
247#if SNP_DEBUG\r
248 Aprint ("Support(): supported on %x\n", Controller);\r
249 snp_wait_for_key ();\r
250#endif\r
251\r
252Done:\r
253 if (IsUndi31) {\r
254 gBS->CloseProtocol (\r
255 Controller,\r
256 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
257 This->DriverBindingHandle,\r
258 Controller\r
259 );\r
260\r
261 } else {\r
262 gBS->CloseProtocol (\r
263 Controller,\r
264 &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
265 This->DriverBindingHandle,\r
266 Controller\r
267 );\r
268 }\r
269\r
270 return Status;\r
271}\r
272\r
1cc8ee78 273STATIC\r
878ddf1f 274EFI_STATUS\r
275EFIAPI\r
276SimpleNetworkDriverStart (\r
277 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
278 IN EFI_HANDLE Controller,\r
279 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
280 )\r
281/*++\r
282\r
283Routine Description:\r
284 called for any handle that we said "supported" in the above call!\r
285\r
286Arguments:\r
287 This - Protocol instance pointer.\r
288 Controller - Handle of device to start\r
289 RemainingDevicePath - Not used.\r
290\r
291 Returns:\r
292 EFI_SUCCESS - This driver supports this device.\r
293 other - This driver failed to start this device.\r
294\r
295--*/\r
296{\r
297 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;\r
298 EFI_DEVICE_PATH_PROTOCOL *NiiDevicePath;\r
299 EFI_STATUS Status;\r
300 PXE_UNDI *pxe;\r
301 SNP_DRIVER *snp;\r
302 VOID *addr;\r
303 VOID *addrUnmap;\r
304 EFI_PHYSICAL_ADDRESS paddr;\r
305 EFI_HANDLE Handle;\r
306 UINTN Size;\r
307 BOOLEAN UndiNew;\r
308 PXE_PCI_CONFIG_INFO ConfigInfo;\r
309 PCI_TYPE00 *ConfigHeader;\r
310 UINT32 *TempBar;\r
311 UINT8 BarIndex;\r
312 PXE_STATFLAGS InitStatFlags;\r
313\r
314 DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() "));\r
315\r
316 Status = gBS->OpenProtocol (\r
317 Controller,\r
318 &gEfiDevicePathProtocolGuid,\r
319 (VOID **) &NiiDevicePath,\r
320 This->DriverBindingHandle,\r
321 Controller,\r
322 EFI_OPEN_PROTOCOL_BY_DRIVER\r
323 );\r
324\r
325 if (EFI_ERROR (Status)) {\r
326 return Status;\r
327 }\r
328\r
329 Status = gBS->LocateDevicePath (\r
330 &gEfiPciIoProtocolGuid,\r
331 &NiiDevicePath,\r
332 &Handle\r
333 );\r
334\r
335 if (EFI_ERROR (Status)) {\r
336 return Status;\r
337 }\r
338\r
339 Status = gBS->OpenProtocol (\r
340 Handle,\r
341 &gEfiPciIoProtocolGuid,\r
342 (VOID **) &mPciIoFncs,\r
343 This->DriverBindingHandle,\r
344 Controller,\r
345 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
346 );\r
347 if (EFI_ERROR (Status)) {\r
348 return Status;\r
349 }\r
350 //\r
351 // Get the NII interface. look for 3.1 undi first, if it is not there\r
352 // then look for 3.0, validate the interface.\r
353 //\r
354 Status = gBS->OpenProtocol (\r
355 Controller,\r
356 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
357 (VOID **) &Nii,\r
358 This->DriverBindingHandle,\r
359 Controller,\r
360 EFI_OPEN_PROTOCOL_BY_DRIVER\r
361 );\r
362 if (Status == EFI_ALREADY_STARTED) {\r
363 gBS->CloseProtocol (\r
364 Controller,\r
365 &gEfiDevicePathProtocolGuid,\r
366 This->DriverBindingHandle,\r
367 Controller\r
368 );\r
369 return Status;\r
370 }\r
371\r
372 if (!EFI_ERROR (Status)) {\r
373 //\r
374 // probably not a 3.1 UNDI\r
375 //\r
376 UndiNew = TRUE;\r
377#if SNP_DEBUG\r
378 Aprint ("Start(): UNDI3.1 found\n");\r
379 snp_wait_for_key ();\r
380#endif\r
381 } else {\r
382 UndiNew = FALSE;\r
383 Status = gBS->OpenProtocol (\r
384 Controller,\r
385 &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
386 (VOID **) &Nii,\r
387 This->DriverBindingHandle,\r
388 Controller,\r
389 EFI_OPEN_PROTOCOL_BY_DRIVER\r
390 );\r
391 if (EFI_ERROR (Status)) {\r
392 gBS->CloseProtocol (\r
393 Controller,\r
394 &gEfiDevicePathProtocolGuid,\r
395 This->DriverBindingHandle,\r
396 Controller\r
397 );\r
398\r
399 return Status;\r
400 }\r
401\r
402#if SNP_DEBUG\r
403 Aprint ("Start(): UNDI3.0 found\n");\r
404 snp_wait_for_key ();\r
405#endif\r
406 }\r
407\r
408 pxe = (PXE_UNDI *) (UINTN) (Nii->ID);\r
409\r
410 if (calc_8bit_cksum (pxe, pxe->hw.Len) != 0) {\r
411 DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));\r
412 goto NiiError;\r
413 }\r
414\r
415 if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
416 //\r
417 // We can get any packets.\r
418 //\r
419 } else if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
420 //\r
421 // We need to be able to get broadcast packets for DHCP.\r
422 // If we do not have promiscuous support, we must at least have\r
423 // broadcast support or we cannot do DHCP!\r
424 //\r
425 } else {\r
426 DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));\r
427 goto NiiError;\r
428 }\r
429 //\r
430 // OK, we like this UNDI, and we know snp is not already there on this handle\r
431 // Allocate and initialize a new simple network protocol structure.\r
432 //\r
433 Status = mPciIoFncs->AllocateBuffer (\r
434 mPciIoFncs,\r
435 AllocateAnyPages,\r
436 EfiBootServicesData,\r
437 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
438 &addr,\r
439 0\r
440 );\r
441\r
442 if (Status != EFI_SUCCESS) {\r
443 DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));\r
444 goto NiiError;\r
445 }\r
446\r
447 snp = (SNP_DRIVER *) (UINTN) addr;\r
448\r
449 if (!UndiNew) {\r
450 Size = SNP_MEM_PAGES (sizeof (SNP_DRIVER));\r
451\r
452 Status = mPciIoFncs->Map (\r
453 mPciIoFncs,\r
454 EfiPciIoOperationBusMasterCommonBuffer,\r
455 addr,\r
456 &Size,\r
457 &paddr,\r
458 &addrUnmap\r
459 );\r
460\r
461 ASSERT (paddr);\r
462\r
463 DEBUG ((EFI_D_NET, "\nSNP_DRIVER @ %Xh, sizeof(SNP_DRIVER) == %d", addr, sizeof (SNP_DRIVER)));\r
464 snp = (SNP_DRIVER *) (UINTN) paddr;\r
465 snp->SnpDriverUnmap = addrUnmap;\r
466 }\r
467\r
468 ZeroMem (snp, sizeof (SNP_DRIVER));\r
469\r
470 snp->IoFncs = mPciIoFncs;\r
471 snp->IsOldUndi = (BOOLEAN) (!UndiNew);\r
472\r
473 snp->Signature = SNP_DRIVER_SIGNATURE;\r
474\r
475 EfiInitializeLock (&snp->lock, EFI_TPL_NOTIFY);\r
476\r
477 snp->snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;\r
478 snp->snp.Start = snp_undi32_start;\r
479 snp->snp.Stop = snp_undi32_stop;\r
480 snp->snp.Initialize = snp_undi32_initialize;\r
481 snp->snp.Reset = snp_undi32_reset;\r
482 snp->snp.Shutdown = snp_undi32_shutdown;\r
483 snp->snp.ReceiveFilters = snp_undi32_receive_filters;\r
484 snp->snp.StationAddress = snp_undi32_station_address;\r
485 snp->snp.Statistics = snp_undi32_statistics;\r
486 snp->snp.MCastIpToMac = snp_undi32_mcast_ip_to_mac;\r
487 snp->snp.NvData = snp_undi32_nvdata;\r
488 snp->snp.GetStatus = snp_undi32_get_status;\r
489 snp->snp.Transmit = snp_undi32_transmit;\r
490 snp->snp.Receive = snp_undi32_receive;\r
491 snp->snp.WaitForPacket = NULL;\r
492\r
493 snp->snp.Mode = &snp->mode;\r
494\r
495 snp->tx_rx_bufsize = 0;\r
496 snp->tx_rx_buffer = NULL;\r
497\r
498 snp->if_num = Nii->IfNum;\r
499\r
500 if ((pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {\r
501 snp->is_swundi = FALSE;\r
502 snp->issue_undi32_command = &issue_hwundi_command;\r
503 } else {\r
504 snp->is_swundi = TRUE;\r
505\r
506 if ((pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {\r
507 snp->issue_undi32_command = (issue_undi32_command) (UINTN) pxe->sw.EntryPoint;\r
508 } else {\r
509 snp->issue_undi32_command = (issue_undi32_command) (UINTN) ((UINT8) (UINTN) pxe + pxe->sw.EntryPoint);\r
510 }\r
511 }\r
512 //\r
513 // Allocate a global CPB and DB buffer for this UNDI interface.\r
514 // we do this because:\r
515 //\r
516 // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be\r
517 // within 2GB limit, create them here and map them so that when undi calls\r
518 // v2p callback to check if the physical address is < 2gb, we will pass.\r
519 //\r
520 // -This is not a requirement for 3.1 or later UNDIs but the code looks\r
521 // simpler if we use the same cpb, db variables for both old and new undi\r
522 // interfaces from all the SNP interface calls (we don't map the buffers\r
523 // for the newer undi interfaces though)\r
524 // .\r
525 // -it is OK to allocate one global set of CPB, DB pair for each UNDI\r
526 // interface as EFI does not multi-task and so SNP will not be re-entered!\r
527 //\r
528 Status = mPciIoFncs->AllocateBuffer (\r
529 mPciIoFncs,\r
530 AllocateAnyPages,\r
531 EfiBootServicesData,\r
532 SNP_MEM_PAGES (4096),\r
533 &addr,\r
534 0\r
535 );\r
536\r
537 if (Status != EFI_SUCCESS) {\r
538 DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));\r
539 goto Error_DeleteSNP;\r
540 }\r
541\r
542 if (snp->IsOldUndi) {\r
543 Size = SNP_MEM_PAGES (4096);\r
544\r
545 Status = mPciIoFncs->Map (\r
546 mPciIoFncs,\r
547 EfiPciIoOperationBusMasterCommonBuffer,\r
548 addr,\r
549 &Size,\r
550 &paddr,\r
551 &snp->CpbUnmap\r
552 );\r
553\r
554 ASSERT (paddr);\r
555\r
556 snp->cpb = (VOID *) (UINTN) paddr;\r
557 snp->db = (VOID *) ((UINTN) paddr + 2048);\r
558 } else {\r
559 snp->cpb = (VOID *) (UINTN) addr;\r
560 snp->db = (VOID *) ((UINTN) addr + 2048);\r
561 }\r
562 //\r
563 // pxe_start call is going to give the callback functions to UNDI, these callback\r
564 // functions use the BarIndex values from the snp structure, so these must be initialized\r
565 // with default values before doing a pxe_start. The correct values can be obtained after\r
566 // getting the config information from UNDI\r
567 //\r
568 snp->MemoryBarIndex = 0;\r
569 snp->IoBarIndex = 1;\r
570\r
571 //\r
572 // we need the undi init information many times in this snp code, just get it\r
573 // once here and store it in the snp driver structure. to get Init Info\r
574 // from UNDI we have to start undi first.\r
575 //\r
576 Status = pxe_start (snp);\r
577\r
578 if (Status != EFI_SUCCESS) {\r
579 goto Error_DeleteCPBDB;\r
580 }\r
581\r
582 snp->cdb.OpCode = PXE_OPCODE_GET_INIT_INFO;\r
583 snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
584\r
585 snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
586 snp->cdb.CPBaddr = PXE_DBADDR_NOT_USED;\r
587\r
588 snp->cdb.DBsize = sizeof snp->init_info;\r
589 snp->cdb.DBaddr = (UINT64) (UINTN) &snp->init_info;\r
590\r
591 snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
592 snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
593\r
594 snp->cdb.IFnum = snp->if_num;\r
595 snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
596\r
597 DEBUG ((EFI_D_NET, "\nsnp->undi.get_init_info() "));\r
598\r
599 (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);\r
600\r
601 //\r
602 // Save the INIT Stat Code...\r
603 //\r
604 InitStatFlags = snp->cdb.StatFlags;\r
605\r
606 if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
607 DEBUG ((EFI_D_NET, "\nsnp->undi.init_info() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));\r
608 pxe_stop (snp);\r
609 goto Error_DeleteCPBDB;\r
610 }\r
611\r
612 snp->cdb.OpCode = PXE_OPCODE_GET_CONFIG_INFO;\r
613 snp->cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
614\r
615 snp->cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
616 snp->cdb.CPBaddr = PXE_DBADDR_NOT_USED;\r
617\r
618 snp->cdb.DBsize = sizeof ConfigInfo;\r
619 snp->cdb.DBaddr = (UINT64) (UINTN) &ConfigInfo;\r
620\r
621 snp->cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
622 snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
623\r
624 snp->cdb.IFnum = snp->if_num;\r
625 snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
626\r
627 DEBUG ((EFI_D_NET, "\nsnp->undi.get_config_info() "));\r
628\r
629 (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);\r
630\r
631 if (snp->cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
632 DEBUG ((EFI_D_NET, "\nsnp->undi.config_info() %xh:%xh\n", snp->cdb.StatFlags, snp->cdb.StatCode));\r
633 pxe_stop (snp);\r
634 goto Error_DeleteCPBDB;\r
635 }\r
636 //\r
637 // Find the correct BAR to do IO.\r
638 //\r
639 //\r
640 // Enumerate through the PCI BARs for the device to determine which one is\r
641 // the IO BAR. Save the index of the BAR into the adapter info structure.\r
642 // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped\r
643 //\r
644 ConfigHeader = (PCI_TYPE00 *) &ConfigInfo.Config.Byte[0];\r
645 TempBar = (UINT32 *) &ConfigHeader->Device.Bar[0];\r
646 for (BarIndex = 0; BarIndex <= 5; BarIndex++) {\r
647 if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {\r
648 //\r
649 // This is a 64-bit memory bar, skip this and the\r
650 // next bar as well.\r
651 //\r
652 TempBar++;\r
653 }\r
654\r
655 if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {\r
656 snp->IoBarIndex = BarIndex;\r
657 break;\r
658 }\r
659\r
660 TempBar++;\r
661 }\r
662\r
663 //\r
664 // We allocate 2 more global buffers for undi 3.0 interface. We use these\r
665 // buffers to pass to undi when the user buffers are beyond 4GB.\r
666 // UNDI 3.0 wants all the addresses passed to it to be\r
667 // within 2GB limit, create them here and map them so that when undi calls\r
668 // v2p callback to check if the physical address is < 2gb, we will pass.\r
669 //\r
670 // For 3.1 and later UNDIs, we do not do this because undi is\r
671 // going to call the map() callback if and only if it wants to use the\r
672 // device address for any address it receives.\r
673 //\r
674 if (snp->IsOldUndi) {\r
675 //\r
676 // buffer for receive\r
677 //\r
678 Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);\r
679 Status = mPciIoFncs->AllocateBuffer (\r
680 mPciIoFncs,\r
681 AllocateAnyPages,\r
682 EfiBootServicesData,\r
683 Size,\r
684 &addr,\r
685 0\r
686 );\r
687\r
688 if (Status != EFI_SUCCESS) {\r
689 DEBUG ((EFI_D_ERROR, "\nCould not allocate receive buffer.\n"));\r
690 goto Error_DeleteCPBDB;\r
691 }\r
692\r
693 Status = mPciIoFncs->Map (\r
694 mPciIoFncs,\r
695 EfiPciIoOperationBusMasterCommonBuffer,\r
696 addr,\r
697 &Size,\r
698 &paddr,\r
699 &snp->ReceiveBufUnmap\r
700 );\r
701\r
702 ASSERT (paddr);\r
703\r
704 snp->receive_buf = (UINT8 *) (UINTN) paddr;\r
705\r
706 //\r
707 // buffer for fill_header\r
708 //\r
709 Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen);\r
710 Status = mPciIoFncs->AllocateBuffer (\r
711 mPciIoFncs,\r
712 AllocateAnyPages,\r
713 EfiBootServicesData,\r
714 Size,\r
715 &addr,\r
716 0\r
717 );\r
718\r
719 if (Status != EFI_SUCCESS) {\r
720 DEBUG ((EFI_D_ERROR, "\nCould not allocate fill_header buffer.\n"));\r
721 goto Error_DeleteRCVBuf;\r
722 }\r
723\r
724 Status = mPciIoFncs->Map (\r
725 mPciIoFncs,\r
726 EfiPciIoOperationBusMasterCommonBuffer,\r
727 addr,\r
728 &Size,\r
729 &paddr,\r
730 &snp->FillHdrBufUnmap\r
731 );\r
732\r
733 ASSERT (paddr);\r
734 snp->fill_hdr_buf = (UINT8 *) (UINTN) paddr;\r
735 }\r
736 //\r
737 // Initialize simple network protocol mode structure\r
738 //\r
739 snp->mode.State = EfiSimpleNetworkStopped;\r
740 snp->mode.HwAddressSize = snp->init_info.HWaddrLen;\r
741 snp->mode.MediaHeaderSize = snp->init_info.MediaHeaderLen;\r
742 snp->mode.MaxPacketSize = snp->init_info.FrameDataLen;\r
743 snp->mode.NvRamAccessSize = snp->init_info.NvWidth;\r
744 snp->mode.NvRamSize = snp->init_info.NvCount * snp->mode.NvRamAccessSize;\r
745 snp->mode.IfType = snp->init_info.IFtype;\r
746 snp->mode.MaxMCastFilterCount = snp->init_info.MCastFilterCnt;\r
747 snp->mode.MCastFilterCount = 0;\r
748\r
749 switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {\r
750 case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:\r
751 snp->mode.MediaPresentSupported = TRUE;\r
752 break;\r
753\r
754 case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:\r
755 default:\r
756 snp->mode.MediaPresentSupported = FALSE;\r
757 }\r
758\r
759 if ((pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {\r
760 snp->mode.MacAddressChangeable = TRUE;\r
761 } else {\r
762 snp->mode.MacAddressChangeable = FALSE;\r
763 }\r
764\r
765 if ((pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {\r
766 snp->mode.MultipleTxSupported = TRUE;\r
767 } else {\r
768 snp->mode.MultipleTxSupported = FALSE;\r
769 }\r
770\r
771 snp->mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
772\r
773 if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {\r
774 snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
775\r
776 }\r
777\r
778 if ((pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
779 snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
780\r
781 }\r
782\r
783 if ((pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
784 snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
785\r
786 }\r
787\r
788 if ((pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {\r
789 snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
790\r
791 }\r
792\r
793 if (pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) {\r
794 snp->mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
795\r
796 }\r
797\r
798 snp->mode.ReceiveFilterSetting = 0;\r
799\r
800 //\r
801 // need to get the station address to save in the mode structure. we need to\r
802 // initialize the UNDI first for this.\r
803 //\r
804 snp->tx_rx_bufsize = snp->init_info.MemoryRequired;\r
805 Status = pxe_init (snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);\r
806\r
807 if (Status) {\r
808 pxe_stop (snp);\r
809 goto Error_DeleteHdrBuf;\r
810 }\r
811\r
812 Status = pxe_get_stn_addr (snp);\r
813\r
814 if (Status != EFI_SUCCESS) {\r
815 DEBUG ((EFI_D_ERROR, "\nsnp->undi.get_station_addr() failed.\n"));\r
816 pxe_shutdown (snp);\r
817 pxe_stop (snp);\r
818 goto Error_DeleteHdrBuf;\r
819 }\r
820\r
821 snp->mode.MediaPresent = FALSE;\r
822\r
823 //\r
824 // We should not leave UNDI started and initialized here. this DriverStart()\r
825 // routine must only find and attach the SNP interface to UNDI layer that it\r
826 // finds on the given handle!\r
827 // The UNDI layer will be started when upper layers call snp->start.\r
828 // How ever, this DriverStart() must fill up the snp mode structure which\r
829 // contains the MAC address of the NIC. For this reason we started and\r
830 // initialized UNDI here, now we are done, do a shutdown and stop of the\r
831 // UNDI interface!\r
832 //\r
833 pxe_shutdown (snp);\r
834 pxe_stop (snp);\r
835\r
836 //\r
837 // add SNP to the undi handle\r
838 //\r
839 Status = gBS->InstallProtocolInterface (\r
840 &Controller,\r
841 &gEfiSimpleNetworkProtocolGuid,\r
842 EFI_NATIVE_INTERFACE,\r
843 &(snp->snp)\r
844 );\r
845\r
846 if (!EFI_ERROR (Status)) {\r
847 return Status;\r
848 }\r
849\r
850Error_DeleteHdrBuf:\r
851 if (snp->IsOldUndi) {\r
852 Status = mPciIoFncs->Unmap (\r
853 mPciIoFncs,\r
854 snp->FillHdrBufUnmap\r
855 );\r
856 Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen);\r
857 mPciIoFncs->FreeBuffer (\r
858 mPciIoFncs,\r
859 Size,\r
860 snp->fill_hdr_buf\r
861 );\r
862 }\r
863\r
864Error_DeleteRCVBuf:\r
865 if (snp->IsOldUndi) {\r
866 Status = mPciIoFncs->Unmap (\r
867 mPciIoFncs,\r
868 snp->ReceiveBufUnmap\r
869 );\r
870 Size = SNP_MEM_PAGES (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);\r
871 mPciIoFncs->FreeBuffer (\r
872 mPciIoFncs,\r
873 Size,\r
874 snp->receive_buf\r
875 );\r
876\r
877 }\r
878\r
879Error_DeleteCPBDB:\r
880 if (snp->IsOldUndi) {\r
881 Status = mPciIoFncs->Unmap (\r
882 mPciIoFncs,\r
883 snp->CpbUnmap\r
884 );\r
885 }\r
886\r
887 Status = mPciIoFncs->FreeBuffer (\r
888 mPciIoFncs,\r
889 SNP_MEM_PAGES (4096),\r
890 snp->cpb\r
891 );\r
892\r
893Error_DeleteSNP:\r
894 if (snp->IsOldUndi) {\r
895 Status = mPciIoFncs->Unmap (\r
896 mPciIoFncs,\r
897 snp->SnpDriverUnmap\r
898 );\r
899 }\r
900\r
901 mPciIoFncs->FreeBuffer (\r
902 mPciIoFncs,\r
903 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
904 snp\r
905 );\r
906NiiError:\r
907 if (!UndiNew) {\r
908 gBS->CloseProtocol (\r
909 Controller,\r
910 &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
911 This->DriverBindingHandle,\r
912 Controller\r
913 );\r
914 } else {\r
915 gBS->CloseProtocol (\r
916 Controller,\r
917 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
918 This->DriverBindingHandle,\r
919 Controller\r
920 );\r
921 }\r
922\r
923 gBS->CloseProtocol (\r
924 Controller,\r
925 &gEfiDevicePathProtocolGuid,\r
926 This->DriverBindingHandle,\r
927 Controller\r
928 );\r
929\r
930 return Status;\r
931}\r
932\r
1cc8ee78 933STATIC\r
878ddf1f 934EFI_STATUS\r
935EFIAPI\r
936SimpleNetworkDriverStop (\r
937 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
938 IN EFI_HANDLE Controller,\r
939 IN UINTN NumberOfChildren,\r
940 IN EFI_HANDLE *ChildHandleBuffer\r
941 )\r
942/*++\r
943\r
944Routine Description:\r
945\r
946Arguments:\r
947\r
948Returns:\r
949\r
950--*/\r
951{\r
952 EFI_STATUS Status;\r
953 EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;\r
954 SNP_DRIVER *Snp;\r
955\r
956 //\r
957 // Get our context back.\r
958 //\r
959 Status = gBS->OpenProtocol (\r
960 Controller,\r
961 &gEfiSimpleNetworkProtocolGuid,\r
962 (VOID **) &SnpProtocol,\r
963 This->DriverBindingHandle,\r
964 Controller,\r
965 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
966 );\r
967\r
968 if (EFI_ERROR (Status)) {\r
969 return EFI_UNSUPPORTED;\r
970 }\r
971\r
972 Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);\r
973\r
974 Status = gBS->UninstallProtocolInterface (\r
975 Controller,\r
976 &gEfiSimpleNetworkProtocolGuid,\r
977 &Snp->snp\r
978 );\r
979\r
980 if (EFI_ERROR (Status)) {\r
981 return Status;\r
982 }\r
983\r
984 if (!Snp->IsOldUndi) {\r
985 Status = gBS->CloseProtocol (\r
986 Controller,\r
987 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
988 This->DriverBindingHandle,\r
989 Controller\r
990 );\r
991 } else {\r
992 Status = gBS->CloseProtocol (\r
993 Controller,\r
994 &gEfiNetworkInterfaceIdentifierProtocolGuid,\r
995 This->DriverBindingHandle,\r
996 Controller\r
997 );\r
998 }\r
999 \r
1000 Status = gBS->CloseProtocol (\r
1001 Controller,\r
1002 &gEfiDevicePathProtocolGuid,\r
1003 This->DriverBindingHandle,\r
1004 Controller\r
1005 );\r
1006\r
1007 pxe_shutdown (Snp);\r
1008 pxe_stop (Snp);\r
1009\r
1010 if (Snp->IsOldUndi) {\r
1011 Status = mPciIoFncs->Unmap (\r
1012 mPciIoFncs,\r
1013 Snp->FillHdrBufUnmap\r
1014 );\r
1015\r
1016 mPciIoFncs->FreeBuffer (\r
1017 mPciIoFncs,\r
1018 SNP_MEM_PAGES (Snp->init_info.MediaHeaderLen),\r
1019 Snp->fill_hdr_buf\r
1020 );\r
1021 Status = mPciIoFncs->Unmap (\r
1022 mPciIoFncs,\r
1023 Snp->ReceiveBufUnmap\r
1024 );\r
1025\r
1026 mPciIoFncs->FreeBuffer (\r
1027 mPciIoFncs,\r
1028 SNP_MEM_PAGES (Snp->init_info.MediaHeaderLen + Snp->init_info.FrameDataLen),\r
1029 Snp->receive_buf\r
1030 );\r
1031\r
1032 Status = mPciIoFncs->Unmap (\r
1033 mPciIoFncs,\r
1034 Snp->CpbUnmap\r
1035 );\r
1036 Status = mPciIoFncs->Unmap (\r
1037 mPciIoFncs,\r
1038 Snp->SnpDriverUnmap\r
1039 );\r
1040 }\r
1041\r
1042 mPciIoFncs->FreeBuffer (\r
1043 mPciIoFncs,\r
1044 SNP_MEM_PAGES (4096),\r
1045 Snp->cpb\r
1046 );\r
1047\r
1048 mPciIoFncs->FreeBuffer (\r
1049 mPciIoFncs,\r
1050 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
1051 Snp\r
1052 );\r
1053\r
1054 return Status;\r
1055}\r
1056\r
1cc8ee78 1057//\r
1058// Simple Network Protocol Driver Global Variables\r
1059//\r
1060EFI_DRIVER_BINDING_PROTOCOL mSimpleNetworkDriverBinding = {\r
1061 SimpleNetworkDriverSupported,\r
1062 SimpleNetworkDriverStart,\r
1063 SimpleNetworkDriverStop,\r
1064 0xa,\r
1065 NULL,\r
1066 NULL\r
1067};\r
1068\r
1069EFI_STATUS\r
1070add_v2p (\r
1071 IN OUT struct s_v2p **v2p,\r
1072 EFI_PCI_IO_PROTOCOL_OPERATION type,\r
1073 VOID *vaddr,\r
1074 UINTN bsize\r
1075 )\r
1076/*++\r
1077\r
1078Routine Description:\r
1079 This routine maps the given CPU address to a Device address. It creates a\r
1080 an entry in the map list with the virtual and physical addresses and the \r
1081 un map cookie.\r
1082\r
1083Arguments:\r
1084 v2p - pointer to return a map list node pointer.\r
1085 type - the direction in which the data flows from the given virtual address\r
1086 device->cpu or cpu->device or both ways.\r
1087 vaddr - virtual address (or CPU address) to be mapped\r
1088 bsize - size of the buffer to be mapped.\r
1089\r
1090Returns:\r
1091\r
1092 EFI_SUCEESS - routine has completed the mapping\r
1093 other - error as indicated.\r
1094\r
1095--*/\r
1096{\r
1097 EFI_STATUS Status;\r
1098\r
1099 if ((v2p == NULL) || (vaddr == NULL) || (bsize == 0)) {\r
1100 return EFI_INVALID_PARAMETER;\r
1101 }\r
1102\r
1103 Status = gBS->AllocatePool (\r
1104 EfiBootServicesData,\r
1105 sizeof (struct s_v2p),\r
1106 (VOID **) v2p\r
1107 );\r
1108\r
1109 if (Status != EFI_SUCCESS) {\r
1110 return Status;\r
1111 }\r
1112\r
1113 Status = mPciIoFncs->Map (\r
1114 mPciIoFncs,\r
1115 type,\r
1116 vaddr,\r
1117 &bsize,\r
1118 &(*v2p)->paddr,\r
1119 &(*v2p)->unmap\r
1120 );\r
1121 if (Status != EFI_SUCCESS) {\r
1122 gBS->FreePool (*v2p);\r
1123 return Status;\r
1124 }\r
1125 (*v2p)->vaddr = vaddr;\r
1126 (*v2p)->bsize = bsize;\r
1127 (*v2p)->next = _v2p;\r
1128 _v2p = *v2p;\r
1129\r
1130 return EFI_SUCCESS;\r
1131}\r
1132\r
1133EFI_STATUS\r
1134find_v2p (\r
1135 struct s_v2p **v2p,\r
1136 VOID *vaddr\r
1137 )\r
1138/*++\r
1139\r
1140Routine Description:\r
1141 This routine searches the linked list of mapped address nodes (for undi3.0 \r
1142 interface) to find the node that corresponds to the given virtual address and\r
1143 returns a pointer to that node.\r
1144\r
1145Arguments:\r
1146 v2p - pointer to return a map list node pointer.\r
1147 vaddr - virtual address (or CPU address) to be searched in the map list\r
1148\r
1149Returns:\r
1150\r
1151 EFI_SUCEESS - if a match found!\r
1152 Other - match not found\r
1153\r
1154--*/\r
1155{\r
1156 struct s_v2p *v;\r
1157\r
1158 if (v2p == NULL || vaddr == NULL) {\r
1159 return EFI_INVALID_PARAMETER;\r
1160 }\r
1161\r
1162 for (v = _v2p; v != NULL; v = v->next) {\r
1163 if (v->vaddr == vaddr) {\r
1164 *v2p = v;\r
1165 return EFI_SUCCESS;\r
1166 }\r
1167 }\r
1168\r
1169 return EFI_NOT_FOUND;\r
1170}\r
1171\r
1172EFI_STATUS\r
1173del_v2p (\r
1174 VOID *vaddr\r
1175 )\r
1176/*++\r
1177\r
1178Routine Description:\r
1179 This routine unmaps the given virtual address and frees the memory allocated \r
1180 for the map list node corresponding to that address.\r
1181 \r
1182Arguments:\r
1183 vaddr - virtual address (or CPU address) to be unmapped\r
1184\r
1185Returns:\r
1186 EFI_SUCEESS - if successfully unmapped\r
1187 Other - as indicated by the error\r
1188\r
1189\r
1190--*/\r
1191{\r
1192 struct s_v2p *v;\r
1193 struct s_v2p *t;\r
1194 EFI_STATUS Status;\r
1195\r
1196 if (vaddr == NULL) {\r
1197 return EFI_INVALID_PARAMETER;\r
1198 }\r
1199\r
1200 if (_v2p == NULL) {\r
1201 return EFI_NOT_FOUND;\r
1202 }\r
1203 //\r
1204 // Is our node at the head of the list??\r
1205 //\r
1206 if ((v = _v2p)->vaddr == vaddr) {\r
1207 _v2p = _v2p->next;\r
1208\r
1209 Status = mPciIoFncs->Unmap (mPciIoFncs, v->unmap);\r
1210\r
1211 gBS->FreePool (v);\r
1212\r
1213#if SNP_DEBUG\r
1214 if (Status) {\r
1215 Print (L"Unmap failed with status = %x\n", Status);\r
1216 }\r
1217#endif\r
1218 return Status;\r
1219 }\r
1220\r
1221 for (; v->next != NULL; v = t) {\r
1222 if ((t = v->next)->vaddr == vaddr) {\r
1223 v->next = t->next;\r
1224 Status = mPciIoFncs->Unmap (mPciIoFncs, t->unmap);\r
1225 gBS->FreePool (t);\r
1226#if SNP_DEBUG\r
1227 if (Status) {\r
1228 Print (L"Unmap failed with status = %x\n", Status);\r
1229 }\r
1230#endif\r
1231 return Status;\r
1232 }\r
1233 }\r
1234\r
1235 return EFI_NOT_FOUND;\r
1236}\r
1237\r
1238#if SNP_DEBUG\r
1239VOID\r
1240snp_wait_for_key (\r
1241 VOID\r
1242 )\r
1243/*++\r
1244\r
1245Routine Description:\r
1246 Wait for a key stroke, used for debugging purposes\r
1247\r
1248Arguments:\r
1249 none\r
1250\r
1251Returns:\r
1252 none\r
1253\r
1254--*/\r
1255{\r
1256 EFI_INPUT_KEY key;\r
1257\r
1258 Aprint ("\nPress any key to continue\n");\r
1259\r
1260 while (gST->ConIn->ReadKeyStroke (gST->ConIn, &key) == EFI_NOT_READY) {\r
1261 ;\r
1262 }\r
1263}\r
1264#endif\r