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