]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/SnpDxe/Snp.c
1. Add EFI_COMPONENT_NAME2_PROTOCOL.GetControllerName() support.
[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 - 2012, 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 // Module global variables needed to support undi 3.0 interface
19 //
20 EFI_PCI_IO_PROTOCOL *mPciIo;
21 V2P *mV2p = NULL; // undi3.0 map_list head
22 // End Global variables
23 //
24
25 /**
26 One notified function to stop UNDI device when gBS->ExitBootServices() called.
27
28 @param Event Pointer to this event
29 @param Context Event hanlder private data
30
31 **/
32 VOID
33 EFIAPI
34 SnpNotifyExitBootServices (
35 EFI_EVENT Event,
36 VOID *Context
37 )
38 {
39 SNP_DRIVER *Snp;
40
41 Snp = (SNP_DRIVER *)Context;
42
43 //
44 // Shutdown and stop UNDI driver
45 //
46 PxeShutdown (Snp);
47 PxeStop (Snp);
48 }
49
50 /**
51 Send command to UNDI. It does nothing currently.
52
53 @param Cdb command to be sent to UNDI.
54
55 @retval EFI_INVALID_PARAMETER The command is 0.
56 @retval EFI_UNSUPPORTED Default return status because it's not
57 supported currently.
58
59 **/
60 EFI_STATUS
61 EFIAPI
62 IssueHwUndiCommand (
63 UINT64 Cdb
64 )
65 {
66 DEBUG ((EFI_D_ERROR, "\nIssueHwUndiCommand() - This should not be called!"));
67
68 if (Cdb == 0) {
69 return EFI_INVALID_PARAMETER;
70
71 }
72 //
73 // %%TBD - For now, nothing is done.
74 //
75 return EFI_UNSUPPORTED;
76 }
77
78
79 /**
80 Compute 8-bit checksum of a buffer.
81
82 @param Buffer Pointer to buffer.
83 @param Length Length of buffer in bytes.
84
85 @return 8-bit checksum of all bytes in buffer, or zero if ptr is NULL or len
86 is zero.
87
88 **/
89 UINT8
90 Calc8BitCksum (
91 VOID *Buffer,
92 UINTN Length
93 )
94 {
95 UINT8 *Ptr;
96 UINT8 Cksum;
97
98 Ptr = Buffer;
99 Cksum = 0;
100
101 if (Ptr == NULL || Length == 0) {
102 return 0;
103 }
104
105 while (Length-- != 0) {
106 Cksum = (UINT8) (Cksum + *Ptr++);
107 }
108
109 return Cksum;
110 }
111
112 /**
113 Test to see if this driver supports ControllerHandle. This service
114 is called by the EFI boot service ConnectController(). In
115 order to make drivers as small as possible, there are a few calling
116 restrictions for this service. ConnectController() must
117 follow these calling restrictions. If any other agent wishes to call
118 Supported() it must also follow these calling restrictions.
119
120 @param This Protocol instance pointer.
121 @param ControllerHandle Handle of device to test.
122 @param RemainingDevicePath Optional parameter use to pick a specific child
123 device to start.
124
125 @retval EFI_SUCCESS This driver supports this device.
126 @retval EFI_ALREADY_STARTED This driver is already running on this device.
127 @retval other This driver does not support this device.
128
129 **/
130 EFI_STATUS
131 EFIAPI
132 SimpleNetworkDriverSupported (
133 IN EFI_DRIVER_BINDING_PROTOCOL *This,
134 IN EFI_HANDLE Controller,
135 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
136 )
137 {
138 EFI_STATUS Status;
139 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
140 PXE_UNDI *Pxe;
141
142 Status = gBS->OpenProtocol (
143 Controller,
144 &gEfiDevicePathProtocolGuid,
145 NULL,
146 This->DriverBindingHandle,
147 Controller,
148 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
149 );
150 if (EFI_ERROR (Status)) {
151 return Status;
152 }
153
154 Status = gBS->OpenProtocol (
155 Controller,
156 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
157 (VOID **) &NiiProtocol,
158 This->DriverBindingHandle,
159 Controller,
160 EFI_OPEN_PROTOCOL_BY_DRIVER
161 );
162
163 if (EFI_ERROR (Status)) {
164 if (Status == EFI_ALREADY_STARTED) {
165 DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %p\n", Controller));
166 }
167 return Status;
168 }
169
170 DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %p\n", Controller));
171
172 //
173 // check the version, we don't want to connect to the undi16
174 //
175 if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {
176 Status = EFI_UNSUPPORTED;
177 goto Done;
178 }
179 //
180 // Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.
181 //
182 if ((NiiProtocol->Id & 0x0F) != 0) {
183 DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));
184 Status = EFI_UNSUPPORTED;
185 goto Done;
186 }
187
188 Pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->Id);
189
190 //
191 // Verify !PXE revisions.
192 //
193 if (Pxe->hw.Signature != PXE_ROMID_SIGNATURE) {
194 DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));
195 Status = EFI_UNSUPPORTED;
196 goto Done;
197 }
198
199 if (Pxe->hw.Rev < PXE_ROMID_REV) {
200 DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));
201 Status = EFI_UNSUPPORTED;
202 goto Done;
203 }
204
205 if (Pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {
206
207 DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));
208 Status = EFI_UNSUPPORTED;
209 goto Done;
210
211 } else if (Pxe->hw.MajorVer == PXE_ROMID_MAJORVER && Pxe->hw.MinorVer < PXE_ROMID_MINORVER) {
212 DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));
213 Status = EFI_UNSUPPORTED;
214 goto Done;
215 }
216 //
217 // Do S/W UNDI specific checks.
218 //
219 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {
220 if (Pxe->sw.EntryPoint < Pxe->sw.Len) {
221 DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));
222 Status = EFI_UNSUPPORTED;
223 goto Done;
224 }
225
226 if (Pxe->sw.BusCnt == 0) {
227 DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));
228 Status = EFI_UNSUPPORTED;
229 goto Done;
230 }
231 }
232
233 Status = EFI_SUCCESS;
234 DEBUG ((EFI_D_INFO, "Support(): supported on %p\n", Controller));
235
236 Done:
237 gBS->CloseProtocol (
238 Controller,
239 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
240 This->DriverBindingHandle,
241 Controller
242 );
243
244 return Status;
245 }
246
247 /**
248 Start this driver on ControllerHandle. This service is called by the
249 EFI boot service ConnectController(). In order to make
250 drivers as small as possible, there are a few calling restrictions for
251 this service. ConnectController() must follow these
252 calling restrictions. If any other agent wishes to call Start() it
253 must also follow these calling restrictions.
254
255 @param This Protocol instance pointer.
256 @param ControllerHandle Handle of device to bind driver to.
257 @param RemainingDevicePath Optional parameter use to pick a specific child
258 device to start.
259
260 @retval EFI_SUCCESS This driver is added to ControllerHandle
261 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
262 @retval other This driver does not support this device
263
264 **/
265 EFI_STATUS
266 EFIAPI
267 SimpleNetworkDriverStart (
268 IN EFI_DRIVER_BINDING_PROTOCOL *This,
269 IN EFI_HANDLE Controller,
270 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
271 )
272 {
273 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;
274 EFI_DEVICE_PATH_PROTOCOL *NiiDevicePath;
275 EFI_STATUS Status;
276 PXE_UNDI *Pxe;
277 SNP_DRIVER *Snp;
278 VOID *Address;
279 EFI_HANDLE Handle;
280 PXE_PCI_CONFIG_INFO ConfigInfo;
281 PCI_TYPE00 *ConfigHeader;
282 UINT32 *TempBar;
283 UINT8 BarIndex;
284 PXE_STATFLAGS InitStatFlags;
285
286 DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() "));
287
288 Status = gBS->OpenProtocol (
289 Controller,
290 &gEfiDevicePathProtocolGuid,
291 (VOID **) &NiiDevicePath,
292 This->DriverBindingHandle,
293 Controller,
294 EFI_OPEN_PROTOCOL_BY_DRIVER
295 );
296
297 if (EFI_ERROR (Status)) {
298 return Status;
299 }
300
301 Status = gBS->LocateDevicePath (
302 &gEfiPciIoProtocolGuid,
303 &NiiDevicePath,
304 &Handle
305 );
306
307 if (EFI_ERROR (Status)) {
308 return Status;
309 }
310
311 Status = gBS->OpenProtocol (
312 Handle,
313 &gEfiPciIoProtocolGuid,
314 (VOID **) &mPciIo,
315 This->DriverBindingHandle,
316 Controller,
317 EFI_OPEN_PROTOCOL_GET_PROTOCOL
318 );
319 if (EFI_ERROR (Status)) {
320 return Status;
321 }
322 //
323 // Get the NII interface.
324 //
325 Status = gBS->OpenProtocol (
326 Controller,
327 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
328 (VOID **) &Nii,
329 This->DriverBindingHandle,
330 Controller,
331 EFI_OPEN_PROTOCOL_BY_DRIVER
332 );
333 if (EFI_ERROR (Status)) {
334 gBS->CloseProtocol (
335 Controller,
336 &gEfiDevicePathProtocolGuid,
337 This->DriverBindingHandle,
338 Controller
339 );
340 return Status;
341 }
342
343 DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));
344
345 Pxe = (PXE_UNDI *) (UINTN) (Nii->Id);
346
347 if (Calc8BitCksum (Pxe, Pxe->hw.Len) != 0) {
348 DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));
349 goto NiiError;
350 }
351
352 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
353 //
354 // We can get any packets.
355 //
356 } else if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
357 //
358 // We need to be able to get broadcast packets for DHCP.
359 // If we do not have promiscuous support, we must at least have
360 // broadcast support or we cannot do DHCP!
361 //
362 } else {
363 DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));
364 goto NiiError;
365 }
366 //
367 // OK, we like this UNDI, and we know snp is not already there on this handle
368 // Allocate and initialize a new simple network protocol structure.
369 //
370 Status = mPciIo->AllocateBuffer (
371 mPciIo,
372 AllocateAnyPages,
373 EfiBootServicesData,
374 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
375 &Address,
376 0
377 );
378
379 if (Status != EFI_SUCCESS) {
380 DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));
381 goto NiiError;
382 }
383
384 Snp = (SNP_DRIVER *) (UINTN) Address;
385
386 ZeroMem (Snp, sizeof (SNP_DRIVER));
387
388 Snp->PciIo = mPciIo;
389 Snp->Signature = SNP_DRIVER_SIGNATURE;
390
391 EfiInitializeLock (&Snp->Lock, TPL_NOTIFY);
392
393 Snp->Snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
394 Snp->Snp.Start = SnpUndi32Start;
395 Snp->Snp.Stop = SnpUndi32Stop;
396 Snp->Snp.Initialize = SnpUndi32Initialize;
397 Snp->Snp.Reset = SnpUndi32Reset;
398 Snp->Snp.Shutdown = SnpUndi32Shutdown;
399 Snp->Snp.ReceiveFilters = SnpUndi32ReceiveFilters;
400 Snp->Snp.StationAddress = SnpUndi32StationAddress;
401 Snp->Snp.Statistics = SnpUndi32Statistics;
402 Snp->Snp.MCastIpToMac = SnpUndi32McastIpToMac;
403 Snp->Snp.NvData = SnpUndi32NvData;
404 Snp->Snp.GetStatus = SnpUndi32GetStatus;
405 Snp->Snp.Transmit = SnpUndi32Transmit;
406 Snp->Snp.Receive = SnpUndi32Receive;
407 Snp->Snp.WaitForPacket = NULL;
408
409 Snp->Snp.Mode = &Snp->Mode;
410
411 Snp->TxRxBufferSize = 0;
412 Snp->TxRxBuffer = NULL;
413
414 Snp->IfNum = Nii->IfNum;
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 = mPciIo->AllocateBuffer (
445 mPciIo,
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 // PxeStart call is going to give the callback functions to UNDI, these callback
463 // functions use the BarIndex values from the snp structure, so these must be initialized
464 // with default values before doing a PxeStart. The correct values can be obtained after
465 // getting the config information from UNDI
466 //
467 Snp->MemoryBarIndex = 0;
468 Snp->IoBarIndex = 1;
469
470 //
471 // we need the undi init information many times in this snp code, just get it
472 // once here and store it in the snp driver structure. to get Init Info
473 // from UNDI we have to start undi first.
474 //
475 Status = PxeStart (Snp);
476
477 if (Status != EFI_SUCCESS) {
478 goto Error_DeleteSNP;
479 }
480
481 Snp->Cdb.OpCode = PXE_OPCODE_GET_INIT_INFO;
482 Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
483
484 Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
485 Snp->Cdb.CPBaddr = PXE_DBADDR_NOT_USED;
486
487 Snp->Cdb.DBsize = (UINT16) sizeof (Snp->InitInfo);
488 Snp->Cdb.DBaddr = (UINT64)(UINTN) (&Snp->InitInfo);
489
490 Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
491 Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
492
493 Snp->Cdb.IFnum = Snp->IfNum;
494 Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
495
496 DEBUG ((EFI_D_NET, "\nSnp->undi.get_init_info() "));
497
498 (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
499
500 //
501 // Save the INIT Stat Code...
502 //
503 InitStatFlags = Snp->Cdb.StatFlags;
504
505 if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
506 DEBUG ((EFI_D_NET, "\nSnp->undi.init_info() %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));
507 PxeStop (Snp);
508 goto Error_DeleteSNP;
509 }
510
511 Snp->Cdb.OpCode = PXE_OPCODE_GET_CONFIG_INFO;
512 Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
513
514 Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
515 Snp->Cdb.CPBaddr = PXE_DBADDR_NOT_USED;
516
517 Snp->Cdb.DBsize = (UINT16) sizeof (ConfigInfo);
518 Snp->Cdb.DBaddr = (UINT64)(UINTN) &ConfigInfo;
519
520 Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
521 Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
522
523 Snp->Cdb.IFnum = Snp->IfNum;
524 Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
525
526 DEBUG ((EFI_D_NET, "\nSnp->undi.get_config_info() "));
527
528 (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
529
530 if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
531 DEBUG ((EFI_D_NET, "\nSnp->undi.config_info() %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));
532 PxeStop (Snp);
533 goto Error_DeleteSNP;
534 }
535 //
536 // Find the correct BAR to do IO.
537 //
538 //
539 // Enumerate through the PCI BARs for the device to determine which one is
540 // the IO BAR. Save the index of the BAR into the adapter info structure.
541 // for regular 32bit BARs, 0 is memory mapped, 1 is io mapped
542 //
543 ConfigHeader = (PCI_TYPE00 *) &ConfigInfo.Config.Byte[0];
544 TempBar = (UINT32 *) &ConfigHeader->Device.Bar[0];
545 for (BarIndex = 0; BarIndex <= 5; BarIndex++) {
546 if ((*TempBar & PCI_BAR_MEM_MASK) == PCI_BAR_MEM_64BIT) {
547 //
548 // This is a 64-bit memory bar, skip this and the
549 // next bar as well.
550 //
551 TempBar++;
552 }
553
554 if ((*TempBar & PCI_BAR_IO_MASK) == PCI_BAR_IO_MODE) {
555 Snp->IoBarIndex = BarIndex;
556 break;
557 }
558
559 TempBar++;
560 }
561
562 //
563 // Initialize simple network protocol mode structure
564 //
565 Snp->Mode.State = EfiSimpleNetworkStopped;
566 Snp->Mode.HwAddressSize = Snp->InitInfo.HWaddrLen;
567 Snp->Mode.MediaHeaderSize = Snp->InitInfo.MediaHeaderLen;
568 Snp->Mode.MaxPacketSize = Snp->InitInfo.FrameDataLen;
569 Snp->Mode.NvRamAccessSize = Snp->InitInfo.NvWidth;
570 Snp->Mode.NvRamSize = Snp->InitInfo.NvCount * Snp->Mode.NvRamAccessSize;
571 Snp->Mode.IfType = Snp->InitInfo.IFtype;
572 Snp->Mode.MaxMCastFilterCount = Snp->InitInfo.MCastFilterCnt;
573 Snp->Mode.MCastFilterCount = 0;
574
575 switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {
576 case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:
577 Snp->Mode.MediaPresentSupported = TRUE;
578 break;
579
580 case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:
581 default:
582 Snp->Mode.MediaPresentSupported = FALSE;
583 }
584
585 switch (InitStatFlags & PXE_STATFLAGS_GET_STATUS_NO_MEDIA_MASK) {
586 case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED:
587 Snp->MediaStatusSupported = TRUE;
588 break;
589
590 case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED:
591 default:
592 Snp->MediaStatusSupported = FALSE;
593 }
594
595 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {
596 Snp->Mode.MacAddressChangeable = TRUE;
597 } else {
598 Snp->Mode.MacAddressChangeable = FALSE;
599 }
600
601 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {
602 Snp->Mode.MultipleTxSupported = TRUE;
603 } else {
604 Snp->Mode.MultipleTxSupported = FALSE;
605 }
606
607 Snp->Mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
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 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
615 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
616
617 }
618
619 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
620 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
621
622 }
623
624 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {
625 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
626
627 }
628
629 if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
630 Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
631
632 }
633
634 Snp->Mode.ReceiveFilterSetting = 0;
635
636 //
637 // need to get the station address to save in the mode structure. we need to
638 // initialize the UNDI first for this.
639 //
640 Snp->TxRxBufferSize = Snp->InitInfo.MemoryRequired;
641 Status = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
642
643 if (EFI_ERROR (Status)) {
644 PxeStop (Snp);
645 goto Error_DeleteSNP;
646 }
647
648 Status = PxeGetStnAddr (Snp);
649
650 if (Status != EFI_SUCCESS) {
651 DEBUG ((EFI_D_ERROR, "\nSnp->undi.get_station_addr() failed.\n"));
652 PxeShutdown (Snp);
653 PxeStop (Snp);
654 goto Error_DeleteSNP;
655 }
656
657 Snp->Mode.MediaPresent = FALSE;
658
659 //
660 // We should not leave UNDI started and initialized here. this DriverStart()
661 // routine must only find and attach the SNP interface to UNDI layer that it
662 // finds on the given handle!
663 // The UNDI layer will be started when upper layers call Snp->start.
664 // How ever, this DriverStart() must fill up the snp mode structure which
665 // contains the MAC address of the NIC. For this reason we started and
666 // initialized UNDI here, now we are done, do a shutdown and stop of the
667 // UNDI interface!
668 //
669 PxeShutdown (Snp);
670 PxeStop (Snp);
671
672 //
673 // Create EXIT_BOOT_SERIVES Event
674 //
675 Status = gBS->CreateEventEx (
676 EVT_NOTIFY_SIGNAL,
677 TPL_NOTIFY,
678 SnpNotifyExitBootServices,
679 Snp,
680 &gEfiEventExitBootServicesGuid,
681 &Snp->ExitBootServicesEvent
682 );
683 if (EFI_ERROR (Status)) {
684 goto Error_DeleteSNP;
685 }
686
687 //
688 // add SNP to the undi handle
689 //
690 Status = gBS->InstallProtocolInterface (
691 &Controller,
692 &gEfiSimpleNetworkProtocolGuid,
693 EFI_NATIVE_INTERFACE,
694 &(Snp->Snp)
695 );
696
697 if (!EFI_ERROR (Status)) {
698 return Status;
699 }
700
701 Status = mPciIo->FreeBuffer (
702 mPciIo,
703 SNP_MEM_PAGES (4096),
704 Snp->Cpb
705 );
706
707 Error_DeleteSNP:
708
709 mPciIo->FreeBuffer (
710 mPciIo,
711 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
712 Snp
713 );
714 NiiError:
715 gBS->CloseProtocol (
716 Controller,
717 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
718 This->DriverBindingHandle,
719 Controller
720 );
721
722 gBS->CloseProtocol (
723 Controller,
724 &gEfiDevicePathProtocolGuid,
725 This->DriverBindingHandle,
726 Controller
727 );
728
729 return Status;
730 }
731
732 /**
733 Stop this driver on ControllerHandle. This service is called by the
734 EFI boot service DisconnectController(). In order to
735 make drivers as small as possible, there are a few calling
736 restrictions for this service. DisconnectController()
737 must follow these calling restrictions. If any other agent wishes
738 to call Stop() it must also follow these calling restrictions.
739
740 @param This Protocol instance pointer.
741 @param ControllerHandle Handle of device to stop driver on
742 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
743 children is zero stop the entire bus driver.
744 @param ChildHandleBuffer List of Child Handles to Stop.
745
746 @retval EFI_SUCCESS This driver is removed ControllerHandle
747 @retval other This driver was not removed from this device
748
749 **/
750 EFI_STATUS
751 EFIAPI
752 SimpleNetworkDriverStop (
753 IN EFI_DRIVER_BINDING_PROTOCOL *This,
754 IN EFI_HANDLE Controller,
755 IN UINTN NumberOfChildren,
756 IN EFI_HANDLE *ChildHandleBuffer
757 )
758 {
759 EFI_STATUS Status;
760 EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;
761 SNP_DRIVER *Snp;
762
763 //
764 // Get our context back.
765 //
766 Status = gBS->OpenProtocol (
767 Controller,
768 &gEfiSimpleNetworkProtocolGuid,
769 (VOID **) &SnpProtocol,
770 This->DriverBindingHandle,
771 Controller,
772 EFI_OPEN_PROTOCOL_GET_PROTOCOL
773 );
774
775 if (EFI_ERROR (Status)) {
776 return EFI_UNSUPPORTED;
777 }
778
779 Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);
780
781 Status = gBS->UninstallProtocolInterface (
782 Controller,
783 &gEfiSimpleNetworkProtocolGuid,
784 &Snp->Snp
785 );
786
787 if (EFI_ERROR (Status)) {
788 return Status;
789 }
790
791 //
792 // Close EXIT_BOOT_SERIVES Event
793 //
794 gBS->CloseEvent (Snp->ExitBootServicesEvent);
795
796 Status = gBS->CloseProtocol (
797 Controller,
798 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
799 This->DriverBindingHandle,
800 Controller
801 );
802
803 Status = gBS->CloseProtocol (
804 Controller,
805 &gEfiDevicePathProtocolGuid,
806 This->DriverBindingHandle,
807 Controller
808 );
809
810 PxeShutdown (Snp);
811 PxeStop (Snp);
812
813 mPciIo->FreeBuffer (
814 mPciIo,
815 SNP_MEM_PAGES (4096),
816 Snp->Cpb
817 );
818
819 mPciIo->FreeBuffer (
820 mPciIo,
821 SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
822 Snp
823 );
824
825 return Status;
826 }
827
828 //
829 // Simple Network Protocol Driver Global Variables
830 //
831 EFI_DRIVER_BINDING_PROTOCOL gSimpleNetworkDriverBinding = {
832 SimpleNetworkDriverSupported,
833 SimpleNetworkDriverStart,
834 SimpleNetworkDriverStop,
835 0xa,
836 NULL,
837 NULL
838 };
839
840
841 /**
842 This routine maps the given CPU address to a Device address. It creates a
843 an entry in the map list with the virtual and physical addresses and the
844 un map cookie.
845
846 @param V2p pointer to return a map list node pointer.
847 @param Type the direction in which the data flows from the given
848 virtual address device->cpu or cpu->device or both
849 ways.
850 @param VirtualAddress virtual address (or CPU address) to be mapped.
851 @param BufferSize size of the buffer to be mapped.
852
853 @retval EFI_SUCEESS routine has completed the mapping.
854 @retval EFI_INVALID_PARAMETER invalid parameter.
855 @retval EFI_OUT_OF_RESOURCES out of resource.
856 @retval other error as indicated.
857
858 **/
859 EFI_STATUS
860 AddV2P (
861 IN OUT V2P **V2p,
862 EFI_PCI_IO_PROTOCOL_OPERATION Type,
863 VOID *VirtualAddress,
864 UINTN BufferSize
865 )
866 {
867 EFI_STATUS Status;
868
869 if ((V2p == NULL) || (VirtualAddress == NULL) || (BufferSize == 0)) {
870 return EFI_INVALID_PARAMETER;
871 }
872
873 *V2p = AllocatePool (sizeof (V2P));
874 if (*V2p == NULL) {
875 return EFI_OUT_OF_RESOURCES;
876 }
877
878 Status = mPciIo->Map (
879 mPciIo,
880 Type,
881 VirtualAddress,
882 &BufferSize,
883 &(*V2p)->PhysicalAddress,
884 &(*V2p)->Unmap
885 );
886 if (Status != EFI_SUCCESS) {
887 FreePool (*V2p);
888 return Status;
889 }
890 (*V2p)->VirtualAddress = VirtualAddress;
891 (*V2p)->BufferSize = BufferSize;
892 (*V2p)->Next = mV2p;
893 mV2p = *V2p;
894
895 return EFI_SUCCESS;
896 }
897
898
899 /**
900 This routine searches the linked list of mapped address nodes (for undi3.0
901 interface) to find the node that corresponds to the given virtual address and
902 returns a pointer to that node.
903
904 @param V2p pointer to return a map list node pointer.
905 @param VirtualAddr virtual address (or CPU address) to be searched in
906 the map list
907
908 @retval EFI_SUCEESS A match was found.
909 @retval Other A match cannot be found.
910
911 **/
912 EFI_STATUS
913 FindV2p (
914 V2P **V2p,
915 VOID *VirtualAddr
916 )
917 {
918 V2P *Ptr;
919
920 if (V2p == NULL || VirtualAddr == NULL) {
921 return EFI_INVALID_PARAMETER;
922 }
923
924 for (Ptr = mV2p; Ptr != NULL; Ptr = Ptr->Next) {
925 if (Ptr->VirtualAddress == VirtualAddr) {
926 *V2p = Ptr;
927 return EFI_SUCCESS;
928 }
929 }
930
931 return EFI_NOT_FOUND;
932 }
933
934
935 /**
936 Unmap the given virtual address and free the memory allocated for the map list
937 node corresponding to that address.
938
939 @param VirtualAddress virtual address (or CPU address) to be unmapped.
940
941 @retval EFI_SUCEESS Successfully unmapped.
942 @retval Other Other errors as indicated.
943
944 **/
945 EFI_STATUS
946 DelV2p (
947 VOID *VirtualAddress
948 )
949 {
950 V2P *Current;
951 V2P *Next;
952 EFI_STATUS Status;
953
954 if (VirtualAddress == NULL) {
955 return EFI_INVALID_PARAMETER;
956 }
957
958 if (mV2p == NULL) {
959 return EFI_NOT_FOUND;
960 }
961 //
962 // Is our node at the head of the list??
963 //
964 if ((Current = mV2p)->VirtualAddress == VirtualAddress) {
965 mV2p = mV2p->Next;
966
967 Status = mPciIo->Unmap (mPciIo, Current->Unmap);
968
969 FreePool (Current);
970
971 if (EFI_ERROR (Status)) {
972 DEBUG ((EFI_D_ERROR, "Unmap failed with status = %r\n", Status));
973 }
974 return Status;
975 }
976
977 for (; Current->Next != NULL; Current = Next) {
978 if ((Next = Current->Next)->VirtualAddress == VirtualAddress) {
979 Current->Next = Next->Next;
980 Status = mPciIo->Unmap (mPciIo, Next->Unmap);
981 FreePool (Next);
982
983 if (EFI_ERROR (Status)) {
984 DEBUG ((EFI_D_ERROR, "Unmap failed with status = %r\n", Status));
985 }
986 return Status;
987 }
988 }
989
990 return EFI_NOT_FOUND;
991 }
992
993 /**
994 The SNP driver entry point.
995
996 @param ImageHandle The driver image handle.
997 @param SystemTable The system table.
998
999 @retval EFI_SUCEESS Initialization routine has found UNDI hardware,
1000 loaded it's ROM, and installed a notify event for
1001 the Network Indentifier Interface Protocol
1002 successfully.
1003 @retval Other Return value from HandleProtocol for
1004 DeviceIoProtocol or LoadedImageProtocol
1005
1006 **/
1007 EFI_STATUS
1008 EFIAPI
1009 InitializeSnpNiiDriver (
1010 IN EFI_HANDLE ImageHandle,
1011 IN EFI_SYSTEM_TABLE *SystemTable
1012 )
1013 {
1014 return EfiLibInstallDriverBindingComponentName2 (
1015 ImageHandle,
1016 SystemTable,
1017 &gSimpleNetworkDriverBinding,
1018 ImageHandle,
1019 &gSimpleNetworkComponentName,
1020 &gSimpleNetworkComponentName2
1021 );
1022 }