]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/SnpDxe/Snp.c
1. Add EFI_COMPONENT_NAME2_PROTOCOL.GetControllerName() support.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / SnpDxe / Snp.c
CommitLineData
a15a4195 1/** @file\r
894d038a 2 Implementation of driver entry point and driver binding protocol.\r
e2851998 3\r
216f7970 4Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 5This program and the accompanying materials are licensed\r
e2851998 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
a15a4195 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
a15a4195 13**/\r
14\r
15#include "Snp.h"\r
16\r
a15a4195 17//\r
18// Module global variables needed to support undi 3.0 interface\r
19//\r
4cda7726 20EFI_PCI_IO_PROTOCOL *mPciIo;\r
21V2P *mV2p = NULL; // undi3.0 map_list head\r
a15a4195 22// End Global variables\r
23//\r
24\r
0428a6cb 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
a15a4195 49\r
50/**\r
f3816027 51 Send command to UNDI. It does nothing currently.\r
e2851998 52\r
4cda7726 53 @param Cdb command to be sent to UNDI.\r
e2851998 54\r
55 @retval EFI_INVALID_PARAMETER The command is 0.\r
56 @retval EFI_UNSUPPORTED Default return status because it's not\r
f3816027 57 supported currently.\r
e2851998 58\r
a15a4195 59**/\r
60EFI_STATUS\r
9c9f5859 61EFIAPI\r
4cda7726 62IssueHwUndiCommand (\r
63 UINT64 Cdb\r
a15a4195 64 )\r
65{\r
4cda7726 66 DEBUG ((EFI_D_ERROR, "\nIssueHwUndiCommand() - This should not be called!"));\r
a15a4195 67\r
4cda7726 68 if (Cdb == 0) {\r
a15a4195 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
4cda7726 82 @param Buffer Pointer to buffer.\r
83 @param Length Length of buffer in bytes.\r
a15a4195 84\r
e2851998 85 @return 8-bit checksum of all bytes in buffer, or zero if ptr is NULL or len\r
f3816027 86 is zero.\r
a15a4195 87\r
88**/\r
a15a4195 89UINT8\r
4cda7726 90Calc8BitCksum (\r
91 VOID *Buffer,\r
92 UINTN Length\r
a15a4195 93 )\r
94{\r
4cda7726 95 UINT8 *Ptr;\r
96 UINT8 Cksum;\r
a15a4195 97\r
4cda7726 98 Ptr = Buffer;\r
99 Cksum = 0;\r
a15a4195 100\r
4cda7726 101 if (Ptr == NULL || Length == 0) {\r
a15a4195 102 return 0;\r
103 }\r
104\r
4cda7726 105 while (Length-- != 0) {\r
106 Cksum = (UINT8) (Cksum + *Ptr++);\r
a15a4195 107 }\r
108\r
4cda7726 109 return Cksum;\r
a15a4195 110}\r
111\r
a15a4195 112/**\r
4cda7726 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
f3816027 121 @param ControllerHandle Handle of device to test.\r
4cda7726 122 @param RemainingDevicePath Optional parameter use to pick a specific child\r
123 device to start.\r
124\r
f3816027 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
a15a4195 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
4cda7726 140 PXE_UNDI *Pxe;\r
a15a4195 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
0e549d5b 165 DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %p\n", Controller));\r
a15a4195 166 }\r
167 return Status;\r
168 }\r
169\r
0e549d5b 170 DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %p\n", Controller));\r
a15a4195 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
e2851998 182 if ((NiiProtocol->Id & 0x0F) != 0) {\r
9cff2f8d 183 DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));\r
a15a4195 184 Status = EFI_UNSUPPORTED;\r
185 goto Done;\r
186 }\r
187\r
bdc82513 188 Pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->Id);\r
a15a4195 189\r
190 //\r
191 // Verify !PXE revisions.\r
192 //\r
4cda7726 193 if (Pxe->hw.Signature != PXE_ROMID_SIGNATURE) {\r
9cff2f8d 194 DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));\r
a15a4195 195 Status = EFI_UNSUPPORTED;\r
196 goto Done;\r
197 }\r
198\r
4cda7726 199 if (Pxe->hw.Rev < PXE_ROMID_REV) {\r
9cff2f8d 200 DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));\r
a15a4195 201 Status = EFI_UNSUPPORTED;\r
202 goto Done;\r
203 }\r
204\r
4cda7726 205 if (Pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {\r
a15a4195 206\r
9cff2f8d 207 DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));\r
a15a4195 208 Status = EFI_UNSUPPORTED;\r
209 goto Done;\r
210\r
4cda7726 211 } else if (Pxe->hw.MajorVer == PXE_ROMID_MAJORVER && Pxe->hw.MinorVer < PXE_ROMID_MINORVER) {\r
9cff2f8d 212 DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));\r
a15a4195 213 Status = EFI_UNSUPPORTED;\r
214 goto Done;\r
215 }\r
216 //\r
217 // Do S/W UNDI specific checks.\r
218 //\r
4cda7726 219 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {\r
220 if (Pxe->sw.EntryPoint < Pxe->sw.Len) {\r
9cff2f8d 221 DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));\r
a15a4195 222 Status = EFI_UNSUPPORTED;\r
223 goto Done;\r
224 }\r
225\r
4cda7726 226 if (Pxe->sw.BusCnt == 0) {\r
9cff2f8d 227 DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));\r
a15a4195 228 Status = EFI_UNSUPPORTED;\r
229 goto Done;\r
230 }\r
231 }\r
232\r
233 Status = EFI_SUCCESS;\r
0e549d5b 234 DEBUG ((EFI_D_INFO, "Support(): supported on %p\n", Controller));\r
a15a4195 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
a15a4195 247/**\r
4cda7726 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
a15a4195 254\r
255 @param This Protocol instance pointer.\r
4cda7726 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
a15a4195 259\r
4cda7726 260 @retval EFI_SUCCESS This driver is added to ControllerHandle\r
261 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle\r
262 @retval other This driver does not support this device\r
a15a4195 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
4cda7726 276 PXE_UNDI *Pxe;\r
277 SNP_DRIVER *Snp;\r
278 VOID *Address;\r
a15a4195 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
9cff2f8d 286 DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() "));\r
a15a4195 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
4cda7726 314 (VOID **) &mPciIo,\r
a15a4195 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
bdc82513 345 Pxe = (PXE_UNDI *) (UINTN) (Nii->Id);\r
a15a4195 346\r
4cda7726 347 if (Calc8BitCksum (Pxe, Pxe->hw.Len) != 0) {\r
9cff2f8d 348 DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));\r
a15a4195 349 goto NiiError;\r
350 }\r
351\r
4cda7726 352 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
a15a4195 353 //\r
354 // We can get any packets.\r
355 //\r
4cda7726 356 } else if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
a15a4195 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
9cff2f8d 363 DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));\r
a15a4195 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
4cda7726 370 Status = mPciIo->AllocateBuffer (\r
371 mPciIo,\r
a15a4195 372 AllocateAnyPages,\r
373 EfiBootServicesData,\r
374 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
4cda7726 375 &Address,\r
a15a4195 376 0\r
377 );\r
378\r
379 if (Status != EFI_SUCCESS) {\r
9cff2f8d 380 DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));\r
a15a4195 381 goto NiiError;\r
382 }\r
383\r
4cda7726 384 Snp = (SNP_DRIVER *) (UINTN) Address;\r
a15a4195 385\r
4cda7726 386 ZeroMem (Snp, sizeof (SNP_DRIVER));\r
a15a4195 387\r
4cda7726 388 Snp->PciIo = mPciIo;\r
389 Snp->Signature = SNP_DRIVER_SIGNATURE;\r
a15a4195 390\r
4cda7726 391 EfiInitializeLock (&Snp->Lock, TPL_NOTIFY);\r
a15a4195 392\r
4cda7726 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
a15a4195 408\r
4cda7726 409 Snp->Snp.Mode = &Snp->Mode;\r
a15a4195 410\r
4cda7726 411 Snp->TxRxBufferSize = 0;\r
412 Snp->TxRxBuffer = NULL;\r
a15a4195 413\r
4cda7726 414 Snp->IfNum = Nii->IfNum;\r
a15a4195 415\r
4cda7726 416 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {\r
417 Snp->IsSwUndi = FALSE;\r
418 Snp->IssueUndi32Command = &IssueHwUndiCommand;\r
a15a4195 419 } else {\r
4cda7726 420 Snp->IsSwUndi = TRUE;\r
a15a4195 421\r
4cda7726 422 if ((Pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {\r
423 Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) Pxe->sw.EntryPoint;\r
a15a4195 424 } else {\r
4cda7726 425 Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) ((UINT8) (UINTN) Pxe + Pxe->sw.EntryPoint);\r
a15a4195 426 }\r
427 }\r
428 //\r
429 // Allocate a global CPB and DB buffer for this UNDI interface.\r
430 // we do this because:\r
431 //\r
432 // -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be\r
433 // within 2GB limit, create them here and map them so that when undi calls\r
434 // v2p callback to check if the physical address is < 2gb, we will pass.\r
435 //\r
436 // -This is not a requirement for 3.1 or later UNDIs but the code looks\r
437 // simpler if we use the same cpb, db variables for both old and new undi\r
438 // interfaces from all the SNP interface calls (we don't map the buffers\r
439 // for the newer undi interfaces though)\r
440 // .\r
441 // -it is OK to allocate one global set of CPB, DB pair for each UNDI\r
442 // interface as EFI does not multi-task and so SNP will not be re-entered!\r
443 //\r
4cda7726 444 Status = mPciIo->AllocateBuffer (\r
445 mPciIo,\r
a15a4195 446 AllocateAnyPages,\r
447 EfiBootServicesData,\r
448 SNP_MEM_PAGES (4096),\r
4cda7726 449 &Address,\r
a15a4195 450 0\r
451 );\r
452\r
453 if (Status != EFI_SUCCESS) {\r
9cff2f8d 454 DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));\r
a15a4195 455 goto Error_DeleteSNP;\r
456 }\r
457\r
4cda7726 458 Snp->Cpb = (VOID *) (UINTN) Address;\r
459 Snp->Db = (VOID *) ((UINTN) Address + 2048);\r
a15a4195 460\r
461 //\r
4cda7726 462 // PxeStart call is going to give the callback functions to UNDI, these callback\r
a15a4195 463 // functions use the BarIndex values from the snp structure, so these must be initialized\r
4cda7726 464 // with default values before doing a PxeStart. The correct values can be obtained after\r
a15a4195 465 // getting the config information from UNDI\r
466 //\r
4cda7726 467 Snp->MemoryBarIndex = 0;\r
468 Snp->IoBarIndex = 1;\r
a15a4195 469\r
470 //\r
471 // we need the undi init information many times in this snp code, just get it\r
472 // once here and store it in the snp driver structure. to get Init Info\r
473 // from UNDI we have to start undi first.\r
474 //\r
4cda7726 475 Status = PxeStart (Snp);\r
a15a4195 476\r
477 if (Status != EFI_SUCCESS) {\r
478 goto Error_DeleteSNP;\r
479 }\r
480\r
4cda7726 481 Snp->Cdb.OpCode = PXE_OPCODE_GET_INIT_INFO;\r
482 Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
a15a4195 483\r
4cda7726 484 Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
485 Snp->Cdb.CPBaddr = PXE_DBADDR_NOT_USED;\r
a15a4195 486\r
c9325700
ED
487 Snp->Cdb.DBsize = (UINT16) sizeof (Snp->InitInfo);\r
488 Snp->Cdb.DBaddr = (UINT64)(UINTN) (&Snp->InitInfo);\r
a15a4195 489\r
4cda7726 490 Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
491 Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
a15a4195 492\r
4cda7726 493 Snp->Cdb.IFnum = Snp->IfNum;\r
494 Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
a15a4195 495\r
9cff2f8d 496 DEBUG ((EFI_D_NET, "\nSnp->undi.get_init_info() "));\r
a15a4195 497\r
4cda7726 498 (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);\r
a15a4195 499\r
500 //\r
501 // Save the INIT Stat Code...\r
502 //\r
4cda7726 503 InitStatFlags = Snp->Cdb.StatFlags;\r
a15a4195 504\r
4cda7726 505 if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
9cff2f8d 506 DEBUG ((EFI_D_NET, "\nSnp->undi.init_info() %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));\r
4cda7726 507 PxeStop (Snp);\r
a15a4195 508 goto Error_DeleteSNP;\r
509 }\r
510\r
4cda7726 511 Snp->Cdb.OpCode = PXE_OPCODE_GET_CONFIG_INFO;\r
512 Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;\r
a15a4195 513\r
4cda7726 514 Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;\r
515 Snp->Cdb.CPBaddr = PXE_DBADDR_NOT_USED;\r
a15a4195 516\r
c9325700 517 Snp->Cdb.DBsize = (UINT16) sizeof (ConfigInfo);\r
4cda7726 518 Snp->Cdb.DBaddr = (UINT64)(UINTN) &ConfigInfo;\r
a15a4195 519\r
4cda7726 520 Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;\r
521 Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r
a15a4195 522\r
4cda7726 523 Snp->Cdb.IFnum = Snp->IfNum;\r
524 Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r
a15a4195 525\r
9cff2f8d 526 DEBUG ((EFI_D_NET, "\nSnp->undi.get_config_info() "));\r
a15a4195 527\r
4cda7726 528 (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);\r
a15a4195 529\r
4cda7726 530 if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {\r
9cff2f8d 531 DEBUG ((EFI_D_NET, "\nSnp->undi.config_info() %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));\r
4cda7726 532 PxeStop (Snp);\r
a15a4195 533 goto Error_DeleteSNP;\r
534 }\r
535 //\r
536 // Find the correct BAR to do IO.\r
537 //\r
538 //\r
539 // Enumerate through the PCI BARs for the device to determine which one is\r
540 // the IO BAR. Save the index of the BAR into the adapter info structure.\r
541 // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped\r
542 //\r
543 ConfigHeader = (PCI_TYPE00 *) &ConfigInfo.Config.Byte[0];\r
544 TempBar = (UINT32 *) &ConfigHeader->Device.Bar[0];\r
545 for (BarIndex = 0; BarIndex <= 5; BarIndex++) {\r
546 if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {\r
547 //\r
548 // This is a 64-bit memory bar, skip this and the\r
549 // next bar as well.\r
550 //\r
551 TempBar++;\r
552 }\r
553\r
554 if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {\r
4cda7726 555 Snp->IoBarIndex = BarIndex;\r
a15a4195 556 break;\r
557 }\r
558\r
559 TempBar++;\r
560 }\r
561\r
562 //\r
563 // Initialize simple network protocol mode structure\r
564 //\r
4cda7726 565 Snp->Mode.State = EfiSimpleNetworkStopped;\r
566 Snp->Mode.HwAddressSize = Snp->InitInfo.HWaddrLen;\r
567 Snp->Mode.MediaHeaderSize = Snp->InitInfo.MediaHeaderLen;\r
568 Snp->Mode.MaxPacketSize = Snp->InitInfo.FrameDataLen;\r
569 Snp->Mode.NvRamAccessSize = Snp->InitInfo.NvWidth;\r
570 Snp->Mode.NvRamSize = Snp->InitInfo.NvCount * Snp->Mode.NvRamAccessSize;\r
571 Snp->Mode.IfType = Snp->InitInfo.IFtype;\r
572 Snp->Mode.MaxMCastFilterCount = Snp->InitInfo.MCastFilterCnt;\r
573 Snp->Mode.MCastFilterCount = 0;\r
a15a4195 574\r
575 switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {\r
576 case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:\r
4cda7726 577 Snp->Mode.MediaPresentSupported = TRUE;\r
a15a4195 578 break;\r
579\r
580 case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:\r
581 default:\r
4cda7726 582 Snp->Mode.MediaPresentSupported = FALSE;\r
a15a4195 583 }\r
584\r
c777c357 585 switch (InitStatFlags & PXE_STATFLAGS_GET_STATUS_NO_MEDIA_MASK) {\r
586 case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED:\r
587 Snp->MediaStatusSupported = TRUE;\r
588 break;\r
589\r
590 case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED:\r
591 default:\r
592 Snp->MediaStatusSupported = FALSE;\r
593 }\r
594\r
4cda7726 595 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {\r
596 Snp->Mode.MacAddressChangeable = TRUE;\r
a15a4195 597 } else {\r
4cda7726 598 Snp->Mode.MacAddressChangeable = FALSE;\r
a15a4195 599 }\r
600\r
4cda7726 601 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {\r
602 Snp->Mode.MultipleTxSupported = TRUE;\r
a15a4195 603 } else {\r
4cda7726 604 Snp->Mode.MultipleTxSupported = FALSE;\r
a15a4195 605 }\r
606\r
4cda7726 607 Snp->Mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;\r
a15a4195 608\r
4cda7726 609 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {\r
610 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
a15a4195 611\r
612 }\r
613\r
4cda7726 614 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {\r
615 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;\r
a15a4195 616\r
617 }\r
618\r
4cda7726 619 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {\r
620 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;\r
a15a4195 621\r
622 }\r
623\r
4cda7726 624 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {\r
625 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;\r
a15a4195 626\r
627 }\r
628\r
e2851998 629 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {\r
4cda7726 630 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;\r
a15a4195 631\r
632 }\r
633\r
4cda7726 634 Snp->Mode.ReceiveFilterSetting = 0;\r
a15a4195 635\r
636 //\r
637 // need to get the station address to save in the mode structure. we need to\r
638 // initialize the UNDI first for this.\r
639 //\r
4cda7726 640 Snp->TxRxBufferSize = Snp->InitInfo.MemoryRequired;\r
641 Status = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);\r
a15a4195 642\r
4cda7726 643 if (EFI_ERROR (Status)) {\r
644 PxeStop (Snp);\r
a15a4195 645 goto Error_DeleteSNP;\r
646 }\r
647\r
4cda7726 648 Status = PxeGetStnAddr (Snp);\r
a15a4195 649\r
650 if (Status != EFI_SUCCESS) {\r
f3816027 651 DEBUG ((EFI_D_ERROR, "\nSnp->undi.get_station_addr() failed.\n"));\r
4cda7726 652 PxeShutdown (Snp);\r
653 PxeStop (Snp);\r
a15a4195 654 goto Error_DeleteSNP;\r
655 }\r
656\r
4cda7726 657 Snp->Mode.MediaPresent = FALSE;\r
a15a4195 658\r
659 //\r
660 // We should not leave UNDI started and initialized here. this DriverStart()\r
661 // routine must only find and attach the SNP interface to UNDI layer that it\r
662 // finds on the given handle!\r
4cda7726 663 // The UNDI layer will be started when upper layers call Snp->start.\r
a15a4195 664 // How ever, this DriverStart() must fill up the snp mode structure which\r
665 // contains the MAC address of the NIC. For this reason we started and\r
666 // initialized UNDI here, now we are done, do a shutdown and stop of the\r
667 // UNDI interface!\r
668 //\r
4cda7726 669 PxeShutdown (Snp);\r
670 PxeStop (Snp);\r
a15a4195 671\r
0428a6cb 672 //\r
673 // Create EXIT_BOOT_SERIVES Event\r
674 //\r
675 Status = gBS->CreateEventEx (\r
676 EVT_NOTIFY_SIGNAL,\r
677 TPL_NOTIFY,\r
678 SnpNotifyExitBootServices,\r
679 Snp,\r
680 &gEfiEventExitBootServicesGuid,\r
681 &Snp->ExitBootServicesEvent\r
682 );\r
683 if (EFI_ERROR (Status)) {\r
684 goto Error_DeleteSNP;\r
685 }\r
686\r
a15a4195 687 //\r
688 // add SNP to the undi handle\r
689 //\r
690 Status = gBS->InstallProtocolInterface (\r
691 &Controller,\r
692 &gEfiSimpleNetworkProtocolGuid,\r
693 EFI_NATIVE_INTERFACE,\r
4cda7726 694 &(Snp->Snp)\r
a15a4195 695 );\r
696\r
697 if (!EFI_ERROR (Status)) {\r
698 return Status;\r
699 }\r
700\r
4cda7726 701 Status = mPciIo->FreeBuffer (\r
702 mPciIo,\r
a15a4195 703 SNP_MEM_PAGES (4096),\r
4cda7726 704 Snp->Cpb\r
a15a4195 705 );\r
706\r
707Error_DeleteSNP:\r
708\r
4cda7726 709 mPciIo->FreeBuffer (\r
710 mPciIo,\r
a15a4195 711 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
4cda7726 712 Snp\r
a15a4195 713 );\r
714NiiError:\r
715 gBS->CloseProtocol (\r
716 Controller,\r
717 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
718 This->DriverBindingHandle,\r
719 Controller\r
720 );\r
721\r
722 gBS->CloseProtocol (\r
723 Controller,\r
724 &gEfiDevicePathProtocolGuid,\r
725 This->DriverBindingHandle,\r
726 Controller\r
727 );\r
728\r
729 return Status;\r
730}\r
731\r
a15a4195 732/**\r
4cda7726 733 Stop this driver on ControllerHandle. This service is called by the\r
734 EFI boot service DisconnectController(). In order to\r
735 make drivers as small as possible, there are a few calling\r
736 restrictions for this service. DisconnectController()\r
737 must follow these calling restrictions. If any other agent wishes\r
738 to call Stop() it must also follow these calling restrictions.\r
e2851998 739\r
4cda7726 740 @param This Protocol instance pointer.\r
741 @param ControllerHandle Handle of device to stop driver on\r
742 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of\r
743 children is zero stop the entire bus driver.\r
744 @param ChildHandleBuffer List of Child Handles to Stop.\r
745\r
746 @retval EFI_SUCCESS This driver is removed ControllerHandle\r
747 @retval other This driver was not removed from this device\r
a15a4195 748\r
749**/\r
750EFI_STATUS\r
751EFIAPI\r
752SimpleNetworkDriverStop (\r
753 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
754 IN EFI_HANDLE Controller,\r
755 IN UINTN NumberOfChildren,\r
756 IN EFI_HANDLE *ChildHandleBuffer\r
757 )\r
758{\r
759 EFI_STATUS Status;\r
760 EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;\r
761 SNP_DRIVER *Snp;\r
762\r
763 //\r
764 // Get our context back.\r
765 //\r
766 Status = gBS->OpenProtocol (\r
767 Controller,\r
768 &gEfiSimpleNetworkProtocolGuid,\r
769 (VOID **) &SnpProtocol,\r
770 This->DriverBindingHandle,\r
771 Controller,\r
772 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
773 );\r
774\r
775 if (EFI_ERROR (Status)) {\r
776 return EFI_UNSUPPORTED;\r
777 }\r
778\r
779 Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);\r
780\r
781 Status = gBS->UninstallProtocolInterface (\r
782 Controller,\r
783 &gEfiSimpleNetworkProtocolGuid,\r
4cda7726 784 &Snp->Snp\r
a15a4195 785 );\r
786\r
787 if (EFI_ERROR (Status)) {\r
788 return Status;\r
789 }\r
790\r
0428a6cb 791 //\r
792 // Close EXIT_BOOT_SERIVES Event\r
793 //\r
794 gBS->CloseEvent (Snp->ExitBootServicesEvent);\r
795\r
a15a4195 796 Status = gBS->CloseProtocol (\r
797 Controller,\r
798 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,\r
799 This->DriverBindingHandle,\r
800 Controller\r
801 );\r
802\r
803 Status = gBS->CloseProtocol (\r
804 Controller,\r
805 &gEfiDevicePathProtocolGuid,\r
806 This->DriverBindingHandle,\r
807 Controller\r
808 );\r
809\r
4cda7726 810 PxeShutdown (Snp);\r
811 PxeStop (Snp);\r
a15a4195 812\r
4cda7726 813 mPciIo->FreeBuffer (\r
814 mPciIo,\r
a15a4195 815 SNP_MEM_PAGES (4096),\r
4cda7726 816 Snp->Cpb\r
a15a4195 817 );\r
818\r
4cda7726 819 mPciIo->FreeBuffer (\r
820 mPciIo,\r
a15a4195 821 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),\r
822 Snp\r
823 );\r
824\r
825 return Status;\r
826}\r
827\r
4cda7726 828//\r
829// Simple Network Protocol Driver Global Variables\r
830//\r
216f7970 831EFI_DRIVER_BINDING_PROTOCOL gSimpleNetworkDriverBinding = {\r
4cda7726 832 SimpleNetworkDriverSupported,\r
833 SimpleNetworkDriverStart,\r
834 SimpleNetworkDriverStop,\r
835 0xa,\r
836 NULL,\r
837 NULL\r
838};\r
839\r
840\r
841/**\r
842 This routine maps the given CPU address to a Device address. It creates a\r
843 an entry in the map list with the virtual and physical addresses and the\r
844 un map cookie.\r
845\r
846 @param V2p pointer to return a map list node pointer.\r
847 @param Type the direction in which the data flows from the given\r
848 virtual address device->cpu or cpu->device or both\r
849 ways.\r
850 @param VirtualAddress virtual address (or CPU address) to be mapped.\r
851 @param BufferSize size of the buffer to be mapped.\r
852\r
853 @retval EFI_SUCEESS routine has completed the mapping.\r
854 @retval EFI_INVALID_PARAMETER invalid parameter.\r
855 @retval EFI_OUT_OF_RESOURCES out of resource.\r
856 @retval other error as indicated.\r
857\r
858**/\r
859EFI_STATUS\r
860AddV2P (\r
861 IN OUT V2P **V2p,\r
862 EFI_PCI_IO_PROTOCOL_OPERATION Type,\r
863 VOID *VirtualAddress,\r
864 UINTN BufferSize\r
865 )\r
866{\r
867 EFI_STATUS Status;\r
868\r
869 if ((V2p == NULL) || (VirtualAddress == NULL) || (BufferSize == 0)) {\r
870 return EFI_INVALID_PARAMETER;\r
871 }\r
872\r
f3816027 873 *V2p = AllocatePool (sizeof (V2P));\r
894d038a 874 if (*V2p == NULL) {\r
4cda7726 875 return EFI_OUT_OF_RESOURCES;\r
876 }\r
877\r
878 Status = mPciIo->Map (\r
f3816027 879 mPciIo,\r
880 Type,\r
881 VirtualAddress,\r
882 &BufferSize,\r
883 &(*V2p)->PhysicalAddress,\r
884 &(*V2p)->Unmap\r
885 );\r
4cda7726 886 if (Status != EFI_SUCCESS) {\r
887 FreePool (*V2p);\r
888 return Status;\r
889 }\r
890 (*V2p)->VirtualAddress = VirtualAddress;\r
f3816027 891 (*V2p)->BufferSize = BufferSize;\r
892 (*V2p)->Next = mV2p;\r
893 mV2p = *V2p;\r
4cda7726 894\r
895 return EFI_SUCCESS;\r
896}\r
897\r
898\r
899/**\r
900 This routine searches the linked list of mapped address nodes (for undi3.0\r
901 interface) to find the node that corresponds to the given virtual address and\r
902 returns a pointer to that node.\r
903\r
904 @param V2p pointer to return a map list node pointer.\r
905 @param VirtualAddr virtual address (or CPU address) to be searched in\r
906 the map list\r
907\r
f3816027 908 @retval EFI_SUCEESS A match was found.\r
909 @retval Other A match cannot be found.\r
4cda7726 910\r
911**/\r
912EFI_STATUS\r
913FindV2p (\r
914 V2P **V2p,\r
915 VOID *VirtualAddr\r
916 )\r
917{\r
918 V2P *Ptr;\r
919\r
920 if (V2p == NULL || VirtualAddr == NULL) {\r
921 return EFI_INVALID_PARAMETER;\r
922 }\r
923\r
924 for (Ptr = mV2p; Ptr != NULL; Ptr = Ptr->Next) {\r
925 if (Ptr->VirtualAddress == VirtualAddr) {\r
926 *V2p = Ptr;\r
927 return EFI_SUCCESS;\r
928 }\r
929 }\r
930\r
931 return EFI_NOT_FOUND;\r
932}\r
933\r
934\r
935/**\r
f3816027 936 Unmap the given virtual address and free the memory allocated for the map list\r
937 node corresponding to that address.\r
4cda7726 938\r
f3816027 939 @param VirtualAddress virtual address (or CPU address) to be unmapped.\r
4cda7726 940\r
f3816027 941 @retval EFI_SUCEESS Successfully unmapped.\r
942 @retval Other Other errors as indicated.\r
4cda7726 943\r
944**/\r
945EFI_STATUS\r
946DelV2p (\r
947 VOID *VirtualAddress\r
948 )\r
949{\r
950 V2P *Current;\r
951 V2P *Next;\r
952 EFI_STATUS Status;\r
953\r
954 if (VirtualAddress == NULL) {\r
955 return EFI_INVALID_PARAMETER;\r
956 }\r
957\r
958 if (mV2p == NULL) {\r
959 return EFI_NOT_FOUND;\r
960 }\r
961 //\r
962 // Is our node at the head of the list??\r
963 //\r
964 if ((Current = mV2p)->VirtualAddress == VirtualAddress) {\r
965 mV2p = mV2p->Next;\r
966\r
967 Status = mPciIo->Unmap (mPciIo, Current->Unmap);\r
968\r
969 FreePool (Current);\r
970\r
971 if (EFI_ERROR (Status)) {\r
972 DEBUG ((EFI_D_ERROR, "Unmap failed with status = %r\n", Status));\r
973 }\r
974 return Status;\r
975 }\r
976\r
977 for (; Current->Next != NULL; Current = Next) {\r
978 if ((Next = Current->Next)->VirtualAddress == VirtualAddress) {\r
979 Current->Next = Next->Next;\r
980 Status = mPciIo->Unmap (mPciIo, Next->Unmap);\r
981 FreePool (Next);\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\r
990 return EFI_NOT_FOUND;\r
991}\r
a15a4195 992\r
993/**\r
4cda7726 994 The SNP driver entry point.\r
a15a4195 995\r
4cda7726 996 @param ImageHandle The driver image handle.\r
997 @param SystemTable The system table.\r
a15a4195 998\r
4cda7726 999 @retval EFI_SUCEESS Initialization routine has found UNDI hardware,\r
1000 loaded it's ROM, and installed a notify event for\r
1001 the Network Indentifier Interface Protocol\r
1002 successfully.\r
1003 @retval Other Return value from HandleProtocol for\r
1004 DeviceIoProtocol or LoadedImageProtocol\r
a15a4195 1005\r
1006**/\r
1007EFI_STATUS\r
1008EFIAPI\r
1009InitializeSnpNiiDriver (\r
1010 IN EFI_HANDLE ImageHandle,\r
1011 IN EFI_SYSTEM_TABLE *SystemTable\r
1012 )\r
1013{\r
1014 return EfiLibInstallDriverBindingComponentName2 (\r
1015 ImageHandle,\r
1016 SystemTable,\r
216f7970 1017 &gSimpleNetworkDriverBinding,\r
f3de0a60 1018 ImageHandle,\r
a15a4195 1019 &gSimpleNetworkComponentName,\r
1020 &gSimpleNetworkComponentName2\r
1021 );\r
1022}\r