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