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