]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/SnpDxe/Snp.c
MdeModulePkg: Clean up source files
[mirror_edk2.git] / MdeModulePkg / Universal / Network / SnpDxe / Snp.c
1 /** @file
2 Implementation of driver entry point and driver binding protocol.
3
4 Copyright (c) 2004 - 2018, 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
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
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
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
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
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
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
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 }