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