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