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