]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/Network/SnpDxe/Snp.c
fixed DMA not be stopped issue when gBS->ExitBootServices called.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / SnpDxe / Snp.c
... / ...
CommitLineData
1/** @file\r
2 Implementation of driver entry point and driver binding protocol.\r
3 \r
4Copyright (c) 2004 - 2009, Intel Corporation. <BR> \r
5All rights reserved. This program and the accompanying materials are licensed \r
6and made available under the terms and conditions of the BSD License which \r
7accompanies this distribution. The full text of the license may be found at \r
8http://opensource.org/licenses/bsd-license.php \r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "Snp.h"\r
16\r
17//\r
18// Module global variables needed to support undi 3.0 interface\r
19//\r
20EFI_PCI_IO_PROTOCOL *mPciIo;\r
21V2P *mV2p = NULL; // undi3.0 map_list head\r
22// End Global variables\r
23//\r
24\r
25/**\r
26 One notified function to stop UNDI device when gBS->ExitBootServices() called.\r
27\r
28 @param Event Pointer to this event\r
29 @param Context Event hanlder private data\r
30\r
31**/\r
32VOID\r
33EFIAPI\r
34SnpNotifyExitBootServices (\r
35 EFI_EVENT Event,\r
36 VOID *Context\r
37 )\r
38{\r
39 SNP_DRIVER *Snp;\r
40\r
41 Snp = (SNP_DRIVER *)Context;\r
42\r
43 //\r
44 // Shutdown and stop UNDI driver\r
45 //\r
46 PxeShutdown (Snp);\r
47 PxeStop (Snp);\r
48}\r
49\r
50/**\r
51 Send command to UNDI. It does nothing currently.\r
52 \r
53 @param Cdb command to be sent to UNDI.\r
54 \r
55 @retval EFI_INVALID_PARAMETER The command is 0. \r
56 @retval EFI_UNSUPPORTED Default return status because it's not \r
57 supported currently.\r
58 \r
59**/\r
60EFI_STATUS\r
61IssueHwUndiCommand (\r
62 UINT64 Cdb\r
63 )\r
64{\r
65 DEBUG ((EFI_D_ERROR, "\nIssueHwUndiCommand() - This should not be called!"));\r
66\r
67 if (Cdb == 0) {\r
68 return EFI_INVALID_PARAMETER;\r
69\r
70 }\r
71 //\r
72 // %%TBD - For now, nothing is done.\r
73 //\r
74 return EFI_UNSUPPORTED;\r
75}\r
76\r
77\r
78/**\r
79 Compute 8-bit checksum of a buffer.\r
80\r
81 @param Buffer Pointer to buffer.\r
82 @param Length Length of buffer in bytes.\r
83\r
84 @return 8-bit checksum of all bytes in buffer, or zero if ptr is NULL or len \r
85 is zero.\r
86\r
87**/\r
88UINT8\r
89Calc8BitCksum (\r
90 VOID *Buffer,\r
91 UINTN Length\r
92 )\r
93{\r
94 UINT8 *Ptr;\r
95 UINT8 Cksum;\r
96\r
97 Ptr = Buffer;\r
98 Cksum = 0;\r
99\r
100 if (Ptr == NULL || Length == 0) {\r
101 return 0;\r
102 }\r
103\r
104 while (Length-- != 0) {\r
105 Cksum = (UINT8) (Cksum + *Ptr++);\r
106 }\r
107\r
108 return Cksum;\r
109}\r
110\r
111/**\r
112 Test to see if this driver supports ControllerHandle. This service\r
113 is called by the EFI boot service ConnectController(). In\r
114 order to make drivers as small as possible, there are a few calling\r
115 restrictions for this service. ConnectController() must\r
116 follow these calling restrictions. If any other agent wishes to call\r
117 Supported() it must also follow these calling restrictions.\r
118\r
119 @param This Protocol instance pointer.\r
120 @param ControllerHandle Handle of device to test.\r
121 @param RemainingDevicePath Optional parameter use to pick a specific child\r
122 device to start.\r
123\r
124 @retval EFI_SUCCESS This driver supports this device.\r
125 @retval EFI_ALREADY_STARTED This driver is already running on this device.\r
126 @retval other This driver does not support this device.\r
127\r
128**/\r
129EFI_STATUS\r
130EFIAPI\r
131SimpleNetworkDriverSupported (\r
132 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
133 IN EFI_HANDLE Controller,\r
134 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
135 )\r
136{\r
137 EFI_STATUS Status;\r
138 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;\r
139 PXE_UNDI *Pxe;\r
140\r
141 Status = gBS->OpenProtocol (\r
142 Controller,\r
143 &gEfiDevicePathProtocolGuid,\r
144 NULL,\r
145 This->DriverBindingHandle,\r
146 Controller,\r
147 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
148 );\r
149 if (EFI_ERROR (Status)) {\r
150 return Status;\r
151 }\r
152\r
153 Status = gBS->OpenProtocol (\r
154 Controller,\r
155 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
156 (VOID **) &NiiProtocol,\r
157 This->DriverBindingHandle,\r
158 Controller,\r
159 EFI_OPEN_PROTOCOL_BY_DRIVER\r
160 );\r
161\r
162 if (EFI_ERROR (Status)) {\r
163 if (Status == EFI_ALREADY_STARTED) {\r
164 DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %p\n", Controller));\r
165 }\r
166 return Status;\r
167 }\r
168\r
169 DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %p\n", Controller));\r
170\r
171 //\r
172 // check the version, we don't want to connect to the undi16\r
173 //\r
174 if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {\r
175 Status = EFI_UNSUPPORTED;\r
176 goto Done;\r
177 }\r
178 //\r
179 // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.\r
180 //\r
181 if (NiiProtocol->ID & 0x0F) {\r
182 DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));\r
183 Status = EFI_UNSUPPORTED;\r
184 goto Done;\r
185 }\r
186\r
187 Pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->ID);\r
188\r
189 //\r
190 // Verify !PXE revisions.\r
191 //\r
192 if (Pxe->hw.Signature != PXE_ROMID_SIGNATURE) {\r
193 DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));\r
194 Status = EFI_UNSUPPORTED;\r
195 goto Done;\r
196 }\r
197\r
198 if (Pxe->hw.Rev < PXE_ROMID_REV) {\r
199 DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));\r
200 Status = EFI_UNSUPPORTED;\r
201 goto Done;\r
202 }\r
203\r
204 if (Pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {\r
205\r
206 DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));\r
207 Status = EFI_UNSUPPORTED;\r
208 goto Done;\r
209\r
210 } else if (Pxe->hw.MajorVer == PXE_ROMID_MAJORVER && Pxe->hw.MinorVer < PXE_ROMID_MINORVER) {\r
211 DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));\r
212 Status = EFI_UNSUPPORTED;\r
213 goto Done;\r
214 }\r
215 //\r
216 // Do S/W UNDI specific checks.\r
217 //\r
218 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {\r
219 if (Pxe->sw.EntryPoint < Pxe->sw.Len) {\r
220 DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));\r
221 Status = EFI_UNSUPPORTED;\r
222 goto Done;\r
223 }\r
224\r
225 if (Pxe->sw.BusCnt == 0) {\r
226 DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));\r
227 Status = EFI_UNSUPPORTED;\r
228 goto Done;\r
229 }\r
230 }\r
231\r
232 Status = EFI_SUCCESS;\r
233 DEBUG ((EFI_D_INFO, "Support(): supported on %p\n", Controller));\r
234\r
235Done:\r
236 gBS->CloseProtocol (\r
237 Controller,\r
238 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
239 This->DriverBindingHandle,\r
240 Controller\r
241 );\r
242\r
243 return Status;\r
244}\r
245\r
246/**\r
247 Start this driver on ControllerHandle. This service is called by the\r
248 EFI boot service ConnectController(). In order to make\r
249 drivers as small as possible, there are a few calling restrictions for\r
250 this service. ConnectController() must follow these\r
251 calling restrictions. If any other agent wishes to call Start() it\r
252 must also follow these calling restrictions.\r
253\r
254 @param This Protocol instance pointer.\r
255 @param ControllerHandle Handle of device to bind driver to.\r
256 @param RemainingDevicePath Optional parameter use to pick a specific child\r
257 device to start.\r
258\r
259 @retval EFI_SUCCESS This driver is added to ControllerHandle\r
260 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
261 @retval other This driver does not support this device\r
262\r
263**/\r
264EFI_STATUS\r
265EFIAPI\r
266SimpleNetworkDriverStart (\r
267 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
268 IN EFI_HANDLE Controller,\r
269 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
270 )\r
271{\r
272 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;\r
273 EFI_DEVICE_PATH_PROTOCOL *NiiDevicePath;\r
274 EFI_STATUS Status;\r
275 PXE_UNDI *Pxe;\r
276 SNP_DRIVER *Snp;\r
277 VOID *Address;\r
278 EFI_HANDLE Handle;\r
279 PXE_PCI_CONFIG_INFO ConfigInfo;\r
280 PCI_TYPE00 *ConfigHeader;\r
281 UINT32 *TempBar;\r
282 UINT8 BarIndex;\r
283 PXE_STATFLAGS InitStatFlags;\r
284\r
285 DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() "));\r
286\r
287 Status = gBS->OpenProtocol (\r
288 Controller,\r
289 &gEfiDevicePathProtocolGuid,\r
290 (VOID **) &NiiDevicePath,\r
291 This->DriverBindingHandle,\r
292 Controller,\r
293 EFI_OPEN_PROTOCOL_BY_DRIVER\r
294 );\r
295\r
296 if (EFI_ERROR (Status)) {\r
297 return Status;\r
298 }\r
299\r
300 Status = gBS->LocateDevicePath (\r
301 &gEfiPciIoProtocolGuid,\r
302 &NiiDevicePath,\r
303 &Handle\r
304 );\r
305\r
306 if (EFI_ERROR (Status)) {\r
307 return Status;\r
308 }\r
309\r
310 Status = gBS->OpenProtocol (\r
311 Handle,\r
312 &gEfiPciIoProtocolGuid,\r
313 (VOID **) &mPciIo,\r
314 This->DriverBindingHandle,\r
315 Controller,\r
316 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
317 );\r
318 if (EFI_ERROR (Status)) {\r
319 return Status;\r
320 }\r
321 //\r
322 // Get the NII interface.\r
323 //\r
324 Status = gBS->OpenProtocol (\r
325 Controller,\r
326 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
327 (VOID **) &Nii,\r
328 This->DriverBindingHandle,\r
329 Controller,\r
330 EFI_OPEN_PROTOCOL_BY_DRIVER\r
331 );\r
332 if (EFI_ERROR (Status)) {\r
333 gBS->CloseProtocol (\r
334 Controller,\r
335 &gEfiDevicePathProtocolGuid,\r
336 This->DriverBindingHandle,\r
337 Controller\r
338 );\r
339 return Status;\r
340 }\r
341\r
342 DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));\r
343\r
344 Pxe = (PXE_UNDI *) (UINTN) (Nii->ID);\r
345\r
346 if (Calc8BitCksum (Pxe, Pxe->hw.Len) != 0) {\r
347 DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));\r
348 goto NiiError;\r
349 }\r
350\r
351 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
352 //\r
353 // We can get any packets.\r
354 //\r
355 } else if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
356 //\r
357 // We need to be able to get broadcast packets for DHCP.\r
358 // If we do not have promiscuous support, we must at least have\r
359 // broadcast support or we cannot do DHCP!\r
360 //\r
361 } else {\r
362 DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));\r
363 goto NiiError;\r
364 }\r
365 //\r
366 // OK, we like this UNDI, and we know snp is not already there on this handle\r
367 // Allocate and initialize a new simple network protocol structure.\r
368 //\r
369 Status = mPciIo->AllocateBuffer (\r
370 mPciIo,\r
371 AllocateAnyPages,\r
372 EfiBootServicesData,\r
373 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
374 &Address,\r
375 0\r
376 );\r
377\r
378 if (Status != EFI_SUCCESS) {\r
379 DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));\r
380 goto NiiError;\r
381 }\r
382\r
383 Snp = (SNP_DRIVER *) (UINTN) Address;\r
384\r
385 ZeroMem (Snp, sizeof (SNP_DRIVER));\r
386\r
387 Snp->PciIo = mPciIo;\r
388 Snp->Signature = SNP_DRIVER_SIGNATURE;\r
389\r
390 EfiInitializeLock (&Snp->Lock, TPL_NOTIFY);\r
391\r
392 Snp->Snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;\r
393 Snp->Snp.Start = SnpUndi32Start;\r
394 Snp->Snp.Stop = SnpUndi32Stop;\r
395 Snp->Snp.Initialize = SnpUndi32Initialize;\r
396 Snp->Snp.Reset = SnpUndi32Reset;\r
397 Snp->Snp.Shutdown = SnpUndi32Shutdown;\r
398 Snp->Snp.ReceiveFilters = SnpUndi32ReceiveFilters;\r
399 Snp->Snp.StationAddress = SnpUndi32StationAddress;\r
400 Snp->Snp.Statistics = SnpUndi32Statistics;\r
401 Snp->Snp.MCastIpToMac = SnpUndi32McastIpToMac;\r
402 Snp->Snp.NvData = SnpUndi32NvData;\r
403 Snp->Snp.GetStatus = SnpUndi32GetStatus;\r
404 Snp->Snp.Transmit = SnpUndi32Transmit;\r
405 Snp->Snp.Receive = SnpUndi32Receive;\r
406 Snp->Snp.WaitForPacket = NULL;\r
407\r
408 Snp->Snp.Mode = &Snp->Mode;\r
409\r
410 Snp->TxRxBufferSize = 0;\r
411 Snp->TxRxBuffer = NULL;\r
412\r
413 Snp->IfNum = Nii->IfNum;\r
414\r
415 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {\r
416 Snp->IsSwUndi = FALSE;\r
417 Snp->IssueUndi32Command = &IssueHwUndiCommand;\r
418 } else {\r
419 Snp->IsSwUndi = TRUE;\r
420\r
421 if ((Pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {\r
422 Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) Pxe->sw.EntryPoint;\r
423 } else {\r
424 Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) ((UINT8) (UINTN) Pxe + Pxe->sw.EntryPoint);\r
425 }\r
426 }\r
427 //\r
428 // Allocate a global CPB and DB buffer for this UNDI interface.\r
429 // we do this because:\r
430 //\r
431 // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be\r
432 // within 2GB limit, create them here and map them so that when undi calls\r
433 // v2p callback to check if the physical address is < 2gb, we will pass.\r
434 //\r
435 // -This is not a requirement for 3.1 or later UNDIs but the code looks\r
436 // simpler if we use the same cpb, db variables for both old and new undi\r
437 // interfaces from all the SNP interface calls (we don't map the buffers\r
438 // for the newer undi interfaces though)\r
439 // .\r
440 // -it is OK to allocate one global set of CPB, DB pair for each UNDI\r
441 // interface as EFI does not multi-task and so SNP will not be re-entered!\r
442 //\r
443 Status = mPciIo->AllocateBuffer (\r
444 mPciIo,\r
445 AllocateAnyPages,\r
446 EfiBootServicesData,\r
447 SNP_MEM_PAGES (4096),\r
448 &Address,\r
449 0\r
450 );\r
451\r
452 if (Status != EFI_SUCCESS) {\r
453 DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));\r
454 goto Error_DeleteSNP;\r
455 }\r
456\r
457 Snp->Cpb = (VOID *) (UINTN) Address;\r
458 Snp->Db = (VOID *) ((UINTN) Address + 2048);\r
459\r
460 //\r
461 // PxeStart call is going to give the callback functions to UNDI, these callback\r
462 // functions use the BarIndex values from the snp structure, so these must be initialized\r
463 // with default values before doing a PxeStart. The correct values can be obtained after\r
464 // getting the config information from UNDI\r
465 //\r
466 Snp->MemoryBarIndex = 0;\r
467 Snp->IoBarIndex = 1;\r
468\r
469 //\r
470 // we need the undi init information many times in this snp code, just get it\r
471 // once here and store it in the snp driver structure. to get Init Info\r
472 // from UNDI we have to start undi first.\r
473 //\r
474 Status = PxeStart (Snp);\r
475\r
476 if (Status != EFI_SUCCESS) {\r
477 goto Error_DeleteSNP;\r
478 }\r
479\r
480 Snp->Cdb.OpCode = PXE_OPCODE_GET_INIT_INFO;\r
481 Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
482\r
483 Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
484 Snp->Cdb.CPBaddr = PXE_DBADDR_NOT_USED;\r
485\r
486 Snp->Cdb.DBsize = sizeof Snp->InitInfo;\r
487 Snp->Cdb.DBaddr = (UINT64)(UINTN) &Snp->InitInfo;\r
488\r
489 Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
490 Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
491\r
492 Snp->Cdb.IFnum = Snp->IfNum;\r
493 Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
494\r
495 DEBUG ((EFI_D_NET, "\nSnp->undi.get_init_info() "));\r
496\r
497 (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);\r
498\r
499 //\r
500 // Save the INIT Stat Code...\r
501 //\r
502 InitStatFlags = Snp->Cdb.StatFlags;\r
503\r
504 if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
505 DEBUG ((EFI_D_NET, "\nSnp->undi.init_info() %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));\r
506 PxeStop (Snp);\r
507 goto Error_DeleteSNP;\r
508 }\r
509\r
510 Snp->Cdb.OpCode = PXE_OPCODE_GET_CONFIG_INFO;\r
511 Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
512\r
513 Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
514 Snp->Cdb.CPBaddr = PXE_DBADDR_NOT_USED;\r
515\r
516 Snp->Cdb.DBsize = sizeof ConfigInfo;\r
517 Snp->Cdb.DBaddr = (UINT64)(UINTN) &ConfigInfo;\r
518\r
519 Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
520 Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
521\r
522 Snp->Cdb.IFnum = Snp->IfNum;\r
523 Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
524\r
525 DEBUG ((EFI_D_NET, "\nSnp->undi.get_config_info() "));\r
526\r
527 (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);\r
528\r
529 if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
530 DEBUG ((EFI_D_NET, "\nSnp->undi.config_info() %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));\r
531 PxeStop (Snp);\r
532 goto Error_DeleteSNP;\r
533 }\r
534 //\r
535 // Find the correct BAR to do IO.\r
536 //\r
537 //\r
538 // Enumerate through the PCI BARs for the device to determine which one is\r
539 // the IO BAR. Save the index of the BAR into the adapter info structure.\r
540 // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped\r
541 //\r
542 ConfigHeader = (PCI_TYPE00 *) &ConfigInfo.Config.Byte[0];\r
543 TempBar = (UINT32 *) &ConfigHeader->Device.Bar[0];\r
544 for (BarIndex = 0; BarIndex <= 5; BarIndex++) {\r
545 if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {\r
546 //\r
547 // This is a 64-bit memory bar, skip this and the\r
548 // next bar as well.\r
549 //\r
550 TempBar++;\r
551 }\r
552\r
553 if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {\r
554 Snp->IoBarIndex = BarIndex;\r
555 break;\r
556 }\r
557\r
558 TempBar++;\r
559 }\r
560\r
561 //\r
562 // Initialize simple network protocol mode structure\r
563 //\r
564 Snp->Mode.State = EfiSimpleNetworkStopped;\r
565 Snp->Mode.HwAddressSize = Snp->InitInfo.HWaddrLen;\r
566 Snp->Mode.MediaHeaderSize = Snp->InitInfo.MediaHeaderLen;\r
567 Snp->Mode.MaxPacketSize = Snp->InitInfo.FrameDataLen;\r
568 Snp->Mode.NvRamAccessSize = Snp->InitInfo.NvWidth;\r
569 Snp->Mode.NvRamSize = Snp->InitInfo.NvCount * Snp->Mode.NvRamAccessSize;\r
570 Snp->Mode.IfType = Snp->InitInfo.IFtype;\r
571 Snp->Mode.MaxMCastFilterCount = Snp->InitInfo.MCastFilterCnt;\r
572 Snp->Mode.MCastFilterCount = 0;\r
573\r
574 switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {\r
575 case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:\r
576 Snp->Mode.MediaPresentSupported = TRUE;\r
577 break;\r
578\r
579 case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:\r
580 default:\r
581 Snp->Mode.MediaPresentSupported = FALSE;\r
582 }\r
583\r
584 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {\r
585 Snp->Mode.MacAddressChangeable = TRUE;\r
586 } else {\r
587 Snp->Mode.MacAddressChangeable = FALSE;\r
588 }\r
589\r
590 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {\r
591 Snp->Mode.MultipleTxSupported = TRUE;\r
592 } else {\r
593 Snp->Mode.MultipleTxSupported = FALSE;\r
594 }\r
595\r
596 Snp->Mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
597\r
598 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {\r
599 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
600\r
601 }\r
602\r
603 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
604 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
605\r
606 }\r
607\r
608 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
609 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
610\r
611 }\r
612\r
613 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {\r
614 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
615\r
616 }\r
617\r
618 if (Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) {\r
619 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
620\r
621 }\r
622\r
623 Snp->Mode.ReceiveFilterSetting = 0;\r
624\r
625 //\r
626 // need to get the station address to save in the mode structure. we need to\r
627 // initialize the UNDI first for this.\r
628 //\r
629 Snp->TxRxBufferSize = Snp->InitInfo.MemoryRequired;\r
630 Status = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);\r
631\r
632 if (EFI_ERROR (Status)) {\r
633 PxeStop (Snp);\r
634 goto Error_DeleteSNP;\r
635 }\r
636\r
637 Status = PxeGetStnAddr (Snp);\r
638\r
639 if (Status != EFI_SUCCESS) {\r
640 DEBUG ((EFI_D_ERROR, "\nSnp->undi.get_station_addr() failed.\n"));\r
641 PxeShutdown (Snp);\r
642 PxeStop (Snp);\r
643 goto Error_DeleteSNP;\r
644 }\r
645\r
646 Snp->Mode.MediaPresent = FALSE;\r
647\r
648 //\r
649 // We should not leave UNDI started and initialized here. this DriverStart()\r
650 // routine must only find and attach the SNP interface to UNDI layer that it\r
651 // finds on the given handle!\r
652 // The UNDI layer will be started when upper layers call Snp->start.\r
653 // How ever, this DriverStart() must fill up the snp mode structure which\r
654 // contains the MAC address of the NIC. For this reason we started and\r
655 // initialized UNDI here, now we are done, do a shutdown and stop of the\r
656 // UNDI interface!\r
657 //\r
658 PxeShutdown (Snp);\r
659 PxeStop (Snp);\r
660\r
661 //\r
662 // Create EXIT_BOOT_SERIVES Event\r
663 //\r
664 Status = gBS->CreateEventEx (\r
665 EVT_NOTIFY_SIGNAL,\r
666 TPL_NOTIFY,\r
667 SnpNotifyExitBootServices,\r
668 Snp,\r
669 &gEfiEventExitBootServicesGuid,\r
670 &Snp->ExitBootServicesEvent\r
671 );\r
672 if (EFI_ERROR (Status)) {\r
673 goto Error_DeleteSNP;\r
674 }\r
675\r
676 //\r
677 // add SNP to the undi handle\r
678 //\r
679 Status = gBS->InstallProtocolInterface (\r
680 &Controller,\r
681 &gEfiSimpleNetworkProtocolGuid,\r
682 EFI_NATIVE_INTERFACE,\r
683 &(Snp->Snp)\r
684 );\r
685\r
686 if (!EFI_ERROR (Status)) {\r
687 return Status;\r
688 }\r
689\r
690 Status = mPciIo->FreeBuffer (\r
691 mPciIo,\r
692 SNP_MEM_PAGES (4096),\r
693 Snp->Cpb\r
694 );\r
695\r
696Error_DeleteSNP:\r
697\r
698 mPciIo->FreeBuffer (\r
699 mPciIo,\r
700 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
701 Snp\r
702 );\r
703NiiError:\r
704 gBS->CloseProtocol (\r
705 Controller,\r
706 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
707 This->DriverBindingHandle,\r
708 Controller\r
709 );\r
710\r
711 gBS->CloseProtocol (\r
712 Controller,\r
713 &gEfiDevicePathProtocolGuid,\r
714 This->DriverBindingHandle,\r
715 Controller\r
716 );\r
717\r
718 return Status;\r
719}\r
720\r
721/**\r
722 Stop this driver on ControllerHandle. This service is called by the\r
723 EFI boot service DisconnectController(). In order to\r
724 make drivers as small as possible, there are a few calling\r
725 restrictions for this service. DisconnectController()\r
726 must follow these calling restrictions. If any other agent wishes\r
727 to call Stop() it must also follow these calling restrictions.\r
728 \r
729 @param This Protocol instance pointer.\r
730 @param ControllerHandle Handle of device to stop driver on\r
731 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
732 children is zero stop the entire bus driver.\r
733 @param ChildHandleBuffer List of Child Handles to Stop.\r
734\r
735 @retval EFI_SUCCESS This driver is removed ControllerHandle\r
736 @retval other This driver was not removed from this device\r
737\r
738**/\r
739EFI_STATUS\r
740EFIAPI\r
741SimpleNetworkDriverStop (\r
742 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
743 IN EFI_HANDLE Controller,\r
744 IN UINTN NumberOfChildren,\r
745 IN EFI_HANDLE *ChildHandleBuffer\r
746 )\r
747{\r
748 EFI_STATUS Status;\r
749 EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;\r
750 SNP_DRIVER *Snp;\r
751\r
752 //\r
753 // Get our context back.\r
754 //\r
755 Status = gBS->OpenProtocol (\r
756 Controller,\r
757 &gEfiSimpleNetworkProtocolGuid,\r
758 (VOID **) &SnpProtocol,\r
759 This->DriverBindingHandle,\r
760 Controller,\r
761 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
762 );\r
763\r
764 if (EFI_ERROR (Status)) {\r
765 return EFI_UNSUPPORTED;\r
766 }\r
767\r
768 Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);\r
769\r
770 Status = gBS->UninstallProtocolInterface (\r
771 Controller,\r
772 &gEfiSimpleNetworkProtocolGuid,\r
773 &Snp->Snp\r
774 );\r
775\r
776 if (EFI_ERROR (Status)) {\r
777 return Status;\r
778 }\r
779\r
780 //\r
781 // Close EXIT_BOOT_SERIVES Event\r
782 //\r
783 gBS->CloseEvent (Snp->ExitBootServicesEvent);\r
784\r
785 Status = gBS->CloseProtocol (\r
786 Controller,\r
787 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
788 This->DriverBindingHandle,\r
789 Controller\r
790 );\r
791\r
792 Status = gBS->CloseProtocol (\r
793 Controller,\r
794 &gEfiDevicePathProtocolGuid,\r
795 This->DriverBindingHandle,\r
796 Controller\r
797 );\r
798\r
799 PxeShutdown (Snp);\r
800 PxeStop (Snp);\r
801\r
802 mPciIo->FreeBuffer (\r
803 mPciIo,\r
804 SNP_MEM_PAGES (4096),\r
805 Snp->Cpb\r
806 );\r
807\r
808 mPciIo->FreeBuffer (\r
809 mPciIo,\r
810 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
811 Snp\r
812 );\r
813\r
814 return Status;\r
815}\r
816\r
817//\r
818// Simple Network Protocol Driver Global Variables\r
819//\r
820EFI_DRIVER_BINDING_PROTOCOL mSimpleNetworkDriverBinding = {\r
821 SimpleNetworkDriverSupported,\r
822 SimpleNetworkDriverStart,\r
823 SimpleNetworkDriverStop,\r
824 0xa,\r
825 NULL,\r
826 NULL\r
827};\r
828\r
829\r
830/**\r
831 This routine maps the given CPU address to a Device address. It creates a\r
832 an entry in the map list with the virtual and physical addresses and the\r
833 un map cookie.\r
834\r
835 @param V2p pointer to return a map list node pointer.\r
836 @param Type the direction in which the data flows from the given\r
837 virtual address device->cpu or cpu->device or both\r
838 ways.\r
839 @param VirtualAddress virtual address (or CPU address) to be mapped.\r
840 @param BufferSize size of the buffer to be mapped.\r
841\r
842 @retval EFI_SUCEESS routine has completed the mapping.\r
843 @retval EFI_INVALID_PARAMETER invalid parameter.\r
844 @retval EFI_OUT_OF_RESOURCES out of resource.\r
845 @retval other error as indicated.\r
846\r
847**/\r
848EFI_STATUS\r
849AddV2P (\r
850 IN OUT V2P **V2p,\r
851 EFI_PCI_IO_PROTOCOL_OPERATION Type,\r
852 VOID *VirtualAddress,\r
853 UINTN BufferSize\r
854 )\r
855{\r
856 EFI_STATUS Status;\r
857\r
858 if ((V2p == NULL) || (VirtualAddress == NULL) || (BufferSize == 0)) {\r
859 return EFI_INVALID_PARAMETER;\r
860 }\r
861\r
862 *V2p = AllocatePool (sizeof (V2P));\r
863 if (*V2p != NULL) {\r
864 return EFI_OUT_OF_RESOURCES;\r
865 }\r
866\r
867 Status = mPciIo->Map (\r
868 mPciIo,\r
869 Type,\r
870 VirtualAddress,\r
871 &BufferSize,\r
872 &(*V2p)->PhysicalAddress,\r
873 &(*V2p)->Unmap\r
874 );\r
875 if (Status != EFI_SUCCESS) {\r
876 FreePool (*V2p);\r
877 return Status;\r
878 }\r
879 (*V2p)->VirtualAddress = VirtualAddress;\r
880 (*V2p)->BufferSize = BufferSize;\r
881 (*V2p)->Next = mV2p;\r
882 mV2p = *V2p;\r
883\r
884 return EFI_SUCCESS;\r
885}\r
886\r
887\r
888/**\r
889 This routine searches the linked list of mapped address nodes (for undi3.0\r
890 interface) to find the node that corresponds to the given virtual address and\r
891 returns a pointer to that node.\r
892\r
893 @param V2p pointer to return a map list node pointer.\r
894 @param VirtualAddr virtual address (or CPU address) to be searched in\r
895 the map list\r
896\r
897 @retval EFI_SUCEESS A match was found.\r
898 @retval Other A match cannot be found.\r
899\r
900**/\r
901EFI_STATUS\r
902FindV2p (\r
903 V2P **V2p,\r
904 VOID *VirtualAddr\r
905 )\r
906{\r
907 V2P *Ptr;\r
908\r
909 if (V2p == NULL || VirtualAddr == NULL) {\r
910 return EFI_INVALID_PARAMETER;\r
911 }\r
912\r
913 for (Ptr = mV2p; Ptr != NULL; Ptr = Ptr->Next) {\r
914 if (Ptr->VirtualAddress == VirtualAddr) {\r
915 *V2p = Ptr;\r
916 return EFI_SUCCESS;\r
917 }\r
918 }\r
919\r
920 return EFI_NOT_FOUND;\r
921}\r
922\r
923\r
924/**\r
925 Unmap the given virtual address and free the memory allocated for the map list\r
926 node corresponding to that address.\r
927\r
928 @param VirtualAddress virtual address (or CPU address) to be unmapped.\r
929\r
930 @retval EFI_SUCEESS Successfully unmapped.\r
931 @retval Other Other errors as indicated.\r
932\r
933**/\r
934EFI_STATUS\r
935DelV2p (\r
936 VOID *VirtualAddress\r
937 )\r
938{\r
939 V2P *Current;\r
940 V2P *Next;\r
941 EFI_STATUS Status;\r
942\r
943 if (VirtualAddress == NULL) {\r
944 return EFI_INVALID_PARAMETER;\r
945 }\r
946\r
947 if (mV2p == NULL) {\r
948 return EFI_NOT_FOUND;\r
949 }\r
950 //\r
951 // Is our node at the head of the list??\r
952 //\r
953 if ((Current = mV2p)->VirtualAddress == VirtualAddress) {\r
954 mV2p = mV2p->Next;\r
955\r
956 Status = mPciIo->Unmap (mPciIo, Current->Unmap);\r
957\r
958 FreePool (Current);\r
959\r
960 if (EFI_ERROR (Status)) {\r
961 DEBUG ((EFI_D_ERROR, "Unmap failed with status = %r\n", Status));\r
962 }\r
963 return Status;\r
964 }\r
965\r
966 for (; Current->Next != NULL; Current = Next) {\r
967 if ((Next = Current->Next)->VirtualAddress == VirtualAddress) {\r
968 Current->Next = Next->Next;\r
969 Status = mPciIo->Unmap (mPciIo, Next->Unmap);\r
970 FreePool (Next);\r
971\r
972 if (EFI_ERROR (Status)) {\r
973 DEBUG ((EFI_D_ERROR, "Unmap failed with status = %r\n", Status));\r
974 }\r
975 return Status;\r
976 }\r
977 }\r
978\r
979 return EFI_NOT_FOUND;\r
980}\r
981\r
982/**\r
983 The SNP driver entry point.\r
984\r
985 @param ImageHandle The driver image handle.\r
986 @param SystemTable The system table.\r
987\r
988 @retval EFI_SUCEESS Initialization routine has found UNDI hardware,\r
989 loaded it's ROM, and installed a notify event for\r
990 the Network Indentifier Interface Protocol\r
991 successfully.\r
992 @retval Other Return value from HandleProtocol for\r
993 DeviceIoProtocol or LoadedImageProtocol\r
994\r
995**/\r
996EFI_STATUS\r
997EFIAPI\r
998InitializeSnpNiiDriver (\r
999 IN EFI_HANDLE ImageHandle,\r
1000 IN EFI_SYSTEM_TABLE *SystemTable\r
1001 )\r
1002{\r
1003 return EfiLibInstallDriverBindingComponentName2 (\r
1004 ImageHandle,\r
1005 SystemTable,\r
1006 &mSimpleNetworkDriverBinding,\r
1007 NULL,\r
1008 &gSimpleNetworkComponentName,\r
1009 &gSimpleNetworkComponentName2\r
1010 );\r
1011}\r