Fixed potential issues to release resources when error occurs.
[mirror_edk2.git] / MdeModulePkg / Bus / Pci / UndiRuntimeDxe / Init.c
1 /*++
2
3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 init.c
15
16 Abstract:
17
18 Initialization functions for EFI UNDI32 driver
19
20 Revision History
21
22 --*/
23
24 #include "Undi32.h"
25 #include <Library/BaseLib.h>
26 //
27 // Global Variables
28 //
29
30 PXE_SW_UNDI *pxe_31 = NULL; // 3.1 entry
31 UNDI32_DEV *UNDI32DeviceList[MAX_NIC_INTERFACES];
32 NII_TABLE *UndiDataPointer = NULL;
33
34 VOID
35 EFIAPI
36 UndiNotifyVirtual (
37 EFI_EVENT Event,
38 VOID *Context
39 )
40 /*++
41
42 Routine Description:
43
44 When address mapping changes to virtual this should make the appropriate
45 address conversions.
46
47 Arguments:
48
49 (Standard Event handler)
50
51 Returns:
52
53 None
54
55 --*/
56 // TODO: Context - add argument and description to function comment
57 {
58 UINT16 Index;
59 VOID *Pxe31Pointer;
60
61 if (pxe_31 != NULL) {
62 Pxe31Pointer = (VOID *) pxe_31;
63
64 EfiConvertPointer (
65 EFI_OPTIONAL_POINTER,
66 (VOID **) &Pxe31Pointer
67 );
68
69 //
70 // UNDI32DeviceList is an array of pointers
71 //
72 for (Index = 0; Index < pxe_31->IFcnt; Index++) {
73 UNDI32DeviceList[Index]->NIIProtocol_31.ID = (UINT64) (UINTN) Pxe31Pointer;
74 EfiConvertPointer (
75 EFI_OPTIONAL_POINTER,
76 (VOID **) &(UNDI32DeviceList[Index])
77 );
78 }
79
80 EfiConvertPointer (
81 EFI_OPTIONAL_POINTER,
82 (VOID **) &(pxe_31->EntryPoint)
83 );
84 pxe_31 = Pxe31Pointer;
85 }
86
87 for (Index = 0; Index <= PXE_OPCODE_LAST_VALID; Index++) {
88 EfiConvertPointer (
89 EFI_OPTIONAL_POINTER,
90 (VOID **) &api_table[Index].api_ptr
91 );
92 }
93 }
94
95 VOID
96 EFIAPI
97 UndiNotifyExitBs (
98 EFI_EVENT Event,
99 VOID *Context
100 )
101 /*++
102
103 Routine Description:
104
105 When EFI is shuting down the boot services, we need to install a
106 configuration table for UNDI to work at runtime!
107
108 Arguments:
109
110 (Standard Event handler)
111
112 Returns:
113
114 None
115
116 --*/
117 // TODO: Context - add argument and description to function comment
118 {
119 InstallConfigTable ();
120 }
121 //
122 // UNDI Class Driver Global Variables
123 //
124 EFI_DRIVER_BINDING_PROTOCOL gUndiDriverBinding = {
125 UndiDriverSupported,
126 UndiDriverStart,
127 UndiDriverStop,
128 0xa,
129 NULL,
130 NULL
131 };
132
133
134 EFI_STATUS
135 EFIAPI
136 UndiDriverSupported (
137 IN EFI_DRIVER_BINDING_PROTOCOL *This,
138 IN EFI_HANDLE Controller,
139 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
140 )
141 /*++
142
143 Routine Description:
144
145 Test to see if this driver supports ControllerHandle. Any ControllerHandle
146 than contains a DevicePath, PciIo protocol, Class code of 2, Vendor ID of 0x8086,
147 and DeviceId of (D100_DEVICE_ID || D102_DEVICE_ID || ICH3_DEVICE_ID_1 ||
148 ICH3_DEVICE_ID_2 || ICH3_DEVICE_ID_3 || ICH3_DEVICE_ID_4 || ICH3_DEVICE_ID_5 ||
149 ICH3_DEVICE_ID_6 || ICH3_DEVICE_ID_7 || ICH3_DEVICE_ID_8) can be supported.
150
151 Arguments:
152
153 This - Protocol instance pointer.
154
155 Controller - Handle of device to test.
156
157 RemainingDevicePath - Not used.
158
159 Returns:
160
161 EFI_SUCCESS - This driver supports this device.
162
163 other - This driver does not support this device.
164
165 --*/
166 {
167 EFI_STATUS Status;
168 EFI_PCI_IO_PROTOCOL *PciIo;
169 PCI_TYPE00 Pci;
170
171 Status = gBS->OpenProtocol (
172 Controller,
173 &gEfiDevicePathProtocolGuid,
174 NULL,
175 This->DriverBindingHandle,
176 Controller,
177 EFI_OPEN_PROTOCOL_TEST_PROTOCOL
178 );
179 if (EFI_ERROR (Status)) {
180 return Status;
181 }
182
183 Status = gBS->OpenProtocol (
184 Controller,
185 &gEfiPciIoProtocolGuid,
186 (VOID **) &PciIo,
187 This->DriverBindingHandle,
188 Controller,
189 EFI_OPEN_PROTOCOL_BY_DRIVER
190 );
191 if (EFI_ERROR (Status)) {
192 return Status;
193 }
194
195 Status = PciIo->Pci.Read (
196 PciIo,
197 EfiPciIoWidthUint8,
198 0,
199 sizeof (PCI_CONFIG_HEADER),
200 &Pci
201 );
202
203 if (!EFI_ERROR (Status)) {
204 Status = EFI_UNSUPPORTED;
205
206 if (Pci.Hdr.ClassCode[2] == 0x02 && Pci.Hdr.VendorId == PCI_VENDOR_ID_INTEL) {
207 switch (Pci.Hdr.DeviceId) {
208 case D100_DEVICE_ID:
209 case D102_DEVICE_ID:
210 case ICH3_DEVICE_ID_1:
211 case ICH3_DEVICE_ID_2:
212 case ICH3_DEVICE_ID_3:
213 case ICH3_DEVICE_ID_4:
214 case ICH3_DEVICE_ID_5:
215 case ICH3_DEVICE_ID_6:
216 case ICH3_DEVICE_ID_7:
217 case ICH3_DEVICE_ID_8:
218 case 0x1039:
219 case 0x103A:
220 case 0x103B:
221 case 0x103C:
222 case 0x103D:
223 case 0x103E:
224 case 0x1050:
225 case 0x1051:
226 case 0x1052:
227 case 0x1053:
228 case 0x1054:
229 case 0x1055:
230 case 0x1056:
231 case 0x1057:
232 case 0x1059:
233 case 0x1064:
234 Status = EFI_SUCCESS;
235 }
236 }
237 }
238
239 gBS->CloseProtocol (
240 Controller,
241 &gEfiPciIoProtocolGuid,
242 This->DriverBindingHandle,
243 Controller
244 );
245
246 return Status;
247 }
248
249 EFI_STATUS
250 EFIAPI
251 UndiDriverStart (
252 IN EFI_DRIVER_BINDING_PROTOCOL *This,
253 IN EFI_HANDLE Controller,
254 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
255 )
256 /*++
257
258 Routine Description:
259
260 Start this driver on Controller by opening PciIo and DevicePath protocol.
261 Initialize PXE structures, create a copy of the Controller Device Path with the
262 NIC's MAC address appended to it, install the NetworkInterfaceIdentifier protocol
263 on the newly created Device Path.
264
265 Arguments:
266
267 This - Protocol instance pointer.
268
269 Controller - Handle of device to work with.
270
271 RemainingDevicePath - Not used, always produce all possible children.
272
273 Returns:
274
275 EFI_SUCCESS - This driver is added to Controller.
276
277 other - This driver does not support this device.
278
279 --*/
280 {
281 EFI_STATUS Status;
282 EFI_DEVICE_PATH_PROTOCOL *UndiDevicePath;
283 PCI_CONFIG_HEADER *CfgHdr;
284 UNDI32_DEV *UNDI32Device;
285 UINT16 NewCommand;
286 UINT8 *TmpPxePointer;
287 EFI_PCI_IO_PROTOCOL *PciIoFncs;
288 UINTN Len;
289 UINT64 Supports;
290 BOOLEAN PciAttributesSaved;
291
292 Status = gBS->OpenProtocol (
293 Controller,
294 &gEfiPciIoProtocolGuid,
295 (VOID **) &PciIoFncs,
296 This->DriverBindingHandle,
297 Controller,
298 EFI_OPEN_PROTOCOL_BY_DRIVER
299 );
300
301 if (EFI_ERROR (Status)) {
302 return Status;
303 }
304
305 Status = gBS->OpenProtocol (
306 Controller,
307 &gEfiDevicePathProtocolGuid,
308 (VOID **) &UndiDevicePath,
309 This->DriverBindingHandle,
310 Controller,
311 EFI_OPEN_PROTOCOL_BY_DRIVER
312 );
313
314 if (EFI_ERROR (Status)) {
315 gBS->CloseProtocol (
316 Controller,
317 &gEfiPciIoProtocolGuid,
318 This->DriverBindingHandle,
319 Controller
320 );
321
322 return Status;
323 }
324
325 PciAttributesSaved = FALSE;
326
327 Status = gBS->AllocatePool (
328 EfiRuntimeServicesData,
329 sizeof (UNDI32_DEV),
330 (VOID **) &UNDI32Device
331 );
332
333 if (EFI_ERROR (Status)) {
334 goto UndiError;
335 }
336
337 ZeroMem ((CHAR8 *) UNDI32Device, sizeof (UNDI32_DEV));
338
339 //
340 // Get original PCI attributes
341 //
342 Status = PciIoFncs->Attributes (
343 PciIoFncs,
344 EfiPciIoAttributeOperationGet,
345 0,
346 &UNDI32Device->NicInfo.OriginalPciAttributes
347 );
348
349 if (EFI_ERROR (Status)) {
350 goto UndiErrorDeleteDevice;
351 }
352 PciAttributesSaved = TRUE;
353
354 //
355 // allocate and initialize both (old and new) the !pxe structures here,
356 // there should only be one copy of each of these structure for any number
357 // of NICs this undi supports. Also, these structures need to be on a
358 // paragraph boundary as per the spec. so, while allocating space for these,
359 // make sure that there is space for 2 !pxe structures (old and new) and a
360 // 32 bytes padding for alignment adjustment (in case)
361 //
362 TmpPxePointer = NULL;
363 if (pxe_31 == NULL) {
364 Status = gBS->AllocatePool (
365 EfiRuntimeServicesData,
366 (sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32),
367 (VOID **) &TmpPxePointer
368 );
369
370 if (EFI_ERROR (Status)) {
371 goto UndiErrorDeleteDevice;
372 }
373
374 ZeroMem (
375 TmpPxePointer,
376 sizeof (PXE_SW_UNDI) + sizeof (PXE_SW_UNDI) + 32
377 );
378 //
379 // check for paragraph alignment here, assuming that the pointer is
380 // already 8 byte aligned.
381 //
382 if (((UINTN) TmpPxePointer & 0x0F) != 0) {
383 pxe_31 = (PXE_SW_UNDI *) ((UINTN) (TmpPxePointer + 8));
384 } else {
385 pxe_31 = (PXE_SW_UNDI *) TmpPxePointer;
386 }
387
388 PxeStructInit (pxe_31);
389 }
390
391 UNDI32Device->NIIProtocol_31.ID = (UINT64) (UINTN) (pxe_31);
392
393 Status = PciIoFncs->Attributes (
394 PciIoFncs,
395 EfiPciIoAttributeOperationSupported,
396 0,
397 &Supports
398 );
399 if (!EFI_ERROR (Status)) {
400 Supports &= EFI_PCI_DEVICE_ENABLE;
401 Status = PciIoFncs->Attributes (
402 PciIoFncs,
403 EfiPciIoAttributeOperationEnable,
404 Supports,
405 NULL
406 );
407 }
408 //
409 // Read all the registers from device's PCI Configuration space
410 //
411 Status = PciIoFncs->Pci.Read (
412 PciIoFncs,
413 EfiPciIoWidthUint32,
414 0,
415 MAX_PCI_CONFIG_LEN,
416 &UNDI32Device->NicInfo.Config
417 );
418
419 CfgHdr = (PCI_CONFIG_HEADER *) &(UNDI32Device->NicInfo.Config[0]);
420
421 //
422 // make sure that this device is a PCI bus master
423 //
424
425 NewCommand = (UINT16) (CfgHdr->Command | PCI_COMMAND_MASTER | PCI_COMMAND_IO);
426 if (CfgHdr->Command != NewCommand) {
427 PciIoFncs->Pci.Write (
428 PciIoFncs,
429 EfiPciIoWidthUint16,
430 PCI_COMMAND,
431 1,
432 &NewCommand
433 );
434 CfgHdr->Command = NewCommand;
435 }
436
437 //
438 // make sure that the latency timer is at least 32
439 //
440 if (CfgHdr->LatencyTimer < 32) {
441 CfgHdr->LatencyTimer = 32;
442 PciIoFncs->Pci.Write (
443 PciIoFncs,
444 EfiPciIoWidthUint8,
445 PCI_LATENCY_TIMER,
446 1,
447 &CfgHdr->LatencyTimer
448 );
449 }
450 //
451 // the IfNum index for the current interface will be the total number
452 // of interfaces initialized so far
453 //
454 UNDI32Device->NIIProtocol_31.IfNum = pxe_31->IFcnt;
455
456 PxeUpdate (&UNDI32Device->NicInfo, pxe_31);
457
458 UNDI32Device->NicInfo.Io_Function = PciIoFncs;
459 UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = UNDI32Device;
460 UNDI32Device->Undi32BaseDevPath = UndiDevicePath;
461
462 Status = AppendMac2DevPath (
463 &UNDI32Device->Undi32DevPath,
464 UNDI32Device->Undi32BaseDevPath,
465 &UNDI32Device->NicInfo
466 );
467
468 if (Status != 0) {
469 goto UndiErrorDeletePxe;
470 }
471
472 UNDI32Device->Signature = UNDI_DEV_SIGNATURE;
473
474 UNDI32Device->NIIProtocol_31.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION_31;
475 UNDI32Device->NIIProtocol_31.Type = EfiNetworkInterfaceUndi;
476 UNDI32Device->NIIProtocol_31.MajorVer = PXE_ROMID_MAJORVER;
477 UNDI32Device->NIIProtocol_31.MinorVer = PXE_ROMID_MINORVER_31;
478 UNDI32Device->NIIProtocol_31.ImageSize = 0;
479 UNDI32Device->NIIProtocol_31.ImageAddr = 0;
480 UNDI32Device->NIIProtocol_31.Ipv6Supported = FALSE;
481
482 UNDI32Device->NIIProtocol_31.StringId[0] = 'U';
483 UNDI32Device->NIIProtocol_31.StringId[1] = 'N';
484 UNDI32Device->NIIProtocol_31.StringId[2] = 'D';
485 UNDI32Device->NIIProtocol_31.StringId[3] = 'I';
486
487 UNDI32Device->DeviceHandle = NULL;
488
489 //
490 // install both the 3.0 and 3.1 NII protocols.
491 //
492 Status = gBS->InstallMultipleProtocolInterfaces (
493 &UNDI32Device->DeviceHandle,
494 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
495 &UNDI32Device->NIIProtocol_31,
496 &gEfiDevicePathProtocolGuid,
497 UNDI32Device->Undi32DevPath,
498 NULL
499 );
500
501 if (EFI_ERROR (Status)) {
502 goto UndiErrorDeleteDevicePath;
503 }
504
505 //
506 // if the table exists, free it and alloc again, or alloc it directly
507 //
508 if (UndiDataPointer != NULL) {
509 Status = gBS->FreePool(UndiDataPointer);
510 }
511 if (EFI_ERROR (Status)) {
512 goto UndiErrorDeleteDevicePath;
513 }
514
515 Len = (pxe_31->IFcnt * sizeof (NII_ENTRY)) + sizeof (UndiDataPointer);
516 Status = gBS->AllocatePool (EfiRuntimeServicesData, Len, (VOID **) &UndiDataPointer);
517
518 if (EFI_ERROR (Status)) {
519 goto UndiErrorAllocDataPointer;
520 }
521
522 //
523 // Open For Child Device
524 //
525 Status = gBS->OpenProtocol (
526 Controller,
527 &gEfiPciIoProtocolGuid,
528 (VOID **) &PciIoFncs,
529 This->DriverBindingHandle,
530 UNDI32Device->DeviceHandle,
531 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
532 );
533
534 return EFI_SUCCESS;
535 UndiErrorAllocDataPointer:
536 gBS->UninstallMultipleProtocolInterfaces (
537 &UNDI32Device->DeviceHandle,
538 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
539 &UNDI32Device->NIIProtocol_31,
540 &gEfiDevicePathProtocolGuid,
541 UNDI32Device->Undi32DevPath,
542 NULL
543 );
544
545 UndiErrorDeleteDevicePath:
546 UNDI32DeviceList[UNDI32Device->NIIProtocol_31.IfNum] = NULL;
547 gBS->FreePool (UNDI32Device->Undi32DevPath);
548
549 UndiErrorDeletePxe:
550 PxeUpdate (NULL, pxe_31);
551 if (TmpPxePointer != NULL) {
552 gBS->FreePool (TmpPxePointer);
553
554 }
555
556 UndiErrorDeleteDevice:
557 if (PciAttributesSaved == TRUE) {
558 //
559 // Restore original PCI attributes
560 //
561 PciIoFncs->Attributes (
562 PciIoFncs,
563 EfiPciIoAttributeOperationSet,
564 UNDI32Device->NicInfo.OriginalPciAttributes,
565 NULL
566 );
567 }
568
569 gBS->FreePool (UNDI32Device);
570
571 UndiError:
572 gBS->CloseProtocol (
573 Controller,
574 &gEfiDevicePathProtocolGuid,
575 This->DriverBindingHandle,
576 Controller
577 );
578
579 gBS->CloseProtocol (
580 Controller,
581 &gEfiPciIoProtocolGuid,
582 This->DriverBindingHandle,
583 Controller
584 );
585
586 return Status;
587 }
588
589 EFI_STATUS
590 EFIAPI
591 UndiDriverStop (
592 IN EFI_DRIVER_BINDING_PROTOCOL *This,
593 IN EFI_HANDLE Controller,
594 IN UINTN NumberOfChildren,
595 IN EFI_HANDLE *ChildHandleBuffer
596 )
597 /*++
598
599 Routine Description:
600 Stop this driver on Controller by removing NetworkInterfaceIdentifier protocol and
601 closing the DevicePath and PciIo protocols on Controller.
602
603 Arguments:
604 This - Protocol instance pointer.
605 Controller - Handle of device to stop driver on.
606 NumberOfChildren - How many children need to be stopped.
607 ChildHandleBuffer - Not used.
608
609 Returns:
610 EFI_SUCCESS - This driver is removed Controller.
611 other - This driver was not removed from this device.
612
613 --*/
614 // TODO: EFI_DEVICE_ERROR - add return value to function comment
615 {
616 EFI_STATUS Status;
617 BOOLEAN AllChildrenStopped;
618 UINTN Index;
619 UNDI32_DEV *UNDI32Device;
620 EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NIIProtocol;
621 EFI_PCI_IO_PROTOCOL *PciIo;
622
623 //
624 // Complete all outstanding transactions to Controller.
625 // Don't allow any new transaction to Controller to be started.
626 //
627 if (NumberOfChildren == 0) {
628
629 //
630 // Close the bus driver
631 //
632 Status = gBS->CloseProtocol (
633 Controller,
634 &gEfiDevicePathProtocolGuid,
635 This->DriverBindingHandle,
636 Controller
637 );
638
639 Status = gBS->CloseProtocol (
640 Controller,
641 &gEfiPciIoProtocolGuid,
642 This->DriverBindingHandle,
643 Controller
644 );
645
646 return Status;
647 }
648
649 AllChildrenStopped = TRUE;
650
651 for (Index = 0; Index < NumberOfChildren; Index++) {
652
653 Status = gBS->OpenProtocol (
654 ChildHandleBuffer[Index],
655 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
656 (VOID **) &NIIProtocol,
657 This->DriverBindingHandle,
658 Controller,
659 EFI_OPEN_PROTOCOL_GET_PROTOCOL
660 );
661 if (!EFI_ERROR (Status)) {
662
663 UNDI32Device = UNDI_DEV_FROM_THIS (NIIProtocol);
664
665 //
666 // Restore original PCI attributes
667 //
668 Status = UNDI32Device->NicInfo.Io_Function->Attributes (
669 UNDI32Device->NicInfo.Io_Function,
670 EfiPciIoAttributeOperationSet,
671 UNDI32Device->NicInfo.OriginalPciAttributes,
672 NULL
673 );
674 ASSERT_EFI_ERROR (Status);
675
676 Status = gBS->CloseProtocol (
677 Controller,
678 &gEfiPciIoProtocolGuid,
679 This->DriverBindingHandle,
680 ChildHandleBuffer[Index]
681 );
682
683 Status = gBS->UninstallMultipleProtocolInterfaces (
684 ChildHandleBuffer[Index],
685 &gEfiDevicePathProtocolGuid,
686 UNDI32Device->Undi32DevPath,
687 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
688 &UNDI32Device->NIIProtocol_31,
689 NULL
690 );
691
692 if (EFI_ERROR (Status)) {
693 gBS->OpenProtocol (
694 Controller,
695 &gEfiPciIoProtocolGuid,
696 (VOID **) &PciIo,
697 This->DriverBindingHandle,
698 ChildHandleBuffer[Index],
699 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
700 );
701 } else {
702 gBS->FreePool (UNDI32Device->Undi32DevPath);
703 gBS->FreePool (UNDI32Device);
704 }
705 }
706
707 if (EFI_ERROR (Status)) {
708 AllChildrenStopped = FALSE;
709 }
710 }
711
712 if (!AllChildrenStopped) {
713 return EFI_DEVICE_ERROR;
714 }
715
716 return EFI_SUCCESS;
717
718 }
719
720 VOID
721 TmpDelay (
722 IN UINT64 UnqId,
723 IN UINTN MicroSeconds
724 )
725 /*++
726
727 Routine Description:
728
729 Use the EFI boot services to produce a pause. This is also the routine which
730 gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can
731 do it's own pause.
732
733 Arguments:
734
735 UnqId - Runtime O/S routine might use this, this temp routine does not use it
736
737 MicroSeconds - Determines the length of pause.
738
739 Returns:
740
741 none
742
743 --*/
744 {
745 gBS->Stall ((UINT32) MicroSeconds);
746 }
747
748 VOID
749 TmpMemIo (
750 IN UINT64 UnqId,
751 IN UINT8 ReadWrite,
752 IN UINT8 Len,
753 IN UINT64 Port,
754 IN UINT64 BuffAddr
755 )
756 /*++
757
758 Routine Description:
759
760 Use the PCI IO abstraction to issue memory or I/O reads and writes. This is also the routine which
761 gets replaced during RunTime by the O/S in the NIC_DATA_INSTANCE so it can do it's own I/O abstractions.
762
763 Arguments:
764
765 UnqId - Runtime O/S routine may use this field, this temp routine does not.
766
767 ReadWrite - Determine if it is an I/O or Memory Read/Write Operation.
768
769 Len - Determines the width of the data operation.
770
771 Port - What port to Read/Write from.
772
773 BuffAddr - Address to read to or write from.
774
775 Returns:
776
777 none
778
779 --*/
780 {
781 EFI_PCI_IO_PROTOCOL_WIDTH Width;
782 NIC_DATA_INSTANCE *AdapterInfo;
783
784 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;
785 AdapterInfo = (NIC_DATA_INSTANCE *) (UINTN) UnqId;
786 switch (Len) {
787 case 2:
788 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;
789 break;
790
791 case 4:
792 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;
793 break;
794
795 case 8:
796 Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;
797 break;
798 }
799
800 switch (ReadWrite) {
801 case PXE_IO_READ:
802 AdapterInfo->Io_Function->Io.Read (
803 AdapterInfo->Io_Function,
804 Width,
805 1,
806 Port,
807 1,
808 (VOID *) (UINTN) (BuffAddr)
809 );
810 break;
811
812 case PXE_IO_WRITE:
813 AdapterInfo->Io_Function->Io.Write (
814 AdapterInfo->Io_Function,
815 Width,
816 1,
817 Port,
818 1,
819 (VOID *) (UINTN) (BuffAddr)
820 );
821 break;
822
823 case PXE_MEM_READ:
824 AdapterInfo->Io_Function->Mem.Read (
825 AdapterInfo->Io_Function,
826 Width,
827 0,
828 Port,
829 1,
830 (VOID *) (UINTN) (BuffAddr)
831 );
832 break;
833
834 case PXE_MEM_WRITE:
835 AdapterInfo->Io_Function->Mem.Write (
836 AdapterInfo->Io_Function,
837 Width,
838 0,
839 Port,
840 1,
841 (VOID *) (UINTN) (BuffAddr)
842 );
843 break;
844 }
845
846 return ;
847 }
848
849 EFI_STATUS
850 AppendMac2DevPath (
851 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevPtr,
852 IN EFI_DEVICE_PATH_PROTOCOL *BaseDevPtr,
853 IN NIC_DATA_INSTANCE *AdapterInfo
854 )
855 /*++
856
857 Routine Description:
858
859 Using the NIC data structure information, read the EEPROM to get the MAC address and then allocate space
860 for a new devicepath (**DevPtr) which will contain the original device path the NIC was found on (*BaseDevPtr)
861 and an added MAC node.
862
863 Arguments:
864
865 DevPtr - Pointer which will point to the newly created device path with the MAC node attached.
866
867 BaseDevPtr - Pointer to the device path which the UNDI device driver is latching on to.
868
869 AdapterInfo - Pointer to the NIC data structure information which the UNDI driver is layering on..
870
871 Returns:
872
873 EFI_SUCCESS - A MAC address was successfully appended to the Base Device Path.
874
875 other - Not enough resources available to create new Device Path node.
876
877 --*/
878 {
879 EFI_MAC_ADDRESS MACAddress;
880 PCI_CONFIG_HEADER *CfgHdr;
881 INT32 Val;
882 INT32 Index;
883 INT32 Index2;
884 UINT8 AddrLen;
885 MAC_ADDR_DEVICE_PATH MacAddrNode;
886 EFI_DEVICE_PATH_PROTOCOL *EndNode;
887 UINT8 *DevicePtr;
888 UINT16 TotalPathLen;
889 UINT16 BasePathLen;
890 EFI_STATUS Status;
891
892 //
893 // set the environment ready (similar to UNDI_Start call) so that we can
894 // execute the other UNDI_ calls to get the mac address
895 // we are using undi 3.1 style
896 //
897 AdapterInfo->Delay = TmpDelay;
898 AdapterInfo->Virt2Phys = (VOID *) 0;
899 AdapterInfo->Block = (VOID *) 0;
900 AdapterInfo->Map_Mem = (VOID *) 0;
901 AdapterInfo->UnMap_Mem = (VOID *) 0;
902 AdapterInfo->Sync_Mem = (VOID *) 0;
903 AdapterInfo->Mem_Io = TmpMemIo;
904 //
905 // these tmp call-backs follow 3.1 undi style
906 // i.e. they have the unique_id parameter.
907 //
908 AdapterInfo->VersionFlag = 0x31;
909 AdapterInfo->Unique_ID = (UINT64) (UINTN) AdapterInfo;
910
911 //
912 // undi init portion
913 //
914 CfgHdr = (PCI_CONFIG_HEADER *) &(AdapterInfo->Config[0]);
915 AdapterInfo->ioaddr = 0;
916 AdapterInfo->RevID = CfgHdr->RevID;
917
918 AddrLen = E100bGetEepromAddrLen (AdapterInfo);
919
920 for (Index = 0, Index2 = 0; Index < 3; Index++) {
921 Val = E100bReadEeprom (AdapterInfo, Index, AddrLen);
922 MACAddress.Addr[Index2++] = (UINT8) Val;
923 MACAddress.Addr[Index2++] = (UINT8) (Val >> 8);
924 }
925
926 SetMem (MACAddress.Addr + Index2, sizeof (EFI_MAC_ADDRESS) - Index2, 0);
927 //for (; Index2 < sizeof (EFI_MAC_ADDRESS); Index2++) {
928 // MACAddress.Addr[Index2] = 0;
929 //}
930 //
931 // stop undi
932 //
933 AdapterInfo->Delay = (VOID *) 0;
934 AdapterInfo->Mem_Io = (VOID *) 0;
935
936 //
937 // fill the mac address node first
938 //
939 ZeroMem ((CHAR8 *) &MacAddrNode, sizeof MacAddrNode);
940 CopyMem (
941 (CHAR8 *) &MacAddrNode.MacAddress,
942 (CHAR8 *) &MACAddress,
943 sizeof (EFI_MAC_ADDRESS)
944 );
945
946 MacAddrNode.Header.Type = MESSAGING_DEVICE_PATH;
947 MacAddrNode.Header.SubType = MSG_MAC_ADDR_DP;
948 MacAddrNode.Header.Length[0] = sizeof (MacAddrNode);
949 MacAddrNode.Header.Length[1] = 0;
950
951 //
952 // find the size of the base dev path.
953 //
954 EndNode = BaseDevPtr;
955
956 while (!IsDevicePathEnd (EndNode)) {
957 EndNode = NextDevicePathNode (EndNode);
958 }
959
960 BasePathLen = (UINT16) ((UINTN) (EndNode) - (UINTN) (BaseDevPtr));
961
962 //
963 // create space for full dev path
964 //
965 TotalPathLen = (UINT16) (BasePathLen + sizeof (MacAddrNode) + sizeof (EFI_DEVICE_PATH_PROTOCOL));
966
967 Status = gBS->AllocatePool (
968 EfiRuntimeServicesData,
969 TotalPathLen,
970 (VOID **) &DevicePtr
971 );
972
973 if (Status != EFI_SUCCESS) {
974 return Status;
975 }
976 //
977 // copy the base path, mac addr and end_dev_path nodes
978 //
979 *DevPtr = (EFI_DEVICE_PATH_PROTOCOL *) DevicePtr;
980 CopyMem (DevicePtr, (CHAR8 *) BaseDevPtr, BasePathLen);
981 DevicePtr += BasePathLen;
982 CopyMem (DevicePtr, (CHAR8 *) &MacAddrNode, sizeof (MacAddrNode));
983 DevicePtr += sizeof (MacAddrNode);
984 CopyMem (DevicePtr, (CHAR8 *) EndNode, sizeof (EFI_DEVICE_PATH_PROTOCOL));
985
986 return EFI_SUCCESS;
987 }
988
989 EFI_STATUS
990 InstallConfigTable (
991 IN VOID
992 )
993 /*++
994
995 Routine Description:
996
997 Install a GUID/Pointer pair into the system's configuration table.
998
999 Arguments:
1000
1001 none
1002
1003 Returns:
1004
1005 EFI_SUCCESS - Install a GUID/Pointer pair into the system's configuration table.
1006
1007 other - Did not successfully install the GUID/Pointer pair into the configuration table.
1008
1009 --*/
1010 // TODO: VOID - add argument and description to function comment
1011 {
1012 EFI_STATUS Status;
1013 EFI_CONFIGURATION_TABLE *CfgPtr;
1014 NII_TABLE *TmpData;
1015 UINT16 Index;
1016 NII_TABLE *UndiData;
1017
1018 if (pxe_31 == NULL) {
1019 return EFI_SUCCESS;
1020 }
1021
1022 if(UndiDataPointer == NULL) {
1023 return EFI_SUCCESS;
1024 }
1025
1026 UndiData = (NII_TABLE *)UndiDataPointer;
1027
1028 UndiData->NumEntries = pxe_31->IFcnt;
1029 UndiData->NextLink = NULL;
1030
1031 for (Index = 0; Index < pxe_31->IFcnt; Index++) {
1032 UndiData->NiiEntry[Index].InterfacePointer = &UNDI32DeviceList[Index]->NIIProtocol_31;
1033 UndiData->NiiEntry[Index].DevicePathPointer = UNDI32DeviceList[Index]->Undi32DevPath;
1034 }
1035
1036 //
1037 // see if there is an entry in the config table already
1038 //
1039 CfgPtr = gST->ConfigurationTable;
1040
1041 for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
1042 Status = CompareGuid (
1043 &CfgPtr->VendorGuid,
1044 &gEfiNetworkInterfaceIdentifierProtocolGuid_31
1045 );
1046 if (Status != EFI_SUCCESS) {
1047 break;
1048 }
1049
1050 CfgPtr++;
1051 }
1052
1053 if (Index < gST->NumberOfTableEntries) {
1054 TmpData = (NII_TABLE *) CfgPtr->VendorTable;
1055
1056 //
1057 // go to the last link
1058 //
1059 while (TmpData->NextLink != NULL) {
1060 TmpData = TmpData->NextLink;
1061 }
1062
1063 TmpData->NextLink = UndiData;
1064
1065 //
1066 // 1st one in chain
1067 //
1068 UndiData = (NII_TABLE *) CfgPtr->VendorTable;
1069 }
1070
1071 //
1072 // create an entry in the configuration table for our GUID
1073 //
1074 Status = gBS->InstallConfigurationTable (
1075 &gEfiNetworkInterfaceIdentifierProtocolGuid_31,
1076 UndiData
1077 );
1078 return Status;
1079 }
1080
1081 /**
1082
1083 Install driver binding protocol of UNDI.
1084
1085 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1086 @param[in] SystemTable A pointer to the EFI System Table.
1087
1088 @retval EFI_SUCCESS The entry point is executed successfully.
1089 @retval other Some error occurs when executing this entry point.
1090
1091 **/
1092 EFI_STATUS
1093 EFIAPI
1094 InitializeUndi(
1095 IN EFI_HANDLE ImageHandle,
1096 IN EFI_SYSTEM_TABLE *SystemTable
1097 )
1098 {
1099 EFI_EVENT Event;
1100 EFI_STATUS Status;
1101
1102 Status = EfiLibInstallDriverBinding (
1103 ImageHandle,
1104 SystemTable,
1105 &gUndiDriverBinding,
1106 ImageHandle
1107 );
1108 ASSERT_EFI_ERROR (Status);
1109
1110 Status = gBS->CreateEvent (
1111 EVT_SIGNAL_EXIT_BOOT_SERVICES,
1112 TPL_NOTIFY,
1113 UndiNotifyExitBs,
1114 NULL,
1115 &Event
1116 );
1117 ASSERT_EFI_ERROR (Status);
1118
1119 Status = gBS->CreateEvent (
1120 EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
1121 TPL_NOTIFY,
1122 UndiNotifyVirtual,
1123 NULL,
1124 &Event
1125 );
1126 ASSERT_EFI_ERROR (Status);
1127
1128 return Status;
1129 }