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