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