1/** @file
2  Implementation of driver entry point and driver binding protocol.
3
4Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials are licensed
6and made available under the terms and conditions of the BSD License which
7accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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**/
24VOID
25EFIAPI
26SnpNotifyExitBootServices (
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**/
52EFI_STATUS
53EFIAPI
54IssueHwUndiCommand (
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**/
81UINT8
82Calc8BitCksum (
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**/
122EFI_STATUS
123EFIAPI
124SimpleNetworkDriverSupported (
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
228Done:
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**/
257EFI_STATUS
258EFIAPI
259SimpleNetworkDriverStart (
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
687Error_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           );
698NiiError:
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**/
741EFI_STATUS
742EFIAPI
743SimpleNetworkDriverStop (
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//
826EFI_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**/
849EFI_STATUS
850EFIAPI
851InitializeSnpNiiDriver (
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