• 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->CableDetectSupported = TRUE;
558     break;
559 
560   case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:
561   default:
562     Snp->CableDetectSupported = 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 (Snp->CableDetectSupported || Snp->MediaStatusSupported) {
576     Snp->Mode.MediaPresentSupported = TRUE;
577   }
578 
579   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {
580     Snp->Mode.MacAddressChangeable = TRUE;
581   } else {
582     Snp->Mode.MacAddressChangeable = FALSE;
583   }
584 
585   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {
586     Snp->Mode.MultipleTxSupported = TRUE;
587   } else {
588     Snp->Mode.MultipleTxSupported = FALSE;
589   }
590 
591   Snp->Mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
592 
593   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
594     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
595 
596   }
597 
598   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
599     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
600 
601   }
602 
603   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
604     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
605 
606   }
607 
608   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {
609     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
610 
611   }
612 
613   if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
614     Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
615 
616   }
617 
618   Snp->Mode.ReceiveFilterSetting = 0;
619 
620   //
621   //  need to get the station address to save in the mode structure. we need to
622   // initialize the UNDI first for this.
623   //
624   Snp->TxRxBufferSize = Snp->InitInfo.MemoryRequired;
625   Status              = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
626 
627   if (EFI_ERROR (Status)) {
628     PxeStop (Snp);
629     goto Error_DeleteSNP;
630   }
631 
632   Status = PxeGetStnAddr (Snp);
633 
634   if (Status != EFI_SUCCESS) {
635     DEBUG ((EFI_D_ERROR, "\nSnp->undi.get_station_addr() failed.\n"));
636     PxeShutdown (Snp);
637     PxeStop (Snp);
638     goto Error_DeleteSNP;
639   }
640 
641   Snp->Mode.MediaPresent = FALSE;
642 
643   //
644   // We should not leave UNDI started and initialized here. this DriverStart()
645   // routine must only find and attach the SNP interface to UNDI layer that it
646   // finds on the given handle!
647   // The UNDI layer will be started when upper layers call Snp->start.
648   // How ever, this DriverStart() must fill up the snp mode structure which
649   // contains the MAC address of the NIC. For this reason we started and
650   // initialized UNDI here, now we are done, do a shutdown and stop of the
651   // UNDI interface!
652   //
653   PxeShutdown (Snp);
654   PxeStop (Snp);
655 
656   //
657   // Create EXIT_BOOT_SERIVES Event
658   //
659   Status = gBS->CreateEventEx (
660                   EVT_NOTIFY_SIGNAL,
661                   TPL_NOTIFY,
662                   SnpNotifyExitBootServices,
663                   Snp,
664                   &gEfiEventExitBootServicesGuid,
665                   &Snp->ExitBootServicesEvent
666                   );
667   if (EFI_ERROR (Status)) {
668     goto Error_DeleteSNP;
669   }
670 
671   //
672   //  add SNP to the undi handle
673   //
674   Status = gBS->InstallProtocolInterface (
675                   &Controller,
676                   &gEfiSimpleNetworkProtocolGuid,
677                   EFI_NATIVE_INTERFACE,
678                   &(Snp->Snp)
679                   );
680 
681   if (!EFI_ERROR (Status)) {
682     return Status;
683   }
684 
685   PciIo->FreeBuffer (
686            PciIo,
687            SNP_MEM_PAGES (4096),
688            Snp->Cpb
689            );
690 
691 Error_DeleteSNP:
692 
693   if (Snp->RecycledTxBuf != NULL) {
694     FreePool (Snp->RecycledTxBuf);
695   }
696 
697   PciIo->FreeBuffer (
698            PciIo,
699            SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
700            Snp
701            );
702 NiiError:
703   gBS->CloseProtocol (
704         Controller,
705         &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
706         This->DriverBindingHandle,
707         Controller
708         );
709 
710   gBS->CloseProtocol (
711         Controller,
712         &gEfiDevicePathProtocolGuid,
713         This->DriverBindingHandle,
714         Controller
715         );
716 
717   //
718   // If we got here that means we are in error state.
719   //
720   if (!EFI_ERROR (Status)) {
721     Status = EFI_DEVICE_ERROR;
722   }
723 
724   return Status;
725 }
726 
727 /**
728   Stop this driver on ControllerHandle. This service is called by the
729   EFI boot service DisconnectController(). In order to
730   make drivers as small as possible, there are a few calling
731   restrictions for this service. DisconnectController()
732   must follow these calling restrictions. If any other agent wishes
733   to call Stop() it must also follow these calling restrictions.
734 
735   @param  This              Protocol instance pointer.
736   @param  ControllerHandle  Handle of device to stop driver on
737   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
738                             children is zero stop the entire bus driver.
739   @param  ChildHandleBuffer List of Child Handles to Stop.
740 
741   @retval EFI_SUCCESS       This driver is removed ControllerHandle
742   @retval other             This driver was not removed from this device
743 
744 **/
745 EFI_STATUS
746 EFIAPI
SimpleNetworkDriverStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)747 SimpleNetworkDriverStop (
748   IN  EFI_DRIVER_BINDING_PROTOCOL    *This,
749   IN  EFI_HANDLE                     Controller,
750   IN  UINTN                          NumberOfChildren,
751   IN  EFI_HANDLE                     *ChildHandleBuffer
752   )
753 {
754   EFI_STATUS                  Status;
755   EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;
756   SNP_DRIVER                  *Snp;
757   EFI_PCI_IO_PROTOCOL         *PciIo;
758 
759   //
760   // Get our context back.
761   //
762   Status = gBS->OpenProtocol (
763                   Controller,
764                   &gEfiSimpleNetworkProtocolGuid,
765                   (VOID **) &SnpProtocol,
766                   This->DriverBindingHandle,
767                   Controller,
768                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
769                   );
770 
771   if (EFI_ERROR (Status)) {
772     return EFI_UNSUPPORTED;
773   }
774 
775   Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);
776 
777   Status = gBS->UninstallProtocolInterface (
778                   Controller,
779                   &gEfiSimpleNetworkProtocolGuid,
780                   &Snp->Snp
781                   );
782 
783   if (EFI_ERROR (Status)) {
784     return Status;
785   }
786 
787   //
788   // Close EXIT_BOOT_SERIVES Event
789   //
790   gBS->CloseEvent (Snp->ExitBootServicesEvent);
791 
792   Status = gBS->CloseProtocol (
793                   Controller,
794                   &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
795                   This->DriverBindingHandle,
796                   Controller
797                   );
798 
799   Status = gBS->CloseProtocol (
800                   Controller,
801                   &gEfiDevicePathProtocolGuid,
802                   This->DriverBindingHandle,
803                   Controller
804                   );
805 
806   PxeShutdown (Snp);
807   PxeStop (Snp);
808 
809   FreePool (Snp->RecycledTxBuf);
810 
811   PciIo = Snp->PciIo;
812   PciIo->FreeBuffer (
813            PciIo,
814            SNP_MEM_PAGES (4096),
815            Snp->Cpb
816            );
817 
818   PciIo->FreeBuffer (
819            PciIo,
820            SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
821            Snp
822            );
823 
824   return Status;
825 }
826 
827 //
828 // Simple Network Protocol Driver Global Variables
829 //
830 EFI_DRIVER_BINDING_PROTOCOL gSimpleNetworkDriverBinding = {
831   SimpleNetworkDriverSupported,
832   SimpleNetworkDriverStart,
833   SimpleNetworkDriverStop,
834   0xa,
835   NULL,
836   NULL
837 };
838 
839 /**
840   The SNP driver entry point.
841 
842   @param ImageHandle       The driver image handle.
843   @param SystemTable       The system table.
844 
845   @retval EFI_SUCEESS      Initialization routine has found UNDI hardware,
846                            loaded it's ROM, and installed a notify event for
847                            the Network Indentifier Interface Protocol
848                            successfully.
849   @retval Other            Return value from HandleProtocol for
850                            DeviceIoProtocol or LoadedImageProtocol
851 
852 **/
853 EFI_STATUS
854 EFIAPI
InitializeSnpNiiDriver(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)855 InitializeSnpNiiDriver (
856   IN EFI_HANDLE       ImageHandle,
857   IN EFI_SYSTEM_TABLE *SystemTable
858   )
859 {
860   return EfiLibInstallDriverBindingComponentName2 (
861            ImageHandle,
862            SystemTable,
863            &gSimpleNetworkDriverBinding,
864            ImageHandle,
865            &gSimpleNetworkComponentName,
866            &gSimpleNetworkComponentName2
867            );
868 }
869