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